Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heat exchange models #183

Merged
merged 34 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
99efbed
Restart heat exchange model.
Nov 1, 2023
8618861
Add heat exchange params.
Nov 1, 2023
508b544
AquaThermAire fails file and regression tests.
Nov 1, 2023
6e78b76
Fails villara test.
Nov 1, 2023
4681954
Adjust villara time.
Nov 1, 2023
7a6b418
Aquatherm added.
Nov 2, 2023
ad7efa0
Merge branch 'master' into heat-exchange-models
spahrenk Nov 6, 2023
539ef53
Merge branch 'master' into heat-exchange-models
Nov 9, 2023
638a51e
Merge branch 'master' into heat-exchange-models
Nov 13, 2023
ccdc7d2
accept master
Nov 13, 2023
098874d
Remove specific AquaTerm refs.
Nov 13, 2023
9bb19c7
No AquaTherm refs.
Nov 13, 2023
2fa7021
AquaTherm back in.
Nov 13, 2023
3611502
Review changes; unlock condenser.
Nov 20, 2023
92d5edf
Merge branch 'master' into heat-exchange-models
Nov 20, 2023
19ae202
Merge branch 'master' into heat-exchange-models
Nov 29, 2023
63b453a
Use 800 C storage tank to pass solar test.
Dec 6, 2023
e7bb180
Merge master.
Dec 11, 2023
592b89e
Fix heating logic issues.
Dec 11, 2023
e2d006f
Set AquaTherm to 12 tank nodes.
Dec 11, 2023
b8e569c
Use whole-tank logic.
Dec 11, 2023
9348872
Merge branch 'master' into heat-exchange-models
Dec 11, 2023
5043494
Improve unit conversion.
Dec 12, 2023
0dcc923
Conform case.
Dec 12, 2023
7553fdd
Merge branch 'master' into heat-exchange-models
Dec 12, 2023
4f64c7a
Merge branch 'master' into heat-exchange-models
Dec 13, 2023
533ec62
Change heat-exch-eff coeff.
Dec 14, 2023
4de5ef1
Define node-heat-exch-effec.
Dec 14, 2023
c5e0c99
Check validity.
Dec 14, 2023
e3f4a7c
Add 2nd third function.
Dec 14, 2023
2e25a71
Review comments; remove outletT space.
Dec 15, 2023
4a3e3f9
Remove unused fnc.
Dec 18, 2023
31cec6c
Change coil config.
Dec 18, 2023
ad4f931
Merge branch 'heat-exchange-models' of https://github.com/bigladder/H…
Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 81 additions & 48 deletions src/HPWH.cc
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ void HPWH::setAllDefaults() {
usesSoCLogic = false;
setMinutesPerStep(1.0);
hpwhVerbosity = VRB_minuteOut;
hasHeatExchanger = false;
heatExchangerEffectiveness = 0.9;
}

