Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 11 additions & 7 deletions doc/src/records/dhwsys.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ Optional name of system; give after the word “DHWSYS” if desired.

Name of a DHWSYS that serves the same loads as this DHWSYS, allowing representation of multiple water heating systems within a unit. If given, wsUse and wsDayUse are not allowed, hot water requirements are derived from the referenced DHWSYS. wsCentralDHWSYS and wsLoadShareDHWSYS cannot both be given.

Loads are shared by assigning DHWUSE events sequentially to all DHWSYSs in a group. This algorithm approximately divides the load by the number of DHWSYSs in the group.

For example, two DHWSYSs should be defined to model two water heating systems serving a load represented by wsDayUse DayUseTyp. Each DHWSYS should include DHWHEATER(s) and other components as needed. DHWSYS Sys1 should specify wsDayUse=DayUseTyp and DHWSYS Sys2 should have wsLoadShareDHWSYS=Sys1 in place of wsDayUse.

**Units** **Legal Range** **Default** **Required** **Variability**
----------- ------------------- ---------------------- -------------- -----------------
*name of a DHWSYS* No shared loads No constant
Expand Down Expand Up @@ -110,39 +114,39 @@ Specifies electrical parasitic power to represent recirculation pumps or other s

Specifies the standard distribution loss multiplier. See App B Eqn 4. To duplicate CEC 2016 methods, this value should be set according to the value derived with App B Eqn 5.

**Units** **Legal Range** **Default** **Required** **Variability**
**Units** **Legal Range** **Default** **Required** **Variability**
----------- ----------------- ------------- -------------- -----------------
$>$ 0 1 No constant
$>$ 0 1 No constant

**wsDSM=*float***

Distribution system multiplier. See RACM App B Eqn 4. To duplicate CEC 2016 methods, wsDSM should be set to the appropriate value from App B Table B-2. Note the NCF (non-compliance factor) included in App B Eqn 4 is *not* a CSE input and thus must be applied externally to wsDSM.

**Units** **Legal Range** **Default** **Required** **Variability**
**Units** **Legal Range** **Default** **Required** **Variability**
----------- ----------------- ------------- -------------- -----------------
$>$ 0 1 No constant
$>$ 0 1 No constant

**wsWF=*float***

Waste factor. See RACM App B Eqn 1. wsWF is applied to hot water draws. The default value (1) reflects the inclusion of waste in draw amounts. App B specifies wsWF=0.9 when the system has a within-unit pumped loop that reduces waste due to immediate availability of hot water at fixtures.

**Units** **Legal Range** **Default** **Required** **Variability**
**Units** **Legal Range** **Default** **Required** **Variability**
----------- ----------------- ------------- -------------- -----------------
$>$ 0 1 No hourly

**wsSSF=*float***

Specifies the solar savings fraction.

**Units** **Legal Range** **Default** **Required** **Variability**
**Units** **Legal Range** **Default** **Required** **Variability**
----------- ----------------- ------------- -------------- -----------------
$\ge$ 0 0 No hourly

**wsElecMtr=*mtrName***

Name of METER object, if any, to which DHWSYS electrical energy use is recorded (under end use DHW). In addition, wsElecMtr provides the default whElectMtr selection for all DHWHEATERs and DHWPUMPs in this DHWSYS.

**Units** **Legal Range** **Default** **Required** **Variability**
**Units** **Legal Range** **Default** **Required** **Variability**
----------- ------------------- ---------------- -------------- -----------------
*name of a METER* *not recorded* No constant

Expand Down
145 changes: 83 additions & 62 deletions src/DHWCalc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ struct DWHRUSE // info about 1 (shower) draw that could have DWHR
DWHRUSE() : wdw_iFx( -1), wdw_coldCnx( 0), wdw_vol( 0.f), wdw_volHR( 0.f), wdw_temp( 0.f)
{}
DWHRUSE( int iFx, int coldCnx, float vol, float volHR, float temp)
: wdw_coldCnx( coldCnx), wdw_vol( vol), wdw_volHR( volHR), wdw_temp( temp)
: wdw_iFx( iFx), wdw_coldCnx( coldCnx), wdw_vol( vol), wdw_volHR( volHR), wdw_temp( temp)
{}
~DWHRUSE() {}

