Skip to content

Commit

Permalink
Merge pull request #142 from EcotopeResearch/add-btwxt
Browse files Browse the repository at this point in the history
Add btwxt for Mitsu QAHV
  • Loading branch information
chipbarnaby committed Mar 26, 2022
2 parents 2e34183 + 699ff59 commit 094fd14
Show file tree
Hide file tree
Showing 31 changed files with 9,400 additions and 7,213 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
@@ -0,0 +1,3 @@
[submodule "vendor/btwxt"]
path = vendor/btwxt
url = https://github.com/bigladder/btwxt.git
2 changes: 2 additions & 0 deletions CMakeLists.txt
Expand Up @@ -27,7 +27,9 @@ if (HPWHSIM_ABRIDGED)
add_compile_definitions( HPWH_ABRIDGED)
endif()

add_subdirectory(vendor)
add_subdirectory(src)

if (NOT HPWHSIM_OMIT_TESTTOOL)
add_subdirectory(test)
endif()
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -13,6 +13,7 @@ HPWHsim is configured as a CMake project. Currently, CMake is only configured to
- Microsoft Visual Studio 2017 with Visual C++ (which can be installed after from the Microsoft Visual Studio Installer)
- CMake 3.5 or later
- Git
- Btwxt 0.2.0

### Building HPWHsim from source

Expand Down
27 changes: 27 additions & 0 deletions cmake/initialize-submodules.cmake
@@ -0,0 +1,27 @@
macro(initialize_submodules)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
set(git_modules_file "${PROJECT_SOURCE_DIR}/.gitmodules")
if (EXISTS ${git_modules_file})
file(STRINGS ${git_modules_file} file_lines)
foreach(line ${file_lines})
if (${line} MATCHES "url =")
string(REGEX REPLACE "\\s*url = .*/(.*).git" "\\1" submodule "${line}")
string(STRIP "${submodule}" submodule)
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${submodule}")
message(FATAL_ERROR "Submodule directory \"${CMAKE_CURRENT_SOURCE_DIR}/${submodule}\" does not exist")
endif()
# Initialize submodule if it hasn't already been cloned
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${submodule}/.git")
message(STATUS "Initialize ${submodule} submodule")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive "${CMAKE_CURRENT_SOURCE_DIR}/${submodule}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init --recursive ${CMAKE_CURRENT_SOURCE_DIR}/${submodule} failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
endif()
endforeach()
endif()
endif()
endmacro()
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Expand Up @@ -19,3 +19,5 @@ add_dependencies(libHPWHsim ${PROJECT_NAME}_version_header)
set_target_properties(libHPWHsim PROPERTIES OUTPUT_NAME HPWHsim)
set_target_properties(libHPWHsim PROPERTIES PDB_NAME libHPWHsim)
target_compile_features(libHPWHsim PUBLIC cxx_std_17)

target_include_directories(libHPWHsim PUBLIC ${PROJECT_SOURCE_DIR}/vendor/btwxt/src)
226 changes: 140 additions & 86 deletions src/HPWH.cc
Expand Up @@ -40,7 +40,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


#include "HPWH.hh"
#include "btwxt.h"
#include "HPWHpresets.cc"

#include <stdarg.h>
#include <fstream>
#include <iostream>
Expand Down Expand Up @@ -2617,7 +2619,7 @@ 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), expCurveFit(false)
isMultipass(true), mpFlowRate_LPS(0.), externalInletHeight(-1), externalOutletHeight(-1), useBtwxtGrid(false)
{}

