Skip to content

Commit 861a070

Browse files
committed
Additional modifications to CEnthalpyModel::RouteMassinReservoir to correct coefficient [A], constant [B], and Jacobian matrices. Also initialized value for _mixing_depth in CReservoir::BaseConstructor.
1 parent 0b3c2d2 commit 861a070

File tree

2 files changed

+66
-61
lines changed

2 files changed

+66
-61
lines changed

src/EnergyTransport.cpp

Lines changed: 65 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ double CEnthalpyModel::GetEnergyLossesFromLake(const int p, double &Q_sens, doub
304304
}
305305

306306
Q_sens =hstar* A_avg * (temp_air -0.5*(T_new+T_old));
307-
Q_cond =kdiff * A_avg * (0.5*(Ts_new+Ts_old)- 0.5*(T_new+T_old));
307+
Q_cond =ksed * A_avg * (0.5*(Ts_new+Ts_old)- 0.5*(T_new+T_old));
308308
Q_sw_in =(SW )*A_avg;
309309
Q_lw_in =(LW_in )*A_avg;
310310
Q_lw_out=(LW )*A_avg;
@@ -314,7 +314,7 @@ double CEnthalpyModel::GetEnergyLossesFromLake(const int p, double &Q_sens, doub
314314
return -(Q_sens + Q_cond + Q_sw_in + Q_lw_in + Q_lw_out + Q_lat + Q_rain) * tstep; //[MJ]
315315
}
316316
//////////////////////////////////////////////////////////////////
317-
/// \brief Calculates Res_mass (total reservoir energ) and ResSedMass (total sediment energy) in basin with reservoir at end of time step
317+
/// \brief Calculates Res_mass (total reservoir energy) and ResSedMass (total sediment energy) in basin with reservoir at end of time step
318318
///
319319
/// \param p [in] subbasin index
320320
/// \param aMout_new[] [in] Array of energy outflows at downstream end of each segment at end of current timestep [MJ/d] [size: nsegs]
@@ -324,7 +324,7 @@ double CEnthalpyModel::GetEnergyLossesFromLake(const int p, double &Q_sens, doub
324324
/// \param tt [in] Time structure
325325
//
326326
void CEnthalpyModel::RouteMassInReservoir (const int p, // SB index
327-
const double *aMout_new, // [MJ/d][size: nsegs ]
327+
const double *aMout_new, // [MJ/d][size: nsegs]
328328
double &Res_mass, // [MJ]
329329
double &ResSedMass, // [MJ]
330330
const optStruct &Options,
@@ -334,28 +334,30 @@ void CEnthalpyModel::RouteMassInReservoir (const int p, //
334334
CReservoir* pRes = _pModel->GetSubBasin(p)->GetReservoir();
335335
int nSegments = _pModel->GetSubBasin(p)->GetNumSegments();
336336

337-
double V_new=pRes->GetStorage ();
338-
double V_old=pRes->GetOldStorage ();
339-
double Q_new=pRes->GetOutflowRate ()*SEC_PER_DAY;
340-
double Q_old=pRes->GetOldOutflowRate()*SEC_PER_DAY;
341-
double A_new=pRes->GetSurfaceArea();
342-
double A_old=pRes->GetOldSurfaceArea();
343-
double A_avg=0.5*(A_new+A_old);
344-
double tstep=Options.timestep;
345-
337+
double V_new=pRes->GetStorage();
338+
double V_old=pRes->GetOldStorage();
339+
346340
if((V_old<=0.0) || (V_new<=0.0)) { Res_mass=ResSedMass=0.0; return;} //handles dried out reservoir/lake
347341

348-
double V_h_new = pRes->GetHypolimnionStorage ();
349-
double V_h_old = pRes->GetOldHypolimnionStorage ();
342+
double V_h_new = pRes->GetHypolimnionStorage();
343+
double V_h_old = pRes->GetOldHypolimnionStorage();
350344
double V_e_new = V_new-V_h_new;
351345
double V_e_old = V_old-V_h_old;
352-
double Q_dn_new = 0;
353-
double Q_dn_old = 0;
354-
double Q_up_new = 0;
355-
double Q_up_old = 0;
346+
double Q_new=pRes->GetOutflowRate()*SEC_PER_DAY;
347+
double Q_old=pRes->GetOldOutflowRate()*SEC_PER_DAY;
348+
double A_new=pRes->GetSurfaceArea();
349+
double A_old=pRes->GetOldSurfaceArea();
350+
double A_avg=0.5*(A_new+A_old);
356351
double A_h_new = pRes->GetMixingArea();
357352
double A_h_old = pRes->GetOldMixingArea();
358353
double A_h_avg = 0.5 * (A_h_new + A_h_old);
354+
355+
double Q_dn_new = 0.0;
356+
double Q_dn_old = 0.0;
357+
double Q_up_new = 0.0;
358+
double Q_up_old = 0.0;
359+
360+
double tstep=Options.timestep;
359361

360362
CHydroUnit* pHRU=_pModel->GetHydroUnit(pRes->GetHRUIndex());
361363

@@ -367,13 +369,10 @@ void CEnthalpyModel::RouteMassInReservoir (const int p, //
367369
double hstar(0);
368370
if(pHRU!=NULL) { //otherwise only simulate advective mixing+ rain input
369371
Acorr =pHRU->GetArea()*M2_PER_KM2/A_avg; //handles the fact that GetAET() returns mm/d normalized by HRU area, not actual area
370-
371372
temp_air =pHRU->GetForcingFunctions()->temp_ave; //[C]
372373
SW =pHRU->GetForcingFunctions()->SW_radia_net; //[MJ/m2/d]
373374
LW_in =pHRU->GetForcingFunctions()->LW_incoming; //[MJ/m2/d]
374-
375375
LW =-STEFAN_BOLTZ*EMISS_WATER*pow(T_old+ZERO_CELSIUS,4); //[MJ/m2/d] //TMP DEBUG -time-lagged - should include in the N-R formulation
376-
377376
AET =pRes->GetAET()*Acorr/ MM_PER_METER ; //[m/d]
378377
// Vsed =pRes->GetLakebedThickness() * pHRU->GetArea()*M2_PER_KM2;
379378
hstar =pRes->GetLakeConvectionCoeff(); //[MJ/m2/d/K]
@@ -382,7 +381,7 @@ void CEnthalpyModel::RouteMassInReservoir (const int p, //
382381

383382
double Ts_old=ConvertVolumetricEnthalpyToTemperature(_aMsed_last[p]/V_h_old);
384383

385-
384+
// water density in each layer as a function of water temperature (Chapra, 2008)
386385
double dens_e,dens_h,vdiff,kdiff;
387386

388387
double a0= 999.842594;
@@ -395,23 +394,24 @@ void CEnthalpyModel::RouteMassInReservoir (const int p, //
395394
dens_e = a0+a1*T_old + a2*pow(T_old,2) + a3*pow(T_old,3) +a4*pow(T_old,4)+a5*pow(T_old,5);
396395
dens_h = a0+a1*Ts_old + a2*pow(Ts_old,2) + a3*pow(Ts_old,3) +a4*pow(Ts_old,4)+a5*pow(Ts_old,5);
397396

398-
double N2;
399-
400-
if(dens_e<dens_h){
401-
N2 = -1*GRAVITY/dens_e*(dens_e-dens_h)/1.0;
397+
// Brunt-Väisälä frequency at thermocline depth (assume dz = 1.0m) (Jennings et al. 2012)
398+
double N2=1.0e-12; // value when dens_e >= dens_h
399+
if(dens_e<dens_h){
400+
N2 = -1*GRAVITY/dens_e*(dens_e-dens_h)/1.0;
402401
}
403-
double m = -0.65;
404-
double b = -3.1;
405402

403+
// Vertical convection coefficient as function of N2 (Quay et el. 1980; Figure 10)
404+
double m = -0.65;
405+
double b = -3.1;
406406
vdiff = pow(10,m*log10(N2)+b)/100/100;
407407
kdiff = vdiff*HCP_WATER*SEC_PER_DAY;
408408

409-
410-
// N-R solution of Crank-nicolson problem as set of two non-linear algebraic equations
409+
// N-R solution of Crank-nicolson problem as set of two non-linear algebraic equations [A][E]=[B]
411410
// -----------------------------------------------------------------------------------------
412-
//dE /dt=Qh_in-Qh_out+(Rnet*A+P*hrain*A)-ET*rho*LH*A+k*(Tair-T(E))*A+ksed*(Tsed-T(E))*A //[MJ/d]
413-
//dEsed/dt= -ksed*(Tsed-T(E))*A //[MJ/d]
411+
//dEe/dt = Qh_in - Qh_out - Qdn*Ee/Ve + Qup*Eh/Vh + As*(Rnet+Phrain-ET*rho*LH) + As*k*(Tair-Te) + Ah*kdiff*(Th-Te) // [MJ/d]
412+
//dEh/dt = Qdn*Ee/Ve – Qup*Eh/Vh + Ah*kdiff*(Te-Th) // [MJ/d]
414413
//
414+
415415
//Allocate memory
416416
double *B=new double [2];
417417
double *R=new double [2];
@@ -424,20 +424,24 @@ double b = -3.1;
424424
for (int j = 0; j < 2; j++) {A[i][j]=J[i][j]=0.0;}
425425
}
426426

427+
// constants matrix
427428
B[0] = 0.5*(aMout_new[nSegments-1]+_aMout[p][nSegments-1])*tstep; // inflow [MJ]
429+
B[0]+=(1.0-0.5*tstep/V_e_old*Q_old)*_aMres_last[p]; // outflow [MJ]
428430
B[0]+=_aMresRain[p]*tstep; // rainfall inputs [MJ]
429-
B[0]+= A_avg *(SW+LW_in)*tstep; // net incoming radiation [MJ]
430-
B[0]+= A_avg *(LW )*tstep; // net outgoing radiation [MJ]
431-
B[0]-= A_avg *(AET*DENSITY_WATER*LH_VAPOR)*tstep; // latent heat [MJ]
432-
B[0]+= A_avg *(hstar*temp_air)*tstep; // sensible heat exhange [MJ]
433-
434-
B[0]+=(1.0-0.5*tstep/V_old*Q_old)*_aMres_last[p];
435-
B[0]-=0.5*tstep*hstar*A_old*T_old;
436-
B[0]-=0.5*tstep*kdiff *A_avg*T_old;
437-
B[0]+=0.5*tstep*kdiff *A_avg*Ts_old;
438-
439-
B[1] =0.5*tstep*kdiff *A_avg*T_old;
440-
B[1]+=_aMsed_last[p]-0.5*tstep*kdiff *A_avg*Ts_old;
431+
B[0]+= A_avg*(SW+LW_in)*tstep; // net incoming radiation [MJ]
432+
B[0]+= A_avg*(LW )*tstep; // net outgoing radiation [MJ]
433+
B[0]-= A_avg*(AET*DENSITY_WATER*LH_VAPOR)*tstep; // latent heat [MJ]
434+
B[0]+= A_avg*hstar*(temp_air-0.5*T_old)*tstep; // sensible heat exhange [MJ]
435+
//B[0]-=0.5*tstep*hstar*A_avg*T_old; // sensible heat exchange [MJ]
436+
B[0]+=0.5*tstep*kdiff*A_h_avg*(Ts_old-T_old); // diffusive heat exchange [MJ]
437+
//B[0]-=0.5*tstep*kdiff*A_h_avg*T_old; // diffusive heat exchange [MJ]
438+
B[0]+=(1.0-0.5*tstep/V_e_old*Q_dn_old)*_aMres_last[p]; // downward advection [MJ]
439+
B[0]+=0.5*tstep/V_h_old*Q_up_old*_aMsed_last[p]; // upward advection [MJ]
440+
441+
B[1] =0.5*tstep*kdiff*A_h_avg*(T_old-Ts_old); // diffusive heat exchange [MJ]
442+
//B[1]-=0.5*tstep*kdiff*A_h_avg*Ts_old;
443+
B[1]+=0.5*tstep/V_e_old*Q_dn_old*_aMres_last[p]; // downward advection [MJ]
444+
B[1]+=(1-0.5*tstep/V_h_old*Q_up_old)*_aMsed_last[p]; // upward advection [MJ]
441445

442446
int iter=0;
443447
double change=ALMOST_INF;
@@ -452,35 +456,35 @@ double b = -3.1;
452456
T_guess = ConvertVolumetricEnthalpyToTemperature(E_guess/V_e_new);
453457
Ts_guess= ConvertVolumetricEnthalpyToTemperature(Es_guess/V_h_new);
454458

455-
A[0][0] = 1.0 + 0.5 * tstep * Q_new/V_new;
456-
A[1][1] = 1.0;
457-
A[1][0] = 0.0;
458-
A[0][1] = 0.0;
459+
A[0][0] = 1.0 + 0.5*tstep*(Q_new + Q_dn_new)/V_e_new;
460+
A[1][1] = 1.0 + 0.5*tstep*Q_up_new/V_h_new;
461+
A[1][0] = 0.5*tstep*Q_dn_new/V_e_new;
462+
A[0][1] = 0.5*tstep*Q_up_new/V_h_new;
459463
if (E_guess!=0.0){
460-
A[0][0]+= 0.5*tstep*hstar*A_new*T_guess/E_guess;
461-
A[0][0]+= 0.5*tstep*kdiff *A_avg*T_guess/E_guess; //[MJ/m2/d/K]*[m2]/[MJ/m3/K] = [m3/d]
462-
A[1][0]-= 0.5*tstep*kdiff *A_avg*T_guess/E_guess;
464+
A[0][0]+= 0.5*tstep*hstar*A_avg* T_guess/E_guess;
465+
A[0][0]+= 0.5*tstep*kdiff*A_h_avg*T_guess/E_guess; //[MJ/m2/d/K]*[m2]/[MJ/m3/K] = [m3/d]
466+
A[1][0]-= 0.5*tstep*kdiff*A_h_avg*T_guess/E_guess;
463467
}
464468
if (Es_guess!=0.0){
465-
A[0][1]-= 0.5*tstep*kdiff *A_avg*Ts_guess/Es_guess;
466-
A[1][1]+= 0.5*tstep*kdiff *A_avg*Ts_guess/Es_guess;
469+
A[0][1]-= 0.5*tstep*kdiff*A_h_avg*Ts_guess/Es_guess;
470+
A[1][1]+= 0.5*tstep*kdiff*A_h_avg*Ts_guess/Es_guess;
467471
}
468472

469473
//J_ij=A_ij+E*dA_ij/dE = Jacobian
470-
J[0][0]=A[0][0]+0.5*tstep*(hstar*A_new+kdiff*A_avg) * (TemperatureEnthalpyDerivative(E_guess /V_e_new)/ V_e_new);
471-
J[0][1]=A[0][1]-0.5*tstep*( kdiff*A_avg) * (TemperatureEnthalpyDerivative(Es_guess/V_h_new )/ V_h_new );
472-
J[1][0]=A[1][0]-0.5*tstep*( kdiff*A_avg) * (TemperatureEnthalpyDerivative(E_guess /V_e_new)/ V_e_new);
473-
J[1][1]=A[1][1]+0.5*tstep*( kdiff*A_avg) * (TemperatureEnthalpyDerivative(Es_guess/V_h_new )/ V_h_new );
474+
J[0][0]=A[0][0]+0.5*tstep*(hstar*A_avg+kdiff*A_h_avg) * (TemperatureEnthalpyDerivative(E_guess /V_e_new)/V_e_new);
475+
J[0][1]=A[0][1]+0.5*tstep*( kdiff*A_h_avg) * (TemperatureEnthalpyDerivative(Es_guess/V_h_new)/V_h_new);
476+
J[1][0]=A[1][0]-0.5*tstep*( kdiff*A_h_avg) * (TemperatureEnthalpyDerivative(E_guess /V_e_new)/V_e_new);
477+
J[1][1]=A[1][1]+0.5*tstep*( kdiff*A_h_avg) * (TemperatureEnthalpyDerivative(Es_guess/V_h_new)/V_h_new);
474478

475-
R[0] =-A[0][0]*E_guess-A[0][1]*Es_guess+B[0];
476-
R[1] =-A[1][0]*E_guess-A[1][1]*Es_guess+B[1];
479+
R[0] = -A[0][0]*E_guess-A[0][1]*Es_guess+B[0];
480+
R[1] = -A[1][0]*E_guess-A[1][1]*Es_guess+B[1];
477481

478482
//invert 2x2 matrix analytically
479483
double den= (J[0][1]*J[1][0]-J[0][0]*J[1][1]);
480484
dE = (J[0][1]*R[1]-J[1][1]*R[0])/den;
481485
dEs = (J[1][0]*R[0]-J[0][0]*R[1])/den;
482486

483-
change =sqrt(dE*dE+dEs*dEs)/ V_e_new / HCP_WATER; //convert to approx temp difference (for >0C water)
487+
change =sqrt(dE*dE+dEs*dEs)/V_new/HCP_WATER; //convert to approx temp difference (for >0C water)
484488

485489
E_guess +=dE;
486490
Es_guess +=dEs;
@@ -494,6 +498,7 @@ double b = -3.1;
494498
delete [] R;
495499
for (int i=0;i<2;i++){delete [] A[i]; delete[] J[i]; } delete[] A; delete[] J;
496500
}
501+
497502
//////////////////////////////////////////////////////////////////
498503
/// \brief returns total energy lost from subbasin reach over current time step [MJ]
499504
/// \param p [in] subbasin index

src/Reservoir.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ void CReservoir::BaseConstructor(const string Name,const long SubID)
1818
_SBID=SubID;
1919

2020
_pDownSB=NULL;
21-
// _mixing_depth=1;
21+
_mixing_depth=5.0;
2222
_lakebed_thick=1.0;
2323
_lakebed_cond =0.0;
2424
_lake_convcoeff=2.0;

0 commit comments

Comments
 (0)