Expand Down Expand Up @@ -1009,7 +1009,7 @@ void DHWSYS::ws_InitTicks( // initialize tick data for hour
ws_iTkNDWHR = -1;
} // DHWSYS::ws_InitTicks
//----------------------------------------------------------------------------
RC DHWSYS::ws_DoHourDWHR() // current hour DHWHEATREC modeling
RC DHWSYS::ws_DoHourDWHR() // current hour DHWHEATREC modeling (all DHWHEATRECs)
{
RC rc = RCOK;

Expand All @@ -1024,62 +1024,86 @@ RC DHWSYS::ws_DoHourDWHR() // current hour DHWHEATREC modeling
// ws_qDWHR = 0.f; // total heat recovered by all DHWHEATREC devices, Btu
// ws_whUseNoHR = 0.; // check value: hour total hot water use w/o HR, gal
// init'd by caller
double qRWHSum = 0.;
double qRWHSum = 0.; // hour total recovered heat to WH inlet, Btu
int multiDraw = 0;
// int nTk = Top.tp_NHrTicks();
for (int iTk=ws_iTk0DWHR; iTk < ws_iTkNDWHR; iTk++)
{ DHWTICK& tk = ws_ticks[ iTk]; // DHWSYS tick info
if (tk.wtk_nHRDraws == 0)
continue; // no DHWHEATREC draws in this tick
float vOther // non-DHWHEATREC draws that contribute to each
if (tk.wtk_nHRDraws > 1)
multiDraw++;
float whUseOther = tk.wtk_whUse;
float vHotOther // non-DHWHEATREC draws that contribute to each
// feedWH-DHWHEATREC potable-side vol
= tk.wtk_whUse / max(ws_wrFeedWHCount, 1);
= whUseOther / max(ws_wrFeedWHCount, 1);
#if defined( _DEBUG)
int nReDo = 0; // debugging aid, see below
reDo:
#endif
float whUse = 0.f; // hot water use, this tick / all DHWHEATREC draws
float fxUseMix = 0.f; // mixed water use
float qR = 0.f; // tick heat recovered
float qRWH = 0.f; // tick heat recovered to WH feed
float whUseNoHR = 0.f; // tick hot water use w/o HR
DHWHEATREC* pWR;
RLUPC(WrR, pWR, pWR->ownTi == ss)
{ DHWHRTICK& wrtk = pWR->wr_ticks[iTk]; // DHWHEATREC tick info
if (wrtk.wrtk_draws.size() > 0)
whUse += pWR->wr_CalcTick( this,
wrtk, // tick info for *pWR
vOther, // total non-HR hot water use, gal
ws_whUseNoHR, fxUseMix, qR, qRWH); // results accum'd
vHotOther, // total non-HR hot water use, gal
whUseNoHR, fxUseMix, qR, qRWH); // results accum'd
}
ws_AccumUseTick( // accum to ws_tick, ws_whUse, and ws_fxMixUse
C_DHWEUCH_SHOWER, iTk, fxUseMix, whUse);
#if defined( _DEBUG)
if (!nReDo)
#endif
ws_AccumUseTick( // accum to ws_tick, ws_whUse, and ws_fxMixUse
C_DHWEUCH_SHOWER, iTk, fxUseMix, whUse);

// water heater inlet temp
float tO = ws_tInlet;
if (tk.wtk_whUse > 0.)
tO += qRWH / (waterRhoCp * tk.wtk_whUse);
#if defined( _DEBUG)
else if (qRWH > 0.f)
printf("\nInconsistency: wtk_whUse=%0.3f qRWHWt=%0.3f",
tk.wtk_whUse, qRWH);
#endif
tk.wtk_tInletX = ws_AdjustTInletForSSF(tO);
qRWHSum += qRWH;
ws_qDWHR += qR; // accum to hour total heat recovered
} // end tick

#if 0 && defined( _DEBUG)
if (frDiff( float( whUseTot), ws_whUse.total, .001f) > .001f)
printf( "\nMismatch!");
#if defined( _DEBUG)
// tick energy balance
float qXNoHR = (whUseNoHR+whUseOther) * waterRhoCp * (ws_tUse - ws_tInlet);
float qX = tk.wtk_whUse * waterRhoCp * (ws_tUse - tO);
float qXHR = qX + qR;
if (frDiff(qXHR, qXNoHR, 1.f) > .001f)
{
printf("\nDHWSYS '%s': ws_DoHourDWHR tick balance error (md=%d)", name, multiDraw);
if (nReDo++ < 2)
goto reDo; // repeat calc (debugging aid)
}
#endif
ws_qDWHR += qR; // hour total heat recovered
qRWHSum += qRWH; // hour total heat to WH inlet
ws_whUseNoHR += whUseNoHR; // hour total WH use w/o HR

} // end tick