HPWH::HeatSource::HeatSource(const HeatSource &hSource) {
Expand Down Expand Up @@ -2645,7 +2647,12 @@ HPWH::HeatSource::HeatSource(const HeatSource &hSource) {
shrinkage = hSource.shrinkage;

perfMap = hSource.perfMap;


perfGrid = hSource.perfGrid;
perfGridValues = hSource.perfGridValues;
perfRGI = hSource.perfRGI;
useBtwxtGrid = hSource.useBtwxtGrid;

defrostMap = hSource.defrostMap;
resDefrost = hSource.resDefrost;

Expand All @@ -2667,7 +2674,6 @@ HPWH::HeatSource::HeatSource(const HeatSource &hSource) {
typeOfHeatSource = hSource.typeOfHeatSource;
isMultipass = hSource.isMultipass;
mpFlowRate_LPS = hSource.mpFlowRate_LPS;
expCurveFit = hSource.expCurveFit;

externalInletHeight = hSource.externalInletHeight;
externalOutletHeight = hSource.externalOutletHeight;
Expand Down Expand Up @@ -2712,6 +2718,11 @@ HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource &hSource) {

perfMap = hSource.perfMap;

perfGrid = hSource.perfGrid;
perfGridValues = hSource.perfGridValues;
perfRGI = hSource.perfRGI;
useBtwxtGrid = hSource.useBtwxtGrid;

defrostMap = hSource.defrostMap;
resDefrost = hSource.resDefrost;

Expand All @@ -2733,7 +2744,6 @@ HPWH::HeatSource& HPWH::HeatSource::operator=(const HeatSource &hSource) {
typeOfHeatSource = hSource.typeOfHeatSource;
isMultipass = hSource.isMultipass;
mpFlowRate_LPS = hSource.mpFlowRate_LPS;
expCurveFit = hSource.expCurveFit;

externalInletHeight = hSource.externalInletHeight;
externalOutletHeight = hSource.externalOutletHeight;
Expand Down Expand Up @@ -3270,79 +3280,85 @@ void HPWH::HeatSource::getCapacity(double externalT_C, double condenserTemp_C, d
size_t i_next = 1;
double Tout_F = C_TO_F(setpointTemp_C);

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;
if (useBtwxtGrid) {
std::vector<double> 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 {
i_prev = i - 1;
i_next = i;
}
break;
}
else {
if (i == perfMap.size() - 1) {
extrapolate = true;
i_prev = i - 1;
i_next = i;
break;
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;
// 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;
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_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;
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 (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);
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);

// 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;
}
}
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(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);
regressedMethod(cop, perfMap[0].COP_coeffs, externalT_F, Tout_F, condenserTemp_F);
}
}

if (doDefrost) {
Expand Down Expand Up @@ -3391,23 +3407,26 @@ void HPWH::HeatSource::getCapacityMP(double externalT_C, double condenserTemp_C,
}
}

// 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;
}
}

if (expCurveFit) {
regressedExpMP(input_BTUperHr, perfMap[0].inputPower_coeffs, externalT_F, condenserTemp_F);
regressedExpMP(cop, perfMap[0].COP_coeffs, externalT_F, condenserTemp_F);

if (useBtwxtGrid) {
std::vector<double> 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);

Expand All @@ -3432,14 +3451,15 @@ 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*/) {
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.
Expand Down Expand Up @@ -3486,15 +3506,13 @@ void HPWH::HeatSource::regressedMethodMP(double &ynew, std::vector<double> &coef
coefficents[5] * x1 * x2;
}

void HPWH::HeatSource::regressedExpMP(double &ynew, std::vector<double> &coefficents, double x1, double x2) {
//Const Tair Tin Tair2 Tin2 TairTin
ynew = exp( coefficents[0] +
coefficents[1] * x1 +
coefficents[2] * x2 +
coefficents[3] * log(x1) +
coefficents[4] * log(x2) +
coefficents[5] * log(x1 + x2)
);

void HPWH::HeatSource::btwxtInterp(double& input_BTUperHr, double& cop, std::vector<double> &target) {

std::vector<double> result = perfRGI->get_values_at_target(target);

input_BTUperHr = result[0];
cop = result[1];
}

void HPWH::HeatSource::calcHeatDist(std::vector<double> &heatDistribution) {
Expand Down Expand Up @@ -4136,12 +4154,48 @@ int HPWH::checkInputs() {
}
}

// 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");

// 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;
}
returnVal = HPWH_ABORT;
}
}

Expand Down

0 comments on commit 094fd14

Please sign in to comment.