HPWH::HPWH(const HPWH &hpwh) {
Expand Down Expand Up @@ -2447,77 +2449,93 @@ void HPWH::updateTankTemps(double drawVolume_L,double inletT_C,double tankAmbien
lowInletT = inletT_C;
lowInletV = drawVolume_L - inletVol2_L;
}
//calculate how many nodes to draw (drawVolume_N)
double drawVolume_N = drawVolume_L / nodeVolume_L;
if(drawVolume_L > tankVolume_L) {
//if (hpwhVerbosity >= VRB_reluctant) {
// //msg("WARNING: Drawing more than the tank volume in one step is undefined 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 < getNumNodes(); 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 / getNumNodes() * tankVolume_L + tankTemps_C[0] * (drawVolume_L - tankVolume_L))
/ drawVolume_L * drawVolume_N;

drawVolume_N = 0.;
if (hasHeatExchanger) {// heat-exchange models

const double densityTank_kgperL = DENSITYWATER_kgperL;
const double CpTank_kJperkgC = CPWATER_kJperkgC;

double C_Node_kJperC = CpTank_kJperkgC * densityTank_kgperL * nodeVolume_L;
double C_draw_kJperC = CPWATER_kJperkgC * DENSITYWATER_kgperL * drawVolume_L;

outletTemp_C = inletT_C;
for (auto &nodeTemp: tankTemps_C) {
double maxHeatExchange_kJ = (nodeTemp - outletTemp_C) / (1. / C_Node_kJperC + 1. / C_draw_kJperC);
double heatExchange_kJ = heatExchangerEffectiveness * maxHeatExchange_kJ;

nodeTemp -= heatExchange_kJ / C_Node_kJperC;
outletTemp_C += heatExchange_kJ / C_draw_kJperC;
}
}
else {
//calculate how many nodes to draw (drawVolume_N)
double drawVolume_N = drawVolume_L / nodeVolume_L;
if(drawVolume_L > tankVolume_L) {
//if (hpwhVerbosity >= VRB_reluctant) {
// //msg("WARNING: Drawing more than the tank volume in one step is undefined 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 < getNumNodes(); 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 / getNumNodes() * tankVolume_L + tankTemps_C[0] * (drawVolume_L - tankVolume_L))
/ drawVolume_L * drawVolume_N;

/////////////////////////////////////////////////////////////////////////////////////////////////
drawVolume_N = 0.;
}

while(drawVolume_N > 0) {

while(drawVolume_N > 0) {
// Draw one node at a time
double drawFraction = drawVolume_N > 1. ? 1. : drawVolume_N;
double nodeInletTV = 0.;

// Draw one node at a time
double drawFraction = drawVolume_N > 1. ? 1. : drawVolume_N;
double nodeInletTV = 0.;
//add temperature for outletT average
outletTemp_C += drawFraction * tankTemps_C[getNumNodes() - 1];

//add temperature for outletT average
outletTemp_C += drawFraction * tankTemps_C[getNumNodes() - 1];
double cumInletFraction = 0.;
for(int i = getNumNodes() - 1; i >= lowInletH; i--) {

double cumInletFraction = 0.;
for(int i = getNumNodes() - 1; i >= lowInletH; i--) {

// Reset inlet inputs at this node.
double 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;
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;
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];
// 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;

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

//fill in average outlet T - it is a weighted averaged, with weights == nodes drawn
this->outletTemp_C /= (drawVolume_L / nodeVolume_L);
mixTankInversions();
}

/////////////////////////////////////////////////////////////////////////////////////////////////
//fill in average outlet T - it is a weighted averaged, with weights == nodes drawn
outletTemp_C /= (drawVolume_L / nodeVolume_L);
}

//Account for mixing at the bottom of the tank
if(tankMixesOnDraw && drawVolume_L > 0.) {
Expand All @@ -2527,7 +2545,7 @@ void HPWH::updateTankTemps(double drawVolume_L,double inletT_C,double tankAmbien

} //end if(draw_volume_L > 0)


/////////////////////////////////////////////////////////////////////////////////////////////////
if(doConduction) {

// Get the "constant" tau for the stability condition and the conduction calculation
Expand Down Expand Up @@ -2896,7 +2914,6 @@ void HPWH::mapResRelativePosToHeatSources() {
});
}


// 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;
Expand Down Expand Up @@ -2949,7 +2966,8 @@ int HPWH::checkInputs() {

//check is condensity sums to 1
condensitySum = 0;
for(int j = 0; j < heatSources[i].getCondensitySize(); ++j) condensitySum += heatSources[i].condensity[j];

for(int j = 0; j < heatSources[i].getCondensitySize(); j++) condensitySum += heatSources[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);
Expand Down Expand Up @@ -3215,6 +3233,21 @@ int HPWH::HPWHinit_file(string configFile) {
}
return HPWH_ABORT;
}
} else if(token == "hasHeatExchanger") {
// false of this model uses heat exchange
line_ss >> tempString;
if(tempString == "true") hasHeatExchanger = true;
else if(tempString == "false") hasHeatExchanger = false;
else {
if(hpwhVerbosity >= VRB_reluctant) {
msg("Improper value for %s\n",token.c_str());
}
return HPWH_ABORT;
}
} else if(token == "heatExchangerEffectiveness") {
// applies to heat-exchange models only
line_ss >> tempDouble;
heatExchangerEffectiveness = tempDouble;
} else if(token == "verbosity") {
line_ss >> token;
if(token == "silent") {
Expand Down
12 changes: 10 additions & 2 deletions src/HPWH.hh
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,9 @@ public:
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_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
Expand Down Expand Up @@ -913,7 +915,7 @@ private:
/**< the mass of water (kg) in a single node */
double nodeMass_kg;

/**< the heat capacity of the water (kJ/�C) in a single node */
/**< the heat capacity of the water (kJ/�C) in a single node */
double nodeCp_kJperC;

/**< the height in meters of the one node */
Expand Down Expand Up @@ -1000,6 +1002,12 @@ private:
/// Generates a vector of logical nodes
std::vector<HPWH::NodeWeight> 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;

}; //end of HPWH class

class HPWH::HeatSource {
Expand Down
66 changes: 64 additions & 2 deletions src/HPWHpresets.cc
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ int HPWH::HPWHinit_presets(MODELS presetNum) {

else if (presetNum == MODELS_StorageTank) {
setNumNodes(12);
setpoint_C = F_TO_C(127.0);
setpoint_C = 800.;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be changing on this branch, and will likely cause conflicts when master is merged in.


tankSizeFixed = false;
tankVolume_L = GAL_TO_L(80);
Expand Down Expand Up @@ -3819,8 +3819,70 @@ int HPWH::HPWHinit_presets(MODELS presetNum) {
heatSources[1].followedByHeatSource = &heatSources[2];

heatSources[0].companionHeatSource = &heatSources[2];
}
}
else if (presetNum == MODELS_AQUATHERMAIRE) { // AquaThermAire
setNumNodes(1);
setpoint_C = F_TO_C(125.);

tankVolume_L = GAL_TO_L(54.4);
tankUA_kJperHrC = 10.35;

doTempDepression = false;
tankMixesOnDraw = true;

// heat exchangers only
hasHeatExchanger = true;
heatExchangerEffectiveness = 0.9;

HeatSource compressor(this);

//compressor values
compressor.isOn = false;
compressor.isVIP = false;
compressor.typeOfHeatSource = TYPE_compressor;

compressor.setCondensity({1.});

//AOSmithPHPT60 values
compressor.perfMap.reserve(4);

compressor.perfMap.push_back({
5, // Temperature (T_F)
{-1423, 38.70 ,0.}, // Input Power Coefficients (inputPower_coeffs)
{-0.13839, 0.012319, 0.} // COP Coefficients (COP_coeffs)
});

compressor.perfMap.push_back({
34, // Temperature (T_F)
{-1558, 42.40, 0.}, // Input Power Coefficients (inputPower_coeffs)
{-0.19375, 0.017247, 0.} // COP Coefficients (COP_coeffs)
});

compressor.perfMap.push_back({
67, // Temperature (T_F)
{-1713, 46.60, 0.}, // Input Power Coefficients (inputPower_coeffs)
{-0.28156, 0.025064, 0.} // COP Coefficients (COP_coeffs)
});

compressor.perfMap.push_back({
95, // Temperature (T_F)
{-1844, 50.17, 0.}, // Input Power Coefficients (inputPower_coeffs)
{-0.47273, 0.042082, 0.} // COP Coefficients (COP_coeffs)
});

compressor.minT = F_TO_C(-25);
compressor.maxT = F_TO_C(125.);
compressor.hysteresis_dC = dF_TO_dC(1);
compressor.configuration = HeatSource::CONFIG_WRAPPED;

//logic conditions
compressor.addTurnOnLogic(HPWH::bottomTwelfth(dF_TO_dC(111)));
compressor.addTurnOnLogic(HPWH::standby(dF_TO_dC(14)));

//set everything in its places
heatSources.resize(1);
heatSources[0] = compressor;
}
else {
if (hpwhVerbosity >= VRB_reluctant) {
msg("You have tried to select a preset model which does not exist. \n");
Expand Down
71 changes: 71 additions & 0 deletions test/AquaThermAire.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
verbosity silent
numNodes 1 #number of nodes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to 12?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

setpoint 125 F
volume 54.4 gal
UA 10.35 kJperHrC
depressTemp false
mixOnDraw true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be false, the draw doesn't go into the tank at all, and it shouldn't cause any mixing of the water.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

hasHeatExchanger true
heatExchangerEffectiveness 0.9

#a test comment
numHeatSources 1

heatsource 0 isVIP false
heatsource 0 isOn false
heatsource 0 type compressor
heatsource 0 condensity 1

#we have input power and COP equations at for ambient temperatures
heatsource 0 nTemps 4
heatsource 0 T1 5 F
heatsource 0 T2 34 F
heatsource 0 T3 67 F
heatsource 0 T4 95 F

#quadratic terms for this product are zero. It's remarkably linear.

# 5F Coefficients
heatsource 0 inPowT1const -1423
heatsource 0 inPowT1lin 38.70
heatsource 0 inPowT1quad 0.0
heatsource 0 copT1const -0.13839
heatsource 0 copT1lin 0.012319
heatsource 0 copT1quad 0.0

# 34F Coefficients
heatsource 0 inPowT2const -1558
heatsource 0 inPowT2lin 42.40
heatsource 0 inPowT2quad 0.0
heatsource 0 copT2const -0.19375
heatsource 0 copT2lin 0.017247
heatsource 0 copT2quad 0.0

# 67F Coefficients
heatsource 0 inPowT3const -1713
heatsource 0 inPowT3lin 46.60
heatsource 0 inPowT3quad 0.0
heatsource 0 copT3const -0.28156
heatsource 0 copT3lin 0.025064
heatsource 0 copT3quad 0.0

# 95F Coefficients
heatsource 0 inPowT4const -1844
heatsource 0 inPowT4lin 50.17
heatsource 0 inPowT4quad 0.0
heatsource 0 copT4const -0.47273
heatsource 0 copT4lin 0.042082
heatsource 0 copT4quad 0.0


heatsource 0 minT -25 F
heatsource 0 maxT 125 F
heatsource 0 hysteresis 1 F
heatsource 0 coilConfig wrapped
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be "submerged" based on conversations with Ben. What impact will this have on the simulation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapped and submerged use different heat distributions. Simulation results are slightly altered.


#Turns on when average tank temperature is 111F or colder
heatsource 0 onlogic nodes 1 absolute < 111 F

#BL not sure how to specify standby turn on. Trying this for now
#Intent is to get it to turn on at 111F which is 14F below 125F
heatsource 0 onlogic standby 14 F
Loading