// calc hour average adjusted inlet and hot water temps
float tInletXNoSSF = ws_tInlet;
// hour average adjusted inlet and hot water temps
float tInletXNoSSF;
if (qRWHSum > 0.)
{ tInletXNoSSF = ws_tInlet + qRWHSum / (waterRhoCp * ws_whUse.total);
ws_tInletX = ws_AdjustTInletForSSF( tInletXNoSSF);
{
tInletXNoSSF = ws_tInlet + qRWHSum / (waterRhoCp * ws_whUse.total);
ws_tInletX = ws_AdjustTInletForSSF(tInletXNoSSF);
}
else
tInletXNoSSF = ws_tInlet;

#if defined( _DEBUG)
float qXNoHR = ws_whUseNoHR * waterRhoCp * (ws_tUse - ws_tInlet);
// hour energy balance
float qXNoHR = ws_whUseNoHR * waterRhoCp * (ws_tUse - ws_tInlet);
float qX = ws_whUse.total * waterRhoCp * (ws_tUse - tInletXNoSSF);
if (frDiff(qX+ws_qDWHR, qXNoHR, 1.f) > .001f)
printf( "\nDHWSYS '%s': ws_DoHourDWHR balance error", name);
float qXHR = qX + ws_qDWHR;
if (frDiff(qXHR, qXNoHR, 1.f) > .001f)
printf("\nDHWSYS '%s': ws_DoHourDWHR balance error (md=%d)", name, multiDraw);
#endif

return rc;
} // DHWSYS::ws_DoHourDWHR
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -2702,7 +2726,7 @@ RC DHWHEATREC::wr_SetFXConnections(
float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
DHWSYS* pWS, // parent DHWSYS
DHWHRTICK& wrtk, // current tick info for this DHWHEATREC
float vOther, // hot water draws for other fixtures, gal
float vHotOther, // hot water draws for other fixtures, gal
// included in potable flow if feedsWH
float& whUseNoHR, // returned updated: hot water use w/o heat recovery, gal
// used re energy balance check
Expand All @@ -2711,40 +2735,26 @@ float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
float& qRWH) // returned updated: tick recovered heat added to WH inlet water, Btu

// returns hot water use for served fixtures, gal
// (not including vOther)
// (not including vHotOther)
{
int nD = wrtk.wrtk_draws.size();
if (nD == 0)
return 0.f; // no draws, no effect

#if 0 && defined( _DEBUG)
// if (Top.jDay == 91 && Top.iHr == 20)
// printf(" Hit\n");
static int nDMulti = 0;
if (nD > 1)
{
if (nDMulti++ == 0)
printf("\nMultiple draws: jDay=%d iH=%d",
Top.jDay, Top.iHr);
}
else
nDMulti = 0;
#endif

// tick constants
float tpI = pWS->ws_tInlet; // mains temp
float tHotFX = pWS->ws_tUse; // hot water temp at fixture

float vd = 0.f; // total mixed use at all fixture(s), all draws, gal
// = drain volume
float tdI = 0.f; // average drain-side entering temp, F
float vMixHR = 0.f; // total mixed use at fixtures with cold side
float vMixFXHR = 0.f; // total mixed use at fixtures with cold side
// connection to DHWHEATREC, gal
float vHotFX0= 0.f; // hot water req'd for fixtures that use
// mains water for mixing, gal

// re parallel potable-side DHWHEATRECs
// caller allocates vOther equally to all feedsWH-DHWHEATREC(s) in DHWSYS
// caller allocates vHotOther equally to all feedsWH-DHWHEATREC(s) in DHWSYS
// >> DHWHEATER inlet flow for other draws assumed to flow equally via parallel paths
// this-DHWHEATREC fixture flows are assigned to this-DHWHEATREC potable flow
// >> this-DHWHEATER's fixtures DHWHEATER and tempering flows do NOT
Expand Down Expand Up @@ -2774,7 +2784,7 @@ float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
else
// fixture cold comes from DHWHEATREC
// accum mixed vol, compute vHotFX below
vMixHR += hru.wdw_vol;
vMixFXHR += hru.wdw_vol;
}
fxUseMix += vd; // accum to caller's total

