From a1bc89f633c48c3133d7288a6926d64773b7657c Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Mon, 23 Oct 2023 11:46:03 -0600 Subject: [PATCH 1/9] Batch reformat h and cc files. --- .clang-format | 234 + .github/workflows/clang-format-check.yml | 19 + .gitignore | 1 - src/HPWH.cc | 10057 +++++++++++---------- src/HPWH.in.hh | 2452 ++--- src/HPWHHeatingLogics.cc | 426 +- src/HPWHpresets.cc | 8370 +++++++++-------- test/main.cc | 915 +- test/testCompressorFcts.cc | 177 +- test/testHeatingLogics.cc | 484 +- test/testMaxSetpoint.cc | 297 +- test/testPerformanceMaps.cc | 1031 ++- test/testResistanceFcts.cc | 411 +- test/testScaleHPWH.cc | 931 +- test/testSizingFractions.cc | 211 +- test/testStateOfChargeFcts.cc | 113 +- test/testTankSizeFixed.cc | 188 +- test/testUtilityFcts.cc | 593 +- 18 files changed, 14352 insertions(+), 12558 deletions(-) create mode 100644 .clang-format create mode 100644 .github/workflows/clang-format-check.yml diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..c2e69bdb --- /dev/null +++ b/.clang-format @@ -0,0 +1,234 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +# AlignConsecutiveShortCaseStatements: # clang-format 17 +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +# AllowBreakBeforeNoexceptSpecifier: Never # clang-format 17 +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: # relevant only if BreakBeforeBraces==Custom + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Stroustrup +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: AfterComma +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: false +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + # BinaryMinDigits: 0 + Decimal: 0 + # DecimalMinDigits: 0 + Hex: 0 + # HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +# KeepEmptyLinesAtEOF: false # clang-format 17 +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +# RemoveParentheses: Leave # clang-format 17 +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +#SpaceBeforeJsonColon: false # clang-format 17 +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: # to be tested + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +# SpacesInParens: Never # clang-format 17 +# SpacesInParensOptions: # # clang-format 17 +# InCStyleCasts: false +# InConditionalStatements: false +# InEmptyParentheses: false +# Other: false +SpacesInSquareBrackets: false +Standard: c++17 +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +# TypeNames: [] # clang-format 17 +UseTab: Never +# VerilogBreakBetweenInstancePorts: true # clang-format 17 +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml new file mode 100644 index 00000000..048c129e --- /dev/null +++ b/.github/workflows/clang-format-check.yml @@ -0,0 +1,19 @@ +name: clang-format Check +on: [push, pull_request] +jobs: + formatting-check: + name: Formatting Check + runs-on: ubuntu-latest + strategy: + matrix: + path: + - 'src' + - 'include/${{github.workspace}}' + - 'test' + steps: + - uses: actions/checkout@v3 + - name: Run clang-format style check for C++ programs. + uses: jidicula/clang-format-action@v4.11.0 + with: + clang-format-version: '16' + check-path: ${{ matrix.path }} diff --git a/.gitignore b/.gitignore index b1c0b0dd..9d449f14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.* !/.gitignore *~ ~* diff --git a/src/HPWH.cc b/src/HPWH.cc index e4341bb5..85cdf729 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -38,7 +38,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "HPWH.hh" #include "btwxt.h" @@ -48,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -using std::endl; using std::cout; +using std::endl; using std::string; const float HPWH::DENSITYWATER_kgperL = 0.995f; @@ -64,4914 +63,5460 @@ 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.); -//ugh, this should be in the header +// ugh, this should be in the header const std::string HPWH::version_maint = HPWHVRSN_META; -#define SETPOINT_FIX // #define to include fixes for +#define SETPOINT_FIX // #define to include fixes for // setpoint-below-water-temp issues // 1-22-2017 -//the HPWH functions -//the publics -HPWH::HPWH() : setOfSources(NULL), tankTemps_C(NULL), nextTankTemps_C(NULL), messageCallback(NULL), messageCallbackContextPtr(NULL), hpwhVerbosity(VRB_silent) -{ setAllDefaults(); }; +// the HPWH functions +// the publics +HPWH::HPWH() + : setOfSources(NULL) + , tankTemps_C(NULL) + , nextTankTemps_C(NULL) + , messageCallback(NULL) + , messageCallbackContextPtr(NULL) + , hpwhVerbosity(VRB_silent) +{ + setAllDefaults(); +}; -void HPWH::setAllDefaults() { - delete[] tankTemps_C; - delete[] nextTankTemps_C; - delete[] setOfSources; +void HPWH::setAllDefaults() +{ + delete[] tankTemps_C; + delete[] nextTankTemps_C; + delete[] setOfSources; + + simHasFailed = true; + isHeating = false; + setpointFixed = false; + tankSizeFixed = true; + canScale = false; + numHeatSources = 0; + member_inletT_C = HPWH_ABORT; + currentSoCFraction = 1.; + setOfSources = NULL; + tankTemps_C = NULL; + nextTankTemps_C = NULL; + doTempDepression = false; + locationTemperature_C = UNINITIALIZED_LOCATIONTEMP; + mixBelowFractionOnDraw = 1. / 3.; + doInversionMixing = true; + doConduction = true; + inletHeight = 0; + inlet2Height = 0; + fittingsUA_kJperHrC = 0.; + prevDRstatus = DR_ALLOW; + timerLimitTOT = 60.; + timerTOT = 0.; + usesSoCLogic = false; +} + +HPWH::HPWH(const HPWH& hpwh) +{ + simHasFailed = hpwh.simHasFailed; - simHasFailed = true; isHeating = false; setpointFixed = false; tankSizeFixed = true; canScale = false; - numHeatSources = 0; - member_inletT_C = HPWH_ABORT; - currentSoCFraction = 1.; - setOfSources = NULL; tankTemps_C = NULL; nextTankTemps_C = NULL; doTempDepression = false; - locationTemperature_C = UNINITIALIZED_LOCATIONTEMP; - mixBelowFractionOnDraw = 1. / 3.; - doInversionMixing = true; doConduction = true; - inletHeight = 0; inlet2Height = 0; fittingsUA_kJperHrC = 0.; - prevDRstatus = DR_ALLOW; timerLimitTOT = 60.; timerTOT = 0.; - usesSoCLogic = false; -} + hpwhVerbosity = hpwh.hpwhVerbosity; -HPWH::HPWH(const HPWH &hpwh) { - simHasFailed = hpwh.simHasFailed; + // these should actually be the same pointers + messageCallback = hpwh.messageCallback; + messageCallbackContextPtr = hpwh.messageCallbackContextPtr; - hpwhVerbosity = hpwh.hpwhVerbosity; + isHeating = hpwh.isHeating; - //these should actually be the same pointers - messageCallback = hpwh.messageCallback; - messageCallbackContextPtr = hpwh.messageCallbackContextPtr; - - isHeating = hpwh.isHeating; - - numHeatSources = hpwh.numHeatSources; - setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i] = hpwh.setOfSources[i]; - setOfSources[i].hpwh = this; - } - - - - tankVolume_L = hpwh.tankVolume_L; - tankUA_kJperHrC = hpwh.tankUA_kJperHrC; - fittingsUA_kJperHrC = hpwh.fittingsUA_kJperHrC; - - setpoint_C = hpwh.setpoint_C; - numNodes = hpwh.numNodes; - nodeDensity = hpwh.nodeDensity; - tankTemps_C = new double[numNodes]; - nextTankTemps_C = new double[numNodes]; - for (int i = 0; i < numNodes; i++) { - tankTemps_C[i] = hpwh.tankTemps_C[i]; - nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; - } - inletHeight = hpwh.inletHeight; - inlet2Height = hpwh.inlet2Height; - - outletTemp_C = hpwh.outletTemp_C; - condenserInlet_C = hpwh.condenserInlet_C; - condenserOutlet_C = hpwh.condenserOutlet_C; - externalVolumeHeated_L = hpwh.externalVolumeHeated_L; - energyRemovedFromEnvironment_kWh = hpwh.energyRemovedFromEnvironment_kWh; - standbyLosses_kWh = hpwh.standbyLosses_kWh; + numHeatSources = hpwh.numHeatSources; + setOfSources = new HeatSource[numHeatSources]; + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i] = hpwh.setOfSources[i]; + setOfSources[i].hpwh = this; + } - tankMixesOnDraw = hpwh.tankMixesOnDraw; - mixBelowFractionOnDraw = hpwh.mixBelowFractionOnDraw; - doTempDepression = hpwh.doTempDepression; + tankVolume_L = hpwh.tankVolume_L; + tankUA_kJperHrC = hpwh.tankUA_kJperHrC; + fittingsUA_kJperHrC = hpwh.fittingsUA_kJperHrC; - doInversionMixing = hpwh.doInversionMixing; - doConduction = hpwh.doConduction; + setpoint_C = hpwh.setpoint_C; + numNodes = hpwh.numNodes; + nodeDensity = hpwh.nodeDensity; + tankTemps_C = new double[numNodes]; + nextTankTemps_C = new double[numNodes]; + for (int i = 0; i < numNodes; i++) { + tankTemps_C[i] = hpwh.tankTemps_C[i]; + nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; + } + inletHeight = hpwh.inletHeight; + inlet2Height = hpwh.inlet2Height; - locationTemperature_C = hpwh.locationTemperature_C; - - prevDRstatus = hpwh.prevDRstatus; - timerLimitTOT = hpwh.timerLimitTOT; + outletTemp_C = hpwh.outletTemp_C; + condenserInlet_C = hpwh.condenserInlet_C; + condenserOutlet_C = hpwh.condenserOutlet_C; + externalVolumeHeated_L = hpwh.externalVolumeHeated_L; + energyRemovedFromEnvironment_kWh = hpwh.energyRemovedFromEnvironment_kWh; + standbyLosses_kWh = hpwh.standbyLosses_kWh; - usesSoCLogic = hpwh.usesSoCLogic; + tankMixesOnDraw = hpwh.tankMixesOnDraw; + mixBelowFractionOnDraw = hpwh.mixBelowFractionOnDraw; + doTempDepression = hpwh.doTempDepression; - volPerNode_LperNode = hpwh.volPerNode_LperNode; - node_height = hpwh.node_height; - fracAreaTop = hpwh.fracAreaTop; - fracAreaSide = hpwh.fracAreaSide; + doInversionMixing = hpwh.doInversionMixing; + doConduction = hpwh.doConduction; -} + locationTemperature_C = hpwh.locationTemperature_C; -HPWH & HPWH::operator=(const HPWH &hpwh) { - if (this == &hpwh) { - return *this; - } + prevDRstatus = hpwh.prevDRstatus; + timerLimitTOT = hpwh.timerLimitTOT; + usesSoCLogic = hpwh.usesSoCLogic; - simHasFailed = hpwh.simHasFailed; + volPerNode_LperNode = hpwh.volPerNode_LperNode; + node_height = hpwh.node_height; + fracAreaTop = hpwh.fracAreaTop; + fracAreaSide = hpwh.fracAreaSide; +} + +HPWH& HPWH::operator=(const HPWH& hpwh) +{ + if (this == &hpwh) { + return *this; + } - hpwhVerbosity = hpwh.hpwhVerbosity; + simHasFailed = hpwh.simHasFailed; - //these should actually be the same pointers - messageCallback = hpwh.messageCallback; - messageCallbackContextPtr = hpwh.messageCallbackContextPtr; + hpwhVerbosity = hpwh.hpwhVerbosity; - isHeating = hpwh.isHeating; + // these should actually be the same pointers + messageCallback = hpwh.messageCallback; + messageCallbackContextPtr = hpwh.messageCallbackContextPtr; - numHeatSources = hpwh.numHeatSources; + isHeating = hpwh.isHeating; - delete[] setOfSources; - setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i] = hpwh.setOfSources[i]; - setOfSources[i].hpwh = this; - //HeatSource assignment will fail (causing the simulation to fail) if a - //HeatSource has backups/companions. - //This could be dealt with in this function (tricky), but the HeatSource - //assignment can't know where its backup/companion pointer goes so it either - //fails or silently does something that's not at all useful. - //I prefer it to fail. -NDK 1/2016 - } + numHeatSources = hpwh.numHeatSources; + delete[] setOfSources; + setOfSources = new HeatSource[numHeatSources]; + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i] = hpwh.setOfSources[i]; + setOfSources[i].hpwh = this; + // HeatSource assignment will fail (causing the simulation to fail) if a + // HeatSource has backups/companions. + // This could be dealt with in this function (tricky), but the HeatSource + // assignment can't know where its backup/companion pointer goes so it either + // fails or silently does something that's not at all useful. + // I prefer it to fail. -NDK 1/2016 + } - tankVolume_L = hpwh.tankVolume_L; - tankUA_kJperHrC = hpwh.tankUA_kJperHrC; - fittingsUA_kJperHrC = hpwh.fittingsUA_kJperHrC; + tankVolume_L = hpwh.tankVolume_L; + tankUA_kJperHrC = hpwh.tankUA_kJperHrC; + fittingsUA_kJperHrC = hpwh.fittingsUA_kJperHrC; - setpoint_C = hpwh.setpoint_C; - numNodes = hpwh.numNodes; - nodeDensity = hpwh.nodeDensity; + setpoint_C = hpwh.setpoint_C; + numNodes = hpwh.numNodes; + nodeDensity = hpwh.nodeDensity; - delete[] tankTemps_C; - delete[] nextTankTemps_C; - tankTemps_C = new double[numNodes]; - nextTankTemps_C = new double[numNodes]; - for (int i = 0; i < numNodes; i++) { - tankTemps_C[i] = hpwh.tankTemps_C[i]; - nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; - } - inletHeight = hpwh.inletHeight; - inlet2Height = hpwh.inlet2Height; + delete[] tankTemps_C; + delete[] nextTankTemps_C; + tankTemps_C = new double[numNodes]; + nextTankTemps_C = new double[numNodes]; + for (int i = 0; i < numNodes; i++) { + tankTemps_C[i] = hpwh.tankTemps_C[i]; + nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; + } + inletHeight = hpwh.inletHeight; + inlet2Height = hpwh.inlet2Height; - outletTemp_C = hpwh.outletTemp_C; - condenserInlet_C = hpwh.condenserInlet_C; - condenserOutlet_C = hpwh.condenserOutlet_C; - externalVolumeHeated_L = hpwh.externalVolumeHeated_L; - energyRemovedFromEnvironment_kWh = hpwh.energyRemovedFromEnvironment_kWh; - standbyLosses_kWh = hpwh.standbyLosses_kWh; + outletTemp_C = hpwh.outletTemp_C; + condenserInlet_C = hpwh.condenserInlet_C; + condenserOutlet_C = hpwh.condenserOutlet_C; + externalVolumeHeated_L = hpwh.externalVolumeHeated_L; + energyRemovedFromEnvironment_kWh = hpwh.energyRemovedFromEnvironment_kWh; + standbyLosses_kWh = hpwh.standbyLosses_kWh; - tankMixesOnDraw = hpwh.tankMixesOnDraw; - mixBelowFractionOnDraw = hpwh.mixBelowFractionOnDraw; + tankMixesOnDraw = hpwh.tankMixesOnDraw; + mixBelowFractionOnDraw = hpwh.mixBelowFractionOnDraw; - doTempDepression = hpwh.doTempDepression; + doTempDepression = hpwh.doTempDepression; - doInversionMixing = hpwh.doInversionMixing; - doConduction = hpwh.doConduction; + doInversionMixing = hpwh.doInversionMixing; + doConduction = hpwh.doConduction; - locationTemperature_C = hpwh.locationTemperature_C; + locationTemperature_C = hpwh.locationTemperature_C; - prevDRstatus = hpwh.prevDRstatus; - timerLimitTOT = hpwh.timerLimitTOT; + prevDRstatus = hpwh.prevDRstatus; + timerLimitTOT = hpwh.timerLimitTOT; - usesSoCLogic = hpwh.usesSoCLogic; + usesSoCLogic = hpwh.usesSoCLogic; - volPerNode_LperNode = hpwh.volPerNode_LperNode; - node_height = hpwh.node_height; - fracAreaTop = hpwh.fracAreaTop; - fracAreaSide = hpwh.fracAreaSide; - return *this; + volPerNode_LperNode = hpwh.volPerNode_LperNode; + node_height = hpwh.node_height; + fracAreaTop = hpwh.fracAreaTop; + fracAreaSide = hpwh.fracAreaSide; + return *this; } -HPWH::~HPWH() { - delete[] tankTemps_C; - delete[] nextTankTemps_C; - delete[] setOfSources; +HPWH::~HPWH() +{ + delete[] tankTemps_C; + delete[] nextTankTemps_C; + delete[] setOfSources; } -string HPWH::getVersion() { - std::stringstream version; +string HPWH::getVersion() +{ + std::stringstream version; - version << version_major << '.' << version_minor << '.' << version_patch << version_maint; + version << version_major << '.' << version_minor << '.' << version_patch << version_maint; - return version.str(); + return version.str(); } - int HPWH::runOneStep(double drawVolume_L, - double tankAmbientT_C, double heatSourceAmbientT_C, - DRMODES DRstatus, - double inletVol2_L, double inletT2_C, - std::vector* nodePowerExtra_W) { - //returns 0 on successful completion, HPWH_ABORT on failure - - //check for errors - if (doTempDepression == true && minutesPerStep != 1) { - msg("minutesPerStep must equal one for temperature depression to work. \n"); - simHasFailed = true; - return HPWH_ABORT; - } - - if ((DRstatus & (DR_TOO | DR_TOT))) { - if (hpwhVerbosity >= VRB_typical) { - msg("DR_TOO | DR_TOT use conflicting logic sets. The logic will follow a DR_TOT scheme \n"); - } - } - - if (hpwhVerbosity >= VRB_typical) { - msg("Beginning runOneStep. \nTank Temps: "); - printTankTemps(); - msg("Step Inputs: InletT_C: %.2lf, drawVolume_L: %.2lf, tankAmbientT_C: %.2lf, heatSourceAmbientT_C: %.2lf, DRstatus: %d, minutesPerStep: %.2lf \n", - member_inletT_C, drawVolume_L, tankAmbientT_C, heatSourceAmbientT_C, DRstatus, minutesPerStep); - } - //is the failure flag is set, don't run - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("simHasFailed is set, aborting. \n"); - } - return HPWH_ABORT; - } - - - //reset the output variables - outletTemp_C = 0.; - condenserInlet_C = 0.; - condenserOutlet_C = 0.; - externalVolumeHeated_L = 0.; - energyRemovedFromEnvironment_kWh = 0.; - standbyLosses_kWh = 0.; - - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i].runtime_min = 0; - setOfSources[i].energyInput_kWh = 0.; - setOfSources[i].energyOutput_kWh = 0.; - } - - // if you are doing temp. depression, set tank and heatSource ambient temps - // to the tracked locationTemperature - double temperatureGoal = tankAmbientT_C; - if (doTempDepression) { - if (locationTemperature_C == UNINITIALIZED_LOCATIONTEMP) { - locationTemperature_C = tankAmbientT_C; - } - tankAmbientT_C = locationTemperature_C; - heatSourceAmbientT_C = locationTemperature_C; - } - - //process draws and standby losses - updateTankTemps(drawVolume_L, member_inletT_C, tankAmbientT_C, inletVol2_L, inletT2_C); - - updateSoCIfNecessary(); - - // First Logic DR checks ////////////////////////////////////////////////////////////////// - - // If the DR signal includes a top off but the previous signal did not, then top it off! - if ((DRstatus & DR_LOC) != 0 && (DRstatus & DR_LOR) != 0) { - turnAllHeatSourcesOff(); // turns off isheating - if (hpwhVerbosity >= VRB_emetic) { - msg("DR_LOC | DR_LOC everything off, DRstatus = %i \n", DRstatus); - } - } - else { //do normal check - if (((DRstatus & DR_TOO) != 0 || (DRstatus & DR_TOT) != 0 ) && timerTOT == 0) { - - // turn on the compressor and last resistance element. - if (hasACompressor()) { - setOfSources[compressorIndex].engageHeatSource(DRstatus); - } - if (lowestElementIndex >= 0) { - setOfSources[lowestElementIndex].engageHeatSource(DRstatus); - } - - if (hpwhVerbosity >= VRB_emetic) { - msg("TURNED ON DR_TOO engaged compressor and lowest resistance element, DRstatus = %i \n", DRstatus); - } - } - - //do HeatSource choice - for (int i = 0; i < numHeatSources; i++) { - if (hpwhVerbosity >= VRB_emetic) { - msg("Heat source choice:\theatsource %d can choose from %lu turn on logics and %lu shut off logics\n", i, setOfSources[i].turnOnLogicSet.size(), setOfSources[i].shutOffLogicSet.size()); - } - if (isHeating == true) { - //check if anything that is on needs to turn off (generally for lowT cutoffs) - //things that just turn on later this step are checked for this in shouldHeat - if (setOfSources[i].isEngaged() && setOfSources[i].shutsOff()) { - setOfSources[i].disengageHeatSource(); - //check if the backup heat source would have to shut off too - if (setOfSources[i].backupHeatSource != NULL && setOfSources[i].backupHeatSource->shutsOff() != true) { - //and if not, go ahead and turn it on - setOfSources[i].backupHeatSource->engageHeatSource(DRstatus); - } - } - - //if there's a priority HeatSource (e.g. upper resistor) and it needs to - //come on, then turn off and start it up - if (setOfSources[i].isVIP) { - if (hpwhVerbosity >= VRB_emetic) { - msg("\tVIP check"); - } - if (setOfSources[i].shouldHeat()) { - if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { - if (hasACompressor()) { - setOfSources[compressorIndex].engageHeatSource(DRstatus); - break; - } - } - else { - turnAllHeatSourcesOff(); - setOfSources[i].engageHeatSource(DRstatus); - //stop looking if the VIP needs to run - break; - } - } - } - } - //if nothing is currently on, then check if something should come on - else /* (isHeating == false) */ { - if (setOfSources[i].shouldHeat()) { - setOfSources[i].engageHeatSource(DRstatus); - //engaging a heat source sets isHeating to true, so this will only trigger once - } - } - - } //end loop over heat sources - - - if (hpwhVerbosity >= VRB_emetic) { - msg("after heat source choosing: "); - for (int i = 0; i < numHeatSources; i++) { - msg("heat source %d: %d \t", i, setOfSources[i].isEngaged()); - } - msg("\n"); - } - - //do heating logic - double minutesToRun = minutesPerStep; - for (int i = 0; i < numHeatSources; i++) { - // check/apply lock-outs - if (hpwhVerbosity >= VRB_emetic) { - msg("Checking lock-out logic for heat source %d:\n", i); - } - if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { - setOfSources[i].lockOutHeatSource(); - if (hpwhVerbosity >= VRB_emetic) { - msg("Locked out heat source, DRstatus = %i\n", DRstatus); - } - } - else - { - // locks or unlocks the heat source - setOfSources[i].toLockOrUnlock(heatSourceAmbientT_C); - } - if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource == NULL) { - setOfSources[i].disengageHeatSource(); - if (hpwhVerbosity >= HPWH::VRB_emetic) { - msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. Simulation will continue will lock out the heat source."); - } - } - - //going through in order, check if the heat source is on - if (setOfSources[i].isEngaged()) { - - HeatSource* heatSourcePtr; - if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource != NULL) { - - // Check that the backup isn't locked out too or already engaged then it will heat on it's own. - if (setOfSources[i].backupHeatSource->toLockOrUnlock(heatSourceAmbientT_C) || - shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, DRstatus) || //){ - setOfSources[i].backupHeatSource->isEngaged() ) { - continue; - } - // Don't turn the backup electric resistance heat source on if the VIP resistance element is on . - else if (VIPIndex >= 0 && setOfSources[VIPIndex].isOn && - setOfSources[i].backupHeatSource->isAResistance()) { - if (hpwhVerbosity >= VRB_typical) { - msg("Locked out back up heat source AND the engaged heat source %i, DRstatus = %i\n", i, DRstatus); - } - continue; - } - else { - heatSourcePtr = setOfSources[i].backupHeatSource; - } - } - else { - heatSourcePtr = &setOfSources[i]; - } - - addHeatParent(heatSourcePtr, heatSourceAmbientT_C, minutesToRun); - - //if it finished early. i.e. shuts off early like if the heatsource met setpoint or maxed out - if (heatSourcePtr->runtime_min < minutesToRun) { - //debugging message handling - if (hpwhVerbosity >= VRB_emetic) { - msg("done heating! runtime_min minutesToRun %.2lf %.2lf\n", heatSourcePtr->runtime_min, minutesToRun); - } - - //subtract time it ran and turn it off - minutesToRun -= heatSourcePtr->runtime_min; - setOfSources[i].disengageHeatSource(); - //and if there's a heat source that follows this heat source (regardless of lockout) that's able to come on, - if (setOfSources[i].followedByHeatSource != NULL && setOfSources[i].followedByHeatSource->shutsOff() == false) { - //turn it on - setOfSources[i].followedByHeatSource->engageHeatSource(DRstatus); - } - // or if there heat source can't produce hotter water (i.e. it's maxed out) and the tank still isn't at setpoint. - // the compressor should get locked out when the maxedOut is true but have to run the resistance first during this - // timestep to make sure tank is above the max temperature for the compressor. - else if (setOfSources[i].maxedOut() && setOfSources[i].backupHeatSource != NULL) { - - // Check that the backup isn't locked out or already engaged then it will heat or already heated on it's own. - if (!setOfSources[i].backupHeatSource->toLockOrUnlock(heatSourceAmbientT_C) && //If not locked out - !shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, DRstatus) && // and not DR locked out - !setOfSources[i].backupHeatSource->isEngaged()) { // and not already engaged - - HeatSource* backupHeatSourcePtr = setOfSources[i].backupHeatSource; - // turn it on - backupHeatSourcePtr->engageHeatSource(DRstatus); - // add heat if it hasn't heated up this whole minute already - if (backupHeatSourcePtr->runtime_min >= 0.) { - addHeatParent(backupHeatSourcePtr, heatSourceAmbientT_C, minutesToRun - backupHeatSourcePtr->runtime_min); - } - } - } - } - } // heat source not engaged - } // end while iHS heat source - } - if (areAllHeatSourcesOff() == true) { - isHeating = false; - } - - //If theres extra user defined heat to add -> Add extra heat! - if (nodePowerExtra_W != NULL && (*nodePowerExtra_W).size() != 0) { - addExtraHeat(nodePowerExtra_W, tankAmbientT_C); - updateSoCIfNecessary(); - } - - //track the depressed local temperature - if (doTempDepression) { - bool compressorRan = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isEngaged() && !setOfSources[i].isLockedOut() && setOfSources[i].depressesTemperature) { - compressorRan = true; - } - } - - if (compressorRan) { - temperatureGoal -= maxDepression_C; //hardcoded 4.5 degree total drop - from experimental data. Changed to an input - } - else { - //otherwise, do nothing, we're going back to ambient - } - - // shrink the gap by the same percentage every minute - that gives us - // exponential behavior the percentage was determined by a fit to - // experimental data - 9.4 minute half life and 4.5 degree total drop - //minus-equals is important, and fits with the order of locationTemperature - //and temperatureGoal, so as to not use fabs() and conditional tests - locationTemperature_C -= (locationTemperature_C - temperatureGoal)*(1 - 0.9289); - } - - //settle outputs - - //outletTemp_C and standbyLosses_kWh are taken care of in updateTankTemps - - //sum energyRemovedFromEnvironment_kWh for each heat source; - for (int i = 0; i < numHeatSources; i++) { - energyRemovedFromEnvironment_kWh += (setOfSources[i].energyOutput_kWh - setOfSources[i].energyInput_kWh); - } - - //cursory check for inverted temperature profile - if (tankTemps_C[numNodes - 1] < tankTemps_C[0]) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The top of the tank is cooler than the bottom. \n"); - } - } - - // Handle DR timer - prevDRstatus = DRstatus; - // DR check for TOT to increase timer. - timerTOT += minutesPerStep; - // Restart the time if we're over the limit or the command is not a top off. - if ((DRstatus & DR_TOT) != 0 && timerTOT >= timerLimitTOT) { - resetTopOffTimer(); - } - else if ((DRstatus & DR_TOO) == 0 && (DRstatus & DR_TOT) == 0) { - resetTopOffTimer(); - } - - - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The simulation has encountered an error. \n"); - } - return HPWH_ABORT; - } - - - if (hpwhVerbosity >= VRB_typical) { - msg("Ending runOneStep. \n\n\n\n"); - } - - return 0; //successful completion of the step returns 0 -} //end runOneStep - - -int HPWH::runNSteps(int N, double *inletT_C, double *drawVolume_L, - double *tankAmbientT_C, double *heatSourceAmbientT_C, - DRMODES *DRstatus) { - //returns 0 on successful completion, HPWH_ABORT on failure - - //these are all the accumulating variables we'll need - double energyRemovedFromEnvironment_kWh_SUM = 0; - double standbyLosses_kWh_SUM = 0; - double outletTemp_C_AVG = 0; - double totalDrawVolume_L = 0; - std::vector heatSources_runTimes_SUM(numHeatSources); - std::vector heatSources_energyInputs_SUM(numHeatSources); - std::vector heatSources_energyOutputs_SUM(numHeatSources); - - if (hpwhVerbosity >= VRB_typical) { - msg("Begin runNSteps. \n"); - } - //run the sim one step at a time, accumulating the outputs as you go - for (int i = 0; i < N; i++) { - runOneStep(inletT_C[i], drawVolume_L[i], tankAmbientT_C[i], heatSourceAmbientT_C[i], - DRstatus[i]); - - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("RunNSteps has encountered an error on step %d of N and has ceased running. \n", i + 1); - } - return HPWH_ABORT; - } - - energyRemovedFromEnvironment_kWh_SUM += energyRemovedFromEnvironment_kWh; - standbyLosses_kWh_SUM += standbyLosses_kWh; - - outletTemp_C_AVG += outletTemp_C * drawVolume_L[i]; - totalDrawVolume_L += drawVolume_L[i]; - - for (int j = 0; j < numHeatSources; j++) { - heatSources_runTimes_SUM[j] += getNthHeatSourceRunTime(j); - heatSources_energyInputs_SUM[j] += getNthHeatSourceEnergyInput(j); - heatSources_energyOutputs_SUM[j] += getNthHeatSourceEnergyOutput(j); - } - - //print minutely output - if (hpwhVerbosity == VRB_minuteOut) { - msg("%f,%f,%f,", tankAmbientT_C[i], drawVolume_L[i], inletT_C[i]); - for (int j = 0; j < numHeatSources; j++) { - msg("%f,%f,", getNthHeatSourceEnergyInput(j), getNthHeatSourceEnergyOutput(j)); - } - msg("%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", - tankTemps_C[0 * numNodes / 12], tankTemps_C[1 * numNodes / 12], - tankTemps_C[2 * numNodes / 12], tankTemps_C[3 * numNodes / 12], - tankTemps_C[4 * numNodes / 12], tankTemps_C[5 * numNodes / 12], - tankTemps_C[6 * numNodes / 12], tankTemps_C[7 * numNodes / 12], - tankTemps_C[8 * numNodes / 12], tankTemps_C[9 * numNodes / 12], - getNthSimTcouple(1, 6), getNthSimTcouple(2, 6), getNthSimTcouple(3, 6), - getNthSimTcouple(4, 6), getNthSimTcouple(5, 6), getNthSimTcouple(6, 6)); - } - - } - //finish weighted avg. of outlet temp by dividing by the total drawn volume - outletTemp_C_AVG /= totalDrawVolume_L; - - //now, reassign all of the accumulated values to their original spots - energyRemovedFromEnvironment_kWh = energyRemovedFromEnvironment_kWh_SUM; - standbyLosses_kWh = standbyLosses_kWh_SUM; - outletTemp_C = outletTemp_C_AVG; - - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i].runtime_min = heatSources_runTimes_SUM[i]; - setOfSources[i].energyInput_kWh = heatSources_energyInputs_SUM[i]; - setOfSources[i].energyOutput_kWh = heatSources_energyOutputs_SUM[i]; - } - - if (hpwhVerbosity >= VRB_typical) { - msg("Ending runNSteps. \n\n\n\n"); - } - return 0; -} - -void HPWH::addHeatParent(HeatSource *heatSourcePtr, double heatSourceAmbientT_C, double minutesToRun) { - - double tempSetpoint_C = -273.15; - - // Check the air temprature and setpoint against maxOut_at_LowT - if (heatSourcePtr->isACompressor()) { - if (heatSourceAmbientT_C <= heatSourcePtr->maxOut_at_LowT.airT_C && - setpoint_C >= heatSourcePtr->maxOut_at_LowT.outT_C) - { - tempSetpoint_C = setpoint_C; //Store setpoint - setSetpoint(heatSourcePtr->maxOut_at_LowT.outT_C); // Reset to new setpoint as this is used in the add heat calc - } - } - //and add heat if it is - heatSourcePtr->addHeat(heatSourceAmbientT_C, minutesToRun); - - //Change the setpoint back to what it was pre-compressor depression - if (tempSetpoint_C > -273.15) { - setSetpoint(tempSetpoint_C); - } -} - - -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< MAXOUTSTRING>(outputString, fmt, ap); + double tankAmbientT_C, + double heatSourceAmbientT_C, + DRMODES DRstatus, + double inletVol2_L, + double inletT2_C, + std::vector* nodePowerExtra_W) +{ + // returns 0 on successful completion, HPWH_ABORT on failure + + // check for errors + if (doTempDepression == true && minutesPerStep != 1) { + msg("minutesPerStep must equal one for temperature depression to work. \n"); + simHasFailed = true; + return HPWH_ABORT; + } + + if ((DRstatus & (DR_TOO | DR_TOT))) { + if (hpwhVerbosity >= VRB_typical) { + msg("DR_TOO | DR_TOT use conflicting logic sets. The logic will follow a DR_TOT scheme " + " \n"); + } + } + + if (hpwhVerbosity >= VRB_typical) { + msg("Beginning runOneStep. \nTank Temps: "); + printTankTemps(); + msg("Step Inputs: InletT_C: %.2lf, drawVolume_L: %.2lf, tankAmbientT_C: %.2lf, " + "heatSourceAmbientT_C: %.2lf, DRstatus: %d, minutesPerStep: %.2lf \n", + member_inletT_C, + drawVolume_L, + tankAmbientT_C, + heatSourceAmbientT_C, + DRstatus, + minutesPerStep); + } + // is the failure flag is set, don't run + if (simHasFailed) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("simHasFailed is set, aborting. \n"); + } + return HPWH_ABORT; + } + + // reset the output variables + outletTemp_C = 0.; + condenserInlet_C = 0.; + condenserOutlet_C = 0.; + externalVolumeHeated_L = 0.; + energyRemovedFromEnvironment_kWh = 0.; + standbyLosses_kWh = 0.; + + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i].runtime_min = 0; + setOfSources[i].energyInput_kWh = 0.; + setOfSources[i].energyOutput_kWh = 0.; + } + + // if you are doing temp. depression, set tank and heatSource ambient temps + // to the tracked locationTemperature + double temperatureGoal = tankAmbientT_C; + if (doTempDepression) { + if (locationTemperature_C == UNINITIALIZED_LOCATIONTEMP) { + locationTemperature_C = tankAmbientT_C; + } + tankAmbientT_C = locationTemperature_C; + heatSourceAmbientT_C = locationTemperature_C; + } + + // process draws and standby losses + updateTankTemps(drawVolume_L, member_inletT_C, tankAmbientT_C, inletVol2_L, inletT2_C); + + updateSoCIfNecessary(); + + // First Logic DR checks ////////////////////////////////////////////////////////////////// + + // If the DR signal includes a top off but the previous signal did not, then top it off! + if ((DRstatus & DR_LOC) != 0 && (DRstatus & DR_LOR) != 0) { + turnAllHeatSourcesOff(); // turns off isheating + if (hpwhVerbosity >= VRB_emetic) { + msg("DR_LOC | DR_LOC everything off, DRstatus = %i \n", DRstatus); + } + } + else { // do normal check + if (((DRstatus & DR_TOO) != 0 || (DRstatus & DR_TOT) != 0) && timerTOT == 0) { + + // turn on the compressor and last resistance element. + if (hasACompressor()) { + setOfSources[compressorIndex].engageHeatSource(DRstatus); + } + if (lowestElementIndex >= 0) { + setOfSources[lowestElementIndex].engageHeatSource(DRstatus); + } + + if (hpwhVerbosity >= VRB_emetic) { + msg("TURNED ON DR_TOO engaged compressor and lowest resistance element, DRstatus = " + "%i \n", + DRstatus); + } + } + + // do HeatSource choice + for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) { + msg("Heat source choice:\theatsource %d can choose from %lu turn on logics and %lu " + "shut off logics\n", + i, + setOfSources[i].turnOnLogicSet.size(), + setOfSources[i].shutOffLogicSet.size()); + } + if (isHeating == true) { + // check if anything that is on needs to turn off (generally for lowT cutoffs) + // things that just turn on later this step are checked for this in shouldHeat + if (setOfSources[i].isEngaged() && setOfSources[i].shutsOff()) { + setOfSources[i].disengageHeatSource(); + // check if the backup heat source would have to shut off too + if (setOfSources[i].backupHeatSource != NULL && + setOfSources[i].backupHeatSource->shutsOff() != true) { + // and if not, go ahead and turn it on + setOfSources[i].backupHeatSource->engageHeatSource(DRstatus); + } + } + + // if there's a priority HeatSource (e.g. upper resistor) and it needs to + // come on, then turn off and start it up + if (setOfSources[i].isVIP) { + if (hpwhVerbosity >= VRB_emetic) { + msg("\tVIP check"); + } + if (setOfSources[i].shouldHeat()) { + if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { + if (hasACompressor()) { + setOfSources[compressorIndex].engageHeatSource(DRstatus); + break; + } + } + else { + turnAllHeatSourcesOff(); + setOfSources[i].engageHeatSource(DRstatus); + // stop looking if the VIP needs to run + break; + } + } + } + } + // if nothing is currently on, then check if something should come on + else /* (isHeating == false) */ { + if (setOfSources[i].shouldHeat()) { + setOfSources[i].engageHeatSource(DRstatus); + // engaging a heat source sets isHeating to true, so this will only trigger once + } + } + + } // end loop over heat sources + + if (hpwhVerbosity >= VRB_emetic) { + msg("after heat source choosing: "); + for (int i = 0; i < numHeatSources; i++) { + msg("heat source %d: %d \t", i, setOfSources[i].isEngaged()); + } + msg("\n"); + } + + // do heating logic + double minutesToRun = minutesPerStep; + for (int i = 0; i < numHeatSources; i++) { + // check/apply lock-outs + if (hpwhVerbosity >= VRB_emetic) { + msg("Checking lock-out logic for heat source %d:\n", i); + } + if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { + setOfSources[i].lockOutHeatSource(); + if (hpwhVerbosity >= VRB_emetic) { + msg("Locked out heat source, DRstatus = %i\n", DRstatus); + } + } + else { + // locks or unlocks the heat source + setOfSources[i].toLockOrUnlock(heatSourceAmbientT_C); + } + if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource == NULL) { + setOfSources[i].disengageHeatSource(); + if (hpwhVerbosity >= HPWH::VRB_emetic) { + msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. " + "Simulation will continue will lock out the heat source."); + } + } + + // going through in order, check if the heat source is on + if (setOfSources[i].isEngaged()) { + + HeatSource* heatSourcePtr; + if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource != NULL) { + + // Check that the backup isn't locked out too or already engaged then it will + // heat on it's own. + if (setOfSources[i].backupHeatSource->toLockOrUnlock(heatSourceAmbientT_C) || + shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, + DRstatus) || //){ + setOfSources[i].backupHeatSource->isEngaged()) { + continue; + } + // Don't turn the backup electric resistance heat source on if the VIP + // resistance element is on . + else if (VIPIndex >= 0 && setOfSources[VIPIndex].isOn && + setOfSources[i].backupHeatSource->isAResistance()) { + if (hpwhVerbosity >= VRB_typical) { + msg("Locked out back up heat source AND the engaged heat source %i, " + "DRstatus = %i\n", + i, + DRstatus); + } + continue; + } + else { + heatSourcePtr = setOfSources[i].backupHeatSource; + } + } + else { + heatSourcePtr = &setOfSources[i]; + } + + addHeatParent(heatSourcePtr, heatSourceAmbientT_C, minutesToRun); + + // if it finished early. i.e. shuts off early like if the heatsource met setpoint or + // maxed out + if (heatSourcePtr->runtime_min < minutesToRun) { + // debugging message handling + if (hpwhVerbosity >= VRB_emetic) { + msg("done heating! runtime_min minutesToRun %.2lf %.2lf\n", + heatSourcePtr->runtime_min, + minutesToRun); + } + + // subtract time it ran and turn it off + minutesToRun -= heatSourcePtr->runtime_min; + setOfSources[i].disengageHeatSource(); + // and if there's a heat source that follows this heat source (regardless of + // lockout) that's able to come on, + if (setOfSources[i].followedByHeatSource != NULL && + setOfSources[i].followedByHeatSource->shutsOff() == false) { + // turn it on + setOfSources[i].followedByHeatSource->engageHeatSource(DRstatus); + } + // or if there heat source can't produce hotter water (i.e. it's maxed out) and + // the tank still isn't at setpoint. the compressor should get locked out when + // the maxedOut is true but have to run the resistance first during this + // timestep to make sure tank is above the max temperature for the compressor. + else if (setOfSources[i].maxedOut() && + setOfSources[i].backupHeatSource != NULL) { + + // Check that the backup isn't locked out or already engaged then it will + // heat or already heated on it's own. + if (!setOfSources[i].backupHeatSource->toLockOrUnlock( + heatSourceAmbientT_C) && // If not locked out + !shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, + DRstatus) && // and not DR locked out + !setOfSources[i] + .backupHeatSource->isEngaged()) { // and not already engaged + + HeatSource* backupHeatSourcePtr = setOfSources[i].backupHeatSource; + // turn it on + backupHeatSourcePtr->engageHeatSource(DRstatus); + // add heat if it hasn't heated up this whole minute already + if (backupHeatSourcePtr->runtime_min >= 0.) { + addHeatParent(backupHeatSourcePtr, + heatSourceAmbientT_C, + minutesToRun - backupHeatSourcePtr->runtime_min); + } + } + } + } + } // heat source not engaged + } // end while iHS heat source + } + if (areAllHeatSourcesOff() == true) { + isHeating = false; + } + + // If theres extra user defined heat to add -> Add extra heat! + if (nodePowerExtra_W != NULL && (*nodePowerExtra_W).size() != 0) { + addExtraHeat(nodePowerExtra_W, tankAmbientT_C); + updateSoCIfNecessary(); + } + + // track the depressed local temperature + if (doTempDepression) { + bool compressorRan = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isEngaged() && !setOfSources[i].isLockedOut() && + setOfSources[i].depressesTemperature) { + compressorRan = true; + } + } + + if (compressorRan) { + temperatureGoal -= maxDepression_C; // hardcoded 4.5 degree total drop - from + // experimental data. Changed to an input + } + else { + // otherwise, do nothing, we're going back to ambient + } + + // shrink the gap by the same percentage every minute - that gives us + // exponential behavior the percentage was determined by a fit to + // experimental data - 9.4 minute half life and 4.5 degree total drop + // minus-equals is important, and fits with the order of locationTemperature + // and temperatureGoal, so as to not use fabs() and conditional tests + locationTemperature_C -= (locationTemperature_C - temperatureGoal) * (1 - 0.9289); + } + + // settle outputs + + // outletTemp_C and standbyLosses_kWh are taken care of in updateTankTemps + + // sum energyRemovedFromEnvironment_kWh for each heat source; + for (int i = 0; i < numHeatSources; i++) { + energyRemovedFromEnvironment_kWh += + (setOfSources[i].energyOutput_kWh - setOfSources[i].energyInput_kWh); + } + + // cursory check for inverted temperature profile + if (tankTemps_C[numNodes - 1] < tankTemps_C[0]) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The top of the tank is cooler than the bottom. \n"); + } + } + + // Handle DR timer + prevDRstatus = DRstatus; + // DR check for TOT to increase timer. + timerTOT += minutesPerStep; + // Restart the time if we're over the limit or the command is not a top off. + if ((DRstatus & DR_TOT) != 0 && timerTOT >= timerLimitTOT) { + resetTopOffTimer(); + } + else if ((DRstatus & DR_TOO) == 0 && (DRstatus & DR_TOT) == 0) { + resetTopOffTimer(); + } + + if (simHasFailed) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The simulation has encountered an error. \n"); + } + return HPWH_ABORT; + } + + if (hpwhVerbosity >= VRB_typical) { + msg("Ending runOneStep. \n\n\n\n"); + } + + return 0; // successful completion of the step returns 0 +} // end runOneStep + +int HPWH::runNSteps(int N, + double* inletT_C, + double* drawVolume_L, + double* tankAmbientT_C, + double* heatSourceAmbientT_C, + DRMODES* DRstatus) +{ + // returns 0 on successful completion, HPWH_ABORT on failure + + // these are all the accumulating variables we'll need + double energyRemovedFromEnvironment_kWh_SUM = 0; + double standbyLosses_kWh_SUM = 0; + double outletTemp_C_AVG = 0; + double totalDrawVolume_L = 0; + std::vector heatSources_runTimes_SUM(numHeatSources); + std::vector heatSources_energyInputs_SUM(numHeatSources); + std::vector heatSources_energyOutputs_SUM(numHeatSources); + + if (hpwhVerbosity >= VRB_typical) { + msg("Begin runNSteps. \n"); + } + // run the sim one step at a time, accumulating the outputs as you go + for (int i = 0; i < N; i++) { + runOneStep( + inletT_C[i], drawVolume_L[i], tankAmbientT_C[i], heatSourceAmbientT_C[i], DRstatus[i]); + + if (simHasFailed) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("RunNSteps has encountered an error on step %d of N and has ceased running. " + "\n", + i + 1); + } + return HPWH_ABORT; + } + + energyRemovedFromEnvironment_kWh_SUM += energyRemovedFromEnvironment_kWh; + standbyLosses_kWh_SUM += standbyLosses_kWh; + + outletTemp_C_AVG += outletTemp_C * drawVolume_L[i]; + totalDrawVolume_L += drawVolume_L[i]; + + for (int j = 0; j < numHeatSources; j++) { + heatSources_runTimes_SUM[j] += getNthHeatSourceRunTime(j); + heatSources_energyInputs_SUM[j] += getNthHeatSourceEnergyInput(j); + heatSources_energyOutputs_SUM[j] += getNthHeatSourceEnergyOutput(j); + } + + // print minutely output + if (hpwhVerbosity == VRB_minuteOut) { + msg("%f,%f,%f,", tankAmbientT_C[i], drawVolume_L[i], inletT_C[i]); + for (int j = 0; j < numHeatSources; j++) { + msg("%f,%f,", getNthHeatSourceEnergyInput(j), getNthHeatSourceEnergyOutput(j)); + } + msg("%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", + tankTemps_C[0 * numNodes / 12], + tankTemps_C[1 * numNodes / 12], + tankTemps_C[2 * numNodes / 12], + tankTemps_C[3 * numNodes / 12], + tankTemps_C[4 * numNodes / 12], + tankTemps_C[5 * numNodes / 12], + tankTemps_C[6 * numNodes / 12], + tankTemps_C[7 * numNodes / 12], + tankTemps_C[8 * numNodes / 12], + tankTemps_C[9 * numNodes / 12], + getNthSimTcouple(1, 6), + getNthSimTcouple(2, 6), + getNthSimTcouple(3, 6), + getNthSimTcouple(4, 6), + getNthSimTcouple(5, 6), + getNthSimTcouple(6, 6)); + } + } + // finish weighted avg. of outlet temp by dividing by the total drawn volume + outletTemp_C_AVG /= totalDrawVolume_L; + + // now, reassign all of the accumulated values to their original spots + energyRemovedFromEnvironment_kWh = energyRemovedFromEnvironment_kWh_SUM; + standbyLosses_kWh = standbyLosses_kWh_SUM; + outletTemp_C = outletTemp_C_AVG; + + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i].runtime_min = heatSources_runTimes_SUM[i]; + setOfSources[i].energyInput_kWh = heatSources_energyInputs_SUM[i]; + setOfSources[i].energyOutput_kWh = heatSources_energyOutputs_SUM[i]; + } + + if (hpwhVerbosity >= VRB_typical) { + msg("Ending runNSteps. \n\n\n\n"); + } + return 0; +} + +void HPWH::addHeatParent(HeatSource* heatSourcePtr, + double heatSourceAmbientT_C, + double minutesToRun) +{ + + double tempSetpoint_C = -273.15; + + // Check the air temprature and setpoint against maxOut_at_LowT + if (heatSourcePtr->isACompressor()) { + if (heatSourceAmbientT_C <= heatSourcePtr->maxOut_at_LowT.airT_C && + setpoint_C >= heatSourcePtr->maxOut_at_LowT.outT_C) { + tempSetpoint_C = setpoint_C; // Store setpoint + setSetpoint(heatSourcePtr->maxOut_at_LowT + .outT_C); // Reset to new setpoint as this is used in the add heat calc + } + } + // and add heat if it is + heatSourcePtr->addHeat(heatSourceAmbientT_C, minutesToRun); + + // Change the setpoint back to what it was pre-compressor depression + if (tempSetpoint_C > -273.15) { + setSetpoint(tempSetpoint_C); + } +} + +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); + vsnprintf(outputString, MAXOUTSTRING, fmt, ap); #endif - p = outputString; - } - else { - p = fmt; - } - sayMessage(p); -} // HPWH::msgV + p = outputString; + } + else { + p = fmt; + } + sayMessage(p); +} // HPWH::msgV + +void HPWH::printHeatSourceInfo() +{ + std::stringstream ss; + double runtime = 0, outputVar = 0; + + ss << std::left; + ss << std::fixed; + ss << std::setprecision(2); + for (int i = 0; i < getNumHeatSources(); i++) { + ss << "heat source " << i << ": " << isNthHeatSourceRunning(i) << "\t\t"; + } + ss << endl; + + for (int i = 0; i < getNumHeatSources(); i++) { + ss << "input energy kwh: " << std::setw(7) << getNthHeatSourceEnergyInput(i) << "\t"; + } + ss << endl; + + for (int i = 0; i < getNumHeatSources(); i++) { + runtime = getNthHeatSourceRunTime(i); + if (runtime != 0) { + outputVar = getNthHeatSourceEnergyInput(i) / (runtime / 60.0); + } + else { + outputVar = 0; + } + ss << "input power kw: " << std::setw(7) << outputVar << "\t\t"; + } + ss << endl; + + for (int i = 0; i < getNumHeatSources(); i++) { + ss << "output energy kwh: " << std::setw(7) << getNthHeatSourceEnergyOutput(i, UNITS_KWH) + << "\t"; + } + ss << endl; + + for (int i = 0; i < getNumHeatSources(); i++) { + runtime = getNthHeatSourceRunTime(i); + if (runtime != 0) { + outputVar = getNthHeatSourceEnergyOutput(i, UNITS_KWH) / (runtime / 60.0); + } + else { + outputVar = 0; + } + ss << "output power kw: " << std::setw(7) << outputVar << "\t"; + } + ss << endl; + + for (int i = 0; i < getNumHeatSources(); i++) { + ss << "run time min: " << std::setw(7) << getNthHeatSourceRunTime(i) << "\t\t"; + } + ss << endl << endl << endl; + + msg(ss.str().c_str()); +} + +void HPWH::printTankTemps() +{ + std::stringstream ss; + ss << std::left; -void HPWH::printHeatSourceInfo() { - std::stringstream ss; - double runtime = 0, outputVar = 0; + for (int i = 0; i < getNumNodes(); i++) { + ss << std::setw(9) << getTankNodeTemp(i) << " "; + } + ss << endl; - ss << std::left; - ss << std::fixed; - ss << std::setprecision(2); - for (int i = 0; i < getNumHeatSources(); i++) { - ss << "heat source " << i << ": " << isNthHeatSourceRunning(i) << "\t\t"; - } - ss << endl; + msg(ss.str().c_str()); +} - for (int i = 0; i < getNumHeatSources(); i++) { - ss << "input energy kwh: " << std::setw(7) << getNthHeatSourceEnergyInput(i) << "\t"; - } - ss << endl; +// public members to write to CSV file +int HPWH::WriteCSVHeading(FILE* outFILE, const char* preamble, int nTCouples, int options) const +{ + + bool doIP = (options & CSVOPT_IPUNITS) != 0; - for (int i = 0; i < getNumHeatSources(); i++) { - runtime = getNthHeatSourceRunTime(i); - if (runtime != 0) { - outputVar = getNthHeatSourceEnergyInput(i) / (runtime / 60.0); - } - else { - outputVar = 0; - } - ss << "input power kw: " << std::setw(7) << outputVar << "\t\t"; - } - ss << endl; + fprintf(outFILE, "%s", preamble); - for (int i = 0; i < getNumHeatSources(); i++) { - ss << "output energy kwh: " << std::setw(7) << getNthHeatSourceEnergyOutput(i, UNITS_KWH) << "\t"; - } - ss << endl; + fprintf(outFILE, "%s", "DRstatus"); - for (int i = 0; i < getNumHeatSources(); i++) { - runtime = getNthHeatSourceRunTime(i); - if (runtime != 0) { - outputVar = getNthHeatSourceEnergyOutput(i, UNITS_KWH) / (runtime / 60.0); - } - else { - outputVar = 0; - } - ss << "output power kw: " << std::setw(7) << outputVar << "\t"; - } - ss << endl; + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { + fprintf(outFILE, ",h_src%dIn (Wh),h_src%dOut (Wh)", iHS + 1, iHS + 1); + } - for (int i = 0; i < getNumHeatSources(); i++) { - ss << "run time min: " << std::setw(7) << getNthHeatSourceRunTime(i) << "\t\t"; - } - ss << endl << endl << endl; + for (int iTC = 0; iTC < nTCouples; iTC++) { + fprintf(outFILE, ",tcouple%d (%s)", iTC + 1, doIP ? "F" : "C"); + } + fprintf(outFILE, "\n"); - msg(ss.str().c_str()); + return 0; } +int HPWH::WriteCSVRow(FILE* outFILE, const char* preamble, int nTCouples, int options) const +{ + + bool doIP = (options & CSVOPT_IPUNITS) != 0; -void HPWH::printTankTemps() { - std::stringstream ss; + fprintf(outFILE, "%s", preamble); - ss << std::left; + fprintf(outFILE, "%i", prevDRstatus); - for (int i = 0; i < getNumNodes(); i++) { - ss << std::setw(9) << getTankNodeTemp(i) << " "; - } - ss << endl; + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { + fprintf(outFILE, + ",%0.2f,%0.2f", + getNthHeatSourceEnergyInput(iHS, UNITS_KWH) * 1000., + getNthHeatSourceEnergyOutput(iHS, UNITS_KWH) * 1000.); + } - msg(ss.str().c_str()); + for (int iTC = 0; iTC < nTCouples; iTC++) { + fprintf(outFILE, ",%0.2f", getNthSimTcouple(iTC + 1, nTCouples, doIP ? UNITS_F : UNITS_C)); + } + + fprintf(outFILE, "\n"); + + return 0; } +bool HPWH::isSetpointFixed() const { return setpointFixed; } -// public members to write to CSV file -int HPWH::WriteCSVHeading(FILE* outFILE, const char* preamble, int nTCouples, int options) const { +int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) +{ + + double newSetpoint_C, temp; + string why; + if (units == UNITS_C) { + newSetpoint_C = newSetpoint; + } + else if (units == UNITS_F) { + newSetpoint_C = F_TO_C(newSetpoint); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for setSetpoint. \n"); + } + return HPWH_ABORT; + } + if (!isNewSetpointPossible(newSetpoint_C, temp, why)) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Unwilling to set this setpoint for the currently selected model, max setpoint is " + "%f C. %s\n", + temp, + why.c_str()); + } + return HPWH_ABORT; + } + + setpoint_C = newSetpoint_C; + + return 0; +} + +double HPWH::getSetpoint(UNITS units /*=UNITS_C*/) const +{ + if (units == UNITS_C) { + return setpoint_C; + } + else if (units == UNITS_F) { + return C_TO_F(setpoint_C); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getSetpoint. \n"); + } + return HPWH_ABORT; + } +} + +double HPWH::getMaxCompressorSetpoint(UNITS units /*=UNITS_C*/) const +{ + + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Unit does not have a compressor \n"); + } + return HPWH_ABORT; + } + + double returnVal = setOfSources[compressorIndex].maxSetpoint_C; + if (units == UNITS_C) { + returnVal = returnVal; + } + else if (units == UNITS_F) { + returnVal = C_TO_F(returnVal); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getMaxCompressorSetpoint. \n"); + } + return HPWH_ABORT; + } + return returnVal; +} + +bool HPWH::isNewSetpointPossible(double newSetpoint, + double& maxAllowedSetpoint, + string& why, + UNITS units /*=UNITS_C*/) const +{ + double newSetpoint_C; + double maxAllowedSetpoint_C = -273.15; + if (units == UNITS_C) { + newSetpoint_C = newSetpoint; + } + else if (units == UNITS_F) { + newSetpoint_C = F_TO_C(newSetpoint); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for isNewSetpointPossible. \n"); + } + return false; + } + bool returnVal = false; + + if (isSetpointFixed()) { + returnVal = (newSetpoint == setpoint_C); + maxAllowedSetpoint_C = setpoint_C; + if (!returnVal) { + why = "The set point is fixed for the currently selected model."; + } + } + else { + + if (hasACompressor()) { // If there's a compressor lets check the new setpoint against the + // compressor's max setpoint + + maxAllowedSetpoint_C = + setOfSources[compressorIndex].maxSetpoint_C - + setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; + + if (newSetpoint_C > maxAllowedSetpoint_C && lowestElementIndex == -1) { + why = "The compressor cannot meet the setpoint temperature and there is no " + "resistance backup."; + returnVal = false; + } + else { + returnVal = true; + } + } + if (lowestElementIndex >= 0) { // If there's a resistance element lets check the new + // setpoint against the its max setpoint + maxAllowedSetpoint_C = setOfSources[lowestElementIndex].maxSetpoint_C; + + if (newSetpoint_C > maxAllowedSetpoint_C) { + why = "The resistance elements cannot produce water this hot."; + returnVal = false; + } + else { + returnVal = true; + } + } + else if (lowestElementIndex == -1 && !hasACompressor()) { // There are no heat sources here! + if (hpwhModel == MODELS_StorageTank) { + returnVal = true; // The one pass the storage tank doesn't have any heating elements + // so sure change the setpoint it does nothing! + } + else { + why = "There aren't any heat sources to check the new setpoint against!"; + returnVal = false; + } + } + } + + if (units == UNITS_C) { + maxAllowedSetpoint = maxAllowedSetpoint_C; + } + else if (units == UNITS_F) { + maxAllowedSetpoint = C_TO_F(maxAllowedSetpoint_C); + } + return returnVal; +} + +double HPWH::calcSoCFraction(double tMains_C, double tMinUseful_C, double tMax_C) const +{ + // Note that volume is ignored in here since with even nodes it cancels out of the SoC + // fractional equation + if (tMains_C >= tMinUseful_C) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("tMains_C is greater than or equal tMinUseful_C. \n"); + } + return HPWH_ABORT; + } + if (tMinUseful_C > tMax_C) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("tMinUseful_C is greater tMax_C. \n"); + } + return HPWH_ABORT; + } + + double chargeEquivalent = 0.; + for (int i = 0; i < numNodes; i++) { + chargeEquivalent += getChargePerNode(tMains_C, tMinUseful_C, tankTemps_C[i]); + } + double maxSoC = numNodes * getChargePerNode(tMains_C, tMinUseful_C, tMax_C); + return chargeEquivalent / maxSoC; +} + +double HPWH::getSoCFraction() const { return currentSoCFraction; } + +void HPWH::calcAndSetSoCFraction() +{ + double newSoCFraction = -1.; + + std::shared_ptr logicSoC = + std::dynamic_pointer_cast( + setOfSources[compressorIndex].turnOnLogicSet[0]); + newSoCFraction = calcSoCFraction(logicSoC->getMainsT_C(), logicSoC->getTempMinUseful_C()); + + currentSoCFraction = newSoCFraction; +} + +double HPWH::getChargePerNode(double tCold, double tMix, double tHot) const +{ + if (tHot < tMix) { + return 0.; + } + return (tHot - tCold) / (tMix - tCold); +} + +double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const +{ + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("No compressor found in this HPWH. \n"); + } + return HPWH_ABORT; + } + if (units == UNITS_C) { + return setOfSources[compressorIndex].minT; + } + else if (units == UNITS_F) { + return C_TO_F(setOfSources[compressorIndex].minT); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getMinOperatingTemp.\n"); + } + return HPWH_ABORT; + } +} + +int HPWH::resetTankToSetpoint() { return setTankToTemperature(setpoint_C); } + +int HPWH::setTankToTemperature(double temp_C) +{ + for (int i = 0; i < numNodes; i++) { + tankTemps_C[i] = temp_C; + } + return 0; +} + +int HPWH::setAirFlowFreedom(double fanFraction) +{ + if (fanFraction < 0 || fanFraction > 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to set the fan fraction outside of bounds. \n"); + } + simHasFailed = true; + return HPWH_ABORT; + } + else { + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isACompressor()) { + setOfSources[i].airflowFreedom = fanFraction; + } + } + } + return 0; +} + +int HPWH::setDoTempDepression(bool doTempDepress) +{ + this->doTempDepression = doTempDepress; + return 0; +} + +int HPWH::setTankSize_adjustUA(double HPWH_size, + UNITS units /*=UNITS_L*/, + bool forceChange /*=false*/) +{ + // Uses the UA before the function is called and adjusts the A part of the UA to match the input + // volume given getTankSurfaceArea(). + double HPWH_size_L; + double oldA = getTankSurfaceArea(UNITS_FT2); + + if (units == UNITS_L) { + HPWH_size_L = HPWH_size; + } + else if (units == UNITS_GAL) { + HPWH_size_L = GAL_TO_L(HPWH_size); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for setTankSize_adjustUA. \n"); + } + return HPWH_ABORT; + } + setTankSize(HPWH_size_L, UNITS_L, forceChange); + setUA(tankUA_kJperHrC / oldA * getTankSurfaceArea(UNITS_FT2), UNITS_kJperHrC); + return 0; +} + +/*static*/ double +HPWH::getTankSurfaceArea(double vol, UNITS volUnits /*=UNITS_L*/, UNITS surfAUnits /*=UNITS_FT2*/) +{ + // returns tank surface area, old defualt was in ft2 + // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, + // HTP, Rheem, and Niles. Corresponds to the inner tank with volume tankVolume_L with the + // assumption that the aspect ratio is the same as the outer dimenisions of the whole unit. + double radius = getTankRadius(vol, volUnits, UNITS_FT); + + double value = 2. * 3.14159 * pow(radius, 2) * (ASPECTRATIO + 1.); + + if (value >= 0.) { + if (surfAUnits == UNITS_M2) + value = FT2_TO_M2(value); + else if (surfAUnits != UNITS_FT2) + value = -1.; + } + return value; +} + +double HPWH::getTankSurfaceArea(UNITS units /*=UNITS_FT2*/) const +{ + // returns tank surface area, old defualt was in ft2 + // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, + // HTP, Rheem, and Niles. Corresponds to the inner tank with volume tankVolume_L with the + // assumption that the aspect ratio is the same as the outer dimenisions of the whole unit. + double value = getTankSurfaceArea(tankVolume_L, UNITS_L, units); + if (value < 0.) { + if (hpwhVerbosity >= VRB_reluctant) + msg("Incorrect unit specification for getTankSurfaceArea. \n"); + value = HPWH_ABORT; + } + return value; +} + +/*static*/ double +HPWH::getTankRadius(double vol, UNITS volUnits /*=UNITS_L*/, UNITS radiusUnits /*=UNITS_FT*/) +{ // returns tank radius, ft for use in calculation of heat loss in the bottom and top of the tank. + // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, + // HTP, Rheem, and Niles, assumes the aspect ratio for the outer measurements is the same is the + // actual tank. + double volft3 = volUnits == UNITS_L ? L_TO_FT3(vol) + : volUnits == UNITS_GAL ? L_TO_FT3(GAL_TO_L(vol)) + : -1.; + + double value = -1.; + if (volft3 >= 0.) { + value = pow(volft3 / 3.14159 / ASPECTRATIO, 1. / 3.); + if (radiusUnits == UNITS_M) + value = FT_TO_M(value); + else if (radiusUnits != UNITS_FT) + value = -1.; + } + return value; +} + +double HPWH::getTankRadius(UNITS units /*=UNITS_FT*/) const +{ + // returns tank radius, ft for use in calculation of heat loss in the bottom and top of the + // tank. Based off 88 insulated storage tanks currently available on the market from Sanden, + // AOSmith, HTP, Rheem, and Niles, assumes the aspect ratio for the outer measurements is the + // same is the actual tank. + + double value = getTankRadius(tankVolume_L, UNITS_L, units); + + if (value < 0.) { + if (hpwhVerbosity >= VRB_reluctant) + msg("Incorrect unit specification for getTankRadius. \n"); + value = HPWH_ABORT; + } + return value; +} + +bool HPWH::isTankSizeFixed() const { return tankSizeFixed; } + +int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChange /*=false*/) +{ + if (isTankSizeFixed() && !forceChange) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not change the tank size for your currently selected model. \n"); + } + return HPWH_ABORT; + } + if (HPWH_size <= 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to set the tank volume outside of bounds. \n"); + } + simHasFailed = true; + return HPWH_ABORT; + } + else { + if (units == UNITS_L) { + this->tankVolume_L = HPWH_size; + } + else if (units == UNITS_GAL) { + this->tankVolume_L = (GAL_TO_L(HPWH_size)); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for setTankSize. \n"); + } + return HPWH_ABORT; + } + } + + calcSizeConstants(); + + return 0; +} +int HPWH::setDoInversionMixing(bool doInvMix) +{ + this->doInversionMixing = doInvMix; + return 0; +} +int HPWH::setDoConduction(bool doCondu) +{ + this->doConduction = doCondu; + return 0; +} + +int HPWH::setUA(double UA, UNITS units /*=UNITS_kJperHrC*/) +{ + if (units == UNITS_kJperHrC) { + tankUA_kJperHrC = UA; + } + else if (units == UNITS_BTUperHrF) { + tankUA_kJperHrC = UAf_TO_UAc(UA); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for setUA. \n"); + } + return HPWH_ABORT; + } + return 0; +} + +int HPWH::getUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const +{ + UA = tankUA_kJperHrC; + if (units == UNITS_kJperHrC) { + // UA is already in correct units + } + else if (units == UNITS_BTUperHrF) { + UA = UA / UAf_TO_UAc(1.); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getUA. \n"); + } + UA = -1.; + return HPWH_ABORT; + } + return 0; +} + +int HPWH::setFittingsUA(double UA, UNITS units /*=UNITS_kJperHrC*/) +{ + if (units == UNITS_kJperHrC) { + fittingsUA_kJperHrC = UA; + } + else if (units == UNITS_BTUperHrF) { + fittingsUA_kJperHrC = UAf_TO_UAc(UA); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for setFittingsUA. \n"); + } + return HPWH_ABORT; + } + return 0; +} +int HPWH::getFittingsUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const +{ + UA = fittingsUA_kJperHrC; + if (units == UNITS_kJperHrC) { + // UA is already in correct units + } + else if (units == UNITS_BTUperHrF) { + UA = UA / UAf_TO_UAc(1.); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getUA. \n"); + } + UA = -1.; + return HPWH_ABORT; + } + return 0; +} + +int HPWH::setInletByFraction(double fractionalHeight) +{ + return setNodeNumFromFractionalHeight(fractionalHeight, inletHeight); +} +int HPWH::setInlet2ByFraction(double fractionalHeight) +{ + return setNodeNumFromFractionalHeight(fractionalHeight, inlet2Height); +} - bool doIP = (options & CSVOPT_IPUNITS) != 0; +int HPWH::setExternalInletHeightByFraction(double fractionalHeight) +{ + return setExternalPortHeightByFraction(fractionalHeight, 1); +} +int HPWH::setExternalOutletHeightByFraction(double fractionalHeight) +{ + return setExternalPortHeightByFraction(fractionalHeight, 2); +} - fprintf(outFILE, "%s", preamble); +int HPWH::setExternalPortHeightByFraction(double fractionalHeight, int whichExternalPort) +{ + if (!hasExternalHeatSource()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Does not have an external heat source \n"); + } + return HPWH_ABORT; + } + + int returnVal = 0; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + if (whichExternalPort == 1) { + returnVal = setNodeNumFromFractionalHeight(fractionalHeight, + setOfSources[i].externalInletHeight); + } + else { + returnVal = setNodeNumFromFractionalHeight(fractionalHeight, + setOfSources[i].externalOutletHeight); + } + + if (returnVal == HPWH_ABORT) { + return returnVal; + } + } + } + return returnVal; +} + +int HPWH::setNodeNumFromFractionalHeight(double fractionalHeight, int& inletNum) +{ + if (fractionalHeight > 1. || fractionalHeight < 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds fraction for setInletByFraction \n"); + } + return HPWH_ABORT; + } - fprintf(outFILE, "%s", "DRstatus"); + int node = (int)std::floor(numNodes * fractionalHeight); + inletNum = (node == numNodes) ? numNodes - 1 : node; - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { - fprintf(outFILE, ",h_src%dIn (Wh),h_src%dOut (Wh)", iHS + 1, iHS + 1); - } + return 0; +} - for (int iTC = 0; iTC < nTCouples; iTC++) { - fprintf(outFILE, ",tcouple%d (%s)", iTC + 1, doIP ? "F" : "C"); - } +int HPWH::getExternalInletHeight() const +{ + if (!hasExternalHeatSource()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Does not have an external heat source \n"); + } + return HPWH_ABORT; + } + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + return setOfSources[i].externalInletHeight; // Return the first one since all external + // sources have some ports + } + } + return HPWH_ABORT; +} +int HPWH::getExternalOutletHeight() const +{ + if (!hasExternalHeatSource()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Does not have an external heat source \n"); + } + return HPWH_ABORT; + } + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + return setOfSources[i].externalOutletHeight; // Return the first one since all external + // sources have some ports + } + } + return HPWH_ABORT; +} + +int HPWH::setTimerLimitTOT(double limit_min) +{ + if (limit_min > 24. * 60. || limit_min < 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds time limit for setTimerLimitTOT \n"); + } + return HPWH_ABORT; + } - fprintf(outFILE, "\n"); + timerLimitTOT = limit_min; - return 0; + return 0; } -int HPWH::WriteCSVRow(FILE* outFILE, const char* preamble, int nTCouples, int options) const { +double HPWH::getTimerLimitTOT_minute() const { return timerLimitTOT; } - bool doIP = (options & CSVOPT_IPUNITS) != 0; - - fprintf(outFILE, "%s", preamble); - - fprintf(outFILE, "%i", prevDRstatus); - - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { - fprintf(outFILE, ",%0.2f,%0.2f", getNthHeatSourceEnergyInput(iHS, UNITS_KWH)*1000., - getNthHeatSourceEnergyOutput(iHS, UNITS_KWH)*1000.); - } - - for (int iTC = 0; iTC < nTCouples; iTC++) { - fprintf(outFILE, ",%0.2f", getNthSimTcouple(iTC + 1, nTCouples, doIP ? UNITS_F : UNITS_C)); - } - - fprintf(outFILE, "\n"); - - return 0; -} - - -bool HPWH::isSetpointFixed() const{ - return setpointFixed; -} - -int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) { - - double newSetpoint_C, temp; - string why; - if (units == UNITS_C) { - newSetpoint_C = newSetpoint; - } - else if (units == UNITS_F) { - newSetpoint_C = F_TO_C(newSetpoint); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for setSetpoint. \n"); - } - return HPWH_ABORT; - } - if (!isNewSetpointPossible(newSetpoint_C, temp, why)) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Unwilling to set this setpoint for the currently selected model, max setpoint is %f C. %s\n", temp, why.c_str()); - } - return HPWH_ABORT; - } - - setpoint_C = newSetpoint_C; - - return 0; -} - -double HPWH::getSetpoint(UNITS units /*=UNITS_C*/) const{ - if (units == UNITS_C) { - return setpoint_C; - } - else if (units == UNITS_F) { - return C_TO_F(setpoint_C); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getSetpoint. \n"); - } - return HPWH_ABORT; - } -} - -double HPWH::getMaxCompressorSetpoint(UNITS units /*=UNITS_C*/) const { - - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Unit does not have a compressor \n"); - } - return HPWH_ABORT; - } - - double returnVal = setOfSources[compressorIndex].maxSetpoint_C; - if (units == UNITS_C) { - returnVal = returnVal; - } - else if (units == UNITS_F) { - returnVal = C_TO_F(returnVal); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getMaxCompressorSetpoint. \n"); - } - return HPWH_ABORT; - } - return returnVal; -} - -bool HPWH::isNewSetpointPossible(double newSetpoint, double& maxAllowedSetpoint, string& why, UNITS units /*=UNITS_C*/) const { - double newSetpoint_C; - double maxAllowedSetpoint_C = -273.15; - if (units == UNITS_C) { - newSetpoint_C = newSetpoint; - } - else if (units == UNITS_F) { - newSetpoint_C = F_TO_C(newSetpoint); - } else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for isNewSetpointPossible. \n"); - } - return false; - } - bool returnVal = false; - - if (isSetpointFixed()) { - returnVal = (newSetpoint == setpoint_C); - maxAllowedSetpoint_C = setpoint_C; - if (!returnVal) { - why = "The set point is fixed for the currently selected model."; - } - } - else { - - if (hasACompressor()) { // If there's a compressor lets check the new setpoint against the compressor's max setpoint - - maxAllowedSetpoint_C = setOfSources[compressorIndex].maxSetpoint_C - - setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; - - if (newSetpoint_C > maxAllowedSetpoint_C && lowestElementIndex == -1) { - why = "The compressor cannot meet the setpoint temperature and there is no resistance backup."; - returnVal = false; - } - else { - returnVal = true; - } - } - if (lowestElementIndex >= 0) { // If there's a resistance element lets check the new setpoint against the its max setpoint - maxAllowedSetpoint_C = setOfSources[lowestElementIndex].maxSetpoint_C; - - if (newSetpoint_C > maxAllowedSetpoint_C) { - why = "The resistance elements cannot produce water this hot."; - returnVal = false; - } - else { - returnVal = true; - } - } - else if (lowestElementIndex == -1 && !hasACompressor()) { // There are no heat sources here! - if (hpwhModel == MODELS_StorageTank) { - returnVal = true; // The one pass the storage tank doesn't have any heating elements so sure change the setpoint it does nothing! - } - else { - why = "There aren't any heat sources to check the new setpoint against!"; - returnVal = false; - } - } - } - - if (units == UNITS_C) { - maxAllowedSetpoint = maxAllowedSetpoint_C; - } - else if (units == UNITS_F) { - maxAllowedSetpoint = C_TO_F(maxAllowedSetpoint_C); - } - return returnVal; -} - -double HPWH::calcSoCFraction(double tMains_C, double tMinUseful_C, double tMax_C) const { - // Note that volume is ignored in here since with even nodes it cancels out of the SoC fractional equation - if (tMains_C >= tMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("tMains_C is greater than or equal tMinUseful_C. \n"); - } - return HPWH_ABORT; - } - if (tMinUseful_C > tMax_C) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("tMinUseful_C is greater tMax_C. \n"); - } - return HPWH_ABORT; - } - - double chargeEquivalent = 0.; - for (int i = 0; i < numNodes; i++) { - chargeEquivalent += getChargePerNode(tMains_C, tMinUseful_C, tankTemps_C[i]); - } - double maxSoC = numNodes * getChargePerNode(tMains_C, tMinUseful_C, tMax_C); - return chargeEquivalent / maxSoC; -} - -double HPWH::getSoCFraction() const { - return currentSoCFraction; -} - -void HPWH::calcAndSetSoCFraction() { - double newSoCFraction = -1.; - - std::shared_ptr logicSoC = std::dynamic_pointer_cast(setOfSources[compressorIndex].turnOnLogicSet[0]); - newSoCFraction = calcSoCFraction(logicSoC->getMainsT_C(), logicSoC->getTempMinUseful_C()); - - currentSoCFraction = newSoCFraction; -} - -double HPWH::getChargePerNode(double tCold, double tMix, double tHot) const { - if (tHot < tMix) { - return 0.; - } - return (tHot - tCold) / (tMix - tCold); -} - -double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("No compressor found in this HPWH. \n"); - } - return HPWH_ABORT; - } - if (units == UNITS_C) { - return setOfSources[compressorIndex].minT; - } - else if (units == UNITS_F) { - return C_TO_F(setOfSources[compressorIndex].minT); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getMinOperatingTemp.\n"); - } - return HPWH_ABORT; - } -} - -int HPWH::resetTankToSetpoint() { - return setTankToTemperature(setpoint_C); -} - -int HPWH::setTankToTemperature(double temp_C) { - for (int i = 0; i < numNodes; i++) { - tankTemps_C[i] = temp_C; - } - return 0; -} - - -int HPWH::setAirFlowFreedom(double fanFraction) { - if (fanFraction < 0 || fanFraction > 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to set the fan fraction outside of bounds. \n"); - } - simHasFailed = true; - return HPWH_ABORT; - } - else { - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { - setOfSources[i].airflowFreedom = fanFraction; - } - } - } - return 0; -} - -int HPWH::setDoTempDepression(bool doTempDepress) { - this->doTempDepression = doTempDepress; - return 0; -} - -int HPWH::setTankSize_adjustUA(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChange /*=false*/) { - //Uses the UA before the function is called and adjusts the A part of the UA to match the input volume given getTankSurfaceArea(). - double HPWH_size_L; - double oldA = getTankSurfaceArea(UNITS_FT2); - - if (units == UNITS_L) { - HPWH_size_L = HPWH_size; - } - else if (units == UNITS_GAL) { - HPWH_size_L = GAL_TO_L(HPWH_size); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for setTankSize_adjustUA. \n"); - } - return HPWH_ABORT; - } - setTankSize(HPWH_size_L, UNITS_L, forceChange); - setUA(tankUA_kJperHrC / oldA * getTankSurfaceArea(UNITS_FT2), UNITS_kJperHrC); - return 0; -} - -/*static*/ double HPWH::getTankSurfaceArea(double vol, UNITS volUnits/*=UNITS_L*/, UNITS surfAUnits /*=UNITS_FT2*/) -{ - // returns tank surface area, old defualt was in ft2 - // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, HTP, Rheem, and Niles. - // Corresponds to the inner tank with volume tankVolume_L with the assumption that the aspect ratio is the same - // as the outer dimenisions of the whole unit. - double radius = getTankRadius(vol, volUnits, UNITS_FT); - - double value = 2. * 3.14159 * pow(radius, 2) * (ASPECTRATIO + 1.); - - if (value >= 0.) - { if (surfAUnits == UNITS_M2) - value = FT2_TO_M2(value); - else if (surfAUnits != UNITS_FT2) - value = -1.; - } - return value; -} - -double HPWH::getTankSurfaceArea(UNITS units /*=UNITS_FT2*/) const { - // returns tank surface area, old defualt was in ft2 - // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, HTP, Rheem, and Niles. - // Corresponds to the inner tank with volume tankVolume_L with the assumption that the aspect ratio is the same - // as the outer dimenisions of the whole unit. - double value = getTankSurfaceArea(tankVolume_L, UNITS_L, units); - if (value < 0.) - { if (hpwhVerbosity >= VRB_reluctant) - msg("Incorrect unit specification for getTankSurfaceArea. \n"); - value = HPWH_ABORT; - } - return value; -} - -/*static*/ double HPWH::getTankRadius(double vol, UNITS volUnits/*=UNITS_L*/, UNITS radiusUnits /*=UNITS_FT*/) -{ // returns tank radius, ft for use in calculation of heat loss in the bottom and top of the tank. - // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, HTP, Rheem, and Niles, - // assumes the aspect ratio for the outer measurements is the same is the actual tank. - double volft3 = - volUnits == UNITS_L ? L_TO_FT3(vol) - : volUnits == UNITS_GAL ? L_TO_FT3(GAL_TO_L(vol)) - : -1.; - - double value = -1.; - if (volft3 >= 0.) - { value = pow(volft3 / 3.14159 / ASPECTRATIO, 1. / 3.); - if (radiusUnits == UNITS_M) - value = FT_TO_M(value); - else if (radiusUnits != UNITS_FT) - value = -1.; - } - return value; -} - -double HPWH::getTankRadius(UNITS units /*=UNITS_FT*/) const{ - // returns tank radius, ft for use in calculation of heat loss in the bottom and top of the tank. - // Based off 88 insulated storage tanks currently available on the market from Sanden, AOSmith, HTP, Rheem, and Niles, - // assumes the aspect ratio for the outer measurements is the same is the actual tank. - - double value = getTankRadius(tankVolume_L, UNITS_L, units); - - if (value < 0.) - { if (hpwhVerbosity >= VRB_reluctant) - msg("Incorrect unit specification for getTankRadius. \n"); - value = HPWH_ABORT; - } - return value; -} - - -bool HPWH::isTankSizeFixed() const{ - return tankSizeFixed; -} - -int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChange /*=false*/) { - if (isTankSizeFixed() && !forceChange) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not change the tank size for your currently selected model. \n"); - } - return HPWH_ABORT; - } - if (HPWH_size <= 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to set the tank volume outside of bounds. \n"); - } - simHasFailed = true; - return HPWH_ABORT; - } - else { - if (units == UNITS_L) { - this->tankVolume_L = HPWH_size; - } - else if (units == UNITS_GAL) { - this->tankVolume_L = (GAL_TO_L(HPWH_size)); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for setTankSize. \n"); - } - return HPWH_ABORT; - } - } - - calcSizeConstants(); - - return 0; -} -int HPWH::setDoInversionMixing(bool doInvMix) { - this->doInversionMixing = doInvMix; - return 0; -} -int HPWH::setDoConduction(bool doCondu) { - this->doConduction = doCondu; - return 0; -} - -int HPWH::setUA(double UA, UNITS units /*=UNITS_kJperHrC*/) { - if (units == UNITS_kJperHrC) { - tankUA_kJperHrC = UA; - } - else if (units == UNITS_BTUperHrF) { - tankUA_kJperHrC = UAf_TO_UAc(UA); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for setUA. \n"); - } - return HPWH_ABORT; - } - return 0; -} - -int HPWH::getUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const { - UA = tankUA_kJperHrC; - if (units == UNITS_kJperHrC) { - // UA is already in correct units - } - else if (units == UNITS_BTUperHrF) { - UA = UA / UAf_TO_UAc(1.); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getUA. \n"); - } - UA = -1.; - return HPWH_ABORT; - } - return 0; -} - -int HPWH::setFittingsUA(double UA, UNITS units /*=UNITS_kJperHrC*/) { - if (units == UNITS_kJperHrC) { - fittingsUA_kJperHrC = UA; - } - else if (units == UNITS_BTUperHrF) { - fittingsUA_kJperHrC = UAf_TO_UAc(UA); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for setFittingsUA. \n"); - } - return HPWH_ABORT; - } - return 0; -} -int HPWH::getFittingsUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const { - UA = fittingsUA_kJperHrC; - if (units == UNITS_kJperHrC) { - // UA is already in correct units - } - else if (units == UNITS_BTUperHrF) { - UA = UA / UAf_TO_UAc(1.); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getUA. \n"); - } - UA = -1.; - return HPWH_ABORT; - } - return 0; -} - -int HPWH::setInletByFraction(double fractionalHeight) { - return setNodeNumFromFractionalHeight(fractionalHeight, inletHeight); -} -int HPWH::setInlet2ByFraction(double fractionalHeight) { - return setNodeNumFromFractionalHeight(fractionalHeight, inlet2Height); -} - -int HPWH::setExternalInletHeightByFraction(double fractionalHeight) { - return setExternalPortHeightByFraction(fractionalHeight, 1); -} -int HPWH::setExternalOutletHeightByFraction(double fractionalHeight) { - return setExternalPortHeightByFraction(fractionalHeight, 2); -} - -int HPWH::setExternalPortHeightByFraction(double fractionalHeight, int whichExternalPort) { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Does not have an external heat source \n"); - } - return HPWH_ABORT; - } - - int returnVal = 0; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - if (whichExternalPort == 1) { - returnVal = setNodeNumFromFractionalHeight(fractionalHeight, setOfSources[i].externalInletHeight); - } - else { - returnVal = setNodeNumFromFractionalHeight(fractionalHeight, setOfSources[i].externalOutletHeight); - } - - if (returnVal == HPWH_ABORT) { - return returnVal; - } - } - } - return returnVal; -} - -int HPWH::setNodeNumFromFractionalHeight(double fractionalHeight, int &inletNum) { - if (fractionalHeight > 1. || fractionalHeight < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds fraction for setInletByFraction \n"); - } - return HPWH_ABORT; - } - - int node = (int)std::floor(numNodes*fractionalHeight); - inletNum = (node == numNodes) ? numNodes - 1 : node; - - return 0; -} - -int HPWH::getExternalInletHeight() const { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Does not have an external heat source \n"); - } - return HPWH_ABORT; - } - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - return setOfSources[i].externalInletHeight; // Return the first one since all external sources have some ports - } - } - return HPWH_ABORT; -} -int HPWH::getExternalOutletHeight() const { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Does not have an external heat source \n"); - } - return HPWH_ABORT; - } - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - return setOfSources[i].externalOutletHeight; // Return the first one since all external sources have some ports - } - } - return HPWH_ABORT; -} - - -int HPWH::setTimerLimitTOT(double limit_min) { - if (limit_min > 24.*60. || limit_min < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds time limit for setTimerLimitTOT \n"); - } - return HPWH_ABORT; - } - - timerLimitTOT = limit_min; - - return 0; -} - -double HPWH::getTimerLimitTOT_minute() const { - return timerLimitTOT; -} - -int HPWH::getInletHeight(int whichInlet) const { - if (whichInlet == 1) { - return inletHeight; - } - else if (whichInlet == 2) { - return inlet2Height; - } - else - { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Invalid inlet chosen in getInletHeight \n"); - } - return HPWH_ABORT; - } -} - -int HPWH::setMaxTempDepression(double maxDepression, UNITS units /*=UNITS_C*/) { - if (units == UNITS_C) { - this->maxDepression_C = maxDepression; - } - else if (units == UNITS_F) { - this->maxDepression_C = F_TO_C(maxDepression); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for max Temp Depression. \n"); - } - return HPWH_ABORT; - } - return 0; -} - -bool HPWH::hasEnteringWaterHighTempShutOff(int heatSourceIndex) { - bool retVal = false; - if (heatSourceIndex >= numHeatSources || heatSourceIndex < 0) { - return retVal; - } - if (setOfSources[heatSourceIndex].shutOffLogicSet.size() == 0) { - return retVal; - } - - for (std::shared_ptr shutOffLogic : setOfSources[heatSourceIndex].shutOffLogicSet) { - if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { - retVal = true; - break; - } - } - return retVal; -} - -int HPWH::setEnteringWaterHighTempShutOff(double highTemp, bool tempIsAbsolute, int heatSourceIndex, UNITS unit /*=UNITS_C*/) { - if (!hasEnteringWaterHighTempShutOff(heatSourceIndex)) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to acess a heating logic that does not exist. \n"); - } - return HPWH_ABORT; - } - - double highTemp_C; - if (unit == UNITS_C) { - highTemp_C = highTemp; - } - else if (unit == UNITS_F) { - highTemp_C = F_TO_C(highTemp); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for set Entering Water High Temp Shut Off. \n"); - } - return HPWH_ABORT; - } - - bool highTempIsNotValid = false; - if (tempIsAbsolute) { - // check differnce with setpoint - if (setpoint_C - highTemp_C < MINSINGLEPASSLIFT) { - highTempIsNotValid = true; - } - } - else { - if (highTemp_C < MINSINGLEPASSLIFT) { - highTempIsNotValid = true; - } - } - if (highTempIsNotValid) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("High temperature shut off is too close to the setpoint, excpected a minimum difference of %.2lf.\n", - MINSINGLEPASSLIFT); - } - return HPWH_ABORT; - } - - for (std::shared_ptr shutOffLogic : setOfSources[heatSourceIndex].shutOffLogicSet) { - if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { - std::dynamic_pointer_cast(shutOffLogic)->setDecisionPoint(highTemp_C, tempIsAbsolute); - break; - } - } - return 0; -} - -int HPWH::setTargetSoCFraction(double target) { - if (!isSoCControlled()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not set target state of charge if HPWH is not using state of charge controls."); - } - return HPWH_ABORT; - } - if (target < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not set a negative target state of charge."); - } - return HPWH_ABORT; - } - - for (int i = 0; i < numHeatSources; i++) { - for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { - if (!logic->getIsEnteringWaterHighTempShutoff()) { - logic->setDecisionPoint(target); - } - } - for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { - logic->setDecisionPoint(target); - } - } - return 0; -} - -bool HPWH::isSoCControlled() const { - return usesSoCLogic; -} - -bool HPWH::canUseSoCControls() { - bool retVal = true; - if (getCompressorCoilConfig() != HPWH::HeatSource::CONFIG_EXTERNAL) { - retVal = false; - } - return retVal; -} - -int HPWH::switchToSoCControls(double targetSoC, double hysteresisFraction /*= 0.05*/, double tempMinUseful /*= 43.333*/, bool constantMainsT /*= false*/, - double mainsT /*= 18.333*/, UNITS tempUnit /*= UNITS_C*/) { - if (!canUseSoCControls()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Cannot set up state of charge controls for integrated or wrapped HPWHs.\n"); - } - return HPWH_ABORT; - } - - double tempMinUseful_C, mainsT_C; - if (tempUnit == UNITS_C) { - tempMinUseful_C = tempMinUseful; - mainsT_C = mainsT; - } - else if (tempUnit == UNITS_F) { - tempMinUseful_C = F_TO_C(tempMinUseful); - mainsT_C = F_TO_C(mainsT); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for set Enterinh Water High Temp Shut Off.\n"); - } - return HPWH_ABORT; - } - - if (mainsT_C >= tempMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The mains temperature can't be equal to or greater than the minimum useful temperature.\n"); - } - return HPWH_ABORT; - } - - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i].clearAllTurnOnLogic(); - - setOfSources[i].shutOffLogicSet.erase(std::remove_if(setOfSources[i].shutOffLogicSet.begin(), - setOfSources[i].shutOffLogicSet.end(), - [&](const auto logic)-> bool - { return !logic->getIsEnteringWaterHighTempShutoff(); }), - setOfSources[i].shutOffLogicSet.end()); - - setOfSources[i].shutOffLogicSet.push_back(shutOffSoC("SoC Shut Off", targetSoC, hysteresisFraction, tempMinUseful_C, constantMainsT, mainsT_C)); - setOfSources[i].turnOnLogicSet.push_back(turnOnSoC("SoC Turn On", targetSoC, hysteresisFraction, tempMinUseful_C, constantMainsT, mainsT_C)); - } - - usesSoCLogic = true; - - return 0; -} - -std::shared_ptr HPWH::turnOnSoC(string desc, double targetSoC, double hystFract, double tempMinUseful_C, - bool constantMainsT, double mainsT_C) { - return std::make_shared(desc, targetSoC, this, -hystFract, tempMinUseful_C, constantMainsT, mainsT_C); -} - -std::shared_ptr HPWH::shutOffSoC(string desc, double targetSoC, double hystFract, double tempMinUseful_C, - bool constantMainsT, double mainsT_C) { - return std::make_shared(desc, targetSoC, this, hystFract, tempMinUseful_C, constantMainsT, mainsT_C, std::greater()); -} - -std::shared_ptr HPWH::topThird(double d) { - std::vector nodeWeights; - for (int i : { 9, 10, 11, 12 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top third", nodeWeights, d, this); -} - -std::shared_ptr HPWH::topThird_absolute(double d) { - std::vector nodeWeights; - for (auto i : { 9,10,11,12 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top third absolute", nodeWeights, d, this); +int HPWH::getInletHeight(int whichInlet) const +{ + if (whichInlet == 1) { + return inletHeight; + } + else if (whichInlet == 2) { + return inlet2Height; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Invalid inlet chosen in getInletHeight \n"); + } + return HPWH_ABORT; + } +} + +int HPWH::setMaxTempDepression(double maxDepression, UNITS units /*=UNITS_C*/) +{ + if (units == UNITS_C) { + this->maxDepression_C = maxDepression; + } + else if (units == UNITS_F) { + this->maxDepression_C = F_TO_C(maxDepression); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for max Temp Depression. \n"); + } + return HPWH_ABORT; + } + return 0; +} + +bool HPWH::hasEnteringWaterHighTempShutOff(int heatSourceIndex) +{ + bool retVal = false; + if (heatSourceIndex >= numHeatSources || heatSourceIndex < 0) { + return retVal; + } + if (setOfSources[heatSourceIndex].shutOffLogicSet.size() == 0) { + return retVal; + } + + for (std::shared_ptr shutOffLogic : + setOfSources[heatSourceIndex].shutOffLogicSet) { + if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { + retVal = true; + break; + } + } + return retVal; +} + +int HPWH::setEnteringWaterHighTempShutOff(double highTemp, + bool tempIsAbsolute, + int heatSourceIndex, + UNITS unit /*=UNITS_C*/) +{ + if (!hasEnteringWaterHighTempShutOff(heatSourceIndex)) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to acess a heating logic that does not exist. \n"); + } + return HPWH_ABORT; + } + + double highTemp_C; + if (unit == UNITS_C) { + highTemp_C = highTemp; + } + else if (unit == UNITS_F) { + highTemp_C = F_TO_C(highTemp); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for set Entering Water High Temp Shut Off. \n"); + } + return HPWH_ABORT; + } + + bool highTempIsNotValid = false; + if (tempIsAbsolute) { + // check differnce with setpoint + if (setpoint_C - highTemp_C < MINSINGLEPASSLIFT) { + highTempIsNotValid = true; + } + } + else { + if (highTemp_C < MINSINGLEPASSLIFT) { + highTempIsNotValid = true; + } + } + if (highTempIsNotValid) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("High temperature shut off is too close to the setpoint, excpected a minimum " + "difference of %.2lf.\n", + MINSINGLEPASSLIFT); + } + return HPWH_ABORT; + } + + for (std::shared_ptr shutOffLogic : + setOfSources[heatSourceIndex].shutOffLogicSet) { + if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { + std::dynamic_pointer_cast(shutOffLogic) + ->setDecisionPoint(highTemp_C, tempIsAbsolute); + break; + } + } + return 0; +} + +int HPWH::setTargetSoCFraction(double target) +{ + if (!isSoCControlled()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not set target state of charge if HPWH is not using state of charge " + "controls."); + } + return HPWH_ABORT; + } + if (target < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not set a negative target state of charge."); + } + return HPWH_ABORT; + } + + for (int i = 0; i < numHeatSources; i++) { + for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { + if (!logic->getIsEnteringWaterHighTempShutoff()) { + logic->setDecisionPoint(target); + } + } + for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { + logic->setDecisionPoint(target); + } + } + return 0; +} + +bool HPWH::isSoCControlled() const { return usesSoCLogic; } + +bool HPWH::canUseSoCControls() +{ + bool retVal = true; + if (getCompressorCoilConfig() != HPWH::HeatSource::CONFIG_EXTERNAL) { + retVal = false; + } + return retVal; +} + +int HPWH::switchToSoCControls(double targetSoC, + double hysteresisFraction /*= 0.05*/, + double tempMinUseful /*= 43.333*/, + bool constantMainsT /*= false*/, + double mainsT /*= 18.333*/, + UNITS tempUnit /*= UNITS_C*/) +{ + if (!canUseSoCControls()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Cannot set up state of charge controls for integrated or wrapped HPWHs.\n"); + } + return HPWH_ABORT; + } + + double tempMinUseful_C, mainsT_C; + if (tempUnit == UNITS_C) { + tempMinUseful_C = tempMinUseful; + mainsT_C = mainsT; + } + else if (tempUnit == UNITS_F) { + tempMinUseful_C = F_TO_C(tempMinUseful); + mainsT_C = F_TO_C(mainsT); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for set Enterinh Water High Temp Shut Off.\n"); + } + return HPWH_ABORT; + } + + if (mainsT_C >= tempMinUseful_C) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The mains temperature can't be equal to or greater than the minimum useful " + "temperature.\n"); + } + return HPWH_ABORT; + } + + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i].clearAllTurnOnLogic(); + + setOfSources[i].shutOffLogicSet.erase( + std::remove_if(setOfSources[i].shutOffLogicSet.begin(), + setOfSources[i].shutOffLogicSet.end(), + [&](const auto logic) -> bool { + return !logic->getIsEnteringWaterHighTempShutoff(); + }), + setOfSources[i].shutOffLogicSet.end()); + + setOfSources[i].shutOffLogicSet.push_back(shutOffSoC("SoC Shut Off", + targetSoC, + hysteresisFraction, + tempMinUseful_C, + constantMainsT, + mainsT_C)); + setOfSources[i].turnOnLogicSet.push_back(turnOnSoC("SoC Turn On", + targetSoC, + hysteresisFraction, + tempMinUseful_C, + constantMainsT, + mainsT_C)); + } + + usesSoCLogic = true; + + return 0; +} + +std::shared_ptr HPWH::turnOnSoC(string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constantMainsT, + double mainsT_C) +{ + return std::make_shared( + desc, targetSoC, this, -hystFract, tempMinUseful_C, constantMainsT, mainsT_C); } -std::shared_ptr HPWH::bottomThird(double d) { - std::vector nodeWeights; - for (auto i : { 1,2,3,4 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("bottom third", nodeWeights, d, this); +std::shared_ptr HPWH::shutOffSoC(string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constantMainsT, + double mainsT_C) +{ + return std::make_shared(desc, + targetSoC, + this, + hystFract, + tempMinUseful_C, + constantMainsT, + mainsT_C, + std::greater()); } -std::shared_ptr HPWH::bottomSixth(double d) { - std::vector nodeWeights; - for (auto i : { 1,2 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("bottom sixth", nodeWeights, d, this); +std::shared_ptr HPWH::topThird(double d) +{ + std::vector nodeWeights; + for (int i : {9, 10, 11, 12}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("top third", nodeWeights, d, this); } -std::shared_ptr HPWH::bottomSixth_absolute(double d) { - std::vector nodeWeights; - for (auto i : { 1,2 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("bottom sixth absolute", nodeWeights, d, this, true); +std::shared_ptr HPWH::topThird_absolute(double d) +{ + std::vector nodeWeights; + for (auto i : {9, 10, 11, 12}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "top third absolute", nodeWeights, d, this); } -std::shared_ptr HPWH::secondSixth(double d) { - std::vector nodeWeights; - for (auto i : { 3,4 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("second sixth", nodeWeights, d, this); +std::shared_ptr HPWH::bottomThird(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2, 3, 4}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("bottom third", nodeWeights, d, this); } -std::shared_ptr HPWH::thirdSixth(double d) { - std::vector nodeWeights; - for (auto i : { 5,6 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("third sixth", nodeWeights, d, this); +std::shared_ptr HPWH::bottomSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("bottom sixth", nodeWeights, d, this); } -std::shared_ptr HPWH::fourthSixth(double d) { - std::vector nodeWeights; - for (auto i : { 7,8 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("fourth sixth", nodeWeights, d, this); +std::shared_ptr HPWH::bottomSixth_absolute(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "bottom sixth absolute", nodeWeights, d, this, true); } -std::shared_ptr HPWH::fifthSixth(double d) { - std::vector nodeWeights; - for (auto i : { 9,10 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("fifth sixth", nodeWeights, d, this); +std::shared_ptr HPWH::secondSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {3, 4}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("second sixth", nodeWeights, d, this); } -std::shared_ptr HPWH::topSixth(double d) { - std::vector nodeWeights; - for (auto i : { 11,12 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top sixth", nodeWeights, d, this); +std::shared_ptr HPWH::thirdSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {5, 6}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("third sixth", nodeWeights, d, this); } +std::shared_ptr HPWH::fourthSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {7, 8}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("fourth sixth", nodeWeights, d, this); +} -std::shared_ptr HPWH::bottomHalf(double d) { - std::vector nodeWeights; - for (auto i : { 1,2,3,4,5,6 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("bottom half", nodeWeights, d, this); +std::shared_ptr HPWH::fifthSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {9, 10}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("fifth sixth", nodeWeights, d, this); } -std::shared_ptr HPWH::bottomTwelth(double d) { - std::vector nodeWeights; - nodeWeights.emplace_back(1); - return std::make_shared("bottom twelth", nodeWeights, d, this); +std::shared_ptr HPWH::topSixth(double d) +{ + std::vector nodeWeights; + for (auto i : {11, 12}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("top sixth", nodeWeights, d, this); } -std::shared_ptr HPWH::standby(double d) { - std::vector nodeWeights; - nodeWeights.emplace_back(13); // uses very top computation node - return std::make_shared("standby", nodeWeights, d, this); +std::shared_ptr HPWH::bottomHalf(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2, 3, 4, 5, 6}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("bottom half", nodeWeights, d, this); } - -std::shared_ptr HPWH::topNodeMaxTemp(double d) { - std::vector nodeWeights; - nodeWeights.emplace_back(13); // uses very top computation node - return std::make_shared("top node", nodeWeights, d, this, true, std::greater()); + +std::shared_ptr HPWH::bottomTwelth(double d) +{ + std::vector nodeWeights; + nodeWeights.emplace_back(1); + return std::make_shared("bottom twelth", nodeWeights, d, this); } -std::shared_ptr HPWH::bottomNodeMaxTemp(double d, bool isEnteringWaterHighTempShutoff /*=false*/) { - std::vector nodeWeights; - nodeWeights.emplace_back(0); // uses very bottom computation node - return std::make_shared("bottom node", nodeWeights, d, this, true, std::greater(), isEnteringWaterHighTempShutoff); +std::shared_ptr HPWH::standby(double d) +{ + std::vector nodeWeights; + nodeWeights.emplace_back(13); // uses very top computation node + return std::make_shared("standby", nodeWeights, d, this); } -std::shared_ptr HPWH::bottomTwelthMaxTemp(double d) { - std::vector nodeWeights; - nodeWeights.emplace_back(1); - return std::make_shared("bottom twelth", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::topThirdMaxTemp(double d) { - std::vector nodeWeights; - for (auto i : { 9,10,11,12 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top third", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::bottomSixthMaxTemp(double d) { - std::vector nodeWeights; - for (auto i : { 1,2 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("bottom sixth", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::secondSixthMaxTemp(double d) { - std::vector nodeWeights; - for (auto i : { 3,4 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("second sixth", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::fifthSixthMaxTemp(double d) { - std::vector nodeWeights; - for (auto i : { 9,10 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top sixth", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::topSixthMaxTemp(double d) { - std::vector nodeWeights; - for (auto i : { 11,12 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("top sixth", nodeWeights, d, this, true, std::greater()); -} - -std::shared_ptr HPWH::largeDraw(double d) { - std::vector nodeWeights; - for (auto i : { 1,2,3,4 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("large draw", nodeWeights, d, this, true); -} - -std::shared_ptr HPWH::largerDraw(double d) { - std::vector nodeWeights; - for (auto i : { 1,2,3,4,5,6 }) { - nodeWeights.emplace_back(i); - } - return std::make_shared("larger draw", nodeWeights, d, this, true); -} - -int HPWH::getNumNodes() const { - return numNodes; -} - -double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const { - if (nodeNum >= numNodes || nodeNum < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the temperature of a tank node that does not exist. \n"); - } - return double(HPWH_ABORT); - } - else { - double result = tankTemps_C[nodeNum]; - //if (result == double(HPWH_ABORT)) { can't happen? - // return result; - //} - if (units == UNITS_C) { - return result; - } - else if (units == UNITS_F) { - return C_TO_F(result); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getTankNodeTemp. \n"); - } - return double(HPWH_ABORT); - } - } -} - - -double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C*/) const { - if (iTCouple > nTCouple || iTCouple < 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access a simulated thermocouple that does not exist. \n"); - } - return double(HPWH_ABORT); - } - else if (nTCouple > numNodes) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have more simulated thermocouples than nodes. \n"); - } - return double(HPWH_ABORT); - } - else { - double weight = (double)numNodes / (double)nTCouple; - double start_ind = (iTCouple - 1.) * weight; - int ind = (int)std::ceil(start_ind); - - double averageTemp_C = 0.0; - - // Check any intial fraction of nodes - averageTemp_C += getTankNodeTemp((int)std::floor(start_ind), UNITS_C) * ((double)ind - start_ind); - weight -= ((double)ind - start_ind); - - // Check the full nodes - while (weight >= 1.0) { - averageTemp_C += getTankNodeTemp(ind, UNITS_C); - weight -= 1.0; - ind += 1; - } - - // Check any leftover - if (weight > 0.) { - averageTemp_C += getTankNodeTemp(ind, UNITS_C) * weight; - } - // Divide by the original weight to get the true average - averageTemp_C /= ((double)numNodes / (double)nTCouple); - - if (units == UNITS_C) { - return averageTemp_C; - } - else if (units == UNITS_F) { - return C_TO_F(averageTemp_C); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getNthSimTcouple. \n"); - } - return double(HPWH_ABORT); - } - } -} - - -int HPWH::getNumHeatSources() const { - return numHeatSources; -} - -int HPWH::getCompressorIndex() const { - return compressorIndex; -} - -int HPWH::getNumResistanceElements() const { - int count = 0; - for (int i = 0; i < numHeatSources; i++) { - count += setOfSources[i].isAResistance() ? 1 : 0; - } - return count; -} - -double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, double inletTemp /*=14.444*/, double outTemp /*=57.222*/, - UNITS pwrUnit /*=UNITS_KW*/, UNITS tempUnit /*=UNITS_C*/) const { - // calculate capacity btu/hr, input btu/hr, and cop - double capTemp_BTUperHr, inputTemp_BTUperHr, copTemp; // temporary variables - double airTemp_C, inletTemp_C, outTemp_C; - - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return double(HPWH_ABORT); - } - - if (tempUnit == UNITS_C) { - airTemp_C = airTemp; - inletTemp_C = inletTemp; - outTemp_C = outTemp; - } - else if (tempUnit == UNITS_F) { - airTemp_C = F_TO_C(airTemp); - inletTemp_C = F_TO_C(inletTemp); - outTemp_C = F_TO_C(outTemp); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for temperatures in getCompressorCapacity. \n"); - } - return double(HPWH_ABORT); - } - - if (airTemp_C < setOfSources[compressorIndex].minT || airTemp_C > setOfSources[compressorIndex].maxT) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The compress does not operate at the specified air temperature. \n"); - } - return double(HPWH_ABORT); - } - - double maxAllowedSetpoint_C = setOfSources[compressorIndex].maxSetpoint_C - - setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; - if (outTemp_C > maxAllowedSetpoint_C) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Inputted outlet temperature of the compressor is higher than can be produced."); - } - return double(HPWH_ABORT); - } - - if (setOfSources[compressorIndex].isExternalMultipass()) { - double averageTemp_C = (outTemp_C + inletTemp_C) / 2.; - setOfSources[compressorIndex].getCapacityMP(airTemp_C, averageTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); - } - else { - setOfSources[compressorIndex].getCapacity(airTemp_C, inletTemp_C, outTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); - } - - double outputCapacity = capTemp_BTUperHr; - if(pwrUnit == UNITS_KW) { - outputCapacity = BTU_TO_KWH(capTemp_BTUperHr); - } - else if (pwrUnit != UNITS_BTUperHr) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for capacity in getCompressorCapacity. \n"); - } - return double(HPWH_ABORT); - } - - return outputCapacity; -} - -double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) const { - //energy used by the heat source is positive - this should always be positive - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the energy input of a heat source that does not exist. \n"); - } - return double(HPWH_ABORT); - } - - if (units == UNITS_KWH) { - return setOfSources[N].energyInput_kWh; - } - else if (units == UNITS_BTU) { - return KWH_TO_BTU(setOfSources[N].energyInput_kWh); - } - else if (units == UNITS_KJ) { - return KWH_TO_KJ(setOfSources[N].energyInput_kWh); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); - } - return double(HPWH_ABORT); - } -} -double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) const { - //returns energy from the heat source into the water - this should always be positive - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the energy output of a heat source that does not exist. \n"); - } - return double(HPWH_ABORT); - } - - if (units == UNITS_KWH) { - return setOfSources[N].energyOutput_kWh; - } - else if (units == UNITS_BTU) { - return KWH_TO_BTU(setOfSources[N].energyOutput_kWh); - } - else if (units == UNITS_KJ) { - return KWH_TO_KJ(setOfSources[N].energyOutput_kWh); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); - } - return double(HPWH_ABORT); - } -} - - -double HPWH::getNthHeatSourceRunTime(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the run time of a heat source that does not exist. \n"); - } - return double(HPWH_ABORT); - } - return setOfSources[N].runtime_min; -} - - -int HPWH::isNthHeatSourceRunning(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the status of a heat source that does not exist. \n"); - } - return HPWH_ABORT; - } - if (setOfSources[N].isEngaged()) { - return 1; - } - else { - return 0; - } -} - - -HPWH::HEATSOURCE_TYPE HPWH::getNthHeatSourceType(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have attempted to access the type of a heat source that does not exist. \n"); - } - return HEATSOURCE_TYPE(HPWH_ABORT); - } - return setOfSources[N].typeOfHeatSource; -} - - -double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const { - if (units == UNITS_L) { - return tankVolume_L; - } - else if (units == UNITS_GAL) { - return L_TO_GAL(tankVolume_L); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getTankSize. \n"); - } - return HPWH_ABORT; - } -} - - -double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { - return outletTemp_C; - } - else if (units == UNITS_F) { - return C_TO_F(outletTemp_C); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getOutletTemp. \n"); - } - return double(HPWH_ABORT); - } -} - - -double HPWH::getCondenserWaterInletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { - return condenserInlet_C; - } - else if (units == UNITS_F) { - return C_TO_F(condenserInlet_C); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); - } - return double(HPWH_ABORT); - } -} - -double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { - return condenserOutlet_C; - } - else if (units == UNITS_F) { - return C_TO_F(condenserOutlet_C); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); - } - return double(HPWH_ABORT); - } -} - -double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const { - if (units == UNITS_L) { - return externalVolumeHeated_L; - } - else if (units == UNITS_GAL) { - return L_TO_GAL(externalVolumeHeated_L); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getExternalVolumeHeated. \n"); - } - return double(HPWH_ABORT); - } -} - -double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const { - //moving heat from the space to the water is the positive direction - if (units == UNITS_KWH) { - return energyRemovedFromEnvironment_kWh; - } - else if (units == UNITS_BTU) { - return KWH_TO_BTU(energyRemovedFromEnvironment_kWh); - } - else if (units == UNITS_KJ) { - return KWH_TO_KJ(energyRemovedFromEnvironment_kWh); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); - } - return double(HPWH_ABORT); - } -} - -double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const { - //moving heat from the water to the space is the positive direction - if (units == UNITS_KWH) { - return standbyLosses_kWh; - } - else if (units == UNITS_BTU) { - return KWH_TO_BTU(standbyLosses_kWh); - } - else if (units == UNITS_KJ) { - return KWH_TO_KJ(standbyLosses_kWh); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getStandbyLosses. \n"); - } - return double(HPWH_ABORT); - } -} - -double HPWH::getTankHeatContent_kJ() const { - // returns tank heat content relative to 0 C using kJ - - //get average tank temperature - double avgTemp = 0.0; - for (int i = 0; i < numNodes; i++) { - avgTemp += tankTemps_C[i]; - } - avgTemp /= numNodes; - - double totalHeat = avgTemp * DENSITYWATER_kgperL * CPWATER_kJperkgC * tankVolume_L; - return totalHeat; -} - -double HPWH::getLocationTemp_C() const { - return locationTemperature_C; -} - -int HPWH::getHPWHModel() const { - return hpwhModel; -} -int HPWH::getCompressorCoilConfig() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return HPWH_ABORT; - } - return setOfSources[compressorIndex].configuration; -} -bool HPWH::isCompressorMultipass() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return HPWH_ABORT; - } - return setOfSources[compressorIndex].isMultipass; -} -bool HPWH::isCompressoExternalMultipass() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return HPWH_ABORT; - } - return setOfSources[compressorIndex].isExternalMultipass(); -} - -bool HPWH::hasACompressor() const { - return compressorIndex >= 0; -} - - -bool HPWH::hasExternalHeatSource() const { - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - return true; - } - } - return false; -} - -double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const { - if (!isCompressoExternalMultipass()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Does not have an external multipass heat source \n"); - } - return HPWH_ABORT; - } - - if (units == HPWH::UNITS_LPS) { - return setOfSources[compressorIndex].mpFlowRate_LPS; - } - else if (units == HPWH::UNITS_GPM) { - return LPS_TO_GPM(setOfSources[compressorIndex].mpFlowRate_LPS); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getExternalMPFlowRate. \n"); - } - return (double)HPWH_ABORT; - } -} - -double HPWH::getCompressorMinRuntime(UNITS units /*=UNITS_MIN*/) const { - - if (hasACompressor()) { - double min_minutes = 10.; - - if (units == UNITS_MIN) { - return min_minutes; - } - else if (units == UNITS_SEC) { - return MIN_TO_SEC(min_minutes); - } - else if (units == UNITS_HR) { - return MIN_TO_HR(min_minutes); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for getCompressorMinRunTime. \n"); - } - return (double)HPWH_ABORT; - } - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("This HPWH has no compressor. \n"); - } - return (double)HPWH_ABORT; - } -} - -int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const { - double aFract = 1.; - double useFract = 1.; - - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return HPWH_ABORT; - } - else if (usesSoCLogic) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model uses SOC control logic and does not have a definition for sizing fractions. \n"); - } - return HPWH_ABORT; - } - - // Every compressor must have at least one on logic - for(std::shared_ptr onLogic : setOfSources[compressorIndex].turnOnLogicSet) { - double tempA; - - if (hpwhVerbosity >= VRB_emetic) { - msg("\tturnon logic: %s ", onLogic->description.c_str()); - } - tempA = onLogic->nodeWeightAvgFract(); // if standby logic will return 1 - aFract = tempA < aFract ? tempA : aFract; - } - aquaFract = aFract; - - // Compressors don't need to have an off logic - if (setOfSources[compressorIndex].shutOffLogicSet.size() != 0) { - for(std::shared_ptr offLogic : setOfSources[compressorIndex].shutOffLogicSet) { - - double tempUse; - - if (hpwhVerbosity >= VRB_emetic) { - msg("\tshutsOff logic: %s ", offLogic->description.c_str()); - } - if (offLogic->description == "large draw" || offLogic->description == "larger draw") { - tempUse = 1.; // These logics are just for checking if there's a big draw to switch to RE - } - else { - tempUse = 1. - offLogic->nodeWeightAvgFract(); - } - useFract = tempUse < useFract ? tempUse : useFract; // Will return the smallest case of the useable fraction for multiple off logics - } - useableFract = useFract; - } - else { - if (hpwhVerbosity >= VRB_emetic) { - msg("\no shutoff logics present"); - } - useableFract = 1.; - } - - // Check if double's are approximately equally and adjust the relationship so it follows the relationship we expect. - // The tolerance plays with 0.1 mm in position if the tank is 1m tall... - double temp = 1. - useableFract; - if (aboutEqual(aquaFract, temp)) { - useableFract = 1. - aquaFract + TOL_MINVALUE; - } - - return 0; -} - -bool HPWH::isHPWHScalable() const { - return canScale; -} - -int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP /*=1.0*/) { - if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not scale the HPWH Capacity or COP \n"); - } - return HPWH_ABORT; - } - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Current model does not have a compressor. \n"); - } - return HPWH_ABORT; - } - if (scaleCapacity <= 0 || scaleCOP <= 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not scale the HPWH Capacity or COP to 0 or less than 0 \n"); - } - return HPWH_ABORT; - } - - for (auto &perfP : setOfSources[compressorIndex].perfMap) { - if (scaleCapacity != 1.) { - std::transform(perfP.inputPower_coeffs.begin(), perfP.inputPower_coeffs.end(), perfP.inputPower_coeffs.begin(), - std::bind(std::multiplies(), std::placeholders::_1, scaleCapacity)); - } - if (scaleCOP != 1.) { - std::transform(perfP.COP_coeffs.begin(), perfP.COP_coeffs.end(), perfP.COP_coeffs.begin(), - std::bind(std::multiplies(), std::placeholders::_1, scaleCOP)); - } - } - - return 0; -} - -int HPWH::setCompressorOutputCapacity(double newCapacity, double airTemp /*=19.722*/, - double inletTemp /*=14.444*/, double outTemp /*=57.222*/, - UNITS pwrUnit /*=UNITS_KW*/, UNITS tempUnit /*=UNITS_C*/) { - - double oldCapacity = getCompressorCapacity(airTemp, inletTemp, outTemp, pwrUnit, tempUnit); - if (oldCapacity == double(HPWH_ABORT)) { - return HPWH_ABORT; - } - - double scale = newCapacity / oldCapacity; - return setScaleHPWHCapacityCOP(scale, 1.); // Scale the compressor capacity -} - - -int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW*/) { - - //Input checks - if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not scale the resistance elements \n"); - } - return HPWH_ABORT; - } - if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("There are no resistance elements to set capacity for \n"); - } - return HPWH_ABORT; - } - if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds value for which in setResistanceCapacity()\n"); - } - return HPWH_ABORT; - } - if (power < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Can not have a negative input power \n"); - } - return HPWH_ABORT; - } - //Unit conversion - double watts; - if (pwrUnit == UNITS_KW) { - watts = power * 1000; // kW to W - } - else if (pwrUnit == UNITS_BTUperHr) { - watts = BTU_TO_KWH(power) * 1000; // BTU to kW then kW to W - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for capacity in setResistanceCapacity. \n"); - } - return HPWH_ABORT; - } - - //Whew so many checks... - if (which == -1) { - // Just get all the elements - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { - setOfSources[i].changeResistanceWatts(watts); - } - } - } - else { - setOfSources[resistanceHeightMap[which].index].changeResistanceWatts(watts); - - // Then check for repeats in the position - int pos = resistanceHeightMap[which].position; - for (int i = 0; i < getNumResistanceElements(); i++) { - if (which != i && resistanceHeightMap[i].position == pos) { - setOfSources[resistanceHeightMap[i].index].changeResistanceWatts(watts); - } - } - } - - return 0; -} - -double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW*/) { - - //Input checks - if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("There are no resistance elements to return capacity for \n"); - } - return HPWH_ABORT; - } - if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds value for which in getResistanceCapacity()\n"); - } - return HPWH_ABORT; - } - - double returnPower = 0; - if (which == -1) { - // Just get all the elements - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { - returnPower += setOfSources[i].perfMap[0].inputPower_coeffs[0]; - } - } - } - else { - // get the power from "which" element by height - returnPower += setOfSources[resistanceHeightMap[which].index].perfMap[0].inputPower_coeffs[0]; - - // Then check for repeats in the position - int pos = resistanceHeightMap[which].position; - for (int i = 0; i < getNumResistanceElements(); i++) { - if (which != i && resistanceHeightMap[i].position == pos) { - returnPower += setOfSources[resistanceHeightMap[i].index].perfMap[0].inputPower_coeffs[0]; - } - } - } - - //Unit conversion - if (pwrUnit == UNITS_KW) { - returnPower /= 1000.; // W to KW - } - else if (pwrUnit == UNITS_BTUperHr) { - returnPower = KWH_TO_BTU(returnPower/1000.); // W to BTU/hr - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect unit specification for capacity in getResistanceCapacity. \n"); - } - return HPWH_ABORT; - } - - return returnPower; -} - -int HPWH::getResistancePosition(int elementIndex) const { - - if (elementIndex < 0 || elementIndex > numHeatSources - 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds value for which in getResistancePosition\n"); - } - return HPWH_ABORT; - } - - if (!setOfSources[elementIndex].isAResistance()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("This index is not a resistance element\n"); - } - return HPWH_ABORT; - } - - for (int i = 0; i < CONDENSITY_SIZE; i++) { - if (setOfSources[elementIndex].condensity[i] == 1) { // res elements have a condenstiy of 1 at a specific node - return i; - } - } - return HPWH_ABORT; -} - -//the privates -void HPWH::updateTankTemps(double drawVolume_L, double inletT_C, double tankAmbientT_C, - double inletVol2_L, double inletT2_C) { - //set up some useful variables for calculations - double drawFraction; - this->outletTemp_C = 0.; - double nodeInletFraction, cumInletFraction, drawVolume_N; - double nodeInletTV = 0.; - - if (drawVolume_L > 0.) { - - //calculate how many nodes to draw (wholeNodesToDraw), and the remainder (drawFraction) - if (inletVol2_L > drawVolume_L) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Volume in inlet 2 is greater than the draw volume. \n"); - } - simHasFailed = true; - return; - } - - // Check which inlet is higher; - int highInletH; - double highInletV, highInletT; - int lowInletH; - double lowInletT, lowInletV; - if (inletHeight > inlet2Height) { - highInletH = inletHeight; - highInletV = drawVolume_L - inletVol2_L; - highInletT = inletT_C; - lowInletH = inlet2Height; - lowInletT = inletT2_C; - lowInletV = inletVol2_L; - } - else { - highInletH = inlet2Height; - highInletV = inletVol2_L; - highInletT = inletT2_C; - lowInletH = inletHeight; - lowInletT = inletT_C; - lowInletV = drawVolume_L - inletVol2_L; - } - //calculate how many nodes to draw (drawVolume_N) - drawVolume_N = drawVolume_L / volPerNode_LperNode; - if (drawVolume_L > tankVolume_L) { - //if (hpwhVerbosity >= 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"); - //} - //simHasFailed = true; - //return; - for (int i = 0; i < numNodes; i++){ - outletTemp_C += tankTemps_C[i]; - tankTemps_C[i] = (inletT_C * (drawVolume_L - inletVol2_L) + inletT2_C * inletVol2_L) / drawVolume_L; - } - outletTemp_C = (outletTemp_C / numNodes * tankVolume_L + tankTemps_C[0] * (drawVolume_L - tankVolume_L))/drawVolume_L * (drawVolume_L / volPerNode_LperNode); - - drawVolume_N = 0.; - } - - ///////////////////////////////////////////////////////////////////////////////////////////////// - - while (drawVolume_N > 0) { - - // Draw one node at a time - drawFraction = drawVolume_N > 1. ? 1. : drawVolume_N; - - //add temperature for outletT average - outletTemp_C += drawFraction * tankTemps_C[numNodes - 1]; - - cumInletFraction = 0.; - for (int i = numNodes - 1; i >= lowInletH; i--) { - - // Reset inlet inputs at this node. - nodeInletFraction = 0.; - nodeInletTV = 0.; - - // Sum of all inlets Vi*Ti at this node - if (i == highInletH) { - nodeInletTV += highInletV * drawFraction / drawVolume_L * highInletT; - nodeInletFraction += highInletV * drawFraction / drawVolume_L; - } - if (i == lowInletH) { - nodeInletTV += lowInletV * drawFraction / drawVolume_L * lowInletT; - nodeInletFraction += lowInletV * drawFraction / drawVolume_L; - - break; // if this is the bottom inlet break out of the four loop and use the boundary condition equation. - } - - // Look at the volume and temperature fluxes into this node - tankTemps_C[i] = (1. - (drawFraction - cumInletFraction)) * tankTemps_C[i] + - nodeInletTV + - (drawFraction - (cumInletFraction + nodeInletFraction)) * tankTemps_C[i - 1]; - - cumInletFraction += nodeInletFraction; - - } - - // Boundary condition equation because it shouldn't take anything from tankTemps_C[i - 1] but it also might not exist. - tankTemps_C[lowInletH] = (1. - (drawFraction - cumInletFraction)) * tankTemps_C[lowInletH] + nodeInletTV; - - drawVolume_N -= drawFraction; - - mixTankInversions(); - } - - - //fill in average outlet T - it is a weighted averaged, with weights == nodes drawn - this->outletTemp_C /= (drawVolume_L / volPerNode_LperNode); - - ///////////////////////////////////////////////////////////////////////////////////////////////// - - //Account for mixing at the bottom of the tank - if (tankMixesOnDraw && drawVolume_L > 0.) { - int mixedBelowNode = (int)(numNodes * mixBelowFractionOnDraw); - mixTankNodes(0, mixedBelowNode, 3.0); - } - - } //end if(draw_volume_L > 0) - +std::shared_ptr HPWH::topNodeMaxTemp(double d) +{ + std::vector nodeWeights; + nodeWeights.emplace_back(13); // uses very top computation node + return std::make_shared( + "top node", nodeWeights, d, this, true, std::greater()); +} - if (doConduction) { - - // Get the "constant" tau for the stability condition and the conduction calculation - const double tau = KWATER_WpermC / (CPWATER_kJperkgC * 1000.0 * DENSITYWATER_kgperL * 1000.0 * (node_height * node_height)) * minutesPerStep * 60.0; - if (tau > 0.5) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The stability condition for conduction has failed, these results are going to be interesting!\n"); - } - simHasFailed = true; - return; - } +std::shared_ptr +HPWH::bottomNodeMaxTemp(double d, bool isEnteringWaterHighTempShutoff /*=false*/) +{ + std::vector nodeWeights; + nodeWeights.emplace_back(0); // uses very bottom computation node + return std::make_shared("bottom node", + nodeWeights, + d, + this, + true, + std::greater(), + isEnteringWaterHighTempShutoff); +} + +std::shared_ptr HPWH::bottomTwelthMaxTemp(double d) +{ + std::vector nodeWeights; + nodeWeights.emplace_back(1); + return std::make_shared( + "bottom twelth", nodeWeights, d, this, true, std::greater()); +} - // Boundary condition for the finite difference. - const double bc = 2.0 * tau * tankUA_kJperHrC * fracAreaTop * node_height / KWATER_WpermC; +std::shared_ptr HPWH::topThirdMaxTemp(double d) +{ + std::vector nodeWeights; + for (auto i : {9, 10, 11, 12}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "top third", nodeWeights, d, this, true, std::greater()); +} - // Boundary nodes for finite difference - nextTankTemps_C[0] = (1.0 - 2.0 * tau - bc) * tankTemps_C[0] + 2.0 * tau * tankTemps_C[1] + bc * tankAmbientT_C; - nextTankTemps_C[numNodes - 1] = (1.0 - 2.0 * tau - bc) * tankTemps_C[numNodes - 1] + 2.0 * tau * tankTemps_C[numNodes - 2] + bc * tankAmbientT_C; +std::shared_ptr HPWH::bottomSixthMaxTemp(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "bottom sixth", nodeWeights, d, this, true, std::greater()); +} + +std::shared_ptr HPWH::secondSixthMaxTemp(double d) +{ + std::vector nodeWeights; + for (auto i : {3, 4}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "second sixth", nodeWeights, d, this, true, std::greater()); +} + +std::shared_ptr HPWH::fifthSixthMaxTemp(double d) +{ + std::vector nodeWeights; + for (auto i : {9, 10}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "top sixth", nodeWeights, d, this, true, std::greater()); +} + +std::shared_ptr HPWH::topSixthMaxTemp(double d) +{ + std::vector nodeWeights; + for (auto i : {11, 12}) { + nodeWeights.emplace_back(i); + } + return std::make_shared( + "top sixth", nodeWeights, d, this, true, std::greater()); +} + +std::shared_ptr HPWH::largeDraw(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2, 3, 4}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("large draw", nodeWeights, d, this, true); +} + +std::shared_ptr HPWH::largerDraw(double d) +{ + std::vector nodeWeights; + for (auto i : {1, 2, 3, 4, 5, 6}) { + nodeWeights.emplace_back(i); + } + return std::make_shared("larger draw", nodeWeights, d, this, true); +} + +int HPWH::getNumNodes() const { return numNodes; } + +double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const +{ + if (nodeNum >= numNodes || nodeNum < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the temperature of a tank node that does not exist. " + "\n"); + } + return double(HPWH_ABORT); + } + else { + double result = tankTemps_C[nodeNum]; + // if (result == double(HPWH_ABORT)) { can't happen? + // return result; + // } + if (units == UNITS_C) { + return result; + } + else if (units == UNITS_F) { + return C_TO_F(result); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getTankNodeTemp. \n"); + } + return double(HPWH_ABORT); + } + } +} + +double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C*/) const +{ + if (iTCouple > nTCouple || iTCouple < 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access a simulated thermocouple that does not exist. \n"); + } + return double(HPWH_ABORT); + } + else if (nTCouple > numNodes) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have more simulated thermocouples than nodes. \n"); + } + return double(HPWH_ABORT); + } + else { + double weight = (double)numNodes / (double)nTCouple; + double start_ind = (iTCouple - 1.) * weight; + int ind = (int)std::ceil(start_ind); + + double averageTemp_C = 0.0; + + // Check any intial fraction of nodes + averageTemp_C += + getTankNodeTemp((int)std::floor(start_ind), UNITS_C) * ((double)ind - start_ind); + weight -= ((double)ind - start_ind); + + // Check the full nodes + while (weight >= 1.0) { + averageTemp_C += getTankNodeTemp(ind, UNITS_C); + weight -= 1.0; + ind += 1; + } + + // Check any leftover + if (weight > 0.) { + averageTemp_C += getTankNodeTemp(ind, UNITS_C) * weight; + } + // Divide by the original weight to get the true average + averageTemp_C /= ((double)numNodes / (double)nTCouple); + + if (units == UNITS_C) { + return averageTemp_C; + } + else if (units == UNITS_F) { + return C_TO_F(averageTemp_C); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getNthSimTcouple. \n"); + } + return double(HPWH_ABORT); + } + } +} + +int HPWH::getNumHeatSources() const { return numHeatSources; } + +int HPWH::getCompressorIndex() const { return compressorIndex; } + +int HPWH::getNumResistanceElements() const +{ + int count = 0; + for (int i = 0; i < numHeatSources; i++) { + count += setOfSources[i].isAResistance() ? 1 : 0; + } + return count; +} + +double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, + double inletTemp /*=14.444*/, + double outTemp /*=57.222*/, + UNITS pwrUnit /*=UNITS_KW*/, + UNITS tempUnit /*=UNITS_C*/) const +{ + // calculate capacity btu/hr, input btu/hr, and cop + double capTemp_BTUperHr, inputTemp_BTUperHr, copTemp; // temporary variables + double airTemp_C, inletTemp_C, outTemp_C; + + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return double(HPWH_ABORT); + } + + if (tempUnit == UNITS_C) { + airTemp_C = airTemp; + inletTemp_C = inletTemp; + outTemp_C = outTemp; + } + else if (tempUnit == UNITS_F) { + airTemp_C = F_TO_C(airTemp); + inletTemp_C = F_TO_C(inletTemp); + outTemp_C = F_TO_C(outTemp); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for temperatures in getCompressorCapacity. \n"); + } + return double(HPWH_ABORT); + } + + if (airTemp_C < setOfSources[compressorIndex].minT || + airTemp_C > setOfSources[compressorIndex].maxT) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The compress does not operate at the specified air temperature. \n"); + } + return double(HPWH_ABORT); + } + + double maxAllowedSetpoint_C = + setOfSources[compressorIndex].maxSetpoint_C - + setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; + if (outTemp_C > maxAllowedSetpoint_C) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Inputted outlet temperature of the compressor is higher than can be produced."); + } + return double(HPWH_ABORT); + } + + if (setOfSources[compressorIndex].isExternalMultipass()) { + double averageTemp_C = (outTemp_C + inletTemp_C) / 2.; + setOfSources[compressorIndex].getCapacityMP( + airTemp_C, averageTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); + } + else { + setOfSources[compressorIndex].getCapacity( + airTemp_C, inletTemp_C, outTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); + } + + double outputCapacity = capTemp_BTUperHr; + if (pwrUnit == UNITS_KW) { + outputCapacity = BTU_TO_KWH(capTemp_BTUperHr); + } + else if (pwrUnit != UNITS_BTUperHr) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for capacity in getCompressorCapacity. \n"); + } + return double(HPWH_ABORT); + } + + return outputCapacity; +} + +double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) const +{ + // energy used by the heat source is positive - this should always be positive + if (N >= numHeatSources || N < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the energy input of a heat source that does not " + "exist. \n"); + } + return double(HPWH_ABORT); + } + + if (units == UNITS_KWH) { + return setOfSources[N].energyInput_kWh; + } + else if (units == UNITS_BTU) { + return KWH_TO_BTU(setOfSources[N].energyInput_kWh); + } + else if (units == UNITS_KJ) { + return KWH_TO_KJ(setOfSources[N].energyInput_kWh); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); + } + return double(HPWH_ABORT); + } +} +double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) const +{ + // returns energy from the heat source into the water - this should always be positive + if (N >= numHeatSources || N < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the energy output of a heat source that does not " + "exist. \n"); + } + return double(HPWH_ABORT); + } + + if (units == UNITS_KWH) { + return setOfSources[N].energyOutput_kWh; + } + else if (units == UNITS_BTU) { + return KWH_TO_BTU(setOfSources[N].energyOutput_kWh); + } + else if (units == UNITS_KJ) { + return KWH_TO_KJ(setOfSources[N].energyOutput_kWh); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getNthHeatSourceRunTime(int N) const +{ + if (N >= numHeatSources || N < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the run time of a heat source that does not exist. " + "\n"); + } + return double(HPWH_ABORT); + } + return setOfSources[N].runtime_min; +} - // Internal nodes for the finite difference - for (int i = 1; i < numNodes - 1; i++) { - nextTankTemps_C[i] = tankTemps_C[i] + tau * (tankTemps_C[i + 1] - 2.0 * tankTemps_C[i] + tankTemps_C[i - 1]); - } +int HPWH::isNthHeatSourceRunning(int N) const +{ + if (N >= numHeatSources || N < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the status of a heat source that does not exist. " + "\n"); + } + return HPWH_ABORT; + } + if (setOfSources[N].isEngaged()) { + return 1; + } + else { + return 0; + } +} + +HPWH::HEATSOURCE_TYPE HPWH::getNthHeatSourceType(int N) const +{ + if (N >= numHeatSources || N < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have attempted to access the type of a heat source that does not exist. \n"); + } + return HEATSOURCE_TYPE(HPWH_ABORT); + } + return setOfSources[N].typeOfHeatSource; +} - // nextTankTemps_C gets assigns to tankTemps_C at the bottom of the function after q_UA. - // UA loss from the sides are found at the bottom of the function. - double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * (tankTemps_C[0] - tankAmbientT_C) * (minutesPerStep / 60.0)); - standbyLosses_kJ += (tankUA_kJperHrC * fracAreaTop * (tankTemps_C[numNodes - 1] - tankAmbientT_C) * (minutesPerStep / 60.0)); - standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); - } - else { // Ignore tank conduction and calculate UA losses from top and bottom. UA loss from the sides are found at the bottom of the function +double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const +{ + if (units == UNITS_L) { + return tankVolume_L; + } + else if (units == UNITS_GAL) { + return L_TO_GAL(tankVolume_L); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getTankSize. \n"); + } + return HPWH_ABORT; + } +} + +double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const +{ + if (units == UNITS_C) { + return outletTemp_C; + } + else if (units == UNITS_F) { + return C_TO_F(outletTemp_C); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getOutletTemp. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getCondenserWaterInletTemp(UNITS units /*=UNITS_C*/) const +{ + if (units == UNITS_C) { + return condenserInlet_C; + } + else if (units == UNITS_F) { + return C_TO_F(condenserInlet_C); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const +{ + if (units == UNITS_C) { + return condenserOutlet_C; + } + else if (units == UNITS_F) { + return C_TO_F(condenserOutlet_C); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const +{ + if (units == UNITS_L) { + return externalVolumeHeated_L; + } + else if (units == UNITS_GAL) { + return L_TO_GAL(externalVolumeHeated_L); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getExternalVolumeHeated. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const +{ + // moving heat from the space to the water is the positive direction + if (units == UNITS_KWH) { + return energyRemovedFromEnvironment_kWh; + } + else if (units == UNITS_BTU) { + return KWH_TO_BTU(energyRemovedFromEnvironment_kWh); + } + else if (units == UNITS_KJ) { + return KWH_TO_KJ(energyRemovedFromEnvironment_kWh); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const +{ + // moving heat from the water to the space is the positive direction + if (units == UNITS_KWH) { + return standbyLosses_kWh; + } + else if (units == UNITS_BTU) { + return KWH_TO_BTU(standbyLosses_kWh); + } + else if (units == UNITS_KJ) { + return KWH_TO_KJ(standbyLosses_kWh); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getStandbyLosses. \n"); + } + return double(HPWH_ABORT); + } +} + +double HPWH::getTankHeatContent_kJ() const +{ + // returns tank heat content relative to 0 C using kJ - for (int i = 0; i < numNodes; i++) { - nextTankTemps_C[i] = tankTemps_C[i]; - } + // get average tank temperature + double avgTemp = 0.0; + for (int i = 0; i < numNodes; i++) { + avgTemp += tankTemps_C[i]; + } + avgTemp /= numNodes; - //kJ's lost as standby in the current time step for the top node. - double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * (tankTemps_C[0] - tankAmbientT_C) * (minutesPerStep / 60.0)); - standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + double totalHeat = avgTemp * DENSITYWATER_kgperL * CPWATER_kJperkgC * tankVolume_L; + return totalHeat; +} - nextTankTemps_C[0] -= standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); +double HPWH::getLocationTemp_C() const { return locationTemperature_C; } - //kJ's lost as standby in the current time step for the bottom node. - standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * (tankTemps_C[numNodes - 1] - tankAmbientT_C) * (minutesPerStep / 60.0)); - standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); +int HPWH::getHPWHModel() const { return hpwhModel; } +int HPWH::getCompressorCoilConfig() const +{ + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return HPWH_ABORT; + } + return setOfSources[compressorIndex].configuration; +} +bool HPWH::isCompressorMultipass() const +{ + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return HPWH_ABORT; + } + return setOfSources[compressorIndex].isMultipass; +} +bool HPWH::isCompressoExternalMultipass() const +{ + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return HPWH_ABORT; + } + return setOfSources[compressorIndex].isExternalMultipass(); +} - nextTankTemps_C[numNodes - 1] -= standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); - // UA loss from the sides are found at the bottom of the function. +bool HPWH::hasACompressor() const { return compressorIndex >= 0; } - } +bool HPWH::hasExternalHeatSource() const +{ + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + return true; + } + } + return false; +} +double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const +{ + if (!isCompressoExternalMultipass()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Does not have an external multipass heat source \n"); + } + return HPWH_ABORT; + } + + if (units == HPWH::UNITS_LPS) { + return setOfSources[compressorIndex].mpFlowRate_LPS; + } + else if (units == HPWH::UNITS_GPM) { + return LPS_TO_GPM(setOfSources[compressorIndex].mpFlowRate_LPS); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getExternalMPFlowRate. \n"); + } + return (double)HPWH_ABORT; + } +} + +double HPWH::getCompressorMinRuntime(UNITS units /*=UNITS_MIN*/) const +{ - //calculate standby losses from the sides of the tank - for (int i = 0; i < numNodes; i++) { - //faction of tank area on the sides - //kJ's lost as standby in the current time step for each node. - double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaSide + fittingsUA_kJperHrC) / numNodes * (tankTemps_C[i] - tankAmbientT_C) * (minutesPerStep / 60.0); - standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + if (hasACompressor()) { + double min_minutes = 10.; + + if (units == UNITS_MIN) { + return min_minutes; + } + else if (units == UNITS_SEC) { + return MIN_TO_SEC(min_minutes); + } + else if (units == UNITS_HR) { + return MIN_TO_HR(min_minutes); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for getCompressorMinRunTime. \n"); + } + return (double)HPWH_ABORT; + } + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("This HPWH has no compressor. \n"); + } + return (double)HPWH_ABORT; + } +} + +int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const +{ + double aFract = 1.; + double useFract = 1.; + + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return HPWH_ABORT; + } + else if (usesSoCLogic) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model uses SOC control logic and does not have a definition for sizing " + "fractions. \n"); + } + return HPWH_ABORT; + } + + // Every compressor must have at least one on logic + for (std::shared_ptr onLogic : setOfSources[compressorIndex].turnOnLogicSet) { + double tempA; + + if (hpwhVerbosity >= VRB_emetic) { + msg("\tturnon logic: %s ", onLogic->description.c_str()); + } + tempA = onLogic->nodeWeightAvgFract(); // if standby logic will return 1 + aFract = tempA < aFract ? tempA : aFract; + } + aquaFract = aFract; + + // Compressors don't need to have an off logic + if (setOfSources[compressorIndex].shutOffLogicSet.size() != 0) { + for (std::shared_ptr offLogic : + setOfSources[compressorIndex].shutOffLogicSet) { + + double tempUse; + + if (hpwhVerbosity >= VRB_emetic) { + msg("\tshutsOff logic: %s ", offLogic->description.c_str()); + } + if (offLogic->description == "large draw" || offLogic->description == "larger draw") { + tempUse = + 1.; // These logics are just for checking if there's a big draw to switch to RE + } + else { + tempUse = 1. - offLogic->nodeWeightAvgFract(); + } + useFract = + tempUse < useFract ? tempUse : useFract; // Will return the smallest case of the + // useable fraction for multiple off logics + } + useableFract = useFract; + } + else { + if (hpwhVerbosity >= VRB_emetic) { + msg("\no shutoff logics present"); + } + useableFract = 1.; + } + + // Check if double's are approximately equally and adjust the relationship so it follows the + // relationship we expect. The tolerance plays with 0.1 mm in position if the tank is 1m tall... + double temp = 1. - useableFract; + if (aboutEqual(aquaFract, temp)) { + useableFract = 1. - aquaFract + TOL_MINVALUE; + } + + return 0; +} + +bool HPWH::isHPWHScalable() const { return canScale; } + +int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP /*=1.0*/) +{ + if (!isHPWHScalable()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not scale the HPWH Capacity or COP \n"); + } + return HPWH_ABORT; + } + if (!hasACompressor()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Current model does not have a compressor. \n"); + } + return HPWH_ABORT; + } + if (scaleCapacity <= 0 || scaleCOP <= 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not scale the HPWH Capacity or COP to 0 or less than 0 \n"); + } + return HPWH_ABORT; + } + + for (auto& perfP : setOfSources[compressorIndex].perfMap) { + if (scaleCapacity != 1.) { + std::transform( + perfP.inputPower_coeffs.begin(), + perfP.inputPower_coeffs.end(), + perfP.inputPower_coeffs.begin(), + std::bind(std::multiplies(), std::placeholders::_1, scaleCapacity)); + } + if (scaleCOP != 1.) { + std::transform(perfP.COP_coeffs.begin(), + perfP.COP_coeffs.end(), + perfP.COP_coeffs.begin(), + std::bind(std::multiplies(), std::placeholders::_1, scaleCOP)); + } + } + + return 0; +} + +int HPWH::setCompressorOutputCapacity(double newCapacity, + double airTemp /*=19.722*/, + double inletTemp /*=14.444*/, + double outTemp /*=57.222*/, + UNITS pwrUnit /*=UNITS_KW*/, + UNITS tempUnit /*=UNITS_C*/) +{ - //The effect of standby loss on temperature in each node - nextTankTemps_C[i] -= standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); - } + double oldCapacity = getCompressorCapacity(airTemp, inletTemp, outTemp, pwrUnit, tempUnit); + if (oldCapacity == double(HPWH_ABORT)) { + return HPWH_ABORT; + } + double scale = newCapacity / oldCapacity; + return setScaleHPWHCapacityCOP(scale, 1.); // Scale the compressor capacity +} - // Assign the new temporary tank temps to the real tank temps. - for (int i = 0; i < numNodes; i++) tankTemps_C[i] = nextTankTemps_C[i]; +int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW*/) +{ - // check for inverted temperature profile - mixTankInversions(); + // Input checks + if (!isHPWHScalable()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not scale the resistance elements \n"); + } + return HPWH_ABORT; + } + if (getNumResistanceElements() == 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("There are no resistance elements to set capacity for \n"); + } + return HPWH_ABORT; + } + if (which < -1 || which > getNumResistanceElements() - 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds value for which in setResistanceCapacity()\n"); + } + return HPWH_ABORT; + } + if (power < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Can not have a negative input power \n"); + } + return HPWH_ABORT; + } + // Unit conversion + double watts; + if (pwrUnit == UNITS_KW) { + watts = power * 1000; // kW to W + } + else if (pwrUnit == UNITS_BTUperHr) { + watts = BTU_TO_KWH(power) * 1000; // BTU to kW then kW to W + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for capacity in setResistanceCapacity. \n"); + } + return HPWH_ABORT; + } + + // Whew so many checks... + if (which == -1) { + // Just get all the elements + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isAResistance()) { + setOfSources[i].changeResistanceWatts(watts); + } + } + } + else { + setOfSources[resistanceHeightMap[which].index].changeResistanceWatts(watts); + + // Then check for repeats in the position + int pos = resistanceHeightMap[which].position; + for (int i = 0; i < getNumResistanceElements(); i++) { + if (which != i && resistanceHeightMap[i].position == pos) { + setOfSources[resistanceHeightMap[i].index].changeResistanceWatts(watts); + } + } + } + + return 0; +} + +double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW*/) +{ -} //end updateTankTemps + // Input checks + if (getNumResistanceElements() == 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("There are no resistance elements to return capacity for \n"); + } + return HPWH_ABORT; + } + if (which < -1 || which > getNumResistanceElements() - 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds value for which in getResistanceCapacity()\n"); + } + return HPWH_ABORT; + } + + double returnPower = 0; + if (which == -1) { + // Just get all the elements + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isAResistance()) { + returnPower += setOfSources[i].perfMap[0].inputPower_coeffs[0]; + } + } + } + else { + // get the power from "which" element by height + returnPower += + setOfSources[resistanceHeightMap[which].index].perfMap[0].inputPower_coeffs[0]; + + // Then check for repeats in the position + int pos = resistanceHeightMap[which].position; + for (int i = 0; i < getNumResistanceElements(); i++) { + if (which != i && resistanceHeightMap[i].position == pos) { + returnPower += + setOfSources[resistanceHeightMap[i].index].perfMap[0].inputPower_coeffs[0]; + } + } + } + + // Unit conversion + if (pwrUnit == UNITS_KW) { + returnPower /= 1000.; // W to KW + } + else if (pwrUnit == UNITS_BTUperHr) { + returnPower = KWH_TO_BTU(returnPower / 1000.); // W to BTU/hr + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect unit specification for capacity in getResistanceCapacity. \n"); + } + return HPWH_ABORT; + } + + return returnPower; +} + +int HPWH::getResistancePosition(int elementIndex) const +{ -void HPWH::updateSoCIfNecessary() { - if (usesSoCLogic) { - calcAndSetSoCFraction(); - } + if (elementIndex < 0 || elementIndex > numHeatSources - 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds value for which in getResistancePosition\n"); + } + return HPWH_ABORT; + } + + if (!setOfSources[elementIndex].isAResistance()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("This index is not a resistance element\n"); + } + return HPWH_ABORT; + } + + for (int i = 0; i < CONDENSITY_SIZE; i++) { + if (setOfSources[elementIndex].condensity[i] == + 1) { // res elements have a condenstiy of 1 at a specific node + return i; + } + } + return HPWH_ABORT; +} + +// the privates +void HPWH::updateTankTemps(double drawVolume_L, + double inletT_C, + double tankAmbientT_C, + double inletVol2_L, + double inletT2_C) +{ + // set up some useful variables for calculations + double drawFraction; + this->outletTemp_C = 0.; + double nodeInletFraction, cumInletFraction, drawVolume_N; + double nodeInletTV = 0.; + + if (drawVolume_L > 0.) { + + // calculate how many nodes to draw (wholeNodesToDraw), and the remainder (drawFraction) + if (inletVol2_L > drawVolume_L) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Volume in inlet 2 is greater than the draw volume. \n"); + } + simHasFailed = true; + return; + } + + // Check which inlet is higher; + int highInletH; + double highInletV, highInletT; + int lowInletH; + double lowInletT, lowInletV; + if (inletHeight > inlet2Height) { + highInletH = inletHeight; + highInletV = drawVolume_L - inletVol2_L; + highInletT = inletT_C; + lowInletH = inlet2Height; + lowInletT = inletT2_C; + lowInletV = inletVol2_L; + } + else { + highInletH = inlet2Height; + highInletV = inletVol2_L; + highInletT = inletT2_C; + lowInletH = inletHeight; + lowInletT = inletT_C; + lowInletV = drawVolume_L - inletVol2_L; + } + // calculate how many nodes to draw (drawVolume_N) + drawVolume_N = drawVolume_L / volPerNode_LperNode; + if (drawVolume_L > tankVolume_L) { + // if (hpwhVerbosity >= 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"); + // } + // simHasFailed = true; + // return; + for (int i = 0; i < numNodes; i++) { + outletTemp_C += tankTemps_C[i]; + tankTemps_C[i] = + (inletT_C * (drawVolume_L - inletVol2_L) + inletT2_C * inletVol2_L) / + drawVolume_L; + } + outletTemp_C = (outletTemp_C / numNodes * tankVolume_L + + tankTemps_C[0] * (drawVolume_L - tankVolume_L)) / + drawVolume_L * (drawVolume_L / volPerNode_LperNode); + + drawVolume_N = 0.; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////// + + while (drawVolume_N > 0) { + + // Draw one node at a time + drawFraction = drawVolume_N > 1. ? 1. : drawVolume_N; + + // add temperature for outletT average + outletTemp_C += drawFraction * tankTemps_C[numNodes - 1]; + + cumInletFraction = 0.; + for (int i = numNodes - 1; i >= lowInletH; i--) { + + // Reset inlet inputs at this node. + nodeInletFraction = 0.; + nodeInletTV = 0.; + + // Sum of all inlets Vi*Ti at this node + if (i == highInletH) { + nodeInletTV += highInletV * drawFraction / drawVolume_L * highInletT; + nodeInletFraction += highInletV * drawFraction / drawVolume_L; + } + if (i == lowInletH) { + nodeInletTV += lowInletV * drawFraction / drawVolume_L * lowInletT; + nodeInletFraction += lowInletV * drawFraction / drawVolume_L; + + break; // if this is the bottom inlet break out of the four loop and use the + // boundary condition equation. + } + + // Look at the volume and temperature fluxes into this node + tankTemps_C[i] = + (1. - (drawFraction - cumInletFraction)) * tankTemps_C[i] + nodeInletTV + + (drawFraction - (cumInletFraction + nodeInletFraction)) * tankTemps_C[i - 1]; + + cumInletFraction += nodeInletFraction; + } + + // Boundary condition equation because it shouldn't take anything from tankTemps_C[i - + // 1] but it also might not exist. + tankTemps_C[lowInletH] = + (1. - (drawFraction - cumInletFraction)) * tankTemps_C[lowInletH] + nodeInletTV; + + drawVolume_N -= drawFraction; + + mixTankInversions(); + } + + // fill in average outlet T - it is a weighted averaged, with weights == nodes drawn + this->outletTemp_C /= (drawVolume_L / volPerNode_LperNode); + + ///////////////////////////////////////////////////////////////////////////////////////////////// + + // Account for mixing at the bottom of the tank + if (tankMixesOnDraw && drawVolume_L > 0.) { + int mixedBelowNode = (int)(numNodes * mixBelowFractionOnDraw); + mixTankNodes(0, mixedBelowNode, 3.0); + } + + } // end if(draw_volume_L > 0) + + if (doConduction) { + + // Get the "constant" tau for the stability condition and the conduction calculation + const double tau = KWATER_WpermC / + (CPWATER_kJperkgC * 1000.0 * DENSITYWATER_kgperL * 1000.0 * + (node_height * node_height)) * + minutesPerStep * 60.0; + if (tau > 0.5) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The stability condition for conduction has failed, these results are going to " + "be interesting!\n"); + } + simHasFailed = true; + return; + } + + // Boundary condition for the finite difference. + const double bc = 2.0 * tau * tankUA_kJperHrC * fracAreaTop * node_height / KWATER_WpermC; + + // Boundary nodes for finite difference + nextTankTemps_C[0] = (1.0 - 2.0 * tau - bc) * tankTemps_C[0] + 2.0 * tau * tankTemps_C[1] + + bc * tankAmbientT_C; + nextTankTemps_C[numNodes - 1] = (1.0 - 2.0 * tau - bc) * tankTemps_C[numNodes - 1] + + 2.0 * tau * tankTemps_C[numNodes - 2] + bc * tankAmbientT_C; + + // Internal nodes for the finite difference + for (int i = 1; i < numNodes - 1; i++) { + nextTankTemps_C[i] = tankTemps_C[i] + tau * (tankTemps_C[i + 1] - 2.0 * tankTemps_C[i] + + tankTemps_C[i - 1]); + } + + // nextTankTemps_C gets assigns to tankTemps_C at the bottom of the function after q_UA. + // UA loss from the sides are found at the bottom of the function. + double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * + (tankTemps_C[0] - tankAmbientT_C) * (minutesPerStep / 60.0)); + standbyLosses_kJ += + (tankUA_kJperHrC * fracAreaTop * (tankTemps_C[numNodes - 1] - tankAmbientT_C) * + (minutesPerStep / 60.0)); + standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + } + else { // Ignore tank conduction and calculate UA losses from top and bottom. UA loss from the + // sides are found at the bottom of the function + + for (int i = 0; i < numNodes; i++) { + nextTankTemps_C[i] = tankTemps_C[i]; + } + + // kJ's lost as standby in the current time step for the top node. + double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * + (tankTemps_C[0] - tankAmbientT_C) * (minutesPerStep / 60.0)); + standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + + nextTankTemps_C[0] -= + standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); + + // kJ's lost as standby in the current time step for the bottom node. + standbyLosses_kJ = (tankUA_kJperHrC * fracAreaTop * + (tankTemps_C[numNodes - 1] - tankAmbientT_C) * (minutesPerStep / 60.0)); + standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + + nextTankTemps_C[numNodes - 1] -= + standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); + // UA loss from the sides are found at the bottom of the function. + } + + // calculate standby losses from the sides of the tank + for (int i = 0; i < numNodes; i++) { + // faction of tank area on the sides + // kJ's lost as standby in the current time step for each node. + double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaSide + fittingsUA_kJperHrC) / + numNodes * (tankTemps_C[i] - tankAmbientT_C) * + (minutesPerStep / 60.0); + standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); + + // The effect of standby loss on temperature in each node + nextTankTemps_C[i] -= + standbyLosses_kJ / ((volPerNode_LperNode * DENSITYWATER_kgperL) * CPWATER_kJperkgC); + } + + // Assign the new temporary tank temps to the real tank temps. + for (int i = 0; i < numNodes; i++) + tankTemps_C[i] = nextTankTemps_C[i]; + + // check for inverted temperature profile + mixTankInversions(); + +} // end updateTankTemps + +void HPWH::updateSoCIfNecessary() +{ + if (usesSoCLogic) { + calcAndSetSoCFraction(); + } } // Inversion mixing modeled after bigladder EnergyPlus code PK -void HPWH::mixTankInversions() { - bool hasInversion; - const double volumePerNode_L = tankVolume_L / numNodes; - //int numdos = 0; - if(doInversionMixing) { - do { - hasInversion = false; - //Start from the top and check downwards - for (int i = numNodes - 1; i > 0; i--) { - if (tankTemps_C[i] < tankTemps_C[i - 1]) { - // Temperature inversion! - hasInversion = true; - - //Mix this inversion mixing temperature by averaging all of the inverted nodes together together. - double Tmixed = 0.0; - double massMixed = 0.0; - int m; - for (m = i; m >= 0; m--) { - Tmixed += tankTemps_C[m] * (volumePerNode_L * DENSITYWATER_kgperL); - massMixed += (volumePerNode_L * DENSITYWATER_kgperL); - if ((m == 0) || (Tmixed / massMixed > tankTemps_C[m - 1])) { - break; - } - } - Tmixed /= massMixed; - - // Assign the tank temps from i to k - for (int k = i; k >= m; k--) tankTemps_C[k] = Tmixed; - } - - } - - } while (hasInversion); - } -} - - -void HPWH::addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbientT_C){ - if ((*nodePowerExtra_W).size() > CONDENSITY_SIZE){ - if (hpwhVerbosity >= VRB_reluctant) { - msg("nodeExtraHeat_KWH (%i) has size greater than %d \n", (*nodePowerExtra_W).size(), CONDENSITY_SIZE); - } - simHasFailed = true; - } - - //for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++){ - // tankTemps_C[i] += (*nodePowerExtra_W)[i] * minutesPerStep * 60. / (CPWATER_kJperkgC * 1000. * DENSITYWATER_kgperL * tankVolume_L / numNodes); - //} - //mixTankInversions(); - - for (int i = 0; i < numHeatSources; i++){ - if (setOfSources[i].typeOfHeatSource == TYPE_extra) { - - // Set up the extra heat source - setOfSources[i].setupExtraHeat(nodePowerExtra_W); - - // condentropy/shrinkage and lowestNode are now in calcDerivedHeatingValues() - calcDerivedHeatingValues(); - - // add heat - setOfSources[i].addHeat(tankAmbientT_C, minutesPerStep); - - // 0 out to ignore features - setOfSources[i].perfMap.clear(); - setOfSources[i].energyInput_kWh = 0.0; - setOfSources[i].energyOutput_kWh = 0.0; - } - } +void HPWH::mixTankInversions() +{ + bool hasInversion; + const double volumePerNode_L = tankVolume_L / numNodes; + // int numdos = 0; + if (doInversionMixing) { + do { + hasInversion = false; + // Start from the top and check downwards + for (int i = numNodes - 1; i > 0; i--) { + if (tankTemps_C[i] < tankTemps_C[i - 1]) { + // Temperature inversion! + hasInversion = true; + + // Mix this inversion mixing temperature by averaging all of the inverted nodes + // together together. + double Tmixed = 0.0; + double massMixed = 0.0; + int m; + for (m = i; m >= 0; m--) { + Tmixed += tankTemps_C[m] * (volumePerNode_L * DENSITYWATER_kgperL); + massMixed += (volumePerNode_L * DENSITYWATER_kgperL); + if ((m == 0) || (Tmixed / massMixed > tankTemps_C[m - 1])) { + break; + } + } + Tmixed /= massMixed; + + // Assign the tank temps from i to k + for (int k = i; k >= m; k--) + tankTemps_C[k] = Tmixed; + } + } + + } while (hasInversion); + } +} + +void HPWH::addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbientT_C) +{ + if ((*nodePowerExtra_W).size() > CONDENSITY_SIZE) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("nodeExtraHeat_KWH (%i) has size greater than %d \n", + (*nodePowerExtra_W).size(), + CONDENSITY_SIZE); + } + simHasFailed = true; + } + + // for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++){ + // tankTemps_C[i] += (*nodePowerExtra_W)[i] * minutesPerStep * 60. / (CPWATER_kJperkgC * 1000. + //* DENSITYWATER_kgperL * tankVolume_L / numNodes); + // } + // mixTankInversions(); + + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].typeOfHeatSource == TYPE_extra) { + + // Set up the extra heat source + setOfSources[i].setupExtraHeat(nodePowerExtra_W); + + // condentropy/shrinkage and lowestNode are now in calcDerivedHeatingValues() + calcDerivedHeatingValues(); + + // add heat + setOfSources[i].addHeat(tankAmbientT_C, minutesPerStep); + + // 0 out to ignore features + setOfSources[i].perfMap.clear(); + setOfSources[i].energyInput_kWh = 0.0; + setOfSources[i].energyOutput_kWh = 0.0; + } + } } /////////////////////////////////////////////////////////////////////////////////// +void HPWH::turnAllHeatSourcesOff() +{ + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i].disengageHeatSource(); + } + isHeating = false; +} + +bool HPWH::areAllHeatSourcesOff() const +{ + bool allOff = true; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isEngaged() == true) { + allOff = false; + } + } + return allOff; +} + +double HPWH::tankAvg_C(const std::vector nodeWeights) const +{ + double sum = 0; + double totWeight = 0; + + for (NodeWeight nodeWeight : nodeWeights) { + // bottom calc node only + if (nodeWeight.nodeNum == 0) { + sum += tankTemps_C[0] * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + // top calc node only + else if (nodeWeight.nodeNum == 13) { + sum += tankTemps_C[numNodes - 1] * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + else { + for (int n = 0; n < nodeDensity; ++n) { + int calcNode = (nodeWeight.nodeNum - 1) * nodeDensity + n; + sum += tankTemps_C[calcNode] * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + } + } + return sum / totWeight; +} + +void HPWH::mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor) +{ + double ave = 0.; + double numAvgNodes = (double)(mixedBelowNode - mixedAboveNode); + for (int i = mixedAboveNode; i < mixedBelowNode; i++) { + ave += tankTemps_C[i]; + } + ave /= numAvgNodes; + + for (int i = mixedAboveNode; i < mixedBelowNode; i++) { + tankTemps_C[i] += ((ave - tankTemps_C[i]) / mixFactor); + // tankTemps_C[i] = tankTemps_C[i] * (1.0 - 1.0 / mixFactor) + ave / mixFactor; + } +} + +// these are the HeatSource functions +// the public functions +HPWH::HeatSource::HeatSource(HPWH* parentInput) + : hpwh(parentInput) + , isOn(false) + , lockedOut(false) + , doDefrost(false) + , backupHeatSource(NULL) + , companionHeatSource(NULL) + , followedByHeatSource(NULL) + , minT(-273.15) + , maxT(100) + , hysteresis_dC(0) + , airflowFreedom(1.0) + , maxSetpoint_C(100.) + , typeOfHeatSource(TYPE_none) + , extrapolationMethod(EXTRAP_LINEAR) + , maxOut_at_LowT {100, -273.15} + , standbyLogic(NULL) + , isMultipass(true) + , mpFlowRate_LPS(0.) + , externalInletHeight(-1) + , externalOutletHeight(-1) + , useBtwxtGrid(false) + , secondaryHeatExchanger {0., 0., 0.} +{ +} + +HPWH::HeatSource::HeatSource(const HeatSource& hSource) +{ + hpwh = hSource.hpwh; + isOn = hSource.isOn; + lockedOut = hSource.lockedOut; + doDefrost = hSource.doDefrost; + + runtime_min = hSource.runtime_min; + energyInput_kWh = hSource.energyInput_kWh; + energyOutput_kWh = hSource.energyOutput_kWh; + + isVIP = hSource.isVIP; + + if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || + hSource.followedByHeatSource != NULL) { + hpwh->simHasFailed = true; + if (hpwh->hpwhVerbosity >= VRB_reluctant) { + hpwh->msg( + "HeatSources cannot be copied if they contain pointers to other HeatSources\n"); + } + } + + for (int i = 0; i < CONDENSITY_SIZE; i++) { + condensity[i] = hSource.condensity[i]; + } + shrinkage = hSource.shrinkage; + + perfMap = hSource.perfMap; + + perfGrid = hSource.perfGrid; + perfGridValues = hSource.perfGridValues; + perfRGI = hSource.perfRGI; + useBtwxtGrid = hSource.useBtwxtGrid; + + defrostMap = hSource.defrostMap; + resDefrost = hSource.resDefrost; + + // i think vector assignment works correctly here + turnOnLogicSet = hSource.turnOnLogicSet; + shutOffLogicSet = hSource.shutOffLogicSet; + standbyLogic = hSource.standbyLogic; + + minT = hSource.minT; + maxT = hSource.maxT; + maxOut_at_LowT = hSource.maxOut_at_LowT; + hysteresis_dC = hSource.hysteresis_dC; + maxSetpoint_C = hSource.maxSetpoint_C; + + depressesTemperature = hSource.depressesTemperature; + airflowFreedom = hSource.airflowFreedom; + + configuration = hSource.configuration; + typeOfHeatSource = hSource.typeOfHeatSource; + isMultipass = hSource.isMultipass; + mpFlowRate_LPS = hSource.mpFlowRate_LPS; + + externalInletHeight = hSource.externalInletHeight; + externalOutletHeight = hSource.externalOutletHeight; + + lowestNode = hSource.lowestNode; + + extrapolationMethod = hSource.extrapolationMethod; + secondaryHeatExchanger = hSource.secondaryHeatExchanger; +} + +HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource& hSource) +{ + if (this == &hSource) { + return *this; + } + + hpwh = hSource.hpwh; + isOn = hSource.isOn; + lockedOut = hSource.lockedOut; + doDefrost = hSource.doDefrost; + + runtime_min = hSource.runtime_min; + energyInput_kWh = hSource.energyInput_kWh; + energyOutput_kWh = hSource.energyOutput_kWh; + + isVIP = hSource.isVIP; + + if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || + hSource.followedByHeatSource != NULL) { + hpwh->simHasFailed = true; + if (hpwh->hpwhVerbosity >= VRB_reluctant) { + hpwh->msg( + "HeatSources cannot be copied if they contain pointers to other HeatSources\n"); + } + } + else { + companionHeatSource = NULL; + backupHeatSource = NULL; + followedByHeatSource = NULL; + } + + for (int i = 0; i < CONDENSITY_SIZE; i++) { + condensity[i] = hSource.condensity[i]; + } + shrinkage = hSource.shrinkage; + + perfMap = hSource.perfMap; + + perfGrid = hSource.perfGrid; + perfGridValues = hSource.perfGridValues; + perfRGI = hSource.perfRGI; + useBtwxtGrid = hSource.useBtwxtGrid; + + defrostMap = hSource.defrostMap; + resDefrost = hSource.resDefrost; + + // i think vector assignment works correctly here + turnOnLogicSet = hSource.turnOnLogicSet; + shutOffLogicSet = hSource.shutOffLogicSet; + standbyLogic = hSource.standbyLogic; + + minT = hSource.minT; + maxT = hSource.maxT; + maxOut_at_LowT = hSource.maxOut_at_LowT; + hysteresis_dC = hSource.hysteresis_dC; + maxSetpoint_C = hSource.maxSetpoint_C; + + depressesTemperature = hSource.depressesTemperature; + airflowFreedom = hSource.airflowFreedom; + + configuration = hSource.configuration; + typeOfHeatSource = hSource.typeOfHeatSource; + isMultipass = hSource.isMultipass; + mpFlowRate_LPS = hSource.mpFlowRate_LPS; + + externalInletHeight = hSource.externalInletHeight; + externalOutletHeight = hSource.externalOutletHeight; + + lowestNode = hSource.lowestNode; + extrapolationMethod = hSource.extrapolationMethod; + secondaryHeatExchanger = hSource.secondaryHeatExchanger; + + return *this; +} + +void HPWH::HeatSource::setCondensity(double cnd1, + double cnd2, + double cnd3, + double cnd4, + double cnd5, + double cnd6, + double cnd7, + double cnd8, + double cnd9, + double cnd10, + double cnd11, + double cnd12) +{ + condensity[0] = cnd1; + condensity[1] = cnd2; + condensity[2] = cnd3; + condensity[3] = cnd4; + condensity[4] = cnd5; + condensity[5] = cnd6; + condensity[6] = cnd7; + condensity[7] = cnd8; + condensity[8] = cnd9; + condensity[9] = cnd10; + condensity[10] = cnd11; + condensity[11] = cnd12; +} + +int HPWH::HeatSource::findParent() const +{ + for (int i = 0; i < hpwh->numHeatSources; ++i) { + if (this == hpwh->setOfSources[i].backupHeatSource) { + return i; + } + } + return -1; +} + +bool HPWH::HeatSource::isEngaged() const { return isOn; } + +bool HPWH::HeatSource::isLockedOut() const { return lockedOut; } + +void HPWH::HeatSource::lockOutHeatSource() { lockedOut = true; } + +void HPWH::HeatSource::unlockHeatSource() { lockedOut = false; } + +bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const +{ + + // if it's already locked out, keep it locked out + if (isLockedOut() == true) { + return true; + } + else { + // when the "external" temperature is too cold - typically used for compressor low temp. + // cutoffs when running, use hysteresis + bool lock = false; + if (isEngaged() == true && heatSourceAmbientT_C < minT - hysteresis_dC) { + lock = true; + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + hpwh->msg("\tlock-out: running below minT\tambient: %.2f\tminT: %.2f", + heatSourceAmbientT_C, + minT); + } + } + // when not running, don't use hysteresis + else if (isEngaged() == false && heatSourceAmbientT_C < minT) { + lock = true; + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + hpwh->msg("\tlock-out: already below minT\tambient: %.2f\tminT: %.2f", + heatSourceAmbientT_C, + minT); + } + } + + // when the "external" temperature is too warm - typically used for resistance lockout + // when running, use hysteresis + if (isEngaged() == true && heatSourceAmbientT_C > maxT + hysteresis_dC) { + lock = true; + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + hpwh->msg("\tlock-out: running above maxT\tambient: %.2f\tmaxT: %.2f", + heatSourceAmbientT_C, + maxT); + } + } + // when not running, don't use hysteresis + else if (isEngaged() == false && heatSourceAmbientT_C > maxT) { + lock = true; + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + hpwh->msg("\tlock-out: already above maxT\tambient: %.2f\tmaxT: %.2f", + heatSourceAmbientT_C, + maxT); + } + } + + if (maxedOut()) { + lock = true; + if (hpwh->hpwhVerbosity >= 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) { + // hpwh->msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. + //Simulation will continue without lock-out"); + // } + // lock = false; + // } + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("\n"); + } + return lock; + } +} + +bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const +{ + + // if it's already unlocked, keep it unlocked + if (isLockedOut() == false) { + return true; + } + // if it the heat source is capped and can't produce hotter water + else if (maxedOut()) { + return false; + } + else { + // when the "external" temperature is no longer too cold or too warm + // when running, use hysteresis + bool unlock = false; + if (isEngaged() == true && heatSourceAmbientT_C > minT + hysteresis_dC && + heatSourceAmbientT_C < maxT - hysteresis_dC) { + unlock = true; + if (hpwh->hpwhVerbosity >= 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) { + hpwh->msg("\tunlock: running below maxT\tambient: %.2f\tmaxT: %.2f", + heatSourceAmbientT_C, + maxT); + } + } + // when not running, don't use hysteresis + else if (isEngaged() == false && heatSourceAmbientT_C > minT && + heatSourceAmbientT_C < maxT) { + unlock = true; + if (hpwh->hpwhVerbosity >= 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) { + hpwh->msg("\tunlock: already below maxT\tambient: %.2f\tmaxT: %.2f", + heatSourceAmbientT_C, + maxT); + } + } + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("\n"); + } + return unlock; + } +} + +bool HPWH::HeatSource::toLockOrUnlock(double heatSourceAmbientT_C) +{ + + if (shouldLockOut(heatSourceAmbientT_C)) { + lockOutHeatSource(); + } + if (shouldUnlock(heatSourceAmbientT_C)) { + unlockHeatSource(); + } + + return isLockedOut(); +} + +bool HPWH::shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const +{ + + if (hs == TYPE_compressor && (DR_signal & DR_LOC) != 0) { + return true; + } + else if (hs == TYPE_resistance && (DR_signal & DR_LOR) != 0) { + return true; + } + return false; +} + +void HPWH::resetTopOffTimer() { timerTOT = 0.; } + +void HPWH::HeatSource::engageHeatSource(DRMODES DR_signal) +{ + isOn = true; + hpwh->isHeating = true; + if (companionHeatSource != NULL && companionHeatSource->shutsOff() != true && + companionHeatSource->isEngaged() == false && + hpwh->shouldDRLockOut(companionHeatSource->typeOfHeatSource, DR_signal) == false) { + companionHeatSource->engageHeatSource(DR_signal); + } +} + +void HPWH::HeatSource::disengageHeatSource() { isOn = false; } + +bool HPWH::HeatSource::shouldHeat() const +{ + // return true if the heat source logic tells it to come on, false if it doesn't, + // or if an unsepcified selector was used + bool shouldEngage = false; + + for (int i = 0; i < (int)turnOnLogicSet.size(); i++) { + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("\tshouldHeat logic: %s ", turnOnLogicSet[i]->description.c_str()); + } + + double average = turnOnLogicSet[i]->getTankValue(); + double comparison = turnOnLogicSet[i]->getComparisonValue(); + + if (turnOnLogicSet[i]->compare(average, comparison)) { + if (turnOnLogicSet[i]->description == "standby" && standbyLogic != NULL) { + double comparisonStandby = standbyLogic->getComparisonValue(); + double avgStandby = standbyLogic->getTankValue(); + + if (turnOnLogicSet[i]->compare(avgStandby, comparisonStandby)) { + shouldEngage = true; + } + } + else { + shouldEngage = true; + } + } + + // quit searching the logics if one of them turns it on + if (shouldEngage) { + // debugging message handling + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("engages!\n"); + } + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("average: %.2lf \t setpoint: %.2lf \t decisionPoint: %.2lf \t " + "comparison: %2.1f\n", + average, + hpwh->setpoint_C, + turnOnLogicSet[i]->getDecisionPoint(), + comparison); + } + break; + } + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("returns: %d \t", shouldEngage); + } + } // end loop over set of logic conditions + + // if everything else wants it to come on, but if it would shut off anyways don't turn it on + if (shouldEngage == true && shutsOff() == true) { + shouldEngage = false; + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("but is denied by shutsOff"); + } + } + + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("\n"); + } + return shouldEngage; +} + +bool HPWH::HeatSource::shutsOff() const +{ + bool shutOff = false; + + if (hpwh->tankTemps_C[0] >= hpwh->setpoint_C) { + shutOff = true; + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("shutsOff bottom node hot: %.2d C \n returns true", hpwh->tankTemps_C[0]); + } + return shutOff; + } + + for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); + } + + double average = shutOffLogicSet[i]->getTankValue(); + double comparison = shutOffLogicSet[i]->getComparisonValue(); + + if (shutOffLogicSet[i]->compare(average, comparison)) { + shutOff = true; + + // debugging message handling + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("shuts down %s\n", shutOffLogicSet[i]->description.c_str()); + } + } + } + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("returns: %d \n", shutOff); + } + return shutOff; +} + +bool HPWH::HeatSource::maxedOut() const +{ + bool maxed = false; + + // If the heat source can't produce water at the setpoint and the control logics are saying to + // shut off + if (hpwh->setpoint_C > maxSetpoint_C) { + if (hpwh->tankTemps_C[0] >= maxSetpoint_C || shutsOff()) { + maxed = true; + } + } + return maxed; +} + +double HPWH::HeatSource::fractToMeetComparisonExternal() const +{ + double fracTemp; + double frac = 1.; + + for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); + } -void HPWH::turnAllHeatSourcesOff() { - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i].disengageHeatSource(); - } - isHeating = false; -} - - -bool HPWH::areAllHeatSourcesOff() const { - bool allOff = true; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isEngaged() == true) { - allOff = false; - } - } - return allOff; -} - -double HPWH::tankAvg_C(const std::vector nodeWeights) const { - double sum = 0; - double totWeight = 0; - - for (NodeWeight nodeWeight : nodeWeights) { - // bottom calc node only - if (nodeWeight.nodeNum == 0) { - sum += tankTemps_C[0] * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - // top calc node only - else if (nodeWeight.nodeNum == 13) { - sum += tankTemps_C[numNodes - 1] * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - else { - for (int n = 0; n < nodeDensity; ++n) { - int calcNode = (nodeWeight.nodeNum - 1) * nodeDensity + n; - sum += tankTemps_C[calcNode] * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - } - } - return sum / totWeight; -} - -void HPWH::mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor ) { - double ave = 0.; - double numAvgNodes = (double) (mixedBelowNode - mixedAboveNode); - for (int i = mixedAboveNode; i < mixedBelowNode; i++) { - ave += tankTemps_C[i]; - } - ave /= numAvgNodes; - - for (int i = mixedAboveNode; i < mixedBelowNode; i++) { - tankTemps_C[i] += ((ave - tankTemps_C[i]) / mixFactor); - //tankTemps_C[i] = tankTemps_C[i] * (1.0 - 1.0 / mixFactor) + ave / mixFactor; - } -} - -//these are the HeatSource functions -//the public functions -HPWH::HeatSource::HeatSource(HPWH *parentInput) - :hpwh(parentInput), isOn(false), lockedOut(false), doDefrost(false), backupHeatSource(NULL), companionHeatSource(NULL), - followedByHeatSource(NULL), minT(-273.15), maxT(100), hysteresis_dC(0), airflowFreedom(1.0), maxSetpoint_C(100.), - typeOfHeatSource(TYPE_none), extrapolationMethod(EXTRAP_LINEAR), maxOut_at_LowT{ 100, -273.15 }, standbyLogic(NULL), - isMultipass(true), mpFlowRate_LPS(0.), externalInletHeight(-1), externalOutletHeight(-1), useBtwxtGrid(false), - secondaryHeatExchanger{ 0., 0., 0. } -{} - -HPWH::HeatSource::HeatSource(const HeatSource &hSource) { - hpwh = hSource.hpwh; - isOn = hSource.isOn; - lockedOut = hSource.lockedOut; - doDefrost = hSource.doDefrost; - - runtime_min = hSource.runtime_min; - energyInput_kWh = hSource.energyInput_kWh; - energyOutput_kWh = hSource.energyOutput_kWh; - - isVIP = hSource.isVIP; - - if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || hSource.followedByHeatSource != NULL) { - hpwh->simHasFailed = true; - if (hpwh->hpwhVerbosity >= VRB_reluctant) { - hpwh->msg("HeatSources cannot be copied if they contain pointers to other HeatSources\n"); - } - } - - for (int i = 0; i < CONDENSITY_SIZE; i++) { - condensity[i] = hSource.condensity[i]; - } - shrinkage = hSource.shrinkage; - - perfMap = hSource.perfMap; - - perfGrid = hSource.perfGrid; - perfGridValues = hSource.perfGridValues; - perfRGI = hSource.perfRGI; - useBtwxtGrid = hSource.useBtwxtGrid; - - defrostMap = hSource.defrostMap; - resDefrost = hSource.resDefrost; - - //i think vector assignment works correctly here - turnOnLogicSet = hSource.turnOnLogicSet; - shutOffLogicSet = hSource.shutOffLogicSet; - standbyLogic = hSource.standbyLogic; - - minT = hSource.minT; - maxT = hSource.maxT; - maxOut_at_LowT = hSource.maxOut_at_LowT; - hysteresis_dC = hSource.hysteresis_dC; - maxSetpoint_C = hSource.maxSetpoint_C; - - depressesTemperature = hSource.depressesTemperature; - airflowFreedom = hSource.airflowFreedom; - - configuration = hSource.configuration; - typeOfHeatSource = hSource.typeOfHeatSource; - isMultipass = hSource.isMultipass; - mpFlowRate_LPS = hSource.mpFlowRate_LPS; - - externalInletHeight = hSource.externalInletHeight; - externalOutletHeight = hSource.externalOutletHeight; - - lowestNode = hSource.lowestNode; - - extrapolationMethod = hSource.extrapolationMethod; - secondaryHeatExchanger = hSource.secondaryHeatExchanger; -} - -HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource &hSource) { - if (this == &hSource) { - return *this; - } - - hpwh = hSource.hpwh; - isOn = hSource.isOn; - lockedOut = hSource.lockedOut; - doDefrost = hSource.doDefrost; - - runtime_min = hSource.runtime_min; - energyInput_kWh = hSource.energyInput_kWh; - energyOutput_kWh = hSource.energyOutput_kWh; + fracTemp = shutOffLogicSet[i]->getFractToMeetComparisonExternal(); - isVIP = hSource.isVIP; + frac = fracTemp < frac ? fracTemp : frac; + } - if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || hSource.followedByHeatSource != NULL) { - hpwh->simHasFailed = true; - if (hpwh->hpwhVerbosity >= VRB_reluctant) { - hpwh->msg("HeatSources cannot be copied if they contain pointers to other HeatSources\n"); - } - } - else { - companionHeatSource = NULL; - backupHeatSource = NULL; - followedByHeatSource = NULL; - } + return frac; +} - for (int i = 0; i < CONDENSITY_SIZE; i++) { - condensity[i] = hSource.condensity[i]; - } - shrinkage = hSource.shrinkage; - - perfMap = hSource.perfMap; - - perfGrid = hSource.perfGrid; - perfGridValues = hSource.perfGridValues; - perfRGI = hSource.perfRGI; - useBtwxtGrid = hSource.useBtwxtGrid; - - defrostMap = hSource.defrostMap; - resDefrost = hSource.resDefrost; - - //i think vector assignment works correctly here - turnOnLogicSet = hSource.turnOnLogicSet; - shutOffLogicSet = hSource.shutOffLogicSet; - standbyLogic = hSource.standbyLogic; - - minT = hSource.minT; - maxT = hSource.maxT; - maxOut_at_LowT = hSource.maxOut_at_LowT; - hysteresis_dC = hSource.hysteresis_dC; - maxSetpoint_C = hSource.maxSetpoint_C; - - depressesTemperature = hSource.depressesTemperature; - airflowFreedom = hSource.airflowFreedom; - - configuration = hSource.configuration; - typeOfHeatSource = hSource.typeOfHeatSource; - isMultipass = hSource.isMultipass; - mpFlowRate_LPS = hSource.mpFlowRate_LPS; - - externalInletHeight = hSource.externalInletHeight; - externalOutletHeight = hSource.externalOutletHeight; - - lowestNode = hSource.lowestNode; - extrapolationMethod = hSource.extrapolationMethod; - secondaryHeatExchanger = hSource.secondaryHeatExchanger; - - return *this; -} - - - -void HPWH::HeatSource::setCondensity(double cnd1, double cnd2, double cnd3, double cnd4, - double cnd5, double cnd6, double cnd7, double cnd8, - double cnd9, double cnd10, double cnd11, double cnd12) { - condensity[0] = cnd1; - condensity[1] = cnd2; - condensity[2] = cnd3; - condensity[3] = cnd4; - condensity[4] = cnd5; - condensity[5] = cnd6; - condensity[6] = cnd7; - condensity[7] = cnd8; - condensity[8] = cnd9; - condensity[9] = cnd10; - condensity[10] = cnd11; - condensity[11] = cnd12; -} - -int HPWH::HeatSource::findParent() const { - for (int i = 0; i < hpwh->numHeatSources; ++i) { - if (this == hpwh->setOfSources[i].backupHeatSource) { - return i; - } - } - return -1; -} - -bool HPWH::HeatSource::isEngaged() const { - return isOn; -} - -bool HPWH::HeatSource::isLockedOut() const { - return lockedOut; -} - -void HPWH::HeatSource::lockOutHeatSource() { - lockedOut = true; -} - -void HPWH::HeatSource::unlockHeatSource() { - lockedOut = false; -} - -bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const { - - // if it's already locked out, keep it locked out - if (isLockedOut() == true) { - return true; - } - else { - //when the "external" temperature is too cold - typically used for compressor low temp. cutoffs - //when running, use hysteresis - bool lock = false; - if (isEngaged() == true && heatSourceAmbientT_C < minT - hysteresis_dC) { - lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { - hpwh->msg("\tlock-out: running below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); - } - } - //when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C < minT) { - lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { - hpwh->msg("\tlock-out: already below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); - } - } - - //when the "external" temperature is too warm - typically used for resistance lockout - //when running, use hysteresis - if (isEngaged() == true && heatSourceAmbientT_C > maxT + hysteresis_dC) { - lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { - hpwh->msg("\tlock-out: running above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); - } - } - //when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C > maxT) { - lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { - hpwh->msg("\tlock-out: already above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); - } - } - - if (maxedOut()) { - lock = true; - if (hpwh->hpwhVerbosity >= 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) { - // hpwh->msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. Simulation will continue without lock-out"); - // } - // lock = false; - // } - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("\n"); - } - return lock; - } -} - -bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const { - - // if it's already unlocked, keep it unlocked - if (isLockedOut() == false) { - return true; - } - // if it the heat source is capped and can't produce hotter water - else if (maxedOut()) { - return false; - } - else { - //when the "external" temperature is no longer too cold or too warm - //when running, use hysteresis - bool unlock = false; - if (isEngaged() == true && heatSourceAmbientT_C > minT + hysteresis_dC && heatSourceAmbientT_C < maxT - hysteresis_dC) { - unlock = true; - if (hpwh->hpwhVerbosity >= 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) { - hpwh->msg("\tunlock: running below maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); - } - } - //when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C > minT && heatSourceAmbientT_C < maxT) { - unlock = true; - if (hpwh->hpwhVerbosity >= 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) { - hpwh->msg("\tunlock: already below maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); - } - } - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("\n"); - } - return unlock; - } -} - -bool HPWH::HeatSource::toLockOrUnlock(double heatSourceAmbientT_C) { - - if (shouldLockOut(heatSourceAmbientT_C)) { - lockOutHeatSource(); - } - if (shouldUnlock(heatSourceAmbientT_C)) { - unlockHeatSource(); - } - - return isLockedOut(); -} - -bool HPWH::shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const { - - if (hs == TYPE_compressor && (DR_signal & DR_LOC) != 0) { - return true; - } - else if (hs == TYPE_resistance && (DR_signal & DR_LOR) != 0) { - return true; - } - return false; -} - -void HPWH::resetTopOffTimer() { - timerTOT = 0.; -} - -void HPWH::HeatSource::engageHeatSource(DRMODES DR_signal) { - isOn = true; - hpwh->isHeating = true; - if (companionHeatSource != NULL && - companionHeatSource->shutsOff() != true && - companionHeatSource->isEngaged() == false && - hpwh->shouldDRLockOut(companionHeatSource->typeOfHeatSource, DR_signal) == false) - { - companionHeatSource->engageHeatSource(DR_signal); - } -} - - -void HPWH::HeatSource::disengageHeatSource() { - isOn = false; -} - -bool HPWH::HeatSource::shouldHeat() const { - //return true if the heat source logic tells it to come on, false if it doesn't, - //or if an unsepcified selector was used - bool shouldEngage = false; - - for (int i = 0; i < (int)turnOnLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("\tshouldHeat logic: %s ", turnOnLogicSet[i]->description.c_str()); - } - - double average = turnOnLogicSet[i]->getTankValue(); - double comparison = turnOnLogicSet[i]->getComparisonValue(); - - if (turnOnLogicSet[i]->compare(average, comparison)) { - if (turnOnLogicSet[i]->description == "standby" && standbyLogic != NULL) { - double comparisonStandby = standbyLogic->getComparisonValue(); - double avgStandby = standbyLogic->getTankValue(); - - if (turnOnLogicSet[i]->compare(avgStandby, comparisonStandby)) { - shouldEngage = true; - } - } - else{ - shouldEngage = true; - } - } - - //quit searching the logics if one of them turns it on - if (shouldEngage) { - //debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("engages!\n"); - } - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("average: %.2lf \t setpoint: %.2lf \t decisionPoint: %.2lf \t comparison: %2.1f\n", average, - hpwh->setpoint_C, turnOnLogicSet[i]->getDecisionPoint(), comparison); - } - break; - } - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("returns: %d \t", shouldEngage); - } - } //end loop over set of logic conditions - - //if everything else wants it to come on, but if it would shut off anyways don't turn it on - if (shouldEngage == true && shutsOff() == true) { - shouldEngage = false; - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("but is denied by shutsOff"); - } - } - - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("\n"); - } - return shouldEngage; -} - - -bool HPWH::HeatSource::shutsOff() const { - bool shutOff = false; - - if (hpwh->tankTemps_C[0] >= hpwh->setpoint_C) { - shutOff = true; - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("shutsOff bottom node hot: %.2d C \n returns true", hpwh->tankTemps_C[0]); - } - return shutOff; - } - - for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); - } - - double average = shutOffLogicSet[i]->getTankValue(); - double comparison = shutOffLogicSet[i]->getComparisonValue(); - - if (shutOffLogicSet[i]->compare(average, comparison)) { - shutOff = true; - - //debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("shuts down %s\n", shutOffLogicSet[i]->description.c_str()); - } - } - } - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("returns: %d \n", shutOff); - } - return shutOff; -} - -bool HPWH::HeatSource::maxedOut() const { - bool maxed = false; - - // If the heat source can't produce water at the setpoint and the control logics are saying to shut off - if (hpwh->setpoint_C > maxSetpoint_C){ - if (hpwh->tankTemps_C[0] >= maxSetpoint_C || shutsOff()) { - maxed = true; - } - } - return maxed; -} - -double HPWH::HeatSource::fractToMeetComparisonExternal() const { - double fracTemp; - double frac = 1.; - - for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); - } - - fracTemp = shutOffLogicSet[i]->getFractToMeetComparisonExternal(); - - frac = fracTemp < frac ? fracTemp : frac; - } - - return frac; -} - -void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) { - double input_BTUperHr = 0., cap_BTUperHr = 0., cop = 0., captmp_kJ = 0.; - double leftoverCap_kJ = 0.0; - // set the leftover capacity of the Heat Source to 0, so the first round of - // passing it on works - - switch (configuration) { - case CONFIG_SUBMERGED: - case CONFIG_WRAPPED: - { - static std::vector heatDistribution(hpwh->numNodes); - //clear the heatDistribution vector, since it's static it is still holding the - //distribution from the last go around - heatDistribution.clear(); - //calcHeatDist takes care of the swooping for wrapped configurations - calcHeatDist(heatDistribution); - - if (isACompressor()) { - hpwh->condenserInlet_C = getCondenserTemp(); - } - // calculate capacity btu/hr, input btu/hr, and cop - getCapacity(externalT_C, getCondenserTemp(), input_BTUperHr, cap_BTUperHr, cop); - - //some outputs for debugging - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("capacity_kWh %.2lf \t\t cap_BTUperHr %.2lf \n", BTU_TO_KWH(cap_BTUperHr)*(minutesToRun) / 60.0, cap_BTUperHr); - } - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("heatDistribution: %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf \n", heatDistribution[0], heatDistribution[1], heatDistribution[2], heatDistribution[3], heatDistribution[4], heatDistribution[5], heatDistribution[6], heatDistribution[7], heatDistribution[8], heatDistribution[9], heatDistribution[10], heatDistribution[11]); - } - //the loop over nodes here is intentional - essentially each node that has - //some amount of heatDistribution acts as a separate resistive element - //maybe start from the top and go down? test this with graphs - for (int i = hpwh->numNodes - 1; i >= 0; i--) { - //for(int i = 0; i < hpwh->numNodes; i++){ - captmp_kJ = BTU_TO_KJ(cap_BTUperHr * minutesToRun / 60.0 * heatDistribution[i]); - if (captmp_kJ != 0) { - //add leftoverCap to the next run, and keep passing it on - leftoverCap_kJ = addHeatAboveNode(captmp_kJ + leftoverCap_kJ, i); - } - } - - if (isACompressor()) { // outlet temperature is the condenser temperature after heat has been added - hpwh->condenserOutlet_C = getCondenserTemp(); - } - - //after you've done everything, any leftover capacity is time that didn't run - this->runtime_min = (1.0 - (leftoverCap_kJ / BTU_TO_KJ(cap_BTUperHr * minutesToRun / 60.0))) * minutesToRun; -#if 1 // error check, 1-22-2017 - if (runtime_min < -0.001) - if (hpwh->hpwhVerbosity >= VRB_reluctant) - hpwh->msg("Internal error: Negative runtime = %0.3f min\n", runtime_min); +void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) +{ + double input_BTUperHr = 0., cap_BTUperHr = 0., cop = 0., captmp_kJ = 0.; + double leftoverCap_kJ = 0.0; + // set the leftover capacity of the Heat Source to 0, so the first round of + // passing it on works + + switch (configuration) { + case CONFIG_SUBMERGED: + case CONFIG_WRAPPED: { + static std::vector heatDistribution(hpwh->numNodes); + // clear the heatDistribution vector, since it's static it is still holding the + // distribution from the last go around + heatDistribution.clear(); + // calcHeatDist takes care of the swooping for wrapped configurations + calcHeatDist(heatDistribution); + + if (isACompressor()) { + hpwh->condenserInlet_C = getCondenserTemp(); + } + // calculate capacity btu/hr, input btu/hr, and cop + getCapacity(externalT_C, getCondenserTemp(), input_BTUperHr, cap_BTUperHr, cop); + + // some outputs for debugging + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("capacity_kWh %.2lf \t\t cap_BTUperHr %.2lf \n", + BTU_TO_KWH(cap_BTUperHr) * (minutesToRun) / 60.0, + cap_BTUperHr); + } + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("heatDistribution: %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf " + "%4.3lf %4.3lf %4.3lf %4.3lf \n", + heatDistribution[0], + heatDistribution[1], + heatDistribution[2], + heatDistribution[3], + heatDistribution[4], + heatDistribution[5], + heatDistribution[6], + heatDistribution[7], + heatDistribution[8], + heatDistribution[9], + heatDistribution[10], + heatDistribution[11]); + } + // the loop over nodes here is intentional - essentially each node that has + // some amount of heatDistribution acts as a separate resistive element + // maybe start from the top and go down? test this with graphs + for (int i = hpwh->numNodes - 1; i >= 0; i--) { + // for(int i = 0; i < hpwh->numNodes; i++){ + captmp_kJ = BTU_TO_KJ(cap_BTUperHr * minutesToRun / 60.0 * heatDistribution[i]); + if (captmp_kJ != 0) { + // add leftoverCap to the next run, and keep passing it on + leftoverCap_kJ = addHeatAboveNode(captmp_kJ + leftoverCap_kJ, i); + } + } + + if (isACompressor()) { // outlet temperature is the condenser temperature after heat has + // been added + hpwh->condenserOutlet_C = getCondenserTemp(); + } + + // after you've done everything, any leftover capacity is time that didn't run + this->runtime_min = + (1.0 - (leftoverCap_kJ / BTU_TO_KJ(cap_BTUperHr * minutesToRun / 60.0))) * minutesToRun; +#if 1 // error check, 1-22-2017 + if (runtime_min < -0.001) + if (hpwh->hpwhVerbosity >= VRB_reluctant) + hpwh->msg("Internal error: Negative runtime = %0.3f min\n", runtime_min); #endif - } - break; + } break; + + case CONFIG_EXTERNAL: + // Else the heat source is external. SANCO2 system is only current example + // capacity is calculated internal to this function, and cap/input_BTUperHr, cop are outputs + this->runtime_min = + addHeatExternal(externalT_C, minutesToRun, cap_BTUperHr, input_BTUperHr, cop); + break; + } + + // Write the input & output energy + energyInput_kWh = BTU_TO_KWH(input_BTUperHr * runtime_min / 60.0); + energyOutput_kWh = BTU_TO_KWH(cap_BTUperHr * runtime_min / 60.0); +} + +// the private functions +void HPWH::HeatSource::sortPerformanceMap() +{ + std::sort(perfMap.begin(), + perfMap.end(), + [](const HPWH::HeatSource::perfPoint& a, + const HPWH::HeatSource::perfPoint& b) -> bool { return a.T_F < b.T_F; }); +} + +double HPWH::HeatSource::expitFunc(double x, double offset) +{ + double val; + val = 1 / (1 + exp(x - offset)); + return val; +} + +void HPWH::HeatSource::normalize(std::vector& distribution) +{ + double sum_tmp = 0.0; + size_t N = distribution.size(); + + for (size_t i = 0; i < N; i++) { + sum_tmp += distribution[i]; + } + for (size_t i = 0; i < N; i++) { + if (sum_tmp > 0.0) { + distribution[i] /= sum_tmp; + } + else { + distribution[i] = 0.0; + } + // this gives a very slight speed improvement (milliseconds per simulated year) + if (distribution[i] < TOL_MINVALUE) { + distribution[i] = 0; + } + } +} + +double HPWH::HeatSource::getCondenserTemp() const +{ + double condenserTemp_C = 0.0; + int tempNodesPerCondensityNode = hpwh->numNodes / CONDENSITY_SIZE; + int j = 0; + + for (int i = 0; i < hpwh->numNodes; i++) { + j = i / tempNodesPerCondensityNode; + if (condensity[j] != 0) { + condenserTemp_C += (condensity[j] / tempNodesPerCondensityNode) * hpwh->tankTemps_C[i]; + // the weights don't need to be added to divide out later because they should always sum + // to 1 + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("condenserTemp_C:\t %.2lf \ti:\t %d \tj\t %d \tcondensity[j]:\t %.2lf " + "\ttankTemps_C[i]:\t %.2lf\n", + condenserTemp_C, + i, + j, + condensity[j], + hpwh->tankTemps_C[i]); + } + } + } + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("condenser temp %.2lf \n", condenserTemp_C); + } + return condenserTemp_C; +} + +void HPWH::HeatSource::getCapacity(double externalT_C, + double condenserTemp_C, + double setpointTemp_C, + double& input_BTUperHr, + double& cap_BTUperHr, + double& cop) +{ + double externalT_F, condenserTemp_F; + + // Add an offset to the condenser temperature (or incoming coldwater temperature) to approximate + // a secondary heat exchange in line with the compressor + condenserTemp_F = C_TO_F(condenserTemp_C + secondaryHeatExchanger.coldSideTemperatureOffest_dC); + externalT_F = C_TO_F(externalT_C); + + // Get bounding performance map points for interpolation/extrapolation + bool extrapolate = false; + size_t i_prev = 0; + size_t i_next = 1; + double Tout_F = C_TO_F(setpointTemp_C + secondaryHeatExchanger.hotSideTemperatureOffset_dC); + + if (useBtwxtGrid) { + std::vector target {externalT_F, Tout_F, condenserTemp_F}; + btwxtInterp(input_BTUperHr, cop, target); + } + else { + if (perfMap.size() > 1) { + double COP_T1, COP_T2; // cop at ambient temperatures T1 and T2 + double inputPower_T1_Watts, + inputPower_T2_Watts; // input power at ambient temperatures T1 and T2 + + for (size_t i = 0; i < perfMap.size(); ++i) { + if (externalT_F < perfMap[i].T_F) { + if (i == 0) { + extrapolate = true; + i_prev = 0; + i_next = 1; + } + else { + i_prev = i - 1; + i_next = i; + } + break; + } + else { + if (i == perfMap.size() - 1) { + extrapolate = true; + i_prev = i - 1; + i_next = i; + break; + } + } + } + + // Calculate COP and Input Power at each of the two reference temepratures + COP_T1 = perfMap[i_prev].COP_coeffs[0]; + COP_T1 += perfMap[i_prev].COP_coeffs[1] * condenserTemp_F; + COP_T1 += perfMap[i_prev].COP_coeffs[2] * condenserTemp_F * condenserTemp_F; + + COP_T2 = perfMap[i_next].COP_coeffs[0]; + COP_T2 += perfMap[i_next].COP_coeffs[1] * condenserTemp_F; + COP_T2 += perfMap[i_next].COP_coeffs[2] * condenserTemp_F * condenserTemp_F; + + inputPower_T1_Watts = perfMap[i_prev].inputPower_coeffs[0]; + inputPower_T1_Watts += perfMap[i_prev].inputPower_coeffs[1] * condenserTemp_F; + inputPower_T1_Watts += + perfMap[i_prev].inputPower_coeffs[2] * condenserTemp_F * condenserTemp_F; + + inputPower_T2_Watts = perfMap[i_next].inputPower_coeffs[0]; + inputPower_T2_Watts += perfMap[i_next].inputPower_coeffs[1] * condenserTemp_F; + inputPower_T2_Watts += + perfMap[i_next].inputPower_coeffs[2] * condenserTemp_F * condenserTemp_F; + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("inputPower_T1_constant_W linear_WperF quadratic_WperF2 \t%.2lf " + "%.2lf %.2lf \n", + perfMap[0].inputPower_coeffs[0], + perfMap[0].inputPower_coeffs[1], + perfMap[0].inputPower_coeffs[2]); + hpwh->msg("inputPower_T2_constant_W linear_WperF quadratic_WperF2 \t%.2lf " + "%.2lf %.2lf \n", + perfMap[1].inputPower_coeffs[0], + perfMap[1].inputPower_coeffs[1], + perfMap[1].inputPower_coeffs[2]); + hpwh->msg("inputPower_T1_Watts: %.2lf \tinputPower_T2_Watts: %.2lf \n", + inputPower_T1_Watts, + inputPower_T2_Watts); + + if (extrapolate) { + hpwh->msg("Warning performance extrapolation\n\tExternal Temperature: " + "%.2lf\tNearest temperatures: %.2lf, %.2lf \n\n", + externalT_F, + perfMap[i_prev].T_F, + perfMap[i_next].T_F); + } + } + + // Interpolate to get COP and input power at the current ambient temperature + linearInterp( + cop, externalT_F, perfMap[i_prev].T_F, perfMap[i_next].T_F, COP_T1, COP_T2); + linearInterp(input_BTUperHr, + externalT_F, + perfMap[i_prev].T_F, + perfMap[i_next].T_F, + inputPower_T1_Watts, + inputPower_T2_Watts); + input_BTUperHr = KWH_TO_BTU(input_BTUperHr / 1000.0); // 1000 converts w to kw); + } + else { // perfMap.size() == 1 or we've got an issue. + if (externalT_F > perfMap[0].T_F) { + extrapolate = true; + if (extrapolationMethod == EXTRAP_NEAREST) { + externalT_F = perfMap[0].T_F; + } + } + + regressedMethod( + input_BTUperHr, perfMap[0].inputPower_coeffs, externalT_F, Tout_F, condenserTemp_F); + input_BTUperHr = KWH_TO_BTU(input_BTUperHr); + + regressedMethod(cop, perfMap[0].COP_coeffs, externalT_F, Tout_F, condenserTemp_F); + } + } + + if (doDefrost) { + // adjust COP by the defrost factor + defrostDerate(cop, externalT_F); + } + + cap_BTUperHr = cop * input_BTUperHr; + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("externalT_F: %.2lf, Tout_F: %.2lf, condenserTemp_F: %.2lf\n", + externalT_F, + Tout_F, + condenserTemp_F); + hpwh->msg("input_BTUperHr: %.2lf , cop: %.2lf, cap_BTUperHr: %.2lf \n", + input_BTUperHr, + cop, + cap_BTUperHr); + } + // here is where the scaling for flow restriction happens + // the input power doesn't change, we just scale the cop by a small percentage + // that is based on the flow rate. The equation is a fit to three points, + // measured experimentally - 12 percent reduction at 150 cfm, 10 percent at + // 200, and 0 at 375. Flow is expressed as fraction of full flow. + if (airflowFreedom != 1) { + double airflow = 375 * airflowFreedom; + cop *= 0.00056 * airflow + 0.79; + } + if (hpwh->hpwhVerbosity >= VRB_typical) { + hpwh->msg("cop: %.2lf \tinput_BTUperHr: %.2lf \tcap_BTUperHr: %.2lf \n", + cop, + input_BTUperHr, + cap_BTUperHr); + if (cop < 0.) { + hpwh->msg(" Warning: COP is Negative! \n"); + } + if (cop < 1.) { + hpwh->msg(" Warning: COP is Less than 1! \n"); + } + } +} + +void HPWH::HeatSource::getCapacityMP(double externalT_C, + double condenserTemp_C, + double& input_BTUperHr, + double& cap_BTUperHr, + double& cop) +{ + double externalT_F, condenserTemp_F; + bool resDefrostHeatingOn = false; + // Convert Celsius to Fahrenheit for the curve fits + condenserTemp_F = C_TO_F(condenserTemp_C + secondaryHeatExchanger.coldSideTemperatureOffest_dC); + externalT_F = C_TO_F(externalT_C); + + // Check if we have resistance elements to turn on for defrost and add the constant lift. + if (resDefrost.inputPwr_kW > 0) { + if (externalT_F < resDefrost.onBelowT_F) { + externalT_F += resDefrost.constTempLift_dF; + resDefrostHeatingOn = true; + } + } + + if (useBtwxtGrid) { + std::vector target {externalT_F, condenserTemp_F}; + btwxtInterp(input_BTUperHr, cop, target); + } + else { + // Get bounding performance map points for interpolation/extrapolation + bool extrapolate = false; + if (externalT_F > perfMap[0].T_F) { + extrapolate = true; + if (extrapolationMethod == EXTRAP_NEAREST) { + externalT_F = perfMap[0].T_F; + } + } + + // Const Tair Tin Tair2 Tin2 TairTin + regressedMethodMP( + input_BTUperHr, perfMap[0].inputPower_coeffs, externalT_F, condenserTemp_F); + regressedMethodMP(cop, perfMap[0].COP_coeffs, externalT_F, condenserTemp_F); + } + input_BTUperHr = KWH_TO_BTU(input_BTUperHr); + + if (doDefrost) { + // adjust COP by the defrost factor + defrostDerate(cop, externalT_F); + } + + cap_BTUperHr = cop * input_BTUperHr; + + // For accounting add the resistance defrost to the input energy + if (resDefrostHeatingOn) { + input_BTUperHr += KW_TO_BTUperH(resDefrost.inputPwr_kW); + } + if (hpwh->hpwhVerbosity >= 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", + input_BTUperHr, + cop, + cap_BTUperHr); + } +} + +double HPWH::HeatSource::calcMPOutletTemperature(double heatingCapacity_KW) +{ + return hpwh->tankTemps_C[externalOutletHeight] + + heatingCapacity_KW / (mpFlowRate_LPS * DENSITYWATER_kgperL * CPWATER_kJperkgC); +} + +void HPWH::HeatSource::setupDefrostMap(double derate35 /*=0.8865*/) +{ + doDefrost = true; + defrostMap.reserve(3); + defrostMap.push_back({17., 1.}); + defrostMap.push_back({35., derate35}); + defrostMap.push_back({47., 1.}); +} - case CONFIG_EXTERNAL: - //Else the heat source is external. SANCO2 system is only current example - //capacity is calculated internal to this function, and cap/input_BTUperHr, cop are outputs - this->runtime_min = addHeatExternal(externalT_C, minutesToRun, cap_BTUperHr, input_BTUperHr, cop); - break; - } - - // Write the input & output energy - energyInput_kWh = BTU_TO_KWH(input_BTUperHr * runtime_min / 60.0); - energyOutput_kWh = BTU_TO_KWH(cap_BTUperHr * runtime_min / 60.0); -} - - - -//the private functions -void HPWH::HeatSource::sortPerformanceMap() { - std::sort(perfMap.begin(), perfMap.end(), - [](const HPWH::HeatSource::perfPoint & a, const HPWH::HeatSource::perfPoint & b) -> bool { - return a.T_F < b.T_F; - }); -} - - -double HPWH::HeatSource::expitFunc(double x, double offset) { - double val; - val = 1 / (1 + exp(x - offset)); - return val; -} - - -void HPWH::HeatSource::normalize(std::vector &distribution) { - double sum_tmp = 0.0; - size_t N = distribution.size(); - - for (size_t i = 0; i < N; i++) { - sum_tmp += distribution[i]; - } - for (size_t i = 0; i < N; i++) { - if (sum_tmp > 0.0) { - distribution[i] /= sum_tmp; - } - else { - distribution[i] = 0.0; - } - //this gives a very slight speed improvement (milliseconds per simulated year) - if (distribution[i] < TOL_MINVALUE) { - distribution[i] = 0; - } - } -} - - -double HPWH::HeatSource::getCondenserTemp() const{ - double condenserTemp_C = 0.0; - int tempNodesPerCondensityNode = hpwh->numNodes / CONDENSITY_SIZE; - int j = 0; - - for (int i = 0; i < hpwh->numNodes; i++) { - j = i / tempNodesPerCondensityNode; - if (condensity[j] != 0) { - condenserTemp_C += (condensity[j] / tempNodesPerCondensityNode) * hpwh->tankTemps_C[i]; - //the weights don't need to be added to divide out later because they should always sum to 1 - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("condenserTemp_C:\t %.2lf \ti:\t %d \tj\t %d \tcondensity[j]:\t %.2lf \ttankTemps_C[i]:\t %.2lf\n", condenserTemp_C, i, j, condensity[j], hpwh->tankTemps_C[i]); - } - } - } - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("condenser temp %.2lf \n", condenserTemp_C); - } - return condenserTemp_C; -} - - -void HPWH::HeatSource::getCapacity(double externalT_C, double condenserTemp_C, double setpointTemp_C, double &input_BTUperHr, double &cap_BTUperHr, double &cop) { - double externalT_F, condenserTemp_F; - - // Add an offset to the condenser temperature (or incoming coldwater temperature) to approximate a secondary heat exchange in line with the compressor - condenserTemp_F = C_TO_F(condenserTemp_C + secondaryHeatExchanger.coldSideTemperatureOffest_dC); - externalT_F = C_TO_F(externalT_C); - - // Get bounding performance map points for interpolation/extrapolation - bool extrapolate = false; - size_t i_prev = 0; - size_t i_next = 1; - double Tout_F = C_TO_F(setpointTemp_C + secondaryHeatExchanger.hotSideTemperatureOffset_dC); - - if (useBtwxtGrid) { - std::vector target{ externalT_F, Tout_F, condenserTemp_F }; - btwxtInterp(input_BTUperHr, cop, target); - } - else { - if (perfMap.size() > 1) { - double COP_T1, COP_T2; //cop at ambient temperatures T1 and T2 - double inputPower_T1_Watts, inputPower_T2_Watts; //input power at ambient temperatures T1 and T2 - - for (size_t i = 0; i < perfMap.size(); ++i) { - if (externalT_F < perfMap[i].T_F) { - if (i == 0) { - extrapolate = true; - i_prev = 0; - i_next = 1; - } - else { - i_prev = i - 1; - i_next = i; - } - break; - } - else { - if (i == perfMap.size() - 1) { - extrapolate = true; - i_prev = i - 1; - i_next = i; - break; - } - } - } - - // Calculate COP and Input Power at each of the two reference temepratures - COP_T1 = perfMap[i_prev].COP_coeffs[0]; - COP_T1 += perfMap[i_prev].COP_coeffs[1] * condenserTemp_F; - COP_T1 += perfMap[i_prev].COP_coeffs[2] * condenserTemp_F * condenserTemp_F; - - COP_T2 = perfMap[i_next].COP_coeffs[0]; - COP_T2 += perfMap[i_next].COP_coeffs[1] * condenserTemp_F; - COP_T2 += perfMap[i_next].COP_coeffs[2] * condenserTemp_F * condenserTemp_F; - - inputPower_T1_Watts = perfMap[i_prev].inputPower_coeffs[0]; - inputPower_T1_Watts += perfMap[i_prev].inputPower_coeffs[1] * condenserTemp_F; - inputPower_T1_Watts += perfMap[i_prev].inputPower_coeffs[2] * condenserTemp_F * condenserTemp_F; - - inputPower_T2_Watts = perfMap[i_next].inputPower_coeffs[0]; - inputPower_T2_Watts += perfMap[i_next].inputPower_coeffs[1] * condenserTemp_F; - inputPower_T2_Watts += perfMap[i_next].inputPower_coeffs[2] * condenserTemp_F * condenserTemp_F; - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("inputPower_T1_constant_W linear_WperF quadratic_WperF2 \t%.2lf %.2lf %.2lf \n", perfMap[0].inputPower_coeffs[0], perfMap[0].inputPower_coeffs[1], perfMap[0].inputPower_coeffs[2]); - hpwh->msg("inputPower_T2_constant_W linear_WperF quadratic_WperF2 \t%.2lf %.2lf %.2lf \n", perfMap[1].inputPower_coeffs[0], perfMap[1].inputPower_coeffs[1], perfMap[1].inputPower_coeffs[2]); - hpwh->msg("inputPower_T1_Watts: %.2lf \tinputPower_T2_Watts: %.2lf \n", inputPower_T1_Watts, inputPower_T2_Watts); - - if (extrapolate) { - hpwh->msg("Warning performance extrapolation\n\tExternal Temperature: %.2lf\tNearest temperatures: %.2lf, %.2lf \n\n", externalT_F, perfMap[i_prev].T_F, perfMap[i_next].T_F); - } - } - - // Interpolate to get COP and input power at the current ambient temperature - linearInterp(cop, externalT_F, perfMap[i_prev].T_F, perfMap[i_next].T_F, COP_T1, COP_T2); - linearInterp(input_BTUperHr, externalT_F, perfMap[i_prev].T_F, perfMap[i_next].T_F, inputPower_T1_Watts, inputPower_T2_Watts); - input_BTUperHr = KWH_TO_BTU(input_BTUperHr / 1000.0);//1000 converts w to kw); - - } - else { //perfMap.size() == 1 or we've got an issue. - if (externalT_F > perfMap[0].T_F) { - extrapolate = true; - if (extrapolationMethod == EXTRAP_NEAREST) { - externalT_F = perfMap[0].T_F; - } - } - - regressedMethod(input_BTUperHr, perfMap[0].inputPower_coeffs, externalT_F, Tout_F, condenserTemp_F); - input_BTUperHr = KWH_TO_BTU(input_BTUperHr); - - regressedMethod(cop, perfMap[0].COP_coeffs, externalT_F, Tout_F, condenserTemp_F); - } - } - - if (doDefrost) { - //adjust COP by the defrost factor - defrostDerate(cop, externalT_F); - } - - cap_BTUperHr = cop * input_BTUperHr; - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("externalT_F: %.2lf, Tout_F: %.2lf, condenserTemp_F: %.2lf\n", externalT_F, Tout_F, condenserTemp_F); - hpwh->msg("input_BTUperHr: %.2lf , cop: %.2lf, cap_BTUperHr: %.2lf \n", input_BTUperHr, cop, cap_BTUperHr); - } - //here is where the scaling for flow restriction happens - //the input power doesn't change, we just scale the cop by a small percentage - //that is based on the flow rate. The equation is a fit to three points, - //measured experimentally - 12 percent reduction at 150 cfm, 10 percent at - //200, and 0 at 375. Flow is expressed as fraction of full flow. - if (airflowFreedom != 1) { - double airflow = 375 * airflowFreedom; - cop *= 0.00056*airflow + 0.79; - } - if (hpwh->hpwhVerbosity >= VRB_typical) { - hpwh->msg("cop: %.2lf \tinput_BTUperHr: %.2lf \tcap_BTUperHr: %.2lf \n", cop, input_BTUperHr, cap_BTUperHr); - if (cop < 0.) { - hpwh->msg(" Warning: COP is Negative! \n"); - } - if (cop < 1.) { - hpwh->msg(" Warning: COP is Less than 1! \n"); - } - } -} - -void HPWH::HeatSource::getCapacityMP(double externalT_C, double condenserTemp_C, double &input_BTUperHr, double &cap_BTUperHr, double &cop) { - double externalT_F, condenserTemp_F; - bool resDefrostHeatingOn = false; - // Convert Celsius to Fahrenheit for the curve fits - condenserTemp_F = C_TO_F(condenserTemp_C + secondaryHeatExchanger.coldSideTemperatureOffest_dC); - externalT_F = C_TO_F(externalT_C); - - // Check if we have resistance elements to turn on for defrost and add the constant lift. - if (resDefrost.inputPwr_kW > 0) { - if (externalT_F < resDefrost.onBelowT_F) { - externalT_F += resDefrost.constTempLift_dF; - resDefrostHeatingOn = true; - } - } - - - - if (useBtwxtGrid) { - std::vector target{ externalT_F, condenserTemp_F }; - btwxtInterp(input_BTUperHr, cop, target); - } - else { - // Get bounding performance map points for interpolation/extrapolation - bool extrapolate = false; - if (externalT_F > perfMap[0].T_F) { - extrapolate = true; - if (extrapolationMethod == EXTRAP_NEAREST) { - externalT_F = perfMap[0].T_F; - } - } - - //Const Tair Tin Tair2 Tin2 TairTin - regressedMethodMP(input_BTUperHr, perfMap[0].inputPower_coeffs, externalT_F, condenserTemp_F); - regressedMethodMP(cop, perfMap[0].COP_coeffs, externalT_F, condenserTemp_F); - - } - input_BTUperHr = KWH_TO_BTU(input_BTUperHr); - - if (doDefrost) { - //adjust COP by the defrost factor - defrostDerate(cop, externalT_F); - } - - cap_BTUperHr = cop * input_BTUperHr; - - //For accounting add the resistance defrost to the input energy - if (resDefrostHeatingOn){ - input_BTUperHr += KW_TO_BTUperH(resDefrost.inputPwr_kW); - } - if (hpwh->hpwhVerbosity >= 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", input_BTUperHr, cop, cap_BTUperHr); - } -} - -double HPWH::HeatSource::calcMPOutletTemperature(double heatingCapacity_KW) { - return hpwh->tankTemps_C[externalOutletHeight] + heatingCapacity_KW / (mpFlowRate_LPS * DENSITYWATER_kgperL * CPWATER_kJperkgC); -} - -void HPWH::HeatSource::setupDefrostMap(double derate35/*=0.8865*/) { - doDefrost = true; - defrostMap.reserve(3); - defrostMap.push_back({ 17., 1. }); - defrostMap.push_back({ 35., derate35 }); - defrostMap.push_back({ 47., 1. }); -} - - -void HPWH::HeatSource::defrostDerate(double &to_derate, double airT_F) { - if (airT_F <= defrostMap[0].T_F || airT_F >= defrostMap[defrostMap.size() - 1].T_F) { - return; // Air temperature outside bounds of the defrost map. There is no extrapolation here. - } - double derate_factor = 1.; - size_t i_prev = 0; - for (size_t i = 1; i < defrostMap.size(); ++i) { - if (airT_F <= defrostMap[i].T_F) { - i_prev = i - 1; - break; - } - } - linearInterp(derate_factor, airT_F, - defrostMap[i_prev].T_F, defrostMap[i_prev + 1].T_F, - defrostMap[i_prev].derate_fraction, defrostMap[i_prev + 1].derate_fraction); - to_derate *= derate_factor; -} - -void HPWH::HeatSource::linearInterp(double &ynew, double xnew, double x0, double x1, double y0, double y1) { - ynew = y0 + (xnew - x0) * (y1 - y0) / (x1 - x0); -} - -void HPWH::HeatSource::regressedMethod(double &ynew, std::vector &coefficents, double x1, double x2, double x3) { - ynew = coefficents[0] + - coefficents[1] * x1 + - coefficents[2] * x2 + - coefficents[3] * x3 + - coefficents[4] * x1 * x1 + - coefficents[5] * x2 * x2 + - coefficents[6] * x3 * x3 + - coefficents[7] * x1 * x2 + - coefficents[8] * x1 * x3 + - coefficents[9] * x2 * x3 + - coefficents[10] * x1 * x2 * x3; -} - -void HPWH::HeatSource::regressedMethodMP(double &ynew, std::vector &coefficents, double x1, double x2) { - //Const Tair Tin Tair2 Tin2 TairTin - ynew = coefficents[0] + - coefficents[1] * x1 + - coefficents[2] * x2 + - coefficents[3] * x1 * x1 + - coefficents[4] * x2 * x2 + - coefficents[5] * x1 * x2; -} - - -void HPWH::HeatSource::btwxtInterp(double& input_BTUperHr, double& cop, std::vector &target) { - - std::vector result = perfRGI->get_values_at_target(target); - - input_BTUperHr = result[0]; - cop = result[1]; -} - -void HPWH::HeatSource::calcHeatDist(std::vector &heatDistribution) { - - // Populate the vector of heat distribution - for (int i = 0; i < hpwh->numNodes; i++) { - if (i < lowestNode) { - heatDistribution.push_back(0); - } - else { - int k; - if (configuration == CONFIG_SUBMERGED) { // Inside the tank, no swoopiness required - //intentional integer division - k = i / int(hpwh->numNodes / CONDENSITY_SIZE); - heatDistribution.push_back(condensity[k]); - } - else if (configuration == CONFIG_WRAPPED) { // Wrapped around the tank, send through the logistic function - double temp = 0; //temp for temporary not temperature - double offset = 5.0 / 1.8; - temp = expitFunc((hpwh->tankTemps_C[i] - hpwh->tankTemps_C[lowestNode]) / this->shrinkage, offset); - temp *= (hpwh->setpoint_C - hpwh->tankTemps_C[i]); -#if defined( SETPOINT_FIX) - if (temp < 0.) - temp = 0.; +void HPWH::HeatSource::defrostDerate(double& to_derate, double airT_F) +{ + if (airT_F <= defrostMap[0].T_F || airT_F >= defrostMap[defrostMap.size() - 1].T_F) { + return; // Air temperature outside bounds of the defrost map. There is no extrapolation + // here. + } + double derate_factor = 1.; + size_t i_prev = 0; + for (size_t i = 1; i < defrostMap.size(); ++i) { + if (airT_F <= defrostMap[i].T_F) { + i_prev = i - 1; + break; + } + } + linearInterp(derate_factor, + airT_F, + defrostMap[i_prev].T_F, + defrostMap[i_prev + 1].T_F, + defrostMap[i_prev].derate_fraction, + defrostMap[i_prev + 1].derate_fraction); + to_derate *= derate_factor; +} + +void HPWH::HeatSource::linearInterp( + double& ynew, double xnew, double x0, double x1, double y0, double y1) +{ + ynew = y0 + (xnew - x0) * (y1 - y0) / (x1 - x0); +} + +void HPWH::HeatSource::regressedMethod( + double& ynew, std::vector& coefficents, double x1, double x2, double x3) +{ + ynew = coefficents[0] + coefficents[1] * x1 + coefficents[2] * x2 + coefficents[3] * x3 + + coefficents[4] * x1 * x1 + coefficents[5] * x2 * x2 + coefficents[6] * x3 * x3 + + coefficents[7] * x1 * x2 + coefficents[8] * x1 * x3 + coefficents[9] * x2 * x3 + + coefficents[10] * x1 * x2 * x3; +} + +void HPWH::HeatSource::regressedMethodMP(double& ynew, + std::vector& coefficents, + double x1, + double x2) +{ + // Const Tair Tin Tair2 Tin2 TairTin + ynew = coefficents[0] + coefficents[1] * x1 + coefficents[2] * x2 + coefficents[3] * x1 * x1 + + coefficents[4] * x2 * x2 + coefficents[5] * x1 * x2; +} + +void HPWH::HeatSource::btwxtInterp(double& input_BTUperHr, double& cop, std::vector& target) +{ + + std::vector result = perfRGI->get_values_at_target(target); + + input_BTUperHr = result[0]; + cop = result[1]; +} + +void HPWH::HeatSource::calcHeatDist(std::vector& heatDistribution) +{ + + // Populate the vector of heat distribution + for (int i = 0; i < hpwh->numNodes; i++) { + if (i < lowestNode) { + heatDistribution.push_back(0); + } + else { + int k; + if (configuration == CONFIG_SUBMERGED) { // Inside the tank, no swoopiness required + // intentional integer division + k = i / int(hpwh->numNodes / CONDENSITY_SIZE); + heatDistribution.push_back(condensity[k]); + } + else if (configuration == CONFIG_WRAPPED) { // Wrapped around the tank, send through the + // logistic function + double temp = 0; // temp for temporary not temperature + double offset = 5.0 / 1.8; + temp = expitFunc((hpwh->tankTemps_C[i] - hpwh->tankTemps_C[lowestNode]) / + this->shrinkage, + offset); + temp *= (hpwh->setpoint_C - hpwh->tankTemps_C[i]); +#if defined(SETPOINT_FIX) + if (temp < 0.) + temp = 0.; #endif - heatDistribution.push_back(temp); - } - } - } - normalize(heatDistribution); - -} - - -double HPWH::HeatSource::addHeatAboveNode(double cap_kJ, int node) { - double Q_kJ, deltaT_C, targetTemp_C; - int setPointNodeNum; - - double volumePerNode_L = hpwh->tankVolume_L / hpwh->numNodes; - double maxTargetTemp_C = std::min(maxSetpoint_C, hpwh->setpoint_C); - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("node %2d cap_kwh %.4lf \n", node, KJ_TO_KWH(cap_kJ)); - } - - // find the first node (from the bottom) that does not have the same temperature as the one above it - // if they all have the same temp., use the top node, hpwh->numNodes-1 - setPointNodeNum = node; - for (int i = node; i < hpwh->numNodes - 1; i++) { - if (hpwh->tankTemps_C[i] != hpwh->tankTemps_C[i + 1]) { - break; - } - else { - setPointNodeNum = i + 1; - } - } - - // maximum heat deliverable in this timestep - while (cap_kJ > 0 && setPointNodeNum < hpwh->numNodes) { - // if the whole tank is at the same temp, the target temp is the setpoint - if (setPointNodeNum == (hpwh->numNodes - 1)) { - targetTemp_C = maxTargetTemp_C; - } - //otherwise the target temp is the first non-equal-temp node - else { - targetTemp_C = hpwh->tankTemps_C[setPointNodeNum + 1]; - } - // With DR tomfoolery make sure the target temperature doesn't exceed the setpoint. - if (targetTemp_C > maxTargetTemp_C) { - targetTemp_C = maxTargetTemp_C; - } - - deltaT_C = targetTemp_C - hpwh->tankTemps_C[setPointNodeNum]; - - //heat needed to bring all equal temp. nodes up to the temp of the next node. kJ - Q_kJ = CPWATER_kJperkgC * volumePerNode_L * DENSITYWATER_kgperL * (setPointNodeNum + 1 - node) * deltaT_C; - - //Running the rest of the time won't recover - if (Q_kJ > cap_kJ) { - for (int j = node; j <= setPointNodeNum; j++) { - hpwh->tankTemps_C[j] += cap_kJ / CPWATER_kJperkgC / volumePerNode_L / DENSITYWATER_kgperL / (setPointNodeNum + 1 - node); - } - cap_kJ = 0; - } -#if defined( SETPOINT_FIX) - else if (Q_kJ > 0.) - { // temp will recover by/before end of timestep - for (int j = node; j <= setPointNodeNum; j++) - hpwh->tankTemps_C[j] = targetTemp_C; - cap_kJ -= Q_kJ; - } - setPointNodeNum++; + heatDistribution.push_back(temp); + } + } + } + normalize(heatDistribution); +} + +double HPWH::HeatSource::addHeatAboveNode(double cap_kJ, int node) +{ + double Q_kJ, deltaT_C, targetTemp_C; + int setPointNodeNum; + + double volumePerNode_L = hpwh->tankVolume_L / hpwh->numNodes; + double maxTargetTemp_C = std::min(maxSetpoint_C, hpwh->setpoint_C); + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("node %2d cap_kwh %.4lf \n", node, KJ_TO_KWH(cap_kJ)); + } + + // find the first node (from the bottom) that does not have the same temperature as the one + // above it if they all have the same temp., use the top node, hpwh->numNodes-1 + setPointNodeNum = node; + for (int i = node; i < hpwh->numNodes - 1; i++) { + if (hpwh->tankTemps_C[i] != hpwh->tankTemps_C[i + 1]) { + break; + } + else { + setPointNodeNum = i + 1; + } + } + + // maximum heat deliverable in this timestep + while (cap_kJ > 0 && setPointNodeNum < hpwh->numNodes) { + // if the whole tank is at the same temp, the target temp is the setpoint + if (setPointNodeNum == (hpwh->numNodes - 1)) { + targetTemp_C = maxTargetTemp_C; + } + // otherwise the target temp is the first non-equal-temp node + else { + targetTemp_C = hpwh->tankTemps_C[setPointNodeNum + 1]; + } + // With DR tomfoolery make sure the target temperature doesn't exceed the setpoint. + if (targetTemp_C > maxTargetTemp_C) { + targetTemp_C = maxTargetTemp_C; + } + + deltaT_C = targetTemp_C - hpwh->tankTemps_C[setPointNodeNum]; + + // heat needed to bring all equal temp. nodes up to the temp of the next node. kJ + Q_kJ = CPWATER_kJperkgC * volumePerNode_L * DENSITYWATER_kgperL * + (setPointNodeNum + 1 - node) * deltaT_C; + + // Running the rest of the time won't recover + if (Q_kJ > cap_kJ) { + for (int j = node; j <= setPointNodeNum; j++) { + hpwh->tankTemps_C[j] += cap_kJ / CPWATER_kJperkgC / volumePerNode_L / + DENSITYWATER_kgperL / (setPointNodeNum + 1 - node); + } + cap_kJ = 0; + } +#if defined(SETPOINT_FIX) + else if (Q_kJ > 0.) { // temp will recover by/before end of timestep + for (int j = node; j <= setPointNodeNum; j++) + hpwh->tankTemps_C[j] = targetTemp_C; + cap_kJ -= Q_kJ; + } + setPointNodeNum++; #else - //temp will recover by/before end of timestep - else { - for (int j = node; j <= setPointNodeNum; j++) { - hpwh->tankTemps_C[j] = targetTemp_C; - } - setPointNodeNum++; - cap_kJ -= Q_kJ; - } + // temp will recover by/before end of timestep + else { + for (int j = node; j <= setPointNodeNum; j++) { + hpwh->tankTemps_C[j] = targetTemp_C; + } + setPointNodeNum++; + cap_kJ -= Q_kJ; + } #endif - } - - //return the unused capacity - return cap_kJ; -} -bool HPWH::HeatSource::isACompressor() const { - return this->typeOfHeatSource == TYPE_compressor; -} - -bool HPWH::HeatSource::isAResistance() const { - return this->typeOfHeatSource == TYPE_resistance; -} -bool HPWH::HeatSource::isExternalMultipass() const { - return isMultipass && configuration == HeatSource::CONFIG_EXTERNAL; -} - -double HPWH::HeatSource::addHeatExternal(double externalT_C, double minutesToRun, double &cap_BTUperHr, double &input_BTUperHr, double &cop) { - double heatingCapacity_kJ, heatingCapacityNeeded_kJ, deltaT_C, timeUsed_min, nodeHeat_kJperNode, nodeFrac, fractToShutOff; - double inputTemp_BTUperHr = 0, capTemp_BTUperHr = 0, copTemp = 0; - double volumePerNode_LperNode = hpwh->tankVolume_L / hpwh->numNodes; - double timeRemaining_min = minutesToRun; - double maxTargetTemp_C = std::min(maxSetpoint_C, hpwh->setpoint_C); - double targetTemp_C = 0.; - input_BTUperHr = 0; - cap_BTUperHr = 0; - cop = 0; - - do { - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("bottom tank temp: %.2lf \n", hpwh->tankTemps_C[0]); - } - - if (this->isMultipass) { - // if multipass evenly mix the tank up - hpwh->mixTankNodes(0, hpwh->numNodes, 1.0); // 1.0 will give even mixing, so all temperatures mixed end at average temperature. - - //how much heat is added this timestep - getCapacityMP(externalT_C, hpwh->tankTemps_C[externalOutletHeight], inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); - double heatingCapacity_KW = BTUperH_TO_KW(capTemp_BTUperHr); - - heatingCapacity_kJ = heatingCapacity_KW * (timeRemaining_min * 60.0); - - targetTemp_C = calcMPOutletTemperature(heatingCapacity_KW); - deltaT_C = targetTemp_C - hpwh->tankTemps_C[externalOutletHeight]; - } - else { - //how much heat is available this timestep - getCapacity(externalT_C, hpwh->tankTemps_C[externalOutletHeight], inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); - heatingCapacity_kJ = BTU_TO_KJ(capTemp_BTUperHr * (minutesToRun / 60.0)); - if (hpwh->hpwhVerbosity >= 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) { - hpwh->msg("\theatingCapacity_kJ remaining this node: %.2lf \n", heatingCapacity_kJ); - } - - //calculate what percentage of the bottom node can be heated to setpoint - //with amount of heat available this timestep - targetTemp_C = maxTargetTemp_C; - deltaT_C = targetTemp_C - hpwh->tankTemps_C[externalOutletHeight]; - - } - - nodeHeat_kJperNode = volumePerNode_LperNode * DENSITYWATER_kgperL * CPWATER_kJperkgC * deltaT_C; - - // Caclulate fraction of node to move - if (nodeHeat_kJperNode <= 0.) { // protect against dividing by zero - if bottom node is at (or above) setpoint, add no heat - nodeFrac = 0.; - } - else { - nodeFrac = heatingCapacity_kJ / nodeHeat_kJperNode; - } - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("nodeHeat_kJperNode: %.2lf nodeFrac: %.2lf \n\n", nodeHeat_kJperNode, nodeFrac); - } - - fractToShutOff = fractToMeetComparisonExternal(); - if (fractToShutOff < 1. && fractToShutOff < nodeFrac && !this->isMultipass) { // circle back and check on this for multipass - nodeFrac = fractToShutOff; - heatingCapacityNeeded_kJ = nodeFrac * nodeHeat_kJperNode; - - timeUsed_min = (heatingCapacityNeeded_kJ / heatingCapacity_kJ) * timeRemaining_min; - timeRemaining_min -= timeUsed_min; - } - //if more than one, round down to 1 and subtract the amount of time it would - //take to heat that node from the timeRemaining - else if (nodeFrac > 1.) { - nodeFrac = 1.; - timeUsed_min = (nodeHeat_kJperNode / heatingCapacity_kJ)*timeRemaining_min; - timeRemaining_min -= timeUsed_min; - } - //otherwise just the fraction available - //this should make heatingCapacity == 0 if nodeFrac < 1 - else { - timeUsed_min = timeRemaining_min; - timeRemaining_min = 0.; - } - - // Track the condenser temperature if this is a compressor before moving the nodes ////////////////////////////////////////// - if (isACompressor()) { - hpwh->condenserInlet_C += hpwh->tankTemps_C[externalOutletHeight] * timeUsed_min; - hpwh->condenserOutlet_C += targetTemp_C * timeUsed_min; - } - - // Moving the nodes down //////////////////////////////////////////////////////////////////////////////////////////////////// - // move all nodes down, mixing if less than a full node - for (int n = externalOutletHeight; n < externalInletHeight; n++) { - hpwh->tankTemps_C[n] = hpwh->tankTemps_C[n] * (1 - nodeFrac) + hpwh->tankTemps_C[n + 1] * nodeFrac; - } - //add water to top node, heated to setpoint - hpwh->tankTemps_C[externalInletHeight] = hpwh->tankTemps_C[externalInletHeight] * (1. - nodeFrac) + targetTemp_C * nodeFrac; - - hpwh->mixTankInversions(); - hpwh->updateSoCIfNecessary(); - - // track outputs - weight by the time ran ////////////////////////////////////////////////////////////////////////////////// - // Add in pump power to approximate a secondary heat exchange in line with the compressor - input_BTUperHr += (inputTemp_BTUperHr + W_TO_BTUperH(secondaryHeatExchanger.extraPumpPower_W)) * timeUsed_min; - cap_BTUperHr += capTemp_BTUperHr * timeUsed_min; - cop += copTemp * timeUsed_min; - - hpwh->externalVolumeHeated_L += nodeFrac * volumePerNode_LperNode; - - //if there's still time remaining and you haven't heated to the cutoff - //specified in shutsOff logic, keep heating - } while (timeRemaining_min > 0 && shutsOff() != true); - - // divide outputs by sum of weight - the total time ran - // not timeRemaining_min == minutesToRun is possible - // must prevent divide by 0 (added 4-11-2023) - double timeRun = minutesToRun - timeRemaining_min; - if (timeRun > 0.) - { input_BTUperHr /= timeRun; - cap_BTUperHr /= timeRun; - cop /= timeRun; - hpwh->condenserInlet_C /= timeRun; - hpwh->condenserOutlet_C /= timeRun; - } - - if (hpwh->hpwhVerbosity >= VRB_emetic) { - hpwh->msg("final remaining time: %.2lf \n", timeRemaining_min); - } - // return the time left - return timeRun; -} - - - - -void HPWH::HeatSource::setupAsResistiveElement(int node, double Watts) { - int i; - - isOn = false; - isVIP = false; - for (i = 0; i < CONDENSITY_SIZE; i++) { - condensity[i] = 0; - } - condensity[node] = 1; - - perfMap.reserve(2); - - perfMap.push_back({ - 50, // Temperature (T_F) - {Watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) - }); - - perfMap.push_back({ - 67, // Temperature (T_F) - {Watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) - }); - - configuration = CONFIG_SUBMERGED; //immersed in tank - - typeOfHeatSource = TYPE_resistance; + } + + // return the unused capacity + return cap_kJ; +} +bool HPWH::HeatSource::isACompressor() const { return this->typeOfHeatSource == TYPE_compressor; } + +bool HPWH::HeatSource::isAResistance() const { return this->typeOfHeatSource == TYPE_resistance; } +bool HPWH::HeatSource::isExternalMultipass() const +{ + return isMultipass && configuration == HeatSource::CONFIG_EXTERNAL; +} + +double HPWH::HeatSource::addHeatExternal(double externalT_C, + double minutesToRun, + double& cap_BTUperHr, + double& input_BTUperHr, + double& cop) +{ + double heatingCapacity_kJ, heatingCapacityNeeded_kJ, deltaT_C, timeUsed_min, nodeHeat_kJperNode, + nodeFrac, fractToShutOff; + double inputTemp_BTUperHr = 0, capTemp_BTUperHr = 0, copTemp = 0; + double volumePerNode_LperNode = hpwh->tankVolume_L / hpwh->numNodes; + double timeRemaining_min = minutesToRun; + double maxTargetTemp_C = std::min(maxSetpoint_C, hpwh->setpoint_C); + double targetTemp_C = 0.; + input_BTUperHr = 0; + cap_BTUperHr = 0; + cop = 0; + + do { + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("bottom tank temp: %.2lf \n", hpwh->tankTemps_C[0]); + } + + if (this->isMultipass) { + // if multipass evenly mix the tank up + hpwh->mixTankNodes( + 0, hpwh->numNodes, 1.0); // 1.0 will give even mixing, so all temperatures mixed end + // at average temperature. + + // how much heat is added this timestep + getCapacityMP(externalT_C, + hpwh->tankTemps_C[externalOutletHeight], + inputTemp_BTUperHr, + capTemp_BTUperHr, + copTemp); + double heatingCapacity_KW = BTUperH_TO_KW(capTemp_BTUperHr); + + heatingCapacity_kJ = heatingCapacity_KW * (timeRemaining_min * 60.0); + + targetTemp_C = calcMPOutletTemperature(heatingCapacity_KW); + deltaT_C = targetTemp_C - hpwh->tankTemps_C[externalOutletHeight]; + } + else { + // how much heat is available this timestep + getCapacity(externalT_C, + hpwh->tankTemps_C[externalOutletHeight], + inputTemp_BTUperHr, + capTemp_BTUperHr, + copTemp); + heatingCapacity_kJ = BTU_TO_KJ(capTemp_BTUperHr * (minutesToRun / 60.0)); + if (hpwh->hpwhVerbosity >= 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) { + hpwh->msg("\theatingCapacity_kJ remaining this node: %.2lf \n", heatingCapacity_kJ); + } + + // calculate what percentage of the bottom node can be heated to setpoint + // with amount of heat available this timestep + targetTemp_C = maxTargetTemp_C; + deltaT_C = targetTemp_C - hpwh->tankTemps_C[externalOutletHeight]; + } + + nodeHeat_kJperNode = + volumePerNode_LperNode * DENSITYWATER_kgperL * CPWATER_kJperkgC * deltaT_C; + + // Caclulate fraction of node to move + if (nodeHeat_kJperNode <= 0.) { // protect against dividing by zero - if bottom node is at + // (or above) setpoint, add no heat + nodeFrac = 0.; + } + else { + nodeFrac = heatingCapacity_kJ / nodeHeat_kJperNode; + } + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg( + "nodeHeat_kJperNode: %.2lf nodeFrac: %.2lf \n\n", nodeHeat_kJperNode, nodeFrac); + } + + fractToShutOff = fractToMeetComparisonExternal(); + if (fractToShutOff < 1. && fractToShutOff < nodeFrac && + !this->isMultipass) { // circle back and check on this for multipass + nodeFrac = fractToShutOff; + heatingCapacityNeeded_kJ = nodeFrac * nodeHeat_kJperNode; + + timeUsed_min = (heatingCapacityNeeded_kJ / heatingCapacity_kJ) * timeRemaining_min; + timeRemaining_min -= timeUsed_min; + } + // if more than one, round down to 1 and subtract the amount of time it would + // take to heat that node from the timeRemaining + else if (nodeFrac > 1.) { + nodeFrac = 1.; + timeUsed_min = (nodeHeat_kJperNode / heatingCapacity_kJ) * timeRemaining_min; + timeRemaining_min -= timeUsed_min; + } + // otherwise just the fraction available + // this should make heatingCapacity == 0 if nodeFrac < 1 + else { + timeUsed_min = timeRemaining_min; + timeRemaining_min = 0.; + } + + // Track the condenser temperature if this is a compressor before moving the nodes + // ////////////////////////////////////////// + if (isACompressor()) { + hpwh->condenserInlet_C += hpwh->tankTemps_C[externalOutletHeight] * timeUsed_min; + hpwh->condenserOutlet_C += targetTemp_C * timeUsed_min; + } + + // Moving the nodes down + // //////////////////////////////////////////////////////////////////////////////////////////////////// + // move all nodes down, mixing if less than a full node + for (int n = externalOutletHeight; n < externalInletHeight; n++) { + hpwh->tankTemps_C[n] = + hpwh->tankTemps_C[n] * (1 - nodeFrac) + hpwh->tankTemps_C[n + 1] * nodeFrac; + } + // add water to top node, heated to setpoint + hpwh->tankTemps_C[externalInletHeight] = + hpwh->tankTemps_C[externalInletHeight] * (1. - nodeFrac) + targetTemp_C * nodeFrac; + + hpwh->mixTankInversions(); + hpwh->updateSoCIfNecessary(); + + // track outputs - weight by the time ran + // ////////////////////////////////////////////////////////////////////////////////// Add in + // pump power to approximate a secondary heat exchange in line with the compressor + input_BTUperHr += + (inputTemp_BTUperHr + W_TO_BTUperH(secondaryHeatExchanger.extraPumpPower_W)) * + timeUsed_min; + cap_BTUperHr += capTemp_BTUperHr * timeUsed_min; + cop += copTemp * timeUsed_min; + + hpwh->externalVolumeHeated_L += nodeFrac * volumePerNode_LperNode; + + // if there's still time remaining and you haven't heated to the cutoff + // specified in shutsOff logic, keep heating + } while (timeRemaining_min > 0 && shutsOff() != true); + + // divide outputs by sum of weight - the total time ran + // not timeRemaining_min == minutesToRun is possible + // must prevent divide by 0 (added 4-11-2023) + double timeRun = minutesToRun - timeRemaining_min; + if (timeRun > 0.) { + input_BTUperHr /= timeRun; + cap_BTUperHr /= timeRun; + cop /= timeRun; + hpwh->condenserInlet_C /= timeRun; + hpwh->condenserOutlet_C /= timeRun; + } + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("final remaining time: %.2lf \n", timeRemaining_min); + } + // return the time left + return timeRun; +} + +void HPWH::HeatSource::setupAsResistiveElement(int node, double Watts) +{ + int i; + + isOn = false; + isVIP = false; + for (i = 0; i < CONDENSITY_SIZE; i++) { + condensity[i] = 0; + } + condensity[node] = 1; + + perfMap.reserve(2); + + perfMap.push_back({ + 50, // Temperature (T_F) + {Watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) + }); + + perfMap.push_back({ + 67, // Temperature (T_F) + {Watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) + }); + + configuration = CONFIG_SUBMERGED; // immersed in tank + + typeOfHeatSource = TYPE_resistance; } ////////////////////////////////////////////////////////////////////////////////////////////////////// -void HPWH::HeatSource::setupExtraHeat(std::vector* nodePowerExtra_W) { - - std::vector tempCondensity(CONDENSITY_SIZE); - double watts = 0.0; - for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++) { - //get sum of vector - watts += (*nodePowerExtra_W)[i]; - - //put into vector for normalization - tempCondensity[i] = (*nodePowerExtra_W)[i]; - } - - normalize(tempCondensity); - - if (hpwh->hpwhVerbosity >= VRB_emetic){ - hpwh->msg("extra heat condensity: "); - for (unsigned int i = 0; i < tempCondensity.size(); i++) { - hpwh->msg("C[%d]: %f", i, tempCondensity[i]); - } - hpwh->msg("\n "); - } - - // set condensity based on normalized vector - setCondensity( tempCondensity[0], tempCondensity[1], tempCondensity[2], tempCondensity[3], - tempCondensity[4], tempCondensity[5], tempCondensity[6], tempCondensity[7], - tempCondensity[8], tempCondensity[9], tempCondensity[10], tempCondensity[11] ); - - perfMap.clear(); - perfMap.reserve(2); - - perfMap.push_back({ - 50, // Temperature (T_F) - { watts, 0.0, 0.0 }, // Input Power Coefficients (inputPower_coeffs) - { 1.0, 0.0, 0.0 } // COP Coefficients (COP_coeffs) - }); - - perfMap.push_back({ - 67, // Temperature (T_F) - { watts, 0.0, 0.0 }, // Input Power Coefficients (inputPower_coeffs) - { 1.0, 0.0, 0.0 } // COP Coefficients (COP_coeffs) - }); +void HPWH::HeatSource::setupExtraHeat(std::vector* nodePowerExtra_W) +{ + std::vector tempCondensity(CONDENSITY_SIZE); + double watts = 0.0; + for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++) { + // get sum of vector + watts += (*nodePowerExtra_W)[i]; + + // put into vector for normalization + tempCondensity[i] = (*nodePowerExtra_W)[i]; + } + + normalize(tempCondensity); + + if (hpwh->hpwhVerbosity >= VRB_emetic) { + hpwh->msg("extra heat condensity: "); + for (unsigned int i = 0; i < tempCondensity.size(); i++) { + hpwh->msg("C[%d]: %f", i, tempCondensity[i]); + } + hpwh->msg("\n "); + } + + // set condensity based on normalized vector + setCondensity(tempCondensity[0], + tempCondensity[1], + tempCondensity[2], + tempCondensity[3], + tempCondensity[4], + tempCondensity[5], + tempCondensity[6], + tempCondensity[7], + tempCondensity[8], + tempCondensity[9], + tempCondensity[10], + tempCondensity[11]); + + perfMap.clear(); + perfMap.reserve(2); + + perfMap.push_back({ + 50, // Temperature (T_F) + {watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) + }); + + perfMap.push_back({ + 67, // Temperature (T_F) + {watts, 0.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {1.0, 0.0, 0.0} // COP Coefficients (COP_coeffs) + }); } //////////////////////////////////////////////////////////////////////////// -void HPWH::HeatSource::addTurnOnLogic(std::shared_ptr logic) { - this->turnOnLogicSet.push_back(logic); +void HPWH::HeatSource::addTurnOnLogic(std::shared_ptr logic) +{ + this->turnOnLogicSet.push_back(logic); } -void HPWH::HeatSource::addShutOffLogic(std::shared_ptr logic) { - this->shutOffLogicSet.push_back(logic); +void HPWH::HeatSource::addShutOffLogic(std::shared_ptr logic) +{ + this->shutOffLogicSet.push_back(logic); } - -void HPWH::HeatSource::clearAllTurnOnLogic() { - this->turnOnLogicSet.clear(); -} -void HPWH::HeatSource::clearAllShutOffLogic() { - this->shutOffLogicSet.clear(); -} -void HPWH::HeatSource::clearAllLogic() { - this->clearAllTurnOnLogic(); - this->clearAllShutOffLogic(); -} - -void HPWH::HeatSource::changeResistanceWatts(double watts) { - for (auto &perfP : perfMap) { - perfP.inputPower_coeffs[0] = watts; - } -} - -void HPWH::calcSizeConstants() { - // calculate conduction between the nodes AND heat loss by node with top and bottom having greater surface area. - // model uses explicit finite difference to find conductive heat exchange between the tank nodes with the boundary conditions - // on the top and bottom node being the fraction of UA that corresponds to the top and bottom of the tank. - // The assumption is that the aspect ratio is the same for all tanks and is the same for the outside measurements of the unit - // and the inner water tank. - const double tank_rad = getTankRadius(UNITS_M); - const double tank_height = ASPECTRATIO * tank_rad; - volPerNode_LperNode = tankVolume_L / numNodes; - - node_height = tank_height / numNodes; - - // The fraction of UA that is on the top or the bottom of the tank. So 2 * fracAreaTop + fracAreaSide is the total tank area. - fracAreaTop = tank_rad / (2.0 * (tank_height + tank_rad)); - - // fracAreaSide is the faction of the area of the cylinder that's not the top or bottom. - fracAreaSide = tank_height / (tank_height + tank_rad); -} - -void HPWH::calcDerivedValues() { - // tank node density (number of calculation nodes per regular node) - nodeDensity = numNodes / 12; - - // condentropy/shrinkage and lowestNode are now in calcDerivedHeatingValues() - calcDerivedHeatingValues(); - - calcSizeConstants(); - - mapResRelativePosToSetOfSources(); - - //heat source ability to depress temp - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { - setOfSources[i].depressesTemperature = true; - } - else if (setOfSources[i].isAResistance()) { - setOfSources[i].depressesTemperature = false; - } - } -} - -void HPWH::calcDerivedHeatingValues(){ - static char outputString[MAXOUTSTRING]; //this is used for debugging outputs - - //condentropy/shrinkage - double condentropy = 0; - double alpha = 1, beta = 2; // Mapping from condentropy to shrinkage - for (int i = 0; i < numHeatSources; i++) { - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, "Heat Source %d \n", i); - } - - // Calculate condentropy and ==> shrinkage - condentropy = 0; - for (int j = 0; j < CONDENSITY_SIZE; j++) { - if (setOfSources[i].condensity[j] > 0) { - condentropy -= setOfSources[i].condensity[j] * log(setOfSources[i].condensity[j]); - if (hpwhVerbosity >= VRB_emetic) msg(outputString, "condentropy %.2lf \n", condentropy); - } - } - setOfSources[i].shrinkage = alpha + condentropy * beta; - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, "shrinkage %.2lf \n\n", setOfSources[i].shrinkage); - } - } - - //lowest node - int lowest = 0; - for (int i = 0; i < numHeatSources; i++) { - lowest = 0; - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, "Heat Source %d \n", i); - } - - for (int j = 0; j < numNodes; j++) { - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, "j: %d j/ (numNodes/CONDENSITY_SIZE) %d \n", j, j / (numNodes / CONDENSITY_SIZE)); - } - - if (setOfSources[i].condensity[(j / (numNodes / CONDENSITY_SIZE))] > 0) { - lowest = j; - break; - } - } - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, " lowest : %d \n", lowest); - } - - setOfSources[i].lowestNode = lowest; - } - - // define condenser index and lowest resistance element index - compressorIndex = -1; // Default = No compressor - lowestElementIndex = -1; // Default = No resistance elements - highestElementIndex = -1; // Default = No resistance elements - VIPIndex = -1; // Default = No VIP element - int lowestElementPos = CONDENSITY_SIZE; - int highestElementPos = 0; // -1 to make sure a an element on the bottom can still be identified. - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { - compressorIndex = i; // NOTE: Maybe won't work with multiple compressors (last compressor will be used) - } - else if (setOfSources[i].isAResistance()){ - // Gets VIP element index - if (setOfSources[i].isVIP) { - if (VIPIndex == -1) { - VIPIndex = i; - } - else { - if (hpwhVerbosity >= VRB_minuteOut) { - msg("More than one resistance element is assigned to VIP"); - }; - } - } - for (int j = 0; j < CONDENSITY_SIZE; j++) { - if (setOfSources[i].condensity[j] > 0.0 && j < lowestElementPos) { - lowestElementIndex = i; - lowestElementPos = j; - } - if (setOfSources[i].condensity[j] > 0.0 && j >= highestElementPos) { - highestElementIndex = i; - highestElementPos = j; - } - } - } - } - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, " compressorIndex : %d \n", compressorIndex); - msg(outputString, " lowestElementIndex : %d \n", lowestElementIndex); - msg(outputString, " highestElementIndex : %d \n", highestElementIndex); - } - if (hpwhVerbosity >= VRB_emetic) { - msg(outputString, " VIPIndex : %d \n", VIPIndex); - } - - //heat source ability to depress temp - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { - setOfSources[i].depressesTemperature = true; - } - else if (setOfSources[i].isAResistance()) { - setOfSources[i].depressesTemperature = false; - } - } - -} - -void HPWH::mapResRelativePosToSetOfSources() { - resistanceHeightMap.clear(); - resistanceHeightMap.reserve(getNumResistanceElements()); - - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { - resistanceHeightMap.push_back({ i, - getResistancePosition(i) - }); - } - } - - // Sort by height, low to high - std::sort(resistanceHeightMap.begin(), resistanceHeightMap.end(), - [](const HPWH::resPoint & a, const HPWH::resPoint & b) -> bool { - return a.position < b.position; // (5 < 5) // evaluates to false - }); + +void HPWH::HeatSource::clearAllTurnOnLogic() { this->turnOnLogicSet.clear(); } +void HPWH::HeatSource::clearAllShutOffLogic() { this->shutOffLogicSet.clear(); } +void HPWH::HeatSource::clearAllLogic() +{ + this->clearAllTurnOnLogic(); + this->clearAllShutOffLogic(); } +void HPWH::HeatSource::changeResistanceWatts(double watts) +{ + for (auto& perfP : perfMap) { + perfP.inputPower_coeffs[0] = watts; + } +} -// Used to check a few inputs after the initialization of a tank model from a preset or a file. -int HPWH::checkInputs() { - int returnVal = 0; - //use a returnVal so that all checks are processed and error messages written - - if (numHeatSources <= 0 && hpwhModel != MODELS_StorageTank) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You must have at least one HeatSource.\n"); - } - returnVal = HPWH_ABORT; - } - if ((numNodes % 12) != 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The number of nodes must be a multiple of 12"); - } - returnVal = HPWH_ABORT; - } - - - double condensitySum; - //loop through all heat sources to check each for malconfigurations - for (int i = 0; i < numHeatSources; i++) { - //check the heat source type to make sure it has been set - if (setOfSources[i].typeOfHeatSource == TYPE_none) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Heat source %d does not have a specified type. Initialization failed.\n", i); - } - returnVal = HPWH_ABORT; - } - //check to make sure there is at least one onlogic or parent with onlogic - int parent = setOfSources[i].findParent(); - if (setOfSources[i].turnOnLogicSet.size() == 0 && (parent == -1 || setOfSources[parent].turnOnLogicSet.size() == 0)) { - if (hpwhVerbosity >= 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."); - } - returnVal = HPWH_ABORT; - } - - // Validate on logics - for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { - if (!logic->isValid()) { - returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) { - msg("On logic at index %i is invalid", i); - } - } - } - // Validate off logics - for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { - if (!logic->isValid()) { - returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) { - msg("Off logic at index %i is invalid", i); - } - } - } - - //check is condensity sums to 1 - condensitySum = 0; - for (int j = 0; j < CONDENSITY_SIZE; j++) condensitySum += setOfSources[i].condensity[j]; - if (fabs(condensitySum - 1.0) > 1e-6) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The condensity for heatsource %d does not sum to 1. \n", i); - msg("It sums to %f \n", condensitySum); - } - returnVal = HPWH_ABORT; - } - //check that air flows are all set properly - if (setOfSources[i].airflowFreedom > 1.0 || setOfSources[i].airflowFreedom <= 0.0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The airflowFreedom must be between 0 and 1 for heatsource %d. \n", i); - } - returnVal = HPWH_ABORT; - } - - if (setOfSources[i].isACompressor()) { - if (setOfSources[i].doDefrost) { - if (setOfSources[i].defrostMap.size() < 3) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Defrost logic set to true but no valid defrost map of length 3 or greater set. \n"); - } - returnVal = HPWH_ABORT; - } - if (setOfSources[i].configuration != HeatSource::CONFIG_EXTERNAL) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Defrost is only simulated for external compressors. \n"); - } - returnVal = HPWH_ABORT; - } - } - } - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - - if (setOfSources[i].shutOffLogicSet.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("External heat sources can only have one shut off logic. \n "); - } - returnVal = HPWH_ABORT; - } - if (0 > setOfSources[i].externalOutletHeight || setOfSources[i].externalOutletHeight > numNodes - 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("External heat sources need an external outlet height within the bounds from from 0 to numNodes-1. \n"); - } - returnVal = HPWH_ABORT; - } - if (0 > setOfSources[i].externalInletHeight || setOfSources[i].externalInletHeight > numNodes - 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("External heat sources need an external inlet height within the bounds from from 0 to numNodes-1. \n"); - } - returnVal = HPWH_ABORT; - } - } - else { - if (setOfSources[i].secondaryHeatExchanger.extraPumpPower_W != 0 || setOfSources[i].secondaryHeatExchanger.extraPumpPower_W) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Heatsource %d is not an external heat source but has an external secondary heat exchanger. \n", i); - } - returnVal = HPWH_ABORT; - } - } - - - // Check performance map - // perfGrid and perfGridValues, and the length of vectors in perfGridValues are equal and that ; - if (setOfSources[i].useBtwxtGrid) { - // If useBtwxtGrid is true that the perfMap is empty - if (setOfSources[i].perfMap.size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Using the grid lookups but a regression based perforamnce map is given \n"); - } - returnVal = HPWH_ABORT; - } - - // Check length of vectors in perfGridValue are equal - if (setOfSources[i].perfGridValues[0].size() != setOfSources[i].perfGridValues[1].size() - && setOfSources[i].perfGridValues[0].size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("When using grid lookups for perfmance the vectors in perfGridValues must be the same length. \n"); - } - returnVal = HPWH_ABORT; - } - - // Check perfGrid's vectors lengths multiplied together == the perfGridValues vector lengths - size_t expLength = 1; - for (const auto& v : setOfSources[i].perfGrid) - { - expLength *= v.size(); - } - if (expLength != setOfSources[i].perfGridValues[0].size()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("When using grid lookups for perfmance the vectors in perfGridValues must be the same length. \n"); - } - returnVal = HPWH_ABORT; - } - } - else { - // Check that perfmap only has 1 point if config_external and multipass - if (setOfSources[i].isExternalMultipass() && setOfSources[i].perfMap.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("External multipass heat sources must have a perfMap of only one point with regression equations. \n"); - } - returnVal = HPWH_ABORT; - } - } - } - - // Check that the on logic and off logics are ordered properly - if (hasACompressor()) { - double aquaF = 0., useF = 1.; - getSizingFractions(aquaF, useF); - if (aquaF < (1. - useF)) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The relationship between the on logic and off logic is not supported. The off logic is beneath the on logic."); - } - returnVal = HPWH_ABORT; - } - } - - double maxTemp; string why; - double tempSetpoint = setpoint_C; - if (!isNewSetpointPossible(tempSetpoint, maxTemp, why)) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Cannot set new setpoint. %s", why.c_str()); - } - returnVal = HPWH_ABORT; - } - - //Check if the UA is out of bounds - if (tankUA_kJperHrC < 0.0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("The tankUA_kJperHrC is less than 0 for a HPWH, it must be greater than 0, tankUA_kJperHrC is: %f \n", tankUA_kJperHrC); - } - returnVal = HPWH_ABORT; - } - - //if there's no failures, return 0 - return returnVal; +void HPWH::calcSizeConstants() +{ + // calculate conduction between the nodes AND heat loss by node with top and bottom having + // greater surface area. model uses explicit finite difference to find conductive heat exchange + // between the tank nodes with the boundary conditions on the top and bottom node being the + // fraction of UA that corresponds to the top and bottom of the tank. The assumption is that the + // aspect ratio is the same for all tanks and is the same for the outside measurements of the + // unit and the inner water tank. + const double tank_rad = getTankRadius(UNITS_M); + const double tank_height = ASPECTRATIO * tank_rad; + volPerNode_LperNode = tankVolume_L / numNodes; + + node_height = tank_height / numNodes; + + // The fraction of UA that is on the top or the bottom of the tank. So 2 * fracAreaTop + + // fracAreaSide is the total tank area. + fracAreaTop = tank_rad / (2.0 * (tank_height + tank_rad)); + + // fracAreaSide is the faction of the area of the cylinder that's not the top or bottom. + fracAreaSide = tank_height / (tank_height + tank_rad); } +void HPWH::calcDerivedValues() +{ + // tank node density (number of calculation nodes per regular node) + nodeDensity = numNodes / 12; + + // condentropy/shrinkage and lowestNode are now in calcDerivedHeatingValues() + calcDerivedHeatingValues(); + calcSizeConstants(); + + mapResRelativePosToSetOfSources(); + + // heat source ability to depress temp + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isACompressor()) { + setOfSources[i].depressesTemperature = true; + } + else if (setOfSources[i].isAResistance()) { + setOfSources[i].depressesTemperature = false; + } + } +} + +void HPWH::calcDerivedHeatingValues() +{ + static char outputString[MAXOUTSTRING]; // this is used for debugging outputs + + // condentropy/shrinkage + double condentropy = 0; + double alpha = 1, beta = 2; // Mapping from condentropy to shrinkage + for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, "Heat Source %d \n", i); + } + + // Calculate condentropy and ==> shrinkage + condentropy = 0; + for (int j = 0; j < CONDENSITY_SIZE; j++) { + if (setOfSources[i].condensity[j] > 0) { + condentropy -= setOfSources[i].condensity[j] * log(setOfSources[i].condensity[j]); + if (hpwhVerbosity >= VRB_emetic) + msg(outputString, "condentropy %.2lf \n", condentropy); + } + } + setOfSources[i].shrinkage = alpha + condentropy * beta; + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, "shrinkage %.2lf \n\n", setOfSources[i].shrinkage); + } + } + + // lowest node + int lowest = 0; + for (int i = 0; i < numHeatSources; i++) { + lowest = 0; + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, "Heat Source %d \n", i); + } + + for (int j = 0; j < numNodes; j++) { + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, + "j: %d j/ (numNodes/CONDENSITY_SIZE) %d \n", + j, + j / (numNodes / CONDENSITY_SIZE)); + } + + if (setOfSources[i].condensity[(j / (numNodes / CONDENSITY_SIZE))] > 0) { + lowest = j; + break; + } + } + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, " lowest : %d \n", lowest); + } + + setOfSources[i].lowestNode = lowest; + } + + // define condenser index and lowest resistance element index + compressorIndex = -1; // Default = No compressor + lowestElementIndex = -1; // Default = No resistance elements + highestElementIndex = -1; // Default = No resistance elements + VIPIndex = -1; // Default = No VIP element + int lowestElementPos = CONDENSITY_SIZE; + int highestElementPos = + 0; // -1 to make sure a an element on the bottom can still be identified. + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isACompressor()) { + compressorIndex = i; // NOTE: Maybe won't work with multiple compressors (last + // compressor will be used) + } + else if (setOfSources[i].isAResistance()) { + // Gets VIP element index + if (setOfSources[i].isVIP) { + if (VIPIndex == -1) { + VIPIndex = i; + } + else { + if (hpwhVerbosity >= VRB_minuteOut) { + msg("More than one resistance element is assigned to VIP"); + }; + } + } + for (int j = 0; j < CONDENSITY_SIZE; j++) { + if (setOfSources[i].condensity[j] > 0.0 && j < lowestElementPos) { + lowestElementIndex = i; + lowestElementPos = j; + } + if (setOfSources[i].condensity[j] > 0.0 && j >= highestElementPos) { + highestElementIndex = i; + highestElementPos = j; + } + } + } + } + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, " compressorIndex : %d \n", compressorIndex); + msg(outputString, " lowestElementIndex : %d \n", lowestElementIndex); + msg(outputString, " highestElementIndex : %d \n", highestElementIndex); + } + if (hpwhVerbosity >= VRB_emetic) { + msg(outputString, " VIPIndex : %d \n", VIPIndex); + } + + // heat source ability to depress temp + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isACompressor()) { + setOfSources[i].depressesTemperature = true; + } + else if (setOfSources[i].isAResistance()) { + setOfSources[i].depressesTemperature = false; + } + } +} + +void HPWH::mapResRelativePosToSetOfSources() +{ + resistanceHeightMap.clear(); + resistanceHeightMap.reserve(getNumResistanceElements()); + + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isAResistance()) { + resistanceHeightMap.push_back({i, getResistancePosition(i)}); + } + } + + // Sort by height, low to high + std::sort(resistanceHeightMap.begin(), + resistanceHeightMap.end(), + [](const HPWH::resPoint& a, const HPWH::resPoint& b) -> bool { + return a.position < b.position; // (5 < 5) // evaluates to false + }); +} + +// Used to check a few inputs after the initialization of a tank model from a preset or a file. +int HPWH::checkInputs() +{ + int returnVal = 0; + // use a returnVal so that all checks are processed and error messages written + + if (numHeatSources <= 0 && hpwhModel != MODELS_StorageTank) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You must have at least one HeatSource.\n"); + } + returnVal = HPWH_ABORT; + } + if ((numNodes % 12) != 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The number of nodes must be a multiple of 12"); + } + returnVal = HPWH_ABORT; + } + + double condensitySum; + // loop through all heat sources to check each for malconfigurations + for (int i = 0; i < numHeatSources; i++) { + // check the heat source type to make sure it has been set + if (setOfSources[i].typeOfHeatSource == TYPE_none) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Heat source %d does not have a specified type. Initialization failed.\n", i); + } + returnVal = HPWH_ABORT; + } + // check to make sure there is at least one onlogic or parent with onlogic + int parent = setOfSources[i].findParent(); + if (setOfSources[i].turnOnLogicSet.size() == 0 && + (parent == -1 || setOfSources[parent].turnOnLogicSet.size() == 0)) { + if (hpwhVerbosity >= 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."); + } + returnVal = HPWH_ABORT; + } + + // Validate on logics + for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { + if (!logic->isValid()) { + returnVal = HPWH_ABORT; + if (hpwhVerbosity >= VRB_reluctant) { + msg("On logic at index %i is invalid", i); + } + } + } + // Validate off logics + for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { + if (!logic->isValid()) { + returnVal = HPWH_ABORT; + if (hpwhVerbosity >= VRB_reluctant) { + msg("Off logic at index %i is invalid", i); + } + } + } + + // check is condensity sums to 1 + condensitySum = 0; + for (int j = 0; j < CONDENSITY_SIZE; j++) + condensitySum += setOfSources[i].condensity[j]; + if (fabs(condensitySum - 1.0) > 1e-6) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The condensity for heatsource %d does not sum to 1. \n", i); + msg("It sums to %f \n", condensitySum); + } + returnVal = HPWH_ABORT; + } + // check that air flows are all set properly + if (setOfSources[i].airflowFreedom > 1.0 || setOfSources[i].airflowFreedom <= 0.0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The airflowFreedom must be between 0 and 1 for heatsource %d. \n", i); + } + returnVal = HPWH_ABORT; + } + + if (setOfSources[i].isACompressor()) { + if (setOfSources[i].doDefrost) { + if (setOfSources[i].defrostMap.size() < 3) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Defrost logic set to true but no valid defrost map of length 3 or " + "greater set. \n"); + } + returnVal = HPWH_ABORT; + } + if (setOfSources[i].configuration != HeatSource::CONFIG_EXTERNAL) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Defrost is only simulated for external compressors. \n"); + } + returnVal = HPWH_ABORT; + } + } + } + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + + if (setOfSources[i].shutOffLogicSet.size() != 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("External heat sources can only have one shut off logic. \n "); + } + returnVal = HPWH_ABORT; + } + if (0 > setOfSources[i].externalOutletHeight || + setOfSources[i].externalOutletHeight > numNodes - 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("External heat sources need an external outlet height within the bounds " + "from from 0 to numNodes-1. \n"); + } + returnVal = HPWH_ABORT; + } + if (0 > setOfSources[i].externalInletHeight || + setOfSources[i].externalInletHeight > numNodes - 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("External heat sources need an external inlet height within the bounds " + "from from 0 to numNodes-1. \n"); + } + returnVal = HPWH_ABORT; + } + } + else { + if (setOfSources[i].secondaryHeatExchanger.extraPumpPower_W != 0 || + setOfSources[i].secondaryHeatExchanger.extraPumpPower_W) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Heatsource %d is not an external heat source but has an external " + "secondary heat exchanger. \n", + i); + } + returnVal = HPWH_ABORT; + } + } + + // Check performance map + // perfGrid and perfGridValues, and the length of vectors in perfGridValues are equal and + // that ; + if (setOfSources[i].useBtwxtGrid) { + // If useBtwxtGrid is true that the perfMap is empty + if (setOfSources[i].perfMap.size() != 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Using the grid lookups but a regression based perforamnce map is given " + "\n"); + } + returnVal = HPWH_ABORT; + } + + // Check length of vectors in perfGridValue are equal + if (setOfSources[i].perfGridValues[0].size() != + setOfSources[i].perfGridValues[1].size() && + setOfSources[i].perfGridValues[0].size() != 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("When using grid lookups for perfmance the vectors in perfGridValues must " + "be the same length. \n"); + } + returnVal = HPWH_ABORT; + } + + // Check perfGrid's vectors lengths multiplied together == the perfGridValues vector + // lengths + size_t expLength = 1; + for (const auto& v : setOfSources[i].perfGrid) { + expLength *= v.size(); + } + if (expLength != setOfSources[i].perfGridValues[0].size()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("When using grid lookups for perfmance the vectors in perfGridValues must " + "be the same length. \n"); + } + returnVal = HPWH_ABORT; + } + } + else { + // Check that perfmap only has 1 point if config_external and multipass + if (setOfSources[i].isExternalMultipass() && setOfSources[i].perfMap.size() != 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("External multipass heat sources must have a perfMap of only one point " + "with regression equations. \n"); + } + returnVal = HPWH_ABORT; + } + } + } + + // Check that the on logic and off logics are ordered properly + if (hasACompressor()) { + double aquaF = 0., useF = 1.; + getSizingFractions(aquaF, useF); + if (aquaF < (1. - useF)) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The relationship between the on logic and off logic is not supported. The off " + "logic is beneath the on logic."); + } + returnVal = HPWH_ABORT; + } + } + + double maxTemp; + string why; + double tempSetpoint = setpoint_C; + if (!isNewSetpointPossible(tempSetpoint, maxTemp, why)) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Cannot set new setpoint. %s", why.c_str()); + } + returnVal = HPWH_ABORT; + } + + // Check if the UA is out of bounds + if (tankUA_kJperHrC < 0.0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("The tankUA_kJperHrC is less than 0 for a HPWH, it must be greater than 0, " + "tankUA_kJperHrC is: %f \n", + tankUA_kJperHrC); + } + returnVal = HPWH_ABORT; + } + + // if there's no failures, return 0 + return returnVal; +} #ifndef HPWH_ABRIDGED -int HPWH::HPWHinit_file(string configFile) { - - setAllDefaults(); // reset all defaults if you're re-initilizing - // sets simHasFailed = true; this gets cleared on successful completion of init - // return 0 on success, HPWH_ABORT for failure - - //open file, check and report errors - std::ifstream inputFILE; - inputFILE.open(configFile.c_str()); - if (!inputFILE.is_open()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Input file failed to open. \n"); - } - return HPWH_ABORT; - } - - //some variables that will be handy - int heatsource, sourceNum, nTemps, tempInt; - string tempString, units; - double tempDouble, dblArray[12]; - - //being file processing, line by line - string line_s; - std::stringstream line_ss; - string token; - while (std::getline(inputFILE, line_s)) { - line_ss.clear(); - line_ss.str(line_s); - - //grab the first word, and start comparing - line_ss >> token; - if (token.at(0) == '#' || line_s.empty()) { - //if you hit a comment, skip to next line - continue; - } - else if (token == "numNodes") { - line_ss >> numNodes; - } - else if (token == "volume") { - line_ss >> tempDouble >> units; - if (units == "gal") tempDouble = GAL_TO_L(tempDouble); - else if (units == "L"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s. \n", token.c_str()); - } - return HPWH_ABORT; - } - tankVolume_L = tempDouble; - } - else if (token == "UA") { - line_ss >> tempDouble >> units; - if (units != "kJperHrC") { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s. \n", token.c_str()); - } - return HPWH_ABORT; - } - tankUA_kJperHrC = tempDouble; - } - else if (token == "depressTemp") { - line_ss >> tempString; - if (tempString == "true") { - doTempDepression = true; - } - else if (tempString == "false") { - doTempDepression = false; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper value for %s\n", token.c_str()); - } - return HPWH_ABORT; - } - } - else if (token == "mixOnDraw") { - line_ss >> tempString; - if (tempString == "true") { - tankMixesOnDraw = true; - } - else if (tempString == "false") { - tankMixesOnDraw = false; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper value for %s\n", token.c_str()); - } - return HPWH_ABORT; - } - } - else if (token == "mixBelowFractionOnDraw") { - line_ss >> tempDouble; - if (tempDouble < 0 || tempDouble > 1) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Out of bounds value for %s. Should be between 0 and 1. \n", token.c_str()); - } - return HPWH_ABORT; - } - mixBelowFractionOnDraw = tempDouble; - } - else if (token == "setpoint") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = F_TO_C(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s. \n", token.c_str()); - } - return HPWH_ABORT; - } - setpoint_C = tempDouble; - //tank will be set to setpoint at end of function - } - else if (token == "setpointFixed") { - line_ss >> tempString; - if (tempString == "true") setpointFixed = true; - else if (tempString == "false") setpointFixed = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper value for %s\n", token.c_str()); - } - return HPWH_ABORT; - } - } - else if (token == "verbosity") { - line_ss >> token; - if (token == "silent") { - hpwhVerbosity = VRB_silent; - } - else if (token == "reluctant") { - hpwhVerbosity = VRB_reluctant; - } - else if (token == "typical") { - hpwhVerbosity = VRB_typical; - } - else if (token == "emetic") { - hpwhVerbosity = VRB_emetic; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect verbosity on input. \n"); - } - return HPWH_ABORT; - } - } - - else if (token == "numHeatSources") { - line_ss >> numHeatSources; - setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { - setOfSources[i] = HeatSource(this); - } - } - else if (token == "heatsource") { - if (numHeatSources == 0) { - msg("You must specify the number of heatsources before setting their properties. \n"); - return HPWH_ABORT; - } - line_ss >> heatsource >> token; - if (token == "isVIP") { - line_ss >> tempString; - if (tempString == "true") setOfSources[heatsource].isVIP = true; - else if (tempString == "false") setOfSources[heatsource].isVIP = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper value for %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "isOn") { - line_ss >> tempString; - if (tempString == "true") setOfSources[heatsource].isOn = true; - else if (tempString == "false") setOfSources[heatsource].isOn = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper value for %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "minT") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = F_TO_C(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s. \n", token.c_str()); - } - return HPWH_ABORT; - } - setOfSources[heatsource].minT = tempDouble; - } - else if (token == "maxT") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = F_TO_C(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s. \n", token.c_str()); - } - return HPWH_ABORT; - } - setOfSources[heatsource].maxT = tempDouble; - } - else if (token == "onlogic" || token == "offlogic" || token == "standbylogic" ) { - line_ss >> tempString; - if (tempString == "nodes") { - std::vector nodeNums; - std::vector weights; - std::string nextToken; - line_ss >> nextToken; - while (std::regex_match(nextToken, std::regex("\\d+"))) { - int nodeNum = std::stoi(nextToken); - if (nodeNum > 13 || nodeNum < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Node number for heatsource %d %s must be between 0 and 13. \n", heatsource, token.c_str()); - } - return HPWH_ABORT; - } - nodeNums.push_back(nodeNum); - line_ss >> nextToken; - } - if (nextToken == "weights") { - line_ss >> nextToken; - while (std::regex_match(nextToken, std::regex("-?\\d*\\.\\d+(?:e-?\\d+)?"))) { - weights.push_back(std::stod(nextToken)); - line_ss >> nextToken; - } - } - else { - for (auto n : nodeNums) { - n += 0; // used to get rid of unused variable compiler warning - weights.push_back(1.0); - } - } - if (nodeNums.size() != weights.size()) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Number of weights for heatsource %d %s (%d) does not macht number of nodes for %s (%d). \n", heatsource, token.c_str(), weights.size(), token.c_str(), nodeNums.size()); - } - return HPWH_ABORT; - } - if (nextToken != "absolute" && nextToken != "relative") { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper definition, \"%s\", for heat source %d %s. Should be \"relative\" or \"absoute\".\n", nextToken.c_str(), heatsource, token.c_str()); - } - return HPWH_ABORT; - } - bool absolute = (nextToken == "absolute"); - std::string compareStr; - line_ss >> compareStr >> tempDouble >> units; - std::function compare; - if (compareStr == "<") compare = std::less(); - else if (compareStr == ">") compare = std::greater(); - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper comparison, \"%s\", for heat source %d %s. Should be \"<\" or \">\".\n", compareStr.c_str(), heatsource, token.c_str()); - } - return HPWH_ABORT; - } - if (units == "F") { - if (absolute) { - tempDouble = F_TO_C(tempDouble); - } - else { - tempDouble = dF_TO_dC(tempDouble); - } - } - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - std::vector nodeWeights; - for (size_t i = 0; i < nodeNums.size(); i++) { - nodeWeights.emplace_back(nodeNums[i], weights[i]); - } - std::shared_ptr logic = std::make_shared("custom", nodeWeights, tempDouble, this, absolute, compare); - if (token == "onlogic") { - setOfSources[heatsource].addTurnOnLogic(logic); - } - else if (token == "offlogic") { - setOfSources[heatsource].addShutOffLogic(std::move(logic)); - } - else { // standby logic - setOfSources[heatsource].standbyLogic = std::make_shared("standby logic", nodeWeights, tempDouble, this, absolute, compare); - } - } - else if (token == "onlogic") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = dF_TO_dC(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - if (tempString == "topThird") { - setOfSources[heatsource].addTurnOnLogic(HPWH::topThird(tempDouble)); - } - else if (tempString == "bottomThird") { - setOfSources[heatsource].addTurnOnLogic(HPWH::bottomThird(tempDouble)); - } - else if (tempString == "standby") { - setOfSources[heatsource].addTurnOnLogic(HPWH::standby(tempDouble)); - } - else if (tempString == "bottomSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::bottomSixth(tempDouble)); - } - else if (tempString == "secondSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::secondSixth(tempDouble)); - } - else if (tempString == "thirdSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::thirdSixth(tempDouble)); - } - else if (tempString == "fourthSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::fourthSixth(tempDouble)); - } - else if (tempString == "fifthSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::fifthSixth(tempDouble)); - } - else if (tempString == "topSixth") { - setOfSources[heatsource].addTurnOnLogic(HPWH::topSixth(tempDouble)); - } - else if (tempString == "bottomHalf") { - setOfSources[heatsource].addTurnOnLogic(HPWH::bottomHalf(tempDouble)); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "offlogic") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = F_TO_C(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - if (tempString == "topNodeMaxTemp") { - setOfSources[heatsource].addShutOffLogic(HPWH::topNodeMaxTemp(tempDouble)); - } - else if (tempString == "bottomNodeMaxTemp") { - setOfSources[heatsource].addShutOffLogic(HPWH::bottomNodeMaxTemp(tempDouble)); - } - else if (tempString == "bottomTwelthMaxTemp") { - setOfSources[heatsource].addShutOffLogic(HPWH::bottomTwelthMaxTemp(tempDouble)); - } - else if (tempString == "bottomSixthMaxTemp") { - setOfSources[heatsource].addShutOffLogic(HPWH::bottomSixthMaxTemp(tempDouble)); - } - else if (tempString == "largeDraw") { - setOfSources[heatsource].addShutOffLogic(HPWH::largeDraw(tempDouble)); - } - else if (tempString == "largerDraw") { - setOfSources[heatsource].addShutOffLogic(HPWH::largerDraw(tempDouble)); - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - } - else if (token == "type") { - line_ss >> tempString; - if (tempString == "resistor") { - setOfSources[heatsource].typeOfHeatSource = TYPE_resistance; - } - else if (tempString == "compressor") { - setOfSources[heatsource].typeOfHeatSource = TYPE_compressor; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "coilConfig") { - line_ss >> tempString; - if (tempString == "wrapped") { - setOfSources[heatsource].configuration = HeatSource::CONFIG_WRAPPED; - } - else if (tempString == "submerged") { - setOfSources[heatsource].configuration = HeatSource::CONFIG_SUBMERGED; - } - else if (tempString == "external") { - setOfSources[heatsource].configuration = HeatSource::CONFIG_EXTERNAL; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "heatCycle") { - line_ss >> tempString; - if (tempString == "singlepass") { - setOfSources[heatsource].isMultipass = false; - } - else if (tempString == "multipass") { - setOfSources[heatsource].isMultipass = true; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - - else if (token == "externalInlet") { - line_ss >> tempInt; - if(tempInt < numNodes && tempInt >= 0) { - setOfSources[heatsource].externalInletHeight = tempInt; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - else if (token == "externalOutlet") { - line_ss >> tempInt; - if (tempInt < numNodes && tempInt >= 0) { - setOfSources[heatsource].externalOutletHeight = tempInt; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper %s for heat source %d\n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - } - - else if (token == "condensity") { - line_ss >> dblArray[0] >> dblArray[1] >> dblArray[2] >> dblArray[3] >> dblArray[4] >> dblArray[5] >> dblArray[6] >> dblArray[7] >> dblArray[8] >> dblArray[9] >> dblArray[10] >> dblArray[11]; - setOfSources[heatsource].setCondensity(dblArray[0], dblArray[1], dblArray[2], dblArray[3], dblArray[4], dblArray[5], dblArray[6], dblArray[7], dblArray[8], dblArray[9], dblArray[10], dblArray[11]); - } - else if (token == "nTemps") { - line_ss >> nTemps; - setOfSources[heatsource].perfMap.resize(nTemps); - } - else if (std::regex_match(token, std::regex("T\\d+"))) { - std::smatch match; - std::regex_match(token, match, std::regex("T(\\d+)")); - nTemps = std::stoi(match[1].str()); - int maxTemps = (int)setOfSources[heatsource].perfMap.size(); - - if (maxTemps < nTemps) { - if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is less than %d. \n", token.c_str(), heatsource, maxTemps, nTemps); - } - return HPWH_ABORT; - } - } - line_ss >> tempDouble >> units; - // if (units == "F") tempDouble = F_TO_C(tempDouble); - if (units == "F"); - // else if (units == "C") ; //do nothing, lol - else if (units == "C") tempDouble = C_TO_F(tempDouble); - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - setOfSources[heatsource].perfMap[nTemps - 1].T_F = tempDouble; - } - else if (std::regex_match(token, std::regex("(?:inPow|cop)T\\d+(?:const|lin|quad)"))) { - std::smatch match; - std::regex_match(token, match, std::regex("(inPow|cop)T(\\d+)(const|lin|quad)")); - string var = match[1].str(); - nTemps = std::stoi(match[2].str()); - string coeff = match[3].str(); - int coeff_num; - if (coeff == "const") { - coeff_num = 0; - } - else if (coeff == "lin") { - coeff_num = 1; - } - else if (coeff == "quad") { - coeff_num = 2; - } - - int maxTemps = (int)setOfSources[heatsource].perfMap.size(); - - if (maxTemps < nTemps) { - if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is less than %d. \n", token.c_str(), heatsource, maxTemps, nTemps); - } - return HPWH_ABORT; - } - } - line_ss >> tempDouble; - - if (var == "inPow") { - setOfSources[heatsource].perfMap[nTemps - 1].inputPower_coeffs.push_back(tempDouble); - } - else if (var == "cop") { - setOfSources[heatsource].perfMap[nTemps - 1].COP_coeffs.push_back(tempDouble); - } - } - else if (token == "hysteresis") { - line_ss >> tempDouble >> units; - if (units == "F") tempDouble = dF_TO_dC(tempDouble); - else if (units == "C"); //do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); - } - return HPWH_ABORT; - } - setOfSources[heatsource].hysteresis_dC = tempDouble; - } - else if (token == "backupSource") { - line_ss >> sourceNum; - setOfSources[heatsource].backupHeatSource = &setOfSources[sourceNum]; - } - else if (token == "companionSource") { - line_ss >> sourceNum; - setOfSources[heatsource].companionHeatSource = &setOfSources[sourceNum]; - } - else if (token == "followedBySource") { - line_ss >> sourceNum; - setOfSources[heatsource].followedByHeatSource = &setOfSources[sourceNum]; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Improper specifier (%s) for heat source %d\n", token.c_str(), heatsource); - } - } - - } //end heatsource options - else { - msg("Improper keyword: %s \n", token.c_str()); - return HPWH_ABORT; - } - - } //end while over lines - - - //take care of the non-input processing - hpwhModel = MODELS_CustomFile; - - tankTemps_C = new double[numNodes]; - resetTankToSetpoint(); - - nextTankTemps_C = new double[numNodes]; - - isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { - isHeating = true; - } - setOfSources[i].sortPerformanceMap(); - } - - calcDerivedValues(); - - if (checkInputs() == HPWH_ABORT) { - return HPWH_ABORT; - } - simHasFailed = false; - return 0; +int HPWH::HPWHinit_file(string configFile) +{ + + setAllDefaults(); // reset all defaults if you're re-initilizing + // sets simHasFailed = true; this gets cleared on successful completion of init + // return 0 on success, HPWH_ABORT for failure + + // open file, check and report errors + std::ifstream inputFILE; + inputFILE.open(configFile.c_str()); + if (!inputFILE.is_open()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Input file failed to open. \n"); + } + return HPWH_ABORT; + } + + // some variables that will be handy + int heatsource, sourceNum, nTemps, tempInt; + string tempString, units; + double tempDouble, dblArray[12]; + + // being file processing, line by line + string line_s; + std::stringstream line_ss; + string token; + while (std::getline(inputFILE, line_s)) { + line_ss.clear(); + line_ss.str(line_s); + + // grab the first word, and start comparing + line_ss >> token; + if (token.at(0) == '#' || line_s.empty()) { + // if you hit a comment, skip to next line + continue; + } + else if (token == "numNodes") { + line_ss >> numNodes; + } + else if (token == "volume") { + line_ss >> tempDouble >> units; + if (units == "gal") + tempDouble = GAL_TO_L(tempDouble); + else if (units == "L") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s. \n", token.c_str()); + } + return HPWH_ABORT; + } + tankVolume_L = tempDouble; + } + else if (token == "UA") { + line_ss >> tempDouble >> units; + if (units != "kJperHrC") { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s. \n", token.c_str()); + } + return HPWH_ABORT; + } + tankUA_kJperHrC = tempDouble; + } + else if (token == "depressTemp") { + line_ss >> tempString; + if (tempString == "true") { + doTempDepression = true; + } + else if (tempString == "false") { + doTempDepression = false; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper value for %s\n", token.c_str()); + } + return HPWH_ABORT; + } + } + else if (token == "mixOnDraw") { + line_ss >> tempString; + if (tempString == "true") { + tankMixesOnDraw = true; + } + else if (tempString == "false") { + tankMixesOnDraw = false; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper value for %s\n", token.c_str()); + } + return HPWH_ABORT; + } + } + else if (token == "mixBelowFractionOnDraw") { + line_ss >> tempDouble; + if (tempDouble < 0 || tempDouble > 1) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Out of bounds value for %s. Should be between 0 and 1. \n", token.c_str()); + } + return HPWH_ABORT; + } + mixBelowFractionOnDraw = tempDouble; + } + else if (token == "setpoint") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = F_TO_C(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s. \n", token.c_str()); + } + return HPWH_ABORT; + } + setpoint_C = tempDouble; + // tank will be set to setpoint at end of function + } + else if (token == "setpointFixed") { + line_ss >> tempString; + if (tempString == "true") + setpointFixed = true; + else if (tempString == "false") + setpointFixed = false; + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper value for %s\n", token.c_str()); + } + return HPWH_ABORT; + } + } + else if (token == "verbosity") { + line_ss >> token; + if (token == "silent") { + hpwhVerbosity = VRB_silent; + } + else if (token == "reluctant") { + hpwhVerbosity = VRB_reluctant; + } + else if (token == "typical") { + hpwhVerbosity = VRB_typical; + } + else if (token == "emetic") { + hpwhVerbosity = VRB_emetic; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect verbosity on input. \n"); + } + return HPWH_ABORT; + } + } + + else if (token == "numHeatSources") { + line_ss >> numHeatSources; + setOfSources = new HeatSource[numHeatSources]; + for (int i = 0; i < numHeatSources; i++) { + setOfSources[i] = HeatSource(this); + } + } + else if (token == "heatsource") { + if (numHeatSources == 0) { + msg("You must specify the number of heatsources before setting their properties. " + "\n"); + return HPWH_ABORT; + } + line_ss >> heatsource >> token; + if (token == "isVIP") { + line_ss >> tempString; + if (tempString == "true") + setOfSources[heatsource].isVIP = true; + else if (tempString == "false") + setOfSources[heatsource].isVIP = false; + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper value for %s for heat source %d\n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "isOn") { + line_ss >> tempString; + if (tempString == "true") + setOfSources[heatsource].isOn = true; + else if (tempString == "false") + setOfSources[heatsource].isOn = false; + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper value for %s for heat source %d\n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "minT") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = F_TO_C(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s. \n", token.c_str()); + } + return HPWH_ABORT; + } + setOfSources[heatsource].minT = tempDouble; + } + else if (token == "maxT") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = F_TO_C(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s. \n", token.c_str()); + } + return HPWH_ABORT; + } + setOfSources[heatsource].maxT = tempDouble; + } + else if (token == "onlogic" || token == "offlogic" || token == "standbylogic") { + line_ss >> tempString; + if (tempString == "nodes") { + std::vector nodeNums; + std::vector weights; + std::string nextToken; + line_ss >> nextToken; + while (std::regex_match(nextToken, std::regex("\\d+"))) { + int nodeNum = std::stoi(nextToken); + if (nodeNum > 13 || nodeNum < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Node number for heatsource %d %s must be between 0 and 13. " + "\n", + heatsource, + token.c_str()); + } + return HPWH_ABORT; + } + nodeNums.push_back(nodeNum); + line_ss >> nextToken; + } + if (nextToken == "weights") { + line_ss >> nextToken; + while ( + std::regex_match(nextToken, std::regex("-?\\d*\\.\\d+(?:e-?\\d+)?"))) { + weights.push_back(std::stod(nextToken)); + line_ss >> nextToken; + } + } + else { + for (auto n : nodeNums) { + n += 0; // used to get rid of unused variable compiler warning + weights.push_back(1.0); + } + } + if (nodeNums.size() != weights.size()) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Number of weights for heatsource %d %s (%d) does not macht number " + "of nodes for %s (%d). \n", + heatsource, + token.c_str(), + weights.size(), + token.c_str(), + nodeNums.size()); + } + return HPWH_ABORT; + } + if (nextToken != "absolute" && nextToken != "relative") { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper definition, \"%s\", for heat source %d %s. Should be " + "\"relative\" or \"absoute\".\n", + nextToken.c_str(), + heatsource, + token.c_str()); + } + return HPWH_ABORT; + } + bool absolute = (nextToken == "absolute"); + std::string compareStr; + line_ss >> compareStr >> tempDouble >> units; + std::function compare; + if (compareStr == "<") + compare = std::less(); + else if (compareStr == ">") + compare = std::greater(); + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper comparison, \"%s\", for heat source %d %s. Should be " + "\"<\" or \">\".\n", + compareStr.c_str(), + heatsource, + token.c_str()); + } + return HPWH_ABORT; + } + if (units == "F") { + if (absolute) { + tempDouble = F_TO_C(tempDouble); + } + else { + tempDouble = dF_TO_dC(tempDouble); + } + } + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s from heatsource %d. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + std::vector nodeWeights; + for (size_t i = 0; i < nodeNums.size(); i++) { + nodeWeights.emplace_back(nodeNums[i], weights[i]); + } + std::shared_ptr logic = + std::make_shared( + "custom", nodeWeights, tempDouble, this, absolute, compare); + if (token == "onlogic") { + setOfSources[heatsource].addTurnOnLogic(logic); + } + else if (token == "offlogic") { + setOfSources[heatsource].addShutOffLogic(std::move(logic)); + } + else { // standby logic + setOfSources[heatsource].standbyLogic = + std::make_shared( + "standby logic", nodeWeights, tempDouble, this, absolute, compare); + } + } + else if (token == "onlogic") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = dF_TO_dC(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s from heatsource %d. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + if (tempString == "topThird") { + setOfSources[heatsource].addTurnOnLogic(HPWH::topThird(tempDouble)); + } + else if (tempString == "bottomThird") { + setOfSources[heatsource].addTurnOnLogic(HPWH::bottomThird(tempDouble)); + } + else if (tempString == "standby") { + setOfSources[heatsource].addTurnOnLogic(HPWH::standby(tempDouble)); + } + else if (tempString == "bottomSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::bottomSixth(tempDouble)); + } + else if (tempString == "secondSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::secondSixth(tempDouble)); + } + else if (tempString == "thirdSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::thirdSixth(tempDouble)); + } + else if (tempString == "fourthSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::fourthSixth(tempDouble)); + } + else if (tempString == "fifthSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::fifthSixth(tempDouble)); + } + else if (tempString == "topSixth") { + setOfSources[heatsource].addTurnOnLogic(HPWH::topSixth(tempDouble)); + } + else if (tempString == "bottomHalf") { + setOfSources[heatsource].addTurnOnLogic(HPWH::bottomHalf(tempDouble)); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "offlogic") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = F_TO_C(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s from heatsource %d. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + if (tempString == "topNodeMaxTemp") { + setOfSources[heatsource].addShutOffLogic(HPWH::topNodeMaxTemp(tempDouble)); + } + else if (tempString == "bottomNodeMaxTemp") { + setOfSources[heatsource].addShutOffLogic( + HPWH::bottomNodeMaxTemp(tempDouble)); + } + else if (tempString == "bottomTwelthMaxTemp") { + setOfSources[heatsource].addShutOffLogic( + HPWH::bottomTwelthMaxTemp(tempDouble)); + } + else if (tempString == "bottomSixthMaxTemp") { + setOfSources[heatsource].addShutOffLogic( + HPWH::bottomSixthMaxTemp(tempDouble)); + } + else if (tempString == "largeDraw") { + setOfSources[heatsource].addShutOffLogic(HPWH::largeDraw(tempDouble)); + } + else if (tempString == "largerDraw") { + setOfSources[heatsource].addShutOffLogic(HPWH::largerDraw(tempDouble)); + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + } + else if (token == "type") { + line_ss >> tempString; + if (tempString == "resistor") { + setOfSources[heatsource].typeOfHeatSource = TYPE_resistance; + } + else if (tempString == "compressor") { + setOfSources[heatsource].typeOfHeatSource = TYPE_compressor; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "coilConfig") { + line_ss >> tempString; + if (tempString == "wrapped") { + setOfSources[heatsource].configuration = HeatSource::CONFIG_WRAPPED; + } + else if (tempString == "submerged") { + setOfSources[heatsource].configuration = HeatSource::CONFIG_SUBMERGED; + } + else if (tempString == "external") { + setOfSources[heatsource].configuration = HeatSource::CONFIG_EXTERNAL; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "heatCycle") { + line_ss >> tempString; + if (tempString == "singlepass") { + setOfSources[heatsource].isMultipass = false; + } + else if (tempString == "multipass") { + setOfSources[heatsource].isMultipass = true; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + + else if (token == "externalInlet") { + line_ss >> tempInt; + if (tempInt < numNodes && tempInt >= 0) { + setOfSources[heatsource].externalInletHeight = tempInt; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + else if (token == "externalOutlet") { + line_ss >> tempInt; + if (tempInt < numNodes && tempInt >= 0) { + setOfSources[heatsource].externalOutletHeight = tempInt; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper %s for heat source %d\n", token.c_str(), heatsource); + } + return HPWH_ABORT; + } + } + + else if (token == "condensity") { + line_ss >> dblArray[0] >> dblArray[1] >> dblArray[2] >> dblArray[3] >> + dblArray[4] >> dblArray[5] >> dblArray[6] >> dblArray[7] >> dblArray[8] >> + dblArray[9] >> dblArray[10] >> dblArray[11]; + setOfSources[heatsource].setCondensity(dblArray[0], + dblArray[1], + dblArray[2], + dblArray[3], + dblArray[4], + dblArray[5], + dblArray[6], + dblArray[7], + dblArray[8], + dblArray[9], + dblArray[10], + dblArray[11]); + } + else if (token == "nTemps") { + line_ss >> nTemps; + setOfSources[heatsource].perfMap.resize(nTemps); + } + else if (std::regex_match(token, std::regex("T\\d+"))) { + std::smatch match; + std::regex_match(token, match, std::regex("T(\\d+)")); + nTemps = std::stoi(match[1].str()); + int maxTemps = (int)setOfSources[heatsource].perfMap.size(); + + if (maxTemps < nTemps) { + if (maxTemps == 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("%s specified for heatsource %d before definition of nTemps. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " + "less than %d. \n", + token.c_str(), + heatsource, + maxTemps, + nTemps); + } + return HPWH_ABORT; + } + } + line_ss >> tempDouble >> units; + // if (units == "F") tempDouble = F_TO_C(tempDouble); + if (units == "F") + ; + // else if (units == "C") ; //do nothing, lol + else if (units == "C") + tempDouble = C_TO_F(tempDouble); + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s from heatsource %d. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + setOfSources[heatsource].perfMap[nTemps - 1].T_F = tempDouble; + } + else if (std::regex_match(token, std::regex("(?:inPow|cop)T\\d+(?:const|lin|quad)"))) { + std::smatch match; + std::regex_match(token, match, std::regex("(inPow|cop)T(\\d+)(const|lin|quad)")); + string var = match[1].str(); + nTemps = std::stoi(match[2].str()); + string coeff = match[3].str(); + int coeff_num; + if (coeff == "const") { + coeff_num = 0; + } + else if (coeff == "lin") { + coeff_num = 1; + } + else if (coeff == "quad") { + coeff_num = 2; + } + + int maxTemps = (int)setOfSources[heatsource].perfMap.size(); + + if (maxTemps < nTemps) { + if (maxTemps == 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("%s specified for heatsource %d before definition of nTemps. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " + "less than %d. \n", + token.c_str(), + heatsource, + maxTemps, + nTemps); + } + return HPWH_ABORT; + } + } + line_ss >> tempDouble; + + if (var == "inPow") { + setOfSources[heatsource].perfMap[nTemps - 1].inputPower_coeffs.push_back( + tempDouble); + } + else if (var == "cop") { + setOfSources[heatsource].perfMap[nTemps - 1].COP_coeffs.push_back(tempDouble); + } + } + else if (token == "hysteresis") { + line_ss >> tempDouble >> units; + if (units == "F") + tempDouble = dF_TO_dC(tempDouble); + else if (units == "C") + ; // do nothing, lol + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect units specification for %s from heatsource %d. \n", + token.c_str(), + heatsource); + } + return HPWH_ABORT; + } + setOfSources[heatsource].hysteresis_dC = tempDouble; + } + else if (token == "backupSource") { + line_ss >> sourceNum; + setOfSources[heatsource].backupHeatSource = &setOfSources[sourceNum]; + } + else if (token == "companionSource") { + line_ss >> sourceNum; + setOfSources[heatsource].companionHeatSource = &setOfSources[sourceNum]; + } + else if (token == "followedBySource") { + line_ss >> sourceNum; + setOfSources[heatsource].followedByHeatSource = &setOfSources[sourceNum]; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Improper specifier (%s) for heat source %d\n", token.c_str(), heatsource); + } + } + + } // end heatsource options + else { + msg("Improper keyword: %s \n", token.c_str()); + return HPWH_ABORT; + } + + } // end while over lines + + // take care of the non-input processing + hpwhModel = MODELS_CustomFile; + + tankTemps_C = new double[numNodes]; + resetTankToSetpoint(); + + nextTankTemps_C = new double[numNodes]; + + isHeating = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isOn) { + isHeating = true; + } + setOfSources[i].sortPerformanceMap(); + } + + calcDerivedValues(); + + if (checkInputs() == HPWH_ABORT) { + return HPWH_ABORT; + } + simHasFailed = false; + return 0; } #endif diff --git a/src/HPWH.in.hh b/src/HPWH.in.hh index 7cdef58d..d5d2d7b6 100644 --- a/src/HPWH.in.hh +++ b/src/HPWH.in.hh @@ -10,1292 +10,1434 @@ #include #include -#include //for exit +#include //for exit #include -namespace Btwxt { class RegularGridInterpolator; }; +namespace Btwxt { +class RegularGridInterpolator; +}; -//#define HPWH_ABRIDGED +// #define HPWH_ABRIDGED /**< If HPWH_ABRIDGED is defined, then some function definitions will be * excluded from compiling. This is done in order to reduce the size of the * final compiled code. */ -#define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR@ -#define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR@ -#define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH@ +#define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR @ +#define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR @ +#define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH @ #define HPWHVRSN_META "@HPWHsim_VRSN_META@" class HPWH { - public: - static const int version_major = HPWHVRSN_MAJOR; - static const int version_minor = HPWHVRSN_MINOR; - static const int version_patch = HPWHVRSN_PATCH; - static const std::string version_maint; // Initialized in source file (HPWH.cc) - - - static const float DENSITYWATER_kgperL; - static const float KWATER_WpermC; - static const float CPWATER_kJperkgC; - static const int CONDENSITY_SIZE = 12; /**< this must be an integer, and only the value 12 change at your own risk */ - static const int MAXOUTSTRING = 200; /**< this is the maximum length for a debuging output string */ - static const float TOL_MINVALUE; /**< any amount of heat distribution less than this is reduced to 0 this saves on computations */ - static const float UNINITIALIZED_LOCATIONTEMP; /**< this is used to tell the - simulation when the location temperature has not been initialized */ - static const float ASPECTRATIO; /**< A constant to define the aspect ratio between the tank height and - radius (H/R). Used to find the radius and tank height from the volume and then - find the surface area. It is derived from the median value of 88 - insulated storage tanks currently available on the market from - Sanden, AOSmith, HTP, Rheem, and Niles, */ - static const double MAXOUTLET_R134A; /**< The max oulet temperature for compressors with the refrigerant R134a*/ - static const double MAXOUTLET_R410A; /**< The max oulet temperature for compressors with the refrigerant R410a*/ - static const double MAXOUTLET_R744; /**< The max oulet temperature for compressors with the refrigerant R744*/ - static const double MINSINGLEPASSLIFT; /**< The minimum temperature lift for single pass compressors */ - - HPWH(); /**< default constructor */ - HPWH(const HPWH &hpwh); /**< copy constructor */ - HPWH & operator=(const HPWH &hpwh); /**< assignment operator */ - ~HPWH(); /**< destructor just a couple dynamic arrays to destroy - could be replaced by vectors eventually? */ - - - ///specifies the various modes for the Demand Response (DR) abilities - ///values may vary - names should be used - enum DRMODES { - DR_ALLOW = 0b0000, /** SANCO2 5-23 - MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ - MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ - MODELS_SANCO2_GS3_45HPA_US_SP = 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ - MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ - - // Sanden synomyms for backward compatability - // allow unmodified code using HPWHsim to build - MODELS_Sanden40 = MODELS_SANCO2_43, - MODELS_Sanden80 = MODELS_SANCO2_83, - MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, - MODELS_Sanden120 = MODELS_SANCO2_119, - - // The new-ish Rheem - MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ - MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ - - // The new new Rheem - MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ - - // Rheem 120V dedicated-circuit product, no resistance elements - MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ - MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ - - // Rheem 120V shared-circuit products, no resistance elements. - MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ - - // The new-ish Stiebel - MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ - - // Generic water heaters, corresponding to the tiers 1, 2, and 3 - MODELS_Generic1 = 170, /**< Generic Tier 1 */ - MODELS_Generic2 = 171, /**< Generic Tier 2 */ - MODELS_Generic3 = 172, /**< Generic Tier 3 */ - MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ - MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ - - MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ - MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ - - MODELS_StorageTank = 180, /**< Generic Tank without heaters */ - MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has scalable input capacity and COP */ - MODELS_Scalable_MP = 191, /** < Lower performance MP model that has scalable input capacity and COP */ - - // Non-preset models - MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ - MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ - MODELS_CustomResTankGeneric = 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ - - // Larger Colmac models in single pass configuration - MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ - - // Larger Colmac models in multi pass configuration - MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ - - // Larger Nyle models in single pass configuration - MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ - MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ - // Larger Nyle models with the cold weather package! - MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ - - // Mitsubishi Electric Trane - MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ - - // Larger Nyle models in multi pass configuration - //MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ - MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - // Large Rheem multi pass models - MODELS_RHEEM_HPHD60HNU_201_MP = 350, - MODELS_RHEEM_HPHD60VNU_201_MP = 351, - MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data - MODELS_RHEEM_HPHD135VNU_483_MP = 353 // really bad fit to data due to inconsistency in data + public: + static const int version_major = HPWHVRSN_MAJOR; + static const int version_minor = HPWHVRSN_MINOR; + static const int version_patch = HPWHVRSN_PATCH; + static const std::string version_maint; // Initialized in source file (HPWH.cc) + + static const float DENSITYWATER_kgperL; + static const float KWATER_WpermC; + static const float CPWATER_kJperkgC; + static const int CONDENSITY_SIZE = + 12; /**< this must be an integer, and only the value 12 change at your own risk */ + static const int MAXOUTSTRING = + 200; /**< this is the maximum length for a debuging output string */ + static const float TOL_MINVALUE; /**< any amount of heat distribution less than this is reduced + to 0 this saves on computations */ + static const float UNINITIALIZED_LOCATIONTEMP; /**< this is used to tell the + simulation when the location temperature has not been initialized */ + static const float + ASPECTRATIO; /**< A constant to define the aspect ratio between the tank height and + radius (H/R). Used to find the radius and tank height from the volume and then + find the surface area. It is derived from the median value of 88 + insulated storage tanks currently available on the market from + Sanden, AOSmith, HTP, Rheem, and Niles, */ + static const double + MAXOUTLET_R134A; /**< The max oulet temperature for compressors with the refrigerant R134a*/ + static const double + MAXOUTLET_R410A; /**< The max oulet temperature for compressors with the refrigerant R410a*/ + static const double + MAXOUTLET_R744; /**< The max oulet temperature for compressors with the refrigerant R744*/ + static const double + MINSINGLEPASSLIFT; /**< The minimum temperature lift for single pass compressors */ + + HPWH(); /**< default constructor */ + HPWH(const HPWH& hpwh); /**< copy constructor */ + HPWH& operator=(const HPWH& hpwh); /**< assignment operator */ + ~HPWH(); /**< destructor just a couple dynamic arrays to destroy - could be replaced by vectors + eventually? */ + + /// specifies the various modes for the Demand Response (DR) abilities + /// values may vary - names should be used + enum DRMODES { + DR_ALLOW = 0b0000, /**= 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 */ + /// specifies the allowable preset HPWH models + /// values may vary - names should be used + enum MODELS { + // these models are used for testing purposes + MODELS_restankNoUA = 1, /**< a simple resistance tank, but with no tank losses */ + MODELS_restankHugeUA = 2, /**< a simple resistance tank, but with very large tank losses */ + MODELS_restankRealistic = 3, /**< a more-or-less realistic resistance tank */ + MODELS_basicIntegrated = 4, /**< a standard integrated HPWH */ + MODELS_externalTest = 5, /**< a single compressor tank, using "external" topology */ + + // these models are based on real tanks and measured lab data + // AO Smith models + MODELS_AOSmithPHPT60 = 102, /**< this is the Ecotope model for the 60 gallon Voltex HPWH */ + MODELS_AOSmithPHPT80 = 103, /**< Voltex 80 gallon tank */ + MODELS_AOSmithHPTU50 = 104, /**< 50 gallon AOSmith HPTU */ + MODELS_AOSmithHPTU66 = 105, /**< 66 gallon AOSmith HPTU */ + MODELS_AOSmithHPTU80 = 106, /**< 80 gallon AOSmith HPTU */ + MODELS_AOSmithHPTU80_DR = 107, /**< 80 gallon AOSmith HPTU */ + MODELS_AOSmithCAHP120 = 108, /**< 12 gallon AOSmith CAHP commercial grade */ + + MODELS_AOSmithHPTS50 = 1101, /**< 50 gallon, AOSmith HPTS */ + MODELS_AOSmithHPTS66 = 1102, /**< 66 gallon, AOSmith HPTS */ + MODELS_AOSmithHPTS80 = 1103, /**< 80 gallon, AOSmith HPTS */ + + // GE Models + MODELS_GE2012 = 110, /**< The 2012 era GeoSpring */ + MODELS_GE2014STDMode = 111, /**< 2014 GE model run in standard mode */ + MODELS_GE2014STDMode_80 = 113, /**< 2014 GE model run in standard mode, 80 gallon unit */ + MODELS_GE2014 = 112, /**< 2014 GE model run in the efficiency mode */ + MODELS_GE2014_80 = 114, /**< 2014 GE model run in the efficiency mode, 80 gallon unit */ + MODELS_GE2014_80DR = 115, /**< 2014 GE model run in the efficiency mode, 80 gallon unit */ + MODELS_BWC2020_65 = 116, /**< The 2020 Bradford White 65 gallon unit */ + + // SANCO2 CO2 transcritical heat pump water heaters + // Rebranding Sanden -> SANCO2 5-23 + MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ + MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ + MODELS_SANCO2_GS3_45HPA_US_SP = + 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ + MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ + + // Sanden synomyms for backward compatability + // allow unmodified code using HPWHsim to build + MODELS_Sanden40 = MODELS_SANCO2_43, + MODELS_Sanden80 = MODELS_SANCO2_83, + MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, + MODELS_Sanden120 = MODELS_SANCO2_119, + + // The new-ish Rheem + MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ + MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ + + // The new new Rheem + MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ + + // Rheem 120V dedicated-circuit product, no resistance elements + MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ + MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ + + // Rheem 120V shared-circuit products, no resistance elements. + MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ + + // The new-ish Stiebel + MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ + + // Generic water heaters, corresponding to the tiers 1, 2, and 3 + MODELS_Generic1 = 170, /**< Generic Tier 1 */ + MODELS_Generic2 = 171, /**< Generic Tier 2 */ + MODELS_Generic3 = 172, /**< Generic Tier 3 */ + MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ + MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ + + MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ + MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ + + MODELS_StorageTank = 180, /**< Generic Tank without heaters */ + MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has + scalable input capacity and COP */ + MODELS_Scalable_MP = + 191, /** < Lower performance MP model that has scalable input capacity and COP */ + + // Non-preset models + MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ + MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ + MODELS_CustomResTankGeneric = + 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ + + // Larger Colmac models in single pass configuration + MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ + + // Larger Colmac models in multi pass configuration + MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ + + // Larger Nyle models in single pass configuration + MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ + MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ + // Larger Nyle models with the cold weather package! + MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ + + // Mitsubishi Electric Trane + MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = + 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ + + // Larger Nyle models in multi pass configuration + // MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ + MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + // Large Rheem multi pass models + MODELS_RHEEM_HPHD60HNU_201_MP = 350, + MODELS_RHEEM_HPHD60VNU_201_MP = 351, + MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data + MODELS_RHEEM_HPHD135VNU_483_MP = 353 // really bad fit to data due to inconsistency in data }; + /// 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 */ - UNITS_F, /**< fahrenheit */ - UNITS_KWH, /**< kilowatt hours */ - UNITS_BTU, /**< british thermal units */ - UNITS_KJ, /**< kilojoules */ - UNITS_KW, /**< kilowatt */ - UNITS_BTUperHr, /**< british thermal units per Hour */ - UNITS_GAL, /**< gallons */ - UNITS_L, /**< liters */ - UNITS_kJperHrC, /**< UA, metric units */ - UNITS_BTUperHrF, /**< UA, imperial units */ - UNITS_FT, /**< feet */ - UNITS_M, /**< meters */ - UNITS_FT2, /**< square feet */ - UNITS_M2, /**< square meters */ - UNITS_MIN, /**< minutes */ - UNITS_SEC, /**< seconds */ - UNITS_HR, /**< hours */ - UNITS_GPM, /**< gallons per minute */ - UNITS_LPS /**< liters per second */ - }; - - /** specifies the type of heat source */ - enum HEATSOURCE_TYPE { - TYPE_none, /**< a default to check to make sure it's been set */ - TYPE_resistance, /**< a resistance element */ - TYPE_compressor, /**< a vapor cycle compressor */ - TYPE_extra /**< an extra element to add user defined heat*/ + enum UNITS { + UNITS_C, /**< celsius */ + UNITS_F, /**< fahrenheit */ + UNITS_KWH, /**< kilowatt hours */ + UNITS_BTU, /**< british thermal units */ + UNITS_KJ, /**< kilojoules */ + UNITS_KW, /**< kilowatt */ + UNITS_BTUperHr, /**< british thermal units per Hour */ + UNITS_GAL, /**< gallons */ + UNITS_L, /**< liters */ + UNITS_kJperHrC, /**< UA, metric units */ + UNITS_BTUperHrF, /**< UA, imperial units */ + UNITS_FT, /**< feet */ + UNITS_M, /**< meters */ + UNITS_FT2, /**< square feet */ + UNITS_M2, /**< square meters */ + UNITS_MIN, /**< minutes */ + UNITS_SEC, /**< seconds */ + UNITS_HR, /**< hours */ + UNITS_GPM, /**< gallons per minute */ + UNITS_LPS /**< liters per second */ }; - /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ - enum EXTRAP_METHOD { - EXTRAP_LINEAR, /**< the default extrapolates linearly */ - EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest point */ - }; - - /** specifies the unit type for outputs in the CSV file-s */ - enum CSVOPTIONS { - CSVOPT_NONE, - CSVOPT_IPUNITS - }; - - struct NodeWeight { - int nodeNum; - double weight; - NodeWeight(int n, double w) : nodeNum(n), weight(w) {}; - - NodeWeight(int n) : nodeNum(n), weight(1.0) {}; - }; - - struct HeatingLogic { - public: - std::string description; - std::function compare; - - HeatingLogic(std::string desc, double d, HPWH *pHPWH, - std::function c, bool isHTS) : - description(desc), decisionPoint(d), parentHPWH(pHPWH), compare(c), - isEnteringWaterHighTempShutoff(isHTS) - {}; - - /**< checks that the input is all valid. */ - virtual const bool isValid() = 0; - /**< gets the value for comparing the tank value to, i.e. the target SoC */ - virtual const double getComparisonValue() = 0; - /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ - virtual const double getTankValue() = 0; - /**< function to calculate where the average node for a logic set is. */ - virtual const double nodeWeightAvgFract() = 0; - /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ - virtual const double getFractToMeetComparisonExternal() = 0; - - virtual int setDecisionPoint(double value) = 0; - double getDecisionPoint() { return decisionPoint; } - bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } - - protected: - double decisionPoint; - HPWH* parentHPWH; - bool isEnteringWaterHighTempShutoff; - }; - - struct SoCBasedHeatingLogic : HeatingLogic { - public: - SoCBasedHeatingLogic(std::string desc, double d, HPWH *pHPWH, - double hF = -0.05, double tM_C = 43.333, bool constMains = false, double mains_C = 18.333, - std::function c = std::less()) : - HeatingLogic(desc, d, pHPWH, c, false), - hysteresisFraction(hF), tempMinUseful_C(tM_C), - useCostantMains(constMains), constantMains_C(mains_C) - {}; - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - const double getMainsT_C(); - const double getTempMinUseful_C(); - int setDecisionPoint(double value); - int setConstantMainsTemperature(double mains_C); - - private: - double tempMinUseful_C; - double hysteresisFraction; - bool useCostantMains; - double constantMains_C; - }; - - struct TempBasedHeatingLogic : HeatingLogic { - public: - TempBasedHeatingLogic(std::string desc, std::vector n, - double d, HPWH *phpwh, bool a = false, - std::function c = std::less(), - bool isHTS = false) : - HeatingLogic(desc, d, phpwh, c, isHTS), - nodeWeights(n), isAbsolute(a) - {}; - - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - - int setDecisionPoint(double value); - int setDecisionPoint(double value, bool absolute); - - private: - const bool areNodeWeightsValid(); - - bool isAbsolute; - std::vector nodeWeights; - }; - - std::shared_ptr shutOffSoC(std::string desc, double targetSoC, double hystFract, double tempMinUseful_C, - bool constMains, double mains_C); - std::shared_ptr turnOnSoC(std::string desc, double targetSoC, double hystFract, double tempMinUseful_C, - bool constMains, double mains_C); - - std::shared_ptr topThird(double d); - std::shared_ptr topThird_absolute(double d); - std::shared_ptr bottomThird(double d); - std::shared_ptr bottomHalf(double d) ; - std::shared_ptr bottomTwelth(double d); - std::shared_ptr bottomSixth(double d); - std::shared_ptr bottomSixth_absolute(double d); - std::shared_ptr secondSixth(double d); - std::shared_ptr thirdSixth(double d); - std::shared_ptr fourthSixth(double d); - std::shared_ptr fifthSixth(double d); - std::shared_ptr topSixth(double d); - - std::shared_ptr standby(double d); - std::shared_ptr topNodeMaxTemp(double d); - std::shared_ptr bottomNodeMaxTemp(double d, bool isEnteringWaterHighTempShutoff = false); - std::shared_ptr bottomTwelthMaxTemp(double d); - std::shared_ptr topThirdMaxTemp(double d); - std::shared_ptr bottomSixthMaxTemp(double d); - std::shared_ptr secondSixthMaxTemp(double d); - std::shared_ptr fifthSixthMaxTemp(double d); - std::shared_ptr topSixthMaxTemp(double d); - - std::shared_ptr largeDraw(double d); - std::shared_ptr largerDraw(double d); - - ///this is the value that the public functions will return in case of a simulation - ///destroying error - static const int HPWH_ABORT = -274000; - - static std::string getVersion(); - /**< This function returns a string with the current version number */ - - int HPWHinit_presets(MODELS presetNum); - /**< This function will reset all member variables to defaults and then - * load in a set of parameters that are hardcoded in this function - - * which particular set of parameters is selected by presetNum. - * This is similar to the way the HPWHsim currently operates, as used in SEEM, - * but not quite as versatile. - * My impression is that this could be a useful input paradigm for CSE - * - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_file(std::string configFile); - /**< This function will load in a set of parameters from a file - * The file name is the input - there should be at most one set of parameters per file - * This is useful for testing new variations, and for the sort of variability - * that we typically do when creating SEEM runs - * Appropriate use of this function can be found in the documentation - - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ - int HPWHinit_resTank(double tankVol_L, double energyFactor, double upperPower_W, double lowerPower_W); - /**< This function will initialize a HPWH object to be a resistance tank. Since - * resistance tanks are so simple, they can be specified with only four variables: - * tank volume, energy factor, and the power of the upper and lower elements. Energy - * factor is converted into UA internally, although an external setter for UA is - * also provided in case the energy factor is unknown. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The logics are also set - * to standard setting, with upper as VIP activating when the top third is too cold. - */ - - int HPWHinit_resTankGeneric(double tankVol_L, double rValue_M2KperW, double upperPower_W, double lowerPower_W); - /**< This function will initialize a HPWH object to be a generic resistance storage water heater, - * with a specific R-Value defined at initalization. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The controls are the same standard controls for - * the HPWHinit_resTank() - */ - - int HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C); - /**< This function will initialize a HPWH object to be a non-specific HPWH model - * with an energy factor as specified. Since energy - * factor is not strongly correlated with energy use, most settings - * are taken from the GE2015_STDMode model. - */ - - int runOneStep(double drawVolume_L, double ambientT_C, - double externalT_C, DRMODES DRstatus, double inletVol2_L = 0., double inletT2_C = 0., - std::vector* nodePowerExtra_W = NULL); - /**< This function will progress the simulation forward in time by one step - * all calculated outputs are stored in private variables and accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** An overloaded function that uses takes inletT_C */ - int runOneStep(double inletT_C, double drawVolume_L, double ambientT_C, - double externalT_C, DRMODES DRstatus, double inletVol2_L = 0., double inletT2_C = 0., - std::vector* nodePowerExtra_W = NULL) { - setInletT(inletT_C); - return runOneStep(drawVolume_L, ambientT_C, - externalT_C, DRstatus, inletVol2_L, inletT2_C, - nodePowerExtra_W); - }; - - - int runNSteps(int N, double *inletT_C, double *drawVolume_L, - double *tankAmbientT_C, double *heatSourceAmbientT_C, - DRMODES *DRstatus); - /**< This function will progress the simulation forward in time by N (equal) steps - * The calculated values will be summed or averaged, as appropriate, and - * then stored in the usual variables to be accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** Setters for the what are typically input variables */ - void setInletT(double newInletT_C) { member_inletT_C = newInletT_C; }; - void setMinutesPerStep(double newMinutesPerStep) { minutesPerStep = 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 - specifically input/output energy/power, and runtime - will print to cout if messageCallback pointer is unspecified - does not use verbosity, as it is public and expected to be called only when needed */ - void printTankTemps(); - /**< this prints out all the node temps, kind of nicely formatted - does not use verbosity, as it is public and expected to be called only when needed */ - int WriteCSVHeading(FILE* outFILE, const char* preamble = "", int nTCouples = 6, int options = CSVOPT_NONE) const; - int WriteCSVRow(FILE* outFILE, const char* preamble = "", int nTCouples = 6, int options = CSVOPT_NONE) const; - /**< a couple of function to write the outputs to a file - they both will return 0 for success - the preamble should be supplied with a trailing comma, as these functions do - not add one. Additionally, a newline is written with each call. */ - - - - bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ - int setSetpoint(double newSetpoint, UNITS units = UNITS_C);/** 0 minutes and < 1440 minutes. */ - double getTimerLimitTOT_minute() const; - /**< Returns the timer limit in minutes for the DR_TOT call. */ - - int getInletHeight(int whichInlet) const; - /**< returns the water inlet height node number */ + /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ + enum EXTRAP_METHOD { + EXTRAP_LINEAR, /**< the default extrapolates linearly */ + EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest + point */ + }; - int getNumNodes() const; - /**< returns the number of nodes */ + /** specifies the unit type for outputs in the CSV file-s */ + enum CSVOPTIONS { + CSVOPT_NONE, + CSVOPT_IPUNITS + }; - double getTankNodeTemp(int nodeNum, UNITS units = UNITS_C) const; - /**< returns the temperature of the water at the specified node - with specified units - or HPWH_ABORT for incorrect node number or unit failure */ + struct NodeWeight { + int nodeNum; + double weight; + NodeWeight(int n, double w) : nodeNum(n), weight(w) {}; - double getNthSimTcouple(int iTCouple, int nTCouple, UNITS units = UNITS_C) const; - /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, - which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, - 1 at the bottom using specified units - returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ - - int getNumHeatSources() const; - /**< returns the number of heat sources */ - - int getNumResistanceElements() const; - /**< returns the number of resistance elements */ - - int getCompressorIndex() const; - /**< returns the index of the compressor in the heat source array. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - double getCompressorCapacity(double airTemp = 19.722, double inletTemp = 14.444, double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW, UNITS tempUnit = UNITS_C) const; - /**< Returns the heating output capacity of the compressor for the current HPWH model. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor. Outlet temperatures greater than the max allowable setpoints will return an error, but - for compressors with a fixed setpoint the */ - - int setCompressorOutputCapacity(double newCapacity, double airTemp = 19.722, double inletTemp = 14.444, double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW, UNITS tempUnit = UNITS_C); - /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and outlet temperatures. - For multi-pass models the capacity is set as the average between the inletTemp and outTemp since multi-pass models will increase - the water temperature only a few degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at - inletTemp might not be accurate for the entire heating cycle. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - int setScaleHPWHCapacityCOP(double scaleCapacity = 1., double scaleCOP = 1.); - /**< Scales the heatpump water heater input capacity and COP*/ - - int setResistanceCapacity(double power, int which = -1, UNITS pwrUNIT = UNITS_KW); - /**< Scale the resistance elements in the heat source list. Which heat source is chosen is changes is given by "which" - - If which (-1) sets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in setOfSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - double getResistanceCapacity(int which = -1, UNITS pwrUNIT = UNITS_KW); - /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given by "which" - - If which (-1) gets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in setOfSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - int getResistancePosition(int elementIndex) const; - - double getNthHeatSourceEnergyInput(int N, UNITS units = UNITS_KWH) const; - /**< returns the energy input to the Nth heat source, with the specified units - energy used by the heat source is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ + NodeWeight(int n) : nodeNum(n), weight(1.0) {}; + }; - double getNthHeatSourceEnergyOutput(int N, UNITS units = UNITS_KWH) const; - /**< returns the energy output from the Nth heat source, with the specified units - energy put into the water is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ - double getNthHeatSourceRunTime(int N) const; - /**< returns the run time for the Nth heat source, in minutes - note: they may sum to more than 1 time step for concurrently running heat sources - returns HPWH_ABORT for N out of bounds */ - int isNthHeatSourceRunning(int N) const; - /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and - returns HPWH_ABORT for N out of bounds */ - HEATSOURCE_TYPE getNthHeatSourceType(int N) const; - /**< returns the enum value for what type of heat source the Nth heat source is */ + struct HeatingLogic { + public: + std::string description; + std::function compare; + + HeatingLogic(std::string desc, + double d, + HPWH* pHPWH, + std::function c, + bool isHTS) + : description(desc) + , decisionPoint(d) + , parentHPWH(pHPWH) + , compare(c) + , isEnteringWaterHighTempShutoff(isHTS) {}; + + /**< checks that the input is all valid. */ + virtual const bool isValid() = 0; + /**< gets the value for comparing the tank value to, i.e. the target SoC */ + virtual const double getComparisonValue() = 0; + /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ + virtual const double getTankValue() = 0; + /**< function to calculate where the average node for a logic set is. */ + virtual const double nodeWeightAvgFract() = 0; + /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ + virtual const double getFractToMeetComparisonExternal() = 0; + + virtual int setDecisionPoint(double value) = 0; + double getDecisionPoint() { return decisionPoint; } + bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } + + protected: + double decisionPoint; + HPWH* parentHPWH; + bool isEnteringWaterHighTempShutoff; + }; + struct SoCBasedHeatingLogic : HeatingLogic { + public: + SoCBasedHeatingLogic(std::string desc, + double d, + HPWH* pHPWH, + double hF = -0.05, + double tM_C = 43.333, + bool constMains = false, + double mains_C = 18.333, + std::function c = std::less()) + : HeatingLogic(desc, d, pHPWH, c, false) + , hysteresisFraction(hF) + , tempMinUseful_C(tM_C) + , useCostantMains(constMains) + , constantMains_C(mains_C) {}; + const bool isValid(); + + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); + const double getMainsT_C(); + const double getTempMinUseful_C(); + int setDecisionPoint(double value); + int setConstantMainsTemperature(double mains_C); + + private: + double tempMinUseful_C; + double hysteresisFraction; + bool useCostantMains; + double constantMains_C; + }; - double getOutletTemp(UNITS units = UNITS_C) const; - /**< returns the outlet temperature in the specified units - returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ - double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser inlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + struct TempBasedHeatingLogic : HeatingLogic { + public: + TempBasedHeatingLogic(std::string desc, + std::vector n, + double d, + HPWH* phpwh, + bool a = false, + std::function c = std::less(), + bool isHTS = false) + : HeatingLogic(desc, d, phpwh, c, isHTS), nodeWeights(n), isAbsolute(a) {}; - double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser outlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + const bool isValid(); - double getExternalVolumeHeated(UNITS units = UNITS_L) const; - /**< returns the volume of water heated in an external in the specified units - returns 0 when no external heat source is running */ + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); - double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; - /**< get the total energy removed from the environment by all heat sources in specified units - (not net energy - does not include standby) - moving heat from the space to the water is the positive direction - returns HPWH_ABORT for incorrect units */ + int setDecisionPoint(double value); + int setDecisionPoint(double value, bool absolute); - double getStandbyLosses(UNITS units = UNITS_KWH) const; - /**< get the amount of heat lost through the tank in specified units - moving heat from the water to the space is the positive direction - negative should occur seldom - returns HPWH_ABORT for incorrect units */ + private: + const bool areNodeWeightsValid(); - double getTankHeatContent_kJ() const; - /**< get the heat content of the tank, relative to zero celsius - * returns using kilojoules */ + bool isAbsolute; + std::vector nodeWeights; + }; - int getHPWHModel() const; - /**< get the model number of the HPWHsim model number of the hpwh */ + std::shared_ptr shutOffSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + std::shared_ptr turnOnSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + + std::shared_ptr topThird(double d); + std::shared_ptr topThird_absolute(double d); + std::shared_ptr bottomThird(double d); + std::shared_ptr bottomHalf(double d); + std::shared_ptr bottomTwelth(double d); + std::shared_ptr bottomSixth(double d); + std::shared_ptr bottomSixth_absolute(double d); + std::shared_ptr secondSixth(double d); + std::shared_ptr thirdSixth(double d); + std::shared_ptr fourthSixth(double d); + std::shared_ptr fifthSixth(double d); + std::shared_ptr topSixth(double d); + + std::shared_ptr standby(double d); + std::shared_ptr topNodeMaxTemp(double d); + std::shared_ptr + bottomNodeMaxTemp(double d, bool isEnteringWaterHighTempShutoff = false); + std::shared_ptr bottomTwelthMaxTemp(double d); + std::shared_ptr topThirdMaxTemp(double d); + std::shared_ptr bottomSixthMaxTemp(double d); + std::shared_ptr secondSixthMaxTemp(double d); + std::shared_ptr fifthSixthMaxTemp(double d); + std::shared_ptr topSixthMaxTemp(double d); + + std::shared_ptr largeDraw(double d); + std::shared_ptr largerDraw(double d); + + /// this is the value that the public functions will return in case of a simulation + /// destroying error + static const int HPWH_ABORT = -274000; + + static std::string getVersion(); + /**< This function returns a string with the current version number */ + + int HPWHinit_presets(MODELS presetNum); + /**< This function will reset all member variables to defaults and then + * load in a set of parameters that are hardcoded in this function - + * which particular set of parameters is selected by presetNum. + * This is similar to the way the HPWHsim currently operates, as used in SEEM, + * but not quite as versatile. + * My impression is that this could be a useful input paradigm for CSE + * + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_file(std::string configFile); + /**< This function will load in a set of parameters from a file + * The file name is the input - there should be at most one set of parameters per file + * This is useful for testing new variations, and for the sort of variability + * that we typically do when creating SEEM runs + * Appropriate use of this function can be found in the documentation + + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ + int HPWHinit_resTank(double tankVol_L, + double energyFactor, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a resistance tank. Since + * resistance tanks are so simple, they can be specified with only four variables: + * tank volume, energy factor, and the power of the upper and lower elements. Energy + * factor is converted into UA internally, although an external setter for UA is + * also provided in case the energy factor is unknown. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The logics are also set + * to standard setting, with upper as VIP activating when the top third is too cold. + */ + + int HPWHinit_resTankGeneric(double tankVol_L, + double rValue_M2KperW, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a generic resistance storage water + * heater, with a specific R-Value defined at initalization. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The controls are the same standard + * controls for the HPWHinit_resTank() + */ + + int HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C); + /**< This function will initialize a HPWH object to be a non-specific HPWH model + * with an energy factor as specified. Since energy + * factor is not strongly correlated with energy use, most settings + * are taken from the GE2015_STDMode model. + */ + + int runOneStep(double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* nodePowerExtra_W = NULL); + /**< This function will progress the simulation forward in time by one step + * all calculated outputs are stored in private variables and accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** An overloaded function that uses takes inletT_C */ + int runOneStep(double inletT_C, + double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* nodePowerExtra_W = NULL) + { + setInletT(inletT_C); + return runOneStep(drawVolume_L, + ambientT_C, + externalT_C, + DRstatus, + inletVol2_L, + inletT2_C, + nodePowerExtra_W); + }; - int getCompressorCoilConfig() const; - bool isCompressorMultipass() const; - bool isCompressoExternalMultipass() const; + int runNSteps(int N, + double* inletT_C, + double* drawVolume_L, + double* tankAmbientT_C, + double* heatSourceAmbientT_C, + DRMODES* DRstatus); + /**< This function will progress the simulation forward in time by N (equal) steps + * The calculated values will be summed or averaged, as appropriate, and + * then stored in the usual variables to be accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** Setters for the what are typically input variables */ + void setInletT(double newInletT_C) { member_inletT_C = newInletT_C; }; + void setMinutesPerStep(double newMinutesPerStep) { minutesPerStep = 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 + specifically input/output energy/power, and runtime + will print to cout if messageCallback pointer is unspecified + does not use verbosity, as it is public and expected to be called only when needed */ + void printTankTemps(); + /**< this prints out all the node temps, kind of nicely formatted + does not use verbosity, as it is public and expected to be called only when needed */ + int WriteCSVHeading(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + int WriteCSVRow(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + /**< a couple of function to write the outputs to a file + they both will return 0 for success + the preamble should be supplied with a trailing comma, as these functions do + not add one. Additionally, a newline is written with each call. */ + + bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ + int setSetpoint(double newSetpoint, UNITS units = UNITS_C); /*** nodePowerExtra_W, double tankAmbientT_C); - /**< adds extra heat defined by the user. Where nodeExtraHeat[] is a vector of heat quantities to be added during the step. nodeExtraHeat[ 0] would go to bottom node, 1 to next etc. */ + int setExternalPortHeightByFraction(double fractionalHeight, int whichPort); + /**< sets the external heater port heights inlet height node number */ - double tankAvg_C(const std::vector nodeWeights) const; - /**< functions to calculate what the temperature in a portion of the tank is */ + int getExternalInletHeight() const; + /**< Returns the node where the split system HPWH adds heated water to the storage tank*/ + int getExternalOutletHeight() const; + /**< Returns the node where the split system HPWH takes cold water out of the storage tank*/ - void mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor); - /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed below node. */ + int setNodeNumFromFractionalHeight(double fractionalHeight, int& inletNum); + /**< This is a setter for the water inlet height, by fraction. */ - void calcDerivedValues(); - /**< a helper function for the inits, calculating condentropy and the lowest node */ - void calcSizeConstants(); - /**< a helper function to set constants for the UA and tank size*/ - void calcDerivedHeatingValues(); - /**< a helper for the helper, calculating condentropy and the lowest node*/ - void mapResRelativePosToSetOfSources(); - /**< a helper function for the inits, creating a mapping function for the position of the resistance elements - to their indexes in setOfSources. */ + int setTimerLimitTOT(double limit_min); + /**< Sets the timer limit in minutes for the DR_TOT call. Must be > 0 minutes and < 1440 + * minutes. */ + double getTimerLimitTOT_minute() const; + /**< Returns the timer limit in minutes for the DR_TOT call. */ - int checkInputs(); - /**< a helper function to run a few checks on the HPWH input parameters */ + int getInletHeight(int whichInlet) const; + /**< returns the water inlet height node number */ - double getChargePerNode(double tCold, double tMix, double tHot) const; + int getNumNodes() const; + /**< returns the number of nodes */ - void calcAndSetSoCFraction(); + double getTankNodeTemp(int nodeNum, UNITS units = UNITS_C) const; + /**< returns the temperature of the water at the specified node - with specified units + or HPWH_ABORT for incorrect node number or unit failure */ - 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; + double getNthSimTcouple(int iTCouple, int nTCouple, UNITS units = UNITS_C) const; + /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, + which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, + 1 at the bottom using specified units + returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ + + int getNumHeatSources() const; + /**< returns the number of heat sources */ + + int getNumResistanceElements() const; + /**< returns the number of resistance elements */ + + int getCompressorIndex() const; + /**< returns the index of the compressor in the heat source array. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + double getCompressorCapacity(double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C) const; + /**< Returns the heating output capacity of the compressor for the current HPWH model. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor. Outlet temperatures greater than the max allowable setpoints will return an + error, but for compressors with a fixed setpoint the */ + + int setCompressorOutputCapacity(double newCapacity, + double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C); + /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and + outlet temperatures. For multi-pass models the capacity is set as the average between the + inletTemp and outTemp since multi-pass models will increase the water temperature only a few + degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at + inletTemp might not be accurate for the entire heating cycle. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + int setScaleHPWHCapacityCOP(double scaleCapacity = 1., double scaleCOP = 1.); + /**< Scales the heatpump water heater input capacity and COP*/ + + int setResistanceCapacity(double power, int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Scale the resistance elements in the heat source list. Which heat source is chosen is + changes is given by "which" + - If which (-1) sets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in setOfSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + double getResistanceCapacity(int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given + by "which" + - If which (-1) gets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in setOfSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + int getResistancePosition(int elementIndex) const; + + double getNthHeatSourceEnergyInput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy input to the Nth heat source, with the specified units + energy used by the heat source is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ - bool simHasFailed; - /**< did an internal error cause the simulation to fail? */ + double getNthHeatSourceEnergyOutput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy output from the Nth heat source, with the specified units + energy put into the water is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ + double getNthHeatSourceRunTime(int N) const; + /**< returns the run time for the Nth heat source, in minutes + note: they may sum to more than 1 time step for concurrently running heat sources + returns HPWH_ABORT for N out of bounds */ + int isNthHeatSourceRunning(int N) const; + /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and + returns HPWH_ABORT for N out of bounds */ + HEATSOURCE_TYPE getNthHeatSourceType(int N) const; + /**< returns the enum value for what type of heat source the Nth heat source is */ + + double getOutletTemp(UNITS units = UNITS_C) const; + /**< returns the outlet temperature in the specified units + returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ + double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser inlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - bool isHeating; - /**< is the hpwh currently heating or not? */ + double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser outlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - bool setpointFixed; - /**< does the HPWH allow the setpoint to vary */ + double getExternalVolumeHeated(UNITS units = UNITS_L) const; + /**< returns the volume of water heated in an external in the specified units + returns 0 when no external heat source is running */ - bool tankSizeFixed; - /**< does the HPWH have a constant tank size or can it be changed */ + double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; + /**< get the total energy removed from the environment by all heat sources in specified units + (not net energy - does not include standby) + moving heat from the space to the water is the positive direction + returns HPWH_ABORT for incorrect units */ - bool canScale; - /**< can the HPWH scale capactiy and COP or not */ + double getStandbyLosses(UNITS units = UNITS_KWH) const; + /**< get the amount of heat lost through the tank in specified units + moving heat from the water to the space is the positive direction + negative should occur seldom + returns HPWH_ABORT for incorrect units */ - VERBOSITY hpwhVerbosity; - /**< an enum to let the sim know how much output to say */ + double getTankHeatContent_kJ() const; + /**< get the heat content of the tank, relative to zero celsius + * returns using kilojoules */ - 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 */ + int getHPWHModel() const; + /**< get the model number of the HPWHsim model number of the hpwh */ + int getCompressorCoilConfig() const; + bool isCompressorMultipass() const; + bool isCompressoExternalMultipass() const; + bool hasACompressor() const; + /**< Returns if the HPWH model has a compressor or not, could be a storage or resistance tank. + */ - MODELS hpwhModel; - /**< The hpwh should know which preset initialized it, or if it was from a file */ + bool hasExternalHeatSource() const; + /**< Returns if the HPWH model has any external heat sources or not, could be a compressor or + * resistance element. */ + double getExternalMPFlowRate(UNITS units = UNITS_GPM) const; + /**< Returns the constant flow rate for an external multipass heat sources. */ - int numHeatSources; - /**< how many heat sources this HPWH has */ - HeatSource *setOfSources; - /**< an array containing the HeatSources, in order of priority */ + double getCompressorMinRuntime(UNITS units = UNITS_MIN) const; - int compressorIndex; - /**< The index of the compressor heat source (set to -1 if no compressor)*/ + int getSizingFractions(double& aquafract, double& percentUseable) const; + /**< returns the fraction of total tank volume from the bottom up where the aquastat is + or the turn on logic for the compressor, and the USEable fraction of storage or 1 minus + where the shut off logic is for the compressor. If the logic spans multiple nodes it + returns the weighted average of the nodes */ - int lowestElementIndex; - /**< The index of the lowest resistance element heat source (set to -1 if no resistance elements)*/ + bool isHPWHScalable() const; + /**< returns if the HPWH is scalable or not*/ - int highestElementIndex; - /**< The index of the highest resistance element heat source. if only one element it equals lowestElementIndex (set to -1 if no resistance elements)*/ + bool shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const; + /**< Checks the demand response signal against the different heat source types */ - int VIPIndex; - /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance elements)*/ + void resetTopOffTimer(); + /**< resets variables for timer associated with the DR_TOT call */ - int numNodes; - /**< the number of nodes in the tank - must be >= 12, in multiples of 12 */ + double getLocationTemp_C() const; + int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); - int nodeDensity; - /**< the number of calculation nodes in a logical node */ + bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); + int setEnteringWaterHighTempShutOff(double highTemp, + bool tempIsAbsolute, + int heatSourceIndex, + UNITS units = UNITS_C); + /**< functions to check for and set specific high temperature shut off logics. + HPWHs can only have one of these, which is at least typical */ - int inletHeight; - /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 and numNodes-1 */ + int setTargetSoCFraction(double target); - int inlet2Height; - /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be between 0 and numNodes-1 */ + bool canUseSoCControls(); - double tankVolume_L; - /**< the volume in liters of the tank */ - double tankUA_kJperHrC; - /**< the UA of the tank, in metric units */ - double fittingsUA_kJperHrC; - /**< the UA of the fittings for the tank, in metric units */ + int switchToSoCControls(double targetSoC, + double hysteresisFraction = 0.05, + double tempMinUseful = 43.333, + bool constantMainsT = false, + double mainsT = 18.333, + UNITS tempUnit = UNITS_C); - double volPerNode_LperNode; - /**< the volume in liters of a single node */ - double node_height; - /**< the height in meters of the one node */ - double fracAreaTop; - /**< the fraction of the UA on the top and bottom of the tank, assuming it's a cylinder */ - double fracAreaSide; - /**< the fraction of the UA on the sides of the tank, assuming it's a cylinder */ + bool isSoCControlled() const; - double currentSoCFraction; - /**< the current state of charge according to the logic */ + private: + class HeatSource; - double setpoint_C; - /**< the setpoint of the tank */ + void setAllDefaults(); /**< sets all the defaults default */ - double *tankTemps_C; - /**< an array holding the temperature of each node - 0 is the bottom node, numNodes is the top */ - double *nextTankTemps_C; - /**< an array holding the future temperature of each node for the conduction calculation - 0 is the bottom node, numNodes is the top */ + void updateTankTemps( + double draw, double inletT, double ambientT, double inletVol2_L, double inletT2_L); + void mixTankInversions(); + /**< Mixes the any temperature inversions in the tank after all the temperature calculations */ + void updateSoCIfNecessary(); - DRMODES prevDRstatus; - /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ + bool areAllHeatSourcesOff() const; + /**< test if all the heat sources are off */ + void turnAllHeatSourcesOff(); + /**< disengage each heat source */ - double timerLimitTOT; - /**< the time limit in minutes on the timer when the compressor and resistance elements are turned back on, used with DR_TOT. */ - double timerTOT; - /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ + void addHeatParent(HeatSource* heatSourcePtr, double heatSourceAmbientT_C, double minutesToRun); - bool usesSoCLogic; + void addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbientT_C); + /**< adds extra heat defined by the user. Where nodeExtraHeat[] is a vector of heat quantities + * to be added during the step. nodeExtraHeat[ 0] would go to bottom node, 1 to next etc. */ - // Some outputs - double outletTemp_C; - /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ + double tankAvg_C(const std::vector nodeWeights) const; + /**< functions to calculate what the temperature in a portion of the tank is */ - double condenserInlet_C; - /**< the temperature of the inlet water to the condensor either an average of tank nodes or taken from the bottom, 0 if no flow or no compressor */ - double condenserOutlet_C; - /**< the temperature of the outlet water from the condensor either, 0 if no flow or no compressor */ - double externalVolumeHeated_L; - /**< the volume of water heated by an external source, 0 if no flow or no external heat source */ + void mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor); + /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed + * below node. */ - double energyRemovedFromEnvironment_kWh; - /**< the total energy removed from the environment, to heat the water */ - double standbyLosses_kWh; - /**< the amount of heat lost to standby */ + void calcDerivedValues(); + /**< a helper function for the inits, calculating condentropy and the lowest node */ + void calcSizeConstants(); + /**< a helper function to set constants for the UA and tank size*/ + void calcDerivedHeatingValues(); + /**< a helper for the helper, calculating condentropy and the lowest node*/ + void mapResRelativePosToSetOfSources(); + /**< a helper function for the inits, creating a mapping function for the position of the + resistance elements to their indexes in setOfSources. */ - // special variables for adding abilities - bool tankMixesOnDraw; - /**< whether or not the bottom fraction (defined by mixBelowFraction) - of the tank should mix during draws */ - double mixBelowFractionOnDraw; - /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ + int checkInputs(); + /**< a helper function to run a few checks on the HPWH input parameters */ - bool doTempDepression; - /**< whether the HPWH should use the alternate ambient temperature that + double getChargePerNode(double tCold, double tMix, double tHot) const; + + 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? */ + + bool isHeating; + /**< is the hpwh currently heating or not? */ + + bool setpointFixed; + /**< does the HPWH allow the setpoint to vary */ + + bool tankSizeFixed; + /**< does the HPWH have a constant tank size or can it be changed */ + + 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 file */ + + int numHeatSources; + /**< how many heat sources this HPWH has */ + HeatSource* setOfSources; + /**< an array containing the HeatSources, in order of priority */ + + int compressorIndex; + /**< The index of the compressor heat source (set to -1 if no compressor)*/ + + int lowestElementIndex; + /**< The index of the lowest resistance element heat source (set to -1 if no resistance + * elements)*/ + + int highestElementIndex; + /**< The index of the highest resistance element heat source. if only one element it equals + * lowestElementIndex (set to -1 if no resistance elements)*/ + + int VIPIndex; + /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance + * elements)*/ + + int numNodes; + /**< the number of nodes in the tank - must be >= 12, in multiples of 12 */ + + int nodeDensity; + /**< the number of calculation nodes in a logical node */ + + int inletHeight; + /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 + * and numNodes-1 */ + + int inlet2Height; + /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be + * between 0 and numNodes-1 */ + + double tankVolume_L; + /**< the volume in liters of the tank */ + double tankUA_kJperHrC; + /**< the UA of the tank, in metric units */ + double fittingsUA_kJperHrC; + /**< the UA of the fittings for the tank, in metric units */ + + double volPerNode_LperNode; + /**< the volume in liters of a single node */ + double node_height; + /**< the height in meters of the one node */ + double fracAreaTop; + /**< the fraction of the UA on the top and bottom of the tank, assuming it's a cylinder */ + double fracAreaSide; + /**< the fraction of the UA on the sides of the tank, assuming it's a cylinder */ + + double currentSoCFraction; + /**< the current state of charge according to the logic */ + + double setpoint_C; + /**< the setpoint of the tank */ + + double* tankTemps_C; + /**< an array holding the temperature of each node - 0 is the bottom node, numNodes is the top + */ + double* nextTankTemps_C; + /**< an array holding the future temperature of each node for the conduction calculation - 0 is + * the bottom node, numNodes is the top */ + + DRMODES prevDRstatus; + /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ + + double timerLimitTOT; + /**< the time limit in minutes on the timer when the compressor and resistance elements are + * turned back on, used with DR_TOT. */ + double timerTOT; + /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ + + bool usesSoCLogic; + + // Some outputs + double outletTemp_C; + /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ + + double condenserInlet_C; + /**< the temperature of the inlet water to the condensor either an average of tank nodes or + * taken from the bottom, 0 if no flow or no compressor */ + double condenserOutlet_C; + /**< the temperature of the outlet water from the condensor either, 0 if no flow or no + * compressor */ + double externalVolumeHeated_L; + /**< the volume of water heated by an external source, 0 if no flow or no external heat source + */ + + double energyRemovedFromEnvironment_kWh; + /**< the total energy removed from the environment, to heat the water */ + double standbyLosses_kWh; + /**< the amount of heat lost to standby */ + + // special variables for adding abilities + bool tankMixesOnDraw; + /**< whether or not the bottom fraction (defined by mixBelowFraction) + of the tank should mix during draws */ + double mixBelowFractionOnDraw; + /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ + + bool doTempDepression; + /**< whether the HPWH should use the alternate ambient temperature that gets depressed when a compressor is running NOTE: this only works for 1 minute steps */ - double locationTemperature_C; - /**< this is the special location temperature that stands in for the the + double locationTemperature_C; + /**< this is the special location temperature that stands in for the the ambient temperature if you are doing temp. depression */ - double maxDepression_C = 2.5; - /** a couple variables to hold values which are typically inputs */ - double member_inletT_C; - double minutesPerStep = 1; + double maxDepression_C = 2.5; + /** a couple variables to hold values which are typically inputs */ + double member_inletT_C; + double minutesPerStep = 1; + + bool doInversionMixing; + /**< If and only if true will model temperature inversion mixing in the tank */ - bool doInversionMixing; - /**< If and only if true will model temperature inversion mixing in the tank */ + bool doConduction; + /**< If and only if true will model conduction between the internal nodes of the tank */ + + struct resPoint { + int index; + int position; + }; + std::vector resistanceHeightMap; + /**< A map from index of an resistance element in setOfSources to position in the tank, its + is sorted by height from lowest to highest*/ - bool doConduction; - /**< If and only if true will model conduction between the internal nodes of the tank */ +}; // end of HPWH class - struct resPoint { - int index; - int position; - }; - std::vector resistanceHeightMap; - /**< A map from index of an resistance element in setOfSources to position in the tank, its - is sorted by height from lowest to highest*/ +class HPWH::HeatSource { + public: + friend class HPWH; + + HeatSource() {} /**< default constructor, does not create a useful HeatSource */ + HeatSource(HPWH* parentHPWH); + /**< constructor assigns a pointer to the hpwh that owns this heat source */ + HeatSource(const HeatSource& hSource); /// copy constructor + HeatSource& operator=(const HeatSource& hSource); /// assignment operator + /**< the copy constructor and assignment operator basically just checks if there + are backup/companion pointers - these can't be copied */ + + void setupAsResistiveElement(int node, double Watts); + /**< configure the heat source to be a resisive element, positioned at the + specified node, with the specified power in watts */ + void setupExtraHeat(std::vector* nodePowerExtra_W); + /**< Configure a user defined heat source added as extra, based off using + nodePowerExtra_W as the total watt input and the condensity*/ + + bool isEngaged() const; + /**< return whether or not the heat source is engaged */ + void engageHeatSource(DRMODES DRstatus = DR_ALLOW); + /**< turn heat source on, i.e. set isEngaged to TRUE */ + void disengageHeatSource(); + /**< turn heat source off, i.e. set isEngaged to FALSE */ + + bool isLockedOut() const; + /**< return whether or not the heat source is locked out */ + void lockOutHeatSource(); + /**< lockout heat source, i.e. set isLockedOut to TRUE */ + void unlockHeatSource(); + /**< unlock heat source, i.e. set isLockedOut to FALSE */ + + bool shouldLockOut(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should lock out */ + bool shouldUnlock(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should unlock */ + + bool toLockOrUnlock(double heatSourceAmbientT_C); + /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the + * heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ + + bool shouldHeat() const; + /**< queries the heat source as to whether or not it should turn on */ + bool shutsOff() const; + /**< queries the heat source whether should shut off */ + + bool maxedOut() const; + /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at + * setpoint. */ + + int findParent() const; + /**< returns the index of the heat source where this heat source is a backup. + returns -1 if none found. */ + + double fractToMeetComparisonExternal() const; + /**< calculates the distance the current state is from the shutOff logic for external + * configurations*/ + + void addHeat(double externalT_C, double minutesToRun); + /**< adds heat to the hpwh - this is the function that interprets the + various configurations (internal/external, resistance/heat pump) to add heat */ + + void setCondensity(double cnd1, + double cnd2, + double cnd3, + double cnd4, + double cnd5, + double cnd6, + double cnd7, + double cnd8, + double cnd9, + double cnd10, + double cnd11, + double cnd12); + /**< a function to set the condensity values, it pretties up the init funcs. */ + + void linearInterp(double& ynew, double xnew, double x0, double x1, double y0, double y1); + /**< Does a simple linear interpolation between two points to the xnew point */ + + void regressedMethod( + double& ynew, std::vector& coefficents, double x1, double x2, double x3); + /**< Does a calculation based on the ten term regression equation */ + + void regressedMethodMP(double& ynew, std::vector& coefficents, double x1, double x2); + /**< Does a calculation based on the five term regression equation for MP split systems */ + + void btwxtInterp(double& input_BTUperHr, double& cop, std::vector& target); + /**< Does a linear interpolation in btwxt to the target point*/ + + void setupDefrostMap(double derate35 = 0.8865); + /**< configure the heat source with a default for the defrost derating */ + void defrostDerate(double& to_derate, double airT_C); + /**< Derates the COP of a system based on the air temperature */ + + private: + // start with a few type definitions + enum COIL_CONFIG { + CONFIG_SUBMERGED, + CONFIG_WRAPPED, + CONFIG_EXTERNAL + }; + /** the creator of the heat source, necessary to access HPWH variables */ + HPWH* hpwh; -}; //end of HPWH class + // these are the heat source state/output variables + bool isOn; + /**< is the heat source running or not */ + bool lockedOut; + /**< is the heat source locked out */ + bool doDefrost; + /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ + // some outputs + double runtime_min; + /**< this is the percentage of the step that the heat source was running */ + double energyInput_kWh; + /**< the energy used by the heat source */ + double energyOutput_kWh; + /**< the energy put into the water by the heat source */ -class HPWH::HeatSource { - public: - friend class HPWH; - - HeatSource(){} /**< default constructor, does not create a useful HeatSource */ - HeatSource(HPWH *parentHPWH); - /**< constructor assigns a pointer to the hpwh that owns this heat source */ - HeatSource(const HeatSource &hSource); ///copy constructor - HeatSource& operator=(const HeatSource &hSource); ///assignment operator - /**< the copy constructor and assignment operator basically just checks if there - are backup/companion pointers - these can't be copied */ - - void setupAsResistiveElement(int node, double Watts); - /**< configure the heat source to be a resisive element, positioned at the - specified node, with the specified power in watts */ - void setupExtraHeat(std::vector* nodePowerExtra_W); - /**< Configure a user defined heat source added as extra, based off using - nodePowerExtra_W as the total watt input and the condensity*/ - - bool isEngaged() const; - /**< return whether or not the heat source is engaged */ - void engageHeatSource(DRMODES DRstatus = DR_ALLOW); - /**< turn heat source on, i.e. set isEngaged to TRUE */ - void disengageHeatSource(); - /**< turn heat source off, i.e. set isEngaged to FALSE */ - - bool isLockedOut() const; - /**< return whether or not the heat source is locked out */ - void lockOutHeatSource(); - /**< lockout heat source, i.e. set isLockedOut to TRUE */ - void unlockHeatSource(); - /**< unlock heat source, i.e. set isLockedOut to FALSE */ - - bool shouldLockOut(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should lock out */ - bool shouldUnlock(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should unlock */ - - bool toLockOrUnlock(double heatSourceAmbientT_C); - /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ - - bool shouldHeat() const; - /**< queries the heat source as to whether or not it should turn on */ - bool shutsOff() const; - /**< queries the heat source whether should shut off */ - - bool maxedOut() const; - /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at setpoint. */ - - int findParent() const; - /**< returns the index of the heat source where this heat source is a backup. - returns -1 if none found. */ - - double fractToMeetComparisonExternal() const; - /**< calculates the distance the current state is from the shutOff logic for external configurations*/ - - void addHeat(double externalT_C, double minutesToRun); - /**< adds heat to the hpwh - this is the function that interprets the - various configurations (internal/external, resistance/heat pump) to add heat */ - - void setCondensity(double cnd1, double cnd2, double cnd3, double cnd4, - double cnd5, double cnd6, double cnd7, double cnd8, - double cnd9, double cnd10, double cnd11, double cnd12); - /**< a function to set the condensity values, it pretties up the init funcs. */ - - void linearInterp(double &ynew, double xnew, double x0, double x1, double y0, double y1); - /**< Does a simple linear interpolation between two points to the xnew point */ - - void regressedMethod(double &ynew, std::vector &coefficents, double x1, double x2, double x3); - /**< Does a calculation based on the ten term regression equation */ - - void regressedMethodMP(double &ynew, std::vector &coefficents, double x1, double x2); - /**< Does a calculation based on the five term regression equation for MP split systems */ - - void btwxtInterp(double& input_BTUperHr, double& cop, std::vector& target); - /**< Does a linear interpolation in btwxt to the target point*/ - - void setupDefrostMap(double derate35 = 0.8865); - /**< configure the heat source with a default for the defrost derating */ - void defrostDerate(double &to_derate, double airT_C); - /**< Derates the COP of a system based on the air temperature */ - - private: - //start with a few type definitions - enum COIL_CONFIG { - CONFIG_SUBMERGED, - CONFIG_WRAPPED, - CONFIG_EXTERNAL - }; - - /** the creator of the heat source, necessary to access HPWH variables */ - HPWH *hpwh; - - // these are the heat source state/output variables - bool isOn; - /**< is the heat source running or not */ - - bool lockedOut; - /**< is the heat source locked out */ - - bool doDefrost; - /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ - - // some outputs - double runtime_min; - /**< this is the percentage of the step that the heat source was running */ - double energyInput_kWh; - /**< the energy used by the heat source */ - double energyOutput_kWh; - /**< the energy put into the water by the heat source */ - -// these are the heat source property variables - bool isVIP; - /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ - HeatSource* backupHeatSource; - /**< a pointer to the heat source which serves as backup to this one + // these are the heat source property variables + bool isVIP; + /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ + HeatSource* backupHeatSource; + /**< a pointer to the heat source which serves as backup to this one should be NULL if no backup exists */ - HeatSource* companionHeatSource; - /**< a pointer to the heat source which will run concurrently with this one + HeatSource* companionHeatSource; + /**< a pointer to the heat source which will run concurrently with this one it still will only turn on if shutsOff is false */ - HeatSource* followedByHeatSource; - /**< a pointer to the heat source which will attempt to run after this one */ + HeatSource* followedByHeatSource; + /**< a pointer to the heat source which will attempt to run after this one */ - double condensity[CONDENSITY_SIZE]; - /**< The condensity function is always composed of 12 nodes. + double condensity[CONDENSITY_SIZE]; + /**< The condensity function is always composed of 12 nodes. It represents the location within the tank where heat will be distributed, and it also is used to calculate the condenser temperature for inputPower/COP calcs. It is conceptually linked to the way condenser coils are wrapped around (or within) the tank, however a resistance heat source can also be simulated by specifying the entire condensity in one node. */ - double shrinkage; - /**< the shrinkage is a derived value, using parameters alpha, beta, - and the condentropy, which is derived from the condensity - alpha and beta are not intended to be settable - see the hpwh_init functions for calculation of shrinkage */ - - struct perfPoint { - double T_F; - std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T - std::vector COP_coeffs; // c0 + c1*T + c2*T*T - }; - - std::vector perfMap; - /**< A map with input/COP quadratic curve coefficients at a given external temperature */ - - std::vector< std::vector > perfGrid; - /**< The axis values defining the regular grid for the performance data. - SP would have 3 axis, MP would have 2 axis*/ - - std::vector< std::vector > perfGridValues; - /**< The values for input power and cop use matching to the grid. Should be long format with { { inputPower_W }, { COP } }. */ - - class Btwxt::RegularGridInterpolator *perfRGI; - /**< The grid interpolator used for mapping performance*/ - - bool useBtwxtGrid; - - /** a vector to hold the set of logical choices for turning this element on */ - std::vector> turnOnLogicSet; - /** a vector to hold the set of logical choices that can cause an element to turn off */ - std::vector> shutOffLogicSet; - /** a single logic that checks the bottom point is below a temperature so the system doesn't short cycle*/ - std::shared_ptr standbyLogic; - - /** some compressors have a resistance element for defrost*/ - struct resistanceElementDefrost - { - double inputPwr_kW; - double constTempLift_dF; - double onBelowT_F; - }; - resistanceElementDefrost resDefrost; - - struct defrostPoint { - double T_F; - double derate_fraction; - }; - std::vector defrostMap; - /**< A list of points for the defrost derate factor ordered by increasing external temperature */ - - struct maxOut_minAir { - double outT_C; - double airT_C; - }; - maxOut_minAir maxOut_at_LowT; - /**< maximum output temperature at the minimum operating temperature of HPWH environment (minT)*/ - - struct SecondaryHeatExchanger { - double coldSideTemperatureOffest_dC; - double hotSideTemperatureOffset_dC; - double extraPumpPower_W; - }; - - SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary heat exchanger by adding extra input energy for the pump and - an increaes in the water to the incoming waater temperature to the heatpump*/ - - void addTurnOnLogic(std::shared_ptr logic); - void addShutOffLogic(std::shared_ptr logic); - /**< these are two small functions to remove some of the cruft in initiation functions */ - void clearAllTurnOnLogic(); - void clearAllShutOffLogic(); - void clearAllLogic(); - /**< these are two small functions to remove some of the cruft in initiation functions */ - - - - void changeResistanceWatts(double watts); - /**< function to change the resistance wattage */ - - bool isACompressor() const; - /**< returns if the heat source uses a compressor or not */ - bool isAResistance() const; - /**< returns if the heat source uses a resistance element or not */ - bool isExternalMultipass() const; - - double minT; - /**< minimum operating temperature of HPWH environment */ - - double maxT; - /**< maximum operating temperature of HPWH environment */ - - double maxSetpoint_C; - /**< the maximum setpoint of the heat source can create, used for compressors predominately */ - - double hysteresis_dC; - /**< a hysteresis term that prevents short cycling due to heat pump self-interaction - when the heat source is engaged, it is subtracted from lowT cutoffs and - added to lowTreheat cutoffs */ + double shrinkage; + /**< the shrinkage is a derived value, using parameters alpha, beta, + and the condentropy, which is derived from the condensity + alpha and beta are not intended to be settable + see the hpwh_init functions for calculation of shrinkage */ + + struct perfPoint { + double T_F; + std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T + std::vector COP_coeffs; // c0 + c1*T + c2*T*T + }; - bool depressesTemperature; - /**< heat pumps can depress the temperature of their space in certain instances - - whether or not this occurs is a bool in HPWH, but a heat source must - know if it is capable of contributing to this effect or not - NOTE: this only works for 1 minute steps - ALSO: this is set according the the heat source type, not user-specified */ + std::vector perfMap; + /**< A map with input/COP quadratic curve coefficients at a given external temperature */ - double airflowFreedom; - /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor - cop (not capacity) for cases where the air flow is restricted - typically ducting */ + std::vector> perfGrid; + /**< The axis values defining the regular grid for the performance data. + SP would have 3 axis, MP would have 2 axis*/ - int externalInletHeight; /**> perfGridValues; + /**< The values for input power and cop use matching to the grid. Should be long format with { { + * inputPower_W }, { COP } }. */ - double mpFlowRate_LPS; /**< The multipass flow rate */ + class Btwxt::RegularGridInterpolator* perfRGI; + /**< The grid interpolator used for mapping performance*/ - COIL_CONFIG configuration; /**< submerged, wrapped, external */ - HEATSOURCE_TYPE typeOfHeatSource; /**< compressor, resistance, extra, none */ - bool isMultipass; /**< single pass or multi-pass. Anything not obviously split system single pass is multipass*/ + bool useBtwxtGrid; - int lowestNode; - /**< hold the number of the first non-zero condensity entry */ + /** a vector to hold the set of logical choices for turning this element on */ + std::vector> turnOnLogicSet; + /** a vector to hold the set of logical choices that can cause an element to turn off */ + std::vector> shutOffLogicSet; + /** a single logic that checks the bottom point is below a temperature so the system doesn't + * short cycle*/ + std::shared_ptr standbyLogic; - EXTRAP_METHOD extrapolationMethod; /**< linear or nearest neighbor*/ + /** some compressors have a resistance element for defrost*/ + struct resistanceElementDefrost { + double inputPwr_kW; + double constTempLift_dF; + double onBelowT_F; + }; + resistanceElementDefrost resDefrost; + + struct defrostPoint { + double T_F; + double derate_fraction; + }; + std::vector defrostMap; + /**< A list of points for the defrost derate factor ordered by increasing external temperature + */ + + struct maxOut_minAir { + double outT_C; + double airT_C; + }; + maxOut_minAir maxOut_at_LowT; + /**< maximum output temperature at the minimum operating temperature of HPWH environment + * (minT)*/ + + struct SecondaryHeatExchanger { + double coldSideTemperatureOffest_dC; + double hotSideTemperatureOffset_dC; + double extraPumpPower_W; + }; + + SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary + heat exchanger by adding extra input energy for the pump and an increaes in the water to the + incoming waater temperature to the heatpump*/ + + void addTurnOnLogic(std::shared_ptr logic); + void addShutOffLogic(std::shared_ptr logic); + /**< these are two small functions to remove some of the cruft in initiation functions */ + void clearAllTurnOnLogic(); + void clearAllShutOffLogic(); + void clearAllLogic(); + /**< these are two small functions to remove some of the cruft in initiation functions */ + + void changeResistanceWatts(double watts); + /**< function to change the resistance wattage */ + + bool isACompressor() const; + /**< returns if the heat source uses a compressor or not */ + bool isAResistance() const; + /**< returns if the heat source uses a resistance element or not */ + bool isExternalMultipass() const; - // some private functions, mostly used for heating the water with the addHeat function + double minT; + /**< minimum operating temperature of HPWH environment */ - double addHeatAboveNode(double cap_kJ, int node); - /**< adds heat to the set of nodes that are at the same temperature, above the - specified node number */ - double addHeatExternal(double externalT_C, double minutesToRun, double &cap_BTUperHr, double &input_BTUperHr, double &cop); - /**< Add heat from a source outside of the tank. Assume the condensity is where - the water is drawn from and hot water is put at the top of the tank. */ + double maxT; + /**< maximum operating temperature of HPWH environment */ - /** I wrote some methods to help with the add heat interface - MJL */ - void getCapacity(double externalT_C, double condenserTemp_C, double setpointTemp_C, double &input_BTUperHr, double &cap_BTUperHr, double &cop); + double maxSetpoint_C; + /**< the maximum setpoint of the heat source can create, used for compressors predominately */ - /** An overloaded function that uses uses the setpoint temperature */ - void getCapacity(double externalT_C, double condenserTemp_C, double &input_BTUperHr, double &cap_BTUperHr, double &cop) { - getCapacity(externalT_C, condenserTemp_C, hpwh->getSetpoint(), input_BTUperHr, cap_BTUperHr, cop); - }; - /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ - void getCapacityMP(double externalT_C, double condenserTemp_C, double &input_BTUperHr, double &cap_BTUperHr, double &cop); + double hysteresis_dC; + /**< a hysteresis term that prevents short cycling due to heat pump self-interaction + when the heat source is engaged, it is subtracted from lowT cutoffs and + added to lowTreheat cutoffs */ + + bool depressesTemperature; + /**< heat pumps can depress the temperature of their space in certain instances - + whether or not this occurs is a bool in HPWH, but a heat source must + know if it is capable of contributing to this effect or not + NOTE: this only works for 1 minute steps + ALSO: this is set according the the heat source type, not user-specified */ - double calcMPOutletTemperature(double heatingCapacity_KW); - /**< returns the temperature of outlet of a external multipass hpwh */ + double airflowFreedom; + /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor + cop (not capacity) for cases where the air flow is restricted - typically ducting */ + + int externalInletHeight; /**getSetpoint(), input_BTUperHr, cap_BTUperHr, cop); + }; + /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ + void getCapacityMP(double externalT_C, + double condenserTemp_C, + double& input_BTUperHr, + double& cap_BTUperHr, + double& cop); - void calcHeatDist(std::vector &heatDistribution); + double calcMPOutletTemperature(double heatingCapacity_KW); + /**< returns the temperature of outlet of a external multipass hpwh */ - double getCondenserTemp() const; - /**< returns the temperature of the condensor - it's a weighted average of the - tank temperature, using the condensity as weights */ + void calcHeatDist(std::vector& heatDistribution); - void sortPerformanceMap(); - /**< sorts the Performance Map by increasing external temperatures */ + double getCondenserTemp() const; + /**< returns the temperature of the condensor - it's a weighted average of the + tank temperature, using the condensity as weights */ - /**< A few helper functions */ - double expitFunc(double x, double offset); - void normalize(std::vector &distribution); + void sortPerformanceMap(); + /**< sorts the Performance Map by increasing external temperatures */ -}; // end of HeatSource class + /**< A few helper functions */ + double expitFunc(double x, double offset); + void normalize(std::vector& distribution); +}; // end of HeatSource class // a few extra functions for unit converesion -inline double dF_TO_dC(double temperature) { return (temperature*5.0/9.0); } -inline double F_TO_C(double temperature) { return ((temperature - 32.0)*5.0/9.0); } -inline double C_TO_F(double temperature) { return (((9.0/5.0)*temperature) + 32.0); } +inline double dF_TO_dC(double temperature) { return (temperature * 5.0 / 9.0); } +inline double F_TO_C(double temperature) { return ((temperature - 32.0) * 5.0 / 9.0); } +inline double C_TO_F(double temperature) { return (((9.0 / 5.0) * temperature) + 32.0); } inline double KWH_TO_BTU(double kwh) { return (3412.14 * kwh); } inline double KWH_TO_KJ(double kwh) { return (kwh * 3600.0); } inline double BTU_TO_KWH(double btu) { return (btu / 3412.14); } inline double BTUperH_TO_KW(double btu) { return (btu / 3412.14); } inline double KW_TO_BTUperH(double kw) { return (kw * 3412.14); } inline double W_TO_BTUperH(double w) { return (w * 3.41214); } -inline double KJ_TO_KWH(double kj) { return (kj/3600.0); } +inline double KJ_TO_KWH(double kj) { return (kj / 3600.0); } inline double BTU_TO_KJ(double btu) { return (btu * 1.055); } inline double GAL_TO_L(double gallons) { return (gallons * 3.78541); } inline double L_TO_GAL(double liters) { return (liters / 3.78541); } @@ -1312,9 +1454,13 @@ inline double MIN_TO_HR(double minute) { return minute / 60.; } inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) { - return static_cast(static_cast(a) | static_cast(b)); + return static_cast(static_cast(a) | static_cast(b)); } -template< typename T> inline bool aboutEqual(T a, T b) { return fabs(a - b) < HPWH::TOL_MINVALUE; } +template +inline bool aboutEqual(T a, T b) +{ + return fabs(a - b) < HPWH::TOL_MINVALUE; +} #endif diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index 3bad1704..c3771bb4 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -5,234 +5,258 @@ File of the presets heating logics available HPWHsim #include "HPWH.hh" /* State of Charge Based Logic*/ -const bool HPWH::SoCBasedHeatingLogic::isValid() { - bool isValid = true; - if (decisionPoint < 0) { - isValid = false; - } - return isValid; +const bool HPWH::SoCBasedHeatingLogic::isValid() +{ + bool isValid = true; + if (decisionPoint < 0) { + isValid = false; + } + return isValid; } -const double HPWH::SoCBasedHeatingLogic::getComparisonValue() { - return decisionPoint + hysteresisFraction; +const double HPWH::SoCBasedHeatingLogic::getComparisonValue() +{ + return decisionPoint + hysteresisFraction; } -const double HPWH::SoCBasedHeatingLogic::getTankValue() { - double soCFraction; - if (parentHPWH->member_inletT_C == HPWH_ABORT && !useCostantMains) { - soCFraction = HPWH_ABORT; - } - else { - soCFraction = parentHPWH->getSoCFraction(); - } - return soCFraction; +const double HPWH::SoCBasedHeatingLogic::getTankValue() +{ + double soCFraction; + if (parentHPWH->member_inletT_C == HPWH_ABORT && !useCostantMains) { + soCFraction = HPWH_ABORT; + } + else { + soCFraction = parentHPWH->getSoCFraction(); + } + return soCFraction; } -const double HPWH::SoCBasedHeatingLogic::getMainsT_C() { - if (useCostantMains) { - return constantMains_C; - } - else { - return parentHPWH->member_inletT_C; - } +const double HPWH::SoCBasedHeatingLogic::getMainsT_C() +{ + if (useCostantMains) { + return constantMains_C; + } + else { + return parentHPWH->member_inletT_C; + } } -const double HPWH::SoCBasedHeatingLogic::getTempMinUseful_C() { - return tempMinUseful_C; -} - -int HPWH::SoCBasedHeatingLogic::setDecisionPoint(double value) { - decisionPoint = value; - return 0; -} +const double HPWH::SoCBasedHeatingLogic::getTempMinUseful_C() { return tempMinUseful_C; } -int HPWH::SoCBasedHeatingLogic::setConstantMainsTemperature(double mains_C) { - constantMains_C = mains_C; - useCostantMains = true; - return 0; +int HPWH::SoCBasedHeatingLogic::setDecisionPoint(double value) +{ + decisionPoint = value; + return 0; } -const double HPWH::SoCBasedHeatingLogic::nodeWeightAvgFract() { - return getComparisonValue(); +int HPWH::SoCBasedHeatingLogic::setConstantMainsTemperature(double mains_C) +{ + constantMains_C = mains_C; + useCostantMains = true; + return 0; } -const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() { - double deltaSoCFraction = (getComparisonValue() + HPWH::TOL_MINVALUE) - getTankValue(); - - // Check how much of a change in the SoC fraction occurs if one full node at set point is added. If this is less than the change needed move on. - double fullNodeSoC = 1. / parentHPWH->numNodes; - if (deltaSoCFraction >= fullNodeSoC) { - return 1.; - } - - // Find the last node greater the min use temp - int calcNode = 0; - for (int i = parentHPWH->numNodes - 1; i >= 0; i--) { - if (parentHPWH->tankTemps_C[i] < tempMinUseful_C) { - calcNode = i + 1; - break; - } - } - if (calcNode == parentHPWH->numNodes) { // if the whole tank is cold - return 1.; - } - - // Find the fraction to heat the calc node to meet the target SoC fraction without heating the node below up to tempMinUseful. - double maxSoC = parentHPWH->numNodes * parentHPWH->getChargePerNode(getMainsT_C(), tempMinUseful_C, parentHPWH->setpoint_C); - double targetTemp = deltaSoCFraction * maxSoC + (parentHPWH->tankTemps_C[calcNode] - getMainsT_C()) / (tempMinUseful_C - getMainsT_C()); - targetTemp = targetTemp * (tempMinUseful_C - getMainsT_C()) + getMainsT_C(); - - //Catch case where node temperature == setpoint - double fractCalcNode; - if (parentHPWH->tankTemps_C[calcNode] >= parentHPWH->setpoint_C) { - fractCalcNode = 1; - } - else { - fractCalcNode = (targetTemp - parentHPWH->tankTemps_C[calcNode]) / (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]); - } - - // If we're at the bottom node there's not another node to heat so case 2 doesn't apply. - if (calcNode == 0) { - return fractCalcNode; - } - - // Fraction to heat next node, where the step change occurs - double fractNextNode = (tempMinUseful_C - parentHPWH->tankTemps_C[calcNode - 1]) / (parentHPWH->tankTemps_C[calcNode] - parentHPWH->tankTemps_C[calcNode - 1]); - fractNextNode += HPWH::TOL_MINVALUE; - - if (parentHPWH->hpwhVerbosity >= VRB_emetic) { - double smallestSoCChangeWhenHeatingNextNode = 1. / maxSoC * (1. + fractNextNode * (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]) / - (tempMinUseful_C - getMainsT_C())); - parentHPWH->msg("fractThisNode %.6f, fractNextNode %.6f, smallestSoCChangeWithNextNode: %.6f, deltaSoCFraction: %.6f\n", - fractCalcNode, fractNextNode, smallestSoCChangeWhenHeatingNextNode, deltaSoCFraction); - } - - // if the fraction is enough to heat up the next node, do that minimum and handle the heating of the next node next iteration. - return std::min(fractCalcNode, fractNextNode); +const double HPWH::SoCBasedHeatingLogic::nodeWeightAvgFract() { return getComparisonValue(); } + +const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() +{ + double deltaSoCFraction = (getComparisonValue() + HPWH::TOL_MINVALUE) - getTankValue(); + + // Check how much of a change in the SoC fraction occurs if one full node at set point is added. + // If this is less than the change needed move on. + double fullNodeSoC = 1. / parentHPWH->numNodes; + if (deltaSoCFraction >= fullNodeSoC) { + return 1.; + } + + // Find the last node greater the min use temp + int calcNode = 0; + for (int i = parentHPWH->numNodes - 1; i >= 0; i--) { + if (parentHPWH->tankTemps_C[i] < tempMinUseful_C) { + calcNode = i + 1; + break; + } + } + if (calcNode == parentHPWH->numNodes) { // if the whole tank is cold + return 1.; + } + + // Find the fraction to heat the calc node to meet the target SoC fraction without heating the + // node below up to tempMinUseful. + double maxSoC = + parentHPWH->numNodes * + parentHPWH->getChargePerNode(getMainsT_C(), tempMinUseful_C, parentHPWH->setpoint_C); + double targetTemp = + deltaSoCFraction * maxSoC + + (parentHPWH->tankTemps_C[calcNode] - getMainsT_C()) / (tempMinUseful_C - getMainsT_C()); + targetTemp = targetTemp * (tempMinUseful_C - getMainsT_C()) + getMainsT_C(); + + // Catch case where node temperature == setpoint + double fractCalcNode; + if (parentHPWH->tankTemps_C[calcNode] >= parentHPWH->setpoint_C) { + fractCalcNode = 1; + } + else { + fractCalcNode = (targetTemp - parentHPWH->tankTemps_C[calcNode]) / + (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]); + } + + // If we're at the bottom node there's not another node to heat so case 2 doesn't apply. + if (calcNode == 0) { + return fractCalcNode; + } + + // Fraction to heat next node, where the step change occurs + double fractNextNode = + (tempMinUseful_C - parentHPWH->tankTemps_C[calcNode - 1]) / + (parentHPWH->tankTemps_C[calcNode] - parentHPWH->tankTemps_C[calcNode - 1]); + fractNextNode += HPWH::TOL_MINVALUE; + + if (parentHPWH->hpwhVerbosity >= VRB_emetic) { + double smallestSoCChangeWhenHeatingNextNode = + 1. / maxSoC * + (1. + fractNextNode * (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]) / + (tempMinUseful_C - getMainsT_C())); + parentHPWH->msg("fractThisNode %.6f, fractNextNode %.6f, smallestSoCChangeWithNextNode: " + "%.6f, deltaSoCFraction: %.6f\n", + fractCalcNode, + fractNextNode, + smallestSoCChangeWhenHeatingNextNode, + deltaSoCFraction); + } + + // if the fraction is enough to heat up the next node, do that minimum and handle the heating of + // the next node next iteration. + return std::min(fractCalcNode, fractNextNode); } - /* Temperature Based Heating Logic*/ -const bool HPWH::TempBasedHeatingLogic::isValid() { - bool isValid = true; - if (!areNodeWeightsValid()) { - isValid = false; - } - return isValid; +const bool HPWH::TempBasedHeatingLogic::isValid() +{ + bool isValid = true; + if (!areNodeWeightsValid()) { + isValid = false; + } + return isValid; } -const bool HPWH::TempBasedHeatingLogic::areNodeWeightsValid() { - for (auto nodeWeight : nodeWeights) { - if (nodeWeight.nodeNum > 13 || nodeWeight.nodeNum < 0) { - return false; - } - } - return true; +const bool HPWH::TempBasedHeatingLogic::areNodeWeightsValid() +{ + for (auto nodeWeight : nodeWeights) { + if (nodeWeight.nodeNum > 13 || nodeWeight.nodeNum < 0) { + return false; + } + } + return true; } -const double HPWH::TempBasedHeatingLogic::getComparisonValue() { - double value = decisionPoint; - if (isAbsolute) { - return value; - } - else { - return parentHPWH->getSetpoint() - value; - } +const double HPWH::TempBasedHeatingLogic::getComparisonValue() +{ + double value = decisionPoint; + if (isAbsolute) { + return value; + } + else { + return parentHPWH->getSetpoint() - value; + } } -const double HPWH::TempBasedHeatingLogic::getTankValue() { - return parentHPWH->tankAvg_C(nodeWeights); +const double HPWH::TempBasedHeatingLogic::getTankValue() +{ + return parentHPWH->tankAvg_C(nodeWeights); } -int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value) { - decisionPoint = value; - return 0; +int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value) +{ + decisionPoint = value; + return 0; } -int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value, bool absolute) { - isAbsolute = absolute; - return setDecisionPoint(value); +int HPWH::TempBasedHeatingLogic::setDecisionPoint(double value, bool absolute) +{ + isAbsolute = absolute; + return setDecisionPoint(value); } -const double HPWH::TempBasedHeatingLogic::nodeWeightAvgFract() { - double logicNode; - double calcNodes = 0, totWeight = 0; - - for (auto nodeWeight : nodeWeights) { - // bottom calc node only - if (nodeWeight.nodeNum == 0) { // simple equation - return 1. / (double)parentHPWH->getNumNodes(); - } - // top calc node only - else if (nodeWeight.nodeNum == 13) { - return 1.; - } - else { // have to tally up the nodes - calcNodes += nodeWeight.nodeNum * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - } - - logicNode = calcNodes / totWeight; - - return logicNode / (double)CONDENSITY_SIZE; +const double HPWH::TempBasedHeatingLogic::nodeWeightAvgFract() +{ + double logicNode; + double calcNodes = 0, totWeight = 0; + + for (auto nodeWeight : nodeWeights) { + // bottom calc node only + if (nodeWeight.nodeNum == 0) { // simple equation + return 1. / (double)parentHPWH->getNumNodes(); + } + // top calc node only + else if (nodeWeight.nodeNum == 13) { + return 1.; + } + else { // have to tally up the nodes + calcNodes += nodeWeight.nodeNum * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + } + + logicNode = calcNodes / totWeight; + + return logicNode / (double)CONDENSITY_SIZE; } -const double HPWH::TempBasedHeatingLogic::getFractToMeetComparisonExternal() { - double fracTemp, diff; - int calcNode = 0; - int firstNode = -1; - double sum = 0; - double totWeight = 0; - - double comparison = getComparisonValue(); - comparison += HPWH::TOL_MINVALUE; // Make this possible so we do slightly over heat - - for (auto nodeWeight : nodeWeights) { - - // bottom calc node only - if (nodeWeight.nodeNum == 0) { // simple equation - calcNode = 0; - firstNode = 0; - sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; - totWeight = nodeWeight.weight; - } - // top calc node only - else if (nodeWeight.nodeNum == 13) { - calcNode = parentHPWH->getNumNodes() - 1; - firstNode = parentHPWH->getNumNodes() - 1; - sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; - totWeight = nodeWeight.weight; - } - else { // have to tally up the nodes - // frac = ( nodesN*comparision - ( Sum Ti from i = 0 to N ) ) / ( TN+1 - T0 ) - firstNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity; - for (int n = 0; n < parentHPWH->nodeDensity; ++n) { // Loop on the nodes in the logics - calcNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity + n; - sum += parentHPWH->tankTemps_C[calcNode] * nodeWeight.weight; - totWeight += nodeWeight.weight; - } - } - } - - if (calcNode == parentHPWH->numNodes - 1) { // top node calc - diff = parentHPWH->getSetpoint() - parentHPWH->tankTemps_C[firstNode]; - } - else { - diff = parentHPWH->tankTemps_C[calcNode + 1] - parentHPWH->tankTemps_C[firstNode]; - } - // if totWeight * comparison - sum < 0 then the shutoff condition is already true and you shouldn't - // be here. Will revaluate shut off condition at the end the do while loop of addHeatExternal, in the - // mean time lets not shift anything around. - if (compare(sum, totWeight * comparison)) { // Then should shut off - fracTemp = 0.; // 0 means shift no nodes - } - else { - // if the difference in denominator is <= 0 then we aren't adding heat to the nodes we care about, so - // shift a whole node. - fracTemp = diff > 0. ? (totWeight * comparison - sum) / diff : 1.; - } - - return fracTemp; +const double HPWH::TempBasedHeatingLogic::getFractToMeetComparisonExternal() +{ + double fracTemp, diff; + int calcNode = 0; + int firstNode = -1; + double sum = 0; + double totWeight = 0; + + double comparison = getComparisonValue(); + comparison += HPWH::TOL_MINVALUE; // Make this possible so we do slightly over heat + + for (auto nodeWeight : nodeWeights) { + + // bottom calc node only + if (nodeWeight.nodeNum == 0) { // simple equation + calcNode = 0; + firstNode = 0; + sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; + totWeight = nodeWeight.weight; + } + // top calc node only + else if (nodeWeight.nodeNum == 13) { + calcNode = parentHPWH->getNumNodes() - 1; + firstNode = parentHPWH->getNumNodes() - 1; + sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; + totWeight = nodeWeight.weight; + } + else { // have to tally up the nodes + // frac = ( nodesN*comparision - ( Sum Ti from i = 0 to N ) ) / ( TN+1 - T0 ) + firstNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity; + for (int n = 0; n < parentHPWH->nodeDensity; ++n) { // Loop on the nodes in the logics + calcNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity + n; + sum += parentHPWH->tankTemps_C[calcNode] * nodeWeight.weight; + totWeight += nodeWeight.weight; + } + } + } + + if (calcNode == parentHPWH->numNodes - 1) { // top node calc + diff = parentHPWH->getSetpoint() - parentHPWH->tankTemps_C[firstNode]; + } + else { + diff = parentHPWH->tankTemps_C[calcNode + 1] - parentHPWH->tankTemps_C[firstNode]; + } + // if totWeight * comparison - sum < 0 then the shutoff condition is already true and you + // shouldn't be here. Will revaluate shut off condition at the end the do while loop of + // addHeatExternal, in the mean time lets not shift anything around. + if (compare(sum, totWeight * comparison)) { // Then should shut off + fracTemp = 0.; // 0 means shift no nodes + } + else { + // if the difference in denominator is <= 0 then we aren't adding heat to the nodes we care + // about, so shift a whole node. + fracTemp = diff > 0. ? (totWeight * comparison - sum) / diff : 1.; + } + + return fracTemp; } - - diff --git a/src/HPWHpresets.cc b/src/HPWHpresets.cc index 2714410d..f6eab77d 100644 --- a/src/HPWHpresets.cc +++ b/src/HPWHpresets.cc @@ -7,4031 +7,4507 @@ File Containing all of the presets available in HPWHsim #include -int HPWH::HPWHinit_resTank() { - //a default resistance tank, nominal 50 gallons, 0.95 EF, standard double 4.5 kW elements - return this->HPWHinit_resTank(GAL_TO_L(47.5), 0.95, 4500, 4500); +int HPWH::HPWHinit_resTank() +{ + // a default resistance tank, nominal 50 gallons, 0.95 EF, standard double 4.5 kW elements + return this->HPWHinit_resTank(GAL_TO_L(47.5), 0.95, 4500, 4500); } -int HPWH::HPWHinit_resTank(double tankVol_L, double energyFactor, double upperPower_W, double lowerPower_W) { - - setAllDefaults(); // reset all defaults if you're re-initilizing - // sets simHasFailed = true; this gets cleared on successful completion of init - // return 0 on success, HPWH_ABORT for failure - - //low power element will cause divide by zero/negative UA in EF -> UA conversion - if (lowerPower_W < 550) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Resistance tank lower element wattage below 550 W. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - if (energyFactor <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Energy Factor less than zero. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - - //use tank size setting function since it has bounds checking - tankSizeFixed = false; - int failure = this->setTankSize(tankVol_L); - if (failure == HPWH_ABORT) { - return failure; - } - - - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - //start tank off at setpoint - resetTankToSetpoint(); - - nextTankTemps_C = new double[numNodes]; - doTempDepression = false; - tankMixesOnDraw = true; - - - HeatSource resistiveElementBottom(this); - resistiveElementBottom.setupAsResistiveElement(0, lowerPower_W); - - //standard logic conditions - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - - if (upperPower_W > 0.) { - // Only add an upper element when the upperPower_W > 0 otherwise ignore this. - // If the element is added this can mess with the intended logic. - HeatSource resistiveElementTop(this); - resistiveElementTop.setupAsResistiveElement(8, upperPower_W); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.isVIP = true; - - numHeatSources = 2; - setOfSources = new HeatSource[numHeatSources]; - - // set everything in it's correct place - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - } - else { - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - setOfSources[0] = resistiveElementBottom; - } - - // (1/EnFac - 1/RecovEff) / (67.5 * ((24/41094) - 1/(RecovEff * Power_btuperHr))) - // Previous comment and the equation source said (1/EnFac + 1/RecovEff) however this was - // determined to be a typo from the source that was kept in the comment. On 8/12/2021 - // the comment was changed to reflect the correct mathematical formulation which is performed - // below. - double recoveryEfficiency = 0.98; - double numerator = (1.0 / energyFactor) - (1.0 / recoveryEfficiency); - double temp = 1.0 / (recoveryEfficiency * lowerPower_W*3.41443); - double denominator = 67.5 * ((24.0 / 41094.0) - temp); - tankUA_kJperHrC = UAf_TO_UAc(numerator / denominator); - - if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { - msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); - } - tankUA_kJperHrC = 0.0; - } - - hpwhModel = MODELS_CustomResTank; - - //calculate oft-used derived values - calcDerivedValues(); - - if (checkInputs() == HPWH_ABORT) return HPWH_ABORT; - - isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { - isHeating = true; - } - setOfSources[i].sortPerformanceMap(); - } - - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { - msg("heat source %d: %p \n", i, &setOfSources[i]); - } - msg("\n\n"); - } - - simHasFailed = false; - return 0; //successful init returns 0 +int HPWH::HPWHinit_resTank(double tankVol_L, + double energyFactor, + double upperPower_W, + double lowerPower_W) +{ + + setAllDefaults(); // reset all defaults if you're re-initilizing + // sets simHasFailed = true; this gets cleared on successful completion of init + // return 0 on success, HPWH_ABORT for failure + + // low power element will cause divide by zero/negative UA in EF -> UA conversion + if (lowerPower_W < 550) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Resistance tank lower element wattage below 550 W. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + if (upperPower_W < 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + if (energyFactor <= 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Energy Factor less than zero. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + + // use tank size setting function since it has bounds checking + tankSizeFixed = false; + int failure = this->setTankSize(tankVol_L); + if (failure == HPWH_ABORT) { + return failure; + } + + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + // start tank off at setpoint + resetTankToSetpoint(); + + nextTankTemps_C = new double[numNodes]; + doTempDepression = false; + tankMixesOnDraw = true; + + HeatSource resistiveElementBottom(this); + resistiveElementBottom.setupAsResistiveElement(0, lowerPower_W); + + // standard logic conditions + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); + + if (upperPower_W > 0.) { + // Only add an upper element when the upperPower_W > 0 otherwise ignore this. + // If the element is added this can mess with the intended logic. + HeatSource resistiveElementTop(this); + resistiveElementTop.setupAsResistiveElement(8, upperPower_W); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.isVIP = true; + + numHeatSources = 2; + setOfSources = new HeatSource[numHeatSources]; + + // set everything in it's correct place + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + } + else { + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + setOfSources[0] = resistiveElementBottom; + } + + // (1/EnFac - 1/RecovEff) / (67.5 * ((24/41094) - 1/(RecovEff * Power_btuperHr))) + // Previous comment and the equation source said (1/EnFac + 1/RecovEff) however this was + // determined to be a typo from the source that was kept in the comment. On 8/12/2021 + // the comment was changed to reflect the correct mathematical formulation which is performed + // below. + double recoveryEfficiency = 0.98; + double numerator = (1.0 / energyFactor) - (1.0 / recoveryEfficiency); + double temp = 1.0 / (recoveryEfficiency * lowerPower_W * 3.41443); + double denominator = 67.5 * ((24.0 / 41094.0) - temp); + tankUA_kJperHrC = UAf_TO_UAc(numerator / denominator); + + if (tankUA_kJperHrC < 0.) { + if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { + msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); + } + tankUA_kJperHrC = 0.0; + } + + hpwhModel = MODELS_CustomResTank; + + // calculate oft-used derived values + calcDerivedValues(); + + if (checkInputs() == HPWH_ABORT) + return HPWH_ABORT; + + isHeating = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isOn) { + isHeating = true; + } + setOfSources[i].sortPerformanceMap(); + } + + if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) { + msg("heat source %d: %p \n", i, &setOfSources[i]); + } + msg("\n\n"); + } + + simHasFailed = false; + return 0; // successful init returns 0 } - -int HPWH::HPWHinit_resTankGeneric(double tankVol_L, double rValue_M2KperW, double upperPower_W, double lowerPower_W) { - - setAllDefaults(); // reset all defaults if you're re-initilizing - // sets simHasFailed = true; this gets cleared on successful completion of init - // return 0 on success, HPWH_ABORT for failure - - //low power element will cause divide by zero/negative UA in EF -> UA conversion - if (lowerPower_W < 0) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Lower resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - if (rValue_M2KperW <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("R-Value is equal to or below 0. DOES NOT COMPUTE\n"); - } - return HPWH_ABORT; - } - - //set tank size function has bounds checking - tankSizeFixed = false; - if (this->setTankSize(tankVol_L) == HPWH_ABORT) { - return HPWH_ABORT; - } - canScale = true; - - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - resetTankToSetpoint(); //start tank off at setpoint - - nextTankTemps_C = new double[numNodes]; - doTempDepression = false; - tankMixesOnDraw = true; - - // Count up heat sources - numHeatSources = 0; - numHeatSources += upperPower_W > 0. ? 1 : 0; - numHeatSources += lowerPower_W > 0. ? 1 : 0; - setOfSources = new HeatSource[numHeatSources]; - - // Deal with upper element - if (upperPower_W > 0.) { - // Only add an upper element when the upperPower_W > 0 otherwise ignore this. - // If the element is added this can mess with the intended logic. - HeatSource resistiveElementTop(this); - resistiveElementTop.setupAsResistiveElement(8, upperPower_W); - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.isVIP = true; - - // Upper should always be first in setOfSources if it exists. - setOfSources[0] = resistiveElementTop; - } - - // Deal with bottom element - if (lowerPower_W > 0.) { - HeatSource resistiveElementBottom(this); - resistiveElementBottom.setupAsResistiveElement(0, lowerPower_W); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40.))); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10.))); - - // set everything in it's correct place - if (numHeatSources == 1) {// if one only one slot - setOfSources[0] = resistiveElementBottom; - } - else if (numHeatSources == 2) { // if two upper already exists - setOfSources[1] = resistiveElementBottom; - setOfSources[0].followedByHeatSource = &setOfSources[1]; - } - } - - // Calc UA - double SA_M2 = getTankSurfaceArea(tankVol_L, HPWH::UNITS_L, HPWH::UNITS_M2); - double tankUA_WperK = SA_M2 / rValue_M2KperW; - tankUA_kJperHrC = tankUA_WperK * 3.6; // 3.6 = 3600 S/Hr and 1/1000 kJ/J - - if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { - msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); - } - tankUA_kJperHrC = 0.0; - } - - hpwhModel = HPWH::MODELS_CustomResTankGeneric; - - //calculate oft-used derived values - calcDerivedValues(); - - if (checkInputs() == HPWH_ABORT) return HPWH_ABORT; - - isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { - isHeating = true; - } - setOfSources[i].sortPerformanceMap(); - } - - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { - msg("heat source %d: %p \n", i, &setOfSources[i]); - } - msg("\n\n"); - } - - simHasFailed = false; - return 0; //successful init returns 0 +int HPWH::HPWHinit_resTankGeneric(double tankVol_L, + double rValue_M2KperW, + double upperPower_W, + double lowerPower_W) +{ + + setAllDefaults(); // reset all defaults if you're re-initilizing + // sets simHasFailed = true; this gets cleared on successful completion of init + // return 0 on success, HPWH_ABORT for failure + + // low power element will cause divide by zero/negative UA in EF -> UA conversion + if (lowerPower_W < 0) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Lower resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + if (upperPower_W < 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + if (rValue_M2KperW <= 0.) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("R-Value is equal to or below 0. DOES NOT COMPUTE\n"); + } + return HPWH_ABORT; + } + + // set tank size function has bounds checking + tankSizeFixed = false; + if (this->setTankSize(tankVol_L) == HPWH_ABORT) { + return HPWH_ABORT; + } + canScale = true; + + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + resetTankToSetpoint(); // start tank off at setpoint + + nextTankTemps_C = new double[numNodes]; + doTempDepression = false; + tankMixesOnDraw = true; + + // Count up heat sources + numHeatSources = 0; + numHeatSources += upperPower_W > 0. ? 1 : 0; + numHeatSources += lowerPower_W > 0. ? 1 : 0; + setOfSources = new HeatSource[numHeatSources]; + + // Deal with upper element + if (upperPower_W > 0.) { + // Only add an upper element when the upperPower_W > 0 otherwise ignore this. + // If the element is added this can mess with the intended logic. + HeatSource resistiveElementTop(this); + resistiveElementTop.setupAsResistiveElement(8, upperPower_W); + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.isVIP = true; + + // Upper should always be first in setOfSources if it exists. + setOfSources[0] = resistiveElementTop; + } + + // Deal with bottom element + if (lowerPower_W > 0.) { + HeatSource resistiveElementBottom(this); + resistiveElementBottom.setupAsResistiveElement(0, lowerPower_W); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40.))); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10.))); + + // set everything in it's correct place + if (numHeatSources == 1) { // if one only one slot + setOfSources[0] = resistiveElementBottom; + } + else if (numHeatSources == 2) { // if two upper already exists + setOfSources[1] = resistiveElementBottom; + setOfSources[0].followedByHeatSource = &setOfSources[1]; + } + } + + // Calc UA + double SA_M2 = getTankSurfaceArea(tankVol_L, HPWH::UNITS_L, HPWH::UNITS_M2); + double tankUA_WperK = SA_M2 / rValue_M2KperW; + tankUA_kJperHrC = tankUA_WperK * 3.6; // 3.6 = 3600 S/Hr and 1/1000 kJ/J + + if (tankUA_kJperHrC < 0.) { + if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { + msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); + } + tankUA_kJperHrC = 0.0; + } + + hpwhModel = HPWH::MODELS_CustomResTankGeneric; + + // calculate oft-used derived values + calcDerivedValues(); + + if (checkInputs() == HPWH_ABORT) + return HPWH_ABORT; + + isHeating = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isOn) { + isHeating = true; + } + setOfSources[i].sortPerformanceMap(); + } + + if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) { + msg("heat source %d: %p \n", i, &setOfSources[i]); + } + msg("\n\n"); + } + + simHasFailed = false; + return 0; // successful init returns 0 } -int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C) { - - setAllDefaults(); // reset all defaults if you're re-initilizing - // sets simHasFailed = true; this gets cleared on successful completion of init - // return 0 on success, HPWH_ABORT for failure - - //except where noted, these values are taken from MODELS_GE2014STDMode on 5/17/16 - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - nextTankTemps_C = new double[numNodes]; - - //start tank off at setpoint - resetTankToSetpoint(); - - tankSizeFixed = false; - - //custom settings - these are set later - //tankVolume_L = GAL_TO_L(45); - //tankUA_kJperHrC = 6.5; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); +int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C) +{ - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); + setAllDefaults(); // reset all defaults if you're re-initilizing + // sets simHasFailed = true; this gets cleared on successful completion of init + // return 0 on success, HPWH_ABORT for failure - compressor.minT = F_TO_C(45.); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; + // except where noted, these values are taken from MODELS_GE2014STDMode on 5/17/16 + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; + nextTankTemps_C = new double[numNodes]; - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + // start tank off at setpoint + resetTankToSetpoint(); - //logic conditions - //this is set customly, from input - //resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); - resistiveElementTop.addTurnOnLogic(HPWH::topThird(resUse_C)); + tankSizeFixed = false; - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); + // custom settings - these are set later + // tankVolume_L = GAL_TO_L(45); + // tankUA_kJperHrC = 6.5; - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); + doTempDepression = false; + tankMixesOnDraw = true; - //custom adjustment for poorer performance - //compressor.addShutOffLogic(HPWH::lowT(F_TO_C(37))); + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); - //end section of parameters from GE model + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.perfMap.reserve(2); + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); - //set tank volume from input - //use tank size setting function since it has bounds checking - int failure = this->setTankSize(tankVol_L); - if (failure == HPWH_ABORT) { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Failure to set tank size in generic hpwh init."); - } - return failure; - } + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + compressor.minT = F_TO_C(45.); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; - // derive conservative (high) UA from tank volume - // curve fit by Jim Lutz, 5-25-2016 - double tankVol_gal = tankVol_L / GAL_TO_L(1.); - double v1 = 7.5156316175 * pow(tankVol_gal, 0.33) + 5.9995357658; - tankUA_kJperHrC = 0.0076183819 * v1 * v1; + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + // logic conditions + // this is set customly, from input + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); + resistiveElementTop.addTurnOnLogic(HPWH::topThird(resUse_C)); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); - //do a linear interpolation to scale COP curve constant, using measured values - // Chip's attempt 24-May-2014 - double uefSpan = 3.4 - 2.0; + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); - //force COP to be 70% of GE at UEF 2 and 95% at UEF 3.4 - //use a fudge factor to scale cop and input power in tandem to maintain constant capacity - double fUEF = (energyFactor - 2.0) / uefSpan; - double genericFudge = (1. - fUEF)*.7 + fUEF * .95; + // custom adjustment for poorer performance + // compressor.addShutOffLogic(HPWH::lowT(F_TO_C(37))); - compressor.perfMap[0].COP_coeffs[0] *= genericFudge; - compressor.perfMap[0].COP_coeffs[1] *= genericFudge; - compressor.perfMap[0].COP_coeffs[2] *= genericFudge; + // end section of parameters from GE model - compressor.perfMap[1].COP_coeffs[0] *= genericFudge; - compressor.perfMap[1].COP_coeffs[1] *= genericFudge; - compressor.perfMap[1].COP_coeffs[2] *= genericFudge; + // set tank volume from input + // use tank size setting function since it has bounds checking + int failure = this->setTankSize(tankVol_L); + if (failure == HPWH_ABORT) { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Failure to set tank size in generic hpwh init."); + } + return failure; + } - compressor.perfMap[0].inputPower_coeffs[0] /= genericFudge; - compressor.perfMap[0].inputPower_coeffs[1] /= genericFudge; - compressor.perfMap[0].inputPower_coeffs[2] /= genericFudge; + // derive conservative (high) UA from tank volume + // curve fit by Jim Lutz, 5-25-2016 + double tankVol_gal = tankVol_L / GAL_TO_L(1.); + double v1 = 7.5156316175 * pow(tankVol_gal, 0.33) + 5.9995357658; + tankUA_kJperHrC = 0.0076183819 * v1 * v1; + + // do a linear interpolation to scale COP curve constant, using measured values + // Chip's attempt 24-May-2014 + double uefSpan = 3.4 - 2.0; + + // force COP to be 70% of GE at UEF 2 and 95% at UEF 3.4 + // use a fudge factor to scale cop and input power in tandem to maintain constant capacity + double fUEF = (energyFactor - 2.0) / uefSpan; + double genericFudge = (1. - fUEF) * .7 + fUEF * .95; - compressor.perfMap[1].inputPower_coeffs[0] /= genericFudge; - compressor.perfMap[1].inputPower_coeffs[1] /= genericFudge; - compressor.perfMap[1].inputPower_coeffs[2] /= genericFudge; + compressor.perfMap[0].COP_coeffs[0] *= genericFudge; + compressor.perfMap[0].COP_coeffs[1] *= genericFudge; + compressor.perfMap[0].COP_coeffs[2] *= genericFudge; - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - - - //standard finishing up init, borrowed from init function - - hpwhModel = MODELS_genericCustomUEF; - - //calculate oft-used derived values - calcDerivedValues(); - - if (checkInputs() == HPWH_ABORT) { - return HPWH_ABORT; - } - - isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { - isHeating = true; - } - setOfSources[i].sortPerformanceMap(); - } - - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { - msg("heat source %d: %p \n", i, &setOfSources[i]); - } - msg("\n\n"); - } - - simHasFailed = false; - - return 0; + compressor.perfMap[1].COP_coeffs[0] *= genericFudge; + compressor.perfMap[1].COP_coeffs[1] *= genericFudge; + compressor.perfMap[1].COP_coeffs[2] *= genericFudge; + + compressor.perfMap[0].inputPower_coeffs[0] /= genericFudge; + compressor.perfMap[0].inputPower_coeffs[1] /= genericFudge; + compressor.perfMap[0].inputPower_coeffs[2] /= genericFudge; + + compressor.perfMap[1].inputPower_coeffs[0] /= genericFudge; + compressor.perfMap[1].inputPower_coeffs[1] /= genericFudge; + compressor.perfMap[1].inputPower_coeffs[2] /= genericFudge; + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + // standard finishing up init, borrowed from init function + + hpwhModel = MODELS_genericCustomUEF; + + // calculate oft-used derived values + calcDerivedValues(); + + if (checkInputs() == HPWH_ABORT) { + return HPWH_ABORT; + } + + isHeating = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isOn) { + isHeating = true; + } + setOfSources[i].sortPerformanceMap(); + } + + if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) { + msg("heat source %d: %p \n", i, &setOfSources[i]); + } + msg("\n\n"); + } + + simHasFailed = false; + + return 0; } +int HPWH::HPWHinit_presets(MODELS presetNum) +{ -int HPWH::HPWHinit_presets(MODELS presetNum) { - - setAllDefaults(); // reset all defaults if you're re-initilizing - // sets simHasFailed = true; this gets cleared on successful completion of init - // return 0 on success, HPWH_ABORT for failure - - //resistive with no UA losses for testing - if (presetNum == MODELS_restankNoUA) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankSizeFixed = false; - tankVolume_L = GAL_TO_L(50); - tankUA_kJperHrC = 0; //0 to turn off - - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 2; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementTop.setupAsResistiveElement(8, 4500); - - //standard logic conditions - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.isVIP = true; - - //assign heat sources into array in order of priority - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - } - - //resistive tank with massive UA loss for testing - else if (presetNum == MODELS_restankHugeUA) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = 50; - - tankSizeFixed = false; - tankVolume_L = 120; - tankUA_kJperHrC = 500; //0 to turn off - - doTempDepression = false; - tankMixesOnDraw = false; - - - numHeatSources = 2; - setOfSources = new HeatSource[numHeatSources]; - - //set up a resistive element at the bottom, 4500 kW - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementTop.setupAsResistiveElement(9, 4500); - - //standard logic conditions - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); - resistiveElementTop.isVIP = true; - - - //assign heat sources into array in order of priority - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - - } - - //realistic resistive tank - else if (presetNum == MODELS_restankRealistic) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankSizeFixed = false; - tankVolume_L = GAL_TO_L(50); - tankUA_kJperHrC = 10; //0 to turn off - - doTempDepression = false; - //should eventually put tankmixes to true when testing progresses - tankMixesOnDraw = false; - - numHeatSources = 2; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementTop.setupAsResistiveElement(9, 4500); - - //standard logic conditions - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); - resistiveElementTop.isVIP = true; - - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - } - - else if (presetNum == MODELS_StorageTank) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = 52; - - setpoint_C = 800; - - tankSizeFixed = false; - tankVolume_L = GAL_TO_L(80); - tankUA_kJperHrC = 10; //0 to turn off - - doTempDepression = false; - tankMixesOnDraw = false; - - //////////////////////////////////////////////////// - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource extra(this); - - //compressor values - extra.isOn = false; - extra.isVIP = false; - extra.typeOfHeatSource = TYPE_extra; - extra.configuration = HeatSource::CONFIG_WRAPPED; - - extra.addTurnOnLogic(HPWH::topThird_absolute(1)); - - //initial guess, will get reset based on the input heat vector - extra.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - setOfSources[0] = extra; - } - - //basic compressor tank for testing - else if (presetNum == MODELS_basicIntegrated) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = 50; - - tankSizeFixed = false; - tankVolume_L = 120; - tankUA_kJperHrC = 10; //0 to turn off - //tankUA_kJperHrC = 0; //0 to turn off - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - HeatSource compressor(this); - - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementTop.setupAsResistiveElement(9, 4500); - - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); - - //standard logic conditions - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); - resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); - resistiveElementTop.isVIP = true; - - - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double oneSixth = 1.0 / 6.0; - compressor.setCondensity(oneSixth, oneSixth, oneSixth, oneSixth, oneSixth, oneSixth, 0, 0, 0, 0, 0, 0); - - //GE tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {0.290 * 1000, 0.00159 * 1000, 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.49, -0.0187, -0.0000133} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {0.375 * 1000, 0.00121 * 1000, 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {5.60, -0.0252, 0.00000254} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = 0; - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(4); - compressor.configuration = HeatSource::CONFIG_WRAPPED; //wrapped around tank - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.addTurnOnLogic(HPWH::bottomThird(20)); - compressor.addTurnOnLogic(HPWH::standby(15)); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = compressor; - setOfSources[2] = resistiveElementBottom; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - - //simple external style for testing - else if (presetNum == MODELS_externalTest) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = 50; - - tankSizeFixed = false; - tankVolume_L = 120; - //tankUA_kJperHrC = 10; //0 to turn off - tankUA_kJperHrC = 0; //0 to turn off - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - //GE tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {0.290 * 1000, 0.00159 * 1000, 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.49, -0.0187, -0.0000133} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {0.375 * 1000, 0.00121 * 1000, 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {5.60, -0.0252, 0.00000254} // COP Coefficients (COP_coeffs) - }); - - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = 0; //no hysteresis - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.addTurnOnLogic(HPWH::bottomThird(20)); - compressor.addTurnOnLogic(HPWH::standby(15)); - - //lowT cutoff - compressor.addShutOffLogic(HPWH::bottomNodeMaxTemp(20, true)); - - - //set everything in its places - setOfSources[0] = compressor; - } - //voltex 60 gallon - else if (presetNum == MODELS_AOSmithPHPT60) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = 215.8; - tankUA_kJperHrC = 7.31; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 5.0; - compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {0.467 * 1000, 0.00281 * 1000, 0.0000072 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.86, -0.0222, -0.00001} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {0.541 * 1000, 0.00147 * 1000, 0.0000176 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {6.58, -0.0392, 0.0000407} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(45.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(4); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4250); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 2000); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); - - //logic conditions - double compStart = dF_TO_dC(43.6); - double standbyT = dF_TO_dC(23.8); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(25.0))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = compressor; - setOfSources[2] = resistiveElementBottom; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; + setAllDefaults(); // reset all defaults if you're re-initilizing + // sets simHasFailed = true; this gets cleared on successful completion of init + // return 0 on success, HPWH_ABORT for failure - } - else if (presetNum == MODELS_AOSmithPHPT80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); + // resistive with no UA losses for testing + if (presetNum == MODELS_restankNoUA) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); - tankVolume_L = 283.9; - tankUA_kJperHrC = 8.8; + tankSizeFixed = false; + tankVolume_L = GAL_TO_L(50); + tankUA_kJperHrC = 0; // 0 to turn off - doTempDepression = false; - tankMixesOnDraw = true; + doTempDepression = false; + tankMixesOnDraw = true; - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; + numHeatSources = 2; + setOfSources = new HeatSource[numHeatSources]; - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementTop.setupAsResistiveElement(8, 4500); - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; + // standard logic conditions + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - double split = 1.0 / 5.0; - compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.isVIP = true; - //voltex60 tier 1 values - compressor.perfMap.reserve(2); + // assign heat sources into array in order of priority + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {0.467 * 1000, 0.00281 * 1000, 0.0000072 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.86, -0.0222, -0.00001} // COP Coefficients (COP_coeffs) - }); + setOfSources[0].followedByHeatSource = &setOfSources[1]; + } - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {0.541 * 1000, 0.00147 * 1000, 0.0000176 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {6.58, -0.0392, 0.0000407} // COP Coefficients (COP_coeffs) - }); + // resistive tank with massive UA loss for testing + else if (presetNum == MODELS_restankHugeUA) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = 50; - compressor.minT = F_TO_C(45.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(4); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4250); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 2000); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + tankSizeFixed = false; + tankVolume_L = 120; + tankUA_kJperHrC = 500; // 0 to turn off + doTempDepression = false; + tankMixesOnDraw = false; - //logic conditions - double compStart = dF_TO_dC(43.6); - double standbyT = dF_TO_dC(23.8); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); + numHeatSources = 2; + setOfSources = new HeatSource[numHeatSources]; - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); + // set up a resistive element at the bottom, 4500 kW + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(25.0))); + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementTop.setupAsResistiveElement(9, 4500); + // standard logic conditions + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = compressor; - setOfSources[2] = resistiveElementBottom; + resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); + resistiveElementTop.isVIP = true; - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; + // assign heat sources into array in order of priority + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; + setOfSources[0].followedByHeatSource = &setOfSources[1]; + } - } - else if (presetNum == MODELS_GE2012) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); + // realistic resistive tank + else if (presetNum == MODELS_restankRealistic) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); - tankVolume_L = 172; - tankUA_kJperHrC = 6.8; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 5.0; - compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {0.3 * 1000, 0.00159 * 1000, 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.7, -0.0210, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {0.378 * 1000, 0.00121 * 1000, 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) - {4.8, -0.0167, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(45.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(4); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4200); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4200); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); - - - //logic conditions - // double compStart = dF_TO_dC(24.4); - double compStart = dF_TO_dC(40.0); - double standbyT = dF_TO_dC(5.2); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(66))); - compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); - //resistiveElementBottom.addShutOffLogic(HPWH::lowTreheat(lowTcutoff)); - //GE element never turns off? - - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(31.0))); - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(28.0))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = compressor; - setOfSources[2] = resistiveElementBottom; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - // If a Colmac single pass preset cold weather or not - else if (MODELS_ColmacCxV_5_SP <= presetNum && presetNum <= MODELS_ColmacCxA_30_SP) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.perfMap.reserve(1); - compressor.hysteresis_dC = 0; - - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - //logic conditions - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(15), this)); - - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom node", nodeWeights1, dF_TO_dC(15.), - this, false, std::greater(), true)); - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - if (presetNum == MODELS_ColmacCxV_5_SP) { - setTankSize_adjustUA(200., UNITS_GAL); - //logic conditions - compressor.minT = F_TO_C(-4.0); - compressor.maxSetpoint_C = MAXOUTLET_R410A; - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 4.9621645063, -0.0096084144, -0.0095647009, -0.0115911960, -0.0000788517, 0.0000886176, - 0.0001114142, 0.0001832377, -0.0000451308, 0.0000411975, 0.0000003535}, // Input Power Coefficients (inputPower_coeffs) - - { 3.8189922420, 0.0569412237, -0.0320101962, -0.0012859036, 0.0000576439, 0.0001101241, - -0.0000352368, -0.0002630301, -0.0000509365, 0.0000369655, -0.0000000606} // COP Coefficients (COP_coeffs) - }); - } - else { - //logic conditions - compressor.minT = F_TO_C(40.); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - if (presetNum == MODELS_ColmacCxA_10_SP) { - setTankSize_adjustUA(500., UNITS_GAL); - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 5.9786974243, 0.0194445115, -0.0077802278, 0.0053809029, -0.0000334832, 0.0001864310, 0.0001190540, - 0.0000040405, -0.0002538279, -0.0000477652, 0.0000014101}, // Input Power Coefficients (inputPower_coeffs) - - { 3.6128563086, 0.0527064498, -0.0278198945, -0.0070529748, 0.0000934705, 0.0000781711, -0.0000359215, - -0.0002223206, 0.0000359239, 0.0000727189, -0.0000005037} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_15_SP) { - setTankSize_adjustUA(600., UNITS_GAL); - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 15.5869846555, -0.0044503761, -0.0577941202, -0.0286911185, -0.0000803325, 0.0003399817, - 0.0002009576, 0.0002494761, -0.0000595773, 0.0001401800, 0.0000004312}, // Input Power Coefficients (inputPower_coeffs) - - { 1.6643120405, 0.0515623393, -0.0110239930, 0.0041514430, 0.0000481544, 0.0000493424, - -0.0000262721, -0.0002356218, -0.0000989625, -0.0000070572, 0.0000004108} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_20_SP) { - setTankSize_adjustUA(800., UNITS_GAL); - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 23.0746692231, 0.0248584608, -0.1417927282, -0.0253733303, -0.0004882754, 0.0006508079, - 0.0002139934, 0.0005552752, -0.0002026772, 0.0000607338, 0.0000021571}, // Input Power Coefficients (inputPower_coeffs) - - { 1.7692660120, 0.0525134783, -0.0081102040, -0.0008715405, 0.0001274956, 0.0000369489, - -0.0000293775, -0.0002778086, -0.0000095067, 0.0000381186, -0.0000003135} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_25_SP) { - setTankSize_adjustUA(1000., UNITS_GAL); - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 20.4185336541, -0.0236920615, -0.0736219119, -0.0260385082, -0.0005048074, 0.0004940510, - 0.0002632660, 0.0009820050, -0.0000223587, 0.0000885101, 0.0000005649}, // Input Power Coefficients (inputPower_coeffs) - - { 0.8942843854, 0.0677641611, -0.0001582927, 0.0048083998, 0.0001196407, 0.0000334921, - -0.0000378740, -0.0004146401, -0.0001213363, -0.0000031856, 0.0000006306} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_30_SP) { - setTankSize_adjustUA(1200., UNITS_GAL); - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 11.3687485772, -0.0207292362, 0.0496254077, -0.0038394967, -0.0005991041, 0.0001304318, - 0.0003099774, 0.0012092717, -0.0001455509, -0.0000893889, 0.0000018221}, // Input Power Coefficients (inputPower_coeffs) - - { 4.4170108542, 0.0596384263, -0.0416104579, -0.0017199887, 0.0000774664, 0.0001521934, - -0.0000251665, -0.0003289731, -0.0000801823, 0.0000325972, 0.0000002705} // COP Coefficients (COP_coeffs) - }); - } - } //End if MODELS_ColmacCxV_5_SP - - //set everything in its places - setOfSources[0] = compressor; - } - - - // if colmac multipass - else if (MODELS_ColmacCxV_5_MP <= presetNum && presetNum <= MODELS_ColmacCxA_30_MP) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.perfMap.reserve(1); - compressor.hysteresis_dC = 0; - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = (int)(numNodes / 3.) - 1; - - //logic conditions - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(5.), this)); - - std::vector nodeWeights1; - nodeWeights1.emplace_back(4); - compressor.addShutOffLogic(std::make_shared("fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); - - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - if (presetNum == MODELS_ColmacCxV_5_MP) { - setTankSize_adjustUA(200., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(9.); //https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf - - //logic conditions - compressor.minT = F_TO_C(-4.0); - compressor.maxT = F_TO_C(105.); - compressor.maxSetpoint_C = MAXOUTLET_R410A; - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 5.8438525529, 0.0003288231, -0.0494255840, -0.0000386642, 0.0004385362, 0.0000647268}, // Input Power Coefficients (inputPower_coeffs) - - { 0.6679056901, 0.0499777846, 0.0251828292, 0.0000699764, -0.0001552229, -0.0002911167} // COP Coefficients (COP_coeffs) - }); - } - else { - //logic conditions - compressor.minT = F_TO_C(40.); - compressor.maxT = F_TO_C(105.); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - if (presetNum == MODELS_ColmacCxA_10_MP) { - setTankSize_adjustUA(500., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(18.); - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 8.6918824405, 0.0136666667, -0.0548348214, -0.0000208333, 0.0005301339, -0.0000250000}, // Input Power Coefficients (inputPower_coeffs) - - { 0.6944181117, 0.0445926666, 0.0213188804, 0.0001172913, -0.0001387694, -0.0002365885} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_15_MP) { - setTankSize_adjustUA(600., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(26.); - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 12.4908723958, 0.0073988095, -0.0411417411, 0.0000000000, 0.0005789621, 0.0000696429}, // Input Power Coefficients (inputPower_coeffs) - - { 1.2846349520, 0.0334658309, 0.0019121906, 0.0002840970, 0.0000497136, -0.0004401737} // COP Coefficients (COP_coeffs) - - }); - - } - else if (presetNum == MODELS_ColmacCxA_20_MP) { - setTankSize_adjustUA(800., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(36.); //https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf - - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 14.4893345424, 0.0355357143, -0.0476593192, -0.0002916667, 0.0006120954, 0.0003607143}, // Input Power Coefficients (inputPower_coeffs) - - { 1.2421582831, 0.0450256569, 0.0051234755, 0.0001271296, -0.0000299981, -0.0002910606} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_25_MP) { - setTankSize_adjustUA(1000., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(32.); - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 14.5805808222, 0.0081934524, -0.0216169085, -0.0001979167, 0.0007376535, 0.0004955357}, // Input Power Coefficients (inputPower_coeffs) - - { 2.0013175767, 0.0576617432, -0.0130480870, 0.0000856818, 0.0000610760, -0.0003684106} // COP Coefficients (COP_coeffs) - }); - - } - else if (presetNum == MODELS_ColmacCxA_30_MP) { - setTankSize_adjustUA(1200., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(41.); - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 14.5824911644, 0.0072083333, -0.0278055246, -0.0002916667, 0.0008841378, 0.0008125000}, // Input Power Coefficients (inputPower_coeffs) - - { 2.6996807527, 0.0617507969, -0.0220966420, 0.0000336149, 0.0000890989, -0.0003682431} // COP Coefficients (COP_coeffs) - }); - } - } - - //set everything in its places - setOfSources[0] = compressor; - } - // If Nyle single pass preset - else if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_C_SP) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - //HeatSource resistiveElement(this); - - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.extrapolationMethod = EXTRAP_NEAREST; - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.perfMap.reserve(1); - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - //logic conditions - if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_SP) {// If not cold weather package - compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package - } - else { - compressor.minT = F_TO_C(35.);// Min air temperature WITH Cold Weather Package - } - compressor.maxT = F_TO_C(120.0); // Max air temperature - compressor.hysteresis_dC = 0; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - // Defines the maximum outlet temperature at the a low air temperature - compressor.maxOut_at_LowT.outT_C = F_TO_C(140.); - compressor.maxOut_at_LowT.airT_C = F_TO_C(40.); - - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(15), this, false)); - - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom node", nodeWeights1, dF_TO_dC(15.), this, false, - std::greater(), true)); - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - //Perfmaps for each compressor size - if (presetNum == MODELS_NyleC25A_SP) { - setTankSize_adjustUA(200., UNITS_GAL); - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {4.060120364 ,-0.020584279,-0.024201054,-0.007023945,0.000017461,0.000110366,0.000060338, - 0.000120015,0.000111068,0.000138907,-0.000001569}, // Input Power Coefficients (inputPower_coeffs) - - {0.462979529,0.065656840,0.001077377,0.003428059,0.000243692,0.000021522,0.000005143, - -0.000384778,-0.000404744,-0.000036277, 0.000001900 } // COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_NyleC60A_SP || presetNum == MODELS_NyleC60A_C_SP) { - setTankSize_adjustUA(300., UNITS_GAL); - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {-0.1180905709,0.0045354306,0.0314990479,-0.0406839757,0.0002355294,0.0000818684,0.0001943834, - -0.0002160871,0.0003053633,0.0003612413,-0.0000035912}, // Input Power Coefficients (inputPower_coeffs) - - {6.8205043418,0.0860385185,-0.0748330699,-0.0172447955,0.0000510842,0.0002187441,-0.0000321036, - -0.0003311463,-0.0002154270,0.0001307922,0.0000005568} // COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_NyleC90A_SP || presetNum == MODELS_NyleC90A_C_SP) { - setTankSize_adjustUA(400., UNITS_GAL); - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {13.27612215047,-0.01014009337,-0.13401028549,-0.02325705976,-0.00032515646,0.00040270625, - 0.00001988733,0.00069451670,0.00069067890,0.00071091372,-0.00000854352}, // Input Power Coefficients (inputPower_coeffs) - - {1.49112327987,0.06616282153,0.00715307252,-0.01269458185,0.00031448571,0.00001765313, - 0.00006002498,-0.00045661397,-0.00034003896,-0.00004327766,0.00000176015} // COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_NyleC125A_SP || presetNum == MODELS_NyleC125A_C_SP) { - setTankSize_adjustUA(500., UNITS_GAL); - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {-3.558277209, -0.038590968, 0.136307181, -0.016945699,0.000983753, -5.18201E-05, - 0.000476904, -0.000514211, -0.000359172, 0.000266509, -1.58646E-07}, // Input Power Coefficients (inputPower_coeffs) - - {4.889555031, 0.117102769, -0.060005795, -0.011871234, -1.79926E-05, 0.000207293, - -1.4452E-05, -0.000492486, -0.000376814, 7.85911E-05, 1.47884E-06}// COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_NyleC185A_SP || presetNum == MODELS_NyleC185A_C_SP) { - setTankSize_adjustUA(800., UNITS_GAL); - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {18.58007733, -0.215324777, -0.089782421, 0.01503161, 0.000332503, 0.000274216, - 2.70498E-05, 0.001387914, 0.000449199, 0.000829578, -5.28641E-06}, // Input Power Coefficients (inputPower_coeffs) - - {-0.629432348, 0.181466663, 0.00044047, 0.012104957, -6.61515E-05, 9.29975E-05, - 9.78042E-05, -0.000872708,-0.001013945, -0.00021852, 5.55444E-06}// COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_NyleC250A_SP || presetNum == MODELS_NyleC250A_C_SP) { - setTankSize_adjustUA(800., UNITS_GAL); - - compressor.perfMap.push_back({ - 90, // Temperature (T_F) - - {-13.89057656,0.025902417,0.304250541,0.061695153,-0.001474249,-0.001126845,-0.000220192, - 0.001241026,0.000571009,-0.000479282,9.04063E-06},// Input Power Coefficients (inputPower_coeffs) - - {7.443904067,0.185978755,-0.098481635,-0.002500073,0.000127658,0.000444321,0.000139547, - -0.001000195,-0.001140199,-8.77557E-05,4.87405E-06} // COP Coefficients (COP_coeffs) - }); - } - - //set everything in its places - setOfSources[0] = compressor; - } - - // If Nyle multipass presets - else if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_C_MP) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.extrapolationMethod = EXTRAP_NEAREST; - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.hysteresis_dC = 0; - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = (int)(numNodes / 3.) - 1; - - //logic conditions//logic conditions - if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_MP) {// If not cold weather package - compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package - } - else { - compressor.minT = F_TO_C(35.);// Min air temperature WITH Cold Weather Package - } - compressor.maxT = F_TO_C(130.0); // Max air temperature - compressor.maxSetpoint_C = F_TO_C(160.); - - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(5.), this)); - - std::vector nodeWeights1; - nodeWeights1.emplace_back(4); - compressor.addShutOffLogic(std::make_shared("fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - // Performance grid - compressor.perfGrid.reserve(2); - compressor.perfGridValues.reserve(2); - - // Nyle MP models are all on the same grid axes - compressor.perfGrid.push_back({ 40., 60., 80., 90. }); // Grid Axis 1 Tair (F) - compressor.perfGrid.push_back({ 40., 60., 80., 100., 130., 150. }); // Grid Axis 2 Tin (F) - - if (presetNum == MODELS_NyleC60A_MP || presetNum == MODELS_NyleC60A_C_MP) { - setTankSize_adjustUA(360., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(13.); - if (presetNum == MODELS_NyleC60A_C_MP) { - compressor.resDefrost = { - 4.5, // inputPwr_kW; - 5.0, // constTempLift_dF; - 40.0 // onBelowT_F - }; - } - // Grid values in long format, table 1, input power (W) - compressor.perfGridValues.push_back({ 3.64, 4.11, 4.86, 5.97, 8.68, 9.95, 3.72, 4.27, 4.99, 6.03, 8.55, 10.02, 3.98, 4.53, - 5.24, 6.24, 8.54, 9.55, 4.45, 4.68, 5.37, 6.34, 8.59, 9.55 - }); - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 3.362637363, 2.917274939, 2.407407407, 1.907872697, 1.296082949, 1.095477387, 4.438172043, - 3.772833724, 3.132264529, 2.505804312, 1.678362573, 1.386227545, 5.467336683, 4.708609272, 3.921755725, 3.169871795, 2.165105386, - 1.860732984, 5.512359551, 5.153846154, 4.290502793, 3.417981073, 2.272409779, 1.927748691 - }); - } - else if (presetNum == MODELS_NyleC90A_MP || presetNum == MODELS_NyleC90A_C_MP) { - setTankSize_adjustUA(480., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(20.); - if (presetNum == MODELS_NyleC90A_C_MP) { - compressor.resDefrost = { - 5.4, // inputPwr_kW; - 5.0, // constTempLift_dF; - 40.0 // onBelowT_F - }; - } - // Grid values in long format, table 1, input power (W) - compressor.perfGridValues.push_back({ 4.41, 6.04, 7.24, 9.14, 12.23, 14.73, 4.78, 6.61, 7.74, 9.40, 12.47, 14.75, - 5.51, 6.66, 8.44, 9.95, 13.06, 15.35, 6.78, 7.79, 8.81, 10.01, 11.91, 13.35 - }); - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 4.79138322, 3.473509934, 2.801104972, 2.177242888, 1.569910057, 1.272233537, 6.071129707, - 4.264750378, 3.536175711, 2.827659574, 2.036086608, 1.666440678, 7.150635209, 5.659159159, 4.305687204, 3.493467337, - 2.487748851, 2.018241042, 6.750737463, 5.604621309, 4.734392736, 3.94005994, 3.04534005, 2.558801498 - }); - - } - else if (presetNum == MODELS_NyleC125A_MP || presetNum == MODELS_NyleC125A_C_MP) { - setTankSize_adjustUA(600., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(28.); - if (presetNum == MODELS_NyleC125A_C_MP) { - compressor.resDefrost = { - 9.0, // inputPwr_kW; - 5.0, // constTempLift_dF; - 40.0 // onBelowT_F - }; - } - // Grid values in long format, table 1, input power (W) - compressor.perfGridValues.push_back({ 6.4, 7.72, 9.65, 12.54, 20.54, 24.69, 6.89, 8.28, 10.13, 12.85, 19.75, 24.39, - 7.69, 9.07, 10.87, 13.44, 19.68, 22.35, 8.58, 9.5, 11.27, 13.69, 19.72, 22.4 - }); - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 4.2390625, 3.465025907, 2.718134715, 2.060606061, 1.247809153, 1.016605913, - 5.374455733, 4.352657005, 3.453109576, 2.645136187, 1.66278481, 1.307093071, 6.503250975, 5.276736494, 4.229070837, - 3.27827381, 2.113821138, 1.770469799, 6.657342657, 5.749473684, 4.612244898, 3.542731921, 2.221095335, 1.816964286 - }); - } - else if (presetNum == MODELS_NyleC185A_MP || presetNum == MODELS_NyleC185A_C_MP) { - setTankSize_adjustUA(960., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(40.); - if (presetNum == MODELS_NyleC185A_C_MP) { - compressor.resDefrost = { - 7.2, // inputPwr_kW; - 5.0, // constTempLift_dF; - 40.0 // onBelowTemp_F - }; - } - // Grid values in long format, table 1, input power (W) - compressor.perfGridValues.push_back({ 7.57, 11.66, 14.05, 18.3, 25.04, 30.48, 6.99, 10.46, 14.28, 18.19, 26.24, 32.32, - 7.87, 12.04, 15.02, 18.81, 25.99, 31.26, 8.15, 12.46, 15.17, 18.95, 26.23, 31.62 - }); - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 5.531043593, 3.556603774, 2.918149466, 2.214754098, 1.590255591, 1.291010499, - 8.010014306, 5.258126195, 3.778711485, 2.916437603, 1.964176829, 1.56404703, 9.65819568, 6.200166113, 4.792276964, - 3.705475811, 2.561369758, 2.05950096, 10.26993865, 6.350722311, 5.04218853, 3.841688654, 2.574151735, 2.025616698 - }); - } - else if (presetNum == MODELS_NyleC250A_MP || presetNum == MODELS_NyleC250A_C_MP) { - setTankSize_adjustUA(960., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(50.); - if (presetNum == MODELS_NyleC250A_C_MP) { - compressor.resDefrost = { - 18.0, // inputPwr_kW; - 5.0, // constTempLift_dF; - 40.0 // onBelowT_F - }; - } - // Grid values in long format, table 1, input power (W) - compressor.perfGridValues.push_back({ 10.89, 12.23, 13.55, 14.58, 15.74, 16.72, 11.46, 13.76, 15.97, 17.79, - 20.56, 22.50, 10.36, 14.66, 18.07, 21.23, 25.81, 29.01, 8.67, 15.05, 18.76, 21.87, 26.63, 30.02 - }); - - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 5.81818181, 4.50040883, 3.69667896, 3.12414266, 2.38500635, 1.93540669, - 7.24520069, 5.50145348, 4.39323732, 3.67734682, 2.73249027, 2.23911111, 10.6196911, 7.05320600, 5.41228555, - 4.28638718, 3.04804339, 2.46053085, 14.7831603, 7.77903268, 5.71801705, 4.40237768, 2.92489673, 2.21419054 - }); - - } - - // Set up regular grid interpolator. - compressor.perfRGI = new Btwxt::RegularGridInterpolator(compressor.perfGrid, compressor.perfGridValues); - compressor.useBtwxtGrid = true; - - //set everything in its places - setOfSources[0] = compressor; - } - // if rheem multipass - else if (MODELS_RHEEM_HPHD60HNU_201_MP <= presetNum && presetNum <= MODELS_RHEEM_HPHD135VNU_483_MP) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.perfMap.reserve(1); - compressor.hysteresis_dC = 0; - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = (int)(numNodes / 3.) - 1; - - //logic conditions - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(5.), this)); - - std::vector nodeWeights1; - nodeWeights1.emplace_back(4); - compressor.addShutOffLogic(std::make_shared("fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - //logic conditions - compressor.minT = F_TO_C(45.); - compressor.maxT = F_TO_C(110.); - compressor.maxSetpoint_C = MAXOUTLET_R134A; // data says 150... - - if (presetNum == MODELS_RHEEM_HPHD60HNU_201_MP || presetNum == MODELS_RHEEM_HPHD60VNU_201_MP) { - setTankSize_adjustUA(250., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(17.4); - compressor.perfMap.push_back({ - 110, // Temperature (T_F) - - { 1.8558438453, 0.0120796155, -0.0135443327, 0.0000059621, 0.0003010506, -0.0000463525}, // Input Power Coefficients (inputPower_coeffs) - - { 3.6840046360, 0.0995685071, -0.0398107723, -0.0001903160, 0.0000980361, -0.0003469814} // COP Coefficients (COP_coeffs) - }); - } - else if (presetNum == MODELS_RHEEM_HPHD135HNU_483_MP || presetNum == MODELS_RHEEM_HPHD135VNU_483_MP) { - setTankSize_adjustUA(500., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(34.87); - compressor.perfMap.push_back({ - 110, // Temperature (T_F) - - { 5.1838201136, 0.0247312962, -0.0120766440, 0.0000493862, 0.0005422089, -0.0001385078}, // Input Power Coefficients (inputPower_coeffs) - - { 5.0207181209, 0.0442525790, -0.0418284882, 0.0000793531, 0.0001132421, -0.0002491563} // COP Coefficients (COP_coeffs) - }); - } - - //set everything in its places - setOfSources[0] = compressor; - } - - else if (presetNum == MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = 65; - - tankVolume_L = GAL_TO_L(500); - tankUA_kJperHrC = 12; - tankSizeFixed = false; - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.minT = F_TO_C(-13.); - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - // What to do about these?! - compressor.hysteresis_dC = 4; - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.maxSetpoint_C = F_TO_C(176.1); - - // Turn on - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("eighth node absolute", nodeWeights, F_TO_C(110.), this, true)); - - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom node", nodeWeights1, dF_TO_dC(15.), this, false, - std::greater(), true)); - compressor.depressesTemperature = false; - - // Performance grid: externalT_F, Tout_F, condenserTemp_F - compressor.perfGrid.reserve(2); - compressor.perfGridValues.reserve(2); - compressor.perfGrid.push_back({ -13, -11.2, -7.6, -4, -0.4, 3.2, 6.8, 10.4, 14, 17.6, 21.2, 24.8, 28.4, 32, 35.6, 39.2, - 42.8, 46.4, 50, 53.6, 57.2, 60.8, 64.4, 68, 71.6, 75.2, 78.8, 82.4, 86, 89.6, 93.2, 96.8, 100.4, 104}); // Grid Axis 1 Tair (F) - compressor.perfGrid.push_back({ 140., 158., 176. }); // Grid Axis 2 Tout (F) - compressor.perfGrid.push_back({ 41, 48.2, 62.6, 75.2, 84.2}); // Grid Axis 3 Tin (F) - - // Grid values in long format, table 1, input power (Btu/hr) - compressor.perfGridValues.push_back({ 56518.565328, 57130.739544, 57094.73612, 57166.756616, 57238.777112, 56518.565328, 57130.739544, 57094.73612, 57166.756616, 57238.777112, - 58061.348896, 58360.24692, 58591.39286, 58870.368216, 59093.547136, 56626.5960719999, 57202.763452, 57310.794196, 57310.794196, 57490.848848, 56626.5960719999, 57202.763452, - 57310.794196, 57310.794196, 57490.848848, 58280.539188, 58519.65556, 58786.67868, 59093.547136, 59372.5190799999, 56950.695128, 57850.95474, 57814.947904, 57814.947904, - 57922.978648, 56950.695128, 57850.95474, 57814.947904, 57814.947904, 57922.978648, 58679.067612, 58977.969048, 59372.5190799999, 59651.494436, 59930.46638, 57418.831764, - 58175.053796, 58283.08454, 58247.07088, 58427.12212, 57418.831764, 58175.053796, 58283.08454, 58247.07088, 58427.12212, 59137.384512, 59376.504296, 59902.566456, 60265.23476, - 60516.313604, 57778.930832, 58643.190432, 58823.23826, 58643.190432, 58967.282664, 57778.930832, 58643.190432, 58823.23826, 58643.190432, 58967.282664, 59515.99368, 59954.377676, - 60321.031196, 60934.77152, 61213.743464, 58103.029888, 59075.313408, 59219.357812, 59291.374896, 59579.45688, 58103.029888, 59075.313408, 59219.357812, 59291.374896, 59579.45688, - 60014.159328, 60273.205192, 60934.77152, 61436.922384, 61799.587276, 58535.152864, 59399.412464, 59795.525192, 59903.555936, 60299.672076, 58535.152864, 59399.412464, 59795.525192, - 59903.555936, 60299.672076, 60512.321564, 60751.448172, 61409.02246, 62022.769608, 62329.641476, 58931.275828, 59651.4842, 60011.58668, 60263.66524, 60551.747224, 58931.275828, - 59651.4842, 60011.58668, 60263.66524, 60551.747224, 60910.860224, 61369.1703, 62022.769608, 62580.713496, 62803.895828, 59219.357812, 60155.634496, 60443.71648, 60659.777968, - 61163.92144, 59219.357812, 60155.634496, 60443.71648, 60659.777968, 61163.92144, 61329.321552, 61687.997816, 62441.224112, 63166.56072, 63585.015224, 59651.4842, 60479.726728, - 61019.88386, 61163.92144, 61920.146884, 59651.4842, 60479.726728, 61019.88386, 61163.92144, 61920.146884, 61707.923896, 62186.166876, 63027.071336, 63724.504608, 64170.862448, - 59723.504696, 60839.83262, 61379.993164, 61524.030744, 62352.273272, 59723.504696, 60839.83262, 61379.993164, 61524.030744, 62352.273272, 61966.96976, 62445.21274, 63361.839716, - 64142.969348, 64505.63424, 59759.511532, 60695.788216, 61524.030744, 61884.136636, 62712.382576, 59759.511532, 60695.788216, 61524.030744, 61884.136636, 62712.382576, 62166.240796, - 62744.114176, 63668.714996, 64282.451908, 64589.323776, 59759.511532, 61019.88386, 61848.1298, 62064.191288, 62964.4509, 59759.511532, 61019.88386, 61848.1298, 62064.191288, - 62964.4509, 62425.28666, 63003.16004, 63975.58004, 64533.523928, 64617.2237, 59471.429548, 61055.894108, 61956.160544, 62460.304016, 63216.526048, 59471.429548, 61055.894108, - 61956.160544, 62460.304016, 63216.526048, 62624.550872, 63202.424252, 64310.351832, 64756.70626, 64728.806336, 61632.061488, 63036.474808, 63828.7105, 64296.847136, 65053.069168, - 61632.061488, 63036.474808, 63828.7105, 64296.847136, 65053.069168, 63561.10734, 64099.125148, 65258.8605359999, 65593.625504, 65621.525428, 51189.004268, 52917.506408, 54826.070024, - 57094.73612, 59327.388556, 51189.004268, 52917.506408, 54826.070024, 57094.73612, 59327.388556, 55391.172288, 58240.683616, 62106.459144, 65733.114888, 65705.214964, 41286.100768, - 42726.524336, 45931.460292, 49784.590948, 53457.6669519999, 41286.100768, 42726.524336, 45931.460292, 49784.590948, 53457.6669519999, 49433.093532, 51067.083272, 57921.8561, - 61604.3082799999, 64477.734316, 35632.444064, 37108.87788, 41394.134924, 45139.228012, 49568.526048, 35632.444064, 37108.87788, 41394.134924, 45139.228012, 49568.526048, 47540.06134, - 47221.233824, 56080.631716, 59539.904976, 61883.276812, 34192.023908, 35596.430404, 39809.6669519999, 43410.72246, 47659.969256, 34192.023908, 35596.430404, 39809.6669519999, - 43410.72246, 47659.969256, 47559.98742, 47061.821772, 54490.482764, 57893.959588, 60153.648712, 32895.641332, 34192.023908, 38225.202392, 41646.20666, 45751.409052, 32895.641332, - 34192.023908, 38225.202392, 41646.20666, 45751.409052, 47659.621232, 46842.624656, 52956.13366, 56220.1211, 58312.420916, 31563.25192, 32715.58668, 36532.707088, 39881.687448, - 43914.869344, 31563.25192, 32715.58668, 36532.707088, 39881.687448, 43914.869344, 47719.402884, 46742.994256, 51393.877808, 54518.382688, 56554.886068, 30194.85226, 31347.18702, - 35092.286932, 38117.171648, 42006.312552, 30194.85226, 31347.18702, 35092.286932, 38117.171648, 42006.312552, 47799.1072039999, 46324.532928, 49692.139396, 52732.951328, 54769.45812, - 30446.923996, 31383.197268, 34300.054652, 37144.884716, 40781.953884, 30446.923996, 31383.197268, 34300.054652, 37144.884716, 40781.953884, 45547.391924, 44212.307032, 47320.867636, - 50389.57608, 52202.90054, 30698.995732, 31311.176772, 33723.88386, 36316.6456, 39701.636208, 30698.995732, 31311.176772, 33723.88386, 36316.6456, 39701.636208, 43295.680056, - 41980.517832, 45089.078436, 47795.121988, 49720.03932, 30987.081128, 31311.176772, 33183.726728, 35344.358668, 38477.27754, 30987.081128, 31311.176772, 33183.726728, 35344.358668, - 38477.27754, 41562.059916, 40486.017476, 43415.236536, 46037.590552, 47795.121988, 31203.146028, 31311.176772, 32571.545688, 34552.126388, 37360.949616, 31203.146028, 31311.176772, - 32571.545688, 34552.126388, 37360.949616, 40486.017476, 39310.3446359999, 42159.859376, 44782.20998, 46511.844904, 31167.132368, 31311.176772, 32355.4842, 34156.010248, 36712.758328, - 31167.132368, 31311.176772, 32355.4842, 34156.010248, 36712.758328, 39449.830608, 38353.862088, 41127.657724, 43666.31538, 45284.360844, 31059.101624, 31131.12212, 32319.473952, - 34156.010248, 36748.771988, 31059.101624, 31131.12212, 32319.473952, 34156.010248, 36748.771988, 38592.985284, 37457.161192, 40151.249096, 42801.496212, 44419.541676, 30879.050384, - 31023.091376, 32319.473952, 34192.023908, 36820.789072, 30879.050384, 31023.091376, 32319.473952, 34192.023908, 36820.789072, 37756.062628, 36680.0236, 39258.536828, 41797.194484, - 43387.343436, 30807.029888, 30951.07088, 32427.504696, 34156.010248, 36748.771988, 30807.029888, 30951.07088, 32427.504696, 34156.010248, 36748.771988, 37795.9182, 36779.657412, - 39258.536828, 41769.29456, 43331.547, 30626.976942, 30735.007686, 32319.473952, 34156.010248, 36748.771988, 30626.976942, 30735.007686, 32319.473952, 34156.010248, 36748.771988, - 37815.84428, 36779.657412, 39286.431634, 41825.090996, 43359.446924, 30446.923996, 30518.944492, 32355.4842, 34264.040992, 36820.789072, 30446.923996, 30518.944492, 32355.4842, - 34264.040992, 36820.789072, 37775.988708, 36759.731332, 39286.431634, 41825.090996, 43359.446924, 30230.859096, 30410.913748, 32319.473952, 34192.023908, 36748.771988, 30230.859096, - 30410.913748, 32319.473952, 34192.023908, 36748.771988, 37775.988708, 36759.731332, 39342.226364, 41825.090996, 43303.650488, 30194.85226, 30194.85226, 32391.491036, 34156.010248, - 36748.771988, 30194.85226, 30194.85226, 32391.491036, 34156.010248, 36748.771988, 37756.062628, 36779.657412, 39342.226364, 41825.090996, 43359.446924 - }); - - // Grid values in long format, table 2, COP - compressor.perfGridValues.push_back({ 1.177126, 1.1393, 1.091664, 1.033858, 0.981755, 1.177126, 1.1393, 1.091664, 1.033858, 0.981755, 1.134534, 1.106615, 1.04928, 0.989101, 0.946182, 1.228935, - 1.190326, 1.136507, 1.075244, 1.023802, 1.228935, 1.190326, 1.136507, 1.075244, 1.023802, 1.174944, 1.147101, 1.087318, 1.026909, 0.980265, 1.324165, 1.27451, 1.218468, 1.156182, 1.103823, - 1.324165, 1.27451, 1.218468, 1.156182, 1.103823, 1.267595, 1.236929, 1.165864, 1.102888, 1.052601, 1.415804, 1.365212, 1.301359, 1.238022, 1.180586, 1.415804, 1.365212, 1.301359, 1.238022, - 1.180586, 1.358408, 1.324943, 1.249272, 1.179609, 1.128155, 1.510855, 1.453792, 1.381237, 1.31747, 1.253435, 1.510855, 1.453792, 1.381237, 1.31747, 1.253435, 1.446639, 1.404653, 1.331368, - 1.249056, 1.195511, 1.60469, 1.540079, 1.462451, 1.39417, 1.326987, 1.60469, 1.540079, 1.462451, 1.39417, 1.326987, 1.529924, 1.492107, 1.404944, 1.325122, 1.265433, 1.690249, 1.630494, - 1.539446, 1.464082, 1.395939, 1.690249, 1.630494, 1.539446, 1.464082, 1.395939, 1.610302, 1.56761, 1.479273, 1.393118, 1.33076, 1.776046, 1.715967, 1.624662, 1.540783, 1.469819, 1.776046, - 1.715967, 1.624662, 1.540783, 1.469819, 1.693465, 1.646725, 1.550545, 1.459601, 1.400666, 1.865309, 1.797965, 1.703902, 1.612645, 1.539888, 1.865309, 1.797965, 1.703902, 1.612645, 1.539888, - 1.776866, 1.728095, 1.626829, 1.531743, 1.461555, 1.956837, 1.881215, 1.777073, 1.690021, 1.603082, 1.956837, 1.881215, 1.777073, 1.690021, 1.603082, 1.857512, 1.807899, 1.699347, 1.599321, - 1.526899, 2.038891, 1.956496, 1.848049, 1.757975, 1.668207, 2.038891, 1.956496, 1.848049, 1.757975, 1.668207, 1.934721, 1.878022, 1.764777, 1.657606, 1.583414, 2.110576, 2.028182, 1.922739, - 1.818155, 1.725237, 2.110576, 2.028182, 1.922739, 1.818155, 1.725237, 1.997516, 1.937435, 1.824625, 1.712596, 1.630169, 2.185899, 2.091178, 1.989083, 1.883087, 1.786388, 2.185899, 2.091178, - 1.989083, 1.883087, 1.786388, 2.06464, 2.003084, 1.88041, 1.763428, 1.68041, 2.29337, 2.155411, 2.063354, 1.942635, 1.844204, 2.29337, 2.155411, 2.063354, 1.942635, 1.844204, 2.125448, 2.061323, - 1.933955, 1.810339, 1.720612, 2.213555, 2.111682, 2.027503, 1.91515, 1.819817, 2.213555, 2.111682, 2.027503, 1.91515, 1.819817, 2.126499, 2.064584, 1.935343, 1.818713, 1.728239, 2.665142, - 2.578088, 2.488506, 2.388206, 2.29651, 2.665142, 2.578088, 2.488506, 2.388206, 2.29651, 2.46407, 2.344111, 2.198428, 2.057188, 1.96338, 3.304405, 3.191319, 2.971384, 2.741049, 2.550691, 3.304405, - 3.191319, 2.971384, 2.741049, 2.550691, 2.763177, 2.673398, 2.356773, 2.216348, 2.116712, 3.827691, 3.676371, 3.297085, 3.022338, 2.752997, 3.827691, 3.676371, 3.297085, 3.022338, 2.752997, - 2.871739, 2.890389, 2.434648, 2.292726, 2.205906, 3.989995, 3.834598, 3.428313, 3.14185, 2.862486, 3.989995, 3.834598, 3.428313, 3.14185, 2.862486, 2.871269, 2.900921, 2.506208, 2.358391, - 2.270261, 4.147236, 3.992101, 3.570419, 3.274967, 2.982684, 4.147236, 3.992101, 3.570419, 3.274967, 2.982684, 2.865266, 2.913751, 2.578296, 2.428607, 2.341945, 4.322305, 4.172262, 3.73583, - 3.419865, 3.107421, 4.322305, 4.172262, 3.73583, 3.419865, 3.107421, 2.861677, 2.919962, 2.65667, 2.504413, 2.414725, 4.518187, 4.354394, 3.889174, 3.578177, 3.248607, 4.518187, 4.354394, 3.889174, - 3.578177, 3.248607, 2.856905, 2.946338, 2.747649, 2.589208, 2.493442, 4.481963, 4.349398, 3.979002, 3.671837, 3.346137, 4.481963, 4.349398, 3.979002, 3.671837, 3.346137, 2.998141, 3.087098, 2.885335, - 2.709619, 2.616032, 4.445162, 4.359402, 4.046983, 3.755577, 3.437188, 4.445162, 4.359402, 4.046983, 3.755577, 3.437188, 3.154067, 3.251216, 3.028152, 2.856705, 2.746669, 4.402673, 4.359402, 4.112859, - 3.858889, 3.546561, 4.402673, 4.359402, 4.112859, 3.858889, 3.546561, 3.285629, 3.371232, 3.1449, 2.965763, 2.857289, 4.373341, 4.359402, 4.19016, 3.947368, 3.65253, 4.373341, 4.359402, 4.19016, - 3.947368, 3.65253, 3.372955, 3.472057, 3.238544, 3.048902, 2.936122, 4.378394, 4.359402, 4.218141, 3.993147, 3.717018, 4.378394, 4.359402, 4.218141, 3.993147, 3.717018, 3.461548, 3.558644, 3.319824, - 3.126817, 3.015709, 4.391304, 4.384616, 4.222841, 3.993147, 3.713376, 4.391304, 4.384616, 4.222841, 3.993147, 3.713376, 3.538402, 3.643836, 3.400556, 3.189995, 3.074423, 4.419242, 4.399884, 4.222841, - 3.988941, 3.706113, 4.419242, 4.399884, 4.222841, 3.988941, 3.706113, 3.616836, 3.721038, 3.477882, 3.266644, 3.147565, 4.429573, 4.410122, 4.208773, 3.993147, 3.713376, 4.429573, 4.410122, 4.208773, - 3.993147, 3.713376, 3.613022, 3.710957, 3.477882, 3.268826, 3.151618, 4.45679, 4.441125, 4.222841, 3.993147, 3.713376, 4.45679, 4.441125, 4.222841, 3.993147, 3.713376, 3.611119, 3.710957, 3.475413, - 3.264466, 3.14959, 4.483146, 4.472566, 4.218141, 3.980557, 3.706113, 4.483146, 4.472566, 4.218141, 3.980557, 3.706113, 3.614928, 3.712969, 3.475413, 3.264466, 3.14959, 4.515188, 4.488454, 4.222841, - 3.988941, 3.713376, 4.515188, 4.488454, 4.222841, 3.988941, 3.713376, 3.614928, 3.712969, 3.470484, 3.264466, 3.153648, 4.522957, 4.520572, 4.213452, 3.993147, 3.713376, 4.522957, 4.520572, 4.213452, - 3.993147, 3.713376, 3.616836, 3.710957, 3.470484, 3.264466, 3.14959 - }); - - // Set up regular grid interpolator. - Btwxt::GriddedData gridded_data(compressor.perfGrid, compressor.perfGridValues); - gridded_data.set_axis_extrap_method(2, Btwxt::Method::LINEAR); //Linearly extrapolate on Tin (F) - compressor.perfRGI = new Btwxt::RegularGridInterpolator(gridded_data); - compressor.useBtwxtGrid = true; - - compressor.secondaryHeatExchanger = { dF_TO_dC(10.), dF_TO_dC(15.), 27. }; - - //set everything in its places - setOfSources[0] = compressor; - - } - - else if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_GS3_45HPA_US_SP || presetNum == MODELS_SANCO2_119) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = 65; - setpointFixed = true; - - if (presetNum == MODELS_SANCO2_119) { - tankVolume_L = GAL_TO_L(119); - tankUA_kJperHrC = 9; - } - else { - tankVolume_L = 315; - tankUA_kJperHrC = 7; - if (presetNum == MODELS_SANCO2_GS3_45HPA_US_SP) { - tankSizeFixed = false; - } - } - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.minT = F_TO_C(-25.); - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - compressor.perfMap.reserve(5); - - compressor.perfMap.push_back({ - 17, // Temperature (T_F) - {1650, 5.5, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {3.2, -0.015, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 35, // Temperature (T_F) - {1100, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {3.7, -0.015, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {880, 3.1, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.25, -0.025, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {740, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {6.2, -0.03, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {790, 2, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.15, -0.04, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.hysteresis_dC = 4; - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.maxSetpoint_C = MAXOUTLET_R744; - - std::vector nodeWeights; - nodeWeights.emplace_back(8); - compressor.addTurnOnLogic(std::make_shared("eighth node absolute", nodeWeights, F_TO_C(113), this, true)); - if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_119) { - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(8.2639))); - // Adds a bonus standby logic so the external heater does not cycle, recommended for any external heater with standby - std::vector nodeWeightStandby; - nodeWeightStandby.emplace_back(0); - compressor.standbyLogic = std::make_shared("bottom node absolute", nodeWeightStandby, F_TO_C(113), this, true, std::greater()); - } - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom node absolute", nodeWeights1, F_TO_C(135), this, true, - std::greater(), true)); - compressor.depressesTemperature = false; //no temp depression - - //set everything in its places - setOfSources[0] = compressor; - } - else if (presetNum == MODELS_SANCO2_43) { - numNodes = 96; - tankTemps_C = new double[numNodes]; - setpoint_C = 65; - setpointFixed = true; - - tankVolume_L = 160; - //tankUA_kJperHrC = 10; //0 to turn off - tankUA_kJperHrC = 5; - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.minT = F_TO_C(-25.); - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(5); - - compressor.perfMap.push_back({ - 17, // Temperature (T_F) - {1650, 5.5, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {3.2, -0.015, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 35, // Temperature (T_F) - {1100, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {3.7, -0.015, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {880, 3.1, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.25, -0.025, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {740, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {6.2, -0.03, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {790, 2, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.15, -0.04, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.hysteresis_dC = 4; - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.maxSetpoint_C = MAXOUTLET_R744; - - std::vector nodeWeights; - nodeWeights.emplace_back(4); - std::vector nodeWeightStandby; - nodeWeightStandby.emplace_back(0); - compressor.addTurnOnLogic(std::make_shared("fourth node absolute", nodeWeights, F_TO_C(113), this, true)); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(8.2639))); - compressor.standbyLogic = std::make_shared("bottom node absolute", nodeWeightStandby, F_TO_C(113), this, true, std::greater()); - - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom twelth absolute", nodeWeights1, F_TO_C(135), this, true, - std::greater(), true)); - compressor.depressesTemperature = false; //no temp depression - - //set everything in its places - setOfSources[0] = compressor; - } - else if (presetNum == MODELS_AOSmithHPTU50 || presetNum == MODELS_RheemHBDR2250 || presetNum == MODELS_RheemHBDR4550) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = 171; - tankUA_kJperHrC = 6; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 5.0; - compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); - - // performance map - compressor.perfMap.reserve(3); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(42.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - if (presetNum == MODELS_RheemHBDR2250) { - resistiveElementTop.setupAsResistiveElement(8, 2250); - } - else { - resistiveElementTop.setupAsResistiveElement(8, 4500); - } - resistiveElementTop.isVIP = true; - - //bottom resistor values - if (presetNum == MODELS_RheemHBDR2250) { - resistiveElementBottom.setupAsResistiveElement(0, 2250); - } - else { - resistiveElementBottom.setupAsResistiveElement(0, 4500); - } - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(35); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - - std::vector nodeWeights; - nodeWeights.emplace_back(11); nodeWeights.emplace_back(12); - resistiveElementTop.addTurnOnLogic(std::make_shared("top sixth absolute", nodeWeights, F_TO_C(105), this, true)); - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(28))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - - - } - else if (presetNum == MODELS_AOSmithHPTU66 || presetNum == MODELS_RheemHBDR2265 || presetNum == MODELS_RheemHBDR4565) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - if (presetNum == MODELS_AOSmithHPTU66) { - tankVolume_L = 244.6; - } - else { - tankVolume_L = 221.4; - } - tankUA_kJperHrC = 8; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - // performance map - compressor.perfMap.reserve(3); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(42.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - if (presetNum == MODELS_RheemHBDR2265) { - resistiveElementTop.setupAsResistiveElement(8, 2250); - } - else { - resistiveElementTop.setupAsResistiveElement(8, 4500); - } - resistiveElementTop.isVIP = true; - - //bottom resistor values - if (presetNum == MODELS_RheemHBDR2265) { - resistiveElementBottom.setupAsResistiveElement(0, 2250); - } - else { - resistiveElementBottom.setupAsResistiveElement(0, 4500); - } - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(35); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - - std::vector nodeWeights; - nodeWeights.emplace_back(11); nodeWeights.emplace_back(12); - resistiveElementTop.addTurnOnLogic(std::make_shared("top sixth absolute", nodeWeights, F_TO_C(105), this, true)); - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(31))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_AOSmithHPTU80 || presetNum == MODELS_RheemHBDR2280 || presetNum == MODELS_RheemHBDR4580) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = 299.5; - tankUA_kJperHrC = 9; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - double split = 1.0 / 3.0; - compressor.setCondensity(split, split, split, 0, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(3); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(42.0); - compressor.maxT = F_TO_C(120.0); - compressor.hysteresis_dC = dF_TO_dC(1); - - //top resistor values - if (presetNum == MODELS_RheemHBDR2280) { - resistiveElementTop.setupAsResistiveElement(8, 2250); - } - else { - resistiveElementTop.setupAsResistiveElement(8, 4500); - } - resistiveElementTop.isVIP = true; - - //bottom resistor values - if (presetNum == MODELS_RheemHBDR2280) { - resistiveElementBottom.setupAsResistiveElement(0, 2250); - } - else { - resistiveElementBottom.setupAsResistiveElement(0, 4500); - } - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(35); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - - std::vector nodeWeights; - // nodeWeights.emplace_back(9); nodeWeights.emplace_back(10); - nodeWeights.emplace_back(11); nodeWeights.emplace_back(12); - resistiveElementTop.addTurnOnLogic(std::make_shared("top sixth absolute", nodeWeights, F_TO_C(105), this, true)); - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(35))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_AOSmithHPTU80_DR) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = 283.9; - tankUA_kJperHrC = 9; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {142.6, 2.152, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {6.989258, -0.038320, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {120.14, 2.513, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {8.188, -0.0432, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(42.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(34.1636); - double standbyT = dF_TO_dC(7.1528); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80.108))); - - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(39.9691))); - resistiveElementTop.addTurnOnLogic(HPWH::topThird_absolute(F_TO_C(87))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_AOSmithCAHP120) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(150.0); - - tankVolume_L = GAL_TO_L(111.76); // AOSmith docs say 111.76 - tankUA_kJperHrC = UAf_TO_UAc(3.94); - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0.3, 0.3, 0.2, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - - //From CAHP 120 COP Tests - compressor.perfMap.reserve(3); - - // Tuned on the multiple K167 tests - compressor.perfMap.push_back({ - 50., // Temperature (T_F) - {2010.49966, -4.20966, 0.085395}, // Input Power Coefficients (inputPower_coeffs) - {5.91, -0.026299, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67.5, // Temperature (T_F) - {2171.012, -6.936571, 0.1094962}, // Input Power Coefficients (inputPower_coeffs) - {7.26272, -0.034135, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95., // Temperature (T_F) - {2276.0625, -7.106608, 0.119911}, // Input Power Coefficients (inputPower_coeffs) - {8.821262, -0.042059, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(47.0); //Product documentation says 45F doesn't look like it in CMP-T test// - compressor.maxT = F_TO_C(110.0); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - double wattRE = 6000;//5650.; - resistiveElementTop.setupAsResistiveElement(7, wattRE); - resistiveElementTop.isVIP = true; // VIP is the only source that turns on independently when something else is already heating. - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, wattRE); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - resistiveElementBottom.setCondensity(0.2, 0.8, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.); // Based of CMP test - - //logic conditions for - double compStart = dF_TO_dC(5.25); - double standbyT = dF_TO_dC(5.); //Given CMP_T test - compressor.addTurnOnLogic(HPWH::secondSixth(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - double resistanceStart = 12.; - resistiveElementTop.addTurnOnLogic(HPWH::topThird(resistanceStart)); - resistiveElementBottom.addTurnOnLogic(HPWH::topThird(resistanceStart)); - - resistiveElementTop.addShutOffLogic(HPWH::fifthSixthMaxTemp(F_TO_C(117.))); - resistiveElementBottom.addShutOffLogic(HPWH::secondSixthMaxTemp(F_TO_C(109.))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - //setOfSources[2].followedByHeatSource = &setOfSources[1];; - - setOfSources[0].companionHeatSource = &setOfSources[1]; - setOfSources[1].companionHeatSource = &setOfSources[2]; - - } - else if (MODELS_AOSmithHPTS50 <= presetNum && presetNum <= MODELS_AOSmithHPTS80) - { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - if (presetNum == MODELS_AOSmithHPTS50) { - tankVolume_L = GAL_TO_L(45.6); - tankUA_kJperHrC = 6.403; - } - else if (presetNum == MODELS_AOSmithHPTS66) { - tankVolume_L = GAL_TO_L(67.63); - tankUA_kJperHrC = UAf_TO_UAc(1.5) * 6.403 / UAf_TO_UAc(1.16); - } - else if (presetNum == MODELS_AOSmithHPTS80) { - tankVolume_L = GAL_TO_L(81.94); - tankUA_kJperHrC = UAf_TO_UAc(1.73) * 6.403 / UAf_TO_UAc(1.16); - } - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementTop(this); - HeatSource resistiveElementBottom(this); - - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0, 0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0); - - // performance map - compressor.perfMap.reserve(3); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {66.82, 2.49, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {8.64, -0.0436, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67.5, // Temperature (T_F) - {85.1, 2.38, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {10.82, -0.0551, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {89, 2.62, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {12.52, -0.0534, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(1.); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - resistiveElementTop.setupAsResistiveElement(8, 4500); - resistiveElementTop.isVIP = true; - - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(30.2); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(11.87))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[2]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - } - - else if (presetNum == MODELS_GE2014STDMode) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 6.5; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); - // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); + tankSizeFixed = false; + tankVolume_L = GAL_TO_L(50); + tankUA_kJperHrC = 10; // 0 to turn off - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; + doTempDepression = false; + // should eventually put tankmixes to true when testing progresses + tankMixesOnDraw = false; - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_GE2014STDMode_80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); + numHeatSources = 2; + setOfSources = new HeatSource[numHeatSources]; - tankVolume_L = GAL_TO_L(75.4); - tankUA_kJperHrC = 10.; - - doTempDepression = false; - tankMixesOnDraw = true; + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementTop.setupAsResistiveElement(9, 4500); - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); - compressor.minT = F_TO_C(37); - // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; + // standard logic conditions + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_GE2014) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); + resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); + resistiveElementTop.isVIP = true; - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 6.5; + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; - doTempDepression = false; - tankMixesOnDraw = true; + setOfSources[0].followedByHeatSource = &setOfSources[1]; + } - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); - // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); - - resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; + else if (presetNum == MODELS_StorageTank) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = 52; - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_GE2014_80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(75.4); - tankUA_kJperHrC = 10.; + setpoint_C = 800; - doTempDepression = false; - tankMixesOnDraw = true; + tankSizeFixed = false; + tankVolume_L = GAL_TO_L(80); + tankUA_kJperHrC = 10; // 0 to turn off - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; + doTempDepression = false; + tankMixesOnDraw = false; - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; + //////////////////////////////////////////////////// + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); - // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); + HeatSource extra(this); - resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; + // compressor values + extra.isOn = false; + extra.isVIP = false; + extra.typeOfHeatSource = TYPE_extra; + extra.configuration = HeatSource::CONFIG_WRAPPED; - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; + extra.addTurnOnLogic(HPWH::topThird_absolute(1)); - } - else if (presetNum == MODELS_GE2014_80DR) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(75.4); - tankUA_kJperHrC = 10.; + // initial guess, will get reset based on the input heat vector + extra.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; + setOfSources[0] = extra; + } - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.addTurnOnLogic(HPWH::topThird_absolute(F_TO_C(87))); - // resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); - // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); - - resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); - // resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - // PRESET USING GE2014 DATA - else if (presetNum == MODELS_BWC2020_65) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(64); - tankUA_kJperHrC = 7.6; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); - // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); - - resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - } - // If Rheem Premium - else if (MODELS_Rheem2020Prem40 <= presetNum && presetNum <= MODELS_Rheem2020Prem80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - if (presetNum == MODELS_Rheem2020Prem40) { - tankVolume_L = GAL_TO_L(36.1); - tankUA_kJperHrC = 9.5; - } - else if (presetNum == MODELS_Rheem2020Prem50) { - tankVolume_L = GAL_TO_L(45.1); - tankUA_kJperHrC = 8.55; - } - else if (presetNum == MODELS_Rheem2020Prem65) { - tankVolume_L = GAL_TO_L(58.5); - tankUA_kJperHrC = 10.64; - } - else if (presetNum == MODELS_Rheem2020Prem80) { - tankVolume_L = GAL_TO_L(72.0); - tankUA_kJperHrC = 10.83; - } - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {250, -1.0883, 0.0176}, // Input Power Coefficients (inputPower_coeffs) - {6.7, -0.0087, -0.0002} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) - {7.0, -0.0168, -0.0001} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.0); - compressor.hysteresis_dC = dF_TO_dC(1); - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); - - //logic conditions - double compStart = dF_TO_dC(32); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[1].backupHeatSource = &setOfSources[2]; - setOfSources[2].backupHeatSource = &setOfSources[1]; - - setOfSources[0].followedByHeatSource = &setOfSources[2]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - } - - // If Rheem Build - else if (MODELS_Rheem2020Build40 <= presetNum && presetNum <= MODELS_Rheem2020Build80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - if (presetNum == MODELS_Rheem2020Build40) { - tankVolume_L = GAL_TO_L(36.1); - tankUA_kJperHrC = 9.5; - } - else if (presetNum == MODELS_Rheem2020Build50) { - tankVolume_L = GAL_TO_L(45.1); - tankUA_kJperHrC = 8.55; - } - else if (presetNum == MODELS_Rheem2020Build65) { - tankVolume_L = GAL_TO_L(58.5); - tankUA_kJperHrC = 10.64; - } - else if (presetNum == MODELS_Rheem2020Build80) { - tankVolume_L = GAL_TO_L(72.0); - tankUA_kJperHrC = 10.83; - } - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {220.0, 0.8743, 0.00454}, // Input Power Coefficients (inputPower_coeffs) - { 7.96064, -0.0448, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) - {8.45936, -0.04539, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.hysteresis_dC = dF_TO_dC(1); - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.0); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); - - //logic conditions - double compStart = dF_TO_dC(30); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[1].backupHeatSource = &setOfSources[2]; - setOfSources[2].backupHeatSource = &setOfSources[1]; - - setOfSources[0].followedByHeatSource = &setOfSources[2]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - } - else if (MODELS_RheemPlugInShared40 <= presetNum && presetNum <= MODELS_RheemPlugInShared80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - - if (presetNum == MODELS_RheemPlugInShared40) { - tankVolume_L = GAL_TO_L(36.0); - tankUA_kJperHrC = 9.5; - setpoint_C = F_TO_C(140.0); - } - else if (presetNum == MODELS_RheemPlugInShared50) { - tankVolume_L = GAL_TO_L(45.0); - tankUA_kJperHrC = 8.55; - setpoint_C = F_TO_C(140.0); - } - else if (presetNum == MODELS_RheemPlugInShared65) { - tankVolume_L = GAL_TO_L(58.5); - tankUA_kJperHrC = 10.64; - setpoint_C = F_TO_C(127.0); - } - else if (presetNum == MODELS_RheemPlugInShared80) { - tankVolume_L = GAL_TO_L(72.0); - tankUA_kJperHrC = 10.83; - setpoint_C = F_TO_C(127.0); - } - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - HeatSource compressor(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {250, -1.0883, 0.0176}, // Input Power Coefficients (inputPower_coeffs) - {6.7, -0.0087, -0.0002} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) - {7.0, -0.0168, -0.0001} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.0); - compressor.hysteresis_dC = dF_TO_dC(1); - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //logic conditions - double compStart = dF_TO_dC(32); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - //set everything in its places - setOfSources[0] = compressor; - } - else if (presetNum == MODELS_RheemPlugInDedicated40 || presetNum == MODELS_RheemPlugInDedicated50) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_RheemPlugInDedicated40) { - tankVolume_L = GAL_TO_L(36); - tankUA_kJperHrC = 5.5; - } - else if (presetNum == MODELS_RheemPlugInDedicated50) { - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 6.33; - } - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 1; - setOfSources = new HeatSource[numHeatSources]; - HeatSource compressor(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0., 0., 0., 0.); - - compressor.perfMap.reserve(2); - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {528.91, 4.8988, 0.0}, // Input Power Coefficients (inputPower_coeffs) - { 4.3943, -0.012443, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 95, // Temperature (T_F) - {494.03, 7.7266, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.48189, -0.01604, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.hysteresis_dC = dF_TO_dC(1); - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.0); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - - - //logic conditions - double compStart = dF_TO_dC(20); - double standbyT = dF_TO_dC(9); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - //set everything in its places - setOfSources[0] = compressor; - } - else if (presetNum == MODELS_RheemHB50) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 7; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 47, // Temperature (T_F) - {280, 4.97342, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.634009, -0.029485, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {280, 5.35992, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {6.3, -0.03, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.hysteresis_dC = dF_TO_dC(1); - compressor.minT = F_TO_C(40.0); - compressor.maxT = F_TO_C(120.0); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4200); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 2250); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - double compStart = dF_TO_dC(38); - double standbyT = dF_TO_dC(13.2639); - compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); - compressor.addTurnOnLogic(HPWH::standby(standbyT)); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(76.7747))); - - resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); - - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_Stiebel220E) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127); - - tankVolume_L = GAL_TO_L(56); - //tankUA_kJperHrC = 10; //0 to turn off - tankUA_kJperHrC = 9; - - doTempDepression = false; - tankMixesOnDraw = false; - - numHeatSources = 2; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElement(this); - - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; + // basic compressor tank for testing + else if (presetNum == MODELS_basicIntegrated) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = 50; - resistiveElement.setupAsResistiveElement(0, 1500); - resistiveElement.hysteresis_dC = dF_TO_dC(0); + tankSizeFixed = false; + tankVolume_L = 120; + tankUA_kJperHrC = 10; // 0 to turn off + // tankUA_kJperHrC = 0; //0 to turn off - compressor.setCondensity(0, 0.12, 0.22, 0.22, 0.22, 0.22, 0, 0, 0, 0, 0, 0); + doTempDepression = false; + tankMixesOnDraw = false; - compressor.perfMap.reserve(2); + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {295.55337, 2.28518, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.744118, -0.025946, 0.0} // COP Coefficients (COP_coeffs) - }); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + HeatSource compressor(this); - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {282.2126, 2.82001, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {8.012112, -0.039394, 0.0} // COP Coefficients (COP_coeffs) - }); + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementTop.setupAsResistiveElement(9, 4500); - compressor.minT = F_TO_C(32.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = 0; //no hysteresis - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - compressor.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(6.5509))); - compressor.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - - compressor.depressesTemperature = false; //no temp depression - - //set everything in its places - setOfSources[0] = compressor; - setOfSources[1] = resistiveElement; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[0].backupHeatSource = &setOfSources[1]; + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // standard logic conditions + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(20)); + resistiveElementBottom.addTurnOnLogic(HPWH::standby(15)); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(20)); + resistiveElementTop.isVIP = true; + + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; - } - else if (presetNum == MODELS_Generic1) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(50); - tankUA_kJperHrC = 9; - doTempDepression = false; - tankMixesOnDraw = true; - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {472.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {2.942642, -0.0125954, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {439.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {3.95076, -0.01638033, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(45.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(8, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40.0))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(80))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(110))); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(35))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_Generic2) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(50); - tankUA_kJperHrC = 7.5; - doTempDepression = false; - tankMixesOnDraw = true; - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {272.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {4.042642, -0.0205954, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {239.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.25076, -0.02638033, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(40.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(60))); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(80))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(40))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_Generic3) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(50); - tankUA_kJperHrC = 5; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {172.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.242642, -0.0285954, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 67, // Temperature (T_F) - {139.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {6.75076, -0.03638033, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(35.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4500); - resistiveElementBottom.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(55))); - - resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(60))); - - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(40))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = compressor; - setOfSources[2] = resistiveElementBottom; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (presetNum == MODELS_UEF2generic) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 6.5; - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {4.29, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - {5.61, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(37.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(18.6605))); - - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); - - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - } - else if (MODELS_AWHSTier3Generic40 <= presetNum && presetNum <= MODELS_AWHSTier3Generic80) { - numNodes = 12; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(127.0); - - if (presetNum == MODELS_AWHSTier3Generic40) { - tankVolume_L = GAL_TO_L(36.1); - tankUA_kJperHrC = 5; - } - else if (presetNum == MODELS_AWHSTier3Generic50) { - tankVolume_L = GAL_TO_L(45); - tankUA_kJperHrC = 6.5; - } - else if (presetNum == MODELS_AWHSTier3Generic65) { - tankVolume_L = GAL_TO_L(64); - tankUA_kJperHrC = 7.6; - } - else if (presetNum == MODELS_AWHSTier3Generic80) { - tankVolume_L = GAL_TO_L(75.4); - tankUA_kJperHrC = 10.; - } - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("Incorrect model specification. \n"); - } - return HPWH_ABORT; - } - - doTempDepression = false; - tankMixesOnDraw = true; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - - //compressor values - compressor.isOn = false; - compressor.isVIP = false; - compressor.typeOfHeatSource = TYPE_compressor; - - double split = 1.0 / 4.0; - compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); - - //voltex60 tier 1 values - compressor.perfMap.reserve(2); - - compressor.perfMap.push_back({ - 50, // Temperature (T_F) - {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) - //{5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - {5.22288834, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.perfMap.push_back({ - 70, // Temperature (T_F) - {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) - //{7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - {6.84694165, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) - }); - - compressor.minT = F_TO_C(42.0); - compressor.maxT = F_TO_C(120.); - compressor.hysteresis_dC = dF_TO_dC(2); - compressor.configuration = HeatSource::CONFIG_WRAPPED; - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - //top resistor values - resistiveElementTop.setupAsResistiveElement(6, 4500); - resistiveElementTop.isVIP = true; - - //bottom resistor values - resistiveElementBottom.setupAsResistiveElement(0, 4000); - resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); - resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); - - //logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); - resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); - compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); - compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); - resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); - resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - } - // If a the model is the TamOMatic, HotTam, Generic... This model is scalable. - else if (presetNum == MODELS_TamScalable_SP) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - canScale = true; // a fully scallable model - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; - tankUA_kJperHrC = 7; - setTankSize_adjustUA(600., UNITS_GAL); - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.isMultipass = false; - compressor.perfMap.reserve(1); - compressor.hysteresis_dC = 0; - - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = numNodes - 1; - - //Defrost Derate - compressor.setupDefrostMap(); - - //Perfmap for input power and COP made from data for poor preforming modeled to be scalled for this model - std::vector inputPwr_coeffs = { 13.6, 0.00995, -0.0342, -0.014, -0.000110, 0.00026, 0.000232, 0.000195, -0.00034, 5.30E-06, 2.3600E-06}; - std::vector COP_coeffs = { 1.945, 0.0412, -0.0112, -0.00161, 0.0000492, 0.0000348, -0.0000323, -0.000166, 0.0000112, 0.0000392, -3.52E-07}; - - compressor.perfMap.push_back({ - 105, // Temperature (T_F) - inputPwr_coeffs, // Input Power Coefficients (inputPower_coeffs - COP_coeffs // COP Coefficients (COP_coeffs) - }); - - //logic conditions - compressor.minT = F_TO_C(40.); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(15), this)); - - //lowT cutoff - std::vector nodeWeights1; - nodeWeights1.emplace_back(1); - compressor.addShutOffLogic(std::make_shared("bottom node", nodeWeights1, dF_TO_dC(15.), this, false, - std::greater(), true)); - compressor.depressesTemperature = false; //no temp depression - - - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - resistiveElementBottom.setupAsResistiveElement(0, 30000); - resistiveElementTop.setupAsResistiveElement(9, 30000); - - //top resistor values - //standard logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(15))); - resistiveElementTop.isVIP = true; - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - } - else if (presetNum == MODELS_Scalable_MP) { - numNodes = 24; - tankTemps_C = new double[numNodes]; - setpoint_C = F_TO_C(135.0); - tankSizeFixed = false; - canScale = true; // a fully scallable model - - doTempDepression = false; - tankMixesOnDraw = false; - - tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important - tankUA_kJperHrC = 7; - - numHeatSources = 3; - setOfSources = new HeatSource[numHeatSources]; - - HeatSource compressor(this); - compressor.isOn = false; - compressor.isVIP = true; - compressor.typeOfHeatSource = TYPE_compressor; - compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); - compressor.configuration = HeatSource::CONFIG_EXTERNAL; - compressor.perfMap.reserve(1); - compressor.hysteresis_dC = 0; - compressor.externalOutletHeight = 0; - compressor.externalInletHeight = (int)(numNodes / 3.) - 1; - - //logic conditions - std::vector nodeWeights; - nodeWeights.emplace_back(4); - compressor.addTurnOnLogic(std::make_shared("fourth node", nodeWeights, dF_TO_dC(5.), this, false)); - - std::vector nodeWeights1; - nodeWeights1.emplace_back(4); - compressor.addShutOffLogic(std::make_shared("fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); - compressor.depressesTemperature = false; //no temp depression - - //Defrost Derate - compressor.setupDefrostMap(); - - //logic conditions - compressor.minT = F_TO_C(40.); - compressor.maxT = F_TO_C(105.); - compressor.maxSetpoint_C = MAXOUTLET_R134A; - - setTankSize_adjustUA(600., UNITS_GAL); - compressor.mpFlowRate_LPS = GPM_TO_LPS(25.); - compressor.perfMap.push_back({ - 100, // Temperature (T_F) - - { 12.4, 0.00739, -0.0410, 0.0, 0.000578, 0.0000696}, // Input Power Coefficients (inputPower_coeffs) - - { 1.20, 0.0333, 0.00191, 0.000283, 0.0000496, -0.000440} // COP Coefficients (COP_coeffs) - - }); - - HeatSource resistiveElementBottom(this); - HeatSource resistiveElementTop(this); - resistiveElementBottom.setupAsResistiveElement(0, 30000); - resistiveElementTop.setupAsResistiveElement(9, 30000); - - //top resistor values - //standard logic conditions - resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(30))); - resistiveElementTop.isVIP = true; - - //set everything in its places - setOfSources[0] = resistiveElementTop; - setOfSources[1] = resistiveElementBottom; - setOfSources[2] = compressor; - - //and you have to do this after putting them into setOfSources, otherwise - //you don't get the right pointers - setOfSources[2].backupHeatSource = &setOfSources[1]; - setOfSources[1].backupHeatSource = &setOfSources[2]; - - setOfSources[0].followedByHeatSource = &setOfSources[1]; - setOfSources[1].followedByHeatSource = &setOfSources[2]; - - setOfSources[0].companionHeatSource = &setOfSources[2]; - } - - else { - if (hpwhVerbosity >= VRB_reluctant) { - msg("You have tried to select a preset model which does not exist. \n"); - } - return HPWH_ABORT; - } - - //start tank off at setpoint - resetTankToSetpoint(); - - // initialize nextTankTemps_C - nextTankTemps_C = new double[numNodes]; - - hpwhModel = presetNum; - - //calculate oft-used derived values - calcDerivedValues(); - - if (checkInputs() == HPWH_ABORT) { - return HPWH_ABORT; - } - - isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { - isHeating = true; - } - setOfSources[i].sortPerformanceMap(); - } - - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { - msg("heat source %d: %p \n", i, &setOfSources[i]); - } - msg("\n\n"); - } - - simHasFailed = false; - return 0; //successful init returns 0 -} //end HPWHinit_presets + double oneSixth = 1.0 / 6.0; + compressor.setCondensity( + oneSixth, oneSixth, oneSixth, oneSixth, oneSixth, oneSixth, 0, 0, 0, 0, 0, 0); + // GE tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {0.290 * 1000, + 0.00159 * 1000, + 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.49, -0.0187, -0.0000133} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {0.375 * 1000, + 0.00121 * 1000, + 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {5.60, -0.0252, 0.00000254} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = 0; + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(4); + compressor.configuration = HeatSource::CONFIG_WRAPPED; // wrapped around tank + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.addTurnOnLogic(HPWH::bottomThird(20)); + compressor.addTurnOnLogic(HPWH::standby(15)); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = compressor; + setOfSources[2] = resistiveElementBottom; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + + // simple external style for testing + else if (presetNum == MODELS_externalTest) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = 50; + + tankSizeFixed = false; + tankVolume_L = 120; + // tankUA_kJperHrC = 10; //0 to turn off + tankUA_kJperHrC = 0; // 0 to turn off + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + // GE tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {0.290 * 1000, + 0.00159 * 1000, + 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.49, -0.0187, -0.0000133} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {0.375 * 1000, + 0.00121 * 1000, + 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {5.60, -0.0252, 0.00000254} // COP Coefficients (COP_coeffs) + }); + + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = 0; // no hysteresis + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.addTurnOnLogic(HPWH::bottomThird(20)); + compressor.addTurnOnLogic(HPWH::standby(15)); + + // lowT cutoff + compressor.addShutOffLogic(HPWH::bottomNodeMaxTemp(20, true)); + + // set everything in its places + setOfSources[0] = compressor; + } + // voltex 60 gallon + else if (presetNum == MODELS_AOSmithPHPT60) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 215.8; + tankUA_kJperHrC = 7.31; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 5.0; + compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {0.467 * 1000, + 0.00281 * 1000, + 0.0000072 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.86, -0.0222, -0.00001} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {0.541 * 1000, + 0.00147 * 1000, + 0.0000176 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {6.58, -0.0392, 0.0000407} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(45.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(4); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4250); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 2000); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // logic conditions + double compStart = dF_TO_dC(43.6); + double standbyT = dF_TO_dC(23.8); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(25.0))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = compressor; + setOfSources[2] = resistiveElementBottom; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_AOSmithPHPT80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 283.9; + tankUA_kJperHrC = 8.8; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 5.0; + compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {0.467 * 1000, + 0.00281 * 1000, + 0.0000072 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.86, -0.0222, -0.00001} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {0.541 * 1000, + 0.00147 * 1000, + 0.0000176 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {6.58, -0.0392, 0.0000407} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(45.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(4); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4250); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 2000); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // logic conditions + double compStart = dF_TO_dC(43.6); + double standbyT = dF_TO_dC(23.8); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(25.0))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = compressor; + setOfSources[2] = resistiveElementBottom; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_GE2012) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 172; + tankUA_kJperHrC = 6.8; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 5.0; + compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {0.3 * 1000, + 0.00159 * 1000, + 0.00000107 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.7, -0.0210, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {0.378 * 1000, + 0.00121 * 1000, + 0.00000216 * 1000}, // Input Power Coefficients (inputPower_coeffs) + {4.8, -0.0167, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(45.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(4); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4200); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4200); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // logic conditions + // double compStart = dF_TO_dC(24.4); + double compStart = dF_TO_dC(40.0); + double standbyT = dF_TO_dC(5.2); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(66))); + compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(compStart)); + // resistiveElementBottom.addShutOffLogic(HPWH::lowTreheat(lowTcutoff)); + // GE element never turns off? + + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(31.0))); + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(28.0))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = compressor; + setOfSources[2] = resistiveElementBottom; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + // If a Colmac single pass preset cold weather or not + else if (MODELS_ColmacCxV_5_SP <= presetNum && presetNum <= MODELS_ColmacCxA_30_SP) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.perfMap.reserve(1); + compressor.hysteresis_dC = 0; + + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + // logic conditions + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(15), this)); + + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic(std::make_shared( + "bottom node", nodeWeights1, dF_TO_dC(15.), this, false, std::greater(), true)); + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + if (presetNum == MODELS_ColmacCxV_5_SP) { + setTankSize_adjustUA(200., UNITS_GAL); + // logic conditions + compressor.minT = F_TO_C(-4.0); + compressor.maxSetpoint_C = MAXOUTLET_R410A; + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {4.9621645063, + -0.0096084144, + -0.0095647009, + -0.0115911960, + -0.0000788517, + 0.0000886176, + 0.0001114142, + 0.0001832377, + -0.0000451308, + 0.0000411975, + 0.0000003535}, // Input Power Coefficients (inputPower_coeffs) + + {3.8189922420, + 0.0569412237, + -0.0320101962, + -0.0012859036, + 0.0000576439, + 0.0001101241, + -0.0000352368, + -0.0002630301, + -0.0000509365, + 0.0000369655, + -0.0000000606} // COP Coefficients (COP_coeffs) + }); + } + else { + // logic conditions + compressor.minT = F_TO_C(40.); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + if (presetNum == MODELS_ColmacCxA_10_SP) { + setTankSize_adjustUA(500., UNITS_GAL); + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {5.9786974243, + 0.0194445115, + -0.0077802278, + 0.0053809029, + -0.0000334832, + 0.0001864310, + 0.0001190540, + 0.0000040405, + -0.0002538279, + -0.0000477652, + 0.0000014101}, // Input Power Coefficients (inputPower_coeffs) + + {3.6128563086, + 0.0527064498, + -0.0278198945, + -0.0070529748, + 0.0000934705, + 0.0000781711, + -0.0000359215, + -0.0002223206, + 0.0000359239, + 0.0000727189, + -0.0000005037} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_15_SP) { + setTankSize_adjustUA(600., UNITS_GAL); + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {15.5869846555, + -0.0044503761, + -0.0577941202, + -0.0286911185, + -0.0000803325, + 0.0003399817, + 0.0002009576, + 0.0002494761, + -0.0000595773, + 0.0001401800, + 0.0000004312}, // Input Power Coefficients (inputPower_coeffs) + + {1.6643120405, + 0.0515623393, + -0.0110239930, + 0.0041514430, + 0.0000481544, + 0.0000493424, + -0.0000262721, + -0.0002356218, + -0.0000989625, + -0.0000070572, + 0.0000004108} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_20_SP) { + setTankSize_adjustUA(800., UNITS_GAL); + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {23.0746692231, + 0.0248584608, + -0.1417927282, + -0.0253733303, + -0.0004882754, + 0.0006508079, + 0.0002139934, + 0.0005552752, + -0.0002026772, + 0.0000607338, + 0.0000021571}, // Input Power Coefficients (inputPower_coeffs) + + {1.7692660120, + 0.0525134783, + -0.0081102040, + -0.0008715405, + 0.0001274956, + 0.0000369489, + -0.0000293775, + -0.0002778086, + -0.0000095067, + 0.0000381186, + -0.0000003135} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_25_SP) { + setTankSize_adjustUA(1000., UNITS_GAL); + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {20.4185336541, + -0.0236920615, + -0.0736219119, + -0.0260385082, + -0.0005048074, + 0.0004940510, + 0.0002632660, + 0.0009820050, + -0.0000223587, + 0.0000885101, + 0.0000005649}, // Input Power Coefficients (inputPower_coeffs) + + {0.8942843854, + 0.0677641611, + -0.0001582927, + 0.0048083998, + 0.0001196407, + 0.0000334921, + -0.0000378740, + -0.0004146401, + -0.0001213363, + -0.0000031856, + 0.0000006306} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_30_SP) { + setTankSize_adjustUA(1200., UNITS_GAL); + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {11.3687485772, + -0.0207292362, + 0.0496254077, + -0.0038394967, + -0.0005991041, + 0.0001304318, + 0.0003099774, + 0.0012092717, + -0.0001455509, + -0.0000893889, + 0.0000018221}, // Input Power Coefficients (inputPower_coeffs) + + {4.4170108542, + 0.0596384263, + -0.0416104579, + -0.0017199887, + 0.0000774664, + 0.0001521934, + -0.0000251665, + -0.0003289731, + -0.0000801823, + 0.0000325972, + 0.0000002705} // COP Coefficients (COP_coeffs) + }); + } + } // End if MODELS_ColmacCxV_5_SP + + // set everything in its places + setOfSources[0] = compressor; + } + + // if colmac multipass + else if (MODELS_ColmacCxV_5_MP <= presetNum && presetNum <= MODELS_ColmacCxA_30_MP) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.perfMap.reserve(1); + compressor.hysteresis_dC = 0; + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = (int)(numNodes / 3.) - 1; + + // logic conditions + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(5.), this)); + + std::vector nodeWeights1; + nodeWeights1.emplace_back(4); + compressor.addShutOffLogic(std::make_shared( + "fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); + + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + if (presetNum == MODELS_ColmacCxV_5_MP) { + setTankSize_adjustUA(200., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS( + 9.); // https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf + + // logic conditions + compressor.minT = F_TO_C(-4.0); + compressor.maxT = F_TO_C(105.); + compressor.maxSetpoint_C = MAXOUTLET_R410A; + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {5.8438525529, + 0.0003288231, + -0.0494255840, + -0.0000386642, + 0.0004385362, + 0.0000647268}, // Input Power Coefficients (inputPower_coeffs) + + {0.6679056901, + 0.0499777846, + 0.0251828292, + 0.0000699764, + -0.0001552229, + -0.0002911167} // COP Coefficients (COP_coeffs) + }); + } + else { + // logic conditions + compressor.minT = F_TO_C(40.); + compressor.maxT = F_TO_C(105.); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + if (presetNum == MODELS_ColmacCxA_10_MP) { + setTankSize_adjustUA(500., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(18.); + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {8.6918824405, + 0.0136666667, + -0.0548348214, + -0.0000208333, + 0.0005301339, + -0.0000250000}, // Input Power Coefficients (inputPower_coeffs) + + {0.6944181117, + 0.0445926666, + 0.0213188804, + 0.0001172913, + -0.0001387694, + -0.0002365885} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_15_MP) { + setTankSize_adjustUA(600., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(26.); + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {12.4908723958, + 0.0073988095, + -0.0411417411, + 0.0000000000, + 0.0005789621, + 0.0000696429}, // Input Power Coefficients (inputPower_coeffs) + + {1.2846349520, + 0.0334658309, + 0.0019121906, + 0.0002840970, + 0.0000497136, + -0.0004401737} // COP Coefficients (COP_coeffs) + + }); + } + else if (presetNum == MODELS_ColmacCxA_20_MP) { + setTankSize_adjustUA(800., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS( + 36.); // https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf + + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {14.4893345424, + 0.0355357143, + -0.0476593192, + -0.0002916667, + 0.0006120954, + 0.0003607143}, // Input Power Coefficients (inputPower_coeffs) + + {1.2421582831, + 0.0450256569, + 0.0051234755, + 0.0001271296, + -0.0000299981, + -0.0002910606} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_25_MP) { + setTankSize_adjustUA(1000., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(32.); + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {14.5805808222, + 0.0081934524, + -0.0216169085, + -0.0001979167, + 0.0007376535, + 0.0004955357}, // Input Power Coefficients (inputPower_coeffs) + + {2.0013175767, + 0.0576617432, + -0.0130480870, + 0.0000856818, + 0.0000610760, + -0.0003684106} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_ColmacCxA_30_MP) { + setTankSize_adjustUA(1200., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(41.); + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {14.5824911644, + 0.0072083333, + -0.0278055246, + -0.0002916667, + 0.0008841378, + 0.0008125000}, // Input Power Coefficients (inputPower_coeffs) + + {2.6996807527, + 0.0617507969, + -0.0220966420, + 0.0000336149, + 0.0000890989, + -0.0003682431} // COP Coefficients (COP_coeffs) + }); + } + } + + // set everything in its places + setOfSources[0] = compressor; + } + // If Nyle single pass preset + else if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_C_SP) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + // HeatSource resistiveElement(this); + + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.extrapolationMethod = EXTRAP_NEAREST; + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.perfMap.reserve(1); + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + // logic conditions + if (MODELS_NyleC25A_SP <= presetNum && + presetNum <= MODELS_NyleC250A_SP) { // If not cold weather package + compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package + } + else { + compressor.minT = F_TO_C(35.); // Min air temperature WITH Cold Weather Package + } + compressor.maxT = F_TO_C(120.0); // Max air temperature + compressor.hysteresis_dC = 0; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // Defines the maximum outlet temperature at the a low air temperature + compressor.maxOut_at_LowT.outT_C = F_TO_C(140.); + compressor.maxOut_at_LowT.airT_C = F_TO_C(40.); + + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(15), this, false)); + + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic(std::make_shared( + "bottom node", nodeWeights1, dF_TO_dC(15.), this, false, std::greater(), true)); + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + // Perfmaps for each compressor size + if (presetNum == MODELS_NyleC25A_SP) { + setTankSize_adjustUA(200., UNITS_GAL); + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {4.060120364, + -0.020584279, + -0.024201054, + -0.007023945, + 0.000017461, + 0.000110366, + 0.000060338, + 0.000120015, + 0.000111068, + 0.000138907, + -0.000001569}, // Input Power Coefficients (inputPower_coeffs) + + {0.462979529, + 0.065656840, + 0.001077377, + 0.003428059, + 0.000243692, + 0.000021522, + 0.000005143, + -0.000384778, + -0.000404744, + -0.000036277, + 0.000001900} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_NyleC60A_SP || presetNum == MODELS_NyleC60A_C_SP) { + setTankSize_adjustUA(300., UNITS_GAL); + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {-0.1180905709, + 0.0045354306, + 0.0314990479, + -0.0406839757, + 0.0002355294, + 0.0000818684, + 0.0001943834, + -0.0002160871, + 0.0003053633, + 0.0003612413, + -0.0000035912}, // Input Power Coefficients (inputPower_coeffs) + + {6.8205043418, + 0.0860385185, + -0.0748330699, + -0.0172447955, + 0.0000510842, + 0.0002187441, + -0.0000321036, + -0.0003311463, + -0.0002154270, + 0.0001307922, + 0.0000005568} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_NyleC90A_SP || presetNum == MODELS_NyleC90A_C_SP) { + setTankSize_adjustUA(400., UNITS_GAL); + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {13.27612215047, + -0.01014009337, + -0.13401028549, + -0.02325705976, + -0.00032515646, + 0.00040270625, + 0.00001988733, + 0.00069451670, + 0.00069067890, + 0.00071091372, + -0.00000854352}, // Input Power Coefficients (inputPower_coeffs) + + {1.49112327987, + 0.06616282153, + 0.00715307252, + -0.01269458185, + 0.00031448571, + 0.00001765313, + 0.00006002498, + -0.00045661397, + -0.00034003896, + -0.00004327766, + 0.00000176015} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_NyleC125A_SP || presetNum == MODELS_NyleC125A_C_SP) { + setTankSize_adjustUA(500., UNITS_GAL); + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {-3.558277209, + -0.038590968, + 0.136307181, + -0.016945699, + 0.000983753, + -5.18201E-05, + 0.000476904, + -0.000514211, + -0.000359172, + 0.000266509, + -1.58646E-07}, // Input Power Coefficients (inputPower_coeffs) + + {4.889555031, + 0.117102769, + -0.060005795, + -0.011871234, + -1.79926E-05, + 0.000207293, + -1.4452E-05, + -0.000492486, + -0.000376814, + 7.85911E-05, + 1.47884E-06} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_NyleC185A_SP || presetNum == MODELS_NyleC185A_C_SP) { + setTankSize_adjustUA(800., UNITS_GAL); + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {18.58007733, + -0.215324777, + -0.089782421, + 0.01503161, + 0.000332503, + 0.000274216, + 2.70498E-05, + 0.001387914, + 0.000449199, + 0.000829578, + -5.28641E-06}, // Input Power Coefficients (inputPower_coeffs) + + {-0.629432348, + 0.181466663, + 0.00044047, + 0.012104957, + -6.61515E-05, + 9.29975E-05, + 9.78042E-05, + -0.000872708, + -0.001013945, + -0.00021852, + 5.55444E-06} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_NyleC250A_SP || presetNum == MODELS_NyleC250A_C_SP) { + setTankSize_adjustUA(800., UNITS_GAL); + + compressor.perfMap.push_back({ + 90, // Temperature (T_F) + + {-13.89057656, + 0.025902417, + 0.304250541, + 0.061695153, + -0.001474249, + -0.001126845, + -0.000220192, + 0.001241026, + 0.000571009, + -0.000479282, + 9.04063E-06}, // Input Power Coefficients (inputPower_coeffs) + + {7.443904067, + 0.185978755, + -0.098481635, + -0.002500073, + 0.000127658, + 0.000444321, + 0.000139547, + -0.001000195, + -0.001140199, + -8.77557E-05, + 4.87405E-06} // COP Coefficients (COP_coeffs) + }); + } + + // set everything in its places + setOfSources[0] = compressor; + } + + // If Nyle multipass presets + else if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_C_MP) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.extrapolationMethod = EXTRAP_NEAREST; + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.hysteresis_dC = 0; + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = (int)(numNodes / 3.) - 1; + + // logic conditions//logic conditions + if (MODELS_NyleC60A_MP <= presetNum && + presetNum <= MODELS_NyleC250A_MP) { // If not cold weather package + compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package + } + else { + compressor.minT = F_TO_C(35.); // Min air temperature WITH Cold Weather Package + } + compressor.maxT = F_TO_C(130.0); // Max air temperature + compressor.maxSetpoint_C = F_TO_C(160.); + + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(5.), this)); + + std::vector nodeWeights1; + nodeWeights1.emplace_back(4); + compressor.addShutOffLogic(std::make_shared( + "fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + // Performance grid + compressor.perfGrid.reserve(2); + compressor.perfGridValues.reserve(2); + + // Nyle MP models are all on the same grid axes + compressor.perfGrid.push_back({40., 60., 80., 90.}); // Grid Axis 1 Tair (F) + compressor.perfGrid.push_back({40., 60., 80., 100., 130., 150.}); // Grid Axis 2 Tin (F) + + if (presetNum == MODELS_NyleC60A_MP || presetNum == MODELS_NyleC60A_C_MP) { + setTankSize_adjustUA(360., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(13.); + if (presetNum == MODELS_NyleC60A_C_MP) { + compressor.resDefrost = { + 4.5, // inputPwr_kW; + 5.0, // constTempLift_dF; + 40.0 // onBelowT_F + }; + } + // Grid values in long format, table 1, input power (W) + compressor.perfGridValues.push_back({3.64, 4.11, 4.86, 5.97, 8.68, 9.95, 3.72, 4.27, + 4.99, 6.03, 8.55, 10.02, 3.98, 4.53, 5.24, 6.24, + 8.54, 9.55, 4.45, 4.68, 5.37, 6.34, 8.59, 9.55}); + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {3.362637363, 2.917274939, 2.407407407, 1.907872697, 1.296082949, 1.095477387, + 4.438172043, 3.772833724, 3.132264529, 2.505804312, 1.678362573, 1.386227545, + 5.467336683, 4.708609272, 3.921755725, 3.169871795, 2.165105386, 1.860732984, + 5.512359551, 5.153846154, 4.290502793, 3.417981073, 2.272409779, 1.927748691}); + } + else if (presetNum == MODELS_NyleC90A_MP || presetNum == MODELS_NyleC90A_C_MP) { + setTankSize_adjustUA(480., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(20.); + if (presetNum == MODELS_NyleC90A_C_MP) { + compressor.resDefrost = { + 5.4, // inputPwr_kW; + 5.0, // constTempLift_dF; + 40.0 // onBelowT_F + }; + } + // Grid values in long format, table 1, input power (W) + compressor.perfGridValues.push_back( + {4.41, 6.04, 7.24, 9.14, 12.23, 14.73, 4.78, 6.61, 7.74, 9.40, 12.47, 14.75, + 5.51, 6.66, 8.44, 9.95, 13.06, 15.35, 6.78, 7.79, 8.81, 10.01, 11.91, 13.35}); + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {4.79138322, 3.473509934, 2.801104972, 2.177242888, 1.569910057, 1.272233537, + 6.071129707, 4.264750378, 3.536175711, 2.827659574, 2.036086608, 1.666440678, + 7.150635209, 5.659159159, 4.305687204, 3.493467337, 2.487748851, 2.018241042, + 6.750737463, 5.604621309, 4.734392736, 3.94005994, 3.04534005, 2.558801498}); + } + else if (presetNum == MODELS_NyleC125A_MP || presetNum == MODELS_NyleC125A_C_MP) { + setTankSize_adjustUA(600., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(28.); + if (presetNum == MODELS_NyleC125A_C_MP) { + compressor.resDefrost = { + 9.0, // inputPwr_kW; + 5.0, // constTempLift_dF; + 40.0 // onBelowT_F + }; + } + // Grid values in long format, table 1, input power (W) + compressor.perfGridValues.push_back( + {6.4, 7.72, 9.65, 12.54, 20.54, 24.69, 6.89, 8.28, 10.13, 12.85, 19.75, 24.39, + 7.69, 9.07, 10.87, 13.44, 19.68, 22.35, 8.58, 9.5, 11.27, 13.69, 19.72, 22.4}); + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {4.2390625, 3.465025907, 2.718134715, 2.060606061, 1.247809153, 1.016605913, + 5.374455733, 4.352657005, 3.453109576, 2.645136187, 1.66278481, 1.307093071, + 6.503250975, 5.276736494, 4.229070837, 3.27827381, 2.113821138, 1.770469799, + 6.657342657, 5.749473684, 4.612244898, 3.542731921, 2.221095335, 1.816964286}); + } + else if (presetNum == MODELS_NyleC185A_MP || presetNum == MODELS_NyleC185A_C_MP) { + setTankSize_adjustUA(960., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(40.); + if (presetNum == MODELS_NyleC185A_C_MP) { + compressor.resDefrost = { + 7.2, // inputPwr_kW; + 5.0, // constTempLift_dF; + 40.0 // onBelowTemp_F + }; + } + // Grid values in long format, table 1, input power (W) + compressor.perfGridValues.push_back( + {7.57, 11.66, 14.05, 18.3, 25.04, 30.48, 6.99, 10.46, 14.28, 18.19, 26.24, 32.32, + 7.87, 12.04, 15.02, 18.81, 25.99, 31.26, 8.15, 12.46, 15.17, 18.95, 26.23, 31.62}); + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {5.531043593, 3.556603774, 2.918149466, 2.214754098, 1.590255591, 1.291010499, + 8.010014306, 5.258126195, 3.778711485, 2.916437603, 1.964176829, 1.56404703, + 9.65819568, 6.200166113, 4.792276964, 3.705475811, 2.561369758, 2.05950096, + 10.26993865, 6.350722311, 5.04218853, 3.841688654, 2.574151735, 2.025616698}); + } + else if (presetNum == MODELS_NyleC250A_MP || presetNum == MODELS_NyleC250A_C_MP) { + setTankSize_adjustUA(960., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(50.); + if (presetNum == MODELS_NyleC250A_C_MP) { + compressor.resDefrost = { + 18.0, // inputPwr_kW; + 5.0, // constTempLift_dF; + 40.0 // onBelowT_F + }; + } + // Grid values in long format, table 1, input power (W) + compressor.perfGridValues.push_back({10.89, 12.23, 13.55, 14.58, 15.74, 16.72, + 11.46, 13.76, 15.97, 17.79, 20.56, 22.50, + 10.36, 14.66, 18.07, 21.23, 25.81, 29.01, + 8.67, 15.05, 18.76, 21.87, 26.63, 30.02}); + + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {5.81818181, 4.50040883, 3.69667896, 3.12414266, 2.38500635, 1.93540669, + 7.24520069, 5.50145348, 4.39323732, 3.67734682, 2.73249027, 2.23911111, + 10.6196911, 7.05320600, 5.41228555, 4.28638718, 3.04804339, 2.46053085, + 14.7831603, 7.77903268, 5.71801705, 4.40237768, 2.92489673, 2.21419054}); + } + + // Set up regular grid interpolator. + compressor.perfRGI = + new Btwxt::RegularGridInterpolator(compressor.perfGrid, compressor.perfGridValues); + compressor.useBtwxtGrid = true; + + // set everything in its places + setOfSources[0] = compressor; + } + // if rheem multipass + else if (MODELS_RHEEM_HPHD60HNU_201_MP <= presetNum && + presetNum <= MODELS_RHEEM_HPHD135VNU_483_MP) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.perfMap.reserve(1); + compressor.hysteresis_dC = 0; + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = (int)(numNodes / 3.) - 1; + + // logic conditions + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(5.), this)); + + std::vector nodeWeights1; + nodeWeights1.emplace_back(4); + compressor.addShutOffLogic(std::make_shared( + "fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + // logic conditions + compressor.minT = F_TO_C(45.); + compressor.maxT = F_TO_C(110.); + compressor.maxSetpoint_C = MAXOUTLET_R134A; // data says 150... + + if (presetNum == MODELS_RHEEM_HPHD60HNU_201_MP || + presetNum == MODELS_RHEEM_HPHD60VNU_201_MP) { + setTankSize_adjustUA(250., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(17.4); + compressor.perfMap.push_back({ + 110, // Temperature (T_F) + + {1.8558438453, + 0.0120796155, + -0.0135443327, + 0.0000059621, + 0.0003010506, + -0.0000463525}, // Input Power Coefficients (inputPower_coeffs) + + {3.6840046360, + 0.0995685071, + -0.0398107723, + -0.0001903160, + 0.0000980361, + -0.0003469814} // COP Coefficients (COP_coeffs) + }); + } + else if (presetNum == MODELS_RHEEM_HPHD135HNU_483_MP || + presetNum == MODELS_RHEEM_HPHD135VNU_483_MP) { + setTankSize_adjustUA(500., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(34.87); + compressor.perfMap.push_back({ + 110, // Temperature (T_F) + + {5.1838201136, + 0.0247312962, + -0.0120766440, + 0.0000493862, + 0.0005422089, + -0.0001385078}, // Input Power Coefficients (inputPower_coeffs) + + {5.0207181209, + 0.0442525790, + -0.0418284882, + 0.0000793531, + 0.0001132421, + -0.0002491563} // COP Coefficients (COP_coeffs) + }); + } + + // set everything in its places + setOfSources[0] = compressor; + } + + else if (presetNum == MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = 65; + + tankVolume_L = GAL_TO_L(500); + tankUA_kJperHrC = 12; + tankSizeFixed = false; + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.minT = F_TO_C(-13.); + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + // What to do about these?! + compressor.hysteresis_dC = 4; + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.maxSetpoint_C = F_TO_C(176.1); + + // Turn on + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "eighth node absolute", nodeWeights, F_TO_C(110.), this, true)); + + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic(std::make_shared( + "bottom node", nodeWeights1, dF_TO_dC(15.), this, false, std::greater(), true)); + compressor.depressesTemperature = false; + + // Performance grid: externalT_F, Tout_F, condenserTemp_F + compressor.perfGrid.reserve(2); + compressor.perfGridValues.reserve(2); + compressor.perfGrid.push_back( + {-13, -11.2, -7.6, -4, -0.4, 3.2, 6.8, 10.4, 14, 17.6, 21.2, 24.8, + 28.4, 32, 35.6, 39.2, 42.8, 46.4, 50, 53.6, 57.2, 60.8, 64.4, 68, + 71.6, 75.2, 78.8, 82.4, 86, 89.6, 93.2, 96.8, 100.4, 104}); // Grid Axis 1 Tair (F) + compressor.perfGrid.push_back({140., 158., 176.}); // Grid Axis 2 Tout (F) + compressor.perfGrid.push_back({41, 48.2, 62.6, 75.2, 84.2}); // Grid Axis 3 Tin (F) + + // Grid values in long format, table 1, input power (Btu/hr) + compressor.perfGridValues.push_back( + {56518.565328, 57130.739544, 57094.73612, 57166.756616, + 57238.777112, 56518.565328, 57130.739544, 57094.73612, + 57166.756616, 57238.777112, 58061.348896, 58360.24692, + 58591.39286, 58870.368216, 59093.547136, 56626.5960719999, + 57202.763452, 57310.794196, 57310.794196, 57490.848848, + 56626.5960719999, 57202.763452, 57310.794196, 57310.794196, + 57490.848848, 58280.539188, 58519.65556, 58786.67868, + 59093.547136, 59372.5190799999, 56950.695128, 57850.95474, + 57814.947904, 57814.947904, 57922.978648, 56950.695128, + 57850.95474, 57814.947904, 57814.947904, 57922.978648, + 58679.067612, 58977.969048, 59372.5190799999, 59651.494436, + 59930.46638, 57418.831764, 58175.053796, 58283.08454, + 58247.07088, 58427.12212, 57418.831764, 58175.053796, + 58283.08454, 58247.07088, 58427.12212, 59137.384512, + 59376.504296, 59902.566456, 60265.23476, 60516.313604, + 57778.930832, 58643.190432, 58823.23826, 58643.190432, + 58967.282664, 57778.930832, 58643.190432, 58823.23826, + 58643.190432, 58967.282664, 59515.99368, 59954.377676, + 60321.031196, 60934.77152, 61213.743464, 58103.029888, + 59075.313408, 59219.357812, 59291.374896, 59579.45688, + 58103.029888, 59075.313408, 59219.357812, 59291.374896, + 59579.45688, 60014.159328, 60273.205192, 60934.77152, + 61436.922384, 61799.587276, 58535.152864, 59399.412464, + 59795.525192, 59903.555936, 60299.672076, 58535.152864, + 59399.412464, 59795.525192, 59903.555936, 60299.672076, + 60512.321564, 60751.448172, 61409.02246, 62022.769608, + 62329.641476, 58931.275828, 59651.4842, 60011.58668, + 60263.66524, 60551.747224, 58931.275828, 59651.4842, + 60011.58668, 60263.66524, 60551.747224, 60910.860224, + 61369.1703, 62022.769608, 62580.713496, 62803.895828, + 59219.357812, 60155.634496, 60443.71648, 60659.777968, + 61163.92144, 59219.357812, 60155.634496, 60443.71648, + 60659.777968, 61163.92144, 61329.321552, 61687.997816, + 62441.224112, 63166.56072, 63585.015224, 59651.4842, + 60479.726728, 61019.88386, 61163.92144, 61920.146884, + 59651.4842, 60479.726728, 61019.88386, 61163.92144, + 61920.146884, 61707.923896, 62186.166876, 63027.071336, + 63724.504608, 64170.862448, 59723.504696, 60839.83262, + 61379.993164, 61524.030744, 62352.273272, 59723.504696, + 60839.83262, 61379.993164, 61524.030744, 62352.273272, + 61966.96976, 62445.21274, 63361.839716, 64142.969348, + 64505.63424, 59759.511532, 60695.788216, 61524.030744, + 61884.136636, 62712.382576, 59759.511532, 60695.788216, + 61524.030744, 61884.136636, 62712.382576, 62166.240796, + 62744.114176, 63668.714996, 64282.451908, 64589.323776, + 59759.511532, 61019.88386, 61848.1298, 62064.191288, + 62964.4509, 59759.511532, 61019.88386, 61848.1298, + 62064.191288, 62964.4509, 62425.28666, 63003.16004, + 63975.58004, 64533.523928, 64617.2237, 59471.429548, + 61055.894108, 61956.160544, 62460.304016, 63216.526048, + 59471.429548, 61055.894108, 61956.160544, 62460.304016, + 63216.526048, 62624.550872, 63202.424252, 64310.351832, + 64756.70626, 64728.806336, 61632.061488, 63036.474808, + 63828.7105, 64296.847136, 65053.069168, 61632.061488, + 63036.474808, 63828.7105, 64296.847136, 65053.069168, + 63561.10734, 64099.125148, 65258.8605359999, 65593.625504, + 65621.525428, 51189.004268, 52917.506408, 54826.070024, + 57094.73612, 59327.388556, 51189.004268, 52917.506408, + 54826.070024, 57094.73612, 59327.388556, 55391.172288, + 58240.683616, 62106.459144, 65733.114888, 65705.214964, + 41286.100768, 42726.524336, 45931.460292, 49784.590948, + 53457.6669519999, 41286.100768, 42726.524336, 45931.460292, + 49784.590948, 53457.6669519999, 49433.093532, 51067.083272, + 57921.8561, 61604.3082799999, 64477.734316, 35632.444064, + 37108.87788, 41394.134924, 45139.228012, 49568.526048, + 35632.444064, 37108.87788, 41394.134924, 45139.228012, + 49568.526048, 47540.06134, 47221.233824, 56080.631716, + 59539.904976, 61883.276812, 34192.023908, 35596.430404, + 39809.6669519999, 43410.72246, 47659.969256, 34192.023908, + 35596.430404, 39809.6669519999, 43410.72246, 47659.969256, + 47559.98742, 47061.821772, 54490.482764, 57893.959588, + 60153.648712, 32895.641332, 34192.023908, 38225.202392, + 41646.20666, 45751.409052, 32895.641332, 34192.023908, + 38225.202392, 41646.20666, 45751.409052, 47659.621232, + 46842.624656, 52956.13366, 56220.1211, 58312.420916, + 31563.25192, 32715.58668, 36532.707088, 39881.687448, + 43914.869344, 31563.25192, 32715.58668, 36532.707088, + 39881.687448, 43914.869344, 47719.402884, 46742.994256, + 51393.877808, 54518.382688, 56554.886068, 30194.85226, + 31347.18702, 35092.286932, 38117.171648, 42006.312552, + 30194.85226, 31347.18702, 35092.286932, 38117.171648, + 42006.312552, 47799.1072039999, 46324.532928, 49692.139396, + 52732.951328, 54769.45812, 30446.923996, 31383.197268, + 34300.054652, 37144.884716, 40781.953884, 30446.923996, + 31383.197268, 34300.054652, 37144.884716, 40781.953884, + 45547.391924, 44212.307032, 47320.867636, 50389.57608, + 52202.90054, 30698.995732, 31311.176772, 33723.88386, + 36316.6456, 39701.636208, 30698.995732, 31311.176772, + 33723.88386, 36316.6456, 39701.636208, 43295.680056, + 41980.517832, 45089.078436, 47795.121988, 49720.03932, + 30987.081128, 31311.176772, 33183.726728, 35344.358668, + 38477.27754, 30987.081128, 31311.176772, 33183.726728, + 35344.358668, 38477.27754, 41562.059916, 40486.017476, + 43415.236536, 46037.590552, 47795.121988, 31203.146028, + 31311.176772, 32571.545688, 34552.126388, 37360.949616, + 31203.146028, 31311.176772, 32571.545688, 34552.126388, + 37360.949616, 40486.017476, 39310.3446359999, 42159.859376, + 44782.20998, 46511.844904, 31167.132368, 31311.176772, + 32355.4842, 34156.010248, 36712.758328, 31167.132368, + 31311.176772, 32355.4842, 34156.010248, 36712.758328, + 39449.830608, 38353.862088, 41127.657724, 43666.31538, + 45284.360844, 31059.101624, 31131.12212, 32319.473952, + 34156.010248, 36748.771988, 31059.101624, 31131.12212, + 32319.473952, 34156.010248, 36748.771988, 38592.985284, + 37457.161192, 40151.249096, 42801.496212, 44419.541676, + 30879.050384, 31023.091376, 32319.473952, 34192.023908, + 36820.789072, 30879.050384, 31023.091376, 32319.473952, + 34192.023908, 36820.789072, 37756.062628, 36680.0236, + 39258.536828, 41797.194484, 43387.343436, 30807.029888, + 30951.07088, 32427.504696, 34156.010248, 36748.771988, + 30807.029888, 30951.07088, 32427.504696, 34156.010248, + 36748.771988, 37795.9182, 36779.657412, 39258.536828, + 41769.29456, 43331.547, 30626.976942, 30735.007686, + 32319.473952, 34156.010248, 36748.771988, 30626.976942, + 30735.007686, 32319.473952, 34156.010248, 36748.771988, + 37815.84428, 36779.657412, 39286.431634, 41825.090996, + 43359.446924, 30446.923996, 30518.944492, 32355.4842, + 34264.040992, 36820.789072, 30446.923996, 30518.944492, + 32355.4842, 34264.040992, 36820.789072, 37775.988708, + 36759.731332, 39286.431634, 41825.090996, 43359.446924, + 30230.859096, 30410.913748, 32319.473952, 34192.023908, + 36748.771988, 30230.859096, 30410.913748, 32319.473952, + 34192.023908, 36748.771988, 37775.988708, 36759.731332, + 39342.226364, 41825.090996, 43303.650488, 30194.85226, + 30194.85226, 32391.491036, 34156.010248, 36748.771988, + 30194.85226, 30194.85226, 32391.491036, 34156.010248, + 36748.771988, 37756.062628, 36779.657412, 39342.226364, + 41825.090996, 43359.446924}); + + // Grid values in long format, table 2, COP + compressor.perfGridValues.push_back( + {1.177126, 1.1393, 1.091664, 1.033858, 0.981755, 1.177126, 1.1393, 1.091664, + 1.033858, 0.981755, 1.134534, 1.106615, 1.04928, 0.989101, 0.946182, 1.228935, + 1.190326, 1.136507, 1.075244, 1.023802, 1.228935, 1.190326, 1.136507, 1.075244, + 1.023802, 1.174944, 1.147101, 1.087318, 1.026909, 0.980265, 1.324165, 1.27451, + 1.218468, 1.156182, 1.103823, 1.324165, 1.27451, 1.218468, 1.156182, 1.103823, + 1.267595, 1.236929, 1.165864, 1.102888, 1.052601, 1.415804, 1.365212, 1.301359, + 1.238022, 1.180586, 1.415804, 1.365212, 1.301359, 1.238022, 1.180586, 1.358408, + 1.324943, 1.249272, 1.179609, 1.128155, 1.510855, 1.453792, 1.381237, 1.31747, + 1.253435, 1.510855, 1.453792, 1.381237, 1.31747, 1.253435, 1.446639, 1.404653, + 1.331368, 1.249056, 1.195511, 1.60469, 1.540079, 1.462451, 1.39417, 1.326987, + 1.60469, 1.540079, 1.462451, 1.39417, 1.326987, 1.529924, 1.492107, 1.404944, + 1.325122, 1.265433, 1.690249, 1.630494, 1.539446, 1.464082, 1.395939, 1.690249, + 1.630494, 1.539446, 1.464082, 1.395939, 1.610302, 1.56761, 1.479273, 1.393118, + 1.33076, 1.776046, 1.715967, 1.624662, 1.540783, 1.469819, 1.776046, 1.715967, + 1.624662, 1.540783, 1.469819, 1.693465, 1.646725, 1.550545, 1.459601, 1.400666, + 1.865309, 1.797965, 1.703902, 1.612645, 1.539888, 1.865309, 1.797965, 1.703902, + 1.612645, 1.539888, 1.776866, 1.728095, 1.626829, 1.531743, 1.461555, 1.956837, + 1.881215, 1.777073, 1.690021, 1.603082, 1.956837, 1.881215, 1.777073, 1.690021, + 1.603082, 1.857512, 1.807899, 1.699347, 1.599321, 1.526899, 2.038891, 1.956496, + 1.848049, 1.757975, 1.668207, 2.038891, 1.956496, 1.848049, 1.757975, 1.668207, + 1.934721, 1.878022, 1.764777, 1.657606, 1.583414, 2.110576, 2.028182, 1.922739, + 1.818155, 1.725237, 2.110576, 2.028182, 1.922739, 1.818155, 1.725237, 1.997516, + 1.937435, 1.824625, 1.712596, 1.630169, 2.185899, 2.091178, 1.989083, 1.883087, + 1.786388, 2.185899, 2.091178, 1.989083, 1.883087, 1.786388, 2.06464, 2.003084, + 1.88041, 1.763428, 1.68041, 2.29337, 2.155411, 2.063354, 1.942635, 1.844204, + 2.29337, 2.155411, 2.063354, 1.942635, 1.844204, 2.125448, 2.061323, 1.933955, + 1.810339, 1.720612, 2.213555, 2.111682, 2.027503, 1.91515, 1.819817, 2.213555, + 2.111682, 2.027503, 1.91515, 1.819817, 2.126499, 2.064584, 1.935343, 1.818713, + 1.728239, 2.665142, 2.578088, 2.488506, 2.388206, 2.29651, 2.665142, 2.578088, + 2.488506, 2.388206, 2.29651, 2.46407, 2.344111, 2.198428, 2.057188, 1.96338, + 3.304405, 3.191319, 2.971384, 2.741049, 2.550691, 3.304405, 3.191319, 2.971384, + 2.741049, 2.550691, 2.763177, 2.673398, 2.356773, 2.216348, 2.116712, 3.827691, + 3.676371, 3.297085, 3.022338, 2.752997, 3.827691, 3.676371, 3.297085, 3.022338, + 2.752997, 2.871739, 2.890389, 2.434648, 2.292726, 2.205906, 3.989995, 3.834598, + 3.428313, 3.14185, 2.862486, 3.989995, 3.834598, 3.428313, 3.14185, 2.862486, + 2.871269, 2.900921, 2.506208, 2.358391, 2.270261, 4.147236, 3.992101, 3.570419, + 3.274967, 2.982684, 4.147236, 3.992101, 3.570419, 3.274967, 2.982684, 2.865266, + 2.913751, 2.578296, 2.428607, 2.341945, 4.322305, 4.172262, 3.73583, 3.419865, + 3.107421, 4.322305, 4.172262, 3.73583, 3.419865, 3.107421, 2.861677, 2.919962, + 2.65667, 2.504413, 2.414725, 4.518187, 4.354394, 3.889174, 3.578177, 3.248607, + 4.518187, 4.354394, 3.889174, 3.578177, 3.248607, 2.856905, 2.946338, 2.747649, + 2.589208, 2.493442, 4.481963, 4.349398, 3.979002, 3.671837, 3.346137, 4.481963, + 4.349398, 3.979002, 3.671837, 3.346137, 2.998141, 3.087098, 2.885335, 2.709619, + 2.616032, 4.445162, 4.359402, 4.046983, 3.755577, 3.437188, 4.445162, 4.359402, + 4.046983, 3.755577, 3.437188, 3.154067, 3.251216, 3.028152, 2.856705, 2.746669, + 4.402673, 4.359402, 4.112859, 3.858889, 3.546561, 4.402673, 4.359402, 4.112859, + 3.858889, 3.546561, 3.285629, 3.371232, 3.1449, 2.965763, 2.857289, 4.373341, + 4.359402, 4.19016, 3.947368, 3.65253, 4.373341, 4.359402, 4.19016, 3.947368, + 3.65253, 3.372955, 3.472057, 3.238544, 3.048902, 2.936122, 4.378394, 4.359402, + 4.218141, 3.993147, 3.717018, 4.378394, 4.359402, 4.218141, 3.993147, 3.717018, + 3.461548, 3.558644, 3.319824, 3.126817, 3.015709, 4.391304, 4.384616, 4.222841, + 3.993147, 3.713376, 4.391304, 4.384616, 4.222841, 3.993147, 3.713376, 3.538402, + 3.643836, 3.400556, 3.189995, 3.074423, 4.419242, 4.399884, 4.222841, 3.988941, + 3.706113, 4.419242, 4.399884, 4.222841, 3.988941, 3.706113, 3.616836, 3.721038, + 3.477882, 3.266644, 3.147565, 4.429573, 4.410122, 4.208773, 3.993147, 3.713376, + 4.429573, 4.410122, 4.208773, 3.993147, 3.713376, 3.613022, 3.710957, 3.477882, + 3.268826, 3.151618, 4.45679, 4.441125, 4.222841, 3.993147, 3.713376, 4.45679, + 4.441125, 4.222841, 3.993147, 3.713376, 3.611119, 3.710957, 3.475413, 3.264466, + 3.14959, 4.483146, 4.472566, 4.218141, 3.980557, 3.706113, 4.483146, 4.472566, + 4.218141, 3.980557, 3.706113, 3.614928, 3.712969, 3.475413, 3.264466, 3.14959, + 4.515188, 4.488454, 4.222841, 3.988941, 3.713376, 4.515188, 4.488454, 4.222841, + 3.988941, 3.713376, 3.614928, 3.712969, 3.470484, 3.264466, 3.153648, 4.522957, + 4.520572, 4.213452, 3.993147, 3.713376, 4.522957, 4.520572, 4.213452, 3.993147, + 3.713376, 3.616836, 3.710957, 3.470484, 3.264466, 3.14959}); + + // Set up regular grid interpolator. + Btwxt::GriddedData gridded_data(compressor.perfGrid, compressor.perfGridValues); + gridded_data.set_axis_extrap_method( + 2, Btwxt::Method::LINEAR); // Linearly extrapolate on Tin (F) + compressor.perfRGI = new Btwxt::RegularGridInterpolator(gridded_data); + compressor.useBtwxtGrid = true; + + compressor.secondaryHeatExchanger = {dF_TO_dC(10.), dF_TO_dC(15.), 27.}; + + // set everything in its places + setOfSources[0] = compressor; + } + + else if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_GS3_45HPA_US_SP || + presetNum == MODELS_SANCO2_119) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = 65; + setpointFixed = true; + + if (presetNum == MODELS_SANCO2_119) { + tankVolume_L = GAL_TO_L(119); + tankUA_kJperHrC = 9; + } + else { + tankVolume_L = 315; + tankUA_kJperHrC = 7; + if (presetNum == MODELS_SANCO2_GS3_45HPA_US_SP) { + tankSizeFixed = false; + } + } + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.minT = F_TO_C(-25.); + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + compressor.perfMap.reserve(5); + + compressor.perfMap.push_back({ + 17, // Temperature (T_F) + {1650, 5.5, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {3.2, -0.015, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 35, // Temperature (T_F) + {1100, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {3.7, -0.015, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {880, 3.1, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.25, -0.025, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {740, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {6.2, -0.03, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {790, 2, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.15, -0.04, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.hysteresis_dC = 4; + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.maxSetpoint_C = MAXOUTLET_R744; + + std::vector nodeWeights; + nodeWeights.emplace_back(8); + compressor.addTurnOnLogic(std::make_shared( + "eighth node absolute", nodeWeights, F_TO_C(113), this, true)); + if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_119) { + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(8.2639))); + // Adds a bonus standby logic so the external heater does not cycle, recommended for any + // external heater with standby + std::vector nodeWeightStandby; + nodeWeightStandby.emplace_back(0); + compressor.standbyLogic = + std::make_shared("bottom node absolute", + nodeWeightStandby, + F_TO_C(113), + this, + true, + std::greater()); + } + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic( + std::make_shared("bottom node absolute", + nodeWeights1, + F_TO_C(135), + this, + true, + std::greater(), + true)); + compressor.depressesTemperature = false; // no temp depression + + // set everything in its places + setOfSources[0] = compressor; + } + else if (presetNum == MODELS_SANCO2_43) { + numNodes = 96; + tankTemps_C = new double[numNodes]; + setpoint_C = 65; + setpointFixed = true; + + tankVolume_L = 160; + // tankUA_kJperHrC = 10; //0 to turn off + tankUA_kJperHrC = 5; + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.minT = F_TO_C(-25.); + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(5); + + compressor.perfMap.push_back({ + 17, // Temperature (T_F) + {1650, 5.5, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {3.2, -0.015, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 35, // Temperature (T_F) + {1100, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {3.7, -0.015, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {880, 3.1, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.25, -0.025, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {740, 4.0, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {6.2, -0.03, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {790, 2, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.15, -0.04, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.hysteresis_dC = 4; + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.maxSetpoint_C = MAXOUTLET_R744; + + std::vector nodeWeights; + nodeWeights.emplace_back(4); + std::vector nodeWeightStandby; + nodeWeightStandby.emplace_back(0); + compressor.addTurnOnLogic(std::make_shared( + "fourth node absolute", nodeWeights, F_TO_C(113), this, true)); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(8.2639))); + compressor.standbyLogic = + std::make_shared("bottom node absolute", + nodeWeightStandby, + F_TO_C(113), + this, + true, + std::greater()); + + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic( + std::make_shared("bottom twelth absolute", + nodeWeights1, + F_TO_C(135), + this, + true, + std::greater(), + true)); + compressor.depressesTemperature = false; // no temp depression + + // set everything in its places + setOfSources[0] = compressor; + } + else if (presetNum == MODELS_AOSmithHPTU50 || presetNum == MODELS_RheemHBDR2250 || + presetNum == MODELS_RheemHBDR4550) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 171; + tankUA_kJperHrC = 6; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 5.0; + compressor.setCondensity(split, split, split, split, split, 0, 0, 0, 0, 0, 0, 0); + + // performance map + compressor.perfMap.reserve(3); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(42.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + if (presetNum == MODELS_RheemHBDR2250) { + resistiveElementTop.setupAsResistiveElement(8, 2250); + } + else { + resistiveElementTop.setupAsResistiveElement(8, 4500); + } + resistiveElementTop.isVIP = true; + + // bottom resistor values + if (presetNum == MODELS_RheemHBDR2250) { + resistiveElementBottom.setupAsResistiveElement(0, 2250); + } + else { + resistiveElementBottom.setupAsResistiveElement(0, 4500); + } + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(35); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + + std::vector nodeWeights; + nodeWeights.emplace_back(11); + nodeWeights.emplace_back(12); + resistiveElementTop.addTurnOnLogic(std::make_shared( + "top sixth absolute", nodeWeights, F_TO_C(105), this, true)); + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(28))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_AOSmithHPTU66 || presetNum == MODELS_RheemHBDR2265 || + presetNum == MODELS_RheemHBDR4565) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + if (presetNum == MODELS_AOSmithHPTU66) { + tankVolume_L = 244.6; + } + else { + tankVolume_L = 221.4; + } + tankUA_kJperHrC = 8; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // performance map + compressor.perfMap.reserve(3); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(42.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + if (presetNum == MODELS_RheemHBDR2265) { + resistiveElementTop.setupAsResistiveElement(8, 2250); + } + else { + resistiveElementTop.setupAsResistiveElement(8, 4500); + } + resistiveElementTop.isVIP = true; + + // bottom resistor values + if (presetNum == MODELS_RheemHBDR2265) { + resistiveElementBottom.setupAsResistiveElement(0, 2250); + } + else { + resistiveElementBottom.setupAsResistiveElement(0, 4500); + } + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(35); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + + std::vector nodeWeights; + nodeWeights.emplace_back(11); + nodeWeights.emplace_back(12); + resistiveElementTop.addTurnOnLogic(std::make_shared( + "top sixth absolute", nodeWeights, F_TO_C(105), this, true)); + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(31))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_AOSmithHPTU80 || presetNum == MODELS_RheemHBDR2280 || + presetNum == MODELS_RheemHBDR4580) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 299.5; + tankUA_kJperHrC = 9; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + double split = 1.0 / 3.0; + compressor.setCondensity(split, split, split, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(3); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {170, 2.02, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.93, -0.027, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {144.5, 2.42, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.67, -0.037, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {94.1, 3.15, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {11.1, -0.056, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(42.0); + compressor.maxT = F_TO_C(120.0); + compressor.hysteresis_dC = dF_TO_dC(1); + + // top resistor values + if (presetNum == MODELS_RheemHBDR2280) { + resistiveElementTop.setupAsResistiveElement(8, 2250); + } + else { + resistiveElementTop.setupAsResistiveElement(8, 4500); + } + resistiveElementTop.isVIP = true; + + // bottom resistor values + if (presetNum == MODELS_RheemHBDR2280) { + resistiveElementBottom.setupAsResistiveElement(0, 2250); + } + else { + resistiveElementBottom.setupAsResistiveElement(0, 4500); + } + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(35); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + + std::vector nodeWeights; + // nodeWeights.emplace_back(9); nodeWeights.emplace_back(10); + nodeWeights.emplace_back(11); + nodeWeights.emplace_back(12); + resistiveElementTop.addTurnOnLogic(std::make_shared( + "top sixth absolute", nodeWeights, F_TO_C(105), this, true)); + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(35))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_AOSmithHPTU80_DR) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = 283.9; + tankUA_kJperHrC = 9; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {142.6, 2.152, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {6.989258, -0.038320, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {120.14, 2.513, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {8.188, -0.0432, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(42.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(34.1636); + double standbyT = dF_TO_dC(7.1528); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80.108))); + + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(39.9691))); + resistiveElementTop.addTurnOnLogic(HPWH::topThird_absolute(F_TO_C(87))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_AOSmithCAHP120) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(150.0); + + tankVolume_L = GAL_TO_L(111.76); // AOSmith docs say 111.76 + tankUA_kJperHrC = UAf_TO_UAc(3.94); + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0.3, 0.3, 0.2, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + // From CAHP 120 COP Tests + compressor.perfMap.reserve(3); + + // Tuned on the multiple K167 tests + compressor.perfMap.push_back({ + 50., // Temperature (T_F) + {2010.49966, -4.20966, 0.085395}, // Input Power Coefficients (inputPower_coeffs) + {5.91, -0.026299, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67.5, // Temperature (T_F) + {2171.012, -6.936571, 0.1094962}, // Input Power Coefficients (inputPower_coeffs) + {7.26272, -0.034135, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95., // Temperature (T_F) + {2276.0625, -7.106608, 0.119911}, // Input Power Coefficients (inputPower_coeffs) + {8.821262, -0.042059, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = + F_TO_C(47.0); // Product documentation says 45F doesn't look like it in CMP-T test// + compressor.maxT = F_TO_C(110.0); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + double wattRE = 6000; // 5650.; + resistiveElementTop.setupAsResistiveElement(7, wattRE); + resistiveElementTop.isVIP = true; // VIP is the only source that turns on independently when + // something else is already heating. + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, wattRE); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + resistiveElementBottom.setCondensity( + 0.2, 0.8, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.); // Based of CMP test + + // logic conditions for + double compStart = dF_TO_dC(5.25); + double standbyT = dF_TO_dC(5.); // Given CMP_T test + compressor.addTurnOnLogic(HPWH::secondSixth(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + double resistanceStart = 12.; + resistiveElementTop.addTurnOnLogic(HPWH::topThird(resistanceStart)); + resistiveElementBottom.addTurnOnLogic(HPWH::topThird(resistanceStart)); + + resistiveElementTop.addShutOffLogic(HPWH::fifthSixthMaxTemp(F_TO_C(117.))); + resistiveElementBottom.addShutOffLogic(HPWH::secondSixthMaxTemp(F_TO_C(109.))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + // setOfSources[2].followedByHeatSource = &setOfSources[1];; + + setOfSources[0].companionHeatSource = &setOfSources[1]; + setOfSources[1].companionHeatSource = &setOfSources[2]; + } + else if (MODELS_AOSmithHPTS50 <= presetNum && presetNum <= MODELS_AOSmithHPTS80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + if (presetNum == MODELS_AOSmithHPTS50) { + tankVolume_L = GAL_TO_L(45.6); + tankUA_kJperHrC = 6.403; + } + else if (presetNum == MODELS_AOSmithHPTS66) { + tankVolume_L = GAL_TO_L(67.63); + tankUA_kJperHrC = UAf_TO_UAc(1.5) * 6.403 / UAf_TO_UAc(1.16); + } + else if (presetNum == MODELS_AOSmithHPTS80) { + tankVolume_L = GAL_TO_L(81.94); + tankUA_kJperHrC = UAf_TO_UAc(1.73) * 6.403 / UAf_TO_UAc(1.16); + } + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementTop(this); + HeatSource resistiveElementBottom(this); + + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0, 0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0); + + // performance map + compressor.perfMap.reserve(3); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {66.82, 2.49, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {8.64, -0.0436, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67.5, // Temperature (T_F) + {85.1, 2.38, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {10.82, -0.0551, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {89, 2.62, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {12.52, -0.0534, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(1.); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + resistiveElementTop.setupAsResistiveElement(8, 4500); + resistiveElementTop.isVIP = true; + + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(30.2); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(11.87))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[2]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + + else if (presetNum == MODELS_GE2014STDMode) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 6.5; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); + // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_GE2014STDMode_80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(75.4); + tankUA_kJperHrC = 10.; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(19.6605))); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); + compressor.minT = F_TO_C(37); + // compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_GE2014) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 6.5; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); + // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); + + resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_GE2014_80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(75.4); + tankUA_kJperHrC = 10.; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); + // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); + + resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_GE2014_80DR) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(75.4); + tankUA_kJperHrC = 10.; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + // resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.addTurnOnLogic(HPWH::topThird_absolute(F_TO_C(87))); + // resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); + // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); + + resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); + // resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + // PRESET USING GE2014 DATA + else if (presetNum == MODELS_BWC2020_65) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(64); + tankUA_kJperHrC = 7.6; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); + // compressor.addShutOffLogic(HPWH::largerDraw(F_TO_C(62.4074))); + + resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + } + // If Rheem Premium + else if (MODELS_Rheem2020Prem40 <= presetNum && presetNum <= MODELS_Rheem2020Prem80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + if (presetNum == MODELS_Rheem2020Prem40) { + tankVolume_L = GAL_TO_L(36.1); + tankUA_kJperHrC = 9.5; + } + else if (presetNum == MODELS_Rheem2020Prem50) { + tankVolume_L = GAL_TO_L(45.1); + tankUA_kJperHrC = 8.55; + } + else if (presetNum == MODELS_Rheem2020Prem65) { + tankVolume_L = GAL_TO_L(58.5); + tankUA_kJperHrC = 10.64; + } + else if (presetNum == MODELS_Rheem2020Prem80) { + tankVolume_L = GAL_TO_L(72.0); + tankUA_kJperHrC = 10.83; + } + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {250, -1.0883, 0.0176}, // Input Power Coefficients (inputPower_coeffs) + {6.7, -0.0087, -0.0002} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) + {7.0, -0.0168, -0.0001} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.0); + compressor.hysteresis_dC = dF_TO_dC(1); + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // logic conditions + double compStart = dF_TO_dC(32); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[1].backupHeatSource = &setOfSources[2]; + setOfSources[2].backupHeatSource = &setOfSources[1]; + + setOfSources[0].followedByHeatSource = &setOfSources[2]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + + // If Rheem Build + else if (MODELS_Rheem2020Build40 <= presetNum && presetNum <= MODELS_Rheem2020Build80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + if (presetNum == MODELS_Rheem2020Build40) { + tankVolume_L = GAL_TO_L(36.1); + tankUA_kJperHrC = 9.5; + } + else if (presetNum == MODELS_Rheem2020Build50) { + tankVolume_L = GAL_TO_L(45.1); + tankUA_kJperHrC = 8.55; + } + else if (presetNum == MODELS_Rheem2020Build65) { + tankVolume_L = GAL_TO_L(58.5); + tankUA_kJperHrC = 10.64; + } + else if (presetNum == MODELS_Rheem2020Build80) { + tankVolume_L = GAL_TO_L(72.0); + tankUA_kJperHrC = 10.83; + } + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {220.0, 0.8743, 0.00454}, // Input Power Coefficients (inputPower_coeffs) + {7.96064, -0.0448, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) + {8.45936, -0.04539, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.hysteresis_dC = dF_TO_dC(1); + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.0); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(4); + + // logic conditions + double compStart = dF_TO_dC(30); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[1].backupHeatSource = &setOfSources[2]; + setOfSources[2].backupHeatSource = &setOfSources[1]; + + setOfSources[0].followedByHeatSource = &setOfSources[2]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + else if (MODELS_RheemPlugInShared40 <= presetNum && presetNum <= MODELS_RheemPlugInShared80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + + if (presetNum == MODELS_RheemPlugInShared40) { + tankVolume_L = GAL_TO_L(36.0); + tankUA_kJperHrC = 9.5; + setpoint_C = F_TO_C(140.0); + } + else if (presetNum == MODELS_RheemPlugInShared50) { + tankVolume_L = GAL_TO_L(45.0); + tankUA_kJperHrC = 8.55; + setpoint_C = F_TO_C(140.0); + } + else if (presetNum == MODELS_RheemPlugInShared65) { + tankVolume_L = GAL_TO_L(58.5); + tankUA_kJperHrC = 10.64; + setpoint_C = F_TO_C(127.0); + } + else if (presetNum == MODELS_RheemPlugInShared80) { + tankVolume_L = GAL_TO_L(72.0); + tankUA_kJperHrC = 10.83; + setpoint_C = F_TO_C(127.0); + } + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + HeatSource compressor(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0.2, 0.2, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {250, -1.0883, 0.0176}, // Input Power Coefficients (inputPower_coeffs) + {6.7, -0.0087, -0.0002} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {275.0, -0.6631, 0.01571}, // Input Power Coefficients (inputPower_coeffs) + {7.0, -0.0168, -0.0001} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.0); + compressor.hysteresis_dC = dF_TO_dC(1); + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // logic conditions + double compStart = dF_TO_dC(32); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + // set everything in its places + setOfSources[0] = compressor; + } + else if (presetNum == MODELS_RheemPlugInDedicated40 || + presetNum == MODELS_RheemPlugInDedicated50) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + if (presetNum == MODELS_RheemPlugInDedicated40) { + tankVolume_L = GAL_TO_L(36); + tankUA_kJperHrC = 5.5; + } + else if (presetNum == MODELS_RheemPlugInDedicated50) { + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 6.33; + } + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 1; + setOfSources = new HeatSource[numHeatSources]; + HeatSource compressor(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity( + 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0., 0., 0., 0.); + + compressor.perfMap.reserve(2); + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {528.91, 4.8988, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {4.3943, -0.012443, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 95, // Temperature (T_F) + {494.03, 7.7266, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.48189, -0.01604, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.hysteresis_dC = dF_TO_dC(1); + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.0); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + + // logic conditions + double compStart = dF_TO_dC(20); + double standbyT = dF_TO_dC(9); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + // set everything in its places + setOfSources[0] = compressor; + } + else if (presetNum == MODELS_RheemHB50) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 7; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 47, // Temperature (T_F) + {280, 4.97342, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.634009, -0.029485, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {280, 5.35992, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {6.3, -0.03, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.hysteresis_dC = dF_TO_dC(1); + compressor.minT = F_TO_C(40.0); + compressor.maxT = F_TO_C(120.0); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.configuration = HPWH::HeatSource::CONFIG_WRAPPED; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4200); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 2250); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + double compStart = dF_TO_dC(38); + double standbyT = dF_TO_dC(13.2639); + compressor.addTurnOnLogic(HPWH::bottomThird(compStart)); + compressor.addTurnOnLogic(HPWH::standby(standbyT)); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(76.7747))); + + resistiveElementTop.addTurnOnLogic(HPWH::topSixth(dF_TO_dC(20.4167))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_Stiebel220E) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127); + + tankVolume_L = GAL_TO_L(56); + // tankUA_kJperHrC = 10; //0 to turn off + tankUA_kJperHrC = 9; + + doTempDepression = false; + tankMixesOnDraw = false; + + numHeatSources = 2; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElement(this); + + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + resistiveElement.setupAsResistiveElement(0, 1500); + resistiveElement.hysteresis_dC = dF_TO_dC(0); + + compressor.setCondensity(0, 0.12, 0.22, 0.22, 0.22, 0.22, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {295.55337, 2.28518, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.744118, -0.025946, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {282.2126, 2.82001, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {8.012112, -0.039394, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(32.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = 0; // no hysteresis + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + compressor.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(6.5509))); + compressor.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + + compressor.depressesTemperature = false; // no temp depression + + // set everything in its places + setOfSources[0] = compressor; + setOfSources[1] = resistiveElement; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[0].backupHeatSource = &setOfSources[1]; + } + else if (presetNum == MODELS_Generic1) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(50); + tankUA_kJperHrC = 9; + doTempDepression = false; + tankMixesOnDraw = true; + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {472.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {2.942642, -0.0125954, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {439.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {3.95076, -0.01638033, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(45.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(8, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40.0))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); + compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(65))); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(80))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(110))); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(35))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_Generic2) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(50); + tankUA_kJperHrC = 7.5; + doTempDepression = false; + tankMixesOnDraw = true; + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {272.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {4.042642, -0.0205954, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {239.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.25076, -0.02638033, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(40.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); + compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(60))); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(80))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(100))); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(40))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_Generic3) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(50); + tankUA_kJperHrC = 5; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {172.58616, 2.09340, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.242642, -0.0285954, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 67, // Temperature (T_F) + {139.5615, 2.62997, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {6.75076, -0.03638033, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(35.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4500); + resistiveElementBottom.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); + compressor.addShutOffLogic(HPWH::largeDraw(F_TO_C(55))); + + resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(60))); + + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(40))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = compressor; + setOfSources[2] = resistiveElementBottom; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_UEF2generic) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 6.5; + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {4.29, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + {5.61, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(37.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(18.6605))); + + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(86.1111))); + + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(12.392))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + else if (MODELS_AWHSTier3Generic40 <= presetNum && presetNum <= MODELS_AWHSTier3Generic80) { + numNodes = 12; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(127.0); + + if (presetNum == MODELS_AWHSTier3Generic40) { + tankVolume_L = GAL_TO_L(36.1); + tankUA_kJperHrC = 5; + } + else if (presetNum == MODELS_AWHSTier3Generic50) { + tankVolume_L = GAL_TO_L(45); + tankUA_kJperHrC = 6.5; + } + else if (presetNum == MODELS_AWHSTier3Generic65) { + tankVolume_L = GAL_TO_L(64); + tankUA_kJperHrC = 7.6; + } + else if (presetNum == MODELS_AWHSTier3Generic80) { + tankVolume_L = GAL_TO_L(75.4); + tankUA_kJperHrC = 10.; + } + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("Incorrect model specification. \n"); + } + return HPWH_ABORT; + } + + doTempDepression = false; + tankMixesOnDraw = true; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + + // compressor values + compressor.isOn = false; + compressor.isVIP = false; + compressor.typeOfHeatSource = TYPE_compressor; + + double split = 1.0 / 4.0; + compressor.setCondensity(split, split, split, split, 0, 0, 0, 0, 0, 0, 0, 0); + + // voltex60 tier 1 values + compressor.perfMap.reserve(2); + + compressor.perfMap.push_back({ + 50, // Temperature (T_F) + {187.064124, 1.939747, 0.0}, // Input Power Coefficients (inputPower_coeffs) + //{5.4977772, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + {5.22288834, -0.0243008, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.perfMap.push_back({ + 70, // Temperature (T_F) + {148.0418, 2.553291, 0.0}, // Input Power Coefficients (inputPower_coeffs) + //{7.207307, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + {6.84694165, -0.0335265, 0.0} // COP Coefficients (COP_coeffs) + }); + + compressor.minT = F_TO_C(42.0); + compressor.maxT = F_TO_C(120.); + compressor.hysteresis_dC = dF_TO_dC(2); + compressor.configuration = HeatSource::CONFIG_WRAPPED; + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + // top resistor values + resistiveElementTop.setupAsResistiveElement(6, 4500); + resistiveElementTop.isVIP = true; + + // bottom resistor values + resistiveElementBottom.setupAsResistiveElement(0, 4000); + resistiveElementBottom.setCondensity(0, 0.2, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0); + resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); + + // logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(20))); + resistiveElementTop.addShutOffLogic(HPWH::topNodeMaxTemp(F_TO_C(116.6358))); + compressor.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(33.6883))); + compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(11.0648))); + resistiveElementBottom.addTurnOnLogic(HPWH::thirdSixth(dF_TO_dC(60))); + resistiveElementBottom.addShutOffLogic(HPWH::bottomTwelthMaxTemp(F_TO_C(80))); + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + } + // If a the model is the TamOMatic, HotTam, Generic... This model is scalable. + else if (presetNum == MODELS_TamScalable_SP) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + canScale = true; // a fully scallable model + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; + tankUA_kJperHrC = 7; + setTankSize_adjustUA(600., UNITS_GAL); + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.isMultipass = false; + compressor.perfMap.reserve(1); + compressor.hysteresis_dC = 0; + + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = numNodes - 1; + + // Defrost Derate + compressor.setupDefrostMap(); + + // Perfmap for input power and COP made from data for poor preforming modeled to be scalled + // for this model + std::vector inputPwr_coeffs = {13.6, + 0.00995, + -0.0342, + -0.014, + -0.000110, + 0.00026, + 0.000232, + 0.000195, + -0.00034, + 5.30E-06, + 2.3600E-06}; + std::vector COP_coeffs = {1.945, + 0.0412, + -0.0112, + -0.00161, + 0.0000492, + 0.0000348, + -0.0000323, + -0.000166, + 0.0000112, + 0.0000392, + -3.52E-07}; + + compressor.perfMap.push_back({ + 105, // Temperature (T_F) + inputPwr_coeffs, // Input Power Coefficients (inputPower_coeffs + COP_coeffs // COP Coefficients (COP_coeffs) + }); + + // logic conditions + compressor.minT = F_TO_C(40.); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(15), this)); + + // lowT cutoff + std::vector nodeWeights1; + nodeWeights1.emplace_back(1); + compressor.addShutOffLogic(std::make_shared( + "bottom node", nodeWeights1, dF_TO_dC(15.), this, false, std::greater(), true)); + compressor.depressesTemperature = false; // no temp depression + + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + resistiveElementBottom.setupAsResistiveElement(0, 30000); + resistiveElementTop.setupAsResistiveElement(9, 30000); + + // top resistor values + // standard logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(15))); + resistiveElementTop.isVIP = true; + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + else if (presetNum == MODELS_Scalable_MP) { + numNodes = 24; + tankTemps_C = new double[numNodes]; + setpoint_C = F_TO_C(135.0); + tankSizeFixed = false; + canScale = true; // a fully scallable model + + doTempDepression = false; + tankMixesOnDraw = false; + + tankVolume_L = 315; // Gets adjust per model but ratio between vol and UA is important + tankUA_kJperHrC = 7; + + numHeatSources = 3; + setOfSources = new HeatSource[numHeatSources]; + + HeatSource compressor(this); + compressor.isOn = false; + compressor.isVIP = true; + compressor.typeOfHeatSource = TYPE_compressor; + compressor.setCondensity(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0); + compressor.configuration = HeatSource::CONFIG_EXTERNAL; + compressor.perfMap.reserve(1); + compressor.hysteresis_dC = 0; + compressor.externalOutletHeight = 0; + compressor.externalInletHeight = (int)(numNodes / 3.) - 1; + + // logic conditions + std::vector nodeWeights; + nodeWeights.emplace_back(4); + compressor.addTurnOnLogic(std::make_shared( + "fourth node", nodeWeights, dF_TO_dC(5.), this, false)); + + std::vector nodeWeights1; + nodeWeights1.emplace_back(4); + compressor.addShutOffLogic(std::make_shared( + "fourth node", nodeWeights1, dF_TO_dC(0.), this, false, std::greater())); + compressor.depressesTemperature = false; // no temp depression + + // Defrost Derate + compressor.setupDefrostMap(); + + // logic conditions + compressor.minT = F_TO_C(40.); + compressor.maxT = F_TO_C(105.); + compressor.maxSetpoint_C = MAXOUTLET_R134A; + + setTankSize_adjustUA(600., UNITS_GAL); + compressor.mpFlowRate_LPS = GPM_TO_LPS(25.); + compressor.perfMap.push_back({ + 100, // Temperature (T_F) + + {12.4, 0.00739, -0.0410, 0.0, 0.000578, 0.0000696}, // Input Power Coefficients + // (inputPower_coeffs) + + {1.20, 0.0333, 0.00191, 0.000283, 0.0000496, -0.000440} // COP Coefficients (COP_coeffs) + + }); + + HeatSource resistiveElementBottom(this); + HeatSource resistiveElementTop(this); + resistiveElementBottom.setupAsResistiveElement(0, 30000); + resistiveElementTop.setupAsResistiveElement(9, 30000); + + // top resistor values + // standard logic conditions + resistiveElementTop.addTurnOnLogic(HPWH::topThird(dF_TO_dC(30))); + resistiveElementTop.isVIP = true; + + // set everything in its places + setOfSources[0] = resistiveElementTop; + setOfSources[1] = resistiveElementBottom; + setOfSources[2] = compressor; + + // and you have to do this after putting them into setOfSources, otherwise + // you don't get the right pointers + setOfSources[2].backupHeatSource = &setOfSources[1]; + setOfSources[1].backupHeatSource = &setOfSources[2]; + + setOfSources[0].followedByHeatSource = &setOfSources[1]; + setOfSources[1].followedByHeatSource = &setOfSources[2]; + + setOfSources[0].companionHeatSource = &setOfSources[2]; + } + + else { + if (hpwhVerbosity >= VRB_reluctant) { + msg("You have tried to select a preset model which does not exist. \n"); + } + return HPWH_ABORT; + } + + // start tank off at setpoint + resetTankToSetpoint(); + + // initialize nextTankTemps_C + nextTankTemps_C = new double[numNodes]; + + hpwhModel = presetNum; + + // calculate oft-used derived values + calcDerivedValues(); + + if (checkInputs() == HPWH_ABORT) { + return HPWH_ABORT; + } + + isHeating = false; + for (int i = 0; i < numHeatSources; i++) { + if (setOfSources[i].isOn) { + isHeating = true; + } + setOfSources[i].sortPerformanceMap(); + } + + if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) { + msg("heat source %d: %p \n", i, &setOfSources[i]); + } + msg("\n\n"); + } + + simHasFailed = false; + return 0; // successful init returns 0 +} // end HPWHinit_presets diff --git a/test/main.cc b/test/main.cc index 34817e9e..79a29458 100644 --- a/test/main.cc +++ b/test/main.cc @@ -13,487 +13,510 @@ #include #include #include -#include -#include // std::max +#include +#include // std::max #define MAX_DIR_LENGTH 255 using std::cout; using std::endl; -using std::string; using std::ifstream; -//using std::ofstream; +using std::string; +// using std::ofstream; typedef std::vector schedule; -int readSchedule(schedule &scheduleArray, string scheduleFileName, long minutesOfTest); +int readSchedule(schedule& scheduleArray, string scheduleFileName, long minutesOfTest); -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - HPWH hpwh; + HPWH hpwh; - 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; + 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 double EBALTHRESHOLD = 0.005; - const int nTestTCouples = 6; + const int nTestTCouples = 6; - const double soCMinTUse_C = F_TO_C(110.); - const double soCMains_C = F_TO_C(65.); + 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); + // Schedule stuff + std::vector scheduleNames; + std::vector allSchedules(7); - string testDirectory, fileToOpen, fileToOpen2, scheduleName, var1, input1, input2, input3, inputFile, outputDirectory; - string inputVariableName, firstCol; - double testVal, newSetpoint, airTemp, airTemp2, tempDepressThresh, inletH, newTankSize, tot_limit; - bool useSoC; - int i, outputCode; - long minutesToRun; + string testDirectory, fileToOpen, fileToOpen2, scheduleName, var1, input1, input2, input3, + inputFile, outputDirectory; + string inputVariableName, firstCol; + double testVal, newSetpoint, airTemp, airTemp2, tempDepressThresh, inletH, newTankSize, + tot_limit; + bool useSoC; + int i, outputCode; + long minutesToRun; - double cumHeatIn[3] = { 0,0,0 }; - double cumHeatOut[3] = { 0,0,0 }; + double cumHeatIn[3] = {0, 0, 0}; + double cumHeatOut[3] = {0, 0, 0}; - bool HPWH_doTempDepress; - int doInvMix, doCondu; + bool HPWH_doTempDepress; + int doInvMix, doCondu; - FILE * outputFile = NULL; - FILE * yearOutFile = NULL; - ifstream controlFile; + 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,"; + 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); + hpwh.setVerbosity(HPWH::VRB_reluctant); #endif - //....................................... - //process command line arguments - //....................................... - - cout << "Testing HPWHsim version " << HPWH::getVersion() << endl; - - //Obvious wrong number of command line arguments - if ((argc > 6)) { - cout << "Invalid input. This program takes FOUR arguments: model specification type (ie. Preset or File), model specification (ie. Sanden80), test name (ie. test50) and output directory\n"; - exit(1); - } - //Help message - if(argc > 1) { - input1 = argv[1]; - input2 = argv[2]; - input3 = argv[3]; - outputDirectory = argv[4]; - } else { - input1 = "asdf"; // Makes the next conditional not crash... a little clumsy but whatever - input2 = "def"; - input3 = "ghi"; - outputDirectory = "."; - } - if (argc < 5 || (argc > 6) || (input1 == "?") || (input1 == "help")) { - cout << "Standard usage: \"hpwhTestTool.x [model spec type Preset/File] [model spec Name] [testName] [airtemp override F (optional)]\"\n"; - cout << "All input files should be located in the test directory, with these names:\n"; - cout << "drawschedule.csv DRschedule.csv ambientTschedule.csv evaporatorTschedule.csv inletTschedule.csv hpwhProperties.csv\n"; - cout << "An output file, `modelname'Output.csv, will be written in the test directory\n"; - 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; - - // Parse the model - newSetpoint = 0; - if(input1 == "Preset") { - inputFile = ""; - - if (getHPWHObject(hpwh, input2) == 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") { - inputFile = input2 + ".txt"; - if (hpwh.HPWHinit_file(inputFile) != 0) exit(1); - } - else { - cout << "Invalid argument, received '"<< input1 << "', expected 'Preset' or 'File'.\n"; - exit(1); - } - -// hpwh.HPWHinit_resSwingTank(80., .95, 0., 10000., F_TO_C(125.)); - - // 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); - - // 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.; - doCondu = 1; - doInvMix = 1; - inletH = 0.; - newTankSize = 0.; - tot_limit = 0.; - useSoC = 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; + //....................................... + // process command line arguments + //....................................... + + cout << "Testing HPWHsim version " << HPWH::getVersion() << endl; + + // Obvious wrong number of command line arguments + if ((argc > 6)) { + cout << "Invalid input. This program takes FOUR arguments: model specification type (ie. " + "Preset or File), model specification (ie. Sanden80), test name (ie. test50) and " + "output directory\n"; + exit(1); + } + // Help message + if (argc > 1) { + input1 = argv[1]; + input2 = argv[2]; + input3 = argv[3]; + outputDirectory = argv[4]; + } + else { + input1 = "asdf"; // Makes the next conditional not crash... a little clumsy but whatever + input2 = "def"; + input3 = "ghi"; + outputDirectory = "."; + } + if (argc < 5 || (argc > 6) || (input1 == "?") || (input1 == "help")) { + cout << "Standard usage: \"hpwhTestTool.x [model spec type Preset/File] [model spec Name] " + "[testName] [airtemp override F (optional)]\"\n"; + cout << "All input files should be located in the test directory, with these names:\n"; + cout << "drawschedule.csv DRschedule.csv ambientTschedule.csv evaporatorTschedule.csv " + "inletTschedule.csv hpwhProperties.csv\n"; + cout << "An output file, `modelname'Output.csv, will be written in the test directory\n"; + 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; + + // Parse the model + newSetpoint = 0; + if (input1 == "Preset") { + inputFile = ""; + + if (getHPWHObject(hpwh, input2) == 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") { + inputFile = input2 + ".txt"; + if (hpwh.HPWHinit_file(inputFile) != 0) + exit(1); + } + else { + cout << "Invalid argument, received '" << input1 << "', expected 'Preset' or 'File'.\n"; + exit(1); + } + + // hpwh.HPWHinit_resSwingTank(80., .95, 0., 10000., F_TO_C(125.)); + + // 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); + + // 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.; + doCondu = 1; + doInvMix = 1; + inletH = 0.; + newTankSize = 0.; + tot_limit = 0.; + useSoC = 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 { + cout << var1 << " in testInfo.txt is an unrecogized key.\n"; + } + } + + if (minutesToRun == 0) { + 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); } - else if(var1 == "length_of_test") { - minutesToRun = (int) testVal; + + if (doCondu == 0) { + outputCode += hpwh.setDoConduction(false); + } + if (newSetpoint > 0) { + if (!allSchedules[5].empty()) { + hpwh.setSetpoint(allSchedules[5][0]); // expect this to fail sometimes + hpwh.resetTankToSetpoint(); + } + else { + hpwh.setSetpoint(newSetpoint); + hpwh.resetTankToSetpoint(); + } + } + if (inletH > 0) { + outputCode += hpwh.setInletByFraction(inletH); + } + if (newTankSize > 0) { + hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL); } - 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 { - cout << var1 << " in testInfo.txt is an unrecogized key.\n"; - } - } - - if(minutesToRun == 0) { - 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 (tot_limit > 0) { + outputCode += hpwh.setTimerLimitTOT(tot_limit); } - } - - 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 - hpwh.resetTankToSetpoint(); - } - else { - hpwh.setSetpoint(newSetpoint); - 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) { - cout << "Control file testInfo.txt has unsettable specifics in it. \n"; - exit(1); - } - - // ----------------------Open the Output Files and Print the Header---------------------------- // - - if (minutesToRun > 500000.) { - 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; - } - hpwh.WriteCSVHeading(outputFile, header.c_str(), nTestTCouples, 0); - } - - // ------------------------------------- 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 (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) { + cout << "Control file testInfo.txt has unsettable specifics in it. \n"; + exit(1); + } + + // ----------------------Open the Output Files and Print the Header---------------------------- + // // + + if (minutesToRun > 500000.) { + 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; + } + hpwh.WriteCSVHeading(outputFile, header.c_str(), nTestTCouples, 0); + } + + // ------------------------------------- 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"; + 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); - - // Check energy balance accounting. - double hpwhElect = 0; - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) { - hpwhElect += hpwh.getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); - } - double hpwhqHW = GAL_TO_L(allSchedules[1][i]) * (hpwh.getOutletTemp() - allSchedules[0][i]) - * HPWH::DENSITYWATER_kgperL - * HPWH::CPWATER_kJperkgC; - double hpwhqEnv = hpwh.getEnergyRemovedFromEnvironment(HPWH::UNITS_KJ); - double hpwhqLoss = hpwh.getStandbyLosses(HPWH::UNITS_KJ); - double deltaHC = hpwh.getTankHeatContent_kJ() - tankHCStart; - double qBal = hpwhqEnv// HP energy extracted from surround - - hpwhqLoss // tank loss to environment - + hpwhElect // electricity in from heat sources - - hpwhqHW // hot water energy from flows in and out - - deltaHC; // change in tank stored energy - - double fBal = fabs(qBal) / std::max(tankHCStart, 1.); - if (fBal > EBALTHRESHOLD){ - cout << "WARNING: On minute " << i << " HPWH has an energy balance error " << qBal << "kJ, " << 100*fBal << "%"<< "\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()) + ", "; - } - hpwh.WriteCSVRow(outputFile, strPreamble.c_str(), nTestTCouples, 0); - } - 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; + 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); + + // Check energy balance accounting. + double hpwhElect = 0; + for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) { + hpwhElect += hpwh.getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); + } + double hpwhqHW = GAL_TO_L(allSchedules[1][i]) * + (hpwh.getOutletTemp() - allSchedules[0][i]) * HPWH::DENSITYWATER_kgperL * + HPWH::CPWATER_kJperkgC; + double hpwhqEnv = hpwh.getEnergyRemovedFromEnvironment(HPWH::UNITS_KJ); + double hpwhqLoss = hpwh.getStandbyLosses(HPWH::UNITS_KJ); + double deltaHC = hpwh.getTankHeatContent_kJ() - tankHCStart; + double qBal = hpwhqEnv // HP energy extracted from surround + - hpwhqLoss // tank loss to environment + + hpwhElect // electricity in from heat sources + - hpwhqHW // hot water energy from flows in and out + - deltaHC; // change in tank stored energy + + double fBal = fabs(qBal) / std::max(tankHCStart, 1.); + if (fBal > EBALTHRESHOLD) { + cout << "WARNING: On minute " << i << " HPWH has an energy balance error " << qBal + << "kJ, " << 100 * fBal << "%" + << "\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()) + ", "; + } + hpwh.WriteCSVRow(outputFile, strPreamble.c_str(), nTestTCouples, 0); + } + 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'; -// 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; - } - // cout << valTmp << " minutes = " << minutesOfTest << "\n"; - - // Fill with the default value - scheduleArray.assign(minutesOfTest, valTmp); - - // Burn the first two lines - std::getline(inputFile, line); - std::getline(inputFile, 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 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) { - - 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"; - } - } - } - - inputFile.close(); - - return 0; + if (snippet != "default") { + cout << "First line of " << scheduleFileName << " must specify default\n"; + return 1; + } + // cout << valTmp << " minutes = " << minutesOfTest << "\n"; + + // Fill with the default value + scheduleArray.assign(minutesOfTest, valTmp); + + // Burn the first two lines + std::getline(inputFile, line); + std::getline(inputFile, 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 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) { + + 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"; + } + } + } + + inputFile.close(); + return 0; } \ No newline at end of file diff --git a/test/testCompressorFcts.cc b/test/testCompressorFcts.cc index ab13578b..a0d3d487 100644 --- a/test/testCompressorFcts.cc +++ b/test/testCompressorFcts.cc @@ -14,75 +14,140 @@ using std::cout; using std::string; - - -void testHasACompressor(string input, bool expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.hasACompressor() == expected); +void testHasACompressor(string input, bool expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.hasACompressor() == expected); } -void testGetCompCoilConfig(string input, int expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.getCompressorCoilConfig() == expected); +void testGetCompCoilConfig(string input, int expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.getCompressorCoilConfig() == expected); } -void testIsCompressorMultipass(string input, bool expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.isCompressorMultipass() == expected); +void testIsCompressorMultipass(string input, bool expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.isCompressorMultipass() == expected); } -void testIsCompressoExternalMultipass(string input, bool expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.isCompressoExternalMultipass() == expected); +void testIsCompressoExternalMultipass(string input, bool expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.isCompressoExternalMultipass() == expected); } -void testGetMaxCompressorSetpoint(string input, double expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.getMaxCompressorSetpoint() == expected); +void testGetMaxCompressorSetpoint(string input, double expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.getMaxCompressorSetpoint() == expected); } -void testGetMinOperatingTemp(string input, double expected) { - HPWH hpwh; - getHPWHObject(hpwh, input); // get preset model - ASSERTTRUE(hpwh.getMinOperatingTemp(HPWH::UNITS_F) == expected); +void testGetMinOperatingTemp(string input, double expected) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); // get preset model + ASSERTTRUE(hpwh.getMinOperatingTemp(HPWH::UNITS_F) == expected); } int main(int, char*) { - const int length = 14; - const string models [length] = {"AOSmithHPTU50", "Stiebel220e","AOSmithCAHP120", \ - "Sanden80", "ColmacCxV_5_SP", "ColmacCxA_20_SP", \ - "TamScalable_SP", "restankRealistic", "StorageTank", \ - "ColmacCxA_20_MP", "Scalable_MP", "NyleC90A_MP", "NyleC90A_C_MP", \ - "QAHV_N136TAU_HPB_SP"}; - const int hasComp[length] = { true, true, true, true, true, true, true, false, false, true, true, true, true, true }; - const int coilConfig[length] = { 1, 1, 1, 2, 2, 2, 2, HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, 2, 2, 2, 2, 2}; // 1 Wrapped 2 External - const int heatCycle[length] = { true, true, true, false, false, false, false, HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, true, true, true, true, false }; //true single, false singlepass - const int isExtMP[length] = { false, false, false, false, false, false, false, HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, true, true, true, true, false }; - - const double maxStpt[length] = { HPWH::MAXOUTLET_R134A, HPWH::MAXOUTLET_R134A,HPWH::MAXOUTLET_R134A, - HPWH::MAXOUTLET_R744, HPWH::MAXOUTLET_R410A, HPWH::MAXOUTLET_R134A, - HPWH::MAXOUTLET_R134A, HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, - HPWH::MAXOUTLET_R134A, HPWH::MAXOUTLET_R134A, F_TO_C(160.), F_TO_C(160.), F_TO_C(176.1) }; // deg C - - const double minTemp[length] = { 42., 32., 47., -25, -4., 40., 40., HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, 40., 40., 40., 35., -13.}; //deg F - - for (int i = 0; i < length; i++) { - testHasACompressor(models[i], hasComp[i]); - testGetCompCoilConfig(models[i], coilConfig[i]); - testIsCompressorMultipass(models[i], heatCycle[i]); - testIsCompressoExternalMultipass(models[i], isExtMP[i]); - - testGetMaxCompressorSetpoint(models[i], maxStpt[i]); - testGetMinOperatingTemp(models[i], minTemp[i]); - } - - //Made it through the gauntlet - return 0; + const int length = 14; + const string models[length] = {"AOSmithHPTU50", + "Stiebel220e", + "AOSmithCAHP120", + "Sanden80", + "ColmacCxV_5_SP", + "ColmacCxA_20_SP", + "TamScalable_SP", + "restankRealistic", + "StorageTank", + "ColmacCxA_20_MP", + "Scalable_MP", + "NyleC90A_MP", + "NyleC90A_C_MP", + "QAHV_N136TAU_HPB_SP"}; + const int hasComp[length] = { + true, true, true, true, true, true, true, false, false, true, true, true, true, true}; + const int coilConfig[length] = { + 1, 1, 1, 2, 2, 2, 2, HPWH::HPWH_ABORT, HPWH::HPWH_ABORT, 2, 2, 2, 2, 2}; // 1 Wrapped 2 + // External + const int heatCycle[length] = {true, + true, + true, + false, + false, + false, + false, + HPWH::HPWH_ABORT, + HPWH::HPWH_ABORT, + true, + true, + true, + true, + false}; // true single, false singlepass + const int isExtMP[length] = {false, + false, + false, + false, + false, + false, + false, + HPWH::HPWH_ABORT, + HPWH::HPWH_ABORT, + true, + true, + true, + true, + false}; + + const double maxStpt[length] = {HPWH::MAXOUTLET_R134A, + HPWH::MAXOUTLET_R134A, + HPWH::MAXOUTLET_R134A, + HPWH::MAXOUTLET_R744, + HPWH::MAXOUTLET_R410A, + HPWH::MAXOUTLET_R134A, + HPWH::MAXOUTLET_R134A, + HPWH::HPWH_ABORT, + HPWH::HPWH_ABORT, + HPWH::MAXOUTLET_R134A, + HPWH::MAXOUTLET_R134A, + F_TO_C(160.), + F_TO_C(160.), + F_TO_C(176.1)}; // deg C + + const double minTemp[length] = {42., + 32., + 47., + -25, + -4., + 40., + 40., + HPWH::HPWH_ABORT, + HPWH::HPWH_ABORT, + 40., + 40., + 40., + 35., + -13.}; // deg F + + for (int i = 0; i < length; i++) { + testHasACompressor(models[i], hasComp[i]); + testGetCompCoilConfig(models[i], coilConfig[i]); + testIsCompressorMultipass(models[i], heatCycle[i]); + testIsCompressoExternalMultipass(models[i], isExtMP[i]); + + testGetMaxCompressorSetpoint(models[i], maxStpt[i]); + testGetMinOperatingTemp(models[i], minTemp[i]); + } + + // Made it through the gauntlet + return 0; } diff --git a/test/testHeatingLogics.cc b/test/testHeatingLogics.cc index b166bada..55c477e3 100644 --- a/test/testHeatingLogics.cc +++ b/test/testHeatingLogics.cc @@ -2,7 +2,7 @@ #include "testUtilityFcts.cc" #include -#include +#include #include using std::cout; @@ -21,246 +21,290 @@ void testSetStateOfCharge(string& input); void testSetStateOfCharge(string& input, double coldWater_F, double minTUse_F, double tankTAt76SoC); -const std::vector hasHighShuttOffVectSP = { "Sanden80", "QAHV_N136TAU_HPB_SP", \ - "ColmacCxA_20_SP", "ColmacCxV_5_SP", "NyleC60A_SP", "NyleC60A_C_SP", "NyleC185A_C_SP", "TamScalable_SP" }; - -const std::vector noHighShuttOffVectMPExternal = {"Scalable_MP", "ColmacCxA_20_MP", "ColmacCxA_15_MP", \ - "ColmacCxV_5_MP", "NyleC90A_MP", "NyleC90A_C_MP" , "NyleC250A_MP", "NyleC250A_C_MP" }; - -const std::vector noHighShuttOffVectIntegrated = { "AOSmithHPTU80", "Rheem2020Build80", \ - "Stiebel220e", "AOSmithCAHP120", "AWHSTier3Generic80", "Generic1", "RheemPlugInDedicated50", \ - "RheemPlugInShared65", "restankRealistic", "StorageTank"}; - -int main(int, char*) { - double tempsForSetSoC[5][3] = { {49, 99, 125}, {65, 110, 129}, {32, 120, 121}, {32, 33, 121}, {80, 81, 132.5} }; - - for (string hpwhStr : hasHighShuttOffVectSP) { - testHasEnteringWaterShutOff(hpwhStr); - testSetEnteringWaterShuffOffOutOfBoundsIndex(hpwhStr); - testSetEnteringWaterShuffOffDeadbandToSmall(hpwhStr); - testSetEnteringWaterHighTempShutOffAbsolute(hpwhStr); - testSetEnteringWaterHighTempShutOffRelative(hpwhStr); - - testChangeToStateofChargeControlled(hpwhStr); - for (int i = 0; i < 5; i++) { - testSetStateOfCharge(hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); - } - } - - for (string hpwhStr : noHighShuttOffVectMPExternal) { - testDoesNotHaveEnteringWaterShutOff(hpwhStr); - testCanNotSetEnteringWaterShutOff(hpwhStr); - - testChangeToStateofChargeControlled(hpwhStr); - for (int i = 0; i < 5; i++) { - testSetStateOfCharge(hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); - } - } - - for (string hpwhStr : noHighShuttOffVectIntegrated) { - testDoesNotHaveEnteringWaterShutOff(hpwhStr); - testCanNotSetEnteringWaterShutOff(hpwhStr); - } - - return 0; +const std::vector hasHighShuttOffVectSP = {"Sanden80", + "QAHV_N136TAU_HPB_SP", + "ColmacCxA_20_SP", + "ColmacCxV_5_SP", + "NyleC60A_SP", + "NyleC60A_C_SP", + "NyleC185A_C_SP", + "TamScalable_SP"}; + +const std::vector noHighShuttOffVectMPExternal = {"Scalable_MP", + "ColmacCxA_20_MP", + "ColmacCxA_15_MP", + "ColmacCxV_5_MP", + "NyleC90A_MP", + "NyleC90A_C_MP", + "NyleC250A_MP", + "NyleC250A_C_MP"}; + +const std::vector noHighShuttOffVectIntegrated = {"AOSmithHPTU80", + "Rheem2020Build80", + "Stiebel220e", + "AOSmithCAHP120", + "AWHSTier3Generic80", + "Generic1", + "RheemPlugInDedicated50", + "RheemPlugInShared65", + "restankRealistic", + "StorageTank"}; + +int main(int, char*) +{ + double tempsForSetSoC[5][3] = { + {49, 99, 125}, {65, 110, 129}, {32, 120, 121}, {32, 33, 121}, {80, 81, 132.5}}; + + for (string hpwhStr : hasHighShuttOffVectSP) { + testHasEnteringWaterShutOff(hpwhStr); + testSetEnteringWaterShuffOffOutOfBoundsIndex(hpwhStr); + testSetEnteringWaterShuffOffDeadbandToSmall(hpwhStr); + testSetEnteringWaterHighTempShutOffAbsolute(hpwhStr); + testSetEnteringWaterHighTempShutOffRelative(hpwhStr); + + testChangeToStateofChargeControlled(hpwhStr); + for (int i = 0; i < 5; i++) { + testSetStateOfCharge( + hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); + } + } + + for (string hpwhStr : noHighShuttOffVectMPExternal) { + testDoesNotHaveEnteringWaterShutOff(hpwhStr); + testCanNotSetEnteringWaterShutOff(hpwhStr); + + testChangeToStateofChargeControlled(hpwhStr); + for (int i = 0; i < 5; i++) { + testSetStateOfCharge( + hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); + } + } + + for (string hpwhStr : noHighShuttOffVectIntegrated) { + testDoesNotHaveEnteringWaterShutOff(hpwhStr); + testCanNotSetEnteringWaterShutOff(hpwhStr); + } + + return 0; } -void testHasEnteringWaterShutOff(string& input) { - HPWH hpwh; - getHPWHObject(hpwh, input); - int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); - ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(index) == true); +void testHasEnteringWaterShutOff(string& input) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); + int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); + ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(index) == true); } -void testDoesNotHaveEnteringWaterShutOff(string& input) { - HPWH hpwh; - getHPWHObject(hpwh, input); - int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); - ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(index) == false); +void testDoesNotHaveEnteringWaterShutOff(string& input) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); + int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); + ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(index) == false); } -void testCanNotSetEnteringWaterShutOff(string& input) { - HPWH hpwh; - getHPWHObject(hpwh, input); - int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); +void testCanNotSetEnteringWaterShutOff(string& input) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); + int index = hpwh.getCompressorIndex() == -1 ? 0 : hpwh.getCompressorIndex(); + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); } -void testSetEnteringWaterShuffOffOutOfBoundsIndex(string& input) { - HPWH hpwh; - getHPWHObject(hpwh, input); - int index = -1; - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); - index = 15; - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); +void testSetEnteringWaterShuffOffOutOfBoundsIndex(string& input) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); + int index = -1; + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); + index = 15; + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(10., false, index) == HPWH::HPWH_ABORT); } -void testSetEnteringWaterShuffOffDeadbandToSmall(string& input) { - HPWH hpwh; - getHPWHObject(hpwh, input); +void testSetEnteringWaterShuffOffDeadbandToSmall(string& input) +{ + HPWH hpwh; + getHPWHObject(hpwh, input); + + double value = HPWH::MINSINGLEPASSLIFT - 1.; + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, false, hpwh.getCompressorIndex()) == + HPWH::HPWH_ABORT); - double value = HPWH::MINSINGLEPASSLIFT - 1.; - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, false, hpwh.getCompressorIndex()) == HPWH::HPWH_ABORT); - - value = HPWH::MINSINGLEPASSLIFT; - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, false, hpwh.getCompressorIndex()) == 0); + value = HPWH::MINSINGLEPASSLIFT; + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, false, hpwh.getCompressorIndex()) == 0); - value = hpwh.getSetpoint() - (HPWH::MINSINGLEPASSLIFT-1); - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, true, hpwh.getCompressorIndex()) == HPWH::HPWH_ABORT); + value = hpwh.getSetpoint() - (HPWH::MINSINGLEPASSLIFT - 1); + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, true, hpwh.getCompressorIndex()) == + HPWH::HPWH_ABORT); - value = hpwh.getSetpoint() - HPWH::MINSINGLEPASSLIFT; - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, true, hpwh.getCompressorIndex()) == 0); + value = hpwh.getSetpoint() - HPWH::MINSINGLEPASSLIFT; + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(value, true, hpwh.getCompressorIndex()) == 0); } -/* Tests we can set the entering water high temp shutt off with aboslute values and it works turns off and on as expected. */ -void testSetEnteringWaterHighTempShutOffAbsolute(string& input) { - const double drawVolume_L = 0.; - const double externalT_C = 20.; - const double delta = 2.; - const double highT_C = 20.; - const bool doAbsolute = true; - HPWH hpwh; - getHPWHObject(hpwh, input); - - // make tank cold to force on - hpwh.setTankToTemperature(highT_C); - - // run a step and check we're heating - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(compressorIsRunning(hpwh)); - - // change entering water temp to below temp - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(highT_C - delta, doAbsolute, hpwh.getCompressorIndex()) == 0); - - // run a step and check we're not heating. - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); - - // and reverse it - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(highT_C + delta, doAbsolute, hpwh.getCompressorIndex()) == 0); - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(compressorIsRunning(hpwh)); +/* Tests we can set the entering water high temp shutt off with aboslute values and it works turns + * off and on as expected. */ +void testSetEnteringWaterHighTempShutOffAbsolute(string& input) +{ + const double drawVolume_L = 0.; + const double externalT_C = 20.; + const double delta = 2.; + const double highT_C = 20.; + const bool doAbsolute = true; + HPWH hpwh; + getHPWHObject(hpwh, input); + + // make tank cold to force on + hpwh.setTankToTemperature(highT_C); + + // run a step and check we're heating + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(compressorIsRunning(hpwh)); + + // change entering water temp to below temp + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( + highT_C - delta, doAbsolute, hpwh.getCompressorIndex()) == 0); + + // run a step and check we're not heating. + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); + + // and reverse it + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( + highT_C + delta, doAbsolute, hpwh.getCompressorIndex()) == 0); + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(compressorIsRunning(hpwh)); } -/* Tests we can set the entering water high temp shutt off with relative values and it works turns off and on as expected. */ -void testSetEnteringWaterHighTempShutOffRelative(string& input) { - const double drawVolume_L = 0.; - const double externalT_C = 20.; - const double delta = 2.; - const double highT_C = 20.; - const bool doAbsolute = false; - HPWH hpwh; - getHPWHObject(hpwh, input); - - const double relativeHighT_C = hpwh.getSetpoint() - highT_C; - // make tank cold to force on - hpwh.setTankToTemperature(highT_C); - - // run a step and check we're heating - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 1); - - // change entering water temp to below temp - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(relativeHighT_C + delta, doAbsolute, hpwh.getCompressorIndex()) == 0); - - // run a step and check we're not heating. - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 0); - - // and reverse it - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(relativeHighT_C - delta, doAbsolute, hpwh.getCompressorIndex()) == 0); - hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 1); +/* Tests we can set the entering water high temp shutt off with relative values and it works turns + * off and on as expected. */ +void testSetEnteringWaterHighTempShutOffRelative(string& input) +{ + const double drawVolume_L = 0.; + const double externalT_C = 20.; + const double delta = 2.; + const double highT_C = 20.; + const bool doAbsolute = false; + HPWH hpwh; + getHPWHObject(hpwh, input); + + const double relativeHighT_C = hpwh.getSetpoint() - highT_C; + // make tank cold to force on + hpwh.setTankToTemperature(highT_C); + + // run a step and check we're heating + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 1); + + // change entering water temp to below temp + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( + relativeHighT_C + delta, doAbsolute, hpwh.getCompressorIndex()) == 0); + + // run a step and check we're not heating. + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 0); + + // and reverse it + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( + relativeHighT_C - delta, doAbsolute, hpwh.getCompressorIndex()) == 0); + hpwh.runOneStep(highT_C, drawVolume_L, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()) == 1); } /* Test we can switch and the controls change as expected*/ -void testChangeToStateofChargeControlled(string& input) { - HPWH hpwh; - const double externalT_C = 20.; - const double setpointT_C = F_TO_C(149.); - - getHPWHObject(hpwh, input); - const bool originalHasHighTempShutOff = hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex()); - if (!hpwh.isSetpointFixed()) { - double temp; - string tempStr; - if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { - return; // Numbers don't aline for this type - } - hpwh.setSetpoint(setpointT_C); - } - - //Just created so should be fasle - ASSERTFALSE(hpwh.isSoCControlled()); - - // change to SOC control; - hpwh.switchToSoCControls(.76, .05, 99, true, 49, HPWH::UNITS_F); - ASSERTTRUE(hpwh.isSoCControlled()); - - // check entering water high temp shut off controll unchanged - ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex()) == originalHasHighTempShutOff); - - // Test we can change the SoC and run a step and check we're heating - if (hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex())) { - ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff(setpointT_C-HPWH::MINSINGLEPASSLIFT, true, hpwh.getCompressorIndex()) == 0); // Force to ignore this part. - } - ASSERTTRUE(hpwh.setTankToTemperature(F_TO_C(100.)) == 0); // .51 - hpwh.runOneStep( 0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(compressorIsRunning(hpwh)); - - // Test if we're on and in band stay on - hpwh.setTankToTemperature(F_TO_C(125)); // .76 (current target) - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(compressorIsRunning(hpwh)); - - // Test we can change the SoC and turn off - hpwh.setTankToTemperature(F_TO_C(133)); // .84 - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); - - // Test if off and in band stay off - hpwh.setTankToTemperature(F_TO_C(125)); // .76 (current target) - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); +void testChangeToStateofChargeControlled(string& input) +{ + HPWH hpwh; + const double externalT_C = 20.; + const double setpointT_C = F_TO_C(149.); + + getHPWHObject(hpwh, input); + const bool originalHasHighTempShutOff = + hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex()); + if (!hpwh.isSetpointFixed()) { + double temp; + string tempStr; + if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { + return; // Numbers don't aline for this type + } + hpwh.setSetpoint(setpointT_C); + } + + // Just created so should be fasle + ASSERTFALSE(hpwh.isSoCControlled()); + + // change to SOC control; + hpwh.switchToSoCControls(.76, .05, 99, true, 49, HPWH::UNITS_F); + ASSERTTRUE(hpwh.isSoCControlled()); + + // check entering water high temp shut off controll unchanged + ASSERTTRUE(hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex()) == + originalHasHighTempShutOff); + + // Test we can change the SoC and run a step and check we're heating + if (hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex())) { + ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( + setpointT_C - HPWH::MINSINGLEPASSLIFT, true, hpwh.getCompressorIndex()) == + 0); // Force to ignore this part. + } + ASSERTTRUE(hpwh.setTankToTemperature(F_TO_C(100.)) == 0); // .51 + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(compressorIsRunning(hpwh)); + + // Test if we're on and in band stay on + hpwh.setTankToTemperature(F_TO_C(125)); // .76 (current target) + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(compressorIsRunning(hpwh)); + + // Test we can change the SoC and turn off + hpwh.setTankToTemperature(F_TO_C(133)); // .84 + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); + + // Test if off and in band stay off + hpwh.setTankToTemperature(F_TO_C(125)); // .76 (current target) + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); } /*Test we can change the target and turn off and on*/ -void testSetStateOfCharge(string& input, double coldWater_F, double minTUse_F, double tankTAt76SoC) { - HPWH hpwh; - const double externalT_C = 20.; - const double setpointT_C = F_TO_C(149.); - - getHPWHObject(hpwh, input); - if (!hpwh.isSetpointFixed()) { - double temp; - string tempStr; - if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { - return; // Numbers don't aline for this type - } - hpwh.setSetpoint(setpointT_C); - } - - // change to SOC control; - hpwh.switchToSoCControls(.85, .05, minTUse_F, true, coldWater_F, HPWH::UNITS_F); - ASSERTTRUE(hpwh.isSoCControlled()); - - // Test if we're on and in band stay on - hpwh.setTankToTemperature(F_TO_C(tankTAt76SoC)); // .76 - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTTRUE(compressorIsRunning(hpwh)); - - // Test we can change the target SoC and turn off - hpwh.setTargetSoCFraction(0.5); - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); - - // Change back in the band and stay turned off - hpwh.setTargetSoCFraction(0.72); - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); - - // Drop below the band and turn on - hpwh.setTargetSoCFraction(0.70); - hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); - ASSERTFALSE(compressorIsRunning(hpwh)); +void testSetStateOfCharge(string& input, double coldWater_F, double minTUse_F, double tankTAt76SoC) +{ + HPWH hpwh; + const double externalT_C = 20.; + const double setpointT_C = F_TO_C(149.); + + getHPWHObject(hpwh, input); + if (!hpwh.isSetpointFixed()) { + double temp; + string tempStr; + if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { + return; // Numbers don't aline for this type + } + hpwh.setSetpoint(setpointT_C); + } + + // change to SOC control; + hpwh.switchToSoCControls(.85, .05, minTUse_F, true, coldWater_F, HPWH::UNITS_F); + ASSERTTRUE(hpwh.isSoCControlled()); + + // Test if we're on and in band stay on + hpwh.setTankToTemperature(F_TO_C(tankTAt76SoC)); // .76 + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTTRUE(compressorIsRunning(hpwh)); + + // Test we can change the target SoC and turn off + hpwh.setTargetSoCFraction(0.5); + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); + + // Change back in the band and stay turned off + hpwh.setTargetSoCFraction(0.72); + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); + + // Drop below the band and turn on + hpwh.setTargetSoCFraction(0.70); + hpwh.runOneStep(0, externalT_C, externalT_C, HPWH::DR_ALLOW); + ASSERTFALSE(compressorIsRunning(hpwh)); } diff --git a/test/testMaxSetpoint.cc b/test/testMaxSetpoint.cc index bb6241d2..5181b8a9 100644 --- a/test/testMaxSetpoint.cc +++ b/test/testMaxSetpoint.cc @@ -9,13 +9,11 @@ #include "testUtilityFcts.cc" #include -#include - +#include using std::cout; using std::string; - void testMaxSetpointResistanceTank(); void testScalableCompressor(); void testJustR134ACompressor(); @@ -29,178 +27,189 @@ const double REMaxShouldBe = 100.; int main(int, char*) { - testMaxSetpointResistanceTank(); - testScalableCompressor(); - testJustR134ACompressor(); - testJustR410ACompressor(); - testJustQAHVCompressor(); - testHybridModel(); - testStorageTankSetpoint(); - testSetpointFixed(); - - //Made it through the gauntlet - return 0; + testMaxSetpointResistanceTank(); + testScalableCompressor(); + testJustR134ACompressor(); + testJustR410ACompressor(); + testJustQAHVCompressor(); + testHybridModel(); + testStorageTankSetpoint(); + testSetpointFixed(); + + // Made it through the gauntlet + return 0; } -void testMaxSetpointResistanceTank() { - HPWH hpwh; - double num; - string why; - hpwh.HPWHinit_resTank(); - - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(100., num, why)); // Can go to boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb - ASSERTTRUE(REMaxShouldBe == num); - - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(99.) == 0) +void testMaxSetpointResistanceTank() +{ + HPWH hpwh; + double num; + string why; + hpwh.HPWHinit_resTank(); + + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(100., num, why)); // Can go to boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb + ASSERTTRUE(REMaxShouldBe == num); + + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(99.) == 0) } -void testScalableCompressor() { - HPWH hpwh; +void testScalableCompressor() +{ + HPWH hpwh; - string input = "TamScalable_SP"; // Just a compressor with R134A - double num; - string why; + string input = "TamScalable_SP"; // Just a compressor with R134A + double num; + string why; - getHPWHObject(hpwh, input); + getHPWHObject(hpwh, input); - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal - ASSERTTRUE(hpwh.isNewSetpointPossible(100, num, why)); // Can go to programed max + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal + ASSERTTRUE(hpwh.isNewSetpointPossible(100, num, why)); // Can go to programed max - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(50.) == 0) + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(50.) == 0) } -void testJustR134ACompressor() { - HPWH hpwh; +void testJustR134ACompressor() +{ + HPWH hpwh; - string input = "NyleC90A_SP"; // Just a compressor with R134A - double num; - string why; + string input = "NyleC90A_SP"; // Just a compressor with R134A + double num; + string why; - getHPWHObject(hpwh, input); + getHPWHObject(hpwh, input); - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling - ASSERTTRUE(HPWH::MAXOUTLET_R134A == num); //Assert we're getting the right number - ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal - ASSERTTRUE(hpwh.isNewSetpointPossible(HPWH::MAXOUTLET_R134A, num, why)); // Can go to programed max + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling + ASSERTTRUE(HPWH::MAXOUTLET_R134A == num); // Assert we're getting the right number + ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal + ASSERTTRUE( + hpwh.isNewSetpointPossible(HPWH::MAXOUTLET_R134A, num, why)); // Can go to programed max - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(50.) == 0) + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(50.) == 0) } -void testJustR410ACompressor() { - HPWH hpwh; - string input = "ColmacCxV_5_SP"; // Just a compressor with R410A - double num; - string why; - - getHPWHObject(hpwh, input); - - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling - ASSERTTRUE(HPWH::MAXOUTLET_R410A == num); //Assert we're getting the right number - ASSERTTRUE(hpwh.isNewSetpointPossible(50., num, why)); // Can go to normal - ASSERTTRUE(hpwh.isNewSetpointPossible(HPWH::MAXOUTLET_R410A, num, why)); // Can go to programed max - - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(50.) == 0) +void testJustR410ACompressor() +{ + HPWH hpwh; + string input = "ColmacCxV_5_SP"; // Just a compressor with R410A + double num; + string why; + + getHPWHObject(hpwh, input); + + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling + ASSERTTRUE(HPWH::MAXOUTLET_R410A == num); // Assert we're getting the right number + ASSERTTRUE(hpwh.isNewSetpointPossible(50., num, why)); // Can go to normal + ASSERTTRUE( + hpwh.isNewSetpointPossible(HPWH::MAXOUTLET_R410A, num, why)); // Can go to programed max + + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(50.) == 0) } -void testJustQAHVCompressor() { - HPWH hpwh; - string input = "QAHV_N136TAU_HPB_SP"; - double num; - string why; +void testJustQAHVCompressor() +{ + HPWH hpwh; + string input = "QAHV_N136TAU_HPB_SP"; + double num; + string why; - getHPWHObject(hpwh, input); + getHPWHObject(hpwh, input); - const double maxQAHVSetpoint = F_TO_C(176.1); - const double qAHVHotSideTemepratureOffset = dF_TO_dC(15.); + const double maxQAHVSetpoint = F_TO_C(176.1); + const double qAHVHotSideTemepratureOffset = dF_TO_dC(15.); - // isNewSetpointPossible should be fine, we aren't changing the setpoint of the Sanden. - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling + // isNewSetpointPossible should be fine, we aren't changing the setpoint of the Sanden. + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal + ASSERTTRUE(hpwh.isNewSetpointPossible(60., num, why)); // Can go to normal - ASSERTFALSE(hpwh.isNewSetpointPossible(maxQAHVSetpoint, num, why)); - ASSERTTRUE(hpwh.isNewSetpointPossible(maxQAHVSetpoint-qAHVHotSideTemepratureOffset, num, why)); + ASSERTFALSE(hpwh.isNewSetpointPossible(maxQAHVSetpoint, num, why)); + ASSERTTRUE( + hpwh.isNewSetpointPossible(maxQAHVSetpoint - qAHVHotSideTemepratureOffset, num, why)); - // Check this carries over into setting the setpoint. - ASSERTTRUE(hpwh.setSetpoint(101) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwh.setSetpoint(maxQAHVSetpoint) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwh.setSetpoint(maxQAHVSetpoint - qAHVHotSideTemepratureOffset) == 0); + // Check this carries over into setting the setpoint. + ASSERTTRUE(hpwh.setSetpoint(101) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setSetpoint(maxQAHVSetpoint) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setSetpoint(maxQAHVSetpoint - qAHVHotSideTemepratureOffset) == 0); } -void testHybridModel() { - HPWH hpwh; - string input = "AOSmithCAHP120"; //Hybrid unit with a compressor with R134A - double num; - string why; - - getHPWHObject(hpwh, input); - - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(100., num, why)); // Can go to boiling - ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb - ASSERTTRUE(REMaxShouldBe == num); // Max is boiling - - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(99.) == 0) // Can go lower than boiling though +void testHybridModel() +{ + HPWH hpwh; + string input = "AOSmithCAHP120"; // Hybrid unit with a compressor with R134A + double num; + string why; + + getHPWHObject(hpwh, input); + + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(100., num, why)); // Can go to boiling + ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb + ASSERTTRUE(REMaxShouldBe == num); // Max is boiling + + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(99.) == 0) // Can go lower than boiling though } -void testStorageTankSetpoint() { - HPWH hpwh; - string input = "StorageTank"; //Hybrid unit with a compressor with R134A - double num; - string why; - - getHPWHObject(hpwh, input); +void testStorageTankSetpoint() +{ + HPWH hpwh; + string input = "StorageTank"; // Hybrid unit with a compressor with R134A + double num; + string why; - // Storage tanks have free reign! - ASSERTTRUE(hpwh.isNewSetpointPossible(101., num, why)); // Can go above boiling! - ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling! - ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb + getHPWHObject(hpwh, input); - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == 0); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(99.) == 0) // Can go lower than boiling though + // Storage tanks have free reign! + ASSERTTRUE(hpwh.isNewSetpointPossible(101., num, why)); // Can go above boiling! + ASSERTTRUE(hpwh.isNewSetpointPossible(99., num, why)); // Can go to near boiling! + ASSERTTRUE(hpwh.isNewSetpointPossible(10., num, why)); // Can go low, albiet dumb + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == 0); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(99.) == 0) // Can go lower than boiling though } -void testSetpointFixed() { - HPWH hpwh; - string input = "Sanden80"; //Fixed setpoint model - double num, num1; - string why; - - getHPWHObject(hpwh, input); - - // Storage tanks have free reign! - ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling! - ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling! - ASSERTFALSE(hpwh.isNewSetpointPossible(60., num, why)); // Can't go to normalish - ASSERTFALSE(hpwh.isNewSetpointPossible(10., num, why)); // Can't go low, albiet dumb - - ASSERTTRUE(num == hpwh.getSetpoint()); // Make sure it thinks the max is the setpoint - ASSERTTRUE(hpwh.isNewSetpointPossible(num, num1, why)) // Check that the setpoint can be set to the setpoint. - - // Check this carries over into setting the setpoint - ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling - ASSERTTRUE(hpwh.setSetpoint(99.) == HPWH::HPWH_ABORT) // Can go lower than boiling though - ASSERTTRUE(hpwh.setSetpoint(60.) == HPWH::HPWH_ABORT); // Can't go to normalish - ASSERTTRUE(hpwh.setSetpoint(10.) == HPWH::HPWH_ABORT); // Can't go low, albiet dumb +void testSetpointFixed() +{ + HPWH hpwh; + string input = "Sanden80"; // Fixed setpoint model + double num, num1; + string why; + + getHPWHObject(hpwh, input); + + // Storage tanks have free reign! + ASSERTFALSE(hpwh.isNewSetpointPossible(101., num, why)); // Can't go above boiling! + ASSERTFALSE(hpwh.isNewSetpointPossible(99., num, why)); // Can't go to near boiling! + ASSERTFALSE(hpwh.isNewSetpointPossible(60., num, why)); // Can't go to normalish + ASSERTFALSE(hpwh.isNewSetpointPossible(10., num, why)); // Can't go low, albiet dumb + + ASSERTTRUE(num == hpwh.getSetpoint()); // Make sure it thinks the max is the setpoint + ASSERTTRUE(hpwh.isNewSetpointPossible( + num, num1, why)) // Check that the setpoint can be set to the setpoint. + + // Check this carries over into setting the setpoint + ASSERTTRUE(hpwh.setSetpoint(101.) == HPWH::HPWH_ABORT); // Can't go above boiling + ASSERTTRUE(hpwh.setSetpoint(99.) == HPWH::HPWH_ABORT) // Can go lower than boiling though + ASSERTTRUE(hpwh.setSetpoint(60.) == HPWH::HPWH_ABORT); // Can't go to normalish + ASSERTTRUE(hpwh.setSetpoint(10.) == HPWH::HPWH_ABORT); // Can't go low, albiet dumb } \ No newline at end of file diff --git a/test/testPerformanceMaps.cc b/test/testPerformanceMaps.cc index 5f90aa00..d8eec1d0 100644 --- a/test/testPerformanceMaps.cc +++ b/test/testPerformanceMaps.cc @@ -6,7 +6,7 @@ #include "testUtilityFcts.cc" #include -#include +#include using std::cout; using std::string; @@ -15,561 +15,666 @@ const double tInOffsetQAHV_dF = 10.; const double tOutOffsetQAHV_dF = 15.; struct performancePointMP { - double tairF; - double tinF; - double outputBTUH; + double tairF; + double tinF; + double outputBTUH; }; -double getCapacityMP_F_KW(HPWH& hpwh, performancePointMP& point) { - return hpwh.getCompressorCapacity(point.tairF, point.tinF, point.tinF, HPWH::UNITS_KW, HPWH::UNITS_F); +double getCapacityMP_F_KW(HPWH& hpwh, performancePointMP& point) +{ + return hpwh.getCompressorCapacity( + point.tairF, point.tinF, point.tinF, HPWH::UNITS_KW, HPWH::UNITS_F); } struct performancePointSP { - double tairF; - double toutF; - double tinF; - double outputBTUH; + double tairF; + double toutF; + double tinF; + double outputBTUH; }; -double getCapacitySP_F_BTUHR(HPWH& hpwh, performancePointSP& point) { - return hpwh.getCompressorCapacity(point.tairF, point.tinF, point.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); +double getCapacitySP_F_BTUHR(HPWH& hpwh, performancePointSP& point) +{ + return hpwh.getCompressorCapacity( + point.tairF, point.tinF, point.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); } -double getCapacitySP_F_BTUHR(HPWH& hpwh, performancePointSP& point, double tInOffSet_dF, double tOutOffSet_dF) { - return hpwh.getCompressorCapacity(point.tairF, point.tinF-tInOffSet_dF, point.toutF-tOutOffSet_dF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); +double getCapacitySP_F_BTUHR(HPWH& hpwh, + performancePointSP& point, + double tInOffSet_dF, + double tOutOffSet_dF) +{ + return hpwh.getCompressorCapacity(point.tairF, + point.tinF - tInOffSet_dF, + point.toutF - tOutOffSet_dF, + HPWH::UNITS_BTUperHr, + HPWH::UNITS_F); } -void testCXA15MatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_15_SP"; - double capacity_kW, capacity_BTUperHr; - // get preset model - getHPWHObject(hpwh, input); - - // test hot ////////////////////////// - double airTempF = 100.; - double waterTempF = 125.; - double setpointF = 150.; - double capacityData_kW = 52.779317; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); - - // test middle //////////////// - airTempF = 80.; - waterTempF = 40.; - setpointF = 150.; - capacityData_kW = 44.962957379; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); - - // test cold //////////////// - airTempF = 60.; - waterTempF = 40.; - setpointF = 125.; - capacityData_kW = 37.5978306881; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); +void testCXA15MatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_15_SP"; + double capacity_kW, capacity_BTUperHr; + // get preset model + getHPWHObject(hpwh, input); + + // test hot ////////////////////////// + double airTempF = 100.; + double waterTempF = 125.; + double setpointF = 150.; + double capacityData_kW = 52.779317; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); + + // test middle //////////////// + airTempF = 80.; + waterTempF = 40.; + setpointF = 150.; + capacityData_kW = 44.962957379; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); + + // test cold //////////////// + airTempF = 60.; + waterTempF = 40.; + setpointF = 125.; + capacityData_kW = 37.5978306881; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); } -void testCXA30MatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_30_SP"; - double capacity_kW, capacity_BTUperHr; - // get preset model - getHPWHObject(hpwh, input); - - // test hot ////////////////////////// - double airTempF = 100.; - double waterTempF = 125.; - double setpointF = 150.; - double capacityData_kW = 105.12836804; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); - - // test middle //////////////// - airTempF = 80.; - waterTempF = 40.; - setpointF = 150.; - capacityData_kW = 89.186101453; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); - - // test cold //////////////// - airTempF = 60.; - waterTempF = 40.; - setpointF = 125.; - capacityData_kW = 74.2437689948; - - capacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - capacity_kW = hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); - - ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); - ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); +void testCXA30MatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_30_SP"; + double capacity_kW, capacity_BTUperHr; + // get preset model + getHPWHObject(hpwh, input); + + // test hot ////////////////////////// + double airTempF = 100.; + double waterTempF = 125.; + double setpointF = 150.; + double capacityData_kW = 105.12836804; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); + + // test middle //////////////// + airTempF = 80.; + waterTempF = 40.; + setpointF = 150.; + capacityData_kW = 89.186101453; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); + + // test cold //////////////// + airTempF = 60.; + waterTempF = 40.; + setpointF = 125.; + capacityData_kW = 74.2437689948; + + capacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + capacity_kW = + hpwh.getCompressorCapacity(F_TO_C(airTempF), F_TO_C(waterTempF), F_TO_C(setpointF)); + + ASSERTTRUE(relcmpd(KWH_TO_BTU(capacityData_kW), capacity_BTUperHr)); + ASSERTTRUE(relcmpd(capacityData_kW, capacity_kW)); } // Colmac MP perfmaps tests -void testCXV5MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxV_5_MP"; - performancePointMP checkPoint; +void testCXV5MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxV_5_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 10.0, 60.0, 8.7756391 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {10.0, 60.0, 8.7756391}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 10.0, 102.0, 9.945545 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {10.0, 102.0, 9.945545}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 70.0, 74.0, 19.09682784 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {70.0, 74.0, 19.09682784}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 70.0, 116.0, 18.97090763 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {70.0, 116.0, 18.97090763}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 116.0, 24.48703111 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 116.0, 24.48703111}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testCXA10MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_10_MP"; - performancePointMP checkPoint; +void testCXA10MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_10_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 66.0, 29.36581754 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {60.0, 66.0, 29.36581754}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 60.0, 114.0, 27.7407144 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {60.0, 114.0, 27.7407144}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 66.0, 37.4860496 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 66.0, 37.4860496}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 114.0, 35.03416199 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 114.0, 35.03416199}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 66.0, 46.63144 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 66.0, 46.63144}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 114.0, 43.4308219 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 114.0, 43.4308219}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testCXA15MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_15_MP"; - performancePointMP checkPoint; +void testCXA15MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_15_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 66.0, 37.94515042 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {60.0, 66.0, 37.94515042}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 60.0, 114.0, 35.2295393 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {60.0, 114.0, 35.2295393}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 66.0, 50.360549115 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 66.0, 50.360549115}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 114.0, 43.528417017 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 114.0, 43.528417017}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 66.0, 66.2675493 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 66.0, 66.2675493}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 114.0, 55.941855 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 114.0, 55.941855}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testCXA20MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_20_MP"; - performancePointMP checkPoint; +void testCXA20MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_20_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 66.0, 57.0994624 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {60.0, 66.0, 57.0994624}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 60.0, 114.0, 53.554293 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {60.0, 114.0, 53.554293}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 66.0, 73.11242842 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 66.0, 73.11242842}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 114.0, 68.034677 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - - checkPoint = { 100.0, 66.0, 90.289474295 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - - checkPoint = { 100.0, 114.0, 84.69323 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 114.0, 68.034677}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + + checkPoint = {100.0, 66.0, 90.289474295}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + + checkPoint = {100.0, 114.0, 84.69323}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testCXA25MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_25_MP"; - performancePointMP checkPoint; +void testCXA25MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_25_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 66.0, 67.28116620 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {60.0, 66.0, 67.28116620}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 60.0, 114.0, 63.5665037 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {60.0, 114.0, 63.5665037}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 66.0, 84.9221285742 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 66.0, 84.9221285742}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 114.0, 79.6237088 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 114.0, 79.6237088}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 66.0, 103.43268186 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - - checkPoint = { 100.0, 114.0, 97.71458413 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 66.0, 103.43268186}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + + checkPoint = {100.0, 114.0, 97.71458413}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testCXA30MPMatchesDataMap() { - HPWH hpwh; - string input = "ColmacCxA_30_MP"; - performancePointMP checkPoint; +void testCXA30MPMatchesDataMap() +{ + HPWH hpwh; + string input = "ColmacCxA_30_MP"; + performancePointMP checkPoint; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 66.0, 76.741462845 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - - checkPoint = { 60.0, 114.0, 73.66879620 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + // test some points outside of defrost //////////////// + checkPoint = {60.0, 66.0, 76.741462845}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 66.0, 94.863116775 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {60.0, 114.0, 73.66879620}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 114.0, 90.998904269 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 66.0, 94.863116775}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 66.0, 112.864628 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 114.0, 90.998904269}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 100.0, 114.0, 109.444451 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {100.0, 66.0, 112.864628}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + + checkPoint = {100.0, 114.0, 109.444451}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testRheemHPHD60() { - //MODELS_RHEEM_HPHD60HNU_201_MP - //MODELS_RHEEM_HPHD60VNU_201_MP - HPWH hpwh; - string input = "RheemHPHD60"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 66.6666666, 60.0, 16.785535996 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 66.6666666, 120.0, 16.76198953 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 88.3333333, 80.0, 20.8571194294 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 110.0, 100.0, 24.287512 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testRheemHPHD60() +{ + // MODELS_RHEEM_HPHD60HNU_201_MP + // MODELS_RHEEM_HPHD60VNU_201_MP + HPWH hpwh; + string input = "RheemHPHD60"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {66.6666666, 60.0, 16.785535996}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {66.6666666, 120.0, 16.76198953}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {88.3333333, 80.0, 20.8571194294}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {110.0, 100.0, 24.287512}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testRheemHPHD135() { - //MODELS_RHEEM_HPHD135HNU_483_MP - //MODELS_RHEEM_HPHD135VNU_483_MP - HPWH hpwh; - string input = "RheemHPHD135"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 66.6666666, 80.0, 38.560161199 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 66.6666666, 140.0, 34.70681846 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 88.3333333, 140.0, 42.40407101 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 110.0, 120.0, 54.3580927 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testRheemHPHD135() +{ + // MODELS_RHEEM_HPHD135HNU_483_MP + // MODELS_RHEEM_HPHD135VNU_483_MP + HPWH hpwh; + string input = "RheemHPHD135"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {66.6666666, 80.0, 38.560161199}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {66.6666666, 140.0, 34.70681846}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {88.3333333, 140.0, 42.40407101}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {110.0, 120.0, 54.3580927}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testNyleC60AMP() { - HPWH hpwh; - string input = "NyleC60A_MP"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 60.0, 16.11 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 60.0, 21.33 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 90.0, 130.0, 19.52 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testNyleC60AMP() +{ + HPWH hpwh; + string input = "NyleC60A_MP"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {60.0, 60.0, 16.11}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 60.0, 21.33}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {90.0, 130.0, 19.52}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testNyleC90AMP() { - HPWH hpwh; - string input = "NyleC90A_MP"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 60.0, 28.19 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 60.0, 37.69 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 90.0, 130.0, 36.27 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testNyleC90AMP() +{ + HPWH hpwh; + string input = "NyleC90A_MP"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {60.0, 60.0, 28.19}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 60.0, 37.69}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {90.0, 130.0, 36.27}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testNyleC125AMP() { - HPWH hpwh; - string input = "NyleC125A_MP"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 60.0, 36.04}; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 60.0, 47.86 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 90.0, 130.0, 43.80}; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testNyleC125AMP() +{ + HPWH hpwh; + string input = "NyleC125A_MP"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {60.0, 60.0, 36.04}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 60.0, 47.86}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {90.0, 130.0, 43.80}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testNyleC185AMP() { - HPWH hpwh; - string input = "NyleC185A_MP"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 60.0, 55.00}; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 60.0, 74.65 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 90.0, 130.0, 67.52 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testNyleC185AMP() +{ + HPWH hpwh; + string input = "NyleC185A_MP"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {60.0, 60.0, 55.00}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 60.0, 74.65}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {90.0, 130.0, 67.52}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testNyleC250AMP() { - HPWH hpwh; - string input = "NyleC250A_MP"; - performancePointMP checkPoint; - - // get preset model - getHPWHObject(hpwh, input); - - // test some points outside of defrost //////////////// - checkPoint = { 60.0, 60.0, 75.70 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 80.0, 60.0, 103.40 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); - checkPoint = { 90.0, 130.0, 77.89 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); +void testNyleC250AMP() +{ + HPWH hpwh; + string input = "NyleC250A_MP"; + performancePointMP checkPoint; + + // get preset model + getHPWHObject(hpwh, input); + + // test some points outside of defrost //////////////// + checkPoint = {60.0, 60.0, 75.70}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {80.0, 60.0, 103.40}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); + checkPoint = {90.0, 130.0, 77.89}; + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacityMP_F_KW(hpwh, checkPoint))); } -void testQAHVMatchesDataMap() { - HPWH hpwh; - string input = "QAHV_N136TAU_HPB_SP"; - performancePointSP checkPoint; // tairF, toutF, tinF, outputW - double outputBTUH; - getHPWHObject(hpwh, input); - - // test - checkPoint = { -13.0, 140.0, 41.0, 66529.49616 }; - outputBTUH = getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF); - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); - // test - checkPoint = { -13.0, 176.0, 41.0, 65872.597448 }; - ASSERTTRUE(getCapacitySP_F_BTUHR(hpwh, checkPoint) == HPWH::HPWH_ABORT); // max setpoint without adjustment forces error - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { -13.0, 176.0, 84.2, 55913.249232 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 14.0, 176.0, 84.2, 92933.01932 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 42.8, 140.0, 41.0, 136425.98804}; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 50.0, 140.0, 41.0, 136425.98804 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 50.0, 176.0, 84.2, 136564.470884}; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 60.8, 158.0, 84.2, 136461.998288 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 71.6, 158.0, 48.2, 136498.001712 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - - // test constant with setpoint between 140 and 158 - checkPoint = { 71.6, 149.0, 48.2, 136498.001712 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 82.4, 176.0, 41.0, 136557.496756 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 104.0, 140.0, 62.6, 136480 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 104.0, 158.0, 62.6, 136480 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - // test - checkPoint = { 104.0, 176.0, 84.2, 136564.470884 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); +void testQAHVMatchesDataMap() +{ + HPWH hpwh; + string input = "QAHV_N136TAU_HPB_SP"; + performancePointSP checkPoint; // tairF, toutF, tinF, outputW + double outputBTUH; + getHPWHObject(hpwh, input); + + // test + checkPoint = {-13.0, 140.0, 41.0, 66529.49616}; + outputBTUH = getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF); + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); + // test + checkPoint = {-13.0, 176.0, 41.0, 65872.597448}; + ASSERTTRUE(getCapacitySP_F_BTUHR(hpwh, checkPoint) == + HPWH::HPWH_ABORT); // max setpoint without adjustment forces error + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {-13.0, 176.0, 84.2, 55913.249232}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {14.0, 176.0, 84.2, 92933.01932}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {42.8, 140.0, 41.0, 136425.98804}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {50.0, 140.0, 41.0, 136425.98804}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {50.0, 176.0, 84.2, 136564.470884}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {60.8, 158.0, 84.2, 136461.998288}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {71.6, 158.0, 48.2, 136498.001712}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + + // test constant with setpoint between 140 and 158 + checkPoint = {71.6, 149.0, 48.2, 136498.001712}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {82.4, 176.0, 41.0, 136557.496756}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {104.0, 140.0, 62.6, 136480}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {104.0, 158.0, 62.6, 136480}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + // test + checkPoint = {104.0, 176.0, 84.2, 136564.470884}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); } -// Also test QAHV constant extrpolation at high air temperatures AND linear extrapolation to hot water temperatures! -void testQAHVExtrapolates() { - HPWH hpwh; - string input = "QAHV_N136TAU_HPB_SP"; - performancePointSP checkPoint; // tairF, toutF, tinF, outputW - getHPWHObject(hpwh, input); - - // test linear along Tin - checkPoint = { -13.0, 140.0, 36.0, 66529.49616 }; - ASSERTTRUE(checkPoint.outputBTUH < getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has increased - // test linear along Tin - checkPoint = { -13.0, 140.0, 100.0, 66529.49616 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased - // test linear along Tin - checkPoint = { -13.0, 176.0, 36.0, 65872.597448 }; - ASSERTTRUE(checkPoint.outputBTUH < getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has increased - // test linear along Tin - checkPoint = { -13.0, 176.0, 100.0, 55913.249232 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased at high Tin - // test linear along Tin - checkPoint = { 10.4, 140.0, 111., 89000.085396 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased at high Tin - // test linear along Tin - checkPoint = { 64.4, 158.0, 100, 136461.998288 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased at high Tin - // test linear along Tin - checkPoint = { 86.0, 158.0, 100, 136461.998288 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased at high Tin - // test linear along Tin - checkPoint = { 104.0, 176.0, 100., 136564.470884 }; - ASSERTTRUE(checkPoint.outputBTUH > getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased at high Tin - - // test const along Tair - checkPoint = { 110.0, 140.0, 62.6, 136480 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - - // test const along Tair - checkPoint = { 114.0, 176.0, 84.2, 136564.470884 }; - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); - - checkPoint = { 114.0, 200.0, 84.2, 136564.470884 }; - double output = getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF); - ASSERTTRUE(output == HPWH::HPWH_ABORT); +// Also test QAHV constant extrpolation at high air temperatures AND linear extrapolation to hot +// water temperatures! +void testQAHVExtrapolates() +{ + HPWH hpwh; + string input = "QAHV_N136TAU_HPB_SP"; + performancePointSP checkPoint; // tairF, toutF, tinF, outputW + getHPWHObject(hpwh, input); + + // test linear along Tin + checkPoint = {-13.0, 140.0, 36.0, 66529.49616}; + ASSERTTRUE( + checkPoint.outputBTUH < + getCapacitySP_F_BTUHR( + hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has increased + // test linear along Tin + checkPoint = {-13.0, 140.0, 100.0, 66529.49616}; + ASSERTTRUE( + checkPoint.outputBTUH > + getCapacitySP_F_BTUHR( + hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has decreased + // test linear along Tin + checkPoint = {-13.0, 176.0, 36.0, 65872.597448}; + ASSERTTRUE( + checkPoint.outputBTUH < + getCapacitySP_F_BTUHR( + hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF)); // Check output has increased + // test linear along Tin + checkPoint = {-13.0, 176.0, 100.0, 55913.249232}; + ASSERTTRUE(checkPoint.outputBTUH > + getCapacitySP_F_BTUHR(hpwh, + checkPoint, + tInOffsetQAHV_dF, + tOutOffsetQAHV_dF)); // Check output has decreased at high Tin + // test linear along Tin + checkPoint = {10.4, 140.0, 111., 89000.085396}; + ASSERTTRUE(checkPoint.outputBTUH > + getCapacitySP_F_BTUHR(hpwh, + checkPoint, + tInOffsetQAHV_dF, + tOutOffsetQAHV_dF)); // Check output has decreased at high Tin + // test linear along Tin + checkPoint = {64.4, 158.0, 100, 136461.998288}; + ASSERTTRUE(checkPoint.outputBTUH > + getCapacitySP_F_BTUHR(hpwh, + checkPoint, + tInOffsetQAHV_dF, + tOutOffsetQAHV_dF)); // Check output has decreased at high Tin + // test linear along Tin + checkPoint = {86.0, 158.0, 100, 136461.998288}; + ASSERTTRUE(checkPoint.outputBTUH > + getCapacitySP_F_BTUHR(hpwh, + checkPoint, + tInOffsetQAHV_dF, + tOutOffsetQAHV_dF)); // Check output has decreased at high Tin + // test linear along Tin + checkPoint = {104.0, 176.0, 100., 136564.470884}; + ASSERTTRUE(checkPoint.outputBTUH > + getCapacitySP_F_BTUHR(hpwh, + checkPoint, + tInOffsetQAHV_dF, + tOutOffsetQAHV_dF)); // Check output has decreased at high Tin + + // test const along Tair + checkPoint = {110.0, 140.0, 62.6, 136480}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + + // test const along Tair + checkPoint = {114.0, 176.0, 84.2, 136564.470884}; + ASSERTTRUE( + relcmpd(checkPoint.outputBTUH, + getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF))); + + checkPoint = {114.0, 200.0, 84.2, 136564.470884}; + double output = getCapacitySP_F_BTUHR(hpwh, checkPoint, tInOffsetQAHV_dF, tOutOffsetQAHV_dF); + ASSERTTRUE(output == HPWH::HPWH_ABORT); } void testSanden() { - HPWH hpwh; - string input = "Sanden120"; - performancePointSP checkPoint; // tairF, toutF, tinF, outputW - double outputBTUH; - getHPWHObject(hpwh, input); - - // nominal - checkPoint = { 60, 149.0, 41.0, 15059.59167 }; - outputBTUH = hpwh.getCompressorCapacity(checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); - - // Cold outlet temperature - checkPoint = { 60, 125.0, 41.0, 15059.59167 }; - outputBTUH = hpwh.getCompressorCapacity(checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); - - // tests fails when output high - checkPoint = { 60, 200, 41.0, 15059.59167 }; - outputBTUH = hpwh.getCompressorCapacity(checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - ASSERTTRUE(outputBTUH == HPWH::HPWH_ABORT); + HPWH hpwh; + string input = "Sanden120"; + performancePointSP checkPoint; // tairF, toutF, tinF, outputW + double outputBTUH; + getHPWHObject(hpwh, input); + + // nominal + checkPoint = {60, 149.0, 41.0, 15059.59167}; + outputBTUH = hpwh.getCompressorCapacity( + checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); + + // Cold outlet temperature + checkPoint = {60, 125.0, 41.0, 15059.59167}; + outputBTUH = hpwh.getCompressorCapacity( + checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + ASSERTTRUE(relcmpd(checkPoint.outputBTUH, outputBTUH)); + + // tests fails when output high + checkPoint = {60, 200, 41.0, 15059.59167}; + outputBTUH = hpwh.getCompressorCapacity( + checkPoint.tairF, checkPoint.tinF, checkPoint.toutF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + ASSERTTRUE(outputBTUH == HPWH::HPWH_ABORT); } int main(int, char*) { - testSanden(); // check can still work with HPWH::getCapacity() as expected + testSanden(); // check can still work with HPWH::getCapacity() as expected - testQAHVMatchesDataMap(); // Test QAHV grid data input correctly - testQAHVExtrapolates(); // Test QAHV grid data extrapolate correctly + testQAHVMatchesDataMap(); // Test QAHV grid data input correctly + testQAHVExtrapolates(); // Test QAHV grid data extrapolate correctly - // Tests that the correct capacity is returned for specific equipement that matches the data set - testCXA15MatchesDataMap(); - testCXA30MatchesDataMap(); + // Tests that the correct capacity is returned for specific equipement that matches the data set + testCXA15MatchesDataMap(); + testCXA30MatchesDataMap(); - testCXV5MPMatchesDataMap(); - testCXA10MPMatchesDataMap(); - testCXA15MPMatchesDataMap(); - testCXA20MPMatchesDataMap(); - testCXA25MPMatchesDataMap(); - testCXA30MPMatchesDataMap(); + testCXV5MPMatchesDataMap(); + testCXA10MPMatchesDataMap(); + testCXA15MPMatchesDataMap(); + testCXA20MPMatchesDataMap(); + testCXA25MPMatchesDataMap(); + testCXA30MPMatchesDataMap(); - testRheemHPHD135(); - testRheemHPHD60(); + testRheemHPHD135(); + testRheemHPHD60(); - testNyleC60AMP(); - testNyleC90AMP(); - testNyleC125AMP(); - testNyleC185AMP(); - testNyleC250AMP(); + testNyleC60AMP(); + testNyleC90AMP(); + testNyleC125AMP(); + testNyleC185AMP(); + testNyleC250AMP(); - //Made it through the gauntlet - return 0; + // Made it through the gauntlet + return 0; } \ No newline at end of file diff --git a/test/testResistanceFcts.cc b/test/testResistanceFcts.cc index efe556c4..c5373ba0 100644 --- a/test/testResistanceFcts.cc +++ b/test/testResistanceFcts.cc @@ -9,225 +9,264 @@ #include "testUtilityFcts.cc" #include -#include +#include using std::cout; using std::string; - -void testSetResistanceCapacityErrorChecks() { - HPWH hpwhHP1, hpwhR; - string input = "ColmacCxA_30_SP"; - - // get preset model - getHPWHObject(hpwhHP1, input); - - ASSERTTRUE(hpwhHP1.setResistanceCapacity(100.) == HPWH::HPWH_ABORT); // Need's to be scalable - - input = "restankRealistic"; - // get preset model - getHPWHObject(hpwhR, input); - ASSERTTRUE(hpwhR.setResistanceCapacity(-100.) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwhR.setResistanceCapacity(100., 3) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwhR.setResistanceCapacity(100., 30000) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwhR.setResistanceCapacity(100., -3) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwhR.setResistanceCapacity(100., 0, HPWH::UNITS_F) == HPWH::HPWH_ABORT); +void testSetResistanceCapacityErrorChecks() +{ + HPWH hpwhHP1, hpwhR; + string input = "ColmacCxA_30_SP"; + + // get preset model + getHPWHObject(hpwhHP1, input); + + ASSERTTRUE(hpwhHP1.setResistanceCapacity(100.) == HPWH::HPWH_ABORT); // Need's to be scalable + + input = "restankRealistic"; + // get preset model + getHPWHObject(hpwhR, input); + ASSERTTRUE(hpwhR.setResistanceCapacity(-100.) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwhR.setResistanceCapacity(100., 3) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwhR.setResistanceCapacity(100., 30000) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwhR.setResistanceCapacity(100., -3) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwhR.setResistanceCapacity(100., 0, HPWH::UNITS_F) == HPWH::HPWH_ABORT); } -void testGetSetResistanceErrors() { - HPWH hpwh; - double lowerElementPower_W = 1000; - double lowerElementPower = lowerElementPower_W / 1000; - hpwh.HPWHinit_resTank(100., 0.95, 0., lowerElementPower_W); - - double returnVal; - returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); // lower - ASSERTTRUE(relcmpd(returnVal, lowerElementPower)); - returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); // both, - ASSERTTRUE(relcmpd(returnVal, lowerElementPower)); - returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); // higher doesn't exist - ASSERTTRUE(returnVal == HPWH::HPWH_ABORT); +void testGetSetResistanceErrors() +{ + HPWH hpwh; + double lowerElementPower_W = 1000; + double lowerElementPower = lowerElementPower_W / 1000; + hpwh.HPWHinit_resTank(100., 0.95, 0., lowerElementPower_W); + + double returnVal; + returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); // lower + ASSERTTRUE(relcmpd(returnVal, lowerElementPower)); + returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); // both, + ASSERTTRUE(relcmpd(returnVal, lowerElementPower)); + returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); // higher doesn't exist + ASSERTTRUE(returnVal == HPWH::HPWH_ABORT); } -void testCommercialTankInitErrors() { - HPWH hpwh; - // init model - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(-800., 10., 100., 100.) == HPWH::HPWH_ABORT); // negative volume - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., -100., 100.) == HPWH::HPWH_ABORT); // negative element - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., 100., -100.) == HPWH::HPWH_ABORT); // negative element - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., -10., 100., 100.) == HPWH::HPWH_ABORT); // negative r value - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 0., 100., 100.) == HPWH::HPWH_ABORT); // 0 r value - ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., 0., 0.) == HPWH::HPWH_ABORT); // Check needs one element +void testCommercialTankInitErrors() +{ + HPWH hpwh; + // init model + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(-800., 10., 100., 100.) == + HPWH::HPWH_ABORT); // negative volume + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., -100., 100.) == + HPWH::HPWH_ABORT); // negative element + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., 100., -100.) == + HPWH::HPWH_ABORT); // negative element + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., -10., 100., 100.) == + HPWH::HPWH_ABORT); // negative r value + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 0., 100., 100.) == HPWH::HPWH_ABORT); // 0 r value + ASSERTTRUE(hpwh.HPWHinit_resTankGeneric(800., 10., 0., 0.) == + HPWH::HPWH_ABORT); // Check needs one element } -void testGetNumResistanceElements() { - HPWH hpwh; - - hpwh.HPWHinit_resTankGeneric(800., 10., 0., 1000.); - ASSERTTRUE(hpwh.getNumResistanceElements() == 1); // Check 1 elements - hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 0.); - ASSERTTRUE(hpwh.getNumResistanceElements() == 1); // Check 1 elements - hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 1000.); - ASSERTTRUE(hpwh.getNumResistanceElements() == 2); // Check 2 elements +void testGetNumResistanceElements() +{ + HPWH hpwh; + + hpwh.HPWHinit_resTankGeneric(800., 10., 0., 1000.); + ASSERTTRUE(hpwh.getNumResistanceElements() == 1); // Check 1 elements + hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 0.); + ASSERTTRUE(hpwh.getNumResistanceElements() == 1); // Check 1 elements + hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 1000.); + ASSERTTRUE(hpwh.getNumResistanceElements() == 2); // Check 2 elements } -void testGetResistancePositionInRETank() { - HPWH hpwh; - - hpwh.HPWHinit_resTankGeneric(800., 10., 0., 1000.); - ASSERTTRUE(hpwh.getResistancePosition(0) == 0); // Check lower element is there - ASSERTTRUE(hpwh.getResistancePosition(1) == HPWH::HPWH_ABORT); // Check no element - ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check no element - - hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 0.); - ASSERTTRUE(hpwh.getResistancePosition(0) == 8); // Check upper element there - ASSERTTRUE(hpwh.getResistancePosition(1) == HPWH::HPWH_ABORT); // Check no elements - ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check no elements - - hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 1000.); - ASSERTTRUE(hpwh.getResistancePosition(0) == 8); // Check upper element there - ASSERTTRUE(hpwh.getResistancePosition(1) == 0); // Check lower element is there - ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check 0 elements} +void testGetResistancePositionInRETank() +{ + HPWH hpwh; + + hpwh.HPWHinit_resTankGeneric(800., 10., 0., 1000.); + ASSERTTRUE(hpwh.getResistancePosition(0) == 0); // Check lower element is there + ASSERTTRUE(hpwh.getResistancePosition(1) == HPWH::HPWH_ABORT); // Check no element + ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check no element + + hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 0.); + ASSERTTRUE(hpwh.getResistancePosition(0) == 8); // Check upper element there + ASSERTTRUE(hpwh.getResistancePosition(1) == HPWH::HPWH_ABORT); // Check no elements + ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check no elements + + hpwh.HPWHinit_resTankGeneric(800., 10., 1000., 1000.); + ASSERTTRUE(hpwh.getResistancePosition(0) == 8); // Check upper element there + ASSERTTRUE(hpwh.getResistancePosition(1) == 0); // Check lower element is there + ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check 0 elements} } -void testGetResistancePositionInCompressorTank() { - HPWH hpwh; +void testGetResistancePositionInCompressorTank() +{ + HPWH hpwh; - string input = "TamScalable_SP"; - // get preset model - getHPWHObject(hpwh, input); + string input = "TamScalable_SP"; + // get preset model + getHPWHObject(hpwh, input); - ASSERTTRUE(hpwh.getResistancePosition(0) == 9); // Check top elements - ASSERTTRUE(hpwh.getResistancePosition(1) == 0); // Check bottom elements - ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check compressor isn't RE - ASSERTTRUE(hpwh.getResistancePosition(-1) == HPWH::HPWH_ABORT); // Check out of bounds - ASSERTTRUE(hpwh.getResistancePosition(1000) == HPWH::HPWH_ABORT); // Check out of bounds + ASSERTTRUE(hpwh.getResistancePosition(0) == 9); // Check top elements + ASSERTTRUE(hpwh.getResistancePosition(1) == 0); // Check bottom elements + ASSERTTRUE(hpwh.getResistancePosition(2) == HPWH::HPWH_ABORT); // Check compressor isn't RE + ASSERTTRUE(hpwh.getResistancePosition(-1) == HPWH::HPWH_ABORT); // Check out of bounds + ASSERTTRUE(hpwh.getResistancePosition(1000) == HPWH::HPWH_ABORT); // Check out of bounds } -void testCommercialTankErrorsWithBottomElement() { - HPWH hpwh; - double elementPower_kW = 10.; //KW - // init model - hpwh.HPWHinit_resTankGeneric(800., 10., 0., elementPower_kW * 1000.); - - // Check only lowest setting works - double factor = 3.; - // set both, but really only one - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, -1, HPWH::UNITS_KW) == 0); // Check sets - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets just bottom with both - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets bottom with bottom - ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); // only have one element - - // set lowest - factor = 4.; - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 0, HPWH::UNITS_KW) == 0); // Set just bottom - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets just bottom with both - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets bottom with bottom - ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); // only have one element - - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 1, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); // set top returns error +void testCommercialTankErrorsWithBottomElement() +{ + HPWH hpwh; + double elementPower_kW = 10.; // KW + // init model + hpwh.HPWHinit_resTankGeneric(800., 10., 0., elementPower_kW * 1000.); + + // Check only lowest setting works + double factor = 3.; + // set both, but really only one + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, -1, HPWH::UNITS_KW) == + 0); // Check sets + ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets just bottom with both + ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets bottom with bottom + ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); // only have one element + + // set lowest + factor = 4.; + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 0, HPWH::UNITS_KW) == + 0); // Set just bottom + ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets just bottom with both + ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets bottom with bottom + ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); // only have one element + + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 1, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); // set top returns error } -void testCommercialTankErrorsWithTopElement() { - HPWH hpwh; - double elementPower_kW = 10.; //KW - // init model - hpwh.HPWHinit_resTankGeneric(800., 10., elementPower_kW * 1000., 0.); - - // Check only bottom setting works - double factor = 3.; - // set both, but only bottom really. - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, -1, HPWH::UNITS_KW) == 0); // Check sets - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets just bottom which is now top with both - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), factor * elementPower_kW)); // Check the lower and only element - ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); // error on non existant element - - // set top - factor = 4.; - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 0, HPWH::UNITS_KW) == 0); // only one element to set - ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), factor * elementPower_kW)); // Check gets just bottom which is now top with both - ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); // error on non existant bottom - - // set bottom returns error - ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 2, HPWH::UNITS_KW) == HPWH::HPWH_ABORT); +void testCommercialTankErrorsWithTopElement() +{ + HPWH hpwh; + double elementPower_kW = 10.; // KW + // init model + hpwh.HPWHinit_resTankGeneric(800., 10., elementPower_kW * 1000., 0.); + + // Check only bottom setting works + double factor = 3.; + // set both, but only bottom really. + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, -1, HPWH::UNITS_KW) == + 0); // Check sets + ASSERTTRUE( + relcmpd(hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets just bottom which is now top with both + ASSERTTRUE(relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check the lower and only element + ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); // error on non existant element + + // set top + factor = 4.; + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 0, HPWH::UNITS_KW) == + 0); // only one element to set + ASSERTTRUE( + relcmpd(hpwh.getResistanceCapacity(0, HPWH::UNITS_KW), + factor * elementPower_kW)); // Check gets just bottom which is now top with both + ASSERTTRUE(hpwh.getResistanceCapacity(1, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); // error on non existant bottom + + // set bottom returns error + ASSERTTRUE(hpwh.setResistanceCapacity(factor * elementPower_kW, 2, HPWH::UNITS_KW) == + HPWH::HPWH_ABORT); } struct InsulationPoint { - double volume_L; - double rValue_IP; - double expectedUA_SI; + double volume_L; + double rValue_IP; + double expectedUA_SI; }; #define R_TO_RSI(rvalue) rvalue * 0.176110 -#define INITGEN(point) hpwh.HPWHinit_resTankGeneric(point.volume_L, R_TO_RSI(point.rValue_IP), elementPower_kW * 1000., elementPower_kW * 1000.) -void testCommercialTankInit() { - HPWH hpwh; - double elementPower_kW = 10.; //KW - double UA; - const InsulationPoint testPoint800 = { 800., 10., 10.500366 }; - const InsulationPoint testPoint2 = { 2., 6., 0.322364 }; - const InsulationPoint testPoint50 = { 50., 12., 1.37808 }; - const InsulationPoint testPoint200 = { 200., 16., 2.604420 }; - const InsulationPoint testPoint200B = { 200., 6., 6.94512163 }; - const InsulationPoint testPoint2000 = { 2000., 16., 12.0886496 }; - const InsulationPoint testPoint20000 = { 20000., 6., 149.628109 }; - - - // Check UA is as expected at 800 gal - INITGEN(testPoint800); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint800.expectedUA_SI, 0.0001)); - // Check UA independent of elements - hpwh.HPWHinit_resTankGeneric(testPoint800.volume_L, R_TO_RSI(testPoint800.rValue_IP), elementPower_kW, elementPower_kW); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint800.expectedUA_SI, 0.0001)); - - // Check UA is as expected at 2 gal - INITGEN(testPoint2); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint2.expectedUA_SI, 0.0001)); - - // Check UA is as expected at 50 gal - INITGEN(testPoint50); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint50.expectedUA_SI, 0.0001)); - - // Check UA is as expected at 200 gal - INITGEN(testPoint200); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint200.expectedUA_SI, 0.0001)); - - INITGEN(testPoint200B); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint200B.expectedUA_SI, 0.0001)); - - // Check UA is as expected at 2000 gal - INITGEN(testPoint2000); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint2000.expectedUA_SI, 0.0001)); - - // Check UA is as expected at 20000 gal - INITGEN(testPoint20000); - hpwh.getUA(UA); - ASSERTTRUE(relcmpd(UA, testPoint20000.expectedUA_SI, 0.0001)); +#define INITGEN(point) \ + hpwh.HPWHinit_resTankGeneric(point.volume_L, \ + R_TO_RSI(point.rValue_IP), \ + elementPower_kW * 1000., \ + elementPower_kW * 1000.) +void testCommercialTankInit() +{ + HPWH hpwh; + double elementPower_kW = 10.; // KW + double UA; + const InsulationPoint testPoint800 = {800., 10., 10.500366}; + const InsulationPoint testPoint2 = {2., 6., 0.322364}; + const InsulationPoint testPoint50 = {50., 12., 1.37808}; + const InsulationPoint testPoint200 = {200., 16., 2.604420}; + const InsulationPoint testPoint200B = {200., 6., 6.94512163}; + const InsulationPoint testPoint2000 = {2000., 16., 12.0886496}; + const InsulationPoint testPoint20000 = {20000., 6., 149.628109}; + + // Check UA is as expected at 800 gal + INITGEN(testPoint800); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint800.expectedUA_SI, 0.0001)); + // Check UA independent of elements + hpwh.HPWHinit_resTankGeneric( + testPoint800.volume_L, R_TO_RSI(testPoint800.rValue_IP), elementPower_kW, elementPower_kW); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint800.expectedUA_SI, 0.0001)); + + // Check UA is as expected at 2 gal + INITGEN(testPoint2); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint2.expectedUA_SI, 0.0001)); + + // Check UA is as expected at 50 gal + INITGEN(testPoint50); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint50.expectedUA_SI, 0.0001)); + + // Check UA is as expected at 200 gal + INITGEN(testPoint200); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint200.expectedUA_SI, 0.0001)); + + INITGEN(testPoint200B); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint200B.expectedUA_SI, 0.0001)); + + // Check UA is as expected at 2000 gal + INITGEN(testPoint2000); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint2000.expectedUA_SI, 0.0001)); + + // Check UA is as expected at 20000 gal + INITGEN(testPoint20000); + hpwh.getUA(UA); + ASSERTTRUE(relcmpd(UA, testPoint20000.expectedUA_SI, 0.0001)); } #undef INITGEN #undef R_TO_RSI int main(int, char*) { - testSetResistanceCapacityErrorChecks(); // Check the resistance reset throws errors when expected. + testSetResistanceCapacityErrorChecks(); // Check the resistance reset throws errors when + // expected. - testGetSetResistanceErrors(); // Check can make ER residential tank with one lower element, and can't set/get upper + testGetSetResistanceErrors(); // Check can make ER residential tank with one lower element, and + // can't set/get upper - testCommercialTankInitErrors(); // test it inits as expected - testGetNumResistanceElements(); // unit test on getNumResistanceElements() - testGetResistancePositionInRETank(); // unit test on getResistancePosition() for an RE tank - testGetResistancePositionInCompressorTank(); // unit test on getResistancePosition() for a compressor + testCommercialTankInitErrors(); // test it inits as expected + testGetNumResistanceElements(); // unit test on getNumResistanceElements() + testGetResistancePositionInRETank(); // unit test on getResistancePosition() for an RE tank + testGetResistancePositionInCompressorTank(); // unit test on getResistancePosition() for a + // compressor - testCommercialTankErrorsWithBottomElement(); // - testCommercialTankErrorsWithTopElement(); - testCommercialTankInit(); // + testCommercialTankErrorsWithBottomElement(); // + testCommercialTankErrorsWithTopElement(); + testCommercialTankInit(); // - //Made it through the gauntlet - return 0; + // Made it through the gauntlet + return 0; } diff --git a/test/testScaleHPWH.cc b/test/testScaleHPWH.cc index e1f83390..4e956316 100644 --- a/test/testScaleHPWH.cc +++ b/test/testScaleHPWH.cc @@ -9,522 +9,567 @@ #include "testUtilityFcts.cc" #include -#include +#include using std::cout; using std::string; struct performance { - double input, output, cop; + double input, output, cop; }; -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 - hpwh.setSetpoint((waterTempC + setpointC) / 2.); - } - else { - hpwh.setSetpoint(waterTempC); - } - hpwh.resetTankToSetpoint(); //Force tank cold - hpwh.setSetpoint(setpointC); - - // Run the step - hpwh.runOneStep(waterTempC, // Inlet water temperature (C ) - 0., // Flow in gallons - airTempC, // Ambient Temp (C) - airTempC, // External Temp (C) - //HPWH::DR_TOO // DR Status (now an enum. Fixed for now as allow) - (HPWH::DR_TOO | HPWH::DR_LOR) // DR Status (now an enum. Fixed for now as allow) - ); - - // Check the heat in and out of the compressor - point.input = hpwh.getNthHeatSourceEnergyInput(hpwh.getCompressorIndex()); - point.output = hpwh.getNthHeatSourceEnergyOutput(hpwh.getCompressorIndex()); - point.cop = point.output / point.input ; +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 + hpwh.setSetpoint((waterTempC + setpointC) / 2.); + } + else { + hpwh.setSetpoint(waterTempC); + } + hpwh.resetTankToSetpoint(); // Force tank cold + hpwh.setSetpoint(setpointC); + + // Run the step + hpwh.runOneStep(waterTempC, // Inlet water temperature (C ) + 0., // Flow in gallons + airTempC, // Ambient Temp (C) + airTempC, // External Temp (C) + // HPWH::DR_TOO // DR Status (now an enum. Fixed for now as allow) + (HPWH::DR_TOO | HPWH::DR_LOR) // DR Status (now an enum. Fixed for now as allow) + ); + + // Check the heat in and out of the compressor + point.input = hpwh.getNthHeatSourceEnergyInput(hpwh.getCompressorIndex()); + point.output = hpwh.getNthHeatSourceEnergyOutput(hpwh.getCompressorIndex()); + point.cop = point.output / point.input; } -void scaleCapacityCOP(HPWH &hpwh, double scaleInput, double scaleCOP, performance &point0, performance &point1, - double waterTempC = F_TO_C(63), double airTempC = F_TO_C(77), double setpointC = F_TO_C(135)) { - // Get peformance unscalled - getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); +void scaleCapacityCOP(HPWH& hpwh, + double scaleInput, + double scaleCOP, + performance& point0, + performance& point1, + double waterTempC = F_TO_C(63), + double airTempC = F_TO_C(77), + double setpointC = F_TO_C(135)) +{ + // Get peformance unscalled + getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); - // Scale the compressor - int val = hpwh.setScaleHPWHCapacityCOP(scaleInput, scaleCOP); - ASSERTTRUE(val == 0); + // Scale the compressor + int val = hpwh.setScaleHPWHCapacityCOP(scaleInput, scaleCOP); + ASSERTTRUE(val == 0); - // Get the scaled performance - getCompressorPerformance(hpwh, point1, waterTempC, airTempC, setpointC); + // Get the scaled performance + getCompressorPerformance(hpwh, point1, waterTempC, airTempC, setpointC); } -void testNoScaleOutOfBounds() { // Test that we can NOT scale the scalable model with scale <= 0 - HPWH hpwh; +void testNoScaleOutOfBounds() +{ // Test that we can NOT scale the scalable model with scale <= 0 + HPWH hpwh; - string input = "TamScalable_SP"; + string input = "TamScalable_SP"; - double num; + double num; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - num = 0; - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(num, 1.) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., num) == HPWH::HPWH_ABORT); + num = 0; + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(num, 1.) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., num) == HPWH::HPWH_ABORT); - num = -1; - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(num, 1.) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., num) == HPWH::HPWH_ABORT); + num = -1; + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(num, 1.) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., num) == HPWH::HPWH_ABORT); } -void testNoneScalable() { // Test a model that is not scalable - HPWH hpwh; +void testNoneScalable() +{ // Test a model that is not scalable + HPWH hpwh; - string input = "AOSmithCAHP120"; + string input = "AOSmithCAHP120"; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., 1.) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., 1.) == HPWH::HPWH_ABORT); } -void testScalableHPWHScales() { // Test the scalable hpwh can scale - HPWH hpwh; - - string input = "TamScalable_SP"; - - performance point0, point1; - double num, anotherNum; - - // get preset model - getHPWHObject(hpwh, input); - - num = 0.001; // Very low - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 0.2; // normal but bad low - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 3.; // normal but pretty high - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 1000; // really high - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 10; - anotherNum = 0.1; // weird high and low - scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); - - scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 1.5; - anotherNum = 0.9; // real high and low - scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); - - scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); +void testScalableHPWHScales() +{ // Test the scalable hpwh can scale + HPWH hpwh; + + string input = "TamScalable_SP"; + + performance point0, point1; + double num, anotherNum; + + // get preset model + getHPWHObject(hpwh, input); + + num = 0.001; // Very low + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 0.2; // normal but bad low + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 3.; // normal but pretty high + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 1000; // really high + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 10; + anotherNum = 0.1; // weird high and low + scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); + + scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 1.5; + anotherNum = 0.9; // real high and low + scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); + + scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); } -void testScalableMPHPWHScales() { // Test the scalable MP hpwh can scale - HPWH hpwh; - - string input = "Scalable_MP"; - - performance point0, point1; - double num, anotherNum; - - // get preset model - getHPWHObject(hpwh, input); - - num = 0.001; // Very low - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 0.2; // normal but bad low - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 3.; // normal but pretty high - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 1000; // really high - scaleCapacityCOP(hpwh, num, 1., point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop)); - - scaleCapacityCOP(hpwh, 1., num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input)); - ASSERTTRUE(cmpd(point0.output, point1.output / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - scaleCapacityCOP(hpwh, num, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 10; - anotherNum = 0.1; // weird high and low - scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); - - scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); - - num = 1.5; - anotherNum = 0.9; // real high and low - scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / num)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); - - scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); - ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); - ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); - ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); +void testScalableMPHPWHScales() +{ // Test the scalable MP hpwh can scale + HPWH hpwh; + + string input = "Scalable_MP"; + + performance point0, point1; + double num, anotherNum; + + // get preset model + getHPWHObject(hpwh, input); + + num = 0.001; // Very low + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 0.2; // normal but bad low + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 3.; // normal but pretty high + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 1000; // really high + scaleCapacityCOP(hpwh, num, 1., point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop)); + + scaleCapacityCOP(hpwh, 1., num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input)); + ASSERTTRUE(cmpd(point0.output, point1.output / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + scaleCapacityCOP(hpwh, num, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / num)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 10; + anotherNum = 0.1; // weird high and low + scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); + + scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); + + num = 1.5; + anotherNum = 0.9; // real high and low + scaleCapacityCOP(hpwh, num, anotherNum, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / num)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / anotherNum)); + + scaleCapacityCOP(hpwh, anotherNum, num, point0, point1); + ASSERTTRUE(cmpd(point0.input, point1.input / anotherNum)); + ASSERTTRUE(cmpd(point0.output, point1.output / num / anotherNum)); + ASSERTTRUE(cmpd(point0.cop, point1.cop / num)); } -void testSPGetCompressorCapacity() { - HPWH hpwh; +void testSPGetCompressorCapacity() +{ + HPWH hpwh; - string input = "ColmacCxA_20_SP"; + string input = "ColmacCxA_20_SP"; - performance point0; + performance point0; - double capacity_kWH, capacity_BTU; - double waterTempC = F_TO_C(63); - double airTempC = F_TO_C(77); - double setpointC = F_TO_C(135); + double capacity_kWH, capacity_BTU; + double waterTempC = F_TO_C(63); + double airTempC = F_TO_C(77); + double setpointC = F_TO_C(135); - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); // gives kWH - capacity_kWH = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC) / 60; // div 60 to kWh because I know above only runs 1 minute + getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); // gives kWH + capacity_kWH = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC) / + 60; // div 60 to kWh because I know above only runs 1 minute - ASSERTTRUE(cmpd(point0.output, capacity_kWH)); + ASSERTTRUE(cmpd(point0.output, capacity_kWH)); - //Test with IP units - capacity_BTU = hpwh.getCompressorCapacity(C_TO_F(airTempC), C_TO_F(waterTempC), C_TO_F(setpointC), HPWH::UNITS_BTUperHr, HPWH::UNITS_F) / 60; // div 60 to BTU because I know above only runs 1 minute - ASSERTTRUE(relcmpd(KWH_TO_BTU(point0.output), capacity_BTU)); // relative cmp since in btu's these will be large numbers + // Test with IP units + capacity_BTU = hpwh.getCompressorCapacity(C_TO_F(airTempC), + C_TO_F(waterTempC), + C_TO_F(setpointC), + HPWH::UNITS_BTUperHr, + HPWH::UNITS_F) / + 60; // div 60 to BTU because I know above only runs 1 minute + ASSERTTRUE(relcmpd(KWH_TO_BTU(point0.output), + capacity_BTU)); // relative cmp since in btu's these will be large numbers } -void testMPGetCompressorCapacity() { - HPWH hpwh; - - string input = "ColmacCxA_20_MP"; - - performance point0; - - double capacity_kWH, capacity_BTU; - double waterTempC = F_TO_C(50); // 50 and 126 to make average 88 - double airTempC = F_TO_C(61.7); - double setpointC = F_TO_C(126); - - // get preset model - getHPWHObject(hpwh, input); - capacity_kWH = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC) / 60.; // div 60 to kWh because I know above only runs 1 minute - getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); // gives kWH - ASSERTTRUE(cmpd(point0.output, capacity_kWH)); - - //Test with IP units - capacity_BTU = hpwh.getCompressorCapacity(C_TO_F(airTempC), C_TO_F(waterTempC), C_TO_F(setpointC), HPWH::UNITS_BTUperHr, HPWH::UNITS_F) / 60; // div 60 to BTU because I know above only runs 1 minute - ASSERTTRUE(relcmpd(KWH_TO_BTU(point0.output), capacity_BTU, 0.0001)); // relative cmp since in btu's these will be large numbers +void testMPGetCompressorCapacity() +{ + HPWH hpwh; + + string input = "ColmacCxA_20_MP"; + + performance point0; + + double capacity_kWH, capacity_BTU; + double waterTempC = F_TO_C(50); // 50 and 126 to make average 88 + double airTempC = F_TO_C(61.7); + double setpointC = F_TO_C(126); + + // get preset model + getHPWHObject(hpwh, input); + capacity_kWH = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC) / + 60.; // div 60 to kWh because I know above only runs 1 minute + getCompressorPerformance(hpwh, point0, waterTempC, airTempC, setpointC); // gives kWH + ASSERTTRUE(cmpd(point0.output, capacity_kWH)); + + // Test with IP units + capacity_BTU = hpwh.getCompressorCapacity(C_TO_F(airTempC), + C_TO_F(waterTempC), + C_TO_F(setpointC), + HPWH::UNITS_BTUperHr, + HPWH::UNITS_F) / + 60; // div 60 to BTU because I know above only runs 1 minute + ASSERTTRUE(relcmpd(KWH_TO_BTU(point0.output), + capacity_BTU, + 0.0001)); // relative cmp since in btu's these will be large numbers } - -void testSetMPCompressorOutputCapacity() { - HPWH hpwh; - - string input = "Scalable_MP"; - - double newCapacity_kW, num; - double waterTempC = F_TO_C(44); - double airTempC = F_TO_C(98); - double setpointC = F_TO_C(150); - - // get preset model - getHPWHObject(hpwh, input); - - //Scale output to 1 kW - num = 1.; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - //Scale output to .01 kW - num = .01; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - //Scale output to 1000 kW - num = 1000.; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - // Check again with changed setpoint, for MP it should affect output capacity since it looks at the mean temperature for the cycle. - setpointC = F_TO_C(100); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTFALSE(cmpd(num, newCapacity_kW)); +void testSetMPCompressorOutputCapacity() +{ + HPWH hpwh; + + string input = "Scalable_MP"; + + double newCapacity_kW, num; + double waterTempC = F_TO_C(44); + double airTempC = F_TO_C(98); + double setpointC = F_TO_C(150); + + // get preset model + getHPWHObject(hpwh, input); + + // Scale output to 1 kW + num = 1.; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Scale output to .01 kW + num = .01; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Scale output to 1000 kW + num = 1000.; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Check again with changed setpoint, for MP it should affect output capacity since it looks at + // the mean temperature for the cycle. + setpointC = F_TO_C(100); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTFALSE(cmpd(num, newCapacity_kW)); } -void testSetCompressorOutputCapacity() { - HPWH hpwh; - - string input = "TamScalable_SP"; - - double newCapacity_kW, num; - double waterTempC = F_TO_C(44); - double airTempC = F_TO_C(98); - double setpointC = F_TO_C(145); - - // get preset model - getHPWHObject(hpwh, input); - - //Scale output to 1 kW - num = 1.; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - //Scale output to .01 kW - num = .01; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - //Scale output to 1000 kW - num = 1000.; - hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); - newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); - ASSERTTRUE(cmpd(num, newCapacity_kW)); - - //Scale output to 1000 kW but let's use do the calc in other units - num = KW_TO_BTUperHR(num); - hpwh.setCompressorOutputCapacity(num, C_TO_F(airTempC), C_TO_F(waterTempC), C_TO_F(setpointC), HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - double newCapacity_BTUperHr = hpwh.getCompressorCapacity(C_TO_F(airTempC), C_TO_F(waterTempC), C_TO_F(setpointC), HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - ASSERTTRUE(relcmpd(num, newCapacity_BTUperHr)); +void testSetCompressorOutputCapacity() +{ + HPWH hpwh; + + string input = "TamScalable_SP"; + + double newCapacity_kW, num; + double waterTempC = F_TO_C(44); + double airTempC = F_TO_C(98); + double setpointC = F_TO_C(145); + + // get preset model + getHPWHObject(hpwh, input); + + // Scale output to 1 kW + num = 1.; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Scale output to .01 kW + num = .01; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Scale output to 1000 kW + num = 1000.; + hpwh.setCompressorOutputCapacity(num, airTempC, waterTempC, setpointC); + newCapacity_kW = hpwh.getCompressorCapacity(airTempC, waterTempC, setpointC); + ASSERTTRUE(cmpd(num, newCapacity_kW)); + + // Scale output to 1000 kW but let's use do the calc in other units + num = KW_TO_BTUperHR(num); + hpwh.setCompressorOutputCapacity(num, + C_TO_F(airTempC), + C_TO_F(waterTempC), + C_TO_F(setpointC), + HPWH::UNITS_BTUperHr, + HPWH::UNITS_F); + double newCapacity_BTUperHr = hpwh.getCompressorCapacity(C_TO_F(airTempC), + C_TO_F(waterTempC), + C_TO_F(setpointC), + HPWH::UNITS_BTUperHr, + HPWH::UNITS_F); + ASSERTTRUE(relcmpd(num, newCapacity_BTUperHr)); } -void testChipsCaseWithIPUnits() { - HPWH hpwh; +void testChipsCaseWithIPUnits() +{ + HPWH hpwh; - string input = "TamScalable_SP"; + string input = "TamScalable_SP"; - double waterTempF = 50; - double airTempF = 50; - double setpointF = 120; - double wh_heatingCap = 20000.; + double waterTempF = 50; + double airTempF = 50; + double setpointF = 120; + double wh_heatingCap = 20000.; - // get preset model - getHPWHObject(hpwh, input); + // get preset model + getHPWHObject(hpwh, input); - //Scale output to 20000 btu/hr but let's use do the calc in other units - hpwh.setCompressorOutputCapacity(wh_heatingCap, airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - double newCapacity_BTUperHr = hpwh.getCompressorCapacity(airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); - ASSERTTRUE(relcmpd(wh_heatingCap, newCapacity_BTUperHr)); + // Scale output to 20000 btu/hr but let's use do the calc in other units + hpwh.setCompressorOutputCapacity( + wh_heatingCap, airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + double newCapacity_BTUperHr = hpwh.getCompressorCapacity( + airTempF, waterTempF, setpointF, HPWH::UNITS_BTUperHr, HPWH::UNITS_F); + ASSERTTRUE(relcmpd(wh_heatingCap, newCapacity_BTUperHr)); } -void testScaleRestank() { - HPWH hpwh; +void testScaleRestank() +{ + HPWH hpwh; - string input = "restankRealistic"; - // get preset model - getHPWHObject(hpwh, input); + string input = "restankRealistic"; + // get preset model + getHPWHObject(hpwh, input); - //Scale COP for restank fails. - int val = hpwh.setScaleHPWHCapacityCOP(2., 2.); - ASSERTTRUE(val == HPWH::HPWH_ABORT); + // Scale COP for restank fails. + int val = hpwh.setScaleHPWHCapacityCOP(2., 2.); + ASSERTTRUE(val == HPWH::HPWH_ABORT); } -void testResistanceScales() { - HPWH hpwh; - - string input = "TamScalable_SP"; - double elementPower = 30.0; //KW - - //hpwh.HPWHinit_resTank(); - getHPWHObject(hpwh, input); - - double returnVal; - returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, elementPower)); - returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, elementPower)); - returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, 2.*elementPower)); - - // check units convert - returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_BTUperHr); - ASSERTTRUE(relcmpd(returnVal, 2.*elementPower * 3412.14)); - - // Check setting bottom works - double factor = 2.0; - hpwh.setResistanceCapacity(factor * elementPower, 0); - returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); - returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, elementPower)); - returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, factor * elementPower + elementPower)); - - // Check setting both works - factor = 3.; - hpwh.setResistanceCapacity(factor * elementPower, -1); - returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); - returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); - returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); - ASSERTTRUE(relcmpd(returnVal, 2.*factor * elementPower)); +void testResistanceScales() +{ + HPWH hpwh; + + string input = "TamScalable_SP"; + double elementPower = 30.0; // KW + + // hpwh.HPWHinit_resTank(); + getHPWHObject(hpwh, input); + + double returnVal; + returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, elementPower)); + returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, elementPower)); + returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, 2. * elementPower)); + + // check units convert + returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_BTUperHr); + ASSERTTRUE(relcmpd(returnVal, 2. * elementPower * 3412.14)); + + // Check setting bottom works + double factor = 2.0; + hpwh.setResistanceCapacity(factor * elementPower, 0); + returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); + returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, elementPower)); + returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, factor * elementPower + elementPower)); + + // Check setting both works + factor = 3.; + hpwh.setResistanceCapacity(factor * elementPower, -1); + returnVal = hpwh.getResistanceCapacity(0, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); + returnVal = hpwh.getResistanceCapacity(1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, factor * elementPower)); + returnVal = hpwh.getResistanceCapacity(-1, HPWH::UNITS_KW); + ASSERTTRUE(relcmpd(returnVal, 2. * factor * elementPower)); } -void testStorageTankErrors() { - HPWH hpwh; - string input = "StorageTank"; - // get preset model - getHPWHObject(hpwh, input); - - ASSERTTRUE(hpwh.setResistanceCapacity(1000.) == HPWH::HPWH_ABORT); - ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., 1.) == HPWH::HPWH_ABORT); +void testStorageTankErrors() +{ + HPWH hpwh; + string input = "StorageTank"; + // get preset model + getHPWHObject(hpwh, input); + ASSERTTRUE(hpwh.setResistanceCapacity(1000.) == HPWH::HPWH_ABORT); + ASSERTTRUE(hpwh.setScaleHPWHCapacityCOP(1., 1.) == HPWH::HPWH_ABORT); } int main(int, char*) { - testSetMPCompressorOutputCapacity(); + testSetMPCompressorOutputCapacity(); + testScalableHPWHScales(); // Test the scalable model scales properly + testNoScaleOutOfBounds(); // Test that models can't scale with invalid inputs - testScalableHPWHScales(); // Test the scalable model scales properly + testNoneScalable(); // Test that models can't scale that are non scalable presets - testNoScaleOutOfBounds(); // Test that models can't scale with invalid inputs - - testNoneScalable(); // Test that models can't scale that are non scalable presets - - testScaleRestank(); // Test the resistance tank can't scale the compressor + testScaleRestank(); // Test the resistance tank can't scale the compressor - testResistanceScales(); // Test the resistance tank scales the resistance elements + testResistanceScales(); // Test the resistance tank scales the resistance elements - testSPGetCompressorCapacity(); //Test we can get the capacity + testSPGetCompressorCapacity(); // Test we can get the capacity - testSetCompressorOutputCapacity(); //Test we can set the capacity with a specific number + testSetCompressorOutputCapacity(); // Test we can set the capacity with a specific number - testChipsCaseWithIPUnits(); //Debuging Chip's case + testChipsCaseWithIPUnits(); // Debuging Chip's case - testStorageTankErrors(); // Make sure we can't scale the storage tank. + testStorageTankErrors(); // Make sure we can't scale the storage tank. - testScalableMPHPWHScales(); // Test for proper scaling in the MP scalable model + testScalableMPHPWHScales(); // Test for proper scaling in the MP scalable model - testMPGetCompressorCapacity(); // Test MP capacity in and out correct. + testMPGetCompressorCapacity(); // Test MP capacity in and out correct. - //testSetMPCompressorOutputCapacity(); // Tets MP capacity can be set correctly. + // testSetMPCompressorOutputCapacity(); // Tets MP capacity can be set correctly. - //Made it through the gauntlet - return 0; + // Made it through the gauntlet + return 0; } diff --git a/test/testSizingFractions.cc b/test/testSizingFractions.cc index b3af85eb..9ac3b341 100644 --- a/test/testSizingFractions.cc +++ b/test/testSizingFractions.cc @@ -9,7 +9,7 @@ #include "testUtilityFcts.cc" #include -#include +#include #define SIZE (double)HPWH::CONDENSITY_SIZE @@ -28,144 +28,149 @@ void testGetCompressorMinRuntime(); int main(int, char*) { - testScalableSizingFract(); - testSandenSizingFract(); - testColmacSizingFract(); - testHPTU50SizingFract(); - test220eSizingFract(); - testGESizingFract(); - testResTankSizingFract(); - testStoTankSizingFract(); - - //Made it through the gauntlet - return 0; + testScalableSizingFract(); + testSandenSizingFract(); + testColmacSizingFract(); + testHPTU50SizingFract(); + test220eSizingFract(); + testGESizingFract(); + testResTankSizingFract(); + testStoTankSizingFract(); + + // Made it through the gauntlet + return 0; } +void testScalableSizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = 4. / SIZE; -void testScalableSizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = 4. / SIZE; - - string input = "TamScalable_SP"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "TamScalable_SP"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions( AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); } -void testSandenSizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = 8. / SIZE; +void testSandenSizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = 8. / SIZE; - string input = "Sanden80"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "Sanden80"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); } -void testColmacSizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = 4. / SIZE; +void testColmacSizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = 4. / SIZE; - string input = "ColmacCxV_5_SP"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "ColmacCxV_5_SP"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); } -void testHPTU50SizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = (1. + 2. + 3. + 4.) / 4. / SIZE; +void testHPTU50SizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = (1. + 2. + 3. + 4.) / 4. / SIZE; - string input = "AOSmithHPTU50"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "AOSmithHPTU50"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1.)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1.)); } -void testGESizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = (1. + 2. + 3. + 4.) / 4. / SIZE; +void testGESizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = (1. + 2. + 3. + 4.) / 4. / SIZE; - string input = "GE"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "GE"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1.)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1.)); } -void test220eSizingFract() { - HPWH hpwh; - double AF, pU; - double AF_answer = (5. + 6.) / 2. / SIZE; +void test220eSizingFract() +{ + HPWH hpwh; + double AF, pU; + double AF_answer = (5. + 6.) / 2. / SIZE; - string input = "Stiebel220e"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "Stiebel220e"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == 0); - ASSERTTRUE(cmpd(AF, AF_answer)); - ASSERTTRUE(cmpd(pU, 1 - 1./SIZE)); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == 0); + ASSERTTRUE(cmpd(AF, AF_answer)); + ASSERTTRUE(cmpd(pU, 1 - 1. / SIZE)); } +void testResTankSizingFract() +{ + HPWH hpwh; + double AF, pU; -void testResTankSizingFract() { - HPWH hpwh; - double AF, pU; - - string input = "restankRealistic"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "restankRealistic"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == HPWH::HPWH_ABORT); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == HPWH::HPWH_ABORT); } -void testStoTankSizingFract() { - HPWH hpwh; - double AF, pU; +void testStoTankSizingFract() +{ + HPWH hpwh; + double AF, pU; - string input = "StorageTank"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model + string input = "StorageTank"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model - int val = hpwh.getSizingFractions(AF, pU); - ASSERTTRUE(val == HPWH::HPWH_ABORT); + int val = hpwh.getSizingFractions(AF, pU); + ASSERTTRUE(val == HPWH::HPWH_ABORT); } +void testGetCompressorMinRuntime() +{ + HPWH hpwh; + string input = "TamScalable_SP"; // Just a compressor with R134A + getHPWHObject(hpwh, input); // get preset model -void testGetCompressorMinRuntime() { - HPWH hpwh; - string input = "TamScalable_SP"; // Just a compressor with R134A - getHPWHObject(hpwh, input); // get preset model - - double expected_mins = 10.; - double expected_secs = expected_mins * 60.; - double expected_hrs = expected_mins / 60.; - - double mins = hpwh.getCompressorMinRuntime(); - ASSERTTRUE(mins == expected_mins); + double expected_mins = 10.; + double expected_secs = expected_mins * 60.; + double expected_hrs = expected_mins / 60.; - double secs = hpwh.getCompressorMinRuntime(HPWH::UNITS_SEC); - ASSERTTRUE(secs == expected_secs); + double mins = hpwh.getCompressorMinRuntime(); + ASSERTTRUE(mins == expected_mins); - double hrs = hpwh.getCompressorMinRuntime(HPWH::UNITS_HR); - ASSERTTRUE(hrs == expected_hrs); + double secs = hpwh.getCompressorMinRuntime(HPWH::UNITS_SEC); + ASSERTTRUE(secs == expected_secs); + double hrs = hpwh.getCompressorMinRuntime(HPWH::UNITS_HR); + ASSERTTRUE(hrs == expected_hrs); } \ No newline at end of file diff --git a/test/testStateOfChargeFcts.cc b/test/testStateOfChargeFcts.cc index c3cb90fa..a4a93892 100644 --- a/test/testStateOfChargeFcts.cc +++ b/test/testStateOfChargeFcts.cc @@ -2,78 +2,79 @@ #include "testUtilityFcts.cc" #include -#include +#include void testGetStateOfCharge(); void testChargeBelowSetpoint(); - int main() { - testGetStateOfCharge(); - testChargeBelowSetpoint(); + testGetStateOfCharge(); + testChargeBelowSetpoint(); } -void testGetStateOfCharge() { - HPWH hpwh; - string input = "Sanden80"; - getHPWHObject(hpwh, input); - double tMains_C = F_TO_C(55.); - double tMinUseful_C = F_TO_C(110.); - double chargeFraction; +void testGetStateOfCharge() +{ + HPWH hpwh; + string input = "Sanden80"; + getHPWHObject(hpwh, input); + double tMains_C = F_TO_C(55.); + double tMinUseful_C = F_TO_C(110.); + double chargeFraction; - // Check for errors - chargeFraction = hpwh.calcSoCFraction(F_TO_C(125.), tMinUseful_C); - ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); - chargeFraction = hpwh.calcSoCFraction(tMains_C, F_TO_C(155.)); - ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(100.)); - ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); + // Check for errors + chargeFraction = hpwh.calcSoCFraction(F_TO_C(125.), tMinUseful_C); + ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); + chargeFraction = hpwh.calcSoCFraction(tMains_C, F_TO_C(155.)); + ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(100.)); + ASSERTTRUE(chargeFraction == HPWH::HPWH_ABORT); - // Check state of charge returns 1 at setpoint - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C); - ASSERTTRUE(cmpd(chargeFraction, 1.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C + 5., tMinUseful_C); - ASSERTTRUE(cmpd(chargeFraction, 1.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C + 5.); - ASSERTTRUE(cmpd(chargeFraction, 1.)); + // Check state of charge returns 1 at setpoint + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C); + ASSERTTRUE(cmpd(chargeFraction, 1.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C + 5., tMinUseful_C); + ASSERTTRUE(cmpd(chargeFraction, 1.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C + 5.); + ASSERTTRUE(cmpd(chargeFraction, 1.)); - // Varying max temp - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(110.)); - ASSERTTRUE(cmpd(chargeFraction, 1.70909)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(120.)); - ASSERTTRUE(cmpd(chargeFraction, 1.4461)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(135.)); - ASSERTTRUE(cmpd(chargeFraction, 1.175)); + // Varying max temp + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(110.)); + ASSERTTRUE(cmpd(chargeFraction, 1.70909)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(120.)); + ASSERTTRUE(cmpd(chargeFraction, 1.4461)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(135.)); + ASSERTTRUE(cmpd(chargeFraction, 1.175)); } -void testChargeBelowSetpoint() { - HPWH hpwh; - string input = "ColmacCxV_5_SP"; - getHPWHObject(hpwh, input); - double tMains_C = F_TO_C(60.); - double tMinUseful_C = F_TO_C(110.); - double chargeFraction; +void testChargeBelowSetpoint() +{ + HPWH hpwh; + string input = "ColmacCxV_5_SP"; + getHPWHObject(hpwh, input); + double tMains_C = F_TO_C(60.); + double tMinUseful_C = F_TO_C(110.); + double chargeFraction; - // Check state of charge returns 1 at setpoint - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C); - ASSERTTRUE(cmpd(chargeFraction, 1.)); + // Check state of charge returns 1 at setpoint + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C); + ASSERTTRUE(cmpd(chargeFraction, 1.)); - // Check state of charge returns 0 when tank below useful - hpwh.setTankToTemperature(F_TO_C(109.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); - ASSERTTRUE(cmpd(chargeFraction, 0.)); + // Check state of charge returns 0 when tank below useful + hpwh.setTankToTemperature(F_TO_C(109.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); + ASSERTTRUE(cmpd(chargeFraction, 0.)); - // Check some lower values with tank set at constant temperatures - hpwh.setTankToTemperature(F_TO_C(110.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); - ASSERTTRUE(cmpd(chargeFraction, 0.625)); + // Check some lower values with tank set at constant temperatures + hpwh.setTankToTemperature(F_TO_C(110.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); + ASSERTTRUE(cmpd(chargeFraction, 0.625)); - hpwh.setTankToTemperature(F_TO_C(120.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); - ASSERTTRUE(cmpd(chargeFraction, 0.75)); + hpwh.setTankToTemperature(F_TO_C(120.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); + ASSERTTRUE(cmpd(chargeFraction, 0.75)); - hpwh.setTankToTemperature(F_TO_C(130.)); - chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); - ASSERTTRUE(cmpd(chargeFraction, 0.875)); + hpwh.setTankToTemperature(F_TO_C(130.)); + chargeFraction = hpwh.calcSoCFraction(tMains_C, tMinUseful_C, F_TO_C(140.)); + ASSERTTRUE(cmpd(chargeFraction, 0.875)); } diff --git a/test/testTankSizeFixed.cc b/test/testTankSizeFixed.cc index be4886d2..7fe2d923 100644 --- a/test/testTankSizeFixed.cc +++ b/test/testTankSizeFixed.cc @@ -9,8 +9,7 @@ #include "testUtilityFcts.cc" #include -#include - +#include using std::cout; using std::string; @@ -18,97 +17,106 @@ using std::string; int testForceChangeTankSize(HPWH::MODELS model); int testIsTankSizeFixed(HPWH::MODELS model); -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - HPWH::MODELS presetModel; - - string input;// = "AOSmithCAHP120"; - - if (argc != 2) { - cout << "Invalid input. This program takes One arguments: preset model specification (ie. Sanden80). Recieved input: \n"; - for (int ii = 0; ii < argc; ii++) { - cout << argv[ii] << " "; - } - exit(1); - } - else { - input = argv[1]; - } - - // get model number - presetModel = mapStringToPreset(input); - - ASSERTTRUE(testIsTankSizeFixed(presetModel) == 0, "Tank size is not fixed"); - ASSERTTRUE(testForceChangeTankSize(presetModel) == 0, "Tank size was not forced to change"); - - //Made it through the gauntlet - return 0; + HPWH::MODELS presetModel; + + string input; // = "AOSmithCAHP120"; + + if (argc != 2) { + cout << "Invalid input. This program takes One arguments: preset model specification (ie. " + "Sanden80). Recieved input: \n"; + for (int ii = 0; ii < argc; ii++) { + cout << argv[ii] << " "; + } + exit(1); + } + else { + input = argv[1]; + } + + // get model number + presetModel = mapStringToPreset(input); + + ASSERTTRUE(testIsTankSizeFixed(presetModel) == 0, "Tank size is not fixed"); + ASSERTTRUE(testForceChangeTankSize(presetModel) == 0, "Tank size was not forced to change"); + + // Made it through the gauntlet + return 0; } -int testIsTankSizeFixed(HPWH::MODELS model) { - HPWH hpwh; - - // set preset - if (hpwh.HPWHinit_presets(model) != 0) return 1; - - double originalTankSize = hpwh.getTankSize(); - double newTankSize = originalTankSize + 100; - - // change the tank size - int result = hpwh.setTankSize(newTankSize); - - if (result != 0 && result != HPWH::HPWH_ABORT) { - cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; - return 1; - } - - if (hpwh.isTankSizeFixed()) { // better not have change! - if (result == 0) { - cout << "Error, setTankSize() returned 0 when should be HPWH_ABORT\n"; - return 1; - } - if (originalTankSize != hpwh.getTankSize()) { - cout << "Error, the tank size has changed when isTankSizeFixed is true\n"; - return 1; - } - } - else { // it better have changed - if (result != 0) { - cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; - return 1; - } - if (newTankSize != hpwh.getTankSize()) { - cout << "Error, the tank size hasn't changed to the new tank size when it should have. New Size: " << newTankSize << ". Returned Value: " << hpwh.getTankSize() << "\n"; - return 1; - } - } - return 0; +int testIsTankSizeFixed(HPWH::MODELS model) +{ + HPWH hpwh; + + // set preset + if (hpwh.HPWHinit_presets(model) != 0) + return 1; + + double originalTankSize = hpwh.getTankSize(); + double newTankSize = originalTankSize + 100; + + // change the tank size + int result = hpwh.setTankSize(newTankSize); + + if (result != 0 && result != HPWH::HPWH_ABORT) { + cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; + return 1; + } + + if (hpwh.isTankSizeFixed()) { // better not have change! + if (result == 0) { + cout << "Error, setTankSize() returned 0 when should be HPWH_ABORT\n"; + return 1; + } + if (originalTankSize != hpwh.getTankSize()) { + cout << "Error, the tank size has changed when isTankSizeFixed is true\n"; + return 1; + } + } + else { // it better have changed + if (result != 0) { + cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; + return 1; + } + if (newTankSize != hpwh.getTankSize()) { + cout << "Error, the tank size hasn't changed to the new tank size when it should have. " + "New Size: " + << newTankSize << ". Returned Value: " << hpwh.getTankSize() << "\n"; + return 1; + } + } + return 0; } -int testForceChangeTankSize(HPWH::MODELS model) { - HPWH hpwh; - - // set preset - if (hpwh.HPWHinit_presets(model) != 0) return 1; - - double newTankSize = 133.312; //No way a tank has this size originally - - // change the tank size - int result = hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL, true); - - if (result != 0 && result != HPWH::HPWH_ABORT) { - cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; - return 1; - } - - // it better have changed - if (result != 0) { - cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; - return 1; - } - if (newTankSize != hpwh.getTankSize(HPWH::UNITS_GAL)) { - cout << "Error, the tank size hasn't changed to the new tank size when it should have. New Size: " << newTankSize << ". Returned Value: " << hpwh.getTankSize(HPWH::UNITS_GAL) << "\n"; - return 1; - } - return 0; +int testForceChangeTankSize(HPWH::MODELS model) +{ + HPWH hpwh; + + // set preset + if (hpwh.HPWHinit_presets(model) != 0) + return 1; + + double newTankSize = 133.312; // No way a tank has this size originally + + // change the tank size + int result = hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL, true); + + if (result != 0 && result != HPWH::HPWH_ABORT) { + cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; + return 1; + } + + // it better have changed + if (result != 0) { + cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; + return 1; + } + if (newTankSize != hpwh.getTankSize(HPWH::UNITS_GAL)) { + cout << "Error, the tank size hasn't changed to the new tank size when it should have. New " + "Size: " + << newTankSize << ". Returned Value: " << hpwh.getTankSize(HPWH::UNITS_GAL) << "\n"; + return 1; + } + return 0; } diff --git a/test/testUtilityFcts.cc b/test/testUtilityFcts.cc index e46b797e..acee23f7 100644 --- a/test/testUtilityFcts.cc +++ b/test/testUtilityFcts.cc @@ -10,316 +10,323 @@ */ #include "HPWH.hh" #include -#include +#include using std::cout; using std::string; -#define F_TO_C(T) ((T-32.0)*5.0/9.0) -#define C_TO_F(T) (((9.0/5.0)*T) + 32.0) -#define dF_TO_dC(T) (T*5.0/9.0) -#define GAL_TO_L(GAL) (GAL*3.78541) +#define F_TO_C(T) ((T - 32.0) * 5.0 / 9.0) +#define C_TO_F(T) (((9.0 / 5.0) * T) + 32.0) +#define dF_TO_dC(T) (T * 5.0 / 9.0) +#define GAL_TO_L(GAL) (GAL * 3.78541) #define KW_TO_BTUperHR(KW) (KW * 3412.14) #define KWH_TO_BTU(KW) (KW * 3412.14) +#define ASSERTTRUE(input, ...) \ + if (!(input)) { \ + cout << "Assertation failed at " << __FILE__ << ", line: " << __LINE__ << ".\n"; \ + exit(1); \ + } +#define ASSERTFALSE(input, ...) \ + if ((input)) { \ + cout << "Assertation failed at " << __FILE__ << ", line: " << __LINE__ << ".\n"; \ + exit(1); \ + } -#define ASSERTTRUE(input, ...) if(! (input)) {cout<< "Assertation failed at " <<__FILE__ << ", line: " << __LINE__ << ".\n"; exit(1);} -#define ASSERTFALSE(input, ...) if( (input)) {cout<< "Assertation failed at " <<__FILE__ << ", line: " << __LINE__ << ".\n"; exit(1);} - - -//Compare doubles -bool cmpd(double A, double B, double epsilon = 0.0001) { - return (fabs(A - B) < epsilon); -} -//Relative Compare doubles -bool relcmpd(double A, double B, double epsilon = 0.00001) { - return fabs(A - B) < (epsilon *(fabs(A) < fabs(B) ? fabs(B) : fabs(A))); +// Compare doubles +bool cmpd(double A, double B, double epsilon = 0.0001) { return (fabs(A - B) < epsilon); } +// Relative Compare doubles +bool relcmpd(double A, double B, double epsilon = 0.00001) +{ + return fabs(A - B) < (epsilon * (fabs(A) < fabs(B) ? fabs(B) : fabs(A))); } -bool compressorIsRunning(HPWH& hpwh) { - return (bool)hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()); +bool compressorIsRunning(HPWH& hpwh) +{ + return (bool)hpwh.isNthHeatSourceRunning(hpwh.getCompressorIndex()); } -HPWH::MODELS mapStringToPreset(string modelName) { +HPWH::MODELS mapStringToPreset(string modelName) +{ - HPWH::MODELS hpwhModel; + HPWH::MODELS hpwhModel; - if(modelName == "Voltex60" || modelName == "AOSmithPHPT60") { - hpwhModel = HPWH::MODELS_AOSmithPHPT60; - } - else if (modelName == "Voltex80" || modelName == "AOSmith80") { - hpwhModel = HPWH::MODELS_AOSmithPHPT80; - } - else if (modelName == "GEred" || modelName == "GE") { - hpwhModel = HPWH::MODELS_GE2012; - } - else if (modelName == "SandenGAU" || modelName == "Sanden80" || modelName == "SandenGen3") { - hpwhModel = HPWH::MODELS_Sanden80; - } - else if (modelName == "Sanden120") { - hpwhModel = HPWH::MODELS_Sanden120; - } - else if (modelName == "SandenGES" || modelName == "Sanden40") { - hpwhModel = HPWH::MODELS_Sanden40; - } - else if (modelName == "AOSmithHPTU50") { - hpwhModel = HPWH::MODELS_AOSmithHPTU50; - } - else if (modelName == "AOSmithHPTU66") { - hpwhModel = HPWH::MODELS_AOSmithHPTU66; - } - else if (modelName == "AOSmithHPTU80") { - hpwhModel = HPWH::MODELS_AOSmithHPTU80; - } - else if (modelName == "AOSmithHPTS50") { - hpwhModel = HPWH::MODELS_AOSmithHPTS50; - } - else if (modelName == "AOSmithHPTS66") { - hpwhModel = HPWH::MODELS_AOSmithHPTS66; - } - else if (modelName == "AOSmithHPTS80") { - hpwhModel = HPWH::MODELS_AOSmithHPTS80; - } - else if (modelName == "AOSmithHPTU80DR") { - hpwhModel = HPWH::MODELS_AOSmithHPTU80_DR; - } - else if (modelName == "GE502014STDMode" || modelName == "GE2014STDMode") { - hpwhModel = HPWH::MODELS_GE2014STDMode; - } - else if (modelName == "GE502014" || modelName == "GE2014") { - hpwhModel = HPWH::MODELS_GE2014; - } - else if (modelName == "GE802014") { - hpwhModel = HPWH::MODELS_GE2014_80DR; - } - else if (modelName == "RheemHB50") { - hpwhModel = HPWH::MODELS_RheemHB50; - } - else if (modelName == "Stiebel220e" || modelName == "Stiebel220E") { - hpwhModel = HPWH::MODELS_Stiebel220E; - } - else if (modelName == "Generic1") { - hpwhModel = HPWH::MODELS_Generic1; - } - else if (modelName == "Generic2") { - hpwhModel = HPWH::MODELS_Generic2; - } - else if (modelName == "Generic3") { - hpwhModel = HPWH::MODELS_Generic3; - } - else if (modelName == "custom") { - hpwhModel = HPWH::MODELS_CustomFile; - } - else if (modelName == "restankRealistic") { - hpwhModel = HPWH::MODELS_restankRealistic; - } - else if (modelName == "StorageTank") { - hpwhModel = HPWH::MODELS_StorageTank; - } - else if (modelName == "BWC2020_65") { - hpwhModel = HPWH::MODELS_BWC2020_65; - } - // New Rheems - else if (modelName == "Rheem2020Prem40") { - hpwhModel = HPWH::MODELS_Rheem2020Prem40; - } - else if (modelName == "Rheem2020Prem50") { - hpwhModel = HPWH::MODELS_Rheem2020Prem50; - } - else if (modelName == "Rheem2020Prem65") { - hpwhModel = HPWH::MODELS_Rheem2020Prem65; - } - else if (modelName == "Rheem2020Prem80") { - hpwhModel = HPWH::MODELS_Rheem2020Prem80; - } - else if (modelName == "Rheem2020Build40") { - hpwhModel = HPWH::MODELS_Rheem2020Build40; - } - else if (modelName == "Rheem2020Build50") { - hpwhModel = HPWH::MODELS_Rheem2020Build50; - } - else if (modelName == "Rheem2020Build65") { - hpwhModel = HPWH::MODELS_Rheem2020Build65; - } - else if (modelName == "Rheem2020Build80") { - hpwhModel = HPWH::MODELS_Rheem2020Build80; - } - else if (modelName == "RheemPlugInDedicated40") { - hpwhModel = HPWH::MODELS_RheemPlugInDedicated40; - } - else if (modelName == "RheemPlugInDedicated50") { - hpwhModel = HPWH::MODELS_RheemPlugInDedicated50; - } - else if (modelName == "RheemPlugInShared40") { - hpwhModel = HPWH::MODELS_RheemPlugInShared40; - } - else if (modelName == "RheemPlugInShared50") { - hpwhModel = HPWH::MODELS_RheemPlugInShared50; - } - else if (modelName == "RheemPlugInShared65") { - hpwhModel = HPWH::MODELS_RheemPlugInShared65; - } - else if (modelName == "RheemPlugInShared80") { - hpwhModel = HPWH::MODELS_RheemPlugInShared80; - } - // Large HPWH's - else if (modelName == "AOSmithCAHP120") { - hpwhModel = HPWH::MODELS_AOSmithCAHP120; - } - else if (modelName == "ColmacCxV_5_SP") { - hpwhModel = HPWH::MODELS_ColmacCxV_5_SP; - } - else if (modelName == "ColmacCxA_10_SP") { - hpwhModel = HPWH::MODELS_ColmacCxA_10_SP; - } - else if (modelName == "ColmacCxA_15_SP") { - hpwhModel = HPWH::MODELS_ColmacCxA_15_SP; - } - else if (modelName == "ColmacCxA_20_SP") { - hpwhModel = HPWH::MODELS_ColmacCxA_20_SP; - } - else if (modelName == "ColmacCxA_25_SP") { - hpwhModel = HPWH::MODELS_ColmacCxA_25_SP; - } - else if (modelName == "ColmacCxA_30_SP") { - hpwhModel = HPWH::MODELS_ColmacCxA_30_SP; - } + if (modelName == "Voltex60" || modelName == "AOSmithPHPT60") { + hpwhModel = HPWH::MODELS_AOSmithPHPT60; + } + else if (modelName == "Voltex80" || modelName == "AOSmith80") { + hpwhModel = HPWH::MODELS_AOSmithPHPT80; + } + else if (modelName == "GEred" || modelName == "GE") { + hpwhModel = HPWH::MODELS_GE2012; + } + else if (modelName == "SandenGAU" || modelName == "Sanden80" || modelName == "SandenGen3") { + hpwhModel = HPWH::MODELS_Sanden80; + } + else if (modelName == "Sanden120") { + hpwhModel = HPWH::MODELS_Sanden120; + } + else if (modelName == "SandenGES" || modelName == "Sanden40") { + hpwhModel = HPWH::MODELS_Sanden40; + } + else if (modelName == "AOSmithHPTU50") { + hpwhModel = HPWH::MODELS_AOSmithHPTU50; + } + else if (modelName == "AOSmithHPTU66") { + hpwhModel = HPWH::MODELS_AOSmithHPTU66; + } + else if (modelName == "AOSmithHPTU80") { + hpwhModel = HPWH::MODELS_AOSmithHPTU80; + } + else if (modelName == "AOSmithHPTS50") { + hpwhModel = HPWH::MODELS_AOSmithHPTS50; + } + else if (modelName == "AOSmithHPTS66") { + hpwhModel = HPWH::MODELS_AOSmithHPTS66; + } + else if (modelName == "AOSmithHPTS80") { + hpwhModel = HPWH::MODELS_AOSmithHPTS80; + } + else if (modelName == "AOSmithHPTU80DR") { + hpwhModel = HPWH::MODELS_AOSmithHPTU80_DR; + } + else if (modelName == "GE502014STDMode" || modelName == "GE2014STDMode") { + hpwhModel = HPWH::MODELS_GE2014STDMode; + } + else if (modelName == "GE502014" || modelName == "GE2014") { + hpwhModel = HPWH::MODELS_GE2014; + } + else if (modelName == "GE802014") { + hpwhModel = HPWH::MODELS_GE2014_80DR; + } + else if (modelName == "RheemHB50") { + hpwhModel = HPWH::MODELS_RheemHB50; + } + else if (modelName == "Stiebel220e" || modelName == "Stiebel220E") { + hpwhModel = HPWH::MODELS_Stiebel220E; + } + else if (modelName == "Generic1") { + hpwhModel = HPWH::MODELS_Generic1; + } + else if (modelName == "Generic2") { + hpwhModel = HPWH::MODELS_Generic2; + } + else if (modelName == "Generic3") { + hpwhModel = HPWH::MODELS_Generic3; + } + else if (modelName == "custom") { + hpwhModel = HPWH::MODELS_CustomFile; + } + else if (modelName == "restankRealistic") { + hpwhModel = HPWH::MODELS_restankRealistic; + } + else if (modelName == "StorageTank") { + hpwhModel = HPWH::MODELS_StorageTank; + } + else if (modelName == "BWC2020_65") { + hpwhModel = HPWH::MODELS_BWC2020_65; + } + // New Rheems + else if (modelName == "Rheem2020Prem40") { + hpwhModel = HPWH::MODELS_Rheem2020Prem40; + } + else if (modelName == "Rheem2020Prem50") { + hpwhModel = HPWH::MODELS_Rheem2020Prem50; + } + else if (modelName == "Rheem2020Prem65") { + hpwhModel = HPWH::MODELS_Rheem2020Prem65; + } + else if (modelName == "Rheem2020Prem80") { + hpwhModel = HPWH::MODELS_Rheem2020Prem80; + } + else if (modelName == "Rheem2020Build40") { + hpwhModel = HPWH::MODELS_Rheem2020Build40; + } + else if (modelName == "Rheem2020Build50") { + hpwhModel = HPWH::MODELS_Rheem2020Build50; + } + else if (modelName == "Rheem2020Build65") { + hpwhModel = HPWH::MODELS_Rheem2020Build65; + } + else if (modelName == "Rheem2020Build80") { + hpwhModel = HPWH::MODELS_Rheem2020Build80; + } + else if (modelName == "RheemPlugInDedicated40") { + hpwhModel = HPWH::MODELS_RheemPlugInDedicated40; + } + else if (modelName == "RheemPlugInDedicated50") { + hpwhModel = HPWH::MODELS_RheemPlugInDedicated50; + } + else if (modelName == "RheemPlugInShared40") { + hpwhModel = HPWH::MODELS_RheemPlugInShared40; + } + else if (modelName == "RheemPlugInShared50") { + hpwhModel = HPWH::MODELS_RheemPlugInShared50; + } + else if (modelName == "RheemPlugInShared65") { + hpwhModel = HPWH::MODELS_RheemPlugInShared65; + } + else if (modelName == "RheemPlugInShared80") { + hpwhModel = HPWH::MODELS_RheemPlugInShared80; + } + // Large HPWH's + else if (modelName == "AOSmithCAHP120") { + hpwhModel = HPWH::MODELS_AOSmithCAHP120; + } + else if (modelName == "ColmacCxV_5_SP") { + hpwhModel = HPWH::MODELS_ColmacCxV_5_SP; + } + else if (modelName == "ColmacCxA_10_SP") { + hpwhModel = HPWH::MODELS_ColmacCxA_10_SP; + } + else if (modelName == "ColmacCxA_15_SP") { + hpwhModel = HPWH::MODELS_ColmacCxA_15_SP; + } + else if (modelName == "ColmacCxA_20_SP") { + hpwhModel = HPWH::MODELS_ColmacCxA_20_SP; + } + else if (modelName == "ColmacCxA_25_SP") { + hpwhModel = HPWH::MODELS_ColmacCxA_25_SP; + } + else if (modelName == "ColmacCxA_30_SP") { + hpwhModel = HPWH::MODELS_ColmacCxA_30_SP; + } - else if (modelName == "ColmacCxV_5_MP") { - hpwhModel = HPWH::MODELS_ColmacCxV_5_MP; - } - else if (modelName == "ColmacCxA_10_MP") { - hpwhModel = HPWH::MODELS_ColmacCxA_10_MP; - } - else if (modelName == "ColmacCxA_15_MP") { - hpwhModel = HPWH::MODELS_ColmacCxA_15_MP; - } - else if (modelName == "ColmacCxA_20_MP") { - hpwhModel = HPWH::MODELS_ColmacCxA_20_MP; - } - else if (modelName == "ColmacCxA_25_MP") { - hpwhModel = HPWH::MODELS_ColmacCxA_25_MP; - } - else if (modelName == "ColmacCxA_30_MP") { - hpwhModel = HPWH::MODELS_ColmacCxA_30_MP; - } - - else if (modelName == "RheemHPHD60") { - hpwhModel = HPWH::MODELS_RHEEM_HPHD60VNU_201_MP; - } - else if (modelName == "RheemHPHD135") { - hpwhModel = HPWH::MODELS_RHEEM_HPHD135VNU_483_MP; - } - //Nyle Single pass models - else if (modelName == "NyleC25A_SP") { - hpwhModel = HPWH::MODELS_NyleC25A_SP; - } - else if (modelName == "NyleC60A_SP") { - hpwhModel = HPWH::MODELS_NyleC60A_SP; - } - else if (modelName == "NyleC90A_SP") { - hpwhModel = HPWH::MODELS_NyleC90A_SP; - } - else if (modelName == "NyleC185A_SP") { - hpwhModel = HPWH::MODELS_NyleC185A_SP; - } - else if (modelName == "NyleC250A_SP") { - hpwhModel = HPWH::MODELS_NyleC250A_SP; - } - else if (modelName == "NyleC60A_C_SP") { - hpwhModel = HPWH::MODELS_NyleC60A_C_SP; - } - else if (modelName == "NyleC90A_C_SP") { - hpwhModel = HPWH::MODELS_NyleC90A_C_SP; - } - else if (modelName == "NyleC185A_C_SP") { - hpwhModel = HPWH::MODELS_NyleC185A_C_SP; - } - else if (modelName == "NyleC250A_C_SP") { - hpwhModel = HPWH::MODELS_NyleC250A_C_SP; - } - // Nyle MP models - else if (modelName == "NyleC60A_MP") { - hpwhModel = HPWH::MODELS_NyleC60A_MP; - } - else if (modelName == "NyleC90A_MP") { - hpwhModel = HPWH::MODELS_NyleC90A_MP; - } - else if (modelName == "NyleC125A_MP") { - hpwhModel = HPWH::MODELS_NyleC125A_MP; - } - else if (modelName == "NyleC185A_MP") { - hpwhModel = HPWH::MODELS_NyleC185A_MP; - } - else if (modelName == "NyleC250A_MP") { - hpwhModel = HPWH::MODELS_NyleC250A_MP; - } - else if (modelName == "NyleC60A_C_MP") { - hpwhModel = HPWH::MODELS_NyleC60A_C_MP; - } - else if (modelName == "NyleC90A_C_MP") { - hpwhModel = HPWH::MODELS_NyleC90A_C_MP; - } - else if (modelName == "NyleC125A_C_MP") { - hpwhModel = HPWH::MODELS_NyleC125A_C_MP; - } - else if (modelName == "NyleC185A_C_MP") { - hpwhModel = HPWH::MODELS_NyleC185A_C_MP; - } - else if (modelName == "NyleC250A_C_MP") { - hpwhModel = HPWH::MODELS_NyleC250A_C_MP; - } - else if (modelName == "QAHV_N136TAU_HPB_SP") { - hpwhModel = HPWH::MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP; - } - // Stack in a couple scalable models - else if (modelName == "TamScalable_SP") { - hpwhModel = HPWH::MODELS_TamScalable_SP; - } - else if (modelName == "TamScalable_SP_2X") { - hpwhModel = HPWH::MODELS_TamScalable_SP; - } - else if (modelName == "TamScalable_SP_Half") { - hpwhModel = HPWH::MODELS_TamScalable_SP; - } - else if (modelName == "Scalable_MP") { - hpwhModel = HPWH::MODELS_Scalable_MP; - } - else if (modelName == "AWHSTier3Generic40") { - hpwhModel = HPWH::MODELS_AWHSTier3Generic40; - } - else if (modelName == "AWHSTier3Generic50") { - hpwhModel = HPWH::MODELS_AWHSTier3Generic50; - } - else if (modelName == "AWHSTier3Generic65") { - hpwhModel = HPWH::MODELS_AWHSTier3Generic65; - } - else if (modelName == "AWHSTier3Generic80") { - hpwhModel = HPWH::MODELS_AWHSTier3Generic80; - } - else { - hpwhModel = HPWH::MODELS_basicIntegrated; - cout << "Couldn't find model " << modelName << ". Exiting...\n"; - exit(1); - } - return hpwhModel; -} + else if (modelName == "ColmacCxV_5_MP") { + hpwhModel = HPWH::MODELS_ColmacCxV_5_MP; + } + else if (modelName == "ColmacCxA_10_MP") { + hpwhModel = HPWH::MODELS_ColmacCxA_10_MP; + } + else if (modelName == "ColmacCxA_15_MP") { + hpwhModel = HPWH::MODELS_ColmacCxA_15_MP; + } + else if (modelName == "ColmacCxA_20_MP") { + hpwhModel = HPWH::MODELS_ColmacCxA_20_MP; + } + else if (modelName == "ColmacCxA_25_MP") { + hpwhModel = HPWH::MODELS_ColmacCxA_25_MP; + } + else if (modelName == "ColmacCxA_30_MP") { + hpwhModel = HPWH::MODELS_ColmacCxA_30_MP; + } + else if (modelName == "RheemHPHD60") { + hpwhModel = HPWH::MODELS_RHEEM_HPHD60VNU_201_MP; + } + else if (modelName == "RheemHPHD135") { + hpwhModel = HPWH::MODELS_RHEEM_HPHD135VNU_483_MP; + } + // Nyle Single pass models + else if (modelName == "NyleC25A_SP") { + hpwhModel = HPWH::MODELS_NyleC25A_SP; + } + else if (modelName == "NyleC60A_SP") { + hpwhModel = HPWH::MODELS_NyleC60A_SP; + } + else if (modelName == "NyleC90A_SP") { + hpwhModel = HPWH::MODELS_NyleC90A_SP; + } + else if (modelName == "NyleC185A_SP") { + hpwhModel = HPWH::MODELS_NyleC185A_SP; + } + else if (modelName == "NyleC250A_SP") { + hpwhModel = HPWH::MODELS_NyleC250A_SP; + } + else if (modelName == "NyleC60A_C_SP") { + hpwhModel = HPWH::MODELS_NyleC60A_C_SP; + } + else if (modelName == "NyleC90A_C_SP") { + hpwhModel = HPWH::MODELS_NyleC90A_C_SP; + } + else if (modelName == "NyleC185A_C_SP") { + hpwhModel = HPWH::MODELS_NyleC185A_C_SP; + } + else if (modelName == "NyleC250A_C_SP") { + hpwhModel = HPWH::MODELS_NyleC250A_C_SP; + } + // Nyle MP models + else if (modelName == "NyleC60A_MP") { + hpwhModel = HPWH::MODELS_NyleC60A_MP; + } + else if (modelName == "NyleC90A_MP") { + hpwhModel = HPWH::MODELS_NyleC90A_MP; + } + else if (modelName == "NyleC125A_MP") { + hpwhModel = HPWH::MODELS_NyleC125A_MP; + } + else if (modelName == "NyleC185A_MP") { + hpwhModel = HPWH::MODELS_NyleC185A_MP; + } + else if (modelName == "NyleC250A_MP") { + hpwhModel = HPWH::MODELS_NyleC250A_MP; + } + else if (modelName == "NyleC60A_C_MP") { + hpwhModel = HPWH::MODELS_NyleC60A_C_MP; + } + else if (modelName == "NyleC90A_C_MP") { + hpwhModel = HPWH::MODELS_NyleC90A_C_MP; + } + else if (modelName == "NyleC125A_C_MP") { + hpwhModel = HPWH::MODELS_NyleC125A_C_MP; + } + else if (modelName == "NyleC185A_C_MP") { + hpwhModel = HPWH::MODELS_NyleC185A_C_MP; + } + else if (modelName == "NyleC250A_C_MP") { + hpwhModel = HPWH::MODELS_NyleC250A_C_MP; + } + else if (modelName == "QAHV_N136TAU_HPB_SP") { + hpwhModel = HPWH::MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP; + } + // Stack in a couple scalable models + else if (modelName == "TamScalable_SP") { + hpwhModel = HPWH::MODELS_TamScalable_SP; + } + else if (modelName == "TamScalable_SP_2X") { + hpwhModel = HPWH::MODELS_TamScalable_SP; + } + else if (modelName == "TamScalable_SP_Half") { + hpwhModel = HPWH::MODELS_TamScalable_SP; + } + else if (modelName == "Scalable_MP") { + hpwhModel = HPWH::MODELS_Scalable_MP; + } + else if (modelName == "AWHSTier3Generic40") { + hpwhModel = HPWH::MODELS_AWHSTier3Generic40; + } + else if (modelName == "AWHSTier3Generic50") { + hpwhModel = HPWH::MODELS_AWHSTier3Generic50; + } + else if (modelName == "AWHSTier3Generic65") { + hpwhModel = HPWH::MODELS_AWHSTier3Generic65; + } + else if (modelName == "AWHSTier3Generic80") { + hpwhModel = HPWH::MODELS_AWHSTier3Generic80; + } + else { + hpwhModel = HPWH::MODELS_basicIntegrated; + cout << "Couldn't find model " << modelName << ". Exiting...\n"; + exit(1); + } + return hpwhModel; +} -int getHPWHObject(HPWH &hpwh, string modelName) { - /**Sets up the preset HPWH object with modelName */ - int returnVal = 1; - HPWH::MODELS model = mapStringToPreset(modelName); +int getHPWHObject(HPWH& hpwh, string modelName) +{ + /**Sets up the preset HPWH object with modelName */ + int returnVal = 1; + HPWH::MODELS model = mapStringToPreset(modelName); - returnVal = hpwh.HPWHinit_presets(model); + returnVal = hpwh.HPWHinit_presets(model); - if (modelName == "TamScalable_SP_2X") { - hpwh.setScaleHPWHCapacityCOP(2., 1.); // Scale the compressor - hpwh.setResistanceCapacity(60.); // Reset resistance elements in kW - } - else if (modelName == "TamScalable_SP_Half") { - hpwh.setScaleHPWHCapacityCOP(1/2., 1.); // Scale the compressor - hpwh.setResistanceCapacity(15.); // Reset resistance elements in kW - } - return returnVal; + if (modelName == "TamScalable_SP_2X") { + hpwh.setScaleHPWHCapacityCOP(2., 1.); // Scale the compressor + hpwh.setResistanceCapacity(60.); // Reset resistance elements in kW + } + else if (modelName == "TamScalable_SP_Half") { + hpwh.setScaleHPWHCapacityCOP(1 / 2., 1.); // Scale the compressor + hpwh.setResistanceCapacity(15.); // Reset resistance elements in kW + } + return returnVal; } \ No newline at end of file From a9feae7b22122d2cbbeea31b8b1599152e64a94f Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Mon, 23 Oct 2023 12:15:29 -0600 Subject: [PATCH 2/9] Fix brace style to Allman. --- .clang-format | 2 +- src/HPWH.in.hh | 71 +++-- src/HPWHHeatingLogics.cc | 95 ++++--- src/HPWHpresets.cc | 501 ++++++++++++++++++++++++------------ test/main.cc | 228 ++++++++++------ test/testCompressorFcts.cc | 3 +- test/testHeatingLogics.cc | 30 ++- test/testPerformanceMaps.cc | 6 +- test/testResistanceFcts.cc | 3 +- test/testScaleHPWH.cc | 11 +- test/testTankSizeFixed.cc | 39 ++- test/testUtilityFcts.cc | 261 ++++++++++++------- 12 files changed, 830 insertions(+), 420 deletions(-) diff --git a/.clang-format b/.clang-format index c2e69bdb..976cf3a1 100644 --- a/.clang-format +++ b/.clang-format @@ -80,7 +80,7 @@ BreakAfterJavaFieldAnnotations: false BreakArrays: true BreakBeforeBinaryOperators: None BreakBeforeConceptDeclarations: Always -BreakBeforeBraces: Stroustrup +BreakBeforeBraces: Allman BreakBeforeInlineASMColon: OnlyMultiline BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma diff --git a/src/HPWH.in.hh b/src/HPWH.in.hh index d5d2d7b6..ed04706c 100644 --- a/src/HPWH.in.hh +++ b/src/HPWH.in.hh @@ -13,7 +13,8 @@ #include //for exit #include -namespace Btwxt { +namespace Btwxt +{ class RegularGridInterpolator; }; @@ -22,12 +23,15 @@ class RegularGridInterpolator; * excluded from compiling. This is done in order to reduce the size of the * final compiled code. */ -#define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR @ -#define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR @ -#define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH @ +// clang-format off +#define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR@ +#define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR@ +#define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH@ #define HPWHVRSN_META "@HPWHsim_VRSN_META@" +// clang-format on -class HPWH { +class HPWH +{ public: static const int version_major = HPWHVRSN_MAJOR; static const int version_minor = HPWHVRSN_MINOR; @@ -68,7 +72,8 @@ class HPWH { /// specifies the various modes for the Demand Response (DR) abilities /// values may vary - names should be used - enum DRMODES { + enum DRMODES + { DR_ALLOW = 0b0000, /**= comparisons, so the numerical order is relevant - enum VERBOSITY { + enum VERBOSITY + { VRB_silent = 0, /**< print no outputs */ VRB_reluctant = 10, /**< print only outputs for fatal errors */ VRB_minuteOut = 15, /**< print minutely output */ @@ -249,7 +256,8 @@ class HPWH { VRB_emetic = 30 /**< print all the things */ }; - enum UNITS { + enum UNITS + { UNITS_C, /**< celsius */ UNITS_F, /**< fahrenheit */ UNITS_KWH, /**< kilowatt hours */ @@ -273,7 +281,8 @@ class HPWH { }; /** specifies the type of heat source */ - enum HEATSOURCE_TYPE { + enum HEATSOURCE_TYPE + { TYPE_none, /**< a default to check to make sure it's been set */ TYPE_resistance, /**< a resistance element */ TYPE_compressor, /**< a vapor cycle compressor */ @@ -281,19 +290,22 @@ class HPWH { }; /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ - enum EXTRAP_METHOD { + enum EXTRAP_METHOD + { EXTRAP_LINEAR, /**< the default extrapolates linearly */ EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest point */ }; /** specifies the unit type for outputs in the CSV file-s */ - enum CSVOPTIONS { + enum CSVOPTIONS + { CSVOPT_NONE, CSVOPT_IPUNITS }; - struct NodeWeight { + struct NodeWeight + { int nodeNum; double weight; NodeWeight(int n, double w) : nodeNum(n), weight(w) {}; @@ -301,7 +313,8 @@ class HPWH { NodeWeight(int n) : nodeNum(n), weight(1.0) {}; }; - struct HeatingLogic { + struct HeatingLogic + { public: std::string description; std::function compare; @@ -338,7 +351,8 @@ class HPWH { bool isEnteringWaterHighTempShutoff; }; - struct SoCBasedHeatingLogic : HeatingLogic { + struct SoCBasedHeatingLogic : HeatingLogic + { public: SoCBasedHeatingLogic(std::string desc, double d, @@ -371,7 +385,8 @@ class HPWH { double constantMains_C; }; - struct TempBasedHeatingLogic : HeatingLogic { + struct TempBasedHeatingLogic : HeatingLogic + { public: TempBasedHeatingLogic(std::string desc, std::vector n, @@ -1086,7 +1101,8 @@ class HPWH { bool doConduction; /**< If and only if true will model conduction between the internal nodes of the tank */ - struct resPoint { + struct resPoint + { int index; int position; }; @@ -1096,7 +1112,8 @@ class HPWH { }; // end of HPWH class -class HPWH::HeatSource { +class HPWH::HeatSource +{ public: friend class HPWH; @@ -1193,7 +1210,8 @@ class HPWH::HeatSource { private: // start with a few type definitions - enum COIL_CONFIG { + enum COIL_CONFIG + { CONFIG_SUBMERGED, CONFIG_WRAPPED, CONFIG_EXTERNAL @@ -1246,7 +1264,8 @@ class HPWH::HeatSource { alpha and beta are not intended to be settable see the hpwh_init functions for calculation of shrinkage */ - struct perfPoint { + struct perfPoint + { double T_F; std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T std::vector COP_coeffs; // c0 + c1*T + c2*T*T @@ -1277,14 +1296,16 @@ class HPWH::HeatSource { std::shared_ptr standbyLogic; /** some compressors have a resistance element for defrost*/ - struct resistanceElementDefrost { + struct resistanceElementDefrost + { double inputPwr_kW; double constTempLift_dF; double onBelowT_F; }; resistanceElementDefrost resDefrost; - struct defrostPoint { + struct defrostPoint + { double T_F; double derate_fraction; }; @@ -1292,7 +1313,8 @@ class HPWH::HeatSource { /**< A list of points for the defrost derate factor ordered by increasing external temperature */ - struct maxOut_minAir { + struct maxOut_minAir + { double outT_C; double airT_C; }; @@ -1300,7 +1322,8 @@ class HPWH::HeatSource { /**< maximum output temperature at the minimum operating temperature of HPWH environment * (minT)*/ - struct SecondaryHeatExchanger { + struct SecondaryHeatExchanger + { double coldSideTemperatureOffest_dC; double hotSideTemperatureOffset_dC; double extraPumpPower_W; diff --git a/src/HPWHHeatingLogics.cc b/src/HPWHHeatingLogics.cc index c3771bb4..0730c362 100644 --- a/src/HPWHHeatingLogics.cc +++ b/src/HPWHHeatingLogics.cc @@ -8,7 +8,8 @@ File of the presets heating logics available HPWHsim const bool HPWH::SoCBasedHeatingLogic::isValid() { bool isValid = true; - if (decisionPoint < 0) { + if (decisionPoint < 0) + { isValid = false; } return isValid; @@ -22,10 +23,12 @@ const double HPWH::SoCBasedHeatingLogic::getComparisonValue() const double HPWH::SoCBasedHeatingLogic::getTankValue() { double soCFraction; - if (parentHPWH->member_inletT_C == HPWH_ABORT && !useCostantMains) { + if (parentHPWH->member_inletT_C == HPWH_ABORT && !useCostantMains) + { soCFraction = HPWH_ABORT; } - else { + else + { soCFraction = parentHPWH->getSoCFraction(); } return soCFraction; @@ -33,10 +36,12 @@ const double HPWH::SoCBasedHeatingLogic::getTankValue() const double HPWH::SoCBasedHeatingLogic::getMainsT_C() { - if (useCostantMains) { + if (useCostantMains) + { return constantMains_C; } - else { + else + { return parentHPWH->member_inletT_C; } } @@ -65,19 +70,23 @@ const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() // Check how much of a change in the SoC fraction occurs if one full node at set point is added. // If this is less than the change needed move on. double fullNodeSoC = 1. / parentHPWH->numNodes; - if (deltaSoCFraction >= fullNodeSoC) { + if (deltaSoCFraction >= fullNodeSoC) + { return 1.; } // Find the last node greater the min use temp int calcNode = 0; - for (int i = parentHPWH->numNodes - 1; i >= 0; i--) { - if (parentHPWH->tankTemps_C[i] < tempMinUseful_C) { + for (int i = parentHPWH->numNodes - 1; i >= 0; i--) + { + if (parentHPWH->tankTemps_C[i] < tempMinUseful_C) + { calcNode = i + 1; break; } } - if (calcNode == parentHPWH->numNodes) { // if the whole tank is cold + if (calcNode == parentHPWH->numNodes) + { // if the whole tank is cold return 1.; } @@ -93,16 +102,19 @@ const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() // Catch case where node temperature == setpoint double fractCalcNode; - if (parentHPWH->tankTemps_C[calcNode] >= parentHPWH->setpoint_C) { + if (parentHPWH->tankTemps_C[calcNode] >= parentHPWH->setpoint_C) + { fractCalcNode = 1; } - else { + else + { fractCalcNode = (targetTemp - parentHPWH->tankTemps_C[calcNode]) / (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]); } // If we're at the bottom node there's not another node to heat so case 2 doesn't apply. - if (calcNode == 0) { + if (calcNode == 0) + { return fractCalcNode; } @@ -112,7 +124,8 @@ const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() (parentHPWH->tankTemps_C[calcNode] - parentHPWH->tankTemps_C[calcNode - 1]); fractNextNode += HPWH::TOL_MINVALUE; - if (parentHPWH->hpwhVerbosity >= VRB_emetic) { + if (parentHPWH->hpwhVerbosity >= VRB_emetic) + { double smallestSoCChangeWhenHeatingNextNode = 1. / maxSoC * (1. + fractNextNode * (parentHPWH->setpoint_C - parentHPWH->tankTemps_C[calcNode]) / @@ -134,7 +147,8 @@ const double HPWH::SoCBasedHeatingLogic::getFractToMeetComparisonExternal() const bool HPWH::TempBasedHeatingLogic::isValid() { bool isValid = true; - if (!areNodeWeightsValid()) { + if (!areNodeWeightsValid()) + { isValid = false; } return isValid; @@ -142,8 +156,10 @@ const bool HPWH::TempBasedHeatingLogic::isValid() const bool HPWH::TempBasedHeatingLogic::areNodeWeightsValid() { - for (auto nodeWeight : nodeWeights) { - if (nodeWeight.nodeNum > 13 || nodeWeight.nodeNum < 0) { + for (auto nodeWeight : nodeWeights) + { + if (nodeWeight.nodeNum > 13 || nodeWeight.nodeNum < 0) + { return false; } } @@ -153,10 +169,12 @@ const bool HPWH::TempBasedHeatingLogic::areNodeWeightsValid() const double HPWH::TempBasedHeatingLogic::getComparisonValue() { double value = decisionPoint; - if (isAbsolute) { + if (isAbsolute) + { return value; } - else { + else + { return parentHPWH->getSetpoint() - value; } } @@ -182,16 +200,20 @@ const double HPWH::TempBasedHeatingLogic::nodeWeightAvgFract() double logicNode; double calcNodes = 0, totWeight = 0; - for (auto nodeWeight : nodeWeights) { + for (auto nodeWeight : nodeWeights) + { // bottom calc node only - if (nodeWeight.nodeNum == 0) { // simple equation + if (nodeWeight.nodeNum == 0) + { // simple equation return 1. / (double)parentHPWH->getNumNodes(); } // top calc node only - else if (nodeWeight.nodeNum == 13) { + else if (nodeWeight.nodeNum == 13) + { return 1.; } - else { // have to tally up the nodes + else + { // have to tally up the nodes calcNodes += nodeWeight.nodeNum * nodeWeight.weight; totWeight += nodeWeight.weight; } @@ -213,26 +235,31 @@ const double HPWH::TempBasedHeatingLogic::getFractToMeetComparisonExternal() double comparison = getComparisonValue(); comparison += HPWH::TOL_MINVALUE; // Make this possible so we do slightly over heat - for (auto nodeWeight : nodeWeights) { + for (auto nodeWeight : nodeWeights) + { // bottom calc node only - if (nodeWeight.nodeNum == 0) { // simple equation + if (nodeWeight.nodeNum == 0) + { // simple equation calcNode = 0; firstNode = 0; sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; totWeight = nodeWeight.weight; } // top calc node only - else if (nodeWeight.nodeNum == 13) { + else if (nodeWeight.nodeNum == 13) + { calcNode = parentHPWH->getNumNodes() - 1; firstNode = parentHPWH->getNumNodes() - 1; sum = parentHPWH->tankTemps_C[firstNode] * nodeWeight.weight; totWeight = nodeWeight.weight; } - else { // have to tally up the nodes + else + { // have to tally up the nodes // frac = ( nodesN*comparision - ( Sum Ti from i = 0 to N ) ) / ( TN+1 - T0 ) firstNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity; - for (int n = 0; n < parentHPWH->nodeDensity; ++n) { // Loop on the nodes in the logics + for (int n = 0; n < parentHPWH->nodeDensity; ++n) + { // Loop on the nodes in the logics calcNode = (nodeWeight.nodeNum - 1) * parentHPWH->nodeDensity + n; sum += parentHPWH->tankTemps_C[calcNode] * nodeWeight.weight; totWeight += nodeWeight.weight; @@ -240,19 +267,23 @@ const double HPWH::TempBasedHeatingLogic::getFractToMeetComparisonExternal() } } - if (calcNode == parentHPWH->numNodes - 1) { // top node calc + if (calcNode == parentHPWH->numNodes - 1) + { // top node calc diff = parentHPWH->getSetpoint() - parentHPWH->tankTemps_C[firstNode]; } - else { + else + { diff = parentHPWH->tankTemps_C[calcNode + 1] - parentHPWH->tankTemps_C[firstNode]; } // if totWeight * comparison - sum < 0 then the shutoff condition is already true and you // shouldn't be here. Will revaluate shut off condition at the end the do while loop of // addHeatExternal, in the mean time lets not shift anything around. - if (compare(sum, totWeight * comparison)) { // Then should shut off - fracTemp = 0.; // 0 means shift no nodes + if (compare(sum, totWeight * comparison)) + { // Then should shut off + fracTemp = 0.; // 0 means shift no nodes } - else { + else + { // if the difference in denominator is <= 0 then we aren't adding heat to the nodes we care // about, so shift a whole node. fracTemp = diff > 0. ? (totWeight * comparison - sum) / diff : 1.; diff --git a/src/HPWHpresets.cc b/src/HPWHpresets.cc index f6eab77d..577c3b22 100644 --- a/src/HPWHpresets.cc +++ b/src/HPWHpresets.cc @@ -23,20 +23,26 @@ int HPWH::HPWHinit_resTank(double tankVol_L, // return 0 on success, HPWH_ABORT for failure // low power element will cause divide by zero/negative UA in EF -> UA conversion - if (lowerPower_W < 550) { - if (hpwhVerbosity >= VRB_reluctant) { + if (lowerPower_W < 550) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Resistance tank lower element wattage below 550 W. DOES NOT COMPUTE\n"); } return HPWH_ABORT; } - if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (upperPower_W < 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } return HPWH_ABORT; } - if (energyFactor <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (energyFactor <= 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Energy Factor less than zero. DOES NOT COMPUTE\n"); } return HPWH_ABORT; @@ -45,7 +51,8 @@ int HPWH::HPWHinit_resTank(double tankVol_L, // use tank size setting function since it has bounds checking tankSizeFixed = false; int failure = this->setTankSize(tankVol_L); - if (failure == HPWH_ABORT) { + if (failure == HPWH_ABORT) + { return failure; } @@ -67,7 +74,8 @@ int HPWH::HPWHinit_resTank(double tankVol_L, resistiveElementBottom.addTurnOnLogic(HPWH::bottomThird(dF_TO_dC(40))); resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10))); - if (upperPower_W > 0.) { + if (upperPower_W > 0.) + { // Only add an upper element when the upperPower_W > 0 otherwise ignore this. // If the element is added this can mess with the intended logic. HeatSource resistiveElementTop(this); @@ -85,7 +93,8 @@ int HPWH::HPWHinit_resTank(double tankVol_L, setOfSources[0].followedByHeatSource = &setOfSources[1]; } - else { + else + { numHeatSources = 1; setOfSources = new HeatSource[numHeatSources]; setOfSources[0] = resistiveElementBottom; @@ -102,8 +111,10 @@ int HPWH::HPWHinit_resTank(double tankVol_L, double denominator = 67.5 * ((24.0 / 41094.0) - temp); tankUA_kJperHrC = UAf_TO_UAc(numerator / denominator); - if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { + if (tankUA_kJperHrC < 0.) + { + if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) + { msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); } tankUA_kJperHrC = 0.0; @@ -118,15 +129,19 @@ int HPWH::HPWHinit_resTank(double tankVol_L, return HPWH_ABORT; isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isOn) + { isHeating = true; } setOfSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) + { + for (int i = 0; i < numHeatSources; i++) + { msg("heat source %d: %p \n", i, &setOfSources[i]); } msg("\n\n"); @@ -147,20 +162,26 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, // return 0 on success, HPWH_ABORT for failure // low power element will cause divide by zero/negative UA in EF -> UA conversion - if (lowerPower_W < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (lowerPower_W < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Lower resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } return HPWH_ABORT; } - if (upperPower_W < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (upperPower_W < 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Upper resistance tank wattage below 0 W. DOES NOT COMPUTE\n"); } return HPWH_ABORT; } - if (rValue_M2KperW <= 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (rValue_M2KperW <= 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("R-Value is equal to or below 0. DOES NOT COMPUTE\n"); } return HPWH_ABORT; @@ -168,7 +189,8 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, // set tank size function has bounds checking tankSizeFixed = false; - if (this->setTankSize(tankVol_L) == HPWH_ABORT) { + if (this->setTankSize(tankVol_L) == HPWH_ABORT) + { return HPWH_ABORT; } canScale = true; @@ -189,7 +211,8 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, setOfSources = new HeatSource[numHeatSources]; // Deal with upper element - if (upperPower_W > 0.) { + if (upperPower_W > 0.) + { // Only add an upper element when the upperPower_W > 0 otherwise ignore this. // If the element is added this can mess with the intended logic. HeatSource resistiveElementTop(this); @@ -202,7 +225,8 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, } // Deal with bottom element - if (lowerPower_W > 0.) { + if (lowerPower_W > 0.) + { HeatSource resistiveElementBottom(this); resistiveElementBottom.setupAsResistiveElement(0, lowerPower_W); @@ -210,10 +234,12 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, resistiveElementBottom.addTurnOnLogic(HPWH::standby(dF_TO_dC(10.))); // set everything in it's correct place - if (numHeatSources == 1) { // if one only one slot + if (numHeatSources == 1) + { // if one only one slot setOfSources[0] = resistiveElementBottom; } - else if (numHeatSources == 2) { // if two upper already exists + else if (numHeatSources == 2) + { // if two upper already exists setOfSources[1] = resistiveElementBottom; setOfSources[0].followedByHeatSource = &setOfSources[1]; } @@ -224,8 +250,10 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, double tankUA_WperK = SA_M2 / rValue_M2KperW; tankUA_kJperHrC = tankUA_WperK * 3.6; // 3.6 = 3600 S/Hr and 1/1000 kJ/J - if (tankUA_kJperHrC < 0.) { - if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) { + if (tankUA_kJperHrC < 0.) + { + if (hpwhVerbosity >= VRB_reluctant && tankUA_kJperHrC < -0.1) + { msg("Computed tankUA_kJperHrC is less than 0, and is reset to 0."); } tankUA_kJperHrC = 0.0; @@ -240,15 +268,19 @@ int HPWH::HPWHinit_resTankGeneric(double tankVol_L, return HPWH_ABORT; isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isOn) + { isHeating = true; } setOfSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) + { + for (int i = 0; i < numHeatSources; i++) + { msg("heat source %d: %p \n", i, &setOfSources[i]); } msg("\n\n"); @@ -346,8 +378,10 @@ int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double res // set tank volume from input // use tank size setting function since it has bounds checking int failure = this->setTankSize(tankVol_L); - if (failure == HPWH_ABORT) { - if (hpwhVerbosity >= VRB_reluctant) { + if (failure == HPWH_ABORT) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Failure to set tank size in generic hpwh init."); } return failure; @@ -404,20 +438,25 @@ int HPWH::HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double res // calculate oft-used derived values calcDerivedValues(); - if (checkInputs() == HPWH_ABORT) { + if (checkInputs() == HPWH_ABORT) + { return HPWH_ABORT; } isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isOn) + { isHeating = true; } setOfSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) + { + for (int i = 0; i < numHeatSources; i++) + { msg("heat source %d: %p \n", i, &setOfSources[i]); } msg("\n\n"); @@ -436,7 +475,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // return 0 on success, HPWH_ABORT for failure // resistive with no UA losses for testing - if (presetNum == MODELS_restankNoUA) { + if (presetNum == MODELS_restankNoUA) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -471,7 +511,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // resistive tank with massive UA loss for testing - else if (presetNum == MODELS_restankHugeUA) { + else if (presetNum == MODELS_restankHugeUA) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = 50; @@ -508,7 +549,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // realistic resistive tank - else if (presetNum == MODELS_restankRealistic) { + else if (presetNum == MODELS_restankRealistic) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -542,7 +584,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; } - else if (presetNum == MODELS_StorageTank) { + else if (presetNum == MODELS_StorageTank) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = 52; @@ -577,7 +620,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // basic compressor tank for testing - else if (presetNum == MODELS_basicIntegrated) { + else if (presetNum == MODELS_basicIntegrated) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = 50; @@ -660,7 +704,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // simple external style for testing - else if (presetNum == MODELS_externalTest) { + else if (presetNum == MODELS_externalTest) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = 50; @@ -719,7 +764,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0] = compressor; } // voltex 60 gallon - else if (presetNum == MODELS_AOSmithPHPT60) { + else if (presetNum == MODELS_AOSmithPHPT60) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -801,7 +847,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_AOSmithPHPT80) { + else if (presetNum == MODELS_AOSmithPHPT80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -883,7 +930,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2012) { + else if (presetNum == MODELS_GE2012) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -971,7 +1019,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[1].followedByHeatSource = &setOfSources[2]; } // If a Colmac single pass preset cold weather or not - else if (MODELS_ColmacCxV_5_SP <= presetNum && presetNum <= MODELS_ColmacCxA_30_SP) { + else if (MODELS_ColmacCxV_5_SP <= presetNum && presetNum <= MODELS_ColmacCxA_30_SP) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -1015,7 +1064,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // Defrost Derate compressor.setupDefrostMap(); - if (presetNum == MODELS_ColmacCxV_5_SP) { + if (presetNum == MODELS_ColmacCxV_5_SP) + { setTankSize_adjustUA(200., UNITS_GAL); // logic conditions compressor.minT = F_TO_C(-4.0); @@ -1049,12 +1099,14 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0000000606} // COP Coefficients (COP_coeffs) }); } - else { + else + { // logic conditions compressor.minT = F_TO_C(40.); compressor.maxSetpoint_C = MAXOUTLET_R134A; - if (presetNum == MODELS_ColmacCxA_10_SP) { + if (presetNum == MODELS_ColmacCxA_10_SP) + { setTankSize_adjustUA(500., UNITS_GAL); compressor.perfMap.push_back({ @@ -1085,7 +1137,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0000005037} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_15_SP) { + else if (presetNum == MODELS_ColmacCxA_15_SP) + { setTankSize_adjustUA(600., UNITS_GAL); compressor.perfMap.push_back({ @@ -1116,7 +1169,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 0.0000004108} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_20_SP) { + else if (presetNum == MODELS_ColmacCxA_20_SP) + { setTankSize_adjustUA(800., UNITS_GAL); compressor.perfMap.push_back({ @@ -1147,7 +1201,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0000003135} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_25_SP) { + else if (presetNum == MODELS_ColmacCxA_25_SP) + { setTankSize_adjustUA(1000., UNITS_GAL); compressor.perfMap.push_back({ @@ -1178,7 +1233,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 0.0000006306} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_30_SP) { + else if (presetNum == MODELS_ColmacCxA_30_SP) + { setTankSize_adjustUA(1200., UNITS_GAL); compressor.perfMap.push_back({ @@ -1216,7 +1272,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // if colmac multipass - else if (MODELS_ColmacCxV_5_MP <= presetNum && presetNum <= MODELS_ColmacCxA_30_MP) { + else if (MODELS_ColmacCxV_5_MP <= presetNum && presetNum <= MODELS_ColmacCxA_30_MP) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -1258,7 +1315,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // Defrost Derate compressor.setupDefrostMap(); - if (presetNum == MODELS_ColmacCxV_5_MP) { + if (presetNum == MODELS_ColmacCxV_5_MP) + { setTankSize_adjustUA(200., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS( 9.); // https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf @@ -1285,13 +1343,15 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0002911167} // COP Coefficients (COP_coeffs) }); } - else { + else + { // logic conditions compressor.minT = F_TO_C(40.); compressor.maxT = F_TO_C(105.); compressor.maxSetpoint_C = MAXOUTLET_R134A; - if (presetNum == MODELS_ColmacCxA_10_MP) { + if (presetNum == MODELS_ColmacCxA_10_MP) + { setTankSize_adjustUA(500., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(18.); compressor.perfMap.push_back({ @@ -1312,7 +1372,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0002365885} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_15_MP) { + else if (presetNum == MODELS_ColmacCxA_15_MP) + { setTankSize_adjustUA(600., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(26.); compressor.perfMap.push_back({ @@ -1334,7 +1395,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) }); } - else if (presetNum == MODELS_ColmacCxA_20_MP) { + else if (presetNum == MODELS_ColmacCxA_20_MP) + { setTankSize_adjustUA(800., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS( 36.); // https://colmacwaterheat.com/wp-content/uploads/2020/10/Technical-Datasheet-Air-Source.pdf @@ -1357,7 +1419,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0002910606} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_25_MP) { + else if (presetNum == MODELS_ColmacCxA_25_MP) + { setTankSize_adjustUA(1000., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(32.); compressor.perfMap.push_back({ @@ -1378,7 +1441,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) -0.0003684106} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_ColmacCxA_30_MP) { + else if (presetNum == MODELS_ColmacCxA_30_MP) + { setTankSize_adjustUA(1200., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(41.); compressor.perfMap.push_back({ @@ -1405,7 +1469,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0] = compressor; } // If Nyle single pass preset - else if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_C_SP) { + else if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_C_SP) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -1435,11 +1500,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.externalInletHeight = numNodes - 1; // logic conditions - if (MODELS_NyleC25A_SP <= presetNum && - presetNum <= MODELS_NyleC250A_SP) { // If not cold weather package - compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package + if (MODELS_NyleC25A_SP <= presetNum && presetNum <= MODELS_NyleC250A_SP) + { // If not cold weather package + compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package } - else { + else + { compressor.minT = F_TO_C(35.); // Min air temperature WITH Cold Weather Package } compressor.maxT = F_TO_C(120.0); // Max air temperature @@ -1466,7 +1532,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.setupDefrostMap(); // Perfmaps for each compressor size - if (presetNum == MODELS_NyleC25A_SP) { + if (presetNum == MODELS_NyleC25A_SP) + { setTankSize_adjustUA(200., UNITS_GAL); compressor.perfMap.push_back({ 90, // Temperature (T_F) @@ -1496,7 +1563,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 0.000001900} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_NyleC60A_SP || presetNum == MODELS_NyleC60A_C_SP) { + else if (presetNum == MODELS_NyleC60A_SP || presetNum == MODELS_NyleC60A_C_SP) + { setTankSize_adjustUA(300., UNITS_GAL); compressor.perfMap.push_back({ 90, // Temperature (T_F) @@ -1526,7 +1594,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 0.0000005568} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_NyleC90A_SP || presetNum == MODELS_NyleC90A_C_SP) { + else if (presetNum == MODELS_NyleC90A_SP || presetNum == MODELS_NyleC90A_C_SP) + { setTankSize_adjustUA(400., UNITS_GAL); compressor.perfMap.push_back({ 90, // Temperature (T_F) @@ -1556,7 +1625,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 0.00000176015} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_NyleC125A_SP || presetNum == MODELS_NyleC125A_C_SP) { + else if (presetNum == MODELS_NyleC125A_SP || presetNum == MODELS_NyleC125A_C_SP) + { setTankSize_adjustUA(500., UNITS_GAL); compressor.perfMap.push_back({ 90, // Temperature (T_F) @@ -1586,7 +1656,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 1.47884E-06} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_NyleC185A_SP || presetNum == MODELS_NyleC185A_C_SP) { + else if (presetNum == MODELS_NyleC185A_SP || presetNum == MODELS_NyleC185A_C_SP) + { setTankSize_adjustUA(800., UNITS_GAL); compressor.perfMap.push_back({ 90, // Temperature (T_F) @@ -1616,7 +1687,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 5.55444E-06} // COP Coefficients (COP_coeffs) }); } - else if (presetNum == MODELS_NyleC250A_SP || presetNum == MODELS_NyleC250A_C_SP) { + else if (presetNum == MODELS_NyleC250A_SP || presetNum == MODELS_NyleC250A_C_SP) + { setTankSize_adjustUA(800., UNITS_GAL); compressor.perfMap.push_back({ @@ -1653,7 +1725,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // If Nyle multipass presets - else if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_C_MP) { + else if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_C_MP) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -1680,11 +1753,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.externalInletHeight = (int)(numNodes / 3.) - 1; // logic conditions//logic conditions - if (MODELS_NyleC60A_MP <= presetNum && - presetNum <= MODELS_NyleC250A_MP) { // If not cold weather package - compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package + if (MODELS_NyleC60A_MP <= presetNum && presetNum <= MODELS_NyleC250A_MP) + { // If not cold weather package + compressor.minT = F_TO_C(40.); // Min air temperature sans Cold Weather Package } - else { + else + { compressor.minT = F_TO_C(35.); // Min air temperature WITH Cold Weather Package } compressor.maxT = F_TO_C(130.0); // Max air temperature @@ -1712,10 +1786,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.perfGrid.push_back({40., 60., 80., 90.}); // Grid Axis 1 Tair (F) compressor.perfGrid.push_back({40., 60., 80., 100., 130., 150.}); // Grid Axis 2 Tin (F) - if (presetNum == MODELS_NyleC60A_MP || presetNum == MODELS_NyleC60A_C_MP) { + if (presetNum == MODELS_NyleC60A_MP || presetNum == MODELS_NyleC60A_C_MP) + { setTankSize_adjustUA(360., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(13.); - if (presetNum == MODELS_NyleC60A_C_MP) { + if (presetNum == MODELS_NyleC60A_C_MP) + { compressor.resDefrost = { 4.5, // inputPwr_kW; 5.0, // constTempLift_dF; @@ -1733,10 +1809,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 5.467336683, 4.708609272, 3.921755725, 3.169871795, 2.165105386, 1.860732984, 5.512359551, 5.153846154, 4.290502793, 3.417981073, 2.272409779, 1.927748691}); } - else if (presetNum == MODELS_NyleC90A_MP || presetNum == MODELS_NyleC90A_C_MP) { + else if (presetNum == MODELS_NyleC90A_MP || presetNum == MODELS_NyleC90A_C_MP) + { setTankSize_adjustUA(480., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(20.); - if (presetNum == MODELS_NyleC90A_C_MP) { + if (presetNum == MODELS_NyleC90A_C_MP) + { compressor.resDefrost = { 5.4, // inputPwr_kW; 5.0, // constTempLift_dF; @@ -1754,10 +1832,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 7.150635209, 5.659159159, 4.305687204, 3.493467337, 2.487748851, 2.018241042, 6.750737463, 5.604621309, 4.734392736, 3.94005994, 3.04534005, 2.558801498}); } - else if (presetNum == MODELS_NyleC125A_MP || presetNum == MODELS_NyleC125A_C_MP) { + else if (presetNum == MODELS_NyleC125A_MP || presetNum == MODELS_NyleC125A_C_MP) + { setTankSize_adjustUA(600., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(28.); - if (presetNum == MODELS_NyleC125A_C_MP) { + if (presetNum == MODELS_NyleC125A_C_MP) + { compressor.resDefrost = { 9.0, // inputPwr_kW; 5.0, // constTempLift_dF; @@ -1775,10 +1855,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 6.503250975, 5.276736494, 4.229070837, 3.27827381, 2.113821138, 1.770469799, 6.657342657, 5.749473684, 4.612244898, 3.542731921, 2.221095335, 1.816964286}); } - else if (presetNum == MODELS_NyleC185A_MP || presetNum == MODELS_NyleC185A_C_MP) { + else if (presetNum == MODELS_NyleC185A_MP || presetNum == MODELS_NyleC185A_C_MP) + { setTankSize_adjustUA(960., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(40.); - if (presetNum == MODELS_NyleC185A_C_MP) { + if (presetNum == MODELS_NyleC185A_C_MP) + { compressor.resDefrost = { 7.2, // inputPwr_kW; 5.0, // constTempLift_dF; @@ -1796,10 +1878,12 @@ int HPWH::HPWHinit_presets(MODELS presetNum) 9.65819568, 6.200166113, 4.792276964, 3.705475811, 2.561369758, 2.05950096, 10.26993865, 6.350722311, 5.04218853, 3.841688654, 2.574151735, 2.025616698}); } - else if (presetNum == MODELS_NyleC250A_MP || presetNum == MODELS_NyleC250A_C_MP) { + else if (presetNum == MODELS_NyleC250A_MP || presetNum == MODELS_NyleC250A_C_MP) + { setTankSize_adjustUA(960., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(50.); - if (presetNum == MODELS_NyleC250A_C_MP) { + if (presetNum == MODELS_NyleC250A_C_MP) + { compressor.resDefrost = { 18.0, // inputPwr_kW; 5.0, // constTempLift_dF; @@ -1830,7 +1914,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // if rheem multipass else if (MODELS_RHEEM_HPHD60HNU_201_MP <= presetNum && - presetNum <= MODELS_RHEEM_HPHD135VNU_483_MP) { + presetNum <= MODELS_RHEEM_HPHD135VNU_483_MP) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -1877,7 +1962,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.maxSetpoint_C = MAXOUTLET_R134A; // data says 150... if (presetNum == MODELS_RHEEM_HPHD60HNU_201_MP || - presetNum == MODELS_RHEEM_HPHD60VNU_201_MP) { + presetNum == MODELS_RHEEM_HPHD60VNU_201_MP) + { setTankSize_adjustUA(250., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(17.4); compressor.perfMap.push_back({ @@ -1899,7 +1985,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) }); } else if (presetNum == MODELS_RHEEM_HPHD135HNU_483_MP || - presetNum == MODELS_RHEEM_HPHD135VNU_483_MP) { + presetNum == MODELS_RHEEM_HPHD135VNU_483_MP) + { setTankSize_adjustUA(500., UNITS_GAL); compressor.mpFlowRate_LPS = GPM_TO_LPS(34.87); compressor.perfMap.push_back({ @@ -1925,7 +2012,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0] = compressor; } - else if (presetNum == MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP) { + else if (presetNum == MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = 65; @@ -2191,20 +2279,24 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } else if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_GS3_45HPA_US_SP || - presetNum == MODELS_SANCO2_119) { + presetNum == MODELS_SANCO2_119) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = 65; setpointFixed = true; - if (presetNum == MODELS_SANCO2_119) { + if (presetNum == MODELS_SANCO2_119) + { tankVolume_L = GAL_TO_L(119); tankUA_kJperHrC = 9; } - else { + else + { tankVolume_L = 315; tankUA_kJperHrC = 7; - if (presetNum == MODELS_SANCO2_GS3_45HPA_US_SP) { + if (presetNum == MODELS_SANCO2_GS3_45HPA_US_SP) + { tankSizeFixed = false; } } @@ -2266,7 +2358,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) nodeWeights.emplace_back(8); compressor.addTurnOnLogic(std::make_shared( "eighth node absolute", nodeWeights, F_TO_C(113), this, true)); - if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_119) { + if (presetNum == MODELS_SANCO2_83 || presetNum == MODELS_SANCO2_119) + { compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(8.2639))); // Adds a bonus standby logic so the external heater does not cycle, recommended for any // external heater with standby @@ -2296,7 +2389,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // set everything in its places setOfSources[0] = compressor; } - else if (presetNum == MODELS_SANCO2_43) { + else if (presetNum == MODELS_SANCO2_43) + { numNodes = 96; tankTemps_C = new double[numNodes]; setpoint_C = 65; @@ -2392,7 +2486,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0] = compressor; } else if (presetNum == MODELS_AOSmithHPTU50 || presetNum == MODELS_RheemHBDR2250 || - presetNum == MODELS_RheemHBDR4550) { + presetNum == MODELS_RheemHBDR4550) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -2446,19 +2541,23 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.maxSetpoint_C = MAXOUTLET_R134A; // top resistor values - if (presetNum == MODELS_RheemHBDR2250) { + if (presetNum == MODELS_RheemHBDR2250) + { resistiveElementTop.setupAsResistiveElement(8, 2250); } - else { + else + { resistiveElementTop.setupAsResistiveElement(8, 4500); } resistiveElementTop.isVIP = true; // bottom resistor values - if (presetNum == MODELS_RheemHBDR2250) { + if (presetNum == MODELS_RheemHBDR2250) + { resistiveElementBottom.setupAsResistiveElement(0, 2250); } - else { + else + { resistiveElementBottom.setupAsResistiveElement(0, 4500); } resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); @@ -2494,15 +2593,18 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } else if (presetNum == MODELS_AOSmithHPTU66 || presetNum == MODELS_RheemHBDR2265 || - presetNum == MODELS_RheemHBDR4565) { + presetNum == MODELS_RheemHBDR4565) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_AOSmithHPTU66) { + if (presetNum == MODELS_AOSmithHPTU66) + { tankVolume_L = 244.6; } - else { + else + { tankVolume_L = 221.4; } tankUA_kJperHrC = 8; @@ -2553,19 +2655,23 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.maxSetpoint_C = MAXOUTLET_R134A; // top resistor values - if (presetNum == MODELS_RheemHBDR2265) { + if (presetNum == MODELS_RheemHBDR2265) + { resistiveElementTop.setupAsResistiveElement(8, 2250); } - else { + else + { resistiveElementTop.setupAsResistiveElement(8, 4500); } resistiveElementTop.isVIP = true; // bottom resistor values - if (presetNum == MODELS_RheemHBDR2265) { + if (presetNum == MODELS_RheemHBDR2265) + { resistiveElementBottom.setupAsResistiveElement(0, 2250); } - else { + else + { resistiveElementBottom.setupAsResistiveElement(0, 4500); } resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); @@ -2601,7 +2707,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } else if (presetNum == MODELS_AOSmithHPTU80 || presetNum == MODELS_RheemHBDR2280 || - presetNum == MODELS_RheemHBDR4580) { + presetNum == MODELS_RheemHBDR4580) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -2654,19 +2761,23 @@ int HPWH::HPWHinit_presets(MODELS presetNum) compressor.hysteresis_dC = dF_TO_dC(1); // top resistor values - if (presetNum == MODELS_RheemHBDR2280) { + if (presetNum == MODELS_RheemHBDR2280) + { resistiveElementTop.setupAsResistiveElement(8, 2250); } - else { + else + { resistiveElementTop.setupAsResistiveElement(8, 4500); } resistiveElementTop.isVIP = true; // bottom resistor values - if (presetNum == MODELS_RheemHBDR2280) { + if (presetNum == MODELS_RheemHBDR2280) + { resistiveElementBottom.setupAsResistiveElement(0, 2250); } - else { + else + { resistiveElementBottom.setupAsResistiveElement(0, 4500); } resistiveElementBottom.hysteresis_dC = dF_TO_dC(2); @@ -2702,7 +2813,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_AOSmithHPTU80_DR) { + else if (presetNum == MODELS_AOSmithHPTU80_DR) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -2781,7 +2893,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_AOSmithCAHP120) { + else if (presetNum == MODELS_AOSmithCAHP120) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(150.0); @@ -2876,20 +2989,24 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[1]; setOfSources[1].companionHeatSource = &setOfSources[2]; } - else if (MODELS_AOSmithHPTS50 <= presetNum && presetNum <= MODELS_AOSmithHPTS80) { + else if (MODELS_AOSmithHPTS50 <= presetNum && presetNum <= MODELS_AOSmithHPTS80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_AOSmithHPTS50) { + if (presetNum == MODELS_AOSmithHPTS50) + { tankVolume_L = GAL_TO_L(45.6); tankUA_kJperHrC = 6.403; } - else if (presetNum == MODELS_AOSmithHPTS66) { + else if (presetNum == MODELS_AOSmithHPTS66) + { tankVolume_L = GAL_TO_L(67.63); tankUA_kJperHrC = UAf_TO_UAc(1.5) * 6.403 / UAf_TO_UAc(1.16); } - else if (presetNum == MODELS_AOSmithHPTS80) { + else if (presetNum == MODELS_AOSmithHPTS80) + { tankVolume_L = GAL_TO_L(81.94); tankUA_kJperHrC = UAf_TO_UAc(1.73) * 6.403 / UAf_TO_UAc(1.16); } @@ -2965,7 +3082,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2014STDMode) { + else if (presetNum == MODELS_GE2014STDMode) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3042,7 +3160,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2014STDMode_80) { + else if (presetNum == MODELS_GE2014STDMode_80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3115,7 +3234,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2014) { + else if (presetNum == MODELS_GE2014) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3195,7 +3315,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2014_80) { + else if (presetNum == MODELS_GE2014_80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3275,7 +3396,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_GE2014_80DR) { + else if (presetNum == MODELS_GE2014_80DR) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3357,7 +3479,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[1].followedByHeatSource = &setOfSources[2]; } // PRESET USING GE2014 DATA - else if (presetNum == MODELS_BWC2020_65) { + else if (presetNum == MODELS_BWC2020_65) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3435,24 +3558,29 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[1].backupHeatSource = &setOfSources[2]; } // If Rheem Premium - else if (MODELS_Rheem2020Prem40 <= presetNum && presetNum <= MODELS_Rheem2020Prem80) { + else if (MODELS_Rheem2020Prem40 <= presetNum && presetNum <= MODELS_Rheem2020Prem80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_Rheem2020Prem40) { + if (presetNum == MODELS_Rheem2020Prem40) + { tankVolume_L = GAL_TO_L(36.1); tankUA_kJperHrC = 9.5; } - else if (presetNum == MODELS_Rheem2020Prem50) { + else if (presetNum == MODELS_Rheem2020Prem50) + { tankVolume_L = GAL_TO_L(45.1); tankUA_kJperHrC = 8.55; } - else if (presetNum == MODELS_Rheem2020Prem65) { + else if (presetNum == MODELS_Rheem2020Prem65) + { tankVolume_L = GAL_TO_L(58.5); tankUA_kJperHrC = 10.64; } - else if (presetNum == MODELS_Rheem2020Prem80) { + else if (presetNum == MODELS_Rheem2020Prem80) + { tankVolume_L = GAL_TO_L(72.0); tankUA_kJperHrC = 10.83; } @@ -3528,24 +3656,29 @@ int HPWH::HPWHinit_presets(MODELS presetNum) } // If Rheem Build - else if (MODELS_Rheem2020Build40 <= presetNum && presetNum <= MODELS_Rheem2020Build80) { + else if (MODELS_Rheem2020Build40 <= presetNum && presetNum <= MODELS_Rheem2020Build80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_Rheem2020Build40) { + if (presetNum == MODELS_Rheem2020Build40) + { tankVolume_L = GAL_TO_L(36.1); tankUA_kJperHrC = 9.5; } - else if (presetNum == MODELS_Rheem2020Build50) { + else if (presetNum == MODELS_Rheem2020Build50) + { tankVolume_L = GAL_TO_L(45.1); tankUA_kJperHrC = 8.55; } - else if (presetNum == MODELS_Rheem2020Build65) { + else if (presetNum == MODELS_Rheem2020Build65) + { tankVolume_L = GAL_TO_L(58.5); tankUA_kJperHrC = 10.64; } - else if (presetNum == MODELS_Rheem2020Build80) { + else if (presetNum == MODELS_Rheem2020Build80) + { tankVolume_L = GAL_TO_L(72.0); tankUA_kJperHrC = 10.83; } @@ -3619,26 +3752,31 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } - else if (MODELS_RheemPlugInShared40 <= presetNum && presetNum <= MODELS_RheemPlugInShared80) { + else if (MODELS_RheemPlugInShared40 <= presetNum && presetNum <= MODELS_RheemPlugInShared80) + { numNodes = 12; tankTemps_C = new double[numNodes]; - if (presetNum == MODELS_RheemPlugInShared40) { + if (presetNum == MODELS_RheemPlugInShared40) + { tankVolume_L = GAL_TO_L(36.0); tankUA_kJperHrC = 9.5; setpoint_C = F_TO_C(140.0); } - else if (presetNum == MODELS_RheemPlugInShared50) { + else if (presetNum == MODELS_RheemPlugInShared50) + { tankVolume_L = GAL_TO_L(45.0); tankUA_kJperHrC = 8.55; setpoint_C = F_TO_C(140.0); } - else if (presetNum == MODELS_RheemPlugInShared65) { + else if (presetNum == MODELS_RheemPlugInShared65) + { tankVolume_L = GAL_TO_L(58.5); tankUA_kJperHrC = 10.64; setpoint_C = F_TO_C(127.0); } - else if (presetNum == MODELS_RheemPlugInShared80) { + else if (presetNum == MODELS_RheemPlugInShared80) + { tankVolume_L = GAL_TO_L(72.0); tankUA_kJperHrC = 10.83; setpoint_C = F_TO_C(127.0); @@ -3686,15 +3824,18 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0] = compressor; } else if (presetNum == MODELS_RheemPlugInDedicated40 || - presetNum == MODELS_RheemPlugInDedicated50) { + presetNum == MODELS_RheemPlugInDedicated50) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_RheemPlugInDedicated40) { + if (presetNum == MODELS_RheemPlugInDedicated40) + { tankVolume_L = GAL_TO_L(36); tankUA_kJperHrC = 5.5; } - else if (presetNum == MODELS_RheemPlugInDedicated50) { + else if (presetNum == MODELS_RheemPlugInDedicated50) + { tankVolume_L = GAL_TO_L(45); tankUA_kJperHrC = 6.33; } @@ -3740,7 +3881,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // set everything in its places setOfSources[0] = compressor; } - else if (presetNum == MODELS_RheemHB50) { + else if (presetNum == MODELS_RheemHB50) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3819,7 +3961,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_Stiebel220E) { + else if (presetNum == MODELS_Stiebel220E) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127); @@ -3879,7 +4022,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // you don't get the right pointers setOfSources[0].backupHeatSource = &setOfSources[1]; } - else if (presetNum == MODELS_Generic1) { + else if (presetNum == MODELS_Generic1) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -3951,7 +4095,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_Generic2) { + else if (presetNum == MODELS_Generic2) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -4027,7 +4172,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_Generic3) { + else if (presetNum == MODELS_Generic3) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -4105,7 +4251,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_UEF2generic) { + else if (presetNum == MODELS_UEF2generic) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); @@ -4181,29 +4328,36 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].followedByHeatSource = &setOfSources[1]; setOfSources[1].followedByHeatSource = &setOfSources[2]; } - else if (MODELS_AWHSTier3Generic40 <= presetNum && presetNum <= MODELS_AWHSTier3Generic80) { + else if (MODELS_AWHSTier3Generic40 <= presetNum && presetNum <= MODELS_AWHSTier3Generic80) + { numNodes = 12; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(127.0); - if (presetNum == MODELS_AWHSTier3Generic40) { + if (presetNum == MODELS_AWHSTier3Generic40) + { tankVolume_L = GAL_TO_L(36.1); tankUA_kJperHrC = 5; } - else if (presetNum == MODELS_AWHSTier3Generic50) { + else if (presetNum == MODELS_AWHSTier3Generic50) + { tankVolume_L = GAL_TO_L(45); tankUA_kJperHrC = 6.5; } - else if (presetNum == MODELS_AWHSTier3Generic65) { + else if (presetNum == MODELS_AWHSTier3Generic65) + { tankVolume_L = GAL_TO_L(64); tankUA_kJperHrC = 7.6; } - else if (presetNum == MODELS_AWHSTier3Generic80) { + else if (presetNum == MODELS_AWHSTier3Generic80) + { tankVolume_L = GAL_TO_L(75.4); tankUA_kJperHrC = 10.; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect model specification. \n"); } return HPWH_ABORT; @@ -4281,7 +4435,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[1].followedByHeatSource = &setOfSources[2]; } // If a the model is the TamOMatic, HotTam, Generic... This model is scalable. - else if (presetNum == MODELS_TamScalable_SP) { + else if (presetNum == MODELS_TamScalable_SP) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -4386,7 +4541,8 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } - else if (presetNum == MODELS_Scalable_MP) { + else if (presetNum == MODELS_Scalable_MP) + { numNodes = 24; tankTemps_C = new double[numNodes]; setpoint_C = F_TO_C(135.0); @@ -4471,8 +4627,10 @@ int HPWH::HPWHinit_presets(MODELS presetNum) setOfSources[0].companionHeatSource = &setOfSources[2]; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have tried to select a preset model which does not exist. \n"); } return HPWH_ABORT; @@ -4489,20 +4647,25 @@ int HPWH::HPWHinit_presets(MODELS presetNum) // calculate oft-used derived values calcDerivedValues(); - if (checkInputs() == HPWH_ABORT) { + if (checkInputs() == HPWH_ABORT) + { return HPWH_ABORT; } isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isOn) + { isHeating = true; } setOfSources[i].sortPerformanceMap(); } - if (hpwhVerbosity >= VRB_emetic) { - for (int i = 0; i < numHeatSources; i++) { + if (hpwhVerbosity >= VRB_emetic) + { + for (int i = 0; i < numHeatSources; i++) + { msg("heat source %d: %p \n", i, &setOfSources[i]); } msg("\n\n"); diff --git a/test/main.cc b/test/main.cc index 79a29458..6fc87fee 100644 --- a/test/main.cc +++ b/test/main.cc @@ -82,26 +82,30 @@ int main(int argc, char* argv[]) cout << "Testing HPWHsim version " << HPWH::getVersion() << endl; // Obvious wrong number of command line arguments - if ((argc > 6)) { + if ((argc > 6)) + { cout << "Invalid input. This program takes FOUR arguments: model specification type (ie. " "Preset or File), model specification (ie. Sanden80), test name (ie. test50) and " "output directory\n"; exit(1); } // Help message - if (argc > 1) { + if (argc > 1) + { input1 = argv[1]; input2 = argv[2]; input3 = argv[3]; outputDirectory = argv[4]; } - else { + else + { input1 = "asdf"; // Makes the next conditional not crash... a little clumsy but whatever input2 = "def"; input3 = "ghi"; outputDirectory = "."; } - if (argc < 5 || (argc > 6) || (input1 == "?") || (input1 == "help")) { + if (argc < 5 || (argc > 6) || (input1 == "?") || (input1 == "help")) + { cout << "Standard usage: \"hpwhTestTool.x [model spec type Preset/File] [model spec Name] " "[testName] [airtemp override F (optional)]\"\n"; cout << "All input files should be located in the test directory, with these names:\n"; @@ -111,11 +115,13 @@ int main(int argc, char* argv[]) exit(1); } - if (argc == 6) { + if (argc == 6) + { airTemp = std::stoi(argv[5]); HPWH_doTempDepress = true; } - else { + else + { airTemp = 0; HPWH_doTempDepress = false; } @@ -125,26 +131,31 @@ int main(int argc, char* argv[]) // Parse the model newSetpoint = 0; - if (input1 == "Preset") { + if (input1 == "Preset") + { inputFile = ""; - if (getHPWHObject(hpwh, input2) == HPWH::HPWH_ABORT) { + if (getHPWHObject(hpwh, input2) == 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) { + if (model == HPWH::MODELS_Sanden80 || model == HPWH::MODELS_Sanden40) + { newSetpoint = (149 - 32) / 1.8; } } - else if (input1 == "File") { + else if (input1 == "File") + { inputFile = input2 + ".txt"; if (hpwh.HPWHinit_file(inputFile) != 0) exit(1); } - else { + else + { cout << "Invalid argument, received '" << input1 << "', expected 'Preset' or 'File'.\n"; exit(1); } @@ -160,7 +171,8 @@ int main(int argc, char* argv[]) // Read the test control file fileToOpen = testDirectory + "/" + "testInfo.txt"; controlFile.open(fileToOpen.c_str()); - if (!controlFile.is_open()) { + if (!controlFile.is_open()) + { cout << "Could not open control file " << fileToOpen << "\n"; exit(1); } @@ -175,37 +187,48 @@ int main(int argc, char* argv[]) useSoC = false; cout << "Running: " << input2 << ", " << input1 << ", " << input3 << endl; - while (controlFile >> var1 >> testVal) { - if (var1 == "setpoint") { // If a setpoint was specified then override the default + while (controlFile >> var1 >> testVal) + { + if (var1 == "setpoint") + { // If a setpoint was specified then override the default newSetpoint = testVal; } - else if (var1 == "length_of_test") { + else if (var1 == "length_of_test") + { minutesToRun = (int)testVal; } - else if (var1 == "doInversionMixing") { + else if (var1 == "doInversionMixing") + { doInvMix = (testVal > 0.0) ? 1 : 0; } - else if (var1 == "doConduction") { + else if (var1 == "doConduction") + { doCondu = (testVal > 0.0) ? 1 : 0; } - else if (var1 == "inletH") { + else if (var1 == "inletH") + { inletH = testVal; } - else if (var1 == "tanksize") { + else if (var1 == "tanksize") + { newTankSize = testVal; } - else if (var1 == "tot_limit") { + else if (var1 == "tot_limit") + { tot_limit = testVal; } - else if (var1 == "useSoC") { + else if (var1 == "useSoC") + { useSoC = (bool)testVal; } - else { + else + { cout << var1 << " in testInfo.txt is an unrecogized key.\n"; } } - if (minutesToRun == 0) { + if (minutesToRun == 0) + { cout << "Error, must record length_of_test in testInfo.txt file\n"; exit(1); } @@ -220,54 +243,69 @@ int main(int argc, char* argv[]) scheduleNames.push_back("setpoint"); scheduleNames.push_back("SoC"); - for (i = 0; (unsigned)i < scheduleNames.size(); i++) { + 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") { + if (outputCode != 0) + { + if (scheduleNames[i] != "setpoint" && scheduleNames[i] != "SoC") + { cout << "readSchedule returns an error on " << scheduleNames[i] << " schedule!\n"; exit(1); } - else { + else + { outputCode = 0; } } } - if (doInvMix == 0) { + if (doInvMix == 0) + { outputCode += hpwh.setDoInversionMixing(false); } - if (doCondu == 0) { + if (doCondu == 0) + { outputCode += hpwh.setDoConduction(false); } - if (newSetpoint > 0) { - if (!allSchedules[5].empty()) { + if (newSetpoint > 0) + { + if (!allSchedules[5].empty()) + { hpwh.setSetpoint(allSchedules[5][0]); // expect this to fail sometimes hpwh.resetTankToSetpoint(); } - else { + else + { hpwh.setSetpoint(newSetpoint); hpwh.resetTankToSetpoint(); } } - if (inletH > 0) { + if (inletH > 0) + { outputCode += hpwh.setInletByFraction(inletH); } - if (newTankSize > 0) { + if (newTankSize > 0) + { hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL); } - if (tot_limit > 0) { + if (tot_limit > 0) + { outputCode += hpwh.setTimerLimitTOT(tot_limit); } - if (useSoC) { - if (allSchedules[6].empty()) { + 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 (outputCode != 0) + { cout << "Control file testInfo.txt has unsettable specifics in it. \n"; exit(1); } @@ -275,27 +313,33 @@ int main(int argc, char* argv[]) // ----------------------Open the Output Files and Print the Header---------------------------- // // - if (minutesToRun > 500000.) { + if (minutesToRun > 500000.) + { fileToOpen = outputDirectory + "/DHW_YRLY.csv"; - if (fopen_s(&yearOutFile, fileToOpen.c_str(), "a+") != 0) { + if (fopen_s(&yearOutFile, fileToOpen.c_str(), "a+") != 0) + { cout << "Could not open output file " << fileToOpen << "\n"; exit(1); } } - else { + else + { fileToOpen = outputDirectory + "/" + input3 + "_" + input1 + "_" + input2 + ".csv"; - if (fopen_s(&outputFile, fileToOpen.c_str(), "w+") != 0) { + 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()) { + if (hpwh.isCompressoExternalMultipass()) + { header += strHeadMP; } - if (useSoC) { + if (useSoC) + { header += strHeadSoC; } hpwh.WriteCSVHeading(outputFile, header.c_str(), nTestTCouples, 0); @@ -307,16 +351,19 @@ int main(int argc, char* argv[]) std::vector nodeExtraHeat_W; std::vector* vectptr = NULL; // Loop over the minutes in the test - for (i = 0; i < minutesToRun; i++) { + for (i = 0; i < minutesToRun; i++) + { #if defined _DEBUG && 0 cout << "Now on minute: " << i << "\n"; #endif - if (HPWH_doTempDepress) { + if (HPWH_doTempDepress) + { airTemp2 = F_TO_C(airTemp); } - else { + else + { airTemp2 = allSchedules[2][i]; } @@ -326,22 +373,27 @@ int main(int argc, char* argv[]) drStatus = static_cast(int(allSchedules[4][i])); // Change setpoint if there is a setpoint schedule. - if (!allSchedules[5].empty() && !hpwh.isSetpointFixed()) { + 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) { + 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.) { + if (hpwh.getHPWHModel() >= 210 && minutesToRun > 500000.) + { // Do a simple mix down of the draw for the cold water temperature - if (hpwh.getSetpoint() <= 125.) { + if (hpwh.getSetpoint() <= 125.) + { allSchedules[1][i] *= (125. - allSchedules[0][i]) / (hpwh.getTankNodeTemp(hpwh.getNumNodes() - 1, HPWH::UNITS_F) - allSchedules[0][i]); @@ -360,7 +412,8 @@ int main(int argc, char* argv[]) // Check energy balance accounting. double hpwhElect = 0; - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) { + for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) + { hpwhElect += hpwh.getNthHeatSourceEnergyInput(iHS, HPWH::UNITS_KJ); } double hpwhqHW = GAL_TO_L(allSchedules[1][i]) * @@ -376,14 +429,17 @@ int main(int argc, char* argv[]) - deltaHC; // change in tank stored energy double fBal = fabs(qBal) / std::max(tankHCStart, 1.); - if (fBal > EBALTHRESHOLD) { + if (fBal > EBALTHRESHOLD) + { cout << "WARNING: On minute " << i << " HPWH has an energy balance error " << qBal << "kJ, " << 100 * fBal << "%" << "\n"; } // Check timing - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) { - if (hpwh.getNthHeatSourceRunTime(iHS) > 1) { + 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"; @@ -391,11 +447,13 @@ int main(int argc, char* argv[]) } } // Check flow for external MP - if (hpwh.isCompressoExternalMultipass()) { + 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 (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"; @@ -403,9 +461,11 @@ int main(int argc, char* argv[]) } } // Recording - if (minutesToRun < 500000.) { + if (minutesToRun < 500000.) + { // Copy current status into the output file - if (HPWH_doTempDepress) { + if (HPWH_doTempDepress) + { airTemp2 = hpwh.getLocationTemp_C(); } strPreamble = std::to_string(i) + ", " + std::to_string(airTemp2) + ", " + @@ -413,43 +473,51 @@ int main(int argc, char* argv[]) std::to_string(allSchedules[0][i]) + ", " + std::to_string(allSchedules[1][i]) + ", "; // Add some more outputs for mp tests - if (hpwh.isCompressoExternalMultipass()) { + if (hpwh.isCompressoExternalMultipass()) + { strPreamble += std::to_string(hpwh.getCondenserWaterInletTemp()) + ", " + std::to_string(hpwh.getCondenserWaterOutletTemp()) + ", " + std::to_string(hpwh.getExternalVolumeHeated(HPWH::UNITS_GAL)) + ", "; } - if (useSoC) { + if (useSoC) + { strPreamble += std::to_string(allSchedules[6][i]) + ", " + std::to_string(hpwh.getSoCFraction()) + ", "; } hpwh.WriteCSVRow(outputFile, strPreamble.c_str(), nTestTCouples, 0); } - else { - for (int iHS = 0; iHS < hpwh.getNumHeatSources(); iHS++) { + 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.) { + 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++) { + 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++) { + 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 { + else + { fclose(outputFile); } controlFile.close(); @@ -468,14 +536,16 @@ int readSchedule(schedule& scheduleArray, string scheduleFileName, long minutesO // open the schedule file provided cout << "Opening " << scheduleFileName << '\n'; - if (!inputFile.is_open()) { + if (!inputFile.is_open()) + { return 1; } inputFile >> snippet >> valTmp; // cout << "snippet " << snippet << " valTmp"<< valTmp<<'\n'; - if (snippet != "default") { + if (snippet != "default") + { cout << "First line of " << scheduleFileName << " must specify default\n"; return 1; } @@ -491,25 +561,31 @@ int readSchedule(schedule& scheduleArray, string scheduleFileName, long minutesO 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 + 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) { + while (inputFile >> minuteHrTmp >> c >> valTmp) + { - if (minuteHrTmp >= (int)scheduleArray.size()) { + 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) { + if (!hourInput) + { scheduleArray[minuteHrTmp] = valTmp; } - else if (hourInput) { - for (int j = minuteHrTmp * 60; j < (minuteHrTmp + 1) * 60; j++) { + 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"; } diff --git a/test/testCompressorFcts.cc b/test/testCompressorFcts.cc index a0d3d487..c3aff1e1 100644 --- a/test/testCompressorFcts.cc +++ b/test/testCompressorFcts.cc @@ -138,7 +138,8 @@ int main(int, char*) 35., -13.}; // deg F - for (int i = 0; i < length; i++) { + for (int i = 0; i < length; i++) + { testHasACompressor(models[i], hasComp[i]); testGetCompCoilConfig(models[i], coilConfig[i]); testIsCompressorMultipass(models[i], heatCycle[i]); diff --git a/test/testHeatingLogics.cc b/test/testHeatingLogics.cc index 55c477e3..f5fde3a1 100644 --- a/test/testHeatingLogics.cc +++ b/test/testHeatingLogics.cc @@ -55,7 +55,8 @@ int main(int, char*) double tempsForSetSoC[5][3] = { {49, 99, 125}, {65, 110, 129}, {32, 120, 121}, {32, 33, 121}, {80, 81, 132.5}}; - for (string hpwhStr : hasHighShuttOffVectSP) { + for (string hpwhStr : hasHighShuttOffVectSP) + { testHasEnteringWaterShutOff(hpwhStr); testSetEnteringWaterShuffOffOutOfBoundsIndex(hpwhStr); testSetEnteringWaterShuffOffDeadbandToSmall(hpwhStr); @@ -63,24 +64,28 @@ int main(int, char*) testSetEnteringWaterHighTempShutOffRelative(hpwhStr); testChangeToStateofChargeControlled(hpwhStr); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { testSetStateOfCharge( hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); } } - for (string hpwhStr : noHighShuttOffVectMPExternal) { + for (string hpwhStr : noHighShuttOffVectMPExternal) + { testDoesNotHaveEnteringWaterShutOff(hpwhStr); testCanNotSetEnteringWaterShutOff(hpwhStr); testChangeToStateofChargeControlled(hpwhStr); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { testSetStateOfCharge( hpwhStr, tempsForSetSoC[i][0], tempsForSetSoC[i][1], tempsForSetSoC[i][2]); } } - for (string hpwhStr : noHighShuttOffVectIntegrated) { + for (string hpwhStr : noHighShuttOffVectIntegrated) + { testDoesNotHaveEnteringWaterShutOff(hpwhStr); testCanNotSetEnteringWaterShutOff(hpwhStr); } @@ -221,10 +226,12 @@ void testChangeToStateofChargeControlled(string& input) getHPWHObject(hpwh, input); const bool originalHasHighTempShutOff = hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex()); - if (!hpwh.isSetpointFixed()) { + if (!hpwh.isSetpointFixed()) + { double temp; string tempStr; - if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { + if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) + { return; // Numbers don't aline for this type } hpwh.setSetpoint(setpointT_C); @@ -242,7 +249,8 @@ void testChangeToStateofChargeControlled(string& input) originalHasHighTempShutOff); // Test we can change the SoC and run a step and check we're heating - if (hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex())) { + if (hpwh.hasEnteringWaterHighTempShutOff(hpwh.getCompressorIndex())) + { ASSERTTRUE(hpwh.setEnteringWaterHighTempShutOff( setpointT_C - HPWH::MINSINGLEPASSLIFT, true, hpwh.getCompressorIndex()) == 0); // Force to ignore this part. @@ -275,10 +283,12 @@ void testSetStateOfCharge(string& input, double coldWater_F, double minTUse_F, d const double setpointT_C = F_TO_C(149.); getHPWHObject(hpwh, input); - if (!hpwh.isSetpointFixed()) { + if (!hpwh.isSetpointFixed()) + { double temp; string tempStr; - if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) { + if (!hpwh.isNewSetpointPossible(setpointT_C, temp, tempStr)) + { return; // Numbers don't aline for this type } hpwh.setSetpoint(setpointT_C); diff --git a/test/testPerformanceMaps.cc b/test/testPerformanceMaps.cc index d8eec1d0..f43a9c1b 100644 --- a/test/testPerformanceMaps.cc +++ b/test/testPerformanceMaps.cc @@ -14,7 +14,8 @@ using std::string; const double tInOffsetQAHV_dF = 10.; const double tOutOffsetQAHV_dF = 15.; -struct performancePointMP { +struct performancePointMP +{ double tairF; double tinF; double outputBTUH; @@ -26,7 +27,8 @@ double getCapacityMP_F_KW(HPWH& hpwh, performancePointMP& point) point.tairF, point.tinF, point.tinF, HPWH::UNITS_KW, HPWH::UNITS_F); } -struct performancePointSP { +struct performancePointSP +{ double tairF; double toutF; double tinF; diff --git a/test/testResistanceFcts.cc b/test/testResistanceFcts.cc index c5373ba0..480a32d6 100644 --- a/test/testResistanceFcts.cc +++ b/test/testResistanceFcts.cc @@ -182,7 +182,8 @@ void testCommercialTankErrorsWithTopElement() HPWH::HPWH_ABORT); } -struct InsulationPoint { +struct InsulationPoint +{ double volume_L; double rValue_IP; double expectedUA_SI; diff --git a/test/testScaleHPWH.cc b/test/testScaleHPWH.cc index 4e956316..f199c633 100644 --- a/test/testScaleHPWH.cc +++ b/test/testScaleHPWH.cc @@ -14,18 +14,21 @@ using std::cout; using std::string; -struct performance { +struct performance +{ double input, output, cop; }; 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 + if (hpwh.isCompressorMultipass()) + { // Multipass capacity looks at the average of the + // temperature of the lift hpwh.setSetpoint((waterTempC + setpointC) / 2.); } - else { + else + { hpwh.setSetpoint(waterTempC); } hpwh.resetTankToSetpoint(); // Force tank cold diff --git a/test/testTankSizeFixed.cc b/test/testTankSizeFixed.cc index 7fe2d923..af286fcc 100644 --- a/test/testTankSizeFixed.cc +++ b/test/testTankSizeFixed.cc @@ -23,15 +23,18 @@ int main(int argc, char* argv[]) string input; // = "AOSmithCAHP120"; - if (argc != 2) { + if (argc != 2) + { cout << "Invalid input. This program takes One arguments: preset model specification (ie. " "Sanden80). Recieved input: \n"; - for (int ii = 0; ii < argc; ii++) { + for (int ii = 0; ii < argc; ii++) + { cout << argv[ii] << " "; } exit(1); } - else { + else + { input = argv[1]; } @@ -59,27 +62,34 @@ int testIsTankSizeFixed(HPWH::MODELS model) // change the tank size int result = hpwh.setTankSize(newTankSize); - if (result != 0 && result != HPWH::HPWH_ABORT) { + if (result != 0 && result != HPWH::HPWH_ABORT) + { cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; return 1; } - if (hpwh.isTankSizeFixed()) { // better not have change! - if (result == 0) { + if (hpwh.isTankSizeFixed()) + { // better not have change! + if (result == 0) + { cout << "Error, setTankSize() returned 0 when should be HPWH_ABORT\n"; return 1; } - if (originalTankSize != hpwh.getTankSize()) { + if (originalTankSize != hpwh.getTankSize()) + { cout << "Error, the tank size has changed when isTankSizeFixed is true\n"; return 1; } } - else { // it better have changed - if (result != 0) { + else + { // it better have changed + if (result != 0) + { cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; return 1; } - if (newTankSize != hpwh.getTankSize()) { + if (newTankSize != hpwh.getTankSize()) + { cout << "Error, the tank size hasn't changed to the new tank size when it should have. " "New Size: " << newTankSize << ". Returned Value: " << hpwh.getTankSize() << "\n"; @@ -102,17 +112,20 @@ int testForceChangeTankSize(HPWH::MODELS model) // change the tank size int result = hpwh.setTankSize(newTankSize, HPWH::UNITS_GAL, true); - if (result != 0 && result != HPWH::HPWH_ABORT) { + if (result != 0 && result != HPWH::HPWH_ABORT) + { cout << "Error, setTankSize() returned an invalid result: " << result << "\n"; return 1; } // it better have changed - if (result != 0) { + if (result != 0) + { cout << "Error, setTankSize() returned HPWH_ABORT when it should be 0\n"; return 1; } - if (newTankSize != hpwh.getTankSize(HPWH::UNITS_GAL)) { + if (newTankSize != hpwh.getTankSize(HPWH::UNITS_GAL)) + { cout << "Error, the tank size hasn't changed to the new tank size when it should have. New " "Size: " << newTankSize << ". Returned Value: " << hpwh.getTankSize(HPWH::UNITS_GAL) << "\n"; diff --git a/test/testUtilityFcts.cc b/test/testUtilityFcts.cc index acee23f7..3a064b5f 100644 --- a/test/testUtilityFcts.cc +++ b/test/testUtilityFcts.cc @@ -23,12 +23,14 @@ using std::string; #define KWH_TO_BTU(KW) (KW * 3412.14) #define ASSERTTRUE(input, ...) \ - if (!(input)) { \ + if (!(input)) \ + { \ cout << "Assertation failed at " << __FILE__ << ", line: " << __LINE__ << ".\n"; \ exit(1); \ } #define ASSERTFALSE(input, ...) \ - if ((input)) { \ + if ((input)) \ + { \ cout << "Assertation failed at " << __FILE__ << ", line: " << __LINE__ << ".\n"; \ exit(1); \ } @@ -51,260 +53,343 @@ HPWH::MODELS mapStringToPreset(string modelName) HPWH::MODELS hpwhModel; - if (modelName == "Voltex60" || modelName == "AOSmithPHPT60") { + if (modelName == "Voltex60" || modelName == "AOSmithPHPT60") + { hpwhModel = HPWH::MODELS_AOSmithPHPT60; } - else if (modelName == "Voltex80" || modelName == "AOSmith80") { + else if (modelName == "Voltex80" || modelName == "AOSmith80") + { hpwhModel = HPWH::MODELS_AOSmithPHPT80; } - else if (modelName == "GEred" || modelName == "GE") { + else if (modelName == "GEred" || modelName == "GE") + { hpwhModel = HPWH::MODELS_GE2012; } - else if (modelName == "SandenGAU" || modelName == "Sanden80" || modelName == "SandenGen3") { + else if (modelName == "SandenGAU" || modelName == "Sanden80" || modelName == "SandenGen3") + { hpwhModel = HPWH::MODELS_Sanden80; } - else if (modelName == "Sanden120") { + else if (modelName == "Sanden120") + { hpwhModel = HPWH::MODELS_Sanden120; } - else if (modelName == "SandenGES" || modelName == "Sanden40") { + else if (modelName == "SandenGES" || modelName == "Sanden40") + { hpwhModel = HPWH::MODELS_Sanden40; } - else if (modelName == "AOSmithHPTU50") { + else if (modelName == "AOSmithHPTU50") + { hpwhModel = HPWH::MODELS_AOSmithHPTU50; } - else if (modelName == "AOSmithHPTU66") { + else if (modelName == "AOSmithHPTU66") + { hpwhModel = HPWH::MODELS_AOSmithHPTU66; } - else if (modelName == "AOSmithHPTU80") { + else if (modelName == "AOSmithHPTU80") + { hpwhModel = HPWH::MODELS_AOSmithHPTU80; } - else if (modelName == "AOSmithHPTS50") { + else if (modelName == "AOSmithHPTS50") + { hpwhModel = HPWH::MODELS_AOSmithHPTS50; } - else if (modelName == "AOSmithHPTS66") { + else if (modelName == "AOSmithHPTS66") + { hpwhModel = HPWH::MODELS_AOSmithHPTS66; } - else if (modelName == "AOSmithHPTS80") { + else if (modelName == "AOSmithHPTS80") + { hpwhModel = HPWH::MODELS_AOSmithHPTS80; } - else if (modelName == "AOSmithHPTU80DR") { + else if (modelName == "AOSmithHPTU80DR") + { hpwhModel = HPWH::MODELS_AOSmithHPTU80_DR; } - else if (modelName == "GE502014STDMode" || modelName == "GE2014STDMode") { + else if (modelName == "GE502014STDMode" || modelName == "GE2014STDMode") + { hpwhModel = HPWH::MODELS_GE2014STDMode; } - else if (modelName == "GE502014" || modelName == "GE2014") { + else if (modelName == "GE502014" || modelName == "GE2014") + { hpwhModel = HPWH::MODELS_GE2014; } - else if (modelName == "GE802014") { + else if (modelName == "GE802014") + { hpwhModel = HPWH::MODELS_GE2014_80DR; } - else if (modelName == "RheemHB50") { + else if (modelName == "RheemHB50") + { hpwhModel = HPWH::MODELS_RheemHB50; } - else if (modelName == "Stiebel220e" || modelName == "Stiebel220E") { + else if (modelName == "Stiebel220e" || modelName == "Stiebel220E") + { hpwhModel = HPWH::MODELS_Stiebel220E; } - else if (modelName == "Generic1") { + else if (modelName == "Generic1") + { hpwhModel = HPWH::MODELS_Generic1; } - else if (modelName == "Generic2") { + else if (modelName == "Generic2") + { hpwhModel = HPWH::MODELS_Generic2; } - else if (modelName == "Generic3") { + else if (modelName == "Generic3") + { hpwhModel = HPWH::MODELS_Generic3; } - else if (modelName == "custom") { + else if (modelName == "custom") + { hpwhModel = HPWH::MODELS_CustomFile; } - else if (modelName == "restankRealistic") { + else if (modelName == "restankRealistic") + { hpwhModel = HPWH::MODELS_restankRealistic; } - else if (modelName == "StorageTank") { + else if (modelName == "StorageTank") + { hpwhModel = HPWH::MODELS_StorageTank; } - else if (modelName == "BWC2020_65") { + else if (modelName == "BWC2020_65") + { hpwhModel = HPWH::MODELS_BWC2020_65; } // New Rheems - else if (modelName == "Rheem2020Prem40") { + else if (modelName == "Rheem2020Prem40") + { hpwhModel = HPWH::MODELS_Rheem2020Prem40; } - else if (modelName == "Rheem2020Prem50") { + else if (modelName == "Rheem2020Prem50") + { hpwhModel = HPWH::MODELS_Rheem2020Prem50; } - else if (modelName == "Rheem2020Prem65") { + else if (modelName == "Rheem2020Prem65") + { hpwhModel = HPWH::MODELS_Rheem2020Prem65; } - else if (modelName == "Rheem2020Prem80") { + else if (modelName == "Rheem2020Prem80") + { hpwhModel = HPWH::MODELS_Rheem2020Prem80; } - else if (modelName == "Rheem2020Build40") { + else if (modelName == "Rheem2020Build40") + { hpwhModel = HPWH::MODELS_Rheem2020Build40; } - else if (modelName == "Rheem2020Build50") { + else if (modelName == "Rheem2020Build50") + { hpwhModel = HPWH::MODELS_Rheem2020Build50; } - else if (modelName == "Rheem2020Build65") { + else if (modelName == "Rheem2020Build65") + { hpwhModel = HPWH::MODELS_Rheem2020Build65; } - else if (modelName == "Rheem2020Build80") { + else if (modelName == "Rheem2020Build80") + { hpwhModel = HPWH::MODELS_Rheem2020Build80; } - else if (modelName == "RheemPlugInDedicated40") { + else if (modelName == "RheemPlugInDedicated40") + { hpwhModel = HPWH::MODELS_RheemPlugInDedicated40; } - else if (modelName == "RheemPlugInDedicated50") { + else if (modelName == "RheemPlugInDedicated50") + { hpwhModel = HPWH::MODELS_RheemPlugInDedicated50; } - else if (modelName == "RheemPlugInShared40") { + else if (modelName == "RheemPlugInShared40") + { hpwhModel = HPWH::MODELS_RheemPlugInShared40; } - else if (modelName == "RheemPlugInShared50") { + else if (modelName == "RheemPlugInShared50") + { hpwhModel = HPWH::MODELS_RheemPlugInShared50; } - else if (modelName == "RheemPlugInShared65") { + else if (modelName == "RheemPlugInShared65") + { hpwhModel = HPWH::MODELS_RheemPlugInShared65; } - else if (modelName == "RheemPlugInShared80") { + else if (modelName == "RheemPlugInShared80") + { hpwhModel = HPWH::MODELS_RheemPlugInShared80; } // Large HPWH's - else if (modelName == "AOSmithCAHP120") { + else if (modelName == "AOSmithCAHP120") + { hpwhModel = HPWH::MODELS_AOSmithCAHP120; } - else if (modelName == "ColmacCxV_5_SP") { + else if (modelName == "ColmacCxV_5_SP") + { hpwhModel = HPWH::MODELS_ColmacCxV_5_SP; } - else if (modelName == "ColmacCxA_10_SP") { + else if (modelName == "ColmacCxA_10_SP") + { hpwhModel = HPWH::MODELS_ColmacCxA_10_SP; } - else if (modelName == "ColmacCxA_15_SP") { + else if (modelName == "ColmacCxA_15_SP") + { hpwhModel = HPWH::MODELS_ColmacCxA_15_SP; } - else if (modelName == "ColmacCxA_20_SP") { + else if (modelName == "ColmacCxA_20_SP") + { hpwhModel = HPWH::MODELS_ColmacCxA_20_SP; } - else if (modelName == "ColmacCxA_25_SP") { + else if (modelName == "ColmacCxA_25_SP") + { hpwhModel = HPWH::MODELS_ColmacCxA_25_SP; } - else if (modelName == "ColmacCxA_30_SP") { + else if (modelName == "ColmacCxA_30_SP") + { hpwhModel = HPWH::MODELS_ColmacCxA_30_SP; } - else if (modelName == "ColmacCxV_5_MP") { + else if (modelName == "ColmacCxV_5_MP") + { hpwhModel = HPWH::MODELS_ColmacCxV_5_MP; } - else if (modelName == "ColmacCxA_10_MP") { + else if (modelName == "ColmacCxA_10_MP") + { hpwhModel = HPWH::MODELS_ColmacCxA_10_MP; } - else if (modelName == "ColmacCxA_15_MP") { + else if (modelName == "ColmacCxA_15_MP") + { hpwhModel = HPWH::MODELS_ColmacCxA_15_MP; } - else if (modelName == "ColmacCxA_20_MP") { + else if (modelName == "ColmacCxA_20_MP") + { hpwhModel = HPWH::MODELS_ColmacCxA_20_MP; } - else if (modelName == "ColmacCxA_25_MP") { + else if (modelName == "ColmacCxA_25_MP") + { hpwhModel = HPWH::MODELS_ColmacCxA_25_MP; } - else if (modelName == "ColmacCxA_30_MP") { + else if (modelName == "ColmacCxA_30_MP") + { hpwhModel = HPWH::MODELS_ColmacCxA_30_MP; } - else if (modelName == "RheemHPHD60") { + else if (modelName == "RheemHPHD60") + { hpwhModel = HPWH::MODELS_RHEEM_HPHD60VNU_201_MP; } - else if (modelName == "RheemHPHD135") { + else if (modelName == "RheemHPHD135") + { hpwhModel = HPWH::MODELS_RHEEM_HPHD135VNU_483_MP; } // Nyle Single pass models - else if (modelName == "NyleC25A_SP") { + else if (modelName == "NyleC25A_SP") + { hpwhModel = HPWH::MODELS_NyleC25A_SP; } - else if (modelName == "NyleC60A_SP") { + else if (modelName == "NyleC60A_SP") + { hpwhModel = HPWH::MODELS_NyleC60A_SP; } - else if (modelName == "NyleC90A_SP") { + else if (modelName == "NyleC90A_SP") + { hpwhModel = HPWH::MODELS_NyleC90A_SP; } - else if (modelName == "NyleC185A_SP") { + else if (modelName == "NyleC185A_SP") + { hpwhModel = HPWH::MODELS_NyleC185A_SP; } - else if (modelName == "NyleC250A_SP") { + else if (modelName == "NyleC250A_SP") + { hpwhModel = HPWH::MODELS_NyleC250A_SP; } - else if (modelName == "NyleC60A_C_SP") { + else if (modelName == "NyleC60A_C_SP") + { hpwhModel = HPWH::MODELS_NyleC60A_C_SP; } - else if (modelName == "NyleC90A_C_SP") { + else if (modelName == "NyleC90A_C_SP") + { hpwhModel = HPWH::MODELS_NyleC90A_C_SP; } - else if (modelName == "NyleC185A_C_SP") { + else if (modelName == "NyleC185A_C_SP") + { hpwhModel = HPWH::MODELS_NyleC185A_C_SP; } - else if (modelName == "NyleC250A_C_SP") { + else if (modelName == "NyleC250A_C_SP") + { hpwhModel = HPWH::MODELS_NyleC250A_C_SP; } // Nyle MP models - else if (modelName == "NyleC60A_MP") { + else if (modelName == "NyleC60A_MP") + { hpwhModel = HPWH::MODELS_NyleC60A_MP; } - else if (modelName == "NyleC90A_MP") { + else if (modelName == "NyleC90A_MP") + { hpwhModel = HPWH::MODELS_NyleC90A_MP; } - else if (modelName == "NyleC125A_MP") { + else if (modelName == "NyleC125A_MP") + { hpwhModel = HPWH::MODELS_NyleC125A_MP; } - else if (modelName == "NyleC185A_MP") { + else if (modelName == "NyleC185A_MP") + { hpwhModel = HPWH::MODELS_NyleC185A_MP; } - else if (modelName == "NyleC250A_MP") { + else if (modelName == "NyleC250A_MP") + { hpwhModel = HPWH::MODELS_NyleC250A_MP; } - else if (modelName == "NyleC60A_C_MP") { + else if (modelName == "NyleC60A_C_MP") + { hpwhModel = HPWH::MODELS_NyleC60A_C_MP; } - else if (modelName == "NyleC90A_C_MP") { + else if (modelName == "NyleC90A_C_MP") + { hpwhModel = HPWH::MODELS_NyleC90A_C_MP; } - else if (modelName == "NyleC125A_C_MP") { + else if (modelName == "NyleC125A_C_MP") + { hpwhModel = HPWH::MODELS_NyleC125A_C_MP; } - else if (modelName == "NyleC185A_C_MP") { + else if (modelName == "NyleC185A_C_MP") + { hpwhModel = HPWH::MODELS_NyleC185A_C_MP; } - else if (modelName == "NyleC250A_C_MP") { + else if (modelName == "NyleC250A_C_MP") + { hpwhModel = HPWH::MODELS_NyleC250A_C_MP; } - else if (modelName == "QAHV_N136TAU_HPB_SP") { + else if (modelName == "QAHV_N136TAU_HPB_SP") + { hpwhModel = HPWH::MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP; } // Stack in a couple scalable models - else if (modelName == "TamScalable_SP") { + else if (modelName == "TamScalable_SP") + { hpwhModel = HPWH::MODELS_TamScalable_SP; } - else if (modelName == "TamScalable_SP_2X") { + else if (modelName == "TamScalable_SP_2X") + { hpwhModel = HPWH::MODELS_TamScalable_SP; } - else if (modelName == "TamScalable_SP_Half") { + else if (modelName == "TamScalable_SP_Half") + { hpwhModel = HPWH::MODELS_TamScalable_SP; } - else if (modelName == "Scalable_MP") { + else if (modelName == "Scalable_MP") + { hpwhModel = HPWH::MODELS_Scalable_MP; } - else if (modelName == "AWHSTier3Generic40") { + else if (modelName == "AWHSTier3Generic40") + { hpwhModel = HPWH::MODELS_AWHSTier3Generic40; } - else if (modelName == "AWHSTier3Generic50") { + else if (modelName == "AWHSTier3Generic50") + { hpwhModel = HPWH::MODELS_AWHSTier3Generic50; } - else if (modelName == "AWHSTier3Generic65") { + else if (modelName == "AWHSTier3Generic65") + { hpwhModel = HPWH::MODELS_AWHSTier3Generic65; } - else if (modelName == "AWHSTier3Generic80") { + else if (modelName == "AWHSTier3Generic80") + { hpwhModel = HPWH::MODELS_AWHSTier3Generic80; } - else { + else + { hpwhModel = HPWH::MODELS_basicIntegrated; cout << "Couldn't find model " << modelName << ". Exiting...\n"; exit(1); @@ -320,11 +405,13 @@ int getHPWHObject(HPWH& hpwh, string modelName) returnVal = hpwh.HPWHinit_presets(model); - if (modelName == "TamScalable_SP_2X") { + if (modelName == "TamScalable_SP_2X") + { hpwh.setScaleHPWHCapacityCOP(2., 1.); // Scale the compressor hpwh.setResistanceCapacity(60.); // Reset resistance elements in kW } - else if (modelName == "TamScalable_SP_Half") { + else if (modelName == "TamScalable_SP_Half") + { hpwh.setScaleHPWHCapacityCOP(1 / 2., 1.); // Scale the compressor hpwh.setResistanceCapacity(15.); // Reset resistance elements in kW } From 325f02622b27c7535ff388c6ddee254828ba4d71 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Mon, 23 Oct 2023 12:29:33 -0600 Subject: [PATCH 3/9] Format cc file. --- src/HPWH.cc | 2663 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 1764 insertions(+), 899 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 85cdf729..3b977f84 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -128,7 +128,8 @@ HPWH::HPWH(const HPWH& hpwh) numHeatSources = hpwh.numHeatSources; setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i] = hpwh.setOfSources[i]; setOfSources[i].hpwh = this; } @@ -142,7 +143,8 @@ HPWH::HPWH(const HPWH& hpwh) nodeDensity = hpwh.nodeDensity; tankTemps_C = new double[numNodes]; nextTankTemps_C = new double[numNodes]; - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { tankTemps_C[i] = hpwh.tankTemps_C[i]; nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; } @@ -178,7 +180,8 @@ HPWH::HPWH(const HPWH& hpwh) HPWH& HPWH::operator=(const HPWH& hpwh) { - if (this == &hpwh) { + if (this == &hpwh) + { return *this; } @@ -196,7 +199,8 @@ HPWH& HPWH::operator=(const HPWH& hpwh) delete[] setOfSources; setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i] = hpwh.setOfSources[i]; setOfSources[i].hpwh = this; // HeatSource assignment will fail (causing the simulation to fail) if a @@ -219,7 +223,8 @@ HPWH& HPWH::operator=(const HPWH& hpwh) delete[] nextTankTemps_C; tankTemps_C = new double[numNodes]; nextTankTemps_C = new double[numNodes]; - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { tankTemps_C[i] = hpwh.tankTemps_C[i]; nextTankTemps_C[i] = hpwh.nextTankTemps_C[i]; } @@ -282,20 +287,24 @@ int HPWH::runOneStep(double drawVolume_L, // returns 0 on successful completion, HPWH_ABORT on failure // check for errors - if (doTempDepression == true && minutesPerStep != 1) { + if (doTempDepression == true && minutesPerStep != 1) + { msg("minutesPerStep must equal one for temperature depression to work. \n"); simHasFailed = true; return HPWH_ABORT; } - if ((DRstatus & (DR_TOO | DR_TOT))) { - if (hpwhVerbosity >= VRB_typical) { + if ((DRstatus & (DR_TOO | DR_TOT))) + { + if (hpwhVerbosity >= 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 (hpwhVerbosity >= VRB_typical) + { msg("Beginning runOneStep. \nTank Temps: "); printTankTemps(); msg("Step Inputs: InletT_C: %.2lf, drawVolume_L: %.2lf, tankAmbientT_C: %.2lf, " @@ -308,8 +317,10 @@ int HPWH::runOneStep(double drawVolume_L, minutesPerStep); } // is the failure flag is set, don't run - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { + if (simHasFailed) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("simHasFailed is set, aborting. \n"); } return HPWH_ABORT; @@ -323,7 +334,8 @@ int HPWH::runOneStep(double drawVolume_L, energyRemovedFromEnvironment_kWh = 0.; standbyLosses_kWh = 0.; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i].runtime_min = 0; setOfSources[i].energyInput_kWh = 0.; setOfSources[i].energyOutput_kWh = 0.; @@ -332,8 +344,10 @@ int HPWH::runOneStep(double drawVolume_L, // if you are doing temp. depression, set tank and heatSource ambient temps // to the tracked locationTemperature double temperatureGoal = tankAmbientT_C; - if (doTempDepression) { - if (locationTemperature_C == UNINITIALIZED_LOCATIONTEMP) { + if (doTempDepression) + { + if (locationTemperature_C == UNINITIALIZED_LOCATIONTEMP) + { locationTemperature_C = tankAmbientT_C; } tankAmbientT_C = locationTemperature_C; @@ -348,24 +362,31 @@ int HPWH::runOneStep(double drawVolume_L, // First Logic DR checks ////////////////////////////////////////////////////////////////// // If the DR signal includes a top off but the previous signal did not, then top it off! - if ((DRstatus & DR_LOC) != 0 && (DRstatus & DR_LOR) != 0) { + if ((DRstatus & DR_LOC) != 0 && (DRstatus & DR_LOR) != 0) + { turnAllHeatSourcesOff(); // turns off isheating - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("DR_LOC | DR_LOC everything off, DRstatus = %i \n", DRstatus); } } - else { // do normal check - if (((DRstatus & DR_TOO) != 0 || (DRstatus & DR_TOT) != 0) && timerTOT == 0) { + else + { // do normal check + if (((DRstatus & DR_TOO) != 0 || (DRstatus & DR_TOT) != 0) && timerTOT == 0) + { // turn on the compressor and last resistance element. - if (hasACompressor()) { + if (hasACompressor()) + { setOfSources[compressorIndex].engageHeatSource(DRstatus); } - if (lowestElementIndex >= 0) { + if (lowestElementIndex >= 0) + { setOfSources[lowestElementIndex].engageHeatSource(DRstatus); } - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("TURNED ON DR_TOO engaged compressor and lowest resistance element, DRstatus = " "%i \n", DRstatus); @@ -373,22 +394,27 @@ int HPWH::runOneStep(double drawVolume_L, } // do HeatSource choice - for (int i = 0; i < numHeatSources; i++) { - if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) + { + if (hpwhVerbosity >= VRB_emetic) + { msg("Heat source choice:\theatsource %d can choose from %lu turn on logics and %lu " "shut off logics\n", i, setOfSources[i].turnOnLogicSet.size(), setOfSources[i].shutOffLogicSet.size()); } - if (isHeating == true) { + if (isHeating == true) + { // check if anything that is on needs to turn off (generally for lowT cutoffs) // things that just turn on later this step are checked for this in shouldHeat - if (setOfSources[i].isEngaged() && setOfSources[i].shutsOff()) { + if (setOfSources[i].isEngaged() && setOfSources[i].shutsOff()) + { setOfSources[i].disengageHeatSource(); // check if the backup heat source would have to shut off too if (setOfSources[i].backupHeatSource != NULL && - setOfSources[i].backupHeatSource->shutsOff() != true) { + setOfSources[i].backupHeatSource->shutsOff() != true) + { // and if not, go ahead and turn it on setOfSources[i].backupHeatSource->engageHeatSource(DRstatus); } @@ -396,18 +422,24 @@ int HPWH::runOneStep(double drawVolume_L, // if there's a priority HeatSource (e.g. upper resistor) and it needs to // come on, then turn off and start it up - if (setOfSources[i].isVIP) { - if (hpwhVerbosity >= VRB_emetic) { + if (setOfSources[i].isVIP) + { + if (hpwhVerbosity >= VRB_emetic) + { msg("\tVIP check"); } - if (setOfSources[i].shouldHeat()) { - if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { - if (hasACompressor()) { + if (setOfSources[i].shouldHeat()) + { + if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) + { + if (hasACompressor()) + { setOfSources[compressorIndex].engageHeatSource(DRstatus); break; } } - else { + else + { turnAllHeatSourcesOff(); setOfSources[i].engageHeatSource(DRstatus); // stop looking if the VIP needs to run @@ -417,8 +449,10 @@ int HPWH::runOneStep(double drawVolume_L, } } // if nothing is currently on, then check if something should come on - else /* (isHeating == false) */ { - if (setOfSources[i].shouldHeat()) { + else /* (isHeating == false) */ + { + if (setOfSources[i].shouldHeat()) + { setOfSources[i].engageHeatSource(DRstatus); // engaging a heat source sets isHeating to true, so this will only trigger once } @@ -426,9 +460,11 @@ int HPWH::runOneStep(double drawVolume_L, } // end loop over heat sources - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("after heat source choosing: "); - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { msg("heat source %d: %d \t", i, setOfSources[i].isEngaged()); } msg("\n"); @@ -436,48 +472,60 @@ int HPWH::runOneStep(double drawVolume_L, // do heating logic double minutesToRun = minutesPerStep; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { // check/apply lock-outs - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("Checking lock-out logic for heat source %d:\n", i); } - if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) { + if (shouldDRLockOut(setOfSources[i].typeOfHeatSource, DRstatus)) + { setOfSources[i].lockOutHeatSource(); - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("Locked out heat source, DRstatus = %i\n", DRstatus); } } - else { + else + { // locks or unlocks the heat source setOfSources[i].toLockOrUnlock(heatSourceAmbientT_C); } - if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource == NULL) { + if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource == NULL) + { setOfSources[i].disengageHeatSource(); - if (hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwhVerbosity >= HPWH::VRB_emetic) + { msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. " "Simulation will continue will lock out the heat source."); } } // going through in order, check if the heat source is on - if (setOfSources[i].isEngaged()) { + if (setOfSources[i].isEngaged()) + { HeatSource* heatSourcePtr; - if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource != NULL) { + if (setOfSources[i].isLockedOut() && setOfSources[i].backupHeatSource != NULL) + { // Check that the backup isn't locked out too or already engaged then it will // heat on it's own. if (setOfSources[i].backupHeatSource->toLockOrUnlock(heatSourceAmbientT_C) || shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, DRstatus) || //){ - setOfSources[i].backupHeatSource->isEngaged()) { + setOfSources[i].backupHeatSource->isEngaged()) + { continue; } // Don't turn the backup electric resistance heat source on if the VIP // resistance element is on . else if (VIPIndex >= 0 && setOfSources[VIPIndex].isOn && - setOfSources[i].backupHeatSource->isAResistance()) { - if (hpwhVerbosity >= VRB_typical) { + setOfSources[i].backupHeatSource->isAResistance()) + { + if (hpwhVerbosity >= VRB_typical) + { msg("Locked out back up heat source AND the engaged heat source %i, " "DRstatus = %i\n", i, @@ -485,11 +533,13 @@ int HPWH::runOneStep(double drawVolume_L, } continue; } - else { + else + { heatSourcePtr = setOfSources[i].backupHeatSource; } } - else { + else + { heatSourcePtr = &setOfSources[i]; } @@ -497,9 +547,11 @@ int HPWH::runOneStep(double drawVolume_L, // if it finished early. i.e. shuts off early like if the heatsource met setpoint or // maxed out - if (heatSourcePtr->runtime_min < minutesToRun) { + if (heatSourcePtr->runtime_min < minutesToRun) + { // debugging message handling - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("done heating! runtime_min minutesToRun %.2lf %.2lf\n", heatSourcePtr->runtime_min, minutesToRun); @@ -511,7 +563,8 @@ int HPWH::runOneStep(double drawVolume_L, // and if there's a heat source that follows this heat source (regardless of // lockout) that's able to come on, if (setOfSources[i].followedByHeatSource != NULL && - setOfSources[i].followedByHeatSource->shutsOff() == false) { + setOfSources[i].followedByHeatSource->shutsOff() == false) + { // turn it on setOfSources[i].followedByHeatSource->engageHeatSource(DRstatus); } @@ -519,8 +572,8 @@ int HPWH::runOneStep(double drawVolume_L, // the tank still isn't at setpoint. the compressor should get locked out when // the maxedOut is true but have to run the resistance first during this // timestep to make sure tank is above the max temperature for the compressor. - else if (setOfSources[i].maxedOut() && - setOfSources[i].backupHeatSource != NULL) { + else if (setOfSources[i].maxedOut() && setOfSources[i].backupHeatSource != NULL) + { // Check that the backup isn't locked out or already engaged then it will // heat or already heated on it's own. @@ -528,14 +581,15 @@ int HPWH::runOneStep(double drawVolume_L, heatSourceAmbientT_C) && // If not locked out !shouldDRLockOut(setOfSources[i].backupHeatSource->typeOfHeatSource, DRstatus) && // and not DR locked out - !setOfSources[i] - .backupHeatSource->isEngaged()) { // and not already engaged + !setOfSources[i].backupHeatSource->isEngaged()) + { // and not already engaged HeatSource* backupHeatSourcePtr = setOfSources[i].backupHeatSource; // turn it on backupHeatSourcePtr->engageHeatSource(DRstatus); // add heat if it hasn't heated up this whole minute already - if (backupHeatSourcePtr->runtime_min >= 0.) { + if (backupHeatSourcePtr->runtime_min >= 0.) + { addHeatParent(backupHeatSourcePtr, heatSourceAmbientT_C, minutesToRun - backupHeatSourcePtr->runtime_min); @@ -546,31 +600,38 @@ int HPWH::runOneStep(double drawVolume_L, } // heat source not engaged } // end while iHS heat source } - if (areAllHeatSourcesOff() == true) { + if (areAllHeatSourcesOff() == true) + { isHeating = false; } // If theres extra user defined heat to add -> Add extra heat! - if (nodePowerExtra_W != NULL && (*nodePowerExtra_W).size() != 0) { + if (nodePowerExtra_W != NULL && (*nodePowerExtra_W).size() != 0) + { addExtraHeat(nodePowerExtra_W, tankAmbientT_C); updateSoCIfNecessary(); } // track the depressed local temperature - if (doTempDepression) { + if (doTempDepression) + { bool compressorRan = false; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { if (setOfSources[i].isEngaged() && !setOfSources[i].isLockedOut() && - setOfSources[i].depressesTemperature) { + setOfSources[i].depressesTemperature) + { compressorRan = true; } } - if (compressorRan) { + if (compressorRan) + { temperatureGoal -= maxDepression_C; // hardcoded 4.5 degree total drop - from // experimental data. Changed to an input } - else { + else + { // otherwise, do nothing, we're going back to ambient } @@ -587,14 +648,17 @@ int HPWH::runOneStep(double drawVolume_L, // outletTemp_C and standbyLosses_kWh are taken care of in updateTankTemps // sum energyRemovedFromEnvironment_kWh for each heat source; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { energyRemovedFromEnvironment_kWh += (setOfSources[i].energyOutput_kWh - setOfSources[i].energyInput_kWh); } // cursory check for inverted temperature profile - if (tankTemps_C[numNodes - 1] < tankTemps_C[0]) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tankTemps_C[numNodes - 1] < tankTemps_C[0]) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The top of the tank is cooler than the bottom. \n"); } } @@ -604,21 +668,26 @@ int HPWH::runOneStep(double drawVolume_L, // DR check for TOT to increase timer. timerTOT += minutesPerStep; // Restart the time if we're over the limit or the command is not a top off. - if ((DRstatus & DR_TOT) != 0 && timerTOT >= timerLimitTOT) { + if ((DRstatus & DR_TOT) != 0 && timerTOT >= timerLimitTOT) + { resetTopOffTimer(); } - else if ((DRstatus & DR_TOO) == 0 && (DRstatus & DR_TOT) == 0) { + else if ((DRstatus & DR_TOO) == 0 && (DRstatus & DR_TOT) == 0) + { resetTopOffTimer(); } - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { + if (simHasFailed) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The simulation has encountered an error. \n"); } return HPWH_ABORT; } - if (hpwhVerbosity >= VRB_typical) { + if (hpwhVerbosity >= VRB_typical) + { msg("Ending runOneStep. \n\n\n\n"); } @@ -643,16 +712,20 @@ int HPWH::runNSteps(int N, std::vector heatSources_energyInputs_SUM(numHeatSources); std::vector heatSources_energyOutputs_SUM(numHeatSources); - if (hpwhVerbosity >= VRB_typical) { + if (hpwhVerbosity >= VRB_typical) + { msg("Begin runNSteps. \n"); } // run the sim one step at a time, accumulating the outputs as you go - for (int i = 0; i < N; i++) { + for (int i = 0; i < N; i++) + { runOneStep( inletT_C[i], drawVolume_L[i], tankAmbientT_C[i], heatSourceAmbientT_C[i], DRstatus[i]); - if (simHasFailed) { - if (hpwhVerbosity >= VRB_reluctant) { + if (simHasFailed) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("RunNSteps has encountered an error on step %d of N and has ceased running. " "\n", i + 1); @@ -666,16 +739,19 @@ int HPWH::runNSteps(int N, outletTemp_C_AVG += outletTemp_C * drawVolume_L[i]; totalDrawVolume_L += drawVolume_L[i]; - for (int j = 0; j < numHeatSources; j++) { + for (int j = 0; j < numHeatSources; j++) + { heatSources_runTimes_SUM[j] += getNthHeatSourceRunTime(j); heatSources_energyInputs_SUM[j] += getNthHeatSourceEnergyInput(j); heatSources_energyOutputs_SUM[j] += getNthHeatSourceEnergyOutput(j); } // print minutely output - if (hpwhVerbosity == VRB_minuteOut) { + if (hpwhVerbosity == VRB_minuteOut) + { msg("%f,%f,%f,", tankAmbientT_C[i], drawVolume_L[i], inletT_C[i]); - for (int j = 0; j < numHeatSources; j++) { + for (int j = 0; j < numHeatSources; j++) + { msg("%f,%f,", getNthHeatSourceEnergyInput(j), getNthHeatSourceEnergyOutput(j)); } msg("%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n", @@ -705,13 +781,15 @@ int HPWH::runNSteps(int N, standbyLosses_kWh = standbyLosses_kWh_SUM; outletTemp_C = outletTemp_C_AVG; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i].runtime_min = heatSources_runTimes_SUM[i]; setOfSources[i].energyInput_kWh = heatSources_energyInputs_SUM[i]; setOfSources[i].energyOutput_kWh = heatSources_energyOutputs_SUM[i]; } - if (hpwhVerbosity >= VRB_typical) { + if (hpwhVerbosity >= VRB_typical) + { msg("Ending runNSteps. \n\n\n\n"); } return 0; @@ -725,9 +803,11 @@ void HPWH::addHeatParent(HeatSource* heatSourcePtr, double tempSetpoint_C = -273.15; // Check the air temprature and setpoint against maxOut_at_LowT - if (heatSourcePtr->isACompressor()) { + if (heatSourcePtr->isACompressor()) + { if (heatSourceAmbientT_C <= heatSourcePtr->maxOut_at_LowT.airT_C && - setpoint_C >= heatSourcePtr->maxOut_at_LowT.outT_C) { + setpoint_C >= heatSourcePtr->maxOut_at_LowT.outT_C) + { tempSetpoint_C = setpoint_C; // Store setpoint setSetpoint(heatSourcePtr->maxOut_at_LowT .outT_C); // Reset to new setpoint as this is used in the add heat calc @@ -737,7 +817,8 @@ void HPWH::addHeatParent(HeatSource* heatSourcePtr, heatSourcePtr->addHeat(heatSourceAmbientT_C, minutesToRun); // Change the setpoint back to what it was pre-compressor depression - if (tempSetpoint_C > -273.15) { + if (tempSetpoint_C > -273.15) + { setSetpoint(tempSetpoint_C); } } @@ -751,10 +832,12 @@ void HPWH::setMessageCallback(void (*callbackFunc)(const string message, void* c } void HPWH::sayMessage(const string message) const { - if (messageCallback != NULL) { + if (messageCallback != NULL) + { (*messageCallback)(message, messageCallbackContextPtr); } - else { + else + { std::cout << message; } } @@ -769,7 +852,8 @@ void HPWH::msgV(const char* fmt, va_list ap /*=NULL*/) const char outputString[MAXOUTSTRING]; const char* p; - if (ap) { + if (ap) + { #if defined(_MSC_VER) vsprintf_s(outputString, fmt, ap); #else @@ -777,7 +861,8 @@ void HPWH::msgV(const char* fmt, va_list ap /*=NULL*/) const #endif p = outputString; } - else { + else + { p = fmt; } sayMessage(p); @@ -791,47 +876,57 @@ void HPWH::printHeatSourceInfo() ss << std::left; ss << std::fixed; ss << std::setprecision(2); - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { ss << "heat source " << i << ": " << isNthHeatSourceRunning(i) << "\t\t"; } ss << endl; - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { ss << "input energy kwh: " << std::setw(7) << getNthHeatSourceEnergyInput(i) << "\t"; } ss << endl; - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { runtime = getNthHeatSourceRunTime(i); - if (runtime != 0) { + if (runtime != 0) + { outputVar = getNthHeatSourceEnergyInput(i) / (runtime / 60.0); } - else { + else + { outputVar = 0; } ss << "input power kw: " << std::setw(7) << outputVar << "\t\t"; } ss << endl; - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { ss << "output energy kwh: " << std::setw(7) << getNthHeatSourceEnergyOutput(i, UNITS_KWH) << "\t"; } ss << endl; - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { runtime = getNthHeatSourceRunTime(i); - if (runtime != 0) { + if (runtime != 0) + { outputVar = getNthHeatSourceEnergyOutput(i, UNITS_KWH) / (runtime / 60.0); } - else { + else + { outputVar = 0; } ss << "output power kw: " << std::setw(7) << outputVar << "\t"; } ss << endl; - for (int i = 0; i < getNumHeatSources(); i++) { + for (int i = 0; i < getNumHeatSources(); i++) + { ss << "run time min: " << std::setw(7) << getNthHeatSourceRunTime(i) << "\t\t"; } ss << endl << endl << endl; @@ -845,7 +940,8 @@ void HPWH::printTankTemps() ss << std::left; - for (int i = 0; i < getNumNodes(); i++) { + for (int i = 0; i < getNumNodes(); i++) + { ss << std::setw(9) << getTankNodeTemp(i) << " "; } ss << endl; @@ -863,11 +959,13 @@ int HPWH::WriteCSVHeading(FILE* outFILE, const char* preamble, int nTCouples, in fprintf(outFILE, "%s", "DRstatus"); - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) + { fprintf(outFILE, ",h_src%dIn (Wh),h_src%dOut (Wh)", iHS + 1, iHS + 1); } - for (int iTC = 0; iTC < nTCouples; iTC++) { + for (int iTC = 0; iTC < nTCouples; iTC++) + { fprintf(outFILE, ",tcouple%d (%s)", iTC + 1, doIP ? "F" : "C"); } @@ -885,14 +983,16 @@ int HPWH::WriteCSVRow(FILE* outFILE, const char* preamble, int nTCouples, int op fprintf(outFILE, "%i", prevDRstatus); - for (int iHS = 0; iHS < getNumHeatSources(); iHS++) { + for (int iHS = 0; iHS < getNumHeatSources(); iHS++) + { fprintf(outFILE, ",%0.2f,%0.2f", getNthHeatSourceEnergyInput(iHS, UNITS_KWH) * 1000., getNthHeatSourceEnergyOutput(iHS, UNITS_KWH) * 1000.); } - for (int iTC = 0; iTC < nTCouples; iTC++) { + for (int iTC = 0; iTC < nTCouples; iTC++) + { fprintf(outFILE, ",%0.2f", getNthSimTcouple(iTC + 1, nTCouples, doIP ? UNITS_F : UNITS_C)); } @@ -908,20 +1008,26 @@ int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) double newSetpoint_C, temp; string why; - if (units == UNITS_C) { + if (units == UNITS_C) + { newSetpoint_C = newSetpoint; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { newSetpoint_C = F_TO_C(newSetpoint); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for setSetpoint. \n"); } return HPWH_ABORT; } - if (!isNewSetpointPossible(newSetpoint_C, temp, why)) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isNewSetpointPossible(newSetpoint_C, temp, why)) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Unwilling to set this setpoint for the currently selected model, max setpoint is " "%f C. %s\n", temp, @@ -937,14 +1043,18 @@ int HPWH::setSetpoint(double newSetpoint, UNITS units /*=UNITS_C*/) double HPWH::getSetpoint(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { + if (units == UNITS_C) + { return setpoint_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(setpoint_C); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getSetpoint. \n"); } return HPWH_ABORT; @@ -954,22 +1064,28 @@ double HPWH::getSetpoint(UNITS units /*=UNITS_C*/) const double HPWH::getMaxCompressorSetpoint(UNITS units /*=UNITS_C*/) const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Unit does not have a compressor \n"); } return HPWH_ABORT; } double returnVal = setOfSources[compressorIndex].maxSetpoint_C; - if (units == UNITS_C) { + if (units == UNITS_C) + { returnVal = returnVal; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { returnVal = C_TO_F(returnVal); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getMaxCompressorSetpoint. \n"); } return HPWH_ABORT; @@ -984,73 +1100,91 @@ bool HPWH::isNewSetpointPossible(double newSetpoint, { double newSetpoint_C; double maxAllowedSetpoint_C = -273.15; - if (units == UNITS_C) { + if (units == UNITS_C) + { newSetpoint_C = newSetpoint; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { newSetpoint_C = F_TO_C(newSetpoint); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for isNewSetpointPossible. \n"); } return false; } bool returnVal = false; - if (isSetpointFixed()) { + if (isSetpointFixed()) + { returnVal = (newSetpoint == setpoint_C); maxAllowedSetpoint_C = setpoint_C; - if (!returnVal) { + if (!returnVal) + { why = "The set point is fixed for the currently selected model."; } } - else { + else + { - if (hasACompressor()) { // If there's a compressor lets check the new setpoint against the - // compressor's max setpoint + if (hasACompressor()) + { // If there's a compressor lets check the new setpoint against the + // compressor's max setpoint maxAllowedSetpoint_C = setOfSources[compressorIndex].maxSetpoint_C - setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; - if (newSetpoint_C > maxAllowedSetpoint_C && lowestElementIndex == -1) { + if (newSetpoint_C > maxAllowedSetpoint_C && lowestElementIndex == -1) + { why = "The compressor cannot meet the setpoint temperature and there is no " "resistance backup."; returnVal = false; } - else { + else + { returnVal = true; } } - if (lowestElementIndex >= 0) { // If there's a resistance element lets check the new - // setpoint against the its max setpoint + if (lowestElementIndex >= 0) + { // If there's a resistance element lets check the new + // setpoint against the its max setpoint maxAllowedSetpoint_C = setOfSources[lowestElementIndex].maxSetpoint_C; - if (newSetpoint_C > maxAllowedSetpoint_C) { + if (newSetpoint_C > maxAllowedSetpoint_C) + { why = "The resistance elements cannot produce water this hot."; returnVal = false; } - else { + else + { returnVal = true; } } - else if (lowestElementIndex == -1 && !hasACompressor()) { // There are no heat sources here! - if (hpwhModel == MODELS_StorageTank) { + else if (lowestElementIndex == -1 && !hasACompressor()) + { // There are no heat sources here! + if (hpwhModel == MODELS_StorageTank) + { returnVal = true; // The one pass the storage tank doesn't have any heating elements // so sure change the setpoint it does nothing! } - else { + else + { why = "There aren't any heat sources to check the new setpoint against!"; returnVal = false; } } } - if (units == UNITS_C) { + if (units == UNITS_C) + { maxAllowedSetpoint = maxAllowedSetpoint_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { maxAllowedSetpoint = C_TO_F(maxAllowedSetpoint_C); } return returnVal; @@ -1060,21 +1194,26 @@ double HPWH::calcSoCFraction(double tMains_C, double tMinUseful_C, double tMax_C { // Note that volume is ignored in here since with even nodes it cancels out of the SoC // fractional equation - if (tMains_C >= tMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tMains_C >= tMinUseful_C) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("tMains_C is greater than or equal tMinUseful_C. \n"); } return HPWH_ABORT; } - if (tMinUseful_C > tMax_C) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tMinUseful_C > tMax_C) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("tMinUseful_C is greater tMax_C. \n"); } return HPWH_ABORT; } double chargeEquivalent = 0.; - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { chargeEquivalent += getChargePerNode(tMains_C, tMinUseful_C, tankTemps_C[i]); } double maxSoC = numNodes * getChargePerNode(tMains_C, tMinUseful_C, tMax_C); @@ -1097,7 +1236,8 @@ void HPWH::calcAndSetSoCFraction() double HPWH::getChargePerNode(double tCold, double tMix, double tHot) const { - if (tHot < tMix) { + if (tHot < tMix) + { return 0.; } return (tHot - tCold) / (tMix - tCold); @@ -1105,20 +1245,26 @@ double HPWH::getChargePerNode(double tCold, double tMix, double tHot) const double HPWH::getMinOperatingTemp(UNITS units /*=UNITS_C*/) const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("No compressor found in this HPWH. \n"); } return HPWH_ABORT; } - if (units == UNITS_C) { + if (units == UNITS_C) + { return setOfSources[compressorIndex].minT; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(setOfSources[compressorIndex].minT); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getMinOperatingTemp.\n"); } return HPWH_ABORT; @@ -1129,7 +1275,8 @@ int HPWH::resetTankToSetpoint() { return setTankToTemperature(setpoint_C); } int HPWH::setTankToTemperature(double temp_C) { - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { tankTemps_C[i] = temp_C; } return 0; @@ -1137,16 +1284,21 @@ int HPWH::setTankToTemperature(double temp_C) int HPWH::setAirFlowFreedom(double fanFraction) { - if (fanFraction < 0 || fanFraction > 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (fanFraction < 0 || fanFraction > 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to set the fan fraction outside of bounds. \n"); } simHasFailed = true; return HPWH_ABORT; } - else { - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { + else + { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isACompressor()) + { setOfSources[i].airflowFreedom = fanFraction; } } @@ -1169,14 +1321,18 @@ int HPWH::setTankSize_adjustUA(double HPWH_size, double HPWH_size_L; double oldA = getTankSurfaceArea(UNITS_FT2); - if (units == UNITS_L) { + if (units == UNITS_L) + { HPWH_size_L = HPWH_size; } - else if (units == UNITS_GAL) { + else if (units == UNITS_GAL) + { HPWH_size_L = GAL_TO_L(HPWH_size); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for setTankSize_adjustUA. \n"); } return HPWH_ABORT; @@ -1197,7 +1353,8 @@ HPWH::getTankSurfaceArea(double vol, UNITS volUnits /*=UNITS_L*/, UNITS surfAUni double value = 2. * 3.14159 * pow(radius, 2) * (ASPECTRATIO + 1.); - if (value >= 0.) { + if (value >= 0.) + { if (surfAUnits == UNITS_M2) value = FT2_TO_M2(value); else if (surfAUnits != UNITS_FT2) @@ -1213,7 +1370,8 @@ double HPWH::getTankSurfaceArea(UNITS units /*=UNITS_FT2*/) const // HTP, Rheem, and Niles. Corresponds to the inner tank with volume tankVolume_L with the // assumption that the aspect ratio is the same as the outer dimenisions of the whole unit. double value = getTankSurfaceArea(tankVolume_L, UNITS_L, units); - if (value < 0.) { + if (value < 0.) + { if (hpwhVerbosity >= VRB_reluctant) msg("Incorrect unit specification for getTankSurfaceArea. \n"); value = HPWH_ABORT; @@ -1232,7 +1390,8 @@ HPWH::getTankRadius(double vol, UNITS volUnits /*=UNITS_L*/, UNITS radiusUnits / : -1.; double value = -1.; - if (volft3 >= 0.) { + if (volft3 >= 0.) + { value = pow(volft3 / 3.14159 / ASPECTRATIO, 1. / 3.); if (radiusUnits == UNITS_M) value = FT_TO_M(value); @@ -1251,7 +1410,8 @@ double HPWH::getTankRadius(UNITS units /*=UNITS_FT*/) const double value = getTankRadius(tankVolume_L, UNITS_L, units); - if (value < 0.) { + if (value < 0.) + { if (hpwhVerbosity >= VRB_reluctant) msg("Incorrect unit specification for getTankRadius. \n"); value = HPWH_ABORT; @@ -1263,28 +1423,37 @@ bool HPWH::isTankSizeFixed() const { return tankSizeFixed; } int HPWH::setTankSize(double HPWH_size, UNITS units /*=UNITS_L*/, bool forceChange /*=false*/) { - if (isTankSizeFixed() && !forceChange) { - if (hpwhVerbosity >= VRB_reluctant) { + if (isTankSizeFixed() && !forceChange) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not change the tank size for your currently selected model. \n"); } return HPWH_ABORT; } - if (HPWH_size <= 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (HPWH_size <= 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to set the tank volume outside of bounds. \n"); } simHasFailed = true; return HPWH_ABORT; } - else { - if (units == UNITS_L) { + else + { + if (units == UNITS_L) + { this->tankVolume_L = HPWH_size; } - else if (units == UNITS_GAL) { + else if (units == UNITS_GAL) + { this->tankVolume_L = (GAL_TO_L(HPWH_size)); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for setTankSize. \n"); } return HPWH_ABORT; @@ -1308,14 +1477,18 @@ int HPWH::setDoConduction(bool doCondu) int HPWH::setUA(double UA, UNITS units /*=UNITS_kJperHrC*/) { - if (units == UNITS_kJperHrC) { + if (units == UNITS_kJperHrC) + { tankUA_kJperHrC = UA; } - else if (units == UNITS_BTUperHrF) { + else if (units == UNITS_BTUperHrF) + { tankUA_kJperHrC = UAf_TO_UAc(UA); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for setUA. \n"); } return HPWH_ABORT; @@ -1326,14 +1499,18 @@ int HPWH::setUA(double UA, UNITS units /*=UNITS_kJperHrC*/) int HPWH::getUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const { UA = tankUA_kJperHrC; - if (units == UNITS_kJperHrC) { + if (units == UNITS_kJperHrC) + { // UA is already in correct units } - else if (units == UNITS_BTUperHrF) { + else if (units == UNITS_BTUperHrF) + { UA = UA / UAf_TO_UAc(1.); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getUA. \n"); } UA = -1.; @@ -1344,14 +1521,18 @@ int HPWH::getUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const int HPWH::setFittingsUA(double UA, UNITS units /*=UNITS_kJperHrC*/) { - if (units == UNITS_kJperHrC) { + if (units == UNITS_kJperHrC) + { fittingsUA_kJperHrC = UA; } - else if (units == UNITS_BTUperHrF) { + else if (units == UNITS_BTUperHrF) + { fittingsUA_kJperHrC = UAf_TO_UAc(UA); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for setFittingsUA. \n"); } return HPWH_ABORT; @@ -1361,14 +1542,18 @@ int HPWH::setFittingsUA(double UA, UNITS units /*=UNITS_kJperHrC*/) int HPWH::getFittingsUA(double& UA, UNITS units /*=UNITS_kJperHrC*/) const { UA = fittingsUA_kJperHrC; - if (units == UNITS_kJperHrC) { + if (units == UNITS_kJperHrC) + { // UA is already in correct units } - else if (units == UNITS_BTUperHrF) { + else if (units == UNITS_BTUperHrF) + { UA = UA / UAf_TO_UAc(1.); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getUA. \n"); } UA = -1.; @@ -1397,26 +1582,33 @@ int HPWH::setExternalOutletHeightByFraction(double fractionalHeight) int HPWH::setExternalPortHeightByFraction(double fractionalHeight, int whichExternalPort) { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasExternalHeatSource()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Does not have an external heat source \n"); } return HPWH_ABORT; } int returnVal = 0; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { - if (whichExternalPort == 1) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) + { + if (whichExternalPort == 1) + { returnVal = setNodeNumFromFractionalHeight(fractionalHeight, setOfSources[i].externalInletHeight); } - else { + else + { returnVal = setNodeNumFromFractionalHeight(fractionalHeight, setOfSources[i].externalOutletHeight); } - if (returnVal == HPWH_ABORT) { + if (returnVal == HPWH_ABORT) + { return returnVal; } } @@ -1426,8 +1618,10 @@ int HPWH::setExternalPortHeightByFraction(double fractionalHeight, int whichExte int HPWH::setNodeNumFromFractionalHeight(double fractionalHeight, int& inletNum) { - if (fractionalHeight > 1. || fractionalHeight < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (fractionalHeight > 1. || fractionalHeight < 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds fraction for setInletByFraction \n"); } return HPWH_ABORT; @@ -1441,14 +1635,18 @@ int HPWH::setNodeNumFromFractionalHeight(double fractionalHeight, int& inletNum) int HPWH::getExternalInletHeight() const { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasExternalHeatSource()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Does not have an external heat source \n"); } return HPWH_ABORT; } - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) + { return setOfSources[i].externalInletHeight; // Return the first one since all external // sources have some ports } @@ -1457,14 +1655,18 @@ int HPWH::getExternalInletHeight() const } int HPWH::getExternalOutletHeight() const { - if (!hasExternalHeatSource()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasExternalHeatSource()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Does not have an external heat source \n"); } return HPWH_ABORT; } - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) + { return setOfSources[i].externalOutletHeight; // Return the first one since all external // sources have some ports } @@ -1474,8 +1676,10 @@ int HPWH::getExternalOutletHeight() const int HPWH::setTimerLimitTOT(double limit_min) { - if (limit_min > 24. * 60. || limit_min < 0.) { - if (hpwhVerbosity >= VRB_reluctant) { + if (limit_min > 24. * 60. || limit_min < 0.) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds time limit for setTimerLimitTOT \n"); } return HPWH_ABORT; @@ -1490,14 +1694,18 @@ double HPWH::getTimerLimitTOT_minute() const { return timerLimitTOT; } int HPWH::getInletHeight(int whichInlet) const { - if (whichInlet == 1) { + if (whichInlet == 1) + { return inletHeight; } - else if (whichInlet == 2) { + else if (whichInlet == 2) + { return inlet2Height; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Invalid inlet chosen in getInletHeight \n"); } return HPWH_ABORT; @@ -1506,14 +1714,18 @@ int HPWH::getInletHeight(int whichInlet) const int HPWH::setMaxTempDepression(double maxDepression, UNITS units /*=UNITS_C*/) { - if (units == UNITS_C) { + if (units == UNITS_C) + { this->maxDepression_C = maxDepression; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { this->maxDepression_C = F_TO_C(maxDepression); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for max Temp Depression. \n"); } return HPWH_ABORT; @@ -1524,16 +1736,19 @@ int HPWH::setMaxTempDepression(double maxDepression, UNITS units /*=UNITS_C*/) bool HPWH::hasEnteringWaterHighTempShutOff(int heatSourceIndex) { bool retVal = false; - if (heatSourceIndex >= numHeatSources || heatSourceIndex < 0) { + if (heatSourceIndex >= numHeatSources || heatSourceIndex < 0) + { return retVal; } - if (setOfSources[heatSourceIndex].shutOffLogicSet.size() == 0) { + if (setOfSources[heatSourceIndex].shutOffLogicSet.size() == 0) + { return retVal; } - for (std::shared_ptr shutOffLogic : - setOfSources[heatSourceIndex].shutOffLogicSet) { - if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { + for (std::shared_ptr shutOffLogic : setOfSources[heatSourceIndex].shutOffLogicSet) + { + if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) + { retVal = true; break; } @@ -1546,41 +1761,53 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, int heatSourceIndex, UNITS unit /*=UNITS_C*/) { - if (!hasEnteringWaterHighTempShutOff(heatSourceIndex)) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasEnteringWaterHighTempShutOff(heatSourceIndex)) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to acess a heating logic that does not exist. \n"); } return HPWH_ABORT; } double highTemp_C; - if (unit == UNITS_C) { + if (unit == UNITS_C) + { highTemp_C = highTemp; } - else if (unit == UNITS_F) { + else if (unit == UNITS_F) + { highTemp_C = F_TO_C(highTemp); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for set Entering Water High Temp Shut Off. \n"); } return HPWH_ABORT; } bool highTempIsNotValid = false; - if (tempIsAbsolute) { + if (tempIsAbsolute) + { // check differnce with setpoint - if (setpoint_C - highTemp_C < MINSINGLEPASSLIFT) { + if (setpoint_C - highTemp_C < MINSINGLEPASSLIFT) + { highTempIsNotValid = true; } } - else { - if (highTemp_C < MINSINGLEPASSLIFT) { + else + { + if (highTemp_C < MINSINGLEPASSLIFT) + { highTempIsNotValid = true; } } - if (highTempIsNotValid) { - if (hpwhVerbosity >= VRB_reluctant) { + if (highTempIsNotValid) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("High temperature shut off is too close to the setpoint, excpected a minimum " "difference of %.2lf.\n", MINSINGLEPASSLIFT); @@ -1588,9 +1815,10 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, return HPWH_ABORT; } - for (std::shared_ptr shutOffLogic : - setOfSources[heatSourceIndex].shutOffLogicSet) { - if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) { + for (std::shared_ptr shutOffLogic : setOfSources[heatSourceIndex].shutOffLogicSet) + { + if (shutOffLogic->getIsEnteringWaterHighTempShutoff()) + { std::dynamic_pointer_cast(shutOffLogic) ->setDecisionPoint(highTemp_C, tempIsAbsolute); break; @@ -1601,27 +1829,35 @@ int HPWH::setEnteringWaterHighTempShutOff(double highTemp, int HPWH::setTargetSoCFraction(double target) { - if (!isSoCControlled()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isSoCControlled()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not set target state of charge if HPWH is not using state of charge " "controls."); } return HPWH_ABORT; } - if (target < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (target < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not set a negative target state of charge."); } return HPWH_ABORT; } - for (int i = 0; i < numHeatSources; i++) { - for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { - if (!logic->getIsEnteringWaterHighTempShutoff()) { + for (int i = 0; i < numHeatSources; i++) + { + for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) + { + if (!logic->getIsEnteringWaterHighTempShutoff()) + { logic->setDecisionPoint(target); } } - for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { + for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) + { logic->setDecisionPoint(target); } } @@ -1633,7 +1869,8 @@ bool HPWH::isSoCControlled() const { return usesSoCLogic; } bool HPWH::canUseSoCControls() { bool retVal = true; - if (getCompressorCoilConfig() != HPWH::HeatSource::CONFIG_EXTERNAL) { + if (getCompressorCoilConfig() != HPWH::HeatSource::CONFIG_EXTERNAL) + { retVal = false; } return retVal; @@ -1646,46 +1883,54 @@ int HPWH::switchToSoCControls(double targetSoC, double mainsT /*= 18.333*/, UNITS tempUnit /*= UNITS_C*/) { - if (!canUseSoCControls()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!canUseSoCControls()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Cannot set up state of charge controls for integrated or wrapped HPWHs.\n"); } return HPWH_ABORT; } double tempMinUseful_C, mainsT_C; - if (tempUnit == UNITS_C) { + if (tempUnit == UNITS_C) + { tempMinUseful_C = tempMinUseful; mainsT_C = mainsT; } - else if (tempUnit == UNITS_F) { + else if (tempUnit == UNITS_F) + { tempMinUseful_C = F_TO_C(tempMinUseful); mainsT_C = F_TO_C(mainsT); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for set Enterinh Water High Temp Shut Off.\n"); } return HPWH_ABORT; } - if (mainsT_C >= tempMinUseful_C) { - if (hpwhVerbosity >= VRB_reluctant) { + if (mainsT_C >= tempMinUseful_C) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The mains temperature can't be equal to or greater than the minimum useful " "temperature.\n"); } return HPWH_ABORT; } - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i].clearAllTurnOnLogic(); setOfSources[i].shutOffLogicSet.erase( std::remove_if(setOfSources[i].shutOffLogicSet.begin(), setOfSources[i].shutOffLogicSet.end(), - [&](const auto logic) -> bool { - return !logic->getIsEnteringWaterHighTempShutoff(); - }), + [&](const auto logic) -> bool + { return !logic->getIsEnteringWaterHighTempShutoff(); }), setOfSources[i].shutOffLogicSet.end()); setOfSources[i].shutOffLogicSet.push_back(shutOffSoC("SoC Shut Off", @@ -1738,7 +1983,8 @@ std::shared_ptr HPWH::shutOffSoC(string desc, std::shared_ptr HPWH::topThird(double d) { std::vector nodeWeights; - for (int i : {9, 10, 11, 12}) { + for (int i : {9, 10, 11, 12}) + { nodeWeights.emplace_back(i); } return std::make_shared("top third", nodeWeights, d, this); @@ -1747,7 +1993,8 @@ std::shared_ptr HPWH::topThird(double d) std::shared_ptr HPWH::topThird_absolute(double d) { std::vector nodeWeights; - for (auto i : {9, 10, 11, 12}) { + for (auto i : {9, 10, 11, 12}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1757,7 +2004,8 @@ std::shared_ptr HPWH::topThird_absolute(double d) std::shared_ptr HPWH::bottomThird(double d) { std::vector nodeWeights; - for (auto i : {1, 2, 3, 4}) { + for (auto i : {1, 2, 3, 4}) + { nodeWeights.emplace_back(i); } return std::make_shared("bottom third", nodeWeights, d, this); @@ -1766,7 +2014,8 @@ std::shared_ptr HPWH::bottomThird(double d) std::shared_ptr HPWH::bottomSixth(double d) { std::vector nodeWeights; - for (auto i : {1, 2}) { + for (auto i : {1, 2}) + { nodeWeights.emplace_back(i); } return std::make_shared("bottom sixth", nodeWeights, d, this); @@ -1775,7 +2024,8 @@ std::shared_ptr HPWH::bottomSixth(double d) std::shared_ptr HPWH::bottomSixth_absolute(double d) { std::vector nodeWeights; - for (auto i : {1, 2}) { + for (auto i : {1, 2}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1785,7 +2035,8 @@ std::shared_ptr HPWH::bottomSixth_absolute(double d std::shared_ptr HPWH::secondSixth(double d) { std::vector nodeWeights; - for (auto i : {3, 4}) { + for (auto i : {3, 4}) + { nodeWeights.emplace_back(i); } return std::make_shared("second sixth", nodeWeights, d, this); @@ -1794,7 +2045,8 @@ std::shared_ptr HPWH::secondSixth(double d) std::shared_ptr HPWH::thirdSixth(double d) { std::vector nodeWeights; - for (auto i : {5, 6}) { + for (auto i : {5, 6}) + { nodeWeights.emplace_back(i); } return std::make_shared("third sixth", nodeWeights, d, this); @@ -1803,7 +2055,8 @@ std::shared_ptr HPWH::thirdSixth(double d) std::shared_ptr HPWH::fourthSixth(double d) { std::vector nodeWeights; - for (auto i : {7, 8}) { + for (auto i : {7, 8}) + { nodeWeights.emplace_back(i); } return std::make_shared("fourth sixth", nodeWeights, d, this); @@ -1812,7 +2065,8 @@ std::shared_ptr HPWH::fourthSixth(double d) std::shared_ptr HPWH::fifthSixth(double d) { std::vector nodeWeights; - for (auto i : {9, 10}) { + for (auto i : {9, 10}) + { nodeWeights.emplace_back(i); } return std::make_shared("fifth sixth", nodeWeights, d, this); @@ -1821,7 +2075,8 @@ std::shared_ptr HPWH::fifthSixth(double d) std::shared_ptr HPWH::topSixth(double d) { std::vector nodeWeights; - for (auto i : {11, 12}) { + for (auto i : {11, 12}) + { nodeWeights.emplace_back(i); } return std::make_shared("top sixth", nodeWeights, d, this); @@ -1830,7 +2085,8 @@ std::shared_ptr HPWH::topSixth(double d) std::shared_ptr HPWH::bottomHalf(double d) { std::vector nodeWeights; - for (auto i : {1, 2, 3, 4, 5, 6}) { + for (auto i : {1, 2, 3, 4, 5, 6}) + { nodeWeights.emplace_back(i); } return std::make_shared("bottom half", nodeWeights, d, this); @@ -1883,7 +2139,8 @@ std::shared_ptr HPWH::bottomTwelthMaxTemp(double d) std::shared_ptr HPWH::topThirdMaxTemp(double d) { std::vector nodeWeights; - for (auto i : {9, 10, 11, 12}) { + for (auto i : {9, 10, 11, 12}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1893,7 +2150,8 @@ std::shared_ptr HPWH::topThirdMaxTemp(double d) std::shared_ptr HPWH::bottomSixthMaxTemp(double d) { std::vector nodeWeights; - for (auto i : {1, 2}) { + for (auto i : {1, 2}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1903,7 +2161,8 @@ std::shared_ptr HPWH::bottomSixthMaxTemp(double d) std::shared_ptr HPWH::secondSixthMaxTemp(double d) { std::vector nodeWeights; - for (auto i : {3, 4}) { + for (auto i : {3, 4}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1913,7 +2172,8 @@ std::shared_ptr HPWH::secondSixthMaxTemp(double d) std::shared_ptr HPWH::fifthSixthMaxTemp(double d) { std::vector nodeWeights; - for (auto i : {9, 10}) { + for (auto i : {9, 10}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1923,7 +2183,8 @@ std::shared_ptr HPWH::fifthSixthMaxTemp(double d) std::shared_ptr HPWH::topSixthMaxTemp(double d) { std::vector nodeWeights; - for (auto i : {11, 12}) { + for (auto i : {11, 12}) + { nodeWeights.emplace_back(i); } return std::make_shared( @@ -1933,7 +2194,8 @@ std::shared_ptr HPWH::topSixthMaxTemp(double d) std::shared_ptr HPWH::largeDraw(double d) { std::vector nodeWeights; - for (auto i : {1, 2, 3, 4}) { + for (auto i : {1, 2, 3, 4}) + { nodeWeights.emplace_back(i); } return std::make_shared("large draw", nodeWeights, d, this, true); @@ -1942,7 +2204,8 @@ std::shared_ptr HPWH::largeDraw(double d) std::shared_ptr HPWH::largerDraw(double d) { std::vector nodeWeights; - for (auto i : {1, 2, 3, 4, 5, 6}) { + for (auto i : {1, 2, 3, 4, 5, 6}) + { nodeWeights.emplace_back(i); } return std::make_shared("larger draw", nodeWeights, d, this, true); @@ -1952,26 +2215,33 @@ int HPWH::getNumNodes() const { return numNodes; } double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const { - if (nodeNum >= numNodes || nodeNum < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (nodeNum >= numNodes || nodeNum < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the temperature of a tank node that does not exist. " "\n"); } return double(HPWH_ABORT); } - else { + else + { double result = tankTemps_C[nodeNum]; // if (result == double(HPWH_ABORT)) { can't happen? // return result; // } - if (units == UNITS_C) { + if (units == UNITS_C) + { return result; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(result); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getTankNodeTemp. \n"); } return double(HPWH_ABORT); @@ -1981,19 +2251,24 @@ double HPWH::getTankNodeTemp(int nodeNum, UNITS units /*=UNITS_C*/) const double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C*/) const { - if (iTCouple > nTCouple || iTCouple < 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (iTCouple > nTCouple || iTCouple < 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access a simulated thermocouple that does not exist. \n"); } return double(HPWH_ABORT); } - else if (nTCouple > numNodes) { - if (hpwhVerbosity >= VRB_reluctant) { + else if (nTCouple > numNodes) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have more simulated thermocouples than nodes. \n"); } return double(HPWH_ABORT); } - else { + else + { double weight = (double)numNodes / (double)nTCouple; double start_ind = (iTCouple - 1.) * weight; int ind = (int)std::ceil(start_ind); @@ -2006,27 +2281,33 @@ double HPWH::getNthSimTcouple(int iTCouple, int nTCouple, UNITS units /*=UNITS_C weight -= ((double)ind - start_ind); // Check the full nodes - while (weight >= 1.0) { + while (weight >= 1.0) + { averageTemp_C += getTankNodeTemp(ind, UNITS_C); weight -= 1.0; ind += 1; } // Check any leftover - if (weight > 0.) { + if (weight > 0.) + { averageTemp_C += getTankNodeTemp(ind, UNITS_C) * weight; } // Divide by the original weight to get the true average averageTemp_C /= ((double)numNodes / (double)nTCouple); - if (units == UNITS_C) { + if (units == UNITS_C) + { return averageTemp_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(averageTemp_C); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getNthSimTcouple. \n"); } return double(HPWH_ABORT); @@ -2041,7 +2322,8 @@ int HPWH::getCompressorIndex() const { return compressorIndex; } int HPWH::getNumResistanceElements() const { int count = 0; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { count += setOfSources[i].isAResistance() ? 1 : 0; } return count; @@ -2057,33 +2339,41 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, double capTemp_BTUperHr, inputTemp_BTUperHr, copTemp; // temporary variables double airTemp_C, inletTemp_C, outTemp_C; - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return double(HPWH_ABORT); } - if (tempUnit == UNITS_C) { + if (tempUnit == UNITS_C) + { airTemp_C = airTemp; inletTemp_C = inletTemp; outTemp_C = outTemp; } - else if (tempUnit == UNITS_F) { + else if (tempUnit == UNITS_F) + { airTemp_C = F_TO_C(airTemp); inletTemp_C = F_TO_C(inletTemp); outTemp_C = F_TO_C(outTemp); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for temperatures in getCompressorCapacity. \n"); } return double(HPWH_ABORT); } if (airTemp_C < setOfSources[compressorIndex].minT || - airTemp_C > setOfSources[compressorIndex].maxT) { - if (hpwhVerbosity >= VRB_reluctant) { + airTemp_C > setOfSources[compressorIndex].maxT) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The compress does not operate at the specified air temperature. \n"); } return double(HPWH_ABORT); @@ -2092,29 +2382,36 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, double maxAllowedSetpoint_C = setOfSources[compressorIndex].maxSetpoint_C - setOfSources[compressorIndex].secondaryHeatExchanger.hotSideTemperatureOffset_dC; - if (outTemp_C > maxAllowedSetpoint_C) { - if (hpwhVerbosity >= VRB_reluctant) { + if (outTemp_C > maxAllowedSetpoint_C) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Inputted outlet temperature of the compressor is higher than can be produced."); } return double(HPWH_ABORT); } - if (setOfSources[compressorIndex].isExternalMultipass()) { + if (setOfSources[compressorIndex].isExternalMultipass()) + { double averageTemp_C = (outTemp_C + inletTemp_C) / 2.; setOfSources[compressorIndex].getCapacityMP( airTemp_C, averageTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); } - else { + else + { setOfSources[compressorIndex].getCapacity( airTemp_C, inletTemp_C, outTemp_C, inputTemp_BTUperHr, capTemp_BTUperHr, copTemp); } double outputCapacity = capTemp_BTUperHr; - if (pwrUnit == UNITS_KW) { + if (pwrUnit == UNITS_KW) + { outputCapacity = BTU_TO_KWH(capTemp_BTUperHr); } - else if (pwrUnit != UNITS_BTUperHr) { - if (hpwhVerbosity >= VRB_reluctant) { + else if (pwrUnit != UNITS_BTUperHr) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for capacity in getCompressorCapacity. \n"); } return double(HPWH_ABORT); @@ -2126,25 +2423,32 @@ double HPWH::getCompressorCapacity(double airTemp /*=19.722*/, double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) const { // energy used by the heat source is positive - this should always be positive - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (N >= numHeatSources || N < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the energy input of a heat source that does not " "exist. \n"); } return double(HPWH_ABORT); } - if (units == UNITS_KWH) { + if (units == UNITS_KWH) + { return setOfSources[N].energyInput_kWh; } - else if (units == UNITS_BTU) { + else if (units == UNITS_BTU) + { return KWH_TO_BTU(setOfSources[N].energyInput_kWh); } - else if (units == UNITS_KJ) { + else if (units == UNITS_KJ) + { return KWH_TO_KJ(setOfSources[N].energyInput_kWh); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); } return double(HPWH_ABORT); @@ -2153,25 +2457,32 @@ double HPWH::getNthHeatSourceEnergyInput(int N, UNITS units /*=UNITS_KWH*/) cons double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) const { // returns energy from the heat source into the water - this should always be positive - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (N >= numHeatSources || N < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the energy output of a heat source that does not " "exist. \n"); } return double(HPWH_ABORT); } - if (units == UNITS_KWH) { + if (units == UNITS_KWH) + { return setOfSources[N].energyOutput_kWh; } - else if (units == UNITS_BTU) { + else if (units == UNITS_BTU) + { return KWH_TO_BTU(setOfSources[N].energyOutput_kWh); } - else if (units == UNITS_KJ) { + else if (units == UNITS_KJ) + { return KWH_TO_KJ(setOfSources[N].energyOutput_kWh); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getNthHeatSourceEnergyInput. \n"); } return double(HPWH_ABORT); @@ -2180,8 +2491,10 @@ double HPWH::getNthHeatSourceEnergyOutput(int N, UNITS units /*=UNITS_KWH*/) con double HPWH::getNthHeatSourceRunTime(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (N >= numHeatSources || N < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the run time of a heat source that does not exist. " "\n"); } @@ -2192,25 +2505,31 @@ double HPWH::getNthHeatSourceRunTime(int N) const int HPWH::isNthHeatSourceRunning(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (N >= numHeatSources || N < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the status of a heat source that does not exist. " "\n"); } return HPWH_ABORT; } - if (setOfSources[N].isEngaged()) { + if (setOfSources[N].isEngaged()) + { return 1; } - else { + else + { return 0; } } HPWH::HEATSOURCE_TYPE HPWH::getNthHeatSourceType(int N) const { - if (N >= numHeatSources || N < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (N >= numHeatSources || N < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You have attempted to access the type of a heat source that does not exist. \n"); } return HEATSOURCE_TYPE(HPWH_ABORT); @@ -2220,14 +2539,18 @@ HPWH::HEATSOURCE_TYPE HPWH::getNthHeatSourceType(int N) const double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const { - if (units == UNITS_L) { + if (units == UNITS_L) + { return tankVolume_L; } - else if (units == UNITS_GAL) { + else if (units == UNITS_GAL) + { return L_TO_GAL(tankVolume_L); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getTankSize. \n"); } return HPWH_ABORT; @@ -2236,14 +2559,18 @@ double HPWH::getTankSize(UNITS units /*=UNITS_L*/) const double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { + if (units == UNITS_C) + { return outletTemp_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(outletTemp_C); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getOutletTemp. \n"); } return double(HPWH_ABORT); @@ -2252,14 +2579,18 @@ double HPWH::getOutletTemp(UNITS units /*=UNITS_C*/) const double HPWH::getCondenserWaterInletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { + if (units == UNITS_C) + { return condenserInlet_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(condenserInlet_C); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); } return double(HPWH_ABORT); @@ -2268,14 +2599,18 @@ double HPWH::getCondenserWaterInletTemp(UNITS units /*=UNITS_C*/) const double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const { - if (units == UNITS_C) { + if (units == UNITS_C) + { return condenserOutlet_C; } - else if (units == UNITS_F) { + else if (units == UNITS_F) + { return C_TO_F(condenserOutlet_C); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getCondenserWaterInletTemp. \n"); } return double(HPWH_ABORT); @@ -2284,14 +2619,18 @@ double HPWH::getCondenserWaterOutletTemp(UNITS units /*=UNITS_C*/) const double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const { - if (units == UNITS_L) { + if (units == UNITS_L) + { return externalVolumeHeated_L; } - else if (units == UNITS_GAL) { + else if (units == UNITS_GAL) + { return L_TO_GAL(externalVolumeHeated_L); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getExternalVolumeHeated. \n"); } return double(HPWH_ABORT); @@ -2301,17 +2640,22 @@ double HPWH::getExternalVolumeHeated(UNITS units /*=UNITS_L*/) const double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const { // moving heat from the space to the water is the positive direction - if (units == UNITS_KWH) { + if (units == UNITS_KWH) + { return energyRemovedFromEnvironment_kWh; } - else if (units == UNITS_BTU) { + else if (units == UNITS_BTU) + { return KWH_TO_BTU(energyRemovedFromEnvironment_kWh); } - else if (units == UNITS_KJ) { + else if (units == UNITS_KJ) + { return KWH_TO_KJ(energyRemovedFromEnvironment_kWh); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getEnergyRemovedFromEnvironment. \n"); } return double(HPWH_ABORT); @@ -2321,17 +2665,22 @@ double HPWH::getEnergyRemovedFromEnvironment(UNITS units /*=UNITS_KWH*/) const double HPWH::getStandbyLosses(UNITS units /*=UNITS_KWH*/) const { // moving heat from the water to the space is the positive direction - if (units == UNITS_KWH) { + if (units == UNITS_KWH) + { return standbyLosses_kWh; } - else if (units == UNITS_BTU) { + else if (units == UNITS_BTU) + { return KWH_TO_BTU(standbyLosses_kWh); } - else if (units == UNITS_KJ) { + else if (units == UNITS_KJ) + { return KWH_TO_KJ(standbyLosses_kWh); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getStandbyLosses. \n"); } return double(HPWH_ABORT); @@ -2344,7 +2693,8 @@ double HPWH::getTankHeatContent_kJ() const // get average tank temperature double avgTemp = 0.0; - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { avgTemp += tankTemps_C[i]; } avgTemp /= numNodes; @@ -2358,8 +2708,10 @@ double HPWH::getLocationTemp_C() const { return locationTemperature_C; } int HPWH::getHPWHModel() const { return hpwhModel; } int HPWH::getCompressorCoilConfig() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return HPWH_ABORT; @@ -2368,8 +2720,10 @@ int HPWH::getCompressorCoilConfig() const } bool HPWH::isCompressorMultipass() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return HPWH_ABORT; @@ -2378,8 +2732,10 @@ bool HPWH::isCompressorMultipass() const } bool HPWH::isCompressoExternalMultipass() const { - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return HPWH_ABORT; @@ -2391,8 +2747,10 @@ bool HPWH::hasACompressor() const { return compressorIndex >= 0; } bool HPWH::hasExternalHeatSource() const { - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) + { return true; } } @@ -2401,21 +2759,27 @@ bool HPWH::hasExternalHeatSource() const double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const { - if (!isCompressoExternalMultipass()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isCompressoExternalMultipass()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Does not have an external multipass heat source \n"); } return HPWH_ABORT; } - if (units == HPWH::UNITS_LPS) { + if (units == HPWH::UNITS_LPS) + { return setOfSources[compressorIndex].mpFlowRate_LPS; } - else if (units == HPWH::UNITS_GPM) { + else if (units == HPWH::UNITS_GPM) + { return LPS_TO_GPM(setOfSources[compressorIndex].mpFlowRate_LPS); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getExternalMPFlowRate. \n"); } return (double)HPWH_ABORT; @@ -2425,27 +2789,35 @@ double HPWH::getExternalMPFlowRate(UNITS units /*=UNITS_GPM*/) const double HPWH::getCompressorMinRuntime(UNITS units /*=UNITS_MIN*/) const { - if (hasACompressor()) { + if (hasACompressor()) + { double min_minutes = 10.; - if (units == UNITS_MIN) { + if (units == UNITS_MIN) + { return min_minutes; } - else if (units == UNITS_SEC) { + else if (units == UNITS_SEC) + { return MIN_TO_SEC(min_minutes); } - else if (units == UNITS_HR) { + else if (units == UNITS_HR) + { return MIN_TO_HR(min_minutes); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for getCompressorMinRunTime. \n"); } return (double)HPWH_ABORT; } } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("This HPWH has no compressor. \n"); } return (double)HPWH_ABORT; @@ -2457,14 +2829,18 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const double aFract = 1.; double useFract = 1.; - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return HPWH_ABORT; } - else if (usesSoCLogic) { - if (hpwhVerbosity >= VRB_reluctant) { + else if (usesSoCLogic) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model uses SOC control logic and does not have a definition for sizing " "fractions. \n"); } @@ -2472,10 +2848,12 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const } // Every compressor must have at least one on logic - for (std::shared_ptr onLogic : setOfSources[compressorIndex].turnOnLogicSet) { + for (std::shared_ptr onLogic : setOfSources[compressorIndex].turnOnLogicSet) + { double tempA; - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("\tturnon logic: %s ", onLogic->description.c_str()); } tempA = onLogic->nodeWeightAvgFract(); // if standby logic will return 1 @@ -2484,20 +2862,24 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const aquaFract = aFract; // Compressors don't need to have an off logic - if (setOfSources[compressorIndex].shutOffLogicSet.size() != 0) { - for (std::shared_ptr offLogic : - setOfSources[compressorIndex].shutOffLogicSet) { + if (setOfSources[compressorIndex].shutOffLogicSet.size() != 0) + { + for (std::shared_ptr offLogic : setOfSources[compressorIndex].shutOffLogicSet) + { double tempUse; - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg("\tshutsOff logic: %s ", offLogic->description.c_str()); } - if (offLogic->description == "large draw" || offLogic->description == "larger draw") { + if (offLogic->description == "large draw" || offLogic->description == "larger draw") + { tempUse = 1.; // These logics are just for checking if there's a big draw to switch to RE } - else { + else + { tempUse = 1. - offLogic->nodeWeightAvgFract(); } useFract = @@ -2506,8 +2888,10 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const } useableFract = useFract; } - else { - if (hpwhVerbosity >= VRB_emetic) { + else + { + if (hpwhVerbosity >= VRB_emetic) + { msg("\no shutoff logics present"); } useableFract = 1.; @@ -2516,7 +2900,8 @@ int HPWH::getSizingFractions(double& aquaFract, double& useableFract) const // Check if double's are approximately equally and adjust the relationship so it follows the // relationship we expect. The tolerance plays with 0.1 mm in position if the tank is 1m tall... double temp = 1. - useableFract; - if (aboutEqual(aquaFract, temp)) { + if (aboutEqual(aquaFract, temp)) + { useableFract = 1. - aquaFract + TOL_MINVALUE; } @@ -2527,34 +2912,43 @@ bool HPWH::isHPWHScalable() const { return canScale; } int HPWH::setScaleHPWHCapacityCOP(double scaleCapacity /*=1.0*/, double scaleCOP /*=1.0*/) { - if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isHPWHScalable()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not scale the HPWH Capacity or COP \n"); } return HPWH_ABORT; } - if (!hasACompressor()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!hasACompressor()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Current model does not have a compressor. \n"); } return HPWH_ABORT; } - if (scaleCapacity <= 0 || scaleCOP <= 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (scaleCapacity <= 0 || scaleCOP <= 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not scale the HPWH Capacity or COP to 0 or less than 0 \n"); } return HPWH_ABORT; } - for (auto& perfP : setOfSources[compressorIndex].perfMap) { - if (scaleCapacity != 1.) { + for (auto& perfP : setOfSources[compressorIndex].perfMap) + { + if (scaleCapacity != 1.) + { std::transform( perfP.inputPower_coeffs.begin(), perfP.inputPower_coeffs.end(), perfP.inputPower_coeffs.begin(), std::bind(std::multiplies(), std::placeholders::_1, scaleCapacity)); } - if (scaleCOP != 1.) { + if (scaleCOP != 1.) + { std::transform(perfP.COP_coeffs.begin(), perfP.COP_coeffs.end(), perfP.COP_coeffs.begin(), @@ -2574,7 +2968,8 @@ int HPWH::setCompressorOutputCapacity(double newCapacity, { double oldCapacity = getCompressorCapacity(airTemp, inletTemp, outTemp, pwrUnit, tempUnit); - if (oldCapacity == double(HPWH_ABORT)) { + if (oldCapacity == double(HPWH_ABORT)) + { return HPWH_ABORT; } @@ -2586,61 +2981,79 @@ int HPWH::setResistanceCapacity(double power, int which /*=-1*/, UNITS pwrUnit / { // Input checks - if (!isHPWHScalable()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isHPWHScalable()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not scale the resistance elements \n"); } return HPWH_ABORT; } - if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (getNumResistanceElements() == 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("There are no resistance elements to set capacity for \n"); } return HPWH_ABORT; } - if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (which < -1 || which > getNumResistanceElements() - 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds value for which in setResistanceCapacity()\n"); } return HPWH_ABORT; } - if (power < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (power < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Can not have a negative input power \n"); } return HPWH_ABORT; } // Unit conversion double watts; - if (pwrUnit == UNITS_KW) { + if (pwrUnit == UNITS_KW) + { watts = power * 1000; // kW to W } - else if (pwrUnit == UNITS_BTUperHr) { + else if (pwrUnit == UNITS_BTUperHr) + { watts = BTU_TO_KWH(power) * 1000; // BTU to kW then kW to W } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for capacity in setResistanceCapacity. \n"); } return HPWH_ABORT; } // Whew so many checks... - if (which == -1) { + if (which == -1) + { // Just get all the elements - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isAResistance()) + { setOfSources[i].changeResistanceWatts(watts); } } } - else { + else + { setOfSources[resistanceHeightMap[which].index].changeResistanceWatts(watts); // Then check for repeats in the position int pos = resistanceHeightMap[which].position; - for (int i = 0; i < getNumResistanceElements(); i++) { - if (which != i && resistanceHeightMap[i].position == pos) { + for (int i = 0; i < getNumResistanceElements(); i++) + { + if (which != i && resistanceHeightMap[i].position == pos) + { setOfSources[resistanceHeightMap[i].index].changeResistanceWatts(watts); } } @@ -2653,37 +3066,47 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* { // Input checks - if (getNumResistanceElements() == 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (getNumResistanceElements() == 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("There are no resistance elements to return capacity for \n"); } return HPWH_ABORT; } - if (which < -1 || which > getNumResistanceElements() - 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (which < -1 || which > getNumResistanceElements() - 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds value for which in getResistanceCapacity()\n"); } return HPWH_ABORT; } double returnPower = 0; - if (which == -1) { + if (which == -1) + { // Just get all the elements - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isAResistance()) + { returnPower += setOfSources[i].perfMap[0].inputPower_coeffs[0]; } } } - else { + else + { // get the power from "which" element by height returnPower += setOfSources[resistanceHeightMap[which].index].perfMap[0].inputPower_coeffs[0]; // Then check for repeats in the position int pos = resistanceHeightMap[which].position; - for (int i = 0; i < getNumResistanceElements(); i++) { - if (which != i && resistanceHeightMap[i].position == pos) { + for (int i = 0; i < getNumResistanceElements(); i++) + { + if (which != i && resistanceHeightMap[i].position == pos) + { returnPower += setOfSources[resistanceHeightMap[i].index].perfMap[0].inputPower_coeffs[0]; } @@ -2691,14 +3114,18 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* } // Unit conversion - if (pwrUnit == UNITS_KW) { + if (pwrUnit == UNITS_KW) + { returnPower /= 1000.; // W to KW } - else if (pwrUnit == UNITS_BTUperHr) { + else if (pwrUnit == UNITS_BTUperHr) + { returnPower = KWH_TO_BTU(returnPower / 1000.); // W to BTU/hr } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect unit specification for capacity in getResistanceCapacity. \n"); } return HPWH_ABORT; @@ -2710,23 +3137,28 @@ double HPWH::getResistanceCapacity(int which /*=-1*/, UNITS pwrUnit /*=UNITS_KW* int HPWH::getResistancePosition(int elementIndex) const { - if (elementIndex < 0 || elementIndex > numHeatSources - 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (elementIndex < 0 || elementIndex > numHeatSources - 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds value for which in getResistancePosition\n"); } return HPWH_ABORT; } - if (!setOfSources[elementIndex].isAResistance()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!setOfSources[elementIndex].isAResistance()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("This index is not a resistance element\n"); } return HPWH_ABORT; } - for (int i = 0; i < CONDENSITY_SIZE; i++) { - if (setOfSources[elementIndex].condensity[i] == - 1) { // res elements have a condenstiy of 1 at a specific node + for (int i = 0; i < CONDENSITY_SIZE; i++) + { + if (setOfSources[elementIndex].condensity[i] == 1) + { // res elements have a condenstiy of 1 at a specific node return i; } } @@ -2746,11 +3178,14 @@ void HPWH::updateTankTemps(double drawVolume_L, double nodeInletFraction, cumInletFraction, drawVolume_N; double nodeInletTV = 0.; - if (drawVolume_L > 0.) { + if (drawVolume_L > 0.) + { // calculate how many nodes to draw (wholeNodesToDraw), and the remainder (drawFraction) - if (inletVol2_L > drawVolume_L) { - if (hpwhVerbosity >= VRB_reluctant) { + if (inletVol2_L > drawVolume_L) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Volume in inlet 2 is greater than the draw volume. \n"); } simHasFailed = true; @@ -2762,7 +3197,8 @@ void HPWH::updateTankTemps(double drawVolume_L, double highInletV, highInletT; int lowInletH; double lowInletT, lowInletV; - if (inletHeight > inlet2Height) { + if (inletHeight > inlet2Height) + { highInletH = inletHeight; highInletV = drawVolume_L - inletVol2_L; highInletT = inletT_C; @@ -2770,7 +3206,8 @@ void HPWH::updateTankTemps(double drawVolume_L, lowInletT = inletT2_C; lowInletV = inletVol2_L; } - else { + else + { highInletH = inlet2Height; highInletV = inletVol2_L; highInletT = inletT2_C; @@ -2780,15 +3217,17 @@ void HPWH::updateTankTemps(double drawVolume_L, } // calculate how many nodes to draw (drawVolume_N) drawVolume_N = drawVolume_L / volPerNode_LperNode; - if (drawVolume_L > tankVolume_L) { + if (drawVolume_L > tankVolume_L) + { // if (hpwhVerbosity >= 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"); + // Terminating simulation. \n"); msg("WARNING: Drawing more than the tank volume in + // one step is undefined behavior. Continuing simulation at your own risk. \n"); // } // simHasFailed = true; // return; - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { outletTemp_C += tankTemps_C[i]; tankTemps_C[i] = (inletT_C * (drawVolume_L - inletVol2_L) + inletT2_C * inletVol2_L) / @@ -2803,7 +3242,8 @@ void HPWH::updateTankTemps(double drawVolume_L, ///////////////////////////////////////////////////////////////////////////////////////////////// - while (drawVolume_N > 0) { + while (drawVolume_N > 0) + { // Draw one node at a time drawFraction = drawVolume_N > 1. ? 1. : drawVolume_N; @@ -2812,18 +3252,21 @@ void HPWH::updateTankTemps(double drawVolume_L, outletTemp_C += drawFraction * tankTemps_C[numNodes - 1]; cumInletFraction = 0.; - for (int i = numNodes - 1; i >= lowInletH; i--) { + for (int i = numNodes - 1; i >= lowInletH; i--) + { // Reset inlet inputs at this node. nodeInletFraction = 0.; nodeInletTV = 0.; // Sum of all inlets Vi*Ti at this node - if (i == highInletH) { + if (i == highInletH) + { nodeInletTV += highInletV * drawFraction / drawVolume_L * highInletT; nodeInletFraction += highInletV * drawFraction / drawVolume_L; } - if (i == lowInletH) { + if (i == lowInletH) + { nodeInletTV += lowInletV * drawFraction / drawVolume_L * lowInletT; nodeInletFraction += lowInletV * drawFraction / drawVolume_L; @@ -2855,22 +3298,26 @@ void HPWH::updateTankTemps(double drawVolume_L, ///////////////////////////////////////////////////////////////////////////////////////////////// // Account for mixing at the bottom of the tank - if (tankMixesOnDraw && drawVolume_L > 0.) { + if (tankMixesOnDraw && drawVolume_L > 0.) + { int mixedBelowNode = (int)(numNodes * mixBelowFractionOnDraw); mixTankNodes(0, mixedBelowNode, 3.0); } } // end if(draw_volume_L > 0) - if (doConduction) { + if (doConduction) + { // Get the "constant" tau for the stability condition and the conduction calculation const double tau = KWATER_WpermC / (CPWATER_kJperkgC * 1000.0 * DENSITYWATER_kgperL * 1000.0 * (node_height * node_height)) * minutesPerStep * 60.0; - if (tau > 0.5) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tau > 0.5) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The stability condition for conduction has failed, these results are going to " "be interesting!\n"); } @@ -2888,7 +3335,8 @@ void HPWH::updateTankTemps(double drawVolume_L, 2.0 * tau * tankTemps_C[numNodes - 2] + bc * tankAmbientT_C; // Internal nodes for the finite difference - for (int i = 1; i < numNodes - 1; i++) { + for (int i = 1; i < numNodes - 1; i++) + { nextTankTemps_C[i] = tankTemps_C[i] + tau * (tankTemps_C[i + 1] - 2.0 * tankTemps_C[i] + tankTemps_C[i - 1]); } @@ -2902,10 +3350,12 @@ void HPWH::updateTankTemps(double drawVolume_L, (minutesPerStep / 60.0)); standbyLosses_kWh += KJ_TO_KWH(standbyLosses_kJ); } - else { // Ignore tank conduction and calculate UA losses from top and bottom. UA loss from the - // sides are found at the bottom of the function + else + { // Ignore tank conduction and calculate UA losses from top and bottom. UA loss from the + // sides are found at the bottom of the function - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { nextTankTemps_C[i] = tankTemps_C[i]; } @@ -2928,7 +3378,8 @@ void HPWH::updateTankTemps(double drawVolume_L, } // calculate standby losses from the sides of the tank - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; i++) + { // faction of tank area on the sides // kJ's lost as standby in the current time step for each node. double standbyLosses_kJ = (tankUA_kJperHrC * fracAreaSide + fittingsUA_kJperHrC) / @@ -2952,7 +3403,8 @@ void HPWH::updateTankTemps(double drawVolume_L, void HPWH::updateSoCIfNecessary() { - if (usesSoCLogic) { + if (usesSoCLogic) + { calcAndSetSoCFraction(); } } @@ -2963,12 +3415,16 @@ void HPWH::mixTankInversions() bool hasInversion; const double volumePerNode_L = tankVolume_L / numNodes; // int numdos = 0; - if (doInversionMixing) { - do { + if (doInversionMixing) + { + do + { hasInversion = false; // Start from the top and check downwards - for (int i = numNodes - 1; i > 0; i--) { - if (tankTemps_C[i] < tankTemps_C[i - 1]) { + for (int i = numNodes - 1; i > 0; i--) + { + if (tankTemps_C[i] < tankTemps_C[i - 1]) + { // Temperature inversion! hasInversion = true; @@ -2977,10 +3433,12 @@ void HPWH::mixTankInversions() double Tmixed = 0.0; double massMixed = 0.0; int m; - for (m = i; m >= 0; m--) { + for (m = i; m >= 0; m--) + { Tmixed += tankTemps_C[m] * (volumePerNode_L * DENSITYWATER_kgperL); massMixed += (volumePerNode_L * DENSITYWATER_kgperL); - if ((m == 0) || (Tmixed / massMixed > tankTemps_C[m - 1])) { + if ((m == 0) || (Tmixed / massMixed > tankTemps_C[m - 1])) + { break; } } @@ -2998,8 +3456,10 @@ void HPWH::mixTankInversions() void HPWH::addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbientT_C) { - if ((*nodePowerExtra_W).size() > CONDENSITY_SIZE) { - if (hpwhVerbosity >= VRB_reluctant) { + if ((*nodePowerExtra_W).size() > CONDENSITY_SIZE) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("nodeExtraHeat_KWH (%i) has size greater than %d \n", (*nodePowerExtra_W).size(), CONDENSITY_SIZE); @@ -3013,8 +3473,10 @@ void HPWH::addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbien // } // mixTankInversions(); - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].typeOfHeatSource == TYPE_extra) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].typeOfHeatSource == TYPE_extra) + { // Set up the extra heat source setOfSources[i].setupExtraHeat(nodePowerExtra_W); @@ -3036,7 +3498,8 @@ void HPWH::addExtraHeat(std::vector* nodePowerExtra_W, double tankAmbien void HPWH::turnAllHeatSourcesOff() { - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i].disengageHeatSource(); } isHeating = false; @@ -3045,8 +3508,10 @@ void HPWH::turnAllHeatSourcesOff() bool HPWH::areAllHeatSourcesOff() const { bool allOff = true; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isEngaged() == true) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isEngaged() == true) + { allOff = false; } } @@ -3058,19 +3523,24 @@ double HPWH::tankAvg_C(const std::vector nodeWeights) const double sum = 0; double totWeight = 0; - for (NodeWeight nodeWeight : nodeWeights) { + for (NodeWeight nodeWeight : nodeWeights) + { // bottom calc node only - if (nodeWeight.nodeNum == 0) { + if (nodeWeight.nodeNum == 0) + { sum += tankTemps_C[0] * nodeWeight.weight; totWeight += nodeWeight.weight; } // top calc node only - else if (nodeWeight.nodeNum == 13) { + else if (nodeWeight.nodeNum == 13) + { sum += tankTemps_C[numNodes - 1] * nodeWeight.weight; totWeight += nodeWeight.weight; } - else { - for (int n = 0; n < nodeDensity; ++n) { + else + { + for (int n = 0; n < nodeDensity; ++n) + { int calcNode = (nodeWeight.nodeNum - 1) * nodeDensity + n; sum += tankTemps_C[calcNode] * nodeWeight.weight; totWeight += nodeWeight.weight; @@ -3084,12 +3554,14 @@ void HPWH::mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor { double ave = 0.; double numAvgNodes = (double)(mixedBelowNode - mixedAboveNode); - for (int i = mixedAboveNode; i < mixedBelowNode; i++) { + for (int i = mixedAboveNode; i < mixedBelowNode; i++) + { ave += tankTemps_C[i]; } ave /= numAvgNodes; - for (int i = mixedAboveNode; i < mixedBelowNode; i++) { + for (int i = mixedAboveNode; i < mixedBelowNode; i++) + { tankTemps_C[i] += ((ave - tankTemps_C[i]) / mixFactor); // tankTemps_C[i] = tankTemps_C[i] * (1.0 - 1.0 / mixFactor) + ave / mixFactor; } @@ -3137,15 +3609,18 @@ HPWH::HeatSource::HeatSource(const HeatSource& hSource) isVIP = hSource.isVIP; if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || - hSource.followedByHeatSource != NULL) { + hSource.followedByHeatSource != NULL) + { hpwh->simHasFailed = true; - if (hpwh->hpwhVerbosity >= VRB_reluctant) { + if (hpwh->hpwhVerbosity >= VRB_reluctant) + { hpwh->msg( "HeatSources cannot be copied if they contain pointers to other HeatSources\n"); } } - for (int i = 0; i < CONDENSITY_SIZE; i++) { + for (int i = 0; i < CONDENSITY_SIZE; i++) + { condensity[i] = hSource.condensity[i]; } shrinkage = hSource.shrinkage; @@ -3190,7 +3665,8 @@ HPWH::HeatSource::HeatSource(const HeatSource& hSource) HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource& hSource) { - if (this == &hSource) { + if (this == &hSource) + { return *this; } @@ -3206,20 +3682,24 @@ HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource& hSource) isVIP = hSource.isVIP; if (hSource.backupHeatSource != NULL || hSource.companionHeatSource != NULL || - hSource.followedByHeatSource != NULL) { + hSource.followedByHeatSource != NULL) + { hpwh->simHasFailed = true; - if (hpwh->hpwhVerbosity >= VRB_reluctant) { + if (hpwh->hpwhVerbosity >= VRB_reluctant) + { hpwh->msg( "HeatSources cannot be copied if they contain pointers to other HeatSources\n"); } } - else { + else + { companionHeatSource = NULL; backupHeatSource = NULL; followedByHeatSource = NULL; } - for (int i = 0; i < CONDENSITY_SIZE; i++) { + for (int i = 0; i < CONDENSITY_SIZE; i++) + { condensity[i] = hSource.condensity[i]; } shrinkage = hSource.shrinkage; @@ -3292,8 +3772,10 @@ void HPWH::HeatSource::setCondensity(double cnd1, int HPWH::HeatSource::findParent() const { - for (int i = 0; i < hpwh->numHeatSources; ++i) { - if (this == hpwh->setOfSources[i].backupHeatSource) { + for (int i = 0; i < hpwh->numHeatSources; ++i) + { + if (this == hpwh->setOfSources[i].backupHeatSource) + { return i; } } @@ -3312,25 +3794,31 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const { // if it's already locked out, keep it locked out - if (isLockedOut() == true) { + if (isLockedOut() == true) + { return true; } - else { + else + { // when the "external" temperature is too cold - typically used for compressor low temp. // cutoffs when running, use hysteresis bool lock = false; - if (isEngaged() == true && heatSourceAmbientT_C < minT - hysteresis_dC) { + if (isEngaged() == true && heatSourceAmbientT_C < minT - hysteresis_dC) + { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + { hpwh->msg("\tlock-out: running below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); } } // when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C < minT) { + else if (isEngaged() == false && heatSourceAmbientT_C < minT) + { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + { hpwh->msg("\tlock-out: already below minT\tambient: %.2f\tminT: %.2f", heatSourceAmbientT_C, minT); @@ -3339,38 +3827,45 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const // when the "external" temperature is too warm - typically used for resistance lockout // when running, use hysteresis - if (isEngaged() == true && heatSourceAmbientT_C > maxT + hysteresis_dC) { + if (isEngaged() == true && heatSourceAmbientT_C > maxT + hysteresis_dC) + { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + { hpwh->msg("\tlock-out: running above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); } } // when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C > maxT) { + else if (isEngaged() == false && heatSourceAmbientT_C > maxT) + { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) + { hpwh->msg("\tlock-out: already above maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); } } - if (maxedOut()) { + if (maxedOut()) + { lock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { + if (hpwh->hpwhVerbosity >= 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) { // hpwh->msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. - //Simulation will continue without lock-out"); + // Simulation will continue without lock-out"); // } // lock = false; // } - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("\n"); } return lock; @@ -3381,49 +3876,58 @@ bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const { // if it's already unlocked, keep it unlocked - if (isLockedOut() == false) { + if (isLockedOut() == false) + { return true; } // if it the heat source is capped and can't produce hotter water - else if (maxedOut()) { + else if (maxedOut()) + { return false; } - else { + else + { // when the "external" temperature is no longer too cold or too warm // when running, use hysteresis bool unlock = false; if (isEngaged() == true && heatSourceAmbientT_C > minT + hysteresis_dC && - heatSourceAmbientT_C < maxT - hysteresis_dC) { + heatSourceAmbientT_C < maxT - hysteresis_dC) + { unlock = true; if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && - heatSourceAmbientT_C > minT + hysteresis_dC) { + 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) { + heatSourceAmbientT_C < maxT - hysteresis_dC) + { hpwh->msg("\tunlock: running below maxT\tambient: %.2f\tmaxT: %.2f", heatSourceAmbientT_C, maxT); } } // when not running, don't use hysteresis - else if (isEngaged() == false && heatSourceAmbientT_C > minT && - heatSourceAmbientT_C < maxT) { + else if (isEngaged() == false && heatSourceAmbientT_C > minT && heatSourceAmbientT_C < maxT) + { unlock = true; - if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic && heatSourceAmbientT_C > minT) { + if (hpwh->hpwhVerbosity >= 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->hpwhVerbosity >= 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->hpwhVerbosity >= VRB_typical) + { hpwh->msg("\n"); } return unlock; @@ -3433,10 +3937,12 @@ bool HPWH::HeatSource::shouldUnlock(double heatSourceAmbientT_C) const bool HPWH::HeatSource::toLockOrUnlock(double heatSourceAmbientT_C) { - if (shouldLockOut(heatSourceAmbientT_C)) { + if (shouldLockOut(heatSourceAmbientT_C)) + { lockOutHeatSource(); } - if (shouldUnlock(heatSourceAmbientT_C)) { + if (shouldUnlock(heatSourceAmbientT_C)) + { unlockHeatSource(); } @@ -3446,10 +3952,12 @@ bool HPWH::HeatSource::toLockOrUnlock(double heatSourceAmbientT_C) bool HPWH::shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const { - if (hs == TYPE_compressor && (DR_signal & DR_LOC) != 0) { + if (hs == TYPE_compressor && (DR_signal & DR_LOC) != 0) + { return true; } - else if (hs == TYPE_resistance && (DR_signal & DR_LOR) != 0) { + else if (hs == TYPE_resistance && (DR_signal & DR_LOR) != 0) + { return true; } return false; @@ -3463,7 +3971,8 @@ void HPWH::HeatSource::engageHeatSource(DRMODES DR_signal) hpwh->isHeating = true; if (companionHeatSource != NULL && companionHeatSource->shutsOff() != true && companionHeatSource->isEngaged() == false && - hpwh->shouldDRLockOut(companionHeatSource->typeOfHeatSource, DR_signal) == false) { + hpwh->shouldDRLockOut(companionHeatSource->typeOfHeatSource, DR_signal) == false) + { companionHeatSource->engageHeatSource(DR_signal); } } @@ -3476,35 +3985,44 @@ bool HPWH::HeatSource::shouldHeat() const // or if an unsepcified selector was used bool shouldEngage = false; - for (int i = 0; i < (int)turnOnLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < (int)turnOnLogicSet.size(); i++) + { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("\tshouldHeat logic: %s ", turnOnLogicSet[i]->description.c_str()); } double average = turnOnLogicSet[i]->getTankValue(); double comparison = turnOnLogicSet[i]->getComparisonValue(); - if (turnOnLogicSet[i]->compare(average, comparison)) { - if (turnOnLogicSet[i]->description == "standby" && standbyLogic != NULL) { + if (turnOnLogicSet[i]->compare(average, comparison)) + { + if (turnOnLogicSet[i]->description == "standby" && standbyLogic != NULL) + { double comparisonStandby = standbyLogic->getComparisonValue(); double avgStandby = standbyLogic->getTankValue(); - if (turnOnLogicSet[i]->compare(avgStandby, comparisonStandby)) { + if (turnOnLogicSet[i]->compare(avgStandby, comparisonStandby)) + { shouldEngage = true; } } - else { + else + { shouldEngage = true; } } // quit searching the logics if one of them turns it on - if (shouldEngage) { + if (shouldEngage) + { // debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("engages!\n"); } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("average: %.2lf \t setpoint: %.2lf \t decisionPoint: %.2lf \t " "comparison: %2.1f\n", average, @@ -3515,20 +4033,24 @@ bool HPWH::HeatSource::shouldHeat() const break; } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("returns: %d \t", shouldEngage); } } // end loop over set of logic conditions // if everything else wants it to come on, but if it would shut off anyways don't turn it on - if (shouldEngage == true && shutsOff() == true) { + if (shouldEngage == true && shutsOff() == true) + { shouldEngage = false; - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("but is denied by shutsOff"); } } - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("\n"); } return shouldEngage; @@ -3538,33 +4060,40 @@ bool HPWH::HeatSource::shutsOff() const { bool shutOff = false; - if (hpwh->tankTemps_C[0] >= hpwh->setpoint_C) { + if (hpwh->tankTemps_C[0] >= hpwh->setpoint_C) + { shutOff = true; - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("shutsOff bottom node hot: %.2d C \n returns true", hpwh->tankTemps_C[0]); } return shutOff; } - for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < (int)shutOffLogicSet.size(); i++) + { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); } double average = shutOffLogicSet[i]->getTankValue(); double comparison = shutOffLogicSet[i]->getComparisonValue(); - if (shutOffLogicSet[i]->compare(average, comparison)) { + if (shutOffLogicSet[i]->compare(average, comparison)) + { shutOff = true; // debugging message handling - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("shuts down %s\n", shutOffLogicSet[i]->description.c_str()); } } } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("returns: %d \n", shutOff); } return shutOff; @@ -3576,8 +4105,10 @@ bool HPWH::HeatSource::maxedOut() const // If the heat source can't produce water at the setpoint and the control logics are saying to // shut off - if (hpwh->setpoint_C > maxSetpoint_C) { - if (hpwh->tankTemps_C[0] >= maxSetpoint_C || shutsOff()) { + if (hpwh->setpoint_C > maxSetpoint_C) + { + if (hpwh->tankTemps_C[0] >= maxSetpoint_C || shutsOff()) + { maxed = true; } } @@ -3589,8 +4120,10 @@ double HPWH::HeatSource::fractToMeetComparisonExternal() const double fracTemp; double frac = 1.; - for (int i = 0; i < (int)shutOffLogicSet.size(); i++) { - if (hpwh->hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < (int)shutOffLogicSet.size(); i++) + { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("\tshutsOff logic: %s ", shutOffLogicSet[i]->description.c_str()); } @@ -3609,9 +4142,11 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) // set the leftover capacity of the Heat Source to 0, so the first round of // passing it on works - switch (configuration) { + switch (configuration) + { case CONFIG_SUBMERGED: - case CONFIG_WRAPPED: { + case CONFIG_WRAPPED: + { static std::vector heatDistribution(hpwh->numNodes); // clear the heatDistribution vector, since it's static it is still holding the // distribution from the last go around @@ -3619,19 +4154,22 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) // calcHeatDist takes care of the swooping for wrapped configurations calcHeatDist(heatDistribution); - if (isACompressor()) { + if (isACompressor()) + { hpwh->condenserInlet_C = getCondenserTemp(); } // calculate capacity btu/hr, input btu/hr, and cop getCapacity(externalT_C, getCondenserTemp(), input_BTUperHr, cap_BTUperHr, cop); // some outputs for debugging - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("capacity_kWh %.2lf \t\t cap_BTUperHr %.2lf \n", BTU_TO_KWH(cap_BTUperHr) * (minutesToRun) / 60.0, cap_BTUperHr); } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("heatDistribution: %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf %4.3lf " "%4.3lf %4.3lf %4.3lf %4.3lf \n", heatDistribution[0], @@ -3650,17 +4188,20 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) // the loop over nodes here is intentional - essentially each node that has // some amount of heatDistribution acts as a separate resistive element // maybe start from the top and go down? test this with graphs - for (int i = hpwh->numNodes - 1; i >= 0; i--) { + for (int i = hpwh->numNodes - 1; i >= 0; i--) + { // for(int i = 0; i < hpwh->numNodes; i++){ captmp_kJ = BTU_TO_KJ(cap_BTUperHr * minutesToRun / 60.0 * heatDistribution[i]); - if (captmp_kJ != 0) { + if (captmp_kJ != 0) + { // add leftoverCap to the next run, and keep passing it on leftoverCap_kJ = addHeatAboveNode(captmp_kJ + leftoverCap_kJ, i); } } - if (isACompressor()) { // outlet temperature is the condenser temperature after heat has - // been added + if (isACompressor()) + { // outlet temperature is the condenser temperature after heat has + // been added hpwh->condenserOutlet_C = getCondenserTemp(); } @@ -3672,7 +4213,8 @@ void HPWH::HeatSource::addHeat(double externalT_C, double minutesToRun) if (hpwh->hpwhVerbosity >= VRB_reluctant) hpwh->msg("Internal error: Negative runtime = %0.3f min\n", runtime_min); #endif - } break; + } + break; case CONFIG_EXTERNAL: // Else the heat source is external. SANCO2 system is only current example @@ -3692,8 +4234,8 @@ void HPWH::HeatSource::sortPerformanceMap() { std::sort(perfMap.begin(), perfMap.end(), - [](const HPWH::HeatSource::perfPoint& a, - const HPWH::HeatSource::perfPoint& b) -> bool { return a.T_F < b.T_F; }); + [](const HPWH::HeatSource::perfPoint& a, const HPWH::HeatSource::perfPoint& b) -> bool + { return a.T_F < b.T_F; }); } double HPWH::HeatSource::expitFunc(double x, double offset) @@ -3708,18 +4250,23 @@ void HPWH::HeatSource::normalize(std::vector& distribution) double sum_tmp = 0.0; size_t N = distribution.size(); - for (size_t i = 0; i < N; i++) { + for (size_t i = 0; i < N; i++) + { sum_tmp += distribution[i]; } - for (size_t i = 0; i < N; i++) { - if (sum_tmp > 0.0) { + for (size_t i = 0; i < N; i++) + { + if (sum_tmp > 0.0) + { distribution[i] /= sum_tmp; } - else { + else + { distribution[i] = 0.0; } // this gives a very slight speed improvement (milliseconds per simulated year) - if (distribution[i] < TOL_MINVALUE) { + if (distribution[i] < TOL_MINVALUE) + { distribution[i] = 0; } } @@ -3731,14 +4278,17 @@ double HPWH::HeatSource::getCondenserTemp() const int tempNodesPerCondensityNode = hpwh->numNodes / CONDENSITY_SIZE; int j = 0; - for (int i = 0; i < hpwh->numNodes; i++) { + for (int i = 0; i < hpwh->numNodes; i++) + { j = i / tempNodesPerCondensityNode; - if (condensity[j] != 0) { + if (condensity[j] != 0) + { condenserTemp_C += (condensity[j] / tempNodesPerCondensityNode) * hpwh->tankTemps_C[i]; // the weights don't need to be added to divide out later because they should always sum // to 1 - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("condenserTemp_C:\t %.2lf \ti:\t %d \tj\t %d \tcondensity[j]:\t %.2lf " "\ttankTemps_C[i]:\t %.2lf\n", condenserTemp_C, @@ -3749,7 +4299,8 @@ double HPWH::HeatSource::getCondenserTemp() const } } } - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("condenser temp %.2lf \n", condenserTemp_C); } return condenserTemp_C; @@ -3775,31 +4326,40 @@ void HPWH::HeatSource::getCapacity(double externalT_C, size_t i_next = 1; double Tout_F = C_TO_F(setpointTemp_C + secondaryHeatExchanger.hotSideTemperatureOffset_dC); - if (useBtwxtGrid) { + if (useBtwxtGrid) + { std::vector target {externalT_F, Tout_F, condenserTemp_F}; btwxtInterp(input_BTUperHr, cop, target); } - else { - if (perfMap.size() > 1) { + else + { + if (perfMap.size() > 1) + { double COP_T1, COP_T2; // cop at ambient temperatures T1 and T2 double inputPower_T1_Watts, inputPower_T2_Watts; // input power at ambient temperatures T1 and T2 - for (size_t i = 0; i < perfMap.size(); ++i) { - if (externalT_F < perfMap[i].T_F) { - if (i == 0) { + for (size_t i = 0; i < perfMap.size(); ++i) + { + if (externalT_F < perfMap[i].T_F) + { + if (i == 0) + { extrapolate = true; i_prev = 0; i_next = 1; } - else { + else + { i_prev = i - 1; i_next = i; } break; } - else { - if (i == perfMap.size() - 1) { + else + { + if (i == perfMap.size() - 1) + { extrapolate = true; i_prev = i - 1; i_next = i; @@ -3827,7 +4387,8 @@ 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->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("inputPower_T1_constant_W linear_WperF quadratic_WperF2 \t%.2lf " "%.2lf %.2lf \n", perfMap[0].inputPower_coeffs[0], @@ -3842,7 +4403,8 @@ void HPWH::HeatSource::getCapacity(double externalT_C, inputPower_T1_Watts, inputPower_T2_Watts); - if (extrapolate) { + if (extrapolate) + { hpwh->msg("Warning performance extrapolation\n\tExternal Temperature: " "%.2lf\tNearest temperatures: %.2lf, %.2lf \n\n", externalT_F, @@ -3862,10 +4424,13 @@ void HPWH::HeatSource::getCapacity(double externalT_C, inputPower_T2_Watts); input_BTUperHr = KWH_TO_BTU(input_BTUperHr / 1000.0); // 1000 converts w to kw); } - else { // perfMap.size() == 1 or we've got an issue. - if (externalT_F > perfMap[0].T_F) { + else + { // perfMap.size() == 1 or we've got an issue. + if (externalT_F > perfMap[0].T_F) + { extrapolate = true; - if (extrapolationMethod == EXTRAP_NEAREST) { + if (extrapolationMethod == EXTRAP_NEAREST) + { externalT_F = perfMap[0].T_F; } } @@ -3878,14 +4443,16 @@ void HPWH::HeatSource::getCapacity(double externalT_C, } } - if (doDefrost) { + if (doDefrost) + { // adjust COP by the defrost factor defrostDerate(cop, externalT_F); } cap_BTUperHr = cop * input_BTUperHr; - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("externalT_F: %.2lf, Tout_F: %.2lf, condenserTemp_F: %.2lf\n", externalT_F, Tout_F, @@ -3900,19 +4467,23 @@ void HPWH::HeatSource::getCapacity(double externalT_C, // that is based on the flow rate. The equation is a fit to three points, // measured experimentally - 12 percent reduction at 150 cfm, 10 percent at // 200, and 0 at 375. Flow is expressed as fraction of full flow. - if (airflowFreedom != 1) { + if (airflowFreedom != 1) + { double airflow = 375 * airflowFreedom; cop *= 0.00056 * airflow + 0.79; } - if (hpwh->hpwhVerbosity >= VRB_typical) { + if (hpwh->hpwhVerbosity >= VRB_typical) + { hpwh->msg("cop: %.2lf \tinput_BTUperHr: %.2lf \tcap_BTUperHr: %.2lf \n", cop, input_BTUperHr, cap_BTUperHr); - if (cop < 0.) { + if (cop < 0.) + { hpwh->msg(" Warning: COP is Negative! \n"); } - if (cop < 1.) { + if (cop < 1.) + { hpwh->msg(" Warning: COP is Less than 1! \n"); } } @@ -3931,23 +4502,29 @@ void HPWH::HeatSource::getCapacityMP(double externalT_C, externalT_F = C_TO_F(externalT_C); // Check if we have resistance elements to turn on for defrost and add the constant lift. - if (resDefrost.inputPwr_kW > 0) { - if (externalT_F < resDefrost.onBelowT_F) { + if (resDefrost.inputPwr_kW > 0) + { + if (externalT_F < resDefrost.onBelowT_F) + { externalT_F += resDefrost.constTempLift_dF; resDefrostHeatingOn = true; } } - if (useBtwxtGrid) { + if (useBtwxtGrid) + { std::vector target {externalT_F, condenserTemp_F}; btwxtInterp(input_BTUperHr, cop, target); } - else { + else + { // Get bounding performance map points for interpolation/extrapolation bool extrapolate = false; - if (externalT_F > perfMap[0].T_F) { + if (externalT_F > perfMap[0].T_F) + { extrapolate = true; - if (extrapolationMethod == EXTRAP_NEAREST) { + if (extrapolationMethod == EXTRAP_NEAREST) + { externalT_F = perfMap[0].T_F; } } @@ -3959,7 +4536,8 @@ void HPWH::HeatSource::getCapacityMP(double externalT_C, } input_BTUperHr = KWH_TO_BTU(input_BTUperHr); - if (doDefrost) { + if (doDefrost) + { // adjust COP by the defrost factor defrostDerate(cop, externalT_F); } @@ -3967,10 +4545,12 @@ void HPWH::HeatSource::getCapacityMP(double externalT_C, cap_BTUperHr = cop * input_BTUperHr; // For accounting add the resistance defrost to the input energy - if (resDefrostHeatingOn) { + if (resDefrostHeatingOn) + { input_BTUperHr += KW_TO_BTUperH(resDefrost.inputPwr_kW); } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= 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", input_BTUperHr, @@ -3996,14 +4576,17 @@ void HPWH::HeatSource::setupDefrostMap(double derate35 /*=0.8865*/) void HPWH::HeatSource::defrostDerate(double& to_derate, double airT_F) { - if (airT_F <= defrostMap[0].T_F || airT_F >= defrostMap[defrostMap.size() - 1].T_F) { + if (airT_F <= defrostMap[0].T_F || airT_F >= defrostMap[defrostMap.size() - 1].T_F) + { return; // Air temperature outside bounds of the defrost map. There is no extrapolation // here. } double derate_factor = 1.; size_t i_prev = 0; - for (size_t i = 1; i < defrostMap.size(); ++i) { - if (airT_F <= defrostMap[i].T_F) { + for (size_t i = 1; i < defrostMap.size(); ++i) + { + if (airT_F <= defrostMap[i].T_F) + { i_prev = i - 1; break; } @@ -4055,20 +4638,25 @@ void HPWH::HeatSource::calcHeatDist(std::vector& heatDistribution) { // Populate the vector of heat distribution - for (int i = 0; i < hpwh->numNodes; i++) { - if (i < lowestNode) { + for (int i = 0; i < hpwh->numNodes; i++) + { + if (i < lowestNode) + { heatDistribution.push_back(0); } - else { + else + { int k; - if (configuration == CONFIG_SUBMERGED) { // Inside the tank, no swoopiness required + if (configuration == CONFIG_SUBMERGED) + { // Inside the tank, no swoopiness required // intentional integer division k = i / int(hpwh->numNodes / CONDENSITY_SIZE); heatDistribution.push_back(condensity[k]); } - else if (configuration == CONFIG_WRAPPED) { // Wrapped around the tank, send through the - // logistic function - double temp = 0; // temp for temporary not temperature + else if (configuration == CONFIG_WRAPPED) + { // Wrapped around the tank, send through the + // logistic function + double temp = 0; // temp for temporary not temperature double offset = 5.0 / 1.8; temp = expitFunc((hpwh->tankTemps_C[i] - hpwh->tankTemps_C[lowestNode]) / this->shrinkage, @@ -4093,34 +4681,42 @@ double HPWH::HeatSource::addHeatAboveNode(double cap_kJ, int node) double volumePerNode_L = hpwh->tankVolume_L / hpwh->numNodes; double maxTargetTemp_C = std::min(maxSetpoint_C, hpwh->setpoint_C); - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("node %2d cap_kwh %.4lf \n", node, KJ_TO_KWH(cap_kJ)); } // find the first node (from the bottom) that does not have the same temperature as the one // above it if they all have the same temp., use the top node, hpwh->numNodes-1 setPointNodeNum = node; - for (int i = node; i < hpwh->numNodes - 1; i++) { - if (hpwh->tankTemps_C[i] != hpwh->tankTemps_C[i + 1]) { + for (int i = node; i < hpwh->numNodes - 1; i++) + { + if (hpwh->tankTemps_C[i] != hpwh->tankTemps_C[i + 1]) + { break; } - else { + else + { setPointNodeNum = i + 1; } } // maximum heat deliverable in this timestep - while (cap_kJ > 0 && setPointNodeNum < hpwh->numNodes) { + while (cap_kJ > 0 && setPointNodeNum < hpwh->numNodes) + { // if the whole tank is at the same temp, the target temp is the setpoint - if (setPointNodeNum == (hpwh->numNodes - 1)) { + if (setPointNodeNum == (hpwh->numNodes - 1)) + { targetTemp_C = maxTargetTemp_C; } // otherwise the target temp is the first non-equal-temp node - else { + else + { targetTemp_C = hpwh->tankTemps_C[setPointNodeNum + 1]; } // With DR tomfoolery make sure the target temperature doesn't exceed the setpoint. - if (targetTemp_C > maxTargetTemp_C) { + if (targetTemp_C > maxTargetTemp_C) + { targetTemp_C = maxTargetTemp_C; } @@ -4131,15 +4727,18 @@ double HPWH::HeatSource::addHeatAboveNode(double cap_kJ, int node) (setPointNodeNum + 1 - node) * deltaT_C; // Running the rest of the time won't recover - if (Q_kJ > cap_kJ) { - for (int j = node; j <= setPointNodeNum; j++) { + if (Q_kJ > cap_kJ) + { + for (int j = node; j <= setPointNodeNum; j++) + { hpwh->tankTemps_C[j] += cap_kJ / CPWATER_kJperkgC / volumePerNode_L / DENSITYWATER_kgperL / (setPointNodeNum + 1 - node); } cap_kJ = 0; } #if defined(SETPOINT_FIX) - else if (Q_kJ > 0.) { // temp will recover by/before end of timestep + else if (Q_kJ > 0.) + { // temp will recover by/before end of timestep for (int j = node; j <= setPointNodeNum; j++) hpwh->tankTemps_C[j] = targetTemp_C; cap_kJ -= Q_kJ; @@ -4147,8 +4746,10 @@ double HPWH::HeatSource::addHeatAboveNode(double cap_kJ, int node) setPointNodeNum++; #else // temp will recover by/before end of timestep - else { - for (int j = node; j <= setPointNodeNum; j++) { + else + { + for (int j = node; j <= setPointNodeNum; j++) + { hpwh->tankTemps_C[j] = targetTemp_C; } setPointNodeNum++; @@ -4185,12 +4786,15 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, cap_BTUperHr = 0; cop = 0; - do { - if (hpwh->hpwhVerbosity >= VRB_emetic) { + do + { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("bottom tank temp: %.2lf \n", hpwh->tankTemps_C[0]); } - if (this->isMultipass) { + if (this->isMultipass) + { // if multipass evenly mix the tank up hpwh->mixTankNodes( 0, hpwh->numNodes, 1.0); // 1.0 will give even mixing, so all temperatures mixed end @@ -4209,7 +4813,8 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, targetTemp_C = calcMPOutletTemperature(heatingCapacity_KW); deltaT_C = targetTemp_C - hpwh->tankTemps_C[externalOutletHeight]; } - else { + else + { // how much heat is available this timestep getCapacity(externalT_C, hpwh->tankTemps_C[externalOutletHeight], @@ -4217,13 +4822,15 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, capTemp_BTUperHr, copTemp); heatingCapacity_kJ = BTU_TO_KJ(capTemp_BTUperHr * (minutesToRun / 60.0)); - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= 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->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("\theatingCapacity_kJ remaining this node: %.2lf \n", heatingCapacity_kJ); } @@ -4237,22 +4844,25 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, volumePerNode_LperNode * DENSITYWATER_kgperL * CPWATER_kJperkgC * deltaT_C; // Caclulate fraction of node to move - if (nodeHeat_kJperNode <= 0.) { // protect against dividing by zero - if bottom node is at - // (or above) setpoint, add no heat + if (nodeHeat_kJperNode <= 0.) + { // protect against dividing by zero - if bottom node is at + // (or above) setpoint, add no heat nodeFrac = 0.; } - else { + else + { nodeFrac = heatingCapacity_kJ / nodeHeat_kJperNode; } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg( "nodeHeat_kJperNode: %.2lf nodeFrac: %.2lf \n\n", nodeHeat_kJperNode, nodeFrac); } fractToShutOff = fractToMeetComparisonExternal(); - if (fractToShutOff < 1. && fractToShutOff < nodeFrac && - !this->isMultipass) { // circle back and check on this for multipass + if (fractToShutOff < 1. && fractToShutOff < nodeFrac && !this->isMultipass) + { // circle back and check on this for multipass nodeFrac = fractToShutOff; heatingCapacityNeeded_kJ = nodeFrac * nodeHeat_kJperNode; @@ -4261,21 +4871,24 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, } // if more than one, round down to 1 and subtract the amount of time it would // take to heat that node from the timeRemaining - else if (nodeFrac > 1.) { + else if (nodeFrac > 1.) + { nodeFrac = 1.; timeUsed_min = (nodeHeat_kJperNode / heatingCapacity_kJ) * timeRemaining_min; timeRemaining_min -= timeUsed_min; } // otherwise just the fraction available // this should make heatingCapacity == 0 if nodeFrac < 1 - else { + else + { timeUsed_min = timeRemaining_min; timeRemaining_min = 0.; } // Track the condenser temperature if this is a compressor before moving the nodes // ////////////////////////////////////////// - if (isACompressor()) { + if (isACompressor()) + { hpwh->condenserInlet_C += hpwh->tankTemps_C[externalOutletHeight] * timeUsed_min; hpwh->condenserOutlet_C += targetTemp_C * timeUsed_min; } @@ -4283,7 +4896,8 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, // Moving the nodes down // //////////////////////////////////////////////////////////////////////////////////////////////////// // move all nodes down, mixing if less than a full node - for (int n = externalOutletHeight; n < externalInletHeight; n++) { + for (int n = externalOutletHeight; n < externalInletHeight; n++) + { hpwh->tankTemps_C[n] = hpwh->tankTemps_C[n] * (1 - nodeFrac) + hpwh->tankTemps_C[n + 1] * nodeFrac; } @@ -4313,7 +4927,8 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, // not timeRemaining_min == minutesToRun is possible // must prevent divide by 0 (added 4-11-2023) double timeRun = minutesToRun - timeRemaining_min; - if (timeRun > 0.) { + if (timeRun > 0.) + { input_BTUperHr /= timeRun; cap_BTUperHr /= timeRun; cop /= timeRun; @@ -4321,7 +4936,8 @@ double HPWH::HeatSource::addHeatExternal(double externalT_C, hpwh->condenserOutlet_C /= timeRun; } - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("final remaining time: %.2lf \n", timeRemaining_min); } // return the time left @@ -4334,7 +4950,8 @@ void HPWH::HeatSource::setupAsResistiveElement(int node, double Watts) isOn = false; isVIP = false; - for (i = 0; i < CONDENSITY_SIZE; i++) { + for (i = 0; i < CONDENSITY_SIZE; i++) + { condensity[i] = 0; } condensity[node] = 1; @@ -4364,7 +4981,8 @@ void HPWH::HeatSource::setupExtraHeat(std::vector* nodePowerExtra_W) std::vector tempCondensity(CONDENSITY_SIZE); double watts = 0.0; - for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++) { + for (unsigned int i = 0; i < (*nodePowerExtra_W).size(); i++) + { // get sum of vector watts += (*nodePowerExtra_W)[i]; @@ -4374,9 +4992,11 @@ void HPWH::HeatSource::setupExtraHeat(std::vector* nodePowerExtra_W) normalize(tempCondensity); - if (hpwh->hpwhVerbosity >= VRB_emetic) { + if (hpwh->hpwhVerbosity >= VRB_emetic) + { hpwh->msg("extra heat condensity: "); - for (unsigned int i = 0; i < tempCondensity.size(); i++) { + for (unsigned int i = 0; i < tempCondensity.size(); i++) + { hpwh->msg("C[%d]: %f", i, tempCondensity[i]); } hpwh->msg("\n "); @@ -4432,7 +5052,8 @@ void HPWH::HeatSource::clearAllLogic() void HPWH::HeatSource::changeResistanceWatts(double watts) { - for (auto& perfP : perfMap) { + for (auto& perfP : perfMap) + { perfP.inputPower_coeffs[0] = watts; } } @@ -4472,11 +5093,14 @@ void HPWH::calcDerivedValues() mapResRelativePosToSetOfSources(); // heat source ability to depress temp - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isACompressor()) + { setOfSources[i].depressesTemperature = true; } - else if (setOfSources[i].isAResistance()) { + else if (setOfSources[i].isAResistance()) + { setOfSources[i].depressesTemperature = false; } } @@ -4489,48 +5113,59 @@ void HPWH::calcDerivedHeatingValues() // condentropy/shrinkage double condentropy = 0; double alpha = 1, beta = 2; // Mapping from condentropy to shrinkage - for (int i = 0; i < numHeatSources; i++) { - if (hpwhVerbosity >= VRB_emetic) { + for (int i = 0; i < numHeatSources; i++) + { + if (hpwhVerbosity >= VRB_emetic) + { msg(outputString, "Heat Source %d \n", i); } // Calculate condentropy and ==> shrinkage condentropy = 0; - for (int j = 0; j < CONDENSITY_SIZE; j++) { - if (setOfSources[i].condensity[j] > 0) { + for (int j = 0; j < CONDENSITY_SIZE; j++) + { + if (setOfSources[i].condensity[j] > 0) + { condentropy -= setOfSources[i].condensity[j] * log(setOfSources[i].condensity[j]); if (hpwhVerbosity >= VRB_emetic) msg(outputString, "condentropy %.2lf \n", condentropy); } } setOfSources[i].shrinkage = alpha + condentropy * beta; - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg(outputString, "shrinkage %.2lf \n\n", setOfSources[i].shrinkage); } } // lowest node int lowest = 0; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { lowest = 0; - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg(outputString, "Heat Source %d \n", i); } - for (int j = 0; j < numNodes; j++) { - if (hpwhVerbosity >= VRB_emetic) { + for (int j = 0; j < numNodes; j++) + { + if (hpwhVerbosity >= VRB_emetic) + { msg(outputString, "j: %d j/ (numNodes/CONDENSITY_SIZE) %d \n", j, j / (numNodes / CONDENSITY_SIZE)); } - if (setOfSources[i].condensity[(j / (numNodes / CONDENSITY_SIZE))] > 0) { + if (setOfSources[i].condensity[(j / (numNodes / CONDENSITY_SIZE))] > 0) + { lowest = j; break; } } - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= VRB_emetic) + { msg(outputString, " lowest : %d \n", lowest); } @@ -4545,50 +5180,65 @@ void HPWH::calcDerivedHeatingValues() int lowestElementPos = CONDENSITY_SIZE; int highestElementPos = 0; // -1 to make sure a an element on the bottom can still be identified. - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isACompressor()) + { compressorIndex = i; // NOTE: Maybe won't work with multiple compressors (last // compressor will be used) } - else if (setOfSources[i].isAResistance()) { + else if (setOfSources[i].isAResistance()) + { // Gets VIP element index - if (setOfSources[i].isVIP) { - if (VIPIndex == -1) { + if (setOfSources[i].isVIP) + { + if (VIPIndex == -1) + { VIPIndex = i; } - else { - if (hpwhVerbosity >= VRB_minuteOut) { + else + { + if (hpwhVerbosity >= VRB_minuteOut) + { msg("More than one resistance element is assigned to VIP"); }; } } - for (int j = 0; j < CONDENSITY_SIZE; j++) { - if (setOfSources[i].condensity[j] > 0.0 && j < lowestElementPos) { + for (int j = 0; j < CONDENSITY_SIZE; j++) + { + if (setOfSources[i].condensity[j] > 0.0 && j < lowestElementPos) + { lowestElementIndex = i; lowestElementPos = j; } - if (setOfSources[i].condensity[j] > 0.0 && j >= highestElementPos) { + if (setOfSources[i].condensity[j] > 0.0 && j >= highestElementPos) + { highestElementIndex = i; highestElementPos = j; } } } } - if (hpwhVerbosity >= VRB_emetic) { + if (hpwhVerbosity >= 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 (hpwhVerbosity >= VRB_emetic) + { msg(outputString, " VIPIndex : %d \n", VIPIndex); } // heat source ability to depress temp - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isACompressor()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isACompressor()) + { setOfSources[i].depressesTemperature = true; } - else if (setOfSources[i].isAResistance()) { + else if (setOfSources[i].isAResistance()) + { setOfSources[i].depressesTemperature = false; } } @@ -4599,8 +5249,10 @@ void HPWH::mapResRelativePosToSetOfSources() resistanceHeightMap.clear(); resistanceHeightMap.reserve(getNumResistanceElements()); - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isAResistance()) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isAResistance()) + { resistanceHeightMap.push_back({i, getResistancePosition(i)}); } } @@ -4608,7 +5260,8 @@ void HPWH::mapResRelativePosToSetOfSources() // Sort by height, low to high std::sort(resistanceHeightMap.begin(), resistanceHeightMap.end(), - [](const HPWH::resPoint& a, const HPWH::resPoint& b) -> bool { + [](const HPWH::resPoint& a, const HPWH::resPoint& b) -> bool + { return a.position < b.position; // (5 < 5) // evaluates to false }); } @@ -4619,14 +5272,18 @@ int HPWH::checkInputs() int returnVal = 0; // use a returnVal so that all checks are processed and error messages written - if (numHeatSources <= 0 && hpwhModel != MODELS_StorageTank) { - if (hpwhVerbosity >= VRB_reluctant) { + if (numHeatSources <= 0 && hpwhModel != MODELS_StorageTank) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("You must have at least one HeatSource.\n"); } returnVal = HPWH_ABORT; } - if ((numNodes % 12) != 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if ((numNodes % 12) != 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The number of nodes must be a multiple of 12"); } returnVal = HPWH_ABORT; @@ -4634,10 +5291,13 @@ int HPWH::checkInputs() double condensitySum; // loop through all heat sources to check each for malconfigurations - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { // check the heat source type to make sure it has been set - if (setOfSources[i].typeOfHeatSource == TYPE_none) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].typeOfHeatSource == TYPE_none) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Heat source %d does not have a specified type. Initialization failed.\n", i); } returnVal = HPWH_ABORT; @@ -4645,8 +5305,10 @@ int HPWH::checkInputs() // check to make sure there is at least one onlogic or parent with onlogic int parent = setOfSources[i].findParent(); if (setOfSources[i].turnOnLogicSet.size() == 0 && - (parent == -1 || setOfSources[parent].turnOnLogicSet.size() == 0)) { - if (hpwhVerbosity >= VRB_reluctant) { + (parent == -1 || setOfSources[parent].turnOnLogicSet.size() == 0)) + { + if (hpwhVerbosity >= 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."); } @@ -4654,19 +5316,25 @@ int HPWH::checkInputs() } // Validate on logics - for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) { - if (!logic->isValid()) { + for (std::shared_ptr logic : setOfSources[i].turnOnLogicSet) + { + if (!logic->isValid()) + { returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) { + if (hpwhVerbosity >= VRB_reluctant) + { msg("On logic at index %i is invalid", i); } } } // Validate off logics - for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) { - if (!logic->isValid()) { + for (std::shared_ptr logic : setOfSources[i].shutOffLogicSet) + { + if (!logic->isValid()) + { returnVal = HPWH_ABORT; - if (hpwhVerbosity >= VRB_reluctant) { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Off logic at index %i is invalid", i); } } @@ -4676,67 +5344,87 @@ int HPWH::checkInputs() condensitySum = 0; for (int j = 0; j < CONDENSITY_SIZE; j++) condensitySum += setOfSources[i].condensity[j]; - if (fabs(condensitySum - 1.0) > 1e-6) { - if (hpwhVerbosity >= VRB_reluctant) { + if (fabs(condensitySum - 1.0) > 1e-6) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The condensity for heatsource %d does not sum to 1. \n", i); msg("It sums to %f \n", condensitySum); } returnVal = HPWH_ABORT; } // check that air flows are all set properly - if (setOfSources[i].airflowFreedom > 1.0 || setOfSources[i].airflowFreedom <= 0.0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].airflowFreedom > 1.0 || setOfSources[i].airflowFreedom <= 0.0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The airflowFreedom must be between 0 and 1 for heatsource %d. \n", i); } returnVal = HPWH_ABORT; } - if (setOfSources[i].isACompressor()) { - if (setOfSources[i].doDefrost) { - if (setOfSources[i].defrostMap.size() < 3) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].isACompressor()) + { + if (setOfSources[i].doDefrost) + { + if (setOfSources[i].defrostMap.size() < 3) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Defrost logic set to true but no valid defrost map of length 3 or " "greater set. \n"); } returnVal = HPWH_ABORT; } - if (setOfSources[i].configuration != HeatSource::CONFIG_EXTERNAL) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].configuration != HeatSource::CONFIG_EXTERNAL) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Defrost is only simulated for external compressors. \n"); } returnVal = HPWH_ABORT; } } } - if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) { + if (setOfSources[i].configuration == HeatSource::CONFIG_EXTERNAL) + { - if (setOfSources[i].shutOffLogicSet.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].shutOffLogicSet.size() != 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("External heat sources can only have one shut off logic. \n "); } returnVal = HPWH_ABORT; } if (0 > setOfSources[i].externalOutletHeight || - setOfSources[i].externalOutletHeight > numNodes - 1) { - if (hpwhVerbosity >= VRB_reluctant) { + setOfSources[i].externalOutletHeight > numNodes - 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("External heat sources need an external outlet height within the bounds " "from from 0 to numNodes-1. \n"); } returnVal = HPWH_ABORT; } if (0 > setOfSources[i].externalInletHeight || - setOfSources[i].externalInletHeight > numNodes - 1) { - if (hpwhVerbosity >= VRB_reluctant) { + setOfSources[i].externalInletHeight > numNodes - 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("External heat sources need an external inlet height within the bounds " "from from 0 to numNodes-1. \n"); } returnVal = HPWH_ABORT; } } - else { + else + { if (setOfSources[i].secondaryHeatExchanger.extraPumpPower_W != 0 || - setOfSources[i].secondaryHeatExchanger.extraPumpPower_W) { - if (hpwhVerbosity >= VRB_reluctant) { + setOfSources[i].secondaryHeatExchanger.extraPumpPower_W) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Heatsource %d is not an external heat source but has an external " "secondary heat exchanger. \n", i); @@ -4748,10 +5436,13 @@ int HPWH::checkInputs() // Check performance map // perfGrid and perfGridValues, and the length of vectors in perfGridValues are equal and // that ; - if (setOfSources[i].useBtwxtGrid) { + if (setOfSources[i].useBtwxtGrid) + { // If useBtwxtGrid is true that the perfMap is empty - if (setOfSources[i].perfMap.size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].perfMap.size() != 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Using the grid lookups but a regression based perforamnce map is given " "\n"); } @@ -4761,8 +5452,10 @@ int HPWH::checkInputs() // Check length of vectors in perfGridValue are equal if (setOfSources[i].perfGridValues[0].size() != setOfSources[i].perfGridValues[1].size() && - setOfSources[i].perfGridValues[0].size() != 0) { - if (hpwhVerbosity >= VRB_reluctant) { + setOfSources[i].perfGridValues[0].size() != 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("When using grid lookups for perfmance the vectors in perfGridValues must " "be the same length. \n"); } @@ -4772,21 +5465,27 @@ int HPWH::checkInputs() // Check perfGrid's vectors lengths multiplied together == the perfGridValues vector // lengths size_t expLength = 1; - for (const auto& v : setOfSources[i].perfGrid) { + for (const auto& v : setOfSources[i].perfGrid) + { expLength *= v.size(); } - if (expLength != setOfSources[i].perfGridValues[0].size()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (expLength != setOfSources[i].perfGridValues[0].size()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("When using grid lookups for perfmance the vectors in perfGridValues must " "be the same length. \n"); } returnVal = HPWH_ABORT; } } - else { + else + { // Check that perfmap only has 1 point if config_external and multipass - if (setOfSources[i].isExternalMultipass() && setOfSources[i].perfMap.size() != 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (setOfSources[i].isExternalMultipass() && setOfSources[i].perfMap.size() != 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("External multipass heat sources must have a perfMap of only one point " "with regression equations. \n"); } @@ -4796,11 +5495,14 @@ int HPWH::checkInputs() } // Check that the on logic and off logics are ordered properly - if (hasACompressor()) { + if (hasACompressor()) + { double aquaF = 0., useF = 1.; getSizingFractions(aquaF, useF); - if (aquaF < (1. - useF)) { - if (hpwhVerbosity >= VRB_reluctant) { + if (aquaF < (1. - useF)) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The relationship between the on logic and off logic is not supported. The off " "logic is beneath the on logic."); } @@ -4811,16 +5513,20 @@ int HPWH::checkInputs() double maxTemp; string why; double tempSetpoint = setpoint_C; - if (!isNewSetpointPossible(tempSetpoint, maxTemp, why)) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!isNewSetpointPossible(tempSetpoint, maxTemp, why)) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Cannot set new setpoint. %s", why.c_str()); } returnVal = HPWH_ABORT; } // Check if the UA is out of bounds - if (tankUA_kJperHrC < 0.0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tankUA_kJperHrC < 0.0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("The tankUA_kJperHrC is less than 0 for a HPWH, it must be greater than 0, " "tankUA_kJperHrC is: %f \n", tankUA_kJperHrC); @@ -4843,8 +5549,10 @@ int HPWH::HPWHinit_file(string configFile) // open file, check and report errors std::ifstream inputFILE; inputFILE.open(configFile.c_str()); - if (!inputFILE.is_open()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (!inputFILE.is_open()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Input file failed to open. \n"); } return HPWH_ABORT; @@ -4859,91 +5567,116 @@ int HPWH::HPWHinit_file(string configFile) string line_s; std::stringstream line_ss; string token; - while (std::getline(inputFILE, line_s)) { + while (std::getline(inputFILE, line_s)) + { line_ss.clear(); line_ss.str(line_s); // grab the first word, and start comparing line_ss >> token; - if (token.at(0) == '#' || line_s.empty()) { + if (token.at(0) == '#' || line_s.empty()) + { // if you hit a comment, skip to next line continue; } - else if (token == "numNodes") { + else if (token == "numNodes") + { line_ss >> numNodes; } - else if (token == "volume") { + else if (token == "volume") + { line_ss >> tempDouble >> units; if (units == "gal") tempDouble = GAL_TO_L(tempDouble); else if (units == "L") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s. \n", token.c_str()); } return HPWH_ABORT; } tankVolume_L = tempDouble; } - else if (token == "UA") { + else if (token == "UA") + { line_ss >> tempDouble >> units; - if (units != "kJperHrC") { - if (hpwhVerbosity >= VRB_reluctant) { + if (units != "kJperHrC") + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s. \n", token.c_str()); } return HPWH_ABORT; } tankUA_kJperHrC = tempDouble; } - else if (token == "depressTemp") { + else if (token == "depressTemp") + { line_ss >> tempString; - if (tempString == "true") { + if (tempString == "true") + { doTempDepression = true; } - else if (tempString == "false") { + else if (tempString == "false") + { doTempDepression = false; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper value for %s\n", token.c_str()); } return HPWH_ABORT; } } - else if (token == "mixOnDraw") { + else if (token == "mixOnDraw") + { line_ss >> tempString; - if (tempString == "true") { + if (tempString == "true") + { tankMixesOnDraw = true; } - else if (tempString == "false") { + else if (tempString == "false") + { tankMixesOnDraw = false; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper value for %s\n", token.c_str()); } return HPWH_ABORT; } } - else if (token == "mixBelowFractionOnDraw") { + else if (token == "mixBelowFractionOnDraw") + { line_ss >> tempDouble; - if (tempDouble < 0 || tempDouble > 1) { - if (hpwhVerbosity >= VRB_reluctant) { + if (tempDouble < 0 || tempDouble > 1) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Out of bounds value for %s. Should be between 0 and 1. \n", token.c_str()); } return HPWH_ABORT; } mixBelowFractionOnDraw = tempDouble; } - else if (token == "setpoint") { + else if (token == "setpoint") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = F_TO_C(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s. \n", token.c_str()); } return HPWH_ABORT; @@ -4951,63 +5684,80 @@ int HPWH::HPWHinit_file(string configFile) setpoint_C = tempDouble; // tank will be set to setpoint at end of function } - else if (token == "setpointFixed") { + else if (token == "setpointFixed") + { line_ss >> tempString; if (tempString == "true") setpointFixed = true; else if (tempString == "false") setpointFixed = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper value for %s\n", token.c_str()); } return HPWH_ABORT; } } - else if (token == "verbosity") { + else if (token == "verbosity") + { line_ss >> token; - if (token == "silent") { + if (token == "silent") + { hpwhVerbosity = VRB_silent; } - else if (token == "reluctant") { + else if (token == "reluctant") + { hpwhVerbosity = VRB_reluctant; } - else if (token == "typical") { + else if (token == "typical") + { hpwhVerbosity = VRB_typical; } - else if (token == "emetic") { + else if (token == "emetic") + { hpwhVerbosity = VRB_emetic; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect verbosity on input. \n"); } return HPWH_ABORT; } } - else if (token == "numHeatSources") { + else if (token == "numHeatSources") + { line_ss >> numHeatSources; setOfSources = new HeatSource[numHeatSources]; - for (int i = 0; i < numHeatSources; i++) { + for (int i = 0; i < numHeatSources; i++) + { setOfSources[i] = HeatSource(this); } } - else if (token == "heatsource") { - if (numHeatSources == 0) { + else if (token == "heatsource") + { + if (numHeatSources == 0) + { msg("You must specify the number of heatsources before setting their properties. " "\n"); return HPWH_ABORT; } line_ss >> heatsource >> token; - if (token == "isVIP") { + if (token == "isVIP") + { line_ss >> tempString; if (tempString == "true") setOfSources[heatsource].isVIP = true; else if (tempString == "false") setOfSources[heatsource].isVIP = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper value for %s for heat source %d\n", token.c_str(), heatsource); @@ -5015,14 +5765,17 @@ int HPWH::HPWHinit_file(string configFile) return HPWH_ABORT; } } - else if (token == "isOn") { + else if (token == "isOn") + { line_ss >> tempString; if (tempString == "true") setOfSources[heatsource].isOn = true; else if (tempString == "false") setOfSources[heatsource].isOn = false; - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper value for %s for heat source %d\n", token.c_str(), heatsource); @@ -5030,45 +5783,56 @@ int HPWH::HPWHinit_file(string configFile) return HPWH_ABORT; } } - else if (token == "minT") { + else if (token == "minT") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = F_TO_C(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s. \n", token.c_str()); } return HPWH_ABORT; } setOfSources[heatsource].minT = tempDouble; } - else if (token == "maxT") { + else if (token == "maxT") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = F_TO_C(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s. \n", token.c_str()); } return HPWH_ABORT; } setOfSources[heatsource].maxT = tempDouble; } - else if (token == "onlogic" || token == "offlogic" || token == "standbylogic") { + else if (token == "onlogic" || token == "offlogic" || token == "standbylogic") + { line_ss >> tempString; - if (tempString == "nodes") { + if (tempString == "nodes") + { std::vector nodeNums; std::vector weights; std::string nextToken; line_ss >> nextToken; - while (std::regex_match(nextToken, std::regex("\\d+"))) { + while (std::regex_match(nextToken, std::regex("\\d+"))) + { int nodeNum = std::stoi(nextToken); - if (nodeNum > 13 || nodeNum < 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (nodeNum > 13 || nodeNum < 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Node number for heatsource %d %s must be between 0 and 13. " "\n", heatsource, @@ -5079,22 +5843,27 @@ int HPWH::HPWHinit_file(string configFile) nodeNums.push_back(nodeNum); line_ss >> nextToken; } - if (nextToken == "weights") { + if (nextToken == "weights") + { line_ss >> nextToken; - while ( - std::regex_match(nextToken, std::regex("-?\\d*\\.\\d+(?:e-?\\d+)?"))) { + while (std::regex_match(nextToken, std::regex("-?\\d*\\.\\d+(?:e-?\\d+)?"))) + { weights.push_back(std::stod(nextToken)); line_ss >> nextToken; } } - else { - for (auto n : nodeNums) { + else + { + for (auto n : nodeNums) + { n += 0; // used to get rid of unused variable compiler warning weights.push_back(1.0); } } - if (nodeNums.size() != weights.size()) { - if (hpwhVerbosity >= VRB_reluctant) { + if (nodeNums.size() != weights.size()) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Number of weights for heatsource %d %s (%d) does not macht number " "of nodes for %s (%d). \n", heatsource, @@ -5105,8 +5874,10 @@ int HPWH::HPWHinit_file(string configFile) } return HPWH_ABORT; } - if (nextToken != "absolute" && nextToken != "relative") { - if (hpwhVerbosity >= VRB_reluctant) { + if (nextToken != "absolute" && nextToken != "relative") + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper definition, \"%s\", for heat source %d %s. Should be " "\"relative\" or \"absoute\".\n", nextToken.c_str(), @@ -5123,8 +5894,10 @@ int HPWH::HPWHinit_file(string configFile) compare = std::less(); else if (compareStr == ">") compare = std::greater(); - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper comparison, \"%s\", for heat source %d %s. Should be " "\"<\" or \">\".\n", compareStr.c_str(), @@ -5133,18 +5906,23 @@ int HPWH::HPWHinit_file(string configFile) } return HPWH_ABORT; } - if (units == "F") { - if (absolute) { + if (units == "F") + { + if (absolute) + { tempDouble = F_TO_C(tempDouble); } - else { + else + { tempDouble = dF_TO_dC(tempDouble); } } else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); @@ -5152,193 +5930,248 @@ int HPWH::HPWHinit_file(string configFile) return HPWH_ABORT; } std::vector nodeWeights; - for (size_t i = 0; i < nodeNums.size(); i++) { + for (size_t i = 0; i < nodeNums.size(); i++) + { nodeWeights.emplace_back(nodeNums[i], weights[i]); } std::shared_ptr logic = std::make_shared( "custom", nodeWeights, tempDouble, this, absolute, compare); - if (token == "onlogic") { + if (token == "onlogic") + { setOfSources[heatsource].addTurnOnLogic(logic); } - else if (token == "offlogic") { + else if (token == "offlogic") + { setOfSources[heatsource].addShutOffLogic(std::move(logic)); } - else { // standby logic + else + { // standby logic setOfSources[heatsource].standbyLogic = std::make_shared( "standby logic", nodeWeights, tempDouble, this, absolute, compare); } } - else if (token == "onlogic") { + else if (token == "onlogic") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = dF_TO_dC(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); } return HPWH_ABORT; } - if (tempString == "topThird") { + if (tempString == "topThird") + { setOfSources[heatsource].addTurnOnLogic(HPWH::topThird(tempDouble)); } - else if (tempString == "bottomThird") { + else if (tempString == "bottomThird") + { setOfSources[heatsource].addTurnOnLogic(HPWH::bottomThird(tempDouble)); } - else if (tempString == "standby") { + else if (tempString == "standby") + { setOfSources[heatsource].addTurnOnLogic(HPWH::standby(tempDouble)); } - else if (tempString == "bottomSixth") { + else if (tempString == "bottomSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::bottomSixth(tempDouble)); } - else if (tempString == "secondSixth") { + else if (tempString == "secondSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::secondSixth(tempDouble)); } - else if (tempString == "thirdSixth") { + else if (tempString == "thirdSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::thirdSixth(tempDouble)); } - else if (tempString == "fourthSixth") { + else if (tempString == "fourthSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::fourthSixth(tempDouble)); } - else if (tempString == "fifthSixth") { + else if (tempString == "fifthSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::fifthSixth(tempDouble)); } - else if (tempString == "topSixth") { + else if (tempString == "topSixth") + { setOfSources[heatsource].addTurnOnLogic(HPWH::topSixth(tempDouble)); } - else if (tempString == "bottomHalf") { + else if (tempString == "bottomHalf") + { setOfSources[heatsource].addTurnOnLogic(HPWH::bottomHalf(tempDouble)); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "offlogic") { + else if (token == "offlogic") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = F_TO_C(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); } return HPWH_ABORT; } - if (tempString == "topNodeMaxTemp") { + if (tempString == "topNodeMaxTemp") + { setOfSources[heatsource].addShutOffLogic(HPWH::topNodeMaxTemp(tempDouble)); } - else if (tempString == "bottomNodeMaxTemp") { + else if (tempString == "bottomNodeMaxTemp") + { setOfSources[heatsource].addShutOffLogic( HPWH::bottomNodeMaxTemp(tempDouble)); } - else if (tempString == "bottomTwelthMaxTemp") { + else if (tempString == "bottomTwelthMaxTemp") + { setOfSources[heatsource].addShutOffLogic( HPWH::bottomTwelthMaxTemp(tempDouble)); } - else if (tempString == "bottomSixthMaxTemp") { + else if (tempString == "bottomSixthMaxTemp") + { setOfSources[heatsource].addShutOffLogic( HPWH::bottomSixthMaxTemp(tempDouble)); } - else if (tempString == "largeDraw") { + else if (tempString == "largeDraw") + { setOfSources[heatsource].addShutOffLogic(HPWH::largeDraw(tempDouble)); } - else if (tempString == "largerDraw") { + else if (tempString == "largerDraw") + { setOfSources[heatsource].addShutOffLogic(HPWH::largerDraw(tempDouble)); } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } } - else if (token == "type") { + else if (token == "type") + { line_ss >> tempString; - if (tempString == "resistor") { + if (tempString == "resistor") + { setOfSources[heatsource].typeOfHeatSource = TYPE_resistance; } - else if (tempString == "compressor") { + else if (tempString == "compressor") + { setOfSources[heatsource].typeOfHeatSource = TYPE_compressor; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "coilConfig") { + else if (token == "coilConfig") + { line_ss >> tempString; - if (tempString == "wrapped") { + if (tempString == "wrapped") + { setOfSources[heatsource].configuration = HeatSource::CONFIG_WRAPPED; } - else if (tempString == "submerged") { + else if (tempString == "submerged") + { setOfSources[heatsource].configuration = HeatSource::CONFIG_SUBMERGED; } - else if (tempString == "external") { + else if (tempString == "external") + { setOfSources[heatsource].configuration = HeatSource::CONFIG_EXTERNAL; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "heatCycle") { + else if (token == "heatCycle") + { line_ss >> tempString; - if (tempString == "singlepass") { + if (tempString == "singlepass") + { setOfSources[heatsource].isMultipass = false; } - else if (tempString == "multipass") { + else if (tempString == "multipass") + { setOfSources[heatsource].isMultipass = true; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "externalInlet") { + else if (token == "externalInlet") + { line_ss >> tempInt; - if (tempInt < numNodes && tempInt >= 0) { + if (tempInt < numNodes && tempInt >= 0) + { setOfSources[heatsource].externalInletHeight = tempInt; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "externalOutlet") { + else if (token == "externalOutlet") + { line_ss >> tempInt; - if (tempInt < numNodes && tempInt >= 0) { + if (tempInt < numNodes && tempInt >= 0) + { setOfSources[heatsource].externalOutletHeight = tempInt; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper %s for heat source %d\n", token.c_str(), heatsource); } return HPWH_ABORT; } } - else if (token == "condensity") { + else if (token == "condensity") + { line_ss >> dblArray[0] >> dblArray[1] >> dblArray[2] >> dblArray[3] >> dblArray[4] >> dblArray[5] >> dblArray[6] >> dblArray[7] >> dblArray[8] >> dblArray[9] >> dblArray[10] >> dblArray[11]; @@ -5355,27 +6188,34 @@ int HPWH::HPWHinit_file(string configFile) dblArray[10], dblArray[11]); } - else if (token == "nTemps") { + else if (token == "nTemps") + { line_ss >> nTemps; setOfSources[heatsource].perfMap.resize(nTemps); } - else if (std::regex_match(token, std::regex("T\\d+"))) { + else if (std::regex_match(token, std::regex("T\\d+"))) + { std::smatch match; std::regex_match(token, match, std::regex("T(\\d+)")); nTemps = std::stoi(match[1].str()); int maxTemps = (int)setOfSources[heatsource].perfMap.size(); - if (maxTemps < nTemps) { - if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (maxTemps < nTemps) + { + if (maxTemps == 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), heatsource); } return HPWH_ABORT; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " "less than %d. \n", token.c_str(), @@ -5393,8 +6233,10 @@ int HPWH::HPWHinit_file(string configFile) // else if (units == "C") ; //do nothing, lol else if (units == "C") tempDouble = C_TO_F(tempDouble); - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); @@ -5403,36 +6245,45 @@ int HPWH::HPWHinit_file(string configFile) } setOfSources[heatsource].perfMap[nTemps - 1].T_F = tempDouble; } - else if (std::regex_match(token, std::regex("(?:inPow|cop)T\\d+(?:const|lin|quad)"))) { + else if (std::regex_match(token, std::regex("(?:inPow|cop)T\\d+(?:const|lin|quad)"))) + { std::smatch match; std::regex_match(token, match, std::regex("(inPow|cop)T(\\d+)(const|lin|quad)")); string var = match[1].str(); nTemps = std::stoi(match[2].str()); string coeff = match[3].str(); int coeff_num; - if (coeff == "const") { + if (coeff == "const") + { coeff_num = 0; } - else if (coeff == "lin") { + else if (coeff == "lin") + { coeff_num = 1; } - else if (coeff == "quad") { + else if (coeff == "quad") + { coeff_num = 2; } int maxTemps = (int)setOfSources[heatsource].perfMap.size(); - if (maxTemps < nTemps) { - if (maxTemps == 0) { - if (hpwhVerbosity >= VRB_reluctant) { + if (maxTemps < nTemps) + { + if (maxTemps == 0) + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("%s specified for heatsource %d before definition of nTemps. \n", token.c_str(), heatsource); } return HPWH_ABORT; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect specification for %s from heatsource %d. nTemps, %d, is " "less than %d. \n", token.c_str(), @@ -5445,22 +6296,27 @@ int HPWH::HPWHinit_file(string configFile) } line_ss >> tempDouble; - if (var == "inPow") { + if (var == "inPow") + { setOfSources[heatsource].perfMap[nTemps - 1].inputPower_coeffs.push_back( tempDouble); } - else if (var == "cop") { + else if (var == "cop") + { setOfSources[heatsource].perfMap[nTemps - 1].COP_coeffs.push_back(tempDouble); } } - else if (token == "hysteresis") { + else if (token == "hysteresis") + { line_ss >> tempDouble >> units; if (units == "F") tempDouble = dF_TO_dC(tempDouble); else if (units == "C") ; // do nothing, lol - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Incorrect units specification for %s from heatsource %d. \n", token.c_str(), heatsource); @@ -5469,26 +6325,32 @@ int HPWH::HPWHinit_file(string configFile) } setOfSources[heatsource].hysteresis_dC = tempDouble; } - else if (token == "backupSource") { + else if (token == "backupSource") + { line_ss >> sourceNum; setOfSources[heatsource].backupHeatSource = &setOfSources[sourceNum]; } - else if (token == "companionSource") { + else if (token == "companionSource") + { line_ss >> sourceNum; setOfSources[heatsource].companionHeatSource = &setOfSources[sourceNum]; } - else if (token == "followedBySource") { + else if (token == "followedBySource") + { line_ss >> sourceNum; setOfSources[heatsource].followedByHeatSource = &setOfSources[sourceNum]; } - else { - if (hpwhVerbosity >= VRB_reluctant) { + else + { + if (hpwhVerbosity >= VRB_reluctant) + { msg("Improper specifier (%s) for heat source %d\n", token.c_str(), heatsource); } } } // end heatsource options - else { + else + { msg("Improper keyword: %s \n", token.c_str()); return HPWH_ABORT; } @@ -5504,8 +6366,10 @@ int HPWH::HPWHinit_file(string configFile) nextTankTemps_C = new double[numNodes]; isHeating = false; - for (int i = 0; i < numHeatSources; i++) { - if (setOfSources[i].isOn) { + for (int i = 0; i < numHeatSources; i++) + { + if (setOfSources[i].isOn) + { isHeating = true; } setOfSources[i].sortPerformanceMap(); @@ -5513,7 +6377,8 @@ int HPWH::HPWHinit_file(string configFile) calcDerivedValues(); - if (checkInputs() == HPWH_ABORT) { + if (checkInputs() == HPWH_ABORT) + { return HPWH_ABORT; } simHasFailed = false; From 09129c1ef72245a10f9502011d8a55bc29758469 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Wed, 20 Dec 2023 13:14:41 -0700 Subject: [PATCH 4/9] Separate clang-format tasks by directory. --- .github/workflows/clang-format-check.yml | 25 +++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 048c129e..e027a5c9 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -4,16 +4,23 @@ jobs: formatting-check: name: Formatting Check runs-on: ubuntu-latest - strategy: - matrix: - path: - - 'src' - - 'include/${{github.workspace}}' - - 'test' steps: - - uses: actions/checkout@v3 - - name: Run clang-format style check for C++ programs. + - name: Checkout + uses: actions/checkout@v3 + - name: Set Project Name + run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV + - name: Run clang-format style check on implementation files. uses: jidicula/clang-format-action@v4.11.0 with: clang-format-version: '16' - check-path: ${{ matrix.path }} + check-path: 'src' + - name: Run clang-format style check on header files. + uses: jidicula/clang-format-action@v4.11.0 + with: + clang-format-version: '16' + check-path: 'include/${{ env.REPOSITORY_NAME }}' + - name: Run clang-format style check on test files. + uses: jidicula/clang-format-action@v4.11.0 + with: + clang-format-version: '16' + check-path: 'test' From 787bf7115547a97fea66f8bad4c239a581182706 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Wed, 20 Dec 2023 14:13:03 -0700 Subject: [PATCH 5/9] Remove include folder from default formatting check. --- .github/workflows/clang-format-check.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index e027a5c9..f4ea0fb6 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -14,11 +14,6 @@ jobs: with: clang-format-version: '16' check-path: 'src' - - name: Run clang-format style check on header files. - uses: jidicula/clang-format-action@v4.11.0 - with: - clang-format-version: '16' - check-path: 'include/${{ env.REPOSITORY_NAME }}' - name: Run clang-format style check on test files. uses: jidicula/clang-format-action@v4.11.0 with: From 93b64c6577dab3b47f172017e92556254fd69323 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Wed, 20 Dec 2023 14:40:07 -0700 Subject: [PATCH 6/9] Fix a couple of formatting left-behinds. --- src/HPWH.cc | 6 +++--- src/HPWHHeatSources.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/HPWH.cc b/src/HPWH.cc index 6056df0b..b615ffeb 100644 --- a/src/HPWH.cc +++ b/src/HPWH.cc @@ -3404,9 +3404,9 @@ void HPWH::updateTankTemps(double drawVolume_L, { // if (hpwhVerbosity >= 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"); + // 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"); // } // simHasFailed = true; // return; diff --git a/src/HPWHHeatSources.cc b/src/HPWHHeatSources.cc index 2f204646..e193e7f7 100644 --- a/src/HPWHHeatSources.cc +++ b/src/HPWHHeatSources.cc @@ -214,7 +214,7 @@ bool HPWH::HeatSource::shouldLockOut(double heatSourceAmbientT_C) const // if (lock == true && backupHeatSource == NULL) { // if (hpwh->hpwhVerbosity >= HPWH::VRB_emetic) { // hpwh->msg("\nWARNING: lock-out triggered, but no backupHeatSource defined. - //Simulation will continue without lock-out"); + // Simulation will continue without lock-out"); // } // lock = false; // } From 416eb17d627c53b377f59ef8dcd310e9569868df Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Wed, 20 Dec 2023 15:26:42 -0700 Subject: [PATCH 7/9] Protect cmake input from formatting. --- src/HPWH.hh | 2727 ++++++++++++++++++++++------------------- src/HPWHversion.in.hh | 6 +- 2 files changed, 1457 insertions(+), 1276 deletions(-) diff --git a/src/HPWH.hh b/src/HPWH.hh index 6d7e0437..ccdae473 100644 --- a/src/HPWH.hh +++ b/src/HPWH.hh @@ -10,1320 +10,1494 @@ #include #include -#include //for exit +#include //for exit #include -namespace Btwxt { class RegularGridInterpolator; }; +namespace Btwxt +{ +class RegularGridInterpolator; +}; -//#define HPWH_ABRIDGED +// #define HPWH_ABRIDGED /**< If HPWH_ABRIDGED is defined, then some function definitions will be * excluded from compiling. This is done in order to reduce the size of the * final compiled code. */ #include "HPWHversion.hh" -class HPWH { -public: - static const int version_major = HPWHVRSN_MAJOR; - static const int version_minor = HPWHVRSN_MINOR; - static const int version_patch = HPWHVRSN_PATCH; - static const std::string version_maint; // Initialized in source file (HPWH.cc) - - static const float DENSITYWATER_kgperL; - static const float KWATER_WpermC; - static const float CPWATER_kJperkgC; - static const int CONDENSITY_SIZE = 12; /** SANCO2 5-23 - MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ - MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ - MODELS_SANCO2_GS3_45HPA_US_SP = 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ - MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ - - // Sanden synomyms for backward compatability - // allow unmodified code using HPWHsim to build - MODELS_Sanden40 = MODELS_SANCO2_43, - MODELS_Sanden80 = MODELS_SANCO2_83, - MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, - MODELS_Sanden120 = MODELS_SANCO2_119, - - // The new-ish Rheem - MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ - MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ - MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ - - // The new new Rheem - MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ - MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ - MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ - - // Rheem 120V dedicated-circuit product, no resistance elements - MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ - MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ - - // Rheem 120V shared-circuit products, no resistance elements. - MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ - MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ - - // The new-ish Stiebel - MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ - - // Generic water heaters, corresponding to the tiers 1, 2, and 3 - MODELS_Generic1 = 170, /**< Generic Tier 1 */ - MODELS_Generic2 = 171, /**< Generic Tier 2 */ - MODELS_Generic3 = 172, /**< Generic Tier 3 */ - MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ - MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ - - MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ - MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ - MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ - - MODELS_StorageTank = 180, /**< Generic Tank without heaters */ - MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has scalable input capacity and COP */ - MODELS_Scalable_MP = 191, /** < Lower performance MP model that has scalable input capacity and COP */ - - // Non-preset models - MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ - MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ - MODELS_CustomResTankGeneric = 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ - - // Larger Colmac models in single pass configuration - MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ - MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ - - // Larger Colmac models in multi pass configuration - MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ - MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ - - // Larger Nyle models in single pass configuration - MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ - MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ - // Larger Nyle models with the cold weather package! - MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ - MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ - MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ - MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ - MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ - - // Mitsubishi Electric Trane - MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ - - // Larger Nyle models in multi pass configuration - //MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ - MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ - MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ - MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ - MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ - MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ - - // Large Rheem multi pass models - MODELS_RHEEM_HPHD60HNU_201_MP = 350, - MODELS_RHEEM_HPHD60VNU_201_MP = 351, - MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data - MODELS_RHEEM_HPHD135VNU_483_MP = 353, // really bad fit to data due to inconsistency in data - - 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 */ - UNITS_F, /**< fahrenheit */ - UNITS_KWH, /**< kilowatt hours */ - UNITS_BTU, /**< british thermal units */ - UNITS_KJ, /**< kilojoules */ - UNITS_KW, /**< kilowatt */ - UNITS_BTUperHr, /**< british thermal units per Hour */ - UNITS_GAL, /**< gallons */ - UNITS_L, /**< liters */ - UNITS_kJperHrC, /**< UA, metric units */ - UNITS_BTUperHrF, /**< UA, imperial units */ - UNITS_FT, /**< feet */ - UNITS_M, /**< meters */ - UNITS_FT2, /**< square feet */ - UNITS_M2, /**< square meters */ - UNITS_MIN, /**< minutes */ - UNITS_SEC, /**< seconds */ - UNITS_HR, /**< hours */ - UNITS_GPM, /**< gallons per minute */ - UNITS_LPS /**< liters per second */ - }; - - /** specifies the type of heat source */ - enum HEATSOURCE_TYPE { - TYPE_none, /**< a default to check to make sure it's been set */ - TYPE_resistance, /**< a resistance element */ - TYPE_compressor /**< a vapor cycle compressor */ - }; - - /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ - enum EXTRAP_METHOD { - EXTRAP_LINEAR, /**< the default extrapolates linearly */ - EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest point */ - }; - - /** specifies the unit type for outputs in the CSV file-s */ - enum CSVOPTIONS { - CSVOPT_NONE = 0, - CSVOPT_IPUNITS = 1 << 0, - CSVOPT_IS_DRAWING = 1 << 1 - }; - - struct NodeWeight { - int nodeNum; - double weight; - NodeWeight(int n,double w): nodeNum(n),weight(w) {}; - - NodeWeight(int n): nodeNum(n),weight(1.0) {}; - }; - - struct HeatingLogic { - public: - std::string description; - std::function compare; - - HeatingLogic(std::string desc,double decisionPoint_in,HPWH *hpwh_in, - std::function c,bool isHTS): - description(desc),decisionPoint(decisionPoint_in),hpwh(hpwh_in),compare(c), - isEnteringWaterHighTempShutoff(isHTS) - {}; - - /**< checks that the input is all valid. */ - virtual const bool isValid() = 0; - /**< gets the value for comparing the tank value to, i.e. the target SoC */ - virtual const double getComparisonValue() = 0; - /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ - virtual const double getTankValue() = 0; - /**< function to calculate where the average node for a logic set is. */ - virtual const double nodeWeightAvgFract() = 0; - /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ - virtual const double getFractToMeetComparisonExternal() = 0; - - virtual int setDecisionPoint(double value) = 0; - double getDecisionPoint() { return decisionPoint; } - bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } - - protected: - double decisionPoint; - HPWH* hpwh; - bool isEnteringWaterHighTempShutoff; - }; - - struct SoCBasedHeatingLogic: HeatingLogic { - public: - SoCBasedHeatingLogic(std::string desc,double decisionPoint,HPWH *hpwh, - double hF = -0.05,double tM_C = 43.333,bool constMains = false,double mains_C = 18.333, - std::function c = std::less()): - HeatingLogic(desc,decisionPoint,hpwh,c,false), - hysteresisFraction(hF),tempMinUseful_C(tM_C), - useCostantMains(constMains),constantMains_C(mains_C) - {}; - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - const double getMainsT_C(); - const double getTempMinUseful_C(); - int setDecisionPoint(double value); - int setConstantMainsTemperature(double mains_C); - - private: - double tempMinUseful_C; - double hysteresisFraction; - bool useCostantMains; - double constantMains_C; - }; - - struct TempBasedHeatingLogic: HeatingLogic { - public: - TempBasedHeatingLogic(std::string desc,std::vector n, - double decisionPoint,HPWH *hpwh,bool a = false, - std::function c = std::less(), - bool isHTS = false): - HeatingLogic(desc,decisionPoint,hpwh,c,isHTS), - nodeWeights(n),isAbsolute(a) - {}; - - const bool isValid(); - - const double getComparisonValue(); - const double getTankValue(); - const double nodeWeightAvgFract(); - const double getFractToMeetComparisonExternal(); - - int setDecisionPoint(double value); - int setDecisionPoint(double value,bool absolute); - - private: - const bool areNodeWeightsValid(); - - bool isAbsolute; - std::vector nodeWeights; - }; - - std::shared_ptr shutOffSoC(std::string desc,double targetSoC,double hystFract,double tempMinUseful_C, - bool constMains,double mains_C); - std::shared_ptr turnOnSoC(std::string desc,double targetSoC,double hystFract,double tempMinUseful_C, - bool constMains,double mains_C); - - std::shared_ptr wholeTank(double decisionPoint,const UNITS units = UNITS_C, const bool absolute = false); - std::shared_ptr topThird(double decisionPoint); - std::shared_ptr topThird_absolute(double decisionPoint); - std::shared_ptr secondThird(double decisionPoint,const UNITS units = UNITS_C, const bool absolute = false); - std::shared_ptr bottomThird(double decisionPoint); - std::shared_ptr bottomHalf(double decisionPoint) ; - std::shared_ptr bottomTwelfth(double decisionPoint); - std::shared_ptr bottomSixth(double decisionPoint); - std::shared_ptr bottomSixth_absolute(double decisionPoint); - std::shared_ptr secondSixth(double decisionPoint); - std::shared_ptr thirdSixth(double decisionPoint); - std::shared_ptr fourthSixth(double decisionPoint); - std::shared_ptr fifthSixth(double decisionPoint); - std::shared_ptr topSixth(double decisionPoint); - - std::shared_ptr standby(double decisionPoint); - std::shared_ptr topNodeMaxTemp(double decisionPoint); - std::shared_ptr bottomNodeMaxTemp(double decisionPoint,bool isEnteringWaterHighTempShutoff = false); - std::shared_ptr bottomTwelfthMaxTemp(double decisionPoint); - std::shared_ptr topThirdMaxTemp(double decisionPoint); - std::shared_ptr bottomSixthMaxTemp(double decisionPoint); - std::shared_ptr secondSixthMaxTemp(double decisionPoint); - std::shared_ptr fifthSixthMaxTemp(double decisionPoint); - std::shared_ptr topSixthMaxTemp(double decisionPoint); - - std::shared_ptr largeDraw(double decisionPoint); - std::shared_ptr largerDraw(double decisionPoint); - - ///this is the value that the public functions will return in case of a simulation - ///destroying error - static const int HPWH_ABORT = -274000; - - static std::string getVersion(); - /**< This function returns a string with the current version number */ - - int HPWHinit_presets(MODELS presetNum); - /**< This function will reset all member variables to defaults and then - * load in a set of parameters that are hardcoded in this function - - * which particular set of parameters is selected by presetNum. - * This is similar to the way the HPWHsim currently operates, as used in SEEM, - * but not quite as versatile. - * My impression is that this could be a useful input paradigm for CSE - * - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_file(std::string configFile); - /**< This function will load in a set of parameters from a file - * The file name is the input - there should be at most one set of parameters per file - * This is useful for testing new variations, and for the sort of variability - * that we typically do when creating SEEM runs - * Appropriate use of this function can be found in the documentation - - * The return value is 0 for successful initialization, HPWH_ABORT otherwise - */ - - int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ - int HPWHinit_resTank(double tankVol_L,double energyFactor,double upperPower_W,double lowerPower_W); - /**< This function will initialize a HPWH object to be a resistance tank. Since - * resistance tanks are so simple, they can be specified with only four variables: - * tank volume, energy factor, and the power of the upper and lower elements. Energy - * factor is converted into UA internally, although an external setter for UA is - * also provided in case the energy factor is unknown. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The logics are also set - * to standard setting, with upper as VIP activating when the top third is too cold. - */ - - int HPWHinit_resTankGeneric(double tankVol_L,double rValue_M2KperW,double upperPower_W,double lowerPower_W); - /**< This function will initialize a HPWH object to be a generic resistance storage water heater, - * with a specific R-Value defined at initalization. - * - * Several assumptions regarding the tank configuration are assumed: the lower element - * is at the bottom, the upper element is at the top third. The controls are the same standard controls for - * the HPWHinit_resTank() - */ - - int HPWHinit_genericHPWH(double tankVol_L,double energyFactor,double resUse_C); - /**< This function will initialize a HPWH object to be a non-specific HPWH model - * with an energy factor as specified. Since energy - * factor is not strongly correlated with energy use, most settings - * are taken from the GE2015_STDMode model. - */ - - int runOneStep(double drawVolume_L,double ambientT_C, - double externalT_C,DRMODES DRstatus,double inletVol2_L = 0.,double inletT2_C = 0., - std::vector* extraHeatDist_W = NULL); - /**< This function will progress the simulation forward in time by one step - * all calculated outputs are stored in private variables and accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** An overloaded function that uses takes inletT_C */ - int runOneStep(double inletT_C,double drawVolume_L,double ambientT_C, - double externalT_C,DRMODES DRstatus,double inletVol2_L = 0.,double inletT2_C = 0., - std::vector* extraHeatDist_W = NULL) { - setInletT(inletT_C); - return runOneStep(drawVolume_L,ambientT_C, - externalT_C,DRstatus,inletVol2_L,inletT2_C, - extraHeatDist_W); - }; - - - int runNSteps(int N,double *inletT_C,double *drawVolume_L, - double *tankAmbientT_C,double *heatSourceAmbientT_C, - DRMODES *DRstatus); - /**< This function will progress the simulation forward in time by N (equal) steps - * The calculated values will be summed or averaged, as appropriate, and - * then stored in the usual variables to be accessed through functions - * - * The return value is 0 for successful simulation run, HPWH_ABORT otherwise - */ - - /** Setters for the what are typically input variables */ - 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 - specifically input/output energy/power, and runtime - will print to cout if messageCallback pointer is unspecified - does not use verbosity, as it is public and expected to be called only when needed */ - void printTankTemps(); - /**< this prints out all the node temps, kind of nicely formatted - does not use verbosity, as it is public and expected to be called only when needed */ - - int WriteCSVHeading(FILE* outFILE,const char* preamble = "",int nTCouples = 6,int options = CSVOPT_NONE) const; - int WriteCSVRow(FILE* outFILE,const char* preamble = "",int nTCouples = 6,int options = CSVOPT_NONE) const; - /**< a couple of function to write the outputs to a file - they both will return 0 for success - the preamble should be supplied with a trailing comma, as these functions do - not add one. Additionally, a newline is written with each call. */ - - /**< Sets the tank node temps based on the provided vector of temps, which are mapped onto the - existing nodes, regardless of numNodes. */ - int setTankLayerTemperatures(std::vector setTemps, const UNITS units = UNITS_C); - void getTankTemps(std::vector &tankTemps); - - bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ - int setSetpoint(double newSetpoint,UNITS units = UNITS_C);/** 0 minutes and < 1440 minutes. */ - double getTimerLimitTOT_minute() const; - /**< Returns the timer limit in minutes for the DR_TOT call. */ - - int getInletHeight(int whichInlet) const; - /**< returns the water inlet height node number */ - - /**< resizes the tankTemp_C and nextTankTemp_C node vectors */ - void setNumNodes(const std::size_t num_nodes); - - /**< returns the number of nodes */ - int getNumNodes() const; - - /**< returns the index of the top node */ - int getIndexTopNode() const; - - double getTankNodeTemp(int nodeNum,UNITS units = UNITS_C) const; - /**< returns the temperature of the water at the specified node - with specified units - or HPWH_ABORT for incorrect node number or unit failure */ - - double getNthSimTcouple(int iTCouple,int nTCouple,UNITS units = UNITS_C) const; - /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, - which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, - 1 at the bottom using specified units - returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ - - int getNumHeatSources() const; - /**< returns the number of heat sources */ - - int getNumResistanceElements() const; - /**< returns the number of resistance elements */ - - int getCompressorIndex() const; - /**< returns the index of the compressor in the heat source array. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - double getCompressorCapacity(double airTemp = 19.722,double inletTemp = 14.444,double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW,UNITS tempUnit = UNITS_C); - /**< Returns the heating output capacity of the compressor for the current HPWH model. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor. Outlet temperatures greater than the max allowable setpoints will return an error, but - for compressors with a fixed setpoint the */ - - int setCompressorOutputCapacity(double newCapacity,double airTemp = 19.722,double inletTemp = 14.444,double outTemp = 57.222, - UNITS pwrUnit = UNITS_KW,UNITS tempUnit = UNITS_C); - /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and outlet temperatures. - For multi-pass models the capacity is set as the average between the inletTemp and outTemp since multi-pass models will increase - the water temperature only a few degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at - inletTemp might not be accurate for the entire heating cycle. - Note only supports HPWHs with one compressor, if multiple will return the last index - of a compressor */ - - int setScaleHPWHCapacityCOP(double scaleCapacity = 1.,double scaleCOP = 1.); - /**< Scales the heatpump water heater input capacity and COP*/ - - int setResistanceCapacity(double power,int which = -1,UNITS pwrUNIT = UNITS_KW); - /**< Scale the resistance elements in the heat source list. Which heat source is chosen is changes is given by "which" - - If which (-1) sets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in heatSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - double getResistanceCapacity(int which = -1,UNITS pwrUNIT = UNITS_KW); - /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given by "which" - - If which (-1) gets all the resisistance elements in the tank. - - If which (0, 1, 2...) sets the resistance element in a low to high order. - So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, regardless of their order - in heatSources. If the elements exist on at the same node then all of the elements are set. - - The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is defined as the - by the ordered height of the resistance elements it cannot refer to a compressor. - */ - - int getResistancePosition(int elementIndex) const; - - double getNthHeatSourceEnergyInput(int N,UNITS units = UNITS_KWH) const; - /**< returns the energy input to the Nth heat source, with the specified units - energy used by the heat source is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ - - double getNthHeatSourceEnergyOutput(int N,UNITS units = UNITS_KWH) const; - /**< returns the energy output from the Nth heat source, with the specified units - energy put into the water is positive - should always be positive - returns HPWH_ABORT for N out of bounds or incorrect units */ - - double getNthHeatSourceRunTime(int N) const; - /**< returns the run time for the Nth heat source, in minutes - note: they may sum to more than 1 time step for concurrently running heat sources - returns HPWH_ABORT for N out of bounds */ - int isNthHeatSourceRunning(int N) const; - /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and - returns HPWH_ABORT for N out of bounds */ - HEATSOURCE_TYPE getNthHeatSourceType(int N) const; - /**< returns the enum value for what type of heat source the Nth heat source is */ - - - double getOutletTemp(UNITS units = UNITS_C) const; - /**< returns the outlet temperature in the specified units - returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ - double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser inlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - - double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; - /**< returns the condenser outlet temperature in the specified units - returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ - - double getExternalVolumeHeated(UNITS units = UNITS_L) const; - /**< returns the volume of water heated in an external in the specified units - returns 0 when no external heat source is running */ - - double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; - /**< get the total energy removed from the environment by all heat sources in specified units - (not net energy - does not include standby) - moving heat from the space to the water is the positive direction - returns HPWH_ABORT for incorrect units */ - - double getStandbyLosses(UNITS units = UNITS_KWH) const; - /**< get the amount of heat lost through the tank in specified units - moving heat from the water to the space is the positive direction - negative should occur seldom - returns HPWH_ABORT for incorrect units */ - - double getTankHeatContent_kJ() const; - /**< get the heat content of the tank, relative to zero celsius - * returns using kilojoules */ - - int getHPWHModel() const; - /**< get the model number of the HPWHsim model number of the hpwh */ - - int getCompressorCoilConfig() const; - bool isCompressorMultipass() const; - bool isCompressoExternalMultipass() const; - - bool hasACompressor() const; - /**< Returns if the HPWH model has a compressor or not, could be a storage or resistance tank. */ - - bool hasExternalHeatSource() const; - /**< Returns if the HPWH model has any external heat sources or not, could be a compressor or resistance element. */ - double getExternalMPFlowRate(UNITS units = UNITS_GPM) const; - /**< Returns the constant flow rate for an external multipass heat sources. */ - - - double getCompressorMinRuntime(UNITS units = UNITS_MIN) const; - - int getSizingFractions(double &aquafract,double &percentUseable) const; - /**< returns the fraction of total tank volume from the bottom up where the aquastat is - or the turn on logic for the compressor, and the USEable fraction of storage or 1 minus - where the shut off logic is for the compressor. If the logic spans multiple nodes it - returns the weighted average of the nodes */ - - bool isHPWHScalable() const; - /**< returns if the HPWH is scalable or not*/ - - bool shouldDRLockOut(HEATSOURCE_TYPE hs,DRMODES DR_signal) const; - /**< Checks the demand response signal against the different heat source types */ - - void resetTopOffTimer(); - /**< resets variables for timer associated with the DR_TOT call */ - - double getLocationTemp_C() const; - int setMaxTempDepression(double maxDepression,UNITS units = UNITS_C); - - bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); - int setEnteringWaterHighTempShutOff(double highTemp,bool tempIsAbsolute,int heatSourceIndex,UNITS units = UNITS_C); - /**< functions to check for and set specific high temperature shut off logics. - HPWHs can only have one of these, which is at least typical */ - - int setTargetSoCFraction(double target); - - bool canUseSoCControls(); - - int switchToSoCControls(double targetSoC,double hysteresisFraction = 0.05,double tempMinUseful = 43.333,bool constantMainsT = false, - double mainsT = 18.333,UNITS tempUnit = UNITS_C); - - bool isSoCControlled() const; - - /// Checks whether energy is balanced during a simulation step. - bool isEnergyBalanced(const double drawVol_L,const double prevHeatContent_kJ,const double fracEnergyTolerance = 0.001); - - /// Overloaded version of above that allows specification of inlet temperature. - bool isEnergyBalanced(const double drawVol_L,double inletT_C_in,const double prevHeatContent_kJ,const double fracEnergyTolerance) { - setInletT(inletT_C_in); - return isEnergyBalanced(drawVol_L,prevHeatContent_kJ,fracEnergyTolerance); - } - - /// Addition of heat from a normal heat sources; return excess heat, if needed, to prevent exceeding maximum or setpoint - double addHeatAboveNode(double qAdd_kJ,const int nodeNum,const double maxT_C); - - /// Addition of extra heat handled separately from normal heat sources - void addExtraHeatAboveNode(double qAdd_kJ,const int nodeNum); - -private: - class HeatSource; - - void setAllDefaults(); /**< sets all the defaults default */ - - void updateTankTemps(double draw,double inletT_C,double ambientT_C,double inletVol2_L,double inletT2_L); - void mixTankInversions(); - /**< Mixes the any temperature inversions in the tank after all the temperature calculations */ - void updateSoCIfNecessary(); - - bool areAllHeatSourcesOff() const; - /**< test if all the heat sources are off */ - void turnAllHeatSourcesOff(); - /**< disengage each heat source */ - - void addHeatParent(HeatSource *heatSourcePtr,double heatSourceAmbientT_C,double minutesToRun); - - /// adds extra heat to the set of nodes that are at the same temperature, above the - /// specified node number - void modifyHeatDistribution(std::vector &heatDistribution); - void addExtraHeat(std::vector &extraHeatDist_W); - - /// "extra" heat added during a simulation step - double extraEnergyInput_kWh; - - double tankAvg_C(const std::vector nodeWeights) const; - /**< functions to calculate what the temperature in a portion of the tank is */ - - void mixTankNodes(int mixedAboveNode,int mixedBelowNode,double mixFactor); - /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed below node. */ - - void calcDerivedValues(); - /**< a helper function for the inits, calculating condentropy and the lowest node */ - void calcSizeConstants(); - /**< a helper function to set constants for the UA and tank size*/ - void calcDerivedHeatingValues(); - /**< a helper for the helper, calculating condentropy and the lowest node*/ - void mapResRelativePosToHeatSources(); - /**< a helper function for the inits, creating a mapping function for the position of the resistance elements - to their indexes in heatSources. */ - - int checkInputs(); - /**< a helper function to run a few checks on the HPWH input parameters */ - - double getChargePerNode(double tCold,double tMix,double tHot) const; - - 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? */ - - bool isHeating; - /**< is the hpwh currently heating or not? */ - - bool setpointFixed; - /**< does the HPWH allow the setpoint to vary */ - - bool tankSizeFixed; - /**< does the HPWH have a constant tank size or can it be changed */ - - 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 */ - +class HPWH +{ + public: + static const int version_major = HPWHVRSN_MAJOR; + static const int version_minor = HPWHVRSN_MINOR; + static const int version_patch = HPWHVRSN_PATCH; + static const std::string version_maint; // Initialized in source file (HPWH.cc) + + static const float DENSITYWATER_kgperL; + static const float KWATER_WpermC; + static const float CPWATER_kJperkgC; + static const int CONDENSITY_SIZE = + 12; /** SANCO2 5-23 + MODELS_SANCO2_43 = 120, /**< SANCO2 43 gallon CO2 external heat pump */ + MODELS_SANCO2_83 = 121, /**< SANCO2 83 gallon CO2 external heat pump */ + MODELS_SANCO2_GS3_45HPA_US_SP = + 122, /**< SANCO2 80 gallon CO2 external heat pump used for MF */ + MODELS_SANCO2_119 = 123, /**< SANCO2 120 gallon CO2 external heat pump */ + + // Sanden synomyms for backward compatability + // allow unmodified code using HPWHsim to build + MODELS_Sanden40 = MODELS_SANCO2_43, + MODELS_Sanden80 = MODELS_SANCO2_83, + MODELS_Sanden_GS3_45HPA_US_SP = MODELS_SANCO2_GS3_45HPA_US_SP, + MODELS_Sanden120 = MODELS_SANCO2_119, + + // The new-ish Rheem + MODELS_RheemHB50 = 140, /**< Rheem 2014 (?) Model */ + MODELS_RheemHBDR2250 = 141, /**< 50 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4550 = 142, /**< 50 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2265 = 143, /**< 65 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4565 = 144, /**< 65 gallon, 4500 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR2280 = 145, /**< 80 gallon, 2250 W resistance Rheem HB Duct Ready */ + MODELS_RheemHBDR4580 = 146, /**< 80 gallon, 4500 W resistance Rheem HB Duct Ready */ + + // The new new Rheem + MODELS_Rheem2020Prem40 = 151, /**< 40 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem50 = 152, /**< 50 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem65 = 153, /**< 65 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Prem80 = 154, /**< 80 gallon, Rheem 2020 Premium */ + MODELS_Rheem2020Build40 = 155, /**< 40 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build50 = 156, /**< 50 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build65 = 157, /**< 65 gallon, Rheem 2020 Builder */ + MODELS_Rheem2020Build80 = 158, /**< 80 gallon, Rheem 2020 Builder */ + + // Rheem 120V dedicated-circuit product, no resistance elements + MODELS_RheemPlugInDedicated40 = 1160, /**< 40 gallon, Rheem 120V dedicated-circuit */ + MODELS_RheemPlugInDedicated50 = 1161, /**< 50 gallon, Rheem 120V dedicated-circuit */ + + // Rheem 120V shared-circuit products, no resistance elements. + MODELS_RheemPlugInShared40 = 1150, /**< 40 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared50 = 1151, /**< 50 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared65 = 1152, /**< 65 gallon, Rheem 120V shared-circuit */ + MODELS_RheemPlugInShared80 = 1153, /**< 80 gallon, Rheem 120V shared-circuit */ + + // The new-ish Stiebel + MODELS_Stiebel220E = 160, /**< Stiebel Eltron (2014 model?) */ + + // Generic water heaters, corresponding to the tiers 1, 2, and 3 + MODELS_Generic1 = 170, /**< Generic Tier 1 */ + MODELS_Generic2 = 171, /**< Generic Tier 2 */ + MODELS_Generic3 = 172, /**< Generic Tier 3 */ + MODELS_UEF2generic = 173, /**< UEF 2.0, modified GE2014STDMode case */ + MODELS_genericCustomUEF = 174, /**< used for creating "generic" model with custom uef*/ + + MODELS_AWHSTier3Generic40 = 175, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic50 = 176, /**< Generic AWHS Tier 3 50 gallons*/ + MODELS_AWHSTier3Generic65 = 177, /**< Generic AWHS Tier 3 65 gallons*/ + MODELS_AWHSTier3Generic80 = 178, /**< Generic AWHS Tier 3 80 gallons*/ + + MODELS_StorageTank = 180, /**< Generic Tank without heaters */ + MODELS_TamScalable_SP = 190, /** < HPWH input passed off a poor preforming SP model that has + scalable input capacity and COP */ + MODELS_Scalable_MP = + 191, /** < Lower performance MP model that has scalable input capacity and COP */ + + // Non-preset models + MODELS_CustomFile = 200, /**< HPWH parameters were input via file */ + MODELS_CustomResTank = 201, /**< HPWH parameters were input via HPWHinit_resTank */ + MODELS_CustomResTankGeneric = + 202, /**< HPWH parameters were input via HPWHinit_commercialResTank */ + + // Larger Colmac models in single pass configuration + MODELS_ColmacCxV_5_SP = 210, /**< Colmac CxA_5 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_10_SP = 211, /**< Colmac CxA_10 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_15_SP = 212, /**< Colmac CxA_15 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_20_SP = 213, /**< Colmac CxA_20 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_25_SP = 214, /**< Colmac CxA_25 external heat pump in Single Pass Mode */ + MODELS_ColmacCxA_30_SP = 215, /**< Colmac CxA_30 external heat pump in Single Pass Mode */ + + // Larger Colmac models in multi pass configuration + MODELS_ColmacCxV_5_MP = 310, /**< Colmac CxA_5 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_10_MP = 311, /**< Colmac CxA_10 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_15_MP = 312, /**< Colmac CxA_15 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_20_MP = 313, /**< Colmac CxA_20 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_25_MP = 314, /**< Colmac CxA_25 external heat pump in Multi Pass Mode */ + MODELS_ColmacCxA_30_MP = 315, /**< Colmac CxA_30 external heat pump in Multi Pass Mode */ + + // Larger Nyle models in single pass configuration + MODELS_NyleC25A_SP = 230, /*< Nyle C25A external heat pump in Single Pass Mode */ + MODELS_NyleC60A_SP = 231, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_SP = 232, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_SP = 233, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_SP = 234, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_SP = 235, /*< Nyle C250A external heat pump in Single Pass Mode */ + // Larger Nyle models with the cold weather package! + MODELS_NyleC60A_C_SP = 241, /*< Nyle C60A external heat pump in Single Pass Mode */ + MODELS_NyleC90A_C_SP = 242, /*< Nyle C90A external heat pump in Single Pass Mode */ + MODELS_NyleC125A_C_SP = 243, /*< Nyle C125A external heat pump in Single Pass Mode */ + MODELS_NyleC185A_C_SP = 244, /*< Nyle C185A external heat pump in Single Pass Mode */ + MODELS_NyleC250A_C_SP = 245, /*< Nyle C250A external heat pump in Single Pass Mode */ + + // Mitsubishi Electric Trane + MODELS_MITSUBISHI_QAHV_N136TAU_HPB_SP = + 250, /*< Mitsubishi Electric Trane QAHV external CO2 heat pump */ + + // Larger Nyle models in multi pass configuration + // MODELS_NyleC25A_MP = 330, /*< Nyle C25A external heat pump in Multi Pass Mode */ + MODELS_NyleC60A_MP = 331, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_MP = 332, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_MP = 333, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_MP = 334, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_MP = 335, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + MODELS_NyleC60A_C_MP = 341, /*< Nyle C60A external heat pump in Multi Pass Mode */ + MODELS_NyleC90A_C_MP = 342, /*< Nyle C90A external heat pump in Multi Pass Mode */ + MODELS_NyleC125A_C_MP = 343, /*< Nyle C125A external heat pump in Multi Pass Mode */ + MODELS_NyleC185A_C_MP = 344, /*< Nyle C185A external heat pump in Multi Pass Mode */ + MODELS_NyleC250A_C_MP = 345, /*< Nyle C250A external heat pump in Multi Pass Mode */ + + // Large Rheem multi pass models + MODELS_RHEEM_HPHD60HNU_201_MP = 350, + MODELS_RHEEM_HPHD60VNU_201_MP = 351, + MODELS_RHEEM_HPHD135HNU_483_MP = 352, // really bad fit to data due to inconsistency in data + MODELS_RHEEM_HPHD135VNU_483_MP = 353, // really bad fit to data due to inconsistency in data + + 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 */ + UNITS_F, /**< fahrenheit */ + UNITS_KWH, /**< kilowatt hours */ + UNITS_BTU, /**< british thermal units */ + UNITS_KJ, /**< kilojoules */ + UNITS_KW, /**< kilowatt */ + UNITS_BTUperHr, /**< british thermal units per Hour */ + UNITS_GAL, /**< gallons */ + UNITS_L, /**< liters */ + UNITS_kJperHrC, /**< UA, metric units */ + UNITS_BTUperHrF, /**< UA, imperial units */ + UNITS_FT, /**< feet */ + UNITS_M, /**< meters */ + UNITS_FT2, /**< square feet */ + UNITS_M2, /**< square meters */ + UNITS_MIN, /**< minutes */ + UNITS_SEC, /**< seconds */ + UNITS_HR, /**< hours */ + UNITS_GPM, /**< gallons per minute */ + UNITS_LPS /**< liters per second */ + }; + + /** specifies the type of heat source */ + enum HEATSOURCE_TYPE + { + TYPE_none, /**< a default to check to make sure it's been set */ + TYPE_resistance, /**< a resistance element */ + TYPE_compressor /**< a vapor cycle compressor */ + }; + + /** specifies the extrapolation method based on Tair, from the perfmap for a heat source */ + enum EXTRAP_METHOD + { + EXTRAP_LINEAR, /**< the default extrapolates linearly */ + EXTRAP_NEAREST /**< extrapolates using nearest neighbor, will just continue from closest + point */ + }; + + /** specifies the unit type for outputs in the CSV file-s */ + enum CSVOPTIONS + { + CSVOPT_NONE = 0, + CSVOPT_IPUNITS = 1 << 0, + CSVOPT_IS_DRAWING = 1 << 1 + }; + + struct NodeWeight + { + int nodeNum; + double weight; + NodeWeight(int n, double w) : nodeNum(n), weight(w) {}; + + NodeWeight(int n) : nodeNum(n), weight(1.0) {}; + }; + + struct HeatingLogic + { + public: + std::string description; + std::function compare; + + HeatingLogic(std::string desc, + double decisionPoint_in, + HPWH* hpwh_in, + std::function c, + bool isHTS) + : description(desc) + , decisionPoint(decisionPoint_in) + , hpwh(hpwh_in) + , compare(c) + , isEnteringWaterHighTempShutoff(isHTS) {}; + + /**< checks that the input is all valid. */ + virtual const bool isValid() = 0; + /**< gets the value for comparing the tank value to, i.e. the target SoC */ + virtual const double getComparisonValue() = 0; + /**< gets the calculated value from the tank, i.e. SoC or tank average of node weights*/ + virtual const double getTankValue() = 0; + /**< function to calculate where the average node for a logic set is. */ + virtual const double nodeWeightAvgFract() = 0; + /**< gets the fraction of a node that has to be heated up to met the turnoff condition*/ + virtual const double getFractToMeetComparisonExternal() = 0; + + virtual int setDecisionPoint(double value) = 0; + double getDecisionPoint() { return decisionPoint; } + bool getIsEnteringWaterHighTempShutoff() { return isEnteringWaterHighTempShutoff; } + + protected: + double decisionPoint; + HPWH* hpwh; + bool isEnteringWaterHighTempShutoff; + }; + + struct SoCBasedHeatingLogic : HeatingLogic + { + public: + SoCBasedHeatingLogic(std::string desc, + double decisionPoint, + HPWH* hpwh, + double hF = -0.05, + double tM_C = 43.333, + bool constMains = false, + double mains_C = 18.333, + std::function c = std::less()) + : HeatingLogic(desc, decisionPoint, hpwh, c, false) + , hysteresisFraction(hF) + , tempMinUseful_C(tM_C) + , useCostantMains(constMains) + , constantMains_C(mains_C) {}; + const bool isValid(); + + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); + const double getMainsT_C(); + const double getTempMinUseful_C(); + int setDecisionPoint(double value); + int setConstantMainsTemperature(double mains_C); + + private: + double tempMinUseful_C; + double hysteresisFraction; + bool useCostantMains; + double constantMains_C; + }; + + struct TempBasedHeatingLogic : HeatingLogic + { + public: + TempBasedHeatingLogic(std::string desc, + std::vector n, + double decisionPoint, + HPWH* hpwh, + bool a = false, + std::function c = std::less(), + bool isHTS = false) + : HeatingLogic(desc, decisionPoint, hpwh, c, isHTS), nodeWeights(n), isAbsolute(a) {}; + + const bool isValid(); + + const double getComparisonValue(); + const double getTankValue(); + const double nodeWeightAvgFract(); + const double getFractToMeetComparisonExternal(); + + int setDecisionPoint(double value); + int setDecisionPoint(double value, bool absolute); + + private: + const bool areNodeWeightsValid(); + + bool isAbsolute; + std::vector nodeWeights; + }; + + std::shared_ptr shutOffSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + std::shared_ptr turnOnSoC(std::string desc, + double targetSoC, + double hystFract, + double tempMinUseful_C, + bool constMains, + double mains_C); + + std::shared_ptr + wholeTank(double decisionPoint, const UNITS units = UNITS_C, const bool absolute = false); + std::shared_ptr topThird(double decisionPoint); + std::shared_ptr topThird_absolute(double decisionPoint); + std::shared_ptr + secondThird(double decisionPoint, const UNITS units = UNITS_C, const bool absolute = false); + std::shared_ptr bottomThird(double decisionPoint); + std::shared_ptr bottomHalf(double decisionPoint); + std::shared_ptr bottomTwelfth(double decisionPoint); + std::shared_ptr bottomSixth(double decisionPoint); + std::shared_ptr bottomSixth_absolute(double decisionPoint); + std::shared_ptr secondSixth(double decisionPoint); + std::shared_ptr thirdSixth(double decisionPoint); + std::shared_ptr fourthSixth(double decisionPoint); + std::shared_ptr fifthSixth(double decisionPoint); + std::shared_ptr topSixth(double decisionPoint); + + std::shared_ptr standby(double decisionPoint); + std::shared_ptr topNodeMaxTemp(double decisionPoint); + std::shared_ptr + bottomNodeMaxTemp(double decisionPoint, bool isEnteringWaterHighTempShutoff = false); + std::shared_ptr bottomTwelfthMaxTemp(double decisionPoint); + std::shared_ptr topThirdMaxTemp(double decisionPoint); + std::shared_ptr bottomSixthMaxTemp(double decisionPoint); + std::shared_ptr secondSixthMaxTemp(double decisionPoint); + std::shared_ptr fifthSixthMaxTemp(double decisionPoint); + std::shared_ptr topSixthMaxTemp(double decisionPoint); + + std::shared_ptr largeDraw(double decisionPoint); + std::shared_ptr largerDraw(double decisionPoint); + + /// this is the value that the public functions will return in case of a simulation + /// destroying error + static const int HPWH_ABORT = -274000; + + static std::string getVersion(); + /**< This function returns a string with the current version number */ + + int HPWHinit_presets(MODELS presetNum); + /**< This function will reset all member variables to defaults and then + * load in a set of parameters that are hardcoded in this function - + * which particular set of parameters is selected by presetNum. + * This is similar to the way the HPWHsim currently operates, as used in SEEM, + * but not quite as versatile. + * My impression is that this could be a useful input paradigm for CSE + * + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_file(std::string configFile); + /**< This function will load in a set of parameters from a file + * The file name is the input - there should be at most one set of parameters per file + * This is useful for testing new variations, and for the sort of variability + * that we typically do when creating SEEM runs + * Appropriate use of this function can be found in the documentation + + * The return value is 0 for successful initialization, HPWH_ABORT otherwise + */ + + int HPWHinit_resTank(); /**< Default resistance tank, EF 0.95, volume 47.5 */ + int HPWHinit_resTank(double tankVol_L, + double energyFactor, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a resistance tank. Since + * resistance tanks are so simple, they can be specified with only four variables: + * tank volume, energy factor, and the power of the upper and lower elements. Energy + * factor is converted into UA internally, although an external setter for UA is + * also provided in case the energy factor is unknown. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The logics are also set + * to standard setting, with upper as VIP activating when the top third is too cold. + */ + + int HPWHinit_resTankGeneric(double tankVol_L, + double rValue_M2KperW, + double upperPower_W, + double lowerPower_W); + /**< This function will initialize a HPWH object to be a generic resistance storage water + * heater, with a specific R-Value defined at initalization. + * + * Several assumptions regarding the tank configuration are assumed: the lower element + * is at the bottom, the upper element is at the top third. The controls are the same standard + * controls for the HPWHinit_resTank() + */ + + int HPWHinit_genericHPWH(double tankVol_L, double energyFactor, double resUse_C); + /**< This function will initialize a HPWH object to be a non-specific HPWH model + * with an energy factor as specified. Since energy + * factor is not strongly correlated with energy use, most settings + * are taken from the GE2015_STDMode model. + */ + + int runOneStep(double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* extraHeatDist_W = NULL); + /**< This function will progress the simulation forward in time by one step + * all calculated outputs are stored in private variables and accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** An overloaded function that uses takes inletT_C */ + int runOneStep(double inletT_C, + double drawVolume_L, + double ambientT_C, + double externalT_C, + DRMODES DRstatus, + double inletVol2_L = 0., + double inletT2_C = 0., + std::vector* extraHeatDist_W = NULL) + { + setInletT(inletT_C); + return runOneStep(drawVolume_L, + ambientT_C, + externalT_C, + DRstatus, + inletVol2_L, + inletT2_C, + extraHeatDist_W); + }; + + int runNSteps(int N, + double* inletT_C, + double* drawVolume_L, + double* tankAmbientT_C, + double* heatSourceAmbientT_C, + DRMODES* DRstatus); + /**< This function will progress the simulation forward in time by N (equal) steps + * The calculated values will be summed or averaged, as appropriate, and + * then stored in the usual variables to be accessed through functions + * + * The return value is 0 for successful simulation run, HPWH_ABORT otherwise + */ + + /** Setters for the what are typically input variables */ + 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 + specifically input/output energy/power, and runtime + will print to cout if messageCallback pointer is unspecified + does not use verbosity, as it is public and expected to be called only when needed */ + void printTankTemps(); + /**< this prints out all the node temps, kind of nicely formatted + does not use verbosity, as it is public and expected to be called only when needed */ + + int WriteCSVHeading(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + int WriteCSVRow(FILE* outFILE, + const char* preamble = "", + int nTCouples = 6, + int options = CSVOPT_NONE) const; + /**< a couple of function to write the outputs to a file + they both will return 0 for success + the preamble should be supplied with a trailing comma, as these functions do + not add one. Additionally, a newline is written with each call. */ + + /**< Sets the tank node temps based on the provided vector of temps, which are mapped onto the + existing nodes, regardless of numNodes. */ + int setTankLayerTemperatures(std::vector setTemps, const UNITS units = UNITS_C); + void getTankTemps(std::vector& tankTemps); + + bool isSetpointFixed() const; /**< is the setpoint allowed to be changed */ + int setSetpoint(double newSetpoint, UNITS units = UNITS_C); /** 0 minutes and < 1440 + * minutes. */ + double getTimerLimitTOT_minute() const; + /**< Returns the timer limit in minutes for the DR_TOT call. */ + + int getInletHeight(int whichInlet) const; + /**< returns the water inlet height node number */ + + /**< resizes the tankTemp_C and nextTankTemp_C node vectors */ + void setNumNodes(const std::size_t num_nodes); + + /**< returns the number of nodes */ + int getNumNodes() const; + + /**< returns the index of the top node */ + int getIndexTopNode() const; + + double getTankNodeTemp(int nodeNum, UNITS units = UNITS_C) const; + /**< returns the temperature of the water at the specified node - with specified units + or HPWH_ABORT for incorrect node number or unit failure */ + + double getNthSimTcouple(int iTCouple, int nTCouple, UNITS units = UNITS_C) const; + /**< returns the temperature from a set number of virtual "thermocouples" specified by nTCouple, + which are constructed from the node temperature array. Specify iTCouple from 1-nTCouple, + 1 at the bottom using specified units + returns HPWH_ABORT for iTCouple < 0, > nTCouple, or incorrect units */ + + int getNumHeatSources() const; + /**< returns the number of heat sources */ + + int getNumResistanceElements() const; + /**< returns the number of resistance elements */ + + int getCompressorIndex() const; + /**< returns the index of the compressor in the heat source array. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + double getCompressorCapacity(double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C); + /**< Returns the heating output capacity of the compressor for the current HPWH model. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor. Outlet temperatures greater than the max allowable setpoints will return an + error, but for compressors with a fixed setpoint the */ + + int setCompressorOutputCapacity(double newCapacity, + double airTemp = 19.722, + double inletTemp = 14.444, + double outTemp = 57.222, + UNITS pwrUnit = UNITS_KW, + UNITS tempUnit = UNITS_C); + /**< Sets the heating output capacity of the compressor at the defined air, inlet water, and + outlet temperatures. For multi-pass models the capacity is set as the average between the + inletTemp and outTemp since multi-pass models will increase the water temperature only a few + degrees at a time (i.e. maybe 10 degF) until the tank reaches the outTemp, the capacity at + inletTemp might not be accurate for the entire heating cycle. + Note only supports HPWHs with one compressor, if multiple will return the last index + of a compressor */ + + int setScaleHPWHCapacityCOP(double scaleCapacity = 1., double scaleCOP = 1.); + /**< Scales the heatpump water heater input capacity and COP*/ + + int setResistanceCapacity(double power, int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Scale the resistance elements in the heat source list. Which heat source is chosen is + changes is given by "which" + - If which (-1) sets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in heatSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + double getResistanceCapacity(int which = -1, UNITS pwrUNIT = UNITS_KW); + /**< Returns the resistance elements capacity. Which heat source is chosen is changes is given + by "which" + - If which (-1) gets all the resisistance elements in the tank. + - If which (0, 1, 2...) sets the resistance element in a low to high order. + So if there are 3 elements 0 is the bottom, 1 is the middle, and 2 is the top element, + regardless of their order in heatSources. If the elements exist on at the same node then all of + the elements are set. + + The only valid values for which are between -1 and getNumResistanceElements()-1. Since which is + defined as the by the ordered height of the resistance elements it cannot refer to a compressor. + */ + + int getResistancePosition(int elementIndex) const; + + double getNthHeatSourceEnergyInput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy input to the Nth heat source, with the specified units + energy used by the heat source is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ + + double getNthHeatSourceEnergyOutput(int N, UNITS units = UNITS_KWH) const; + /**< returns the energy output from the Nth heat source, with the specified units + energy put into the water is positive - should always be positive + returns HPWH_ABORT for N out of bounds or incorrect units */ + + double getNthHeatSourceRunTime(int N) const; + /**< returns the run time for the Nth heat source, in minutes + note: they may sum to more than 1 time step for concurrently running heat sources + returns HPWH_ABORT for N out of bounds */ + int isNthHeatSourceRunning(int N) const; + /**< returns 1 if the Nth heat source is currently engaged, 0 if it is not, and + returns HPWH_ABORT for N out of bounds */ + HEATSOURCE_TYPE getNthHeatSourceType(int N) const; + /**< returns the enum value for what type of heat source the Nth heat source is */ + + double getOutletTemp(UNITS units = UNITS_C) const; + /**< returns the outlet temperature in the specified units + returns 0 when no draw occurs, or HPWH_ABORT for incorrect unit specifier */ + double getCondenserWaterInletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser inlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getCondenserWaterOutletTemp(UNITS units = UNITS_C) const; + /**< returns the condenser outlet temperature in the specified units + returns 0 when no HP not running occurs, or HPWH_ABORT for incorrect unit specifier */ + + double getExternalVolumeHeated(UNITS units = UNITS_L) const; + /**< returns the volume of water heated in an external in the specified units + returns 0 when no external heat source is running */ + + double getEnergyRemovedFromEnvironment(UNITS units = UNITS_KWH) const; + /**< get the total energy removed from the environment by all heat sources in specified units + (not net energy - does not include standby) + moving heat from the space to the water is the positive direction + returns HPWH_ABORT for incorrect units */ + + double getStandbyLosses(UNITS units = UNITS_KWH) const; + /**< get the amount of heat lost through the tank in specified units + moving heat from the water to the space is the positive direction + negative should occur seldom + returns HPWH_ABORT for incorrect units */ + + double getTankHeatContent_kJ() const; + /**< get the heat content of the tank, relative to zero celsius + * returns using kilojoules */ + + int getHPWHModel() const; + /**< get the model number of the HPWHsim model number of the hpwh */ + + int getCompressorCoilConfig() const; + bool isCompressorMultipass() const; + bool isCompressoExternalMultipass() const; + + bool hasACompressor() const; + /**< Returns if the HPWH model has a compressor or not, could be a storage or resistance tank. + */ + + bool hasExternalHeatSource() const; + /**< Returns if the HPWH model has any external heat sources or not, could be a compressor or + * resistance element. */ + double getExternalMPFlowRate(UNITS units = UNITS_GPM) const; + /**< Returns the constant flow rate for an external multipass heat sources. */ + + double getCompressorMinRuntime(UNITS units = UNITS_MIN) const; + + int getSizingFractions(double& aquafract, double& percentUseable) const; + /**< returns the fraction of total tank volume from the bottom up where the aquastat is + or the turn on logic for the compressor, and the USEable fraction of storage or 1 minus + where the shut off logic is for the compressor. If the logic spans multiple nodes it + returns the weighted average of the nodes */ + + bool isHPWHScalable() const; + /**< returns if the HPWH is scalable or not*/ + + bool shouldDRLockOut(HEATSOURCE_TYPE hs, DRMODES DR_signal) const; + /**< Checks the demand response signal against the different heat source types */ + + void resetTopOffTimer(); + /**< resets variables for timer associated with the DR_TOT call */ + + double getLocationTemp_C() const; + int setMaxTempDepression(double maxDepression, UNITS units = UNITS_C); + + bool hasEnteringWaterHighTempShutOff(int heatSourceIndex); + int setEnteringWaterHighTempShutOff(double highTemp, + bool tempIsAbsolute, + int heatSourceIndex, + UNITS units = UNITS_C); + /**< functions to check for and set specific high temperature shut off logics. + HPWHs can only have one of these, which is at least typical */ + + int setTargetSoCFraction(double target); + + bool canUseSoCControls(); + + int switchToSoCControls(double targetSoC, + double hysteresisFraction = 0.05, + double tempMinUseful = 43.333, + bool constantMainsT = false, + double mainsT = 18.333, + UNITS tempUnit = UNITS_C); + + bool isSoCControlled() const; + + /// Checks whether energy is balanced during a simulation step. + bool isEnergyBalanced(const double drawVol_L, + const double prevHeatContent_kJ, + const double fracEnergyTolerance = 0.001); + + /// Overloaded version of above that allows specification of inlet temperature. + bool isEnergyBalanced(const double drawVol_L, + double inletT_C_in, + const double prevHeatContent_kJ, + const double fracEnergyTolerance) + { + setInletT(inletT_C_in); + return isEnergyBalanced(drawVol_L, prevHeatContent_kJ, fracEnergyTolerance); + } + /// Addition of heat from a normal heat sources; return excess heat, if needed, to prevent + /// exceeding maximum or setpoint + double addHeatAboveNode(double qAdd_kJ, const int nodeNum, const double maxT_C); - MODELS hpwhModel; - /**< The hpwh should know which preset initialized it, or if it was from a fileget */ + /// Addition of extra heat handled separately from normal heat sources + void addExtraHeatAboveNode(double qAdd_kJ, const int nodeNum); - // a std::vector containing the HeatSources, in order of priority - std::vector heatSources; + private: + class HeatSource; - int compressorIndex; - /**< The index of the compressor heat source (set to -1 if no compressor)*/ + void setAllDefaults(); /**< sets all the defaults default */ - int lowestElementIndex; - /**< The index of the lowest resistance element heat source (set to -1 if no resistance elements)*/ + void updateTankTemps( + double draw, double inletT_C, double ambientT_C, double inletVol2_L, double inletT2_L); + void mixTankInversions(); + /**< Mixes the any temperature inversions in the tank after all the temperature calculations */ + void updateSoCIfNecessary(); - int highestElementIndex; - /**< The index of the highest resistance element heat source. if only one element it equals lowestElementIndex (set to -1 if no resistance elements)*/ + bool areAllHeatSourcesOff() const; + /**< test if all the heat sources are off */ + void turnAllHeatSourcesOff(); + /**< disengage each heat source */ - int VIPIndex; - /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance elements)*/ + void addHeatParent(HeatSource* heatSourcePtr, double heatSourceAmbientT_C, double minutesToRun); - int inletHeight; - /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 and numNodes-1 */ + /// adds extra heat to the set of nodes that are at the same temperature, above the + /// specified node number + void modifyHeatDistribution(std::vector& heatDistribution); + void addExtraHeat(std::vector& extraHeatDist_W); - int inlet2Height; - /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be between 0 and numNodes-1 */ + /// "extra" heat added during a simulation step + double extraEnergyInput_kWh; - /**< the volume in liters of the tank */ - double tankVolume_L; + double tankAvg_C(const std::vector nodeWeights) const; + /**< functions to calculate what the temperature in a portion of the tank is */ - /**< the UA of the tank, in metric units */ - double tankUA_kJperHrC; + void mixTankNodes(int mixedAboveNode, int mixedBelowNode, double mixFactor); + /**< function to average the nodes in a tank together bewtween the mixed abovenode and mixed + * below node. */ - /**< the UA of the fittings for the tank, in metric units */ - double fittingsUA_kJperHrC; + void calcDerivedValues(); + /**< a helper function for the inits, calculating condentropy and the lowest node */ + void calcSizeConstants(); + /**< a helper function to set constants for the UA and tank size*/ + void calcDerivedHeatingValues(); + /**< a helper for the helper, calculating condentropy and the lowest node*/ + void mapResRelativePosToHeatSources(); + /**< a helper function for the inits, creating a mapping function for the position of the + resistance elements to their indexes in heatSources. */ - /**< the volume (L) of a single node */ - double nodeVolume_L; + int checkInputs(); + /**< a helper function to run a few checks on the HPWH input parameters */ - /**< the mass of water (kg) in a single node */ - double nodeMass_kg; + double getChargePerNode(double tCold, double tMix, double tHot) const; - /**< the heat capacity of the water (kJ/�C) in a single node */ - double nodeCp_kJperC; + void calcAndSetSoCFraction(); - /**< the height in meters of the one node */ - double nodeHeight_m; + 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; - double fracAreaTop; - /**< the fraction of the UA on the top and bottom of the tank, assuming it's a cylinder */ - double fracAreaSide; - /**< the fraction of the UA on the sides of the tank, assuming it's a cylinder */ + bool simHasFailed; + /**< did an internal error cause the simulation to fail? */ - double currentSoCFraction; - /**< the current state of charge according to the logic */ + bool isHeating; + /**< is the hpwh currently heating or not? */ - double setpoint_C; - /**< the setpoint of the tank */ + bool setpointFixed; + /**< does the HPWH allow the setpoint to vary */ - /**< holds the temperature of each node - 0 is the bottom node */ - std::vector tankTemps_C; + bool tankSizeFixed; + /**< does the HPWH have a constant tank size or can it be changed */ - /**< holds the future temperature of each node for the conduction calculation - 0 is the bottom node */ - std::vector nextTankTemps_C; + bool canScale; + /**< can the HPWH scale capactiy and COP or not */ - DRMODES prevDRstatus; - /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ + VERBOSITY hpwhVerbosity; + /**< an enum to let the sim know how much output to say */ - double timerLimitTOT; - /**< the time limit in minutes on the timer when the compressor and resistance elements are turned back on, used with DR_TOT. */ - double timerTOT; - /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ + 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 */ - bool usesSoCLogic; + MODELS hpwhModel; + /**< The hpwh should know which preset initialized it, or if it was from a fileget */ - // Some outputs - double outletTemp_C; - /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ + // a std::vector containing the HeatSources, in order of priority + std::vector heatSources; - double condenserInlet_C; - /**< the temperature of the inlet water to the condensor either an average of tank nodes or taken from the bottom, 0 if no flow or no compressor */ - double condenserOutlet_C; - /**< the temperature of the outlet water from the condensor either, 0 if no flow or no compressor */ - double externalVolumeHeated_L; - /**< the volume of water heated by an external source, 0 if no flow or no external heat source */ + int compressorIndex; + /**< The index of the compressor heat source (set to -1 if no compressor)*/ - double energyRemovedFromEnvironment_kWh; - /**< the total energy removed from the environment, to heat the water */ - double standbyLosses_kWh; - /**< the amount of heat lost to standby */ + int lowestElementIndex; + /**< The index of the lowest resistance element heat source (set to -1 if no resistance + * elements)*/ - // special variables for adding abilities - bool tankMixesOnDraw; - /**< whether or not the bottom fraction (defined by mixBelowFraction) - of the tank should mix during draws */ - double mixBelowFractionOnDraw; - /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ + int highestElementIndex; + /**< The index of the highest resistance element heat source. if only one element it equals + * lowestElementIndex (set to -1 if no resistance elements)*/ - bool doTempDepression; - /**< whether the HPWH should use the alternate ambient temperature that - gets depressed when a compressor is running - NOTE: this only works for 1 minute steps */ - double locationTemperature_C; - /**< this is the special location temperature that stands in for the the - ambient temperature if you are doing temp. depression */ - double maxDepression_C = 2.5; - /** a couple variables to hold values which are typically inputs */ - double member_inletT_C; + int VIPIndex; + /**< The index of the VIP resistance element heat source (set to -1 if no VIP resistance + * elements)*/ - double minutesPerStep = 1.; - double secondsPerStep,hoursPerStep; + int inletHeight; + /**< the number of a node in the tank that the inlet water enters the tank at, must be between 0 + * and numNodes-1 */ - bool doInversionMixing; - /**< If and only if true will model temperature inversion mixing in the tank */ + int inlet2Height; + /**< the number of a node in the tank that the 2nd inlet water enters the tank at, must be + * between 0 and numNodes-1 */ - bool doConduction; - /**< If and only if true will model conduction between the internal nodes of the tank */ + /**< the volume in liters of the tank */ + double tankVolume_L; + + /**< the UA of the tank, in metric units */ + double tankUA_kJperHrC; - struct resPoint { - int index; - int position; - }; - std::vector resistanceHeightMap; - /**< A map from index of an resistance element in heatSources to position in the tank, its - is sorted by height from lowest to highest*/ - - /// Generates a vector of logical nodes - std::vector getNodeWeightRange(double bottomFraction,double topFraction); - - /// False: water is drawn from the tank itself; True: tank provides heat exchange only - bool hasHeatExchanger; - - /// Coefficient (0-1) of effectiveness for heat exchange between tank and water line (used by heat-exchange models only). - double heatExchangerEffectiveness; - - /// Coefficient (0-1) of effectiveness for heat exchange between a single tank node and water line (derived from heatExchangerEffectiveness). - double nodeHeatExchangerEffectiveness; - -}; //end of HPWH class - -class HPWH::HeatSource { -public: - friend class HPWH; - - HeatSource(){} /**< default constructor, does not create a useful HeatSource */ - HeatSource(HPWH *parentHPWH); - /**< constructor assigns a pointer to the hpwh that owns this heat source */ - HeatSource(const HeatSource &hSource); ///copy constructor - HeatSource& operator=(const HeatSource &hSource); ///assignment operator - /**< the copy constructor and assignment operator basically just checks if there - are backup/companion pointers - these can't be copied */ - - void setupAsResistiveElement(int node,double Watts,int condensitySize = CONDENSITY_SIZE); - /**< configure the heat source to be a resisive element, positioned at the - specified node, with the specified power in watts */ - - bool isEngaged() const; - /**< return whether or not the heat source is engaged */ - void engageHeatSource(DRMODES DRstatus = DR_ALLOW); - /**< turn heat source on, i.e. set isEngaged to TRUE */ - void disengageHeatSource(); - /**< turn heat source off, i.e. set isEngaged to FALSE */ - - bool isLockedOut() const; - /**< return whether or not the heat source is locked out */ - void lockOutHeatSource(); - /**< lockout heat source, i.e. set isLockedOut to TRUE */ - void unlockHeatSource(); - /**< unlock heat source, i.e. set isLockedOut to FALSE */ - - bool shouldLockOut(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should lock out */ - bool shouldUnlock(double heatSourceAmbientT_C) const; - /**< queries the heat source as to whether it should unlock */ - - bool toLockOrUnlock(double heatSourceAmbientT_C); - /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ - - bool shouldHeat() const; - /**< queries the heat source as to whether or not it should turn on */ - bool shutsOff() const; - /**< queries the heat source whether should shut off */ - - bool maxedOut() const; - /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at setpoint. */ - - int findParent() const; - /**< returns the index of the heat source where this heat source is a backup. - returns -1 if none found. */ - - double fractToMeetComparisonExternal() const; - /**< calculates the distance the current state is from the shutOff logic for external configurations*/ - - void addHeat(double externalT_C,double minutesToRun); - /**< adds heat to the hpwh - this is the function that interprets the - various configurations (internal/external, resistance/heat pump) to add heat */ - - /// Assign new condensity values from supplied vector. Note the input vector is currently resampled - /// to preserve a condensity vector of size CONDENSITY_SIZE. - void setCondensity(const std::vector &condensity_in); - - int getCondensitySize() const; - - void linearInterp(double &ynew,double xnew,double x0,double x1,double y0,double y1); - /**< Does a simple linear interpolation between two points to the xnew point */ - - void regressedMethod(double &ynew,std::vector &coefficents,double x1,double x2,double x3); - /**< Does a calculation based on the ten term regression equation */ - - void regressedMethodMP(double &ynew,std::vector &coefficents,double x1,double x2); - /**< Does a calculation based on the five term regression equation for MP split systems */ - - void btwxtInterp(double& input_BTUperHr,double& cop,std::vector& target); - /**< Does a linear interpolation in btwxt to the target point*/ - - void setupDefrostMap(double derate35 = 0.8865); - /**< configure the heat source with a default for the defrost derating */ - void defrostDerate(double &to_derate,double airT_C); - /**< Derates the COP of a system based on the air temperature */ - -private: - //start with a few type definitions - enum COIL_CONFIG { - CONFIG_SUBMERGED, - CONFIG_WRAPPED, - CONFIG_EXTERNAL - }; - - /** the creator of the heat source, necessary to access HPWH variables */ - HPWH *hpwh; - - // these are the heat source state/output variables - bool isOn; - /**< is the heat source running or not */ - - bool lockedOut; - /**< is the heat source locked out */ - - bool doDefrost; - /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ - - // some outputs - double runtime_min; - /**< this is the percentage of the step that the heat source was running */ - double energyInput_kWh; - /**< the energy used by the heat source */ - double energyOutput_kWh; - /**< the energy put into the water by the heat source */ - -// these are the heat source property variables - bool isVIP; - /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ - HeatSource* backupHeatSource; - /**< a pointer to the heat source which serves as backup to this one - should be NULL if no backup exists */ - HeatSource* companionHeatSource; - /**< a pointer to the heat source which will run concurrently with this one - it still will only turn on if shutsOff is false */ - - HeatSource* followedByHeatSource; - /**< a pointer to the heat source which will attempt to run after this one */ - - // condensity is represented as a std::vector of size CONDENSITY_SIZE. - // It represents the location within the tank where heat will be distributed, - // and it also is used to calculate the condenser temperature for inputPower/COP calcs. - // It is conceptually linked to the way condenser coils are wrapped around - // (or within) the tank, however a resistance heat source can also be simulated - // by specifying the entire condensity in one node. */ - std::vector condensity; - - double Tshrinkage_C; - /**< Tshrinkage_C is a derived from the condentropy (conditional entropy), - using the condensity and fixed parameters Talpha_C and Tbeta_C. - Talpha_C and Tbeta_C are not intended to be settable - see the hpwh_init functions for calculation of shrinkage */ - - struct perfPoint { - double T_F; - std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T - std::vector COP_coeffs; // c0 + c1*T + c2*T*T - }; - - std::vector perfMap; - /**< A map with input/COP quadratic curve coefficients at a given external temperature */ - - std::vector< std::vector > perfGrid; - /**< The axis values defining the regular grid for the performance data. - SP would have 3 axis, MP would have 2 axis*/ - - std::vector< std::vector > perfGridValues; - /**< The values for input power and cop use matching to the grid. Should be long format with { { inputPower_W }, { COP } }. */ - - class Btwxt::RegularGridInterpolator *perfRGI; - /**< The grid interpolator used for mapping performance*/ - - bool useBtwxtGrid; - - /** a vector to hold the set of logical choices for turning this element on */ - std::vector> turnOnLogicSet; - /** a vector to hold the set of logical choices that can cause an element to turn off */ - std::vector> shutOffLogicSet; - /** a single logic that checks the bottom point is below a temperature so the system doesn't short cycle*/ - std::shared_ptr standbyLogic; - - /** some compressors have a resistance element for defrost*/ - struct resistanceElementDefrost - { - double inputPwr_kW; - double constTempLift_dF; - double onBelowT_F; - }; - resistanceElementDefrost resDefrost; - - struct defrostPoint { - double T_F; - double derate_fraction; - }; - std::vector defrostMap; - /**< A list of points for the defrost derate factor ordered by increasing external temperature */ - - struct maxOut_minAir { - double outT_C; - double airT_C; - }; - maxOut_minAir maxOut_at_LowT; - /**< maximum output temperature at the minimum operating temperature of HPWH environment (minT)*/ - - struct SecondaryHeatExchanger { - double coldSideTemperatureOffest_dC; - double hotSideTemperatureOffset_dC; - double extraPumpPower_W; - }; - - SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary heat exchanger by adding extra input energy for the pump and - an increaes in the water to the incoming waater temperature to the heatpump*/ - - void addTurnOnLogic(std::shared_ptr logic); - void addShutOffLogic(std::shared_ptr logic); - /**< these are two small functions to remove some of the cruft in initiation functions */ - void clearAllTurnOnLogic(); - void clearAllShutOffLogic(); - void clearAllLogic(); - /**< these are two small functions to remove some of the cruft in initiation functions */ - - - - void changeResistanceWatts(double watts); - /**< function to change the resistance wattage */ - - bool isACompressor() const; - /**< returns if the heat source uses a compressor or not */ - bool isAResistance() const; - /**< returns if the heat source uses a resistance element or not */ - bool isExternalMultipass() const; - - double minT; - /**< minimum operating temperature of HPWH environment */ - - double maxT; - /**< maximum operating temperature of HPWH environment */ - - double maxSetpoint_C; - /**< the maximum setpoint of the heat source can create, used for compressors predominately */ - - double hysteresis_dC; - /**< a hysteresis term that prevents short cycling due to heat pump self-interaction - when the heat source is engaged, it is subtracted from lowT cutoffs and - added to lowTreheat cutoffs */ + /**< the UA of the fittings for the tank, in metric units */ + double fittingsUA_kJperHrC; - bool depressesTemperature; - /**< heat pumps can depress the temperature of their space in certain instances - - whether or not this occurs is a bool in HPWH, but a heat source must - know if it is capable of contributing to this effect or not - NOTE: this only works for 1 minute steps - ALSO: this is set according the the heat source type, not user-specified */ + /**< the volume (L) of a single node */ + double nodeVolume_L; - double airflowFreedom; - /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor - cop (not capacity) for cases where the air flow is restricted - typically ducting */ + /**< the mass of water (kg) in a single node */ + double nodeMass_kg; - int externalInletHeight; /** tankTemps_C; - // some private functions, mostly used for heating the water with the addHeat function + /**< holds the future temperature of each node for the conduction calculation - 0 is the bottom + * node */ + std::vector nextTankTemps_C; - double addHeatExternal(double externalT_C,double minutesToRun,double &cap_BTUperHr,double &input_BTUperHr,double &cop); - /**< Add heat from a source outside of the tank. Assume the condensity is where - the water is drawn from and hot water is put at the top of the tank. */ + DRMODES prevDRstatus; + /**< the DRstatus of the tank in the previous time step and at the end of runOneStep */ - /** I wrote some methods to help with the add heat interface - MJL */ - void getCapacity(double externalT_C,double condenserTemp_C,double setpointTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop); + double timerLimitTOT; + /**< the time limit in minutes on the timer when the compressor and resistance elements are + * turned back on, used with DR_TOT. */ + double timerTOT; + /**< the timer used for DR_TOT to turn on the compressor and resistance elements. */ - /** An overloaded function that uses uses the setpoint temperature */ - void getCapacity(double externalT_C,double condenserTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop) { - getCapacity(externalT_C,condenserTemp_C,hpwh->getSetpoint(),input_BTUperHr,cap_BTUperHr,cop); - }; - /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ - void getCapacityMP(double externalT_C,double condenserTemp_C,double &input_BTUperHr,double &cap_BTUperHr,double &cop); + bool usesSoCLogic; - double calcMPOutletTemperature(double heatingCapacity_KW); - /**< returns the temperature of outlet of a external multipass hpwh */ + // Some outputs + double outletTemp_C; + /**< the temperature of the outlet water - taken from top of tank, 0 if no flow */ - void calcHeatDist(std::vector &heatDistribution); + double condenserInlet_C; + /**< the temperature of the inlet water to the condensor either an average of tank nodes or + * taken from the bottom, 0 if no flow or no compressor */ + double condenserOutlet_C; + /**< the temperature of the outlet water from the condensor either, 0 if no flow or no + * compressor */ + double externalVolumeHeated_L; + /**< the volume of water heated by an external source, 0 if no flow or no external heat source + */ - double getTankTemp() const; - /**< returns the tank temperature weighted by the condensity for this heat source */ + double energyRemovedFromEnvironment_kWh; + /**< the total energy removed from the environment, to heat the water */ + double standbyLosses_kWh; + /**< the amount of heat lost to standby */ - void sortPerformanceMap(); - /**< sorts the Performance Map by increasing external temperatures */ + // special variables for adding abilities + bool tankMixesOnDraw; + /**< whether or not the bottom fraction (defined by mixBelowFraction) + of the tank should mix during draws */ + double mixBelowFractionOnDraw; + /**< mixes the tank below this fraction on draws iff tankMixesOnDraw */ -}; // end of HeatSource class + bool doTempDepression; + /**< whether the HPWH should use the alternate ambient temperature that + gets depressed when a compressor is running + NOTE: this only works for 1 minute steps */ + double locationTemperature_C; + /**< this is the special location temperature that stands in for the the + ambient temperature if you are doing temp. depression */ + double maxDepression_C = 2.5; + /** a couple variables to hold values which are typically inputs */ + double member_inletT_C; + + double minutesPerStep = 1.; + double secondsPerStep, hoursPerStep; + + bool doInversionMixing; + /**< If and only if true will model temperature inversion mixing in the tank */ + + bool doConduction; + /**< If and only if true will model conduction between the internal nodes of the tank */ -constexpr double BTUperKWH = 3412.14163312794; // https://www.rapidtables.com/convert/energy/kWh_to_BTU.html -constexpr double FperC = 9. / 5.; // degF / degC -constexpr double offsetF = 32.; // degF offset + struct resPoint + { + int index; + int position; + }; + std::vector resistanceHeightMap; + /**< A map from index of an resistance element in heatSources to position in the tank, its + is sorted by height from lowest to highest*/ + + /// Generates a vector of logical nodes + std::vector getNodeWeightRange(double bottomFraction, double topFraction); + + /// False: water is drawn from the tank itself; True: tank provides heat exchange only + bool hasHeatExchanger; + + /// Coefficient (0-1) of effectiveness for heat exchange between tank and water line (used by + /// heat-exchange models only). + double heatExchangerEffectiveness; + + /// Coefficient (0-1) of effectiveness for heat exchange between a single tank node and water + /// line (derived from heatExchangerEffectiveness). + double nodeHeatExchangerEffectiveness; + +}; // end of HPWH class + +class HPWH::HeatSource +{ + public: + friend class HPWH; + + HeatSource() {} /**< default constructor, does not create a useful HeatSource */ + HeatSource(HPWH* parentHPWH); + /**< constructor assigns a pointer to the hpwh that owns this heat source */ + HeatSource(const HeatSource& hSource); /// copy constructor + HeatSource& operator=(const HeatSource& hSource); /// assignment operator + /**< the copy constructor and assignment operator basically just checks if there + are backup/companion pointers - these can't be copied */ + + void setupAsResistiveElement(int node, double Watts, int condensitySize = CONDENSITY_SIZE); + /**< configure the heat source to be a resisive element, positioned at the + specified node, with the specified power in watts */ + + bool isEngaged() const; + /**< return whether or not the heat source is engaged */ + void engageHeatSource(DRMODES DRstatus = DR_ALLOW); + /**< turn heat source on, i.e. set isEngaged to TRUE */ + void disengageHeatSource(); + /**< turn heat source off, i.e. set isEngaged to FALSE */ + + bool isLockedOut() const; + /**< return whether or not the heat source is locked out */ + void lockOutHeatSource(); + /**< lockout heat source, i.e. set isLockedOut to TRUE */ + void unlockHeatSource(); + /**< unlock heat source, i.e. set isLockedOut to FALSE */ + + bool shouldLockOut(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should lock out */ + bool shouldUnlock(double heatSourceAmbientT_C) const; + /**< queries the heat source as to whether it should unlock */ + + bool toLockOrUnlock(double heatSourceAmbientT_C); + /**< combines shouldLockOut and shouldUnlock to one master function which locks or unlocks the + * heatsource. Return boolean lockedOut (true if locked, false if unlocked)*/ + + bool shouldHeat() const; + /**< queries the heat source as to whether or not it should turn on */ + bool shutsOff() const; + /**< queries the heat source whether should shut off */ + + bool maxedOut() const; + /**< queries the heat source as to if it shouldn't produce hotter water and the tank isn't at + * setpoint. */ + + int findParent() const; + /**< returns the index of the heat source where this heat source is a backup. + returns -1 if none found. */ + + double fractToMeetComparisonExternal() const; + /**< calculates the distance the current state is from the shutOff logic for external + * configurations*/ + + void addHeat(double externalT_C, double minutesToRun); + /**< adds heat to the hpwh - this is the function that interprets the + various configurations (internal/external, resistance/heat pump) to add heat */ + + /// Assign new condensity values from supplied vector. Note the input vector is currently + /// resampled to preserve a condensity vector of size CONDENSITY_SIZE. + void setCondensity(const std::vector& condensity_in); + + int getCondensitySize() const; + + void linearInterp(double& ynew, double xnew, double x0, double x1, double y0, double y1); + /**< Does a simple linear interpolation between two points to the xnew point */ + + void regressedMethod( + double& ynew, std::vector& coefficents, double x1, double x2, double x3); + /**< Does a calculation based on the ten term regression equation */ + + void regressedMethodMP(double& ynew, std::vector& coefficents, double x1, double x2); + /**< Does a calculation based on the five term regression equation for MP split systems */ + + void btwxtInterp(double& input_BTUperHr, double& cop, std::vector& target); + /**< Does a linear interpolation in btwxt to the target point*/ + + void setupDefrostMap(double derate35 = 0.8865); + /**< configure the heat source with a default for the defrost derating */ + void defrostDerate(double& to_derate, double airT_C); + /**< Derates the COP of a system based on the air temperature */ + + private: + // start with a few type definitions + enum COIL_CONFIG + { + CONFIG_SUBMERGED, + CONFIG_WRAPPED, + CONFIG_EXTERNAL + }; + + /** the creator of the heat source, necessary to access HPWH variables */ + HPWH* hpwh; + + // these are the heat source state/output variables + bool isOn; + /**< is the heat source running or not */ + + bool lockedOut; + /**< is the heat source locked out */ + + bool doDefrost; + /**< If and only if true will derate the COP of a compressor to simulate a defrost cycle */ + + // some outputs + double runtime_min; + /**< this is the percentage of the step that the heat source was running */ + double energyInput_kWh; + /**< the energy used by the heat source */ + double energyOutput_kWh; + /**< the energy put into the water by the heat source */ + + // these are the heat source property variables + bool isVIP; + /**< is this heat source a high priority heat source? (e.g. upper resisitor) */ + HeatSource* backupHeatSource; + /**< a pointer to the heat source which serves as backup to this one + should be NULL if no backup exists */ + HeatSource* companionHeatSource; + /**< a pointer to the heat source which will run concurrently with this one + it still will only turn on if shutsOff is false */ + + HeatSource* followedByHeatSource; + /**< a pointer to the heat source which will attempt to run after this one */ + + // condensity is represented as a std::vector of size CONDENSITY_SIZE. + // It represents the location within the tank where heat will be distributed, + // and it also is used to calculate the condenser temperature for inputPower/COP calcs. + // It is conceptually linked to the way condenser coils are wrapped around + // (or within) the tank, however a resistance heat source can also be simulated + // by specifying the entire condensity in one node. */ + std::vector condensity; + + double Tshrinkage_C; + /**< Tshrinkage_C is a derived from the condentropy (conditional entropy), + using the condensity and fixed parameters Talpha_C and Tbeta_C. + Talpha_C and Tbeta_C are not intended to be settable + see the hpwh_init functions for calculation of shrinkage */ + + struct perfPoint + { + double T_F; + std::vector inputPower_coeffs; // c0 + c1*T + c2*T*T + std::vector COP_coeffs; // c0 + c1*T + c2*T*T + }; + + std::vector perfMap; + /**< A map with input/COP quadratic curve coefficients at a given external temperature */ + + std::vector> perfGrid; + /**< The axis values defining the regular grid for the performance data. + SP would have 3 axis, MP would have 2 axis*/ + + std::vector> perfGridValues; + /**< The values for input power and cop use matching to the grid. Should be long format with { { + * inputPower_W }, { COP } }. */ + + class Btwxt::RegularGridInterpolator* perfRGI; + /**< The grid interpolator used for mapping performance*/ + + bool useBtwxtGrid; + + /** a vector to hold the set of logical choices for turning this element on */ + std::vector> turnOnLogicSet; + /** a vector to hold the set of logical choices that can cause an element to turn off */ + std::vector> shutOffLogicSet; + /** a single logic that checks the bottom point is below a temperature so the system doesn't + * short cycle*/ + std::shared_ptr standbyLogic; + + /** some compressors have a resistance element for defrost*/ + struct resistanceElementDefrost + { + double inputPwr_kW; + double constTempLift_dF; + double onBelowT_F; + }; + resistanceElementDefrost resDefrost; + + struct defrostPoint + { + double T_F; + double derate_fraction; + }; + std::vector defrostMap; + /**< A list of points for the defrost derate factor ordered by increasing external temperature + */ + + struct maxOut_minAir + { + double outT_C; + double airT_C; + }; + maxOut_minAir maxOut_at_LowT; + /**< maximum output temperature at the minimum operating temperature of HPWH environment + * (minT)*/ + + struct SecondaryHeatExchanger + { + double coldSideTemperatureOffest_dC; + double hotSideTemperatureOffset_dC; + double extraPumpPower_W; + }; + + SecondaryHeatExchanger secondaryHeatExchanger; /**< adjustments for a approximating a secondary + heat exchanger by adding extra input energy for the pump and an increaes in the water to the + incoming waater temperature to the heatpump*/ + + void addTurnOnLogic(std::shared_ptr logic); + void addShutOffLogic(std::shared_ptr logic); + /**< these are two small functions to remove some of the cruft in initiation functions */ + void clearAllTurnOnLogic(); + void clearAllShutOffLogic(); + void clearAllLogic(); + /**< these are two small functions to remove some of the cruft in initiation functions */ + + void changeResistanceWatts(double watts); + /**< function to change the resistance wattage */ + + bool isACompressor() const; + /**< returns if the heat source uses a compressor or not */ + bool isAResistance() const; + /**< returns if the heat source uses a resistance element or not */ + bool isExternalMultipass() const; + + double minT; + /**< minimum operating temperature of HPWH environment */ + + double maxT; + /**< maximum operating temperature of HPWH environment */ + + double maxSetpoint_C; + /**< the maximum setpoint of the heat source can create, used for compressors predominately */ + + double hysteresis_dC; + /**< a hysteresis term that prevents short cycling due to heat pump self-interaction + when the heat source is engaged, it is subtracted from lowT cutoffs and + added to lowTreheat cutoffs */ + + bool depressesTemperature; + /**< heat pumps can depress the temperature of their space in certain instances - + whether or not this occurs is a bool in HPWH, but a heat source must + know if it is capable of contributing to this effect or not + NOTE: this only works for 1 minute steps + ALSO: this is set according the the heat source type, not user-specified */ + + double airflowFreedom; + /**< airflowFreedom is the fraction of full flow. This is used to de-rate compressor + cop (not capacity) for cases where the air flow is restricted - typically ducting */ + + int externalInletHeight; /**getSetpoint(), input_BTUperHr, cap_BTUperHr, cop); + }; + /** An equivalent getCapcity function just for multipass external (or split) HPWHs */ + void getCapacityMP(double externalT_C, + double condenserTemp_C, + double& input_BTUperHr, + double& cap_BTUperHr, + double& cop); + + double calcMPOutletTemperature(double heatingCapacity_KW); + /**< returns the temperature of outlet of a external multipass hpwh */ + + void calcHeatDist(std::vector& heatDistribution); + + double getTankTemp() const; + /**< returns the tank temperature weighted by the condensity for this heat source */ + + void sortPerformanceMap(); + /**< sorts the Performance Map by increasing external temperatures */ + +}; // end of HeatSource class + +constexpr double BTUperKWH = + 3412.14163312794; // https://www.rapidtables.com/convert/energy/kWh_to_BTU.html +constexpr double FperC = 9. / 5.; // degF / degC +constexpr double offsetF = 32.; // degF offset constexpr double sec_per_min = 60.; // seconds / min -constexpr double min_per_hr = 60.; // min / hr +constexpr double min_per_hr = 60.; // min / hr constexpr double sec_per_hr = sec_per_min * min_per_hr; // seconds / hr // a few extra functions for unit conversion @@ -1351,37 +1525,42 @@ inline double FT2_TO_M2(double feet2) { return (feet2 / 10.7640); } inline double MIN_TO_SEC(double minute) { return minute * sec_per_min; } inline double MIN_TO_HR(double minute) { return minute / min_per_hr; } -inline HPWH::DRMODES operator|(HPWH::DRMODES a,HPWH::DRMODES b) +inline HPWH::DRMODES operator|(HPWH::DRMODES a, HPWH::DRMODES b) { - return static_cast(static_cast(a) | static_cast(b)); + return static_cast(static_cast(a) | static_cast(b)); } -template< typename T> inline bool aboutEqual(T a,T b) { return fabs(a - b) < HPWH::TOL_MINVALUE; } +template +inline bool aboutEqual(T a, T b) +{ + return fabs(a - b) < HPWH::TOL_MINVALUE; +} /// Generate an absolute or relative temperature in degC. -inline double convertTempToC(const double T_F_or_C,const HPWH::UNITS units,const bool absolute){ - return (units == HPWH::UNITS_C) ? T_F_or_C : (absolute ? F_TO_C(T_F_or_C) : dF_TO_dC(T_F_or_C)); +inline double convertTempToC(const double T_F_or_C, const HPWH::UNITS units, const bool absolute) +{ + return (units == HPWH::UNITS_C) ? T_F_or_C : (absolute ? F_TO_C(T_F_or_C) : dF_TO_dC(T_F_or_C)); } // resampling utility functions -double getResampledValue(const std::vector &values,double beginFraction,double endFraction); -bool resample(std::vector &values,const std::vector &sampleValues); -inline bool resampleIntensive(std::vector &values,const std::vector &sampleValues) +double +getResampledValue(const std::vector& values, double beginFraction, double endFraction); +bool resample(std::vector& values, const std::vector& sampleValues); +inline bool resampleIntensive(std::vector& values, const std::vector& sampleValues) { - return resample(values,sampleValues); + return resample(values, sampleValues); } -bool resampleExtensive(std::vector &values,const std::vector &sampleValues); +bool resampleExtensive(std::vector& values, const std::vector& sampleValues); /// helper functions -double expitFunc(double x,double offset); -void normalize(std::vector &distribution); -int findLowestNode(const std::vector &nodeDist,const int numTankNodes); -double findShrinkageT_C(const std::vector &nodeDist); -void calcThermalDist( - std::vector &thermalDist, - const double shrinkageT_C, - const int lowestNode, - const std::vector &nodeTemp_C, - const double setpointT_C); +double expitFunc(double x, double offset); +void normalize(std::vector& distribution); +int findLowestNode(const std::vector& nodeDist, const int numTankNodes); +double findShrinkageT_C(const std::vector& nodeDist); +void calcThermalDist(std::vector& thermalDist, + const double shrinkageT_C, + const int lowestNode, + const std::vector& nodeTemp_C, + const double setpointT_C); #endif diff --git a/src/HPWHversion.in.hh b/src/HPWHversion.in.hh index 7adffdc4..b7a093d4 100644 --- a/src/HPWHversion.in.hh +++ b/src/HPWHversion.in.hh @@ -1,13 +1,15 @@ /* -* Version control -*/ + * Version control + */ #ifndef HPWHversion_hh #define HPWHversion_hh +// clang-format off #define HPWHVRSN_MAJOR @HPWHsim_VRSN_MAJOR@ #define HPWHVRSN_MINOR @HPWHsim_VRSN_MINOR@ #define HPWHVRSN_PATCH @HPWHsim_VRSN_PATCH@ #define HPWHVRSN_META "@HPWHsim_VRSN_META@" +// clang-format on #endif From e1fb54151c02dba0536e85d2fa18a7d692e5bc56 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Wed, 20 Dec 2023 15:45:59 -0700 Subject: [PATCH 8/9] Add final newline. --- test/testPerformanceMaps.cc | 2 +- test/testSizingFractions.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testPerformanceMaps.cc b/test/testPerformanceMaps.cc index f43a9c1b..67f642fb 100644 --- a/test/testPerformanceMaps.cc +++ b/test/testPerformanceMaps.cc @@ -679,4 +679,4 @@ int main(int, char*) // Made it through the gauntlet return 0; -} \ No newline at end of file +} diff --git a/test/testSizingFractions.cc b/test/testSizingFractions.cc index 9ac3b341..9a3664d6 100644 --- a/test/testSizingFractions.cc +++ b/test/testSizingFractions.cc @@ -173,4 +173,4 @@ void testGetCompressorMinRuntime() double hrs = hpwh.getCompressorMinRuntime(HPWH::UNITS_HR); ASSERTTRUE(hrs == expected_hrs); -} \ No newline at end of file +} From 2aef89fc46449de16cdd66dd342422ab5b936ba7 Mon Sep 17 00:00:00 2001 From: Tanaya Mankad Date: Thu, 21 Dec 2023 13:16:03 -0700 Subject: [PATCH 9/9] Revert btwxt to version from main branch. --- vendor/btwxt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/btwxt b/vendor/btwxt index 3f2e487e..2a5926e9 160000 --- a/vendor/btwxt +++ b/vendor/btwxt @@ -1 +1 @@ -Subproject commit 3f2e487e412d6b0d2b169e812104b6c2f4a63b40 +Subproject commit 2a5926e96b594bafbcaa7640a9cabd40b5ae043d