Expand All @@ -2783,16 +2793,16 @@ float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
tdI = bracket(tpI, tdI/max( vd, .0001f), tHotFX);


float vp; // potable-side flow, gal
float tpO = 0.f;// potable-side outlet temp, F
float vHotFX; // fixture hot vol, gal
float vp = 0.f; // potable-side flow, gal
float tpO = 0.f; // potable-side outlet temp, F
float vHotFX = 0.f; // fixture hot vol, gal

if (wr_FeedsFX())
if (vMixFXHR > 0.f) // if any current draw feeds a fixture
{
// DHWHEATREC feeds fixture(s) and possibly WH
vp = wr_FeedsWH() // potable volume
? vMixHR + vHotFX0 + vOther // feeds both
: vMixHR / 2.f; // fixture only: 1st guess
? vMixFXHR + vHotFX0 + vHotOther // feeds both
: vMixFXHR / 2.f; // fixture only: 1st guess
int iL;
for (iL = 0; iL<10; iL++)
{ // cold water temp at wdw_coldCnx fixture(s)
Expand All @@ -2808,7 +2818,7 @@ float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
vHotFX += hru.wdw_vol * DHWMixF(hru.wdw_temp, tHotFX, tpO);
}
if (!wr_FeedsWH())
vp = vMixHR - vHotFX; // cold side flow
vp = vMixFXHR - vHotFX;

#if 0 && defined( _DEBUG)
if (iL > 7)
Expand All @@ -2818,20 +2828,31 @@ float DHWHEATREC::wr_CalcTick( // calculate performance for 1 tick
break;
wr_EffAdjusted(vp, tpI, vd, tdI); // update efficiency
}
vHotFX += vHotFX0; // total fixture hot water
}
else
{ // DWHR feeds WH only -- flows known
vHotFX = vHotFX0;
vp = vHotFX + vOther;
wr_EffAdjusted(vp, tpI, vd, tdI); // derive wr_eff
tpO = wr_HX(vp, tpI, vd, tdI);
{ // no current fixture draw uses tempered cold-side water
// all flows known
vHotFX = vHotFX0; // hot water needed
if (wr_FeedsWH())
{ // potable side feeds water heater
// recovered heat boosts tInlet
vp = vHotFX + vHotOther;
wr_EffAdjusted(vp, tpI, vd, tdI); // derive wr_eff
tpO = wr_HX(vp, tpI, vd, tdI);
}
else
{ // does not feed WH
// no heat recovered
vp = 0.f; // no potable-side flow
tpO = tpI; // outlet temp = inlet temp (insurance)
}
}

float qR1 = vp * waterRhoCp * (tpO - tpI); // recovered heat
qR += qR1;
qRWH += wr_FeedsWH() && vp > 0.f // recovered heat to WH
? qR1 * (vHotFX + vOther) / vp
: 0.f;
if (wr_FeedsWH() && vp > 0.f)
qRWH += qR1 * (vHotFX + vHotOther) / vp; // recovered heat to WH
return vHotFX;

} // DHWHEATREC::wr_CalcTick
Expand Down
4 changes: 2 additions & 2 deletions src/WFPAK.CPP
Original file line number Diff line number Diff line change
Expand Up @@ -2511,9 +2511,9 @@ x printf( "mismatch\n");
{
const char* fName = "tSky.csv";
pF = fopen(fName, "wt");
fprintf(pF, "mon,day,hr,tSky_CSE,tSky_IR\n");
fprintf(pF, "yr,mon,day,hr,osc,tsc,tSky_CSE,tSky_IR\n");
}
fprintf(pF, "%d,%d,%d,%0.1f,%0.1f\n", m, d, h, wd_tSky, tSkyIR);
fprintf(pF, "%d,%d,%d,%d,%0.1f,%0.1f,%0.1f,%0.1f\n", yr, m, d, h, osc, tsc, wd_tSky, tSkyIR);
#endif
}
return rc;
Expand Down
26 changes: 13 additions & 13 deletions test/DWHR.cse
Original file line number Diff line number Diff line change
Expand Up @@ -4538,7 +4538,6 @@ DHWHEATREC DWHR wrFeedsWH=fWH wrCountFXDrain = fxDr wrCountFXCold = fxHR wrCSAR
//////////////////////////////////////////////////////////////////////
// Test cases
//////////////////////////////////////////////////////////////////////

// No heat recovery variants -- all should get same results
// - no DHWHEATREC
// - DHWHEATREC with EF=0
Expand All @@ -4547,14 +4546,21 @@ DO0( "DS0", "Elec0", FX0, WH0, 1)
DO1( "DS0a", "Elec0a", FX0a, WH0a, 1, 1, 0, Yes, 0)
DO1( "DS0b", "Elec0b", FX0b, WH0b, 0, 0, 0, No, 0)

// fixed heat recovery -- these 2 should get same results
// fixed heat recovery -- should get same results
DO0DU( "DSX0", "ElecX0", FXX0, WHX0, "4D7FixedHR", 1)
DO1DU( "DSX0a", "ElecX0a", FXX0a, WHX0a, "4D7", 1, SetEF, 1, 1, No, .5)

DO1( "DSEQ", ElecEQ, FXEQ, WHEQ, 1, 1, 1, Yes, .5)
DO1( "DSUSH", ElecUSH, FXUSH, WHUSH, 1, 1, 1, No, .5)
DO1( "DSUWH", ElecUWH, FXUWH, WHUWH, 1, 1, 0, Yes, .5)

// 2 showers, 1 DHWHEATREC
DO1( "DS2S0Y", Elec2S0Y, FX2S0Y, WH2S0Y, 2, 2, 0, Yes, .6)
DO1( "DS2S1N", Elec2S1N, FX2S1N, WH2S1N, 2, 2, 1, No, .6)
DO1( "DS2S1Y", Elec2S1Y, FX2S1Y, WH2S1Y, 2, 2, 1, Yes, .6)
DO1( "DS2S2N", Elec2S2N, FX2S2N, WH2S2N, 2, 2, 2, No, .6)
DO1( "DS2S2Y", Elec2S2Y, FX2S2Y, WH2S2Y, 2, 2, 2, Yes, .6)

// todo -- drain TD
//////////////////////////////////////////////////////////////////////

Expand All @@ -4581,25 +4587,19 @@ endDHWSYS
DO0Base0( "DSK1a", "ElecK1a", FXK1a, WHK1a) wsCentralDHWSYS=DSC1 DSLOAD
DO0Base0( "DSK1b", "ElecK1b", FXK1b, WHK1b) wsCentralDHWSYS=DSC1 DSLOAD


//=====================================================================
// multi-heater system
// DSMH0: 1 heater / 2 DHWHEATREC / 2 showers
// DSMH: 2 subsystems w/ 1 shower, 1 heater, 1 shower
// multi-heater systems
// should get same results

#if 0
// DSMH0: 1 heater / 2 DHWHEATREC / 2 showers
DO2( "DSMH0", ElecMH0, FXMH0, WHMH0, 2, 1, 1, Yes, .6)

DO0Base0( "DSMH", ElecMH, FXMH, WHMH) wsDayUse = DHW5BRa endDHWSYS

DO0Base( "DSMHKa", ElecMKa, FXMKa, WHMKa, 1) wsLoadShareDHWSYS="DSMH"
// DSMH: 2 systems each w/ 1 shower, 1 heater, 1 DHWHEATREC
DO0Base( "DSMH", ElecMH, FXMH, WHMH,1) wsDayUse = DHW5BRa
DHWHEATREC DWHRa wrFeedsWH=Yes wrCountFXDrain = 1 wrCountFXCold = 1 wrCSARatedEF = .6 wrTDInDiff=0

DO0Base( "DSMHKb", ElecMKb, FXMKb, WHMKb, 1) wsLoadShareDHWSYS="DSMH"
DO0Base( "DSMHKa", ElecMKa, FXMKa, WHMKa, 1) wsLoadShareDHWSYS="DSMH"
DHWHEATREC DWHRa wrFeedsWH=Yes wrCountFXDrain = 1 wrCountFXCold = 1 wrCSARatedEF = .6 wrTDInDiff=0
#endif


//////////////////////////////////////////////////////////////////////

Expand Down
Loading