Skip to content

Commit eaf0a28

Browse files
James CraigJames Craig
authored andcommitted
v511 [BENCHMARKED] - management optimization upgrades
-additional infeasible solution diagnostics (DemandOptimization.cpp) -new strategy for handling negative inflows (DemandOptimization.cpp) fix to handle underflow properly in Management optimization mode (Reservoir.h/.cpp) minor fix to CmvLatFlush with _divert *(LatFlush.cpp) remove unused GetAverageSnowFrac() routine (Model.h/ModelForcingGrids.cpp)
1 parent a34e53b commit eaf0a28

File tree

7 files changed

+78
-52
lines changed

7 files changed

+78
-52
lines changed

src/DemandOptimization.cpp

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,7 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
13951395
int *lpgoalrow=new int [_nGoals]; //index of goal equation for all user-specified goals
13961396

13971397
double **aQiterHist=NULL,**ahiterHist=NULL;
1398+
bool *aInfeasHist= new bool [_maxIterations];
13981399

13991400
aQiterHist=new double *[_pModel->GetNumSubBasins()];
14001401
ahiterHist=new double *[_pModel->GetNumSubBasins()];
@@ -1409,7 +1410,9 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
14091410
ahiterHist[p][i]=0.0;
14101411
}
14111412
}
1412-
1413+
for (int i = 0; i < _maxIterations; i++) {
1414+
aInfeasHist[i]=false;
1415+
}
14131416
// instantiate linear programming solver
14141417
// ----------------------------------------------------------------
14151418
lp_lib::lprec *pLinProg;
@@ -1448,8 +1451,9 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
14481451
}
14491452

14501453
// Set lower bounds of flows (Q) to something a bit less than zero for cushion
1454+
// can't do this- messes up weir formulation
14511455
// ----------------------------------------------------------------
1452-
int nESB = 0;
1456+
/*int nESB = 0;
14531457
for (int pp = 0; pp<pModel->GetNumSubBasins(); pp++)
14541458
{
14551459
p =pModel->GetOrderedSubBasinIndex(pp);
@@ -1469,14 +1473,15 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
14691473
pSB=pModel->GetSubBasin(p);
14701474
if (pSB->IsEnabled() && (pSB->GetReservoir()!=NULL))
14711475
{
1472-
retval=lp_lib::set_lowbo(pLinProg,GetDVColumnInd(DV_QOUTRES,res_count), -0.001);
1473-
ExitGracefullyIf(retval!=1,"SolveManagementProblem::Error adding stage lower bound",RUNTIME_ERR);
1474-
res_count++;
1476+
retval=lp_lib::set_lowbo(pLinProg,GetDVColumnInd(DV_QOUTRES,res_count), -0.001);
1477+
ExitGracefullyIf(retval!=1,"SolveManagementProblem::Error adding stage lower bound",RUNTIME_ERR);
1478+
res_count++;
14751479
}
1476-
}
1480+
}*/
1481+
14771482
// Set lower bounds of stages to min stage -2m
14781483
// ----------------------------------------------------------------
1479-
res_count=0;
1484+
int res_count=0;
14801485
for (int pp = 0; pp<pModel->GetNumSubBasins(); pp++)
14811486
{
14821487
p =pModel->GetOrderedSubBasinIndex(pp);
@@ -1798,9 +1803,9 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
17981803
RHS+=U_n*pSB->GetSpecifiedInflow(t-n*Options.timestep);
17991804
}
18001805
for (int n = 1; n < pSB->GetLatHistorySize(); n++) {
1801-
RHS += pSB->GetUnitHydrograph()[n] * pSB->GetLatHistory()[n-1]; // [n-1] is because this inflow history has not yet been updated
1806+
RHS += pSB->GetUnitHydrograph()[n] * max(pSB->GetLatHistory()[n-1],0.0); // [n-1] is because this inflow history has not yet been updated
18021807
}
1803-
RHS+=aSBrunoff[p]/(tstep*SEC_PER_DAY)*pSB->GetUnitHydrograph()[0]; // [m3]->[m3/s]
1808+
RHS+=max(aSBrunoff[p],0.0)/(tstep*SEC_PER_DAY)*pSB->GetUnitHydrograph()[0]; // [m3]->[m3/s]
18041809
}
18051810
else //assimilating - skip mass balance
18061811
{
@@ -1964,11 +1969,11 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
19641969
// ------------------------------------------------------------------------
19651970
// linearized storage -discharge curve
19661971
// Qout = Qout_guess + dQ/dh * (h-h_guess) if h>h_sill
1967-
// Qout = 0 if h<h_sill
1972+
// Qout = 0 if h<=h_sill
19681973
// handled via 5 constraint equations
19691974

1970-
const double LARGE_NUMBER=1e6;
1971-
const double LARGE_NUMBER2=1000;
1975+
const double LARGE_NUMBER=1e6; //for flow variables
1976+
const double LARGE_NUMBER2=100; //for stage variables
19721977

19731978
//------------------------------------------------------------------------
19741979
//Eqns 1 & 2 : h^n+1 - M*(1-b) <= h_sill
@@ -2025,7 +2030,8 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
20252030
// Q^n+1 <= Qout_guess + dQ/dh * (h^n+1-h_guess) + M(b)
20262031
// Q^n+1 - dQ/dh* h^n+1 + Mb >= [Qout_guess - dQ/dh * h_guess]
20272032
// Q^n+1 - dQ/dh* h^n+1 - Mb <= [Qout_guess - dQ/dh * h_guess]
2028-
// dQ << M
2033+
// dQ << M
2034+
// enforces stage-discharge linearization when b==0
20292035
//------------------------------------------------------------------------
20302036

20312037
//col_ind[0]=GetDVColumnInd(DV_QOUTRES,_aResIndices[p]); row_val[0]=1.0;
@@ -2223,6 +2229,7 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
22232229
lp_lib::set_verbose (pLinProg,IMPORTANT);
22242230

22252231
int nInfeasibleIters=0;
2232+
bool lastInfeasible;
22262233
int iter=0;
22272234
double norm;
22282235
do
@@ -2242,6 +2249,12 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
22422249
{
22432250
if (_do_debug_level>0){ cout<<"LP instability found."<<endl; }
22442251
nInfeasibleIters++;
2252+
lastInfeasible=true;
2253+
aInfeasHist[iter]=true;
2254+
}
2255+
else{
2256+
lastInfeasible=false;
2257+
aInfeasHist[iter]=false;
22452258
}
22462259

22472260
// assign decision variables
@@ -2293,6 +2306,7 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
22932306
}
22942307

22952308
cout<<" Iteration Sequence: "<<endl;
2309+
cout<<" >infeasible?: "; for (int i = 0; i <= iter; i++) { cout << aInfeasHist[i] << " "; }cout << endl;
22962310
for (int p = 0; p < pModel->GetNumSubBasins(); p++) {
22972311
if (pModel->GetSubBasin(p)->GetReservoir()!=NULL){
22982312
long long SBID=pModel->GetSubBasin(p)->GetID();
@@ -2334,15 +2348,18 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
23342348
// ----------------------------------------------------------------
23352349
double value;
23362350
dv_type typ;
2351+
double wobble=0.0;
23372352
double relax=0.0;
23382353
for (int i=0;i<_nDecisionVars;i++)
23392354
{
23402355
p = _pDecisionVars[i]->p_index;
23412356
value = _pDecisionVars[i]->value;
23422357
typ = _pDecisionVars[i]->dvar_type;
2358+
//if (lastInfeasible){wobble=0.005;}
2359+
//else {wobble=0.0;}
23432360

2344-
if (typ == DV_STAGE) {ahiterHist[p][iter]=h_iter[p]; h_iter[p]=(1.0-relax)*value+(relax)*h_iter[p]; }
2345-
else if (typ == DV_QOUT ) {aQiterHist[p][iter]=Q_iter[p]; Q_iter[p]=(1.0-relax)*value+(relax)*h_iter[p]; }
2361+
if (typ == DV_STAGE) {ahiterHist[p][iter]=h_iter[p]; h_iter[p]=(1.0-relax)*value+(relax)*h_iter[p]+wobble; }
2362+
else if (typ == DV_QOUT ) {aQiterHist[p][iter]=Q_iter[p]; Q_iter[p]=(1.0-relax)*value+(relax)*Q_iter[p]; }
23462363
}
23472364

23482365
/*for (int p = 0; p < pModel->GetNumSubBasins(); p++) {
@@ -2462,9 +2479,15 @@ void CDemandOptimizer::SolveManagementProblem(CModel *pModel, const optStruct &O
24622479
delete [] lpgoalrow;
24632480
delete [] aDivert;
24642481
delete [] aDivGuess;
2482+
delete [] aInfeasHist;
2483+
for (p = 0; p < _pModel->GetNumSubBasins(); p++) {
2484+
delete [] aQiterHist[p]; delete [] ahiterHist[p];
2485+
}
2486+
delete [] aQiterHist;
2487+
delete [] ahiterHist;
24652488

24662489
//set state variables corresponding to decision variables
2467-
// SHOULD REALLY ONLY UPDATE DELIVERY, RES_EXTRACT, AND RESERVOIR OUTFLOW - ADD SWITCH TO HAVE OPT MODEL GENERATE STATE VARS OR REGULAR RAVEN SETUP
2490+
// SHOULD REALLY ONLY UPDATE DELIVERY, RES_EXTRACT, AND RESERVOIR OUTFLOW - ADD SWITCH TO HAVE OPT MODEL GENERATE STATE VARS OR REGULAR RAVEN SETUP?
24682491
// ----------------------------------------------------------------
24692492
double value;
24702493
dv_type typ;
@@ -2726,25 +2749,41 @@ void CDemandOptimizer::WriteLPSubMatrix(lp_lib::lprec* pLinProg,string file, con
27262749
for (int i = 0; i < ncols; i++) {
27272750
LPMAT<<lp_lib::get_col_name(pLinProg,i+1)<<",";
27282751
}
2729-
LPMAT<<"compare,RHS"<<endl;
2752+
LPMAT<<"compare,RHS,,prevLHS,test"<<endl;
27302753

27312754
string comp;
27322755
REAL *val=new REAL [ncols+1];
2756+
double sumprod;
2757+
double RHS;
2758+
bool bo;
27332759
for (int j=0; j<=nrows; j++)
27342760
{
2761+
sumprod=0.0;
27352762
LPMAT<<lp_lib::get_row_name(pLinProg,j)<<",";
27362763
lp_lib::get_row(pLinProg,j,val);
2764+
RHS=lp_lib::get_rh(pLinProg,j);
27372765
for (int i = 0; i < ncols; i++) {
27382766
LPMAT<<val[i+1]<<",";
2767+
sumprod+=val[i+1]*_pDecisionVars[i]->value; //LHS vector
27392768
}
27402769
int ctype=lp_lib::get_constr_type(pLinProg,j);
2741-
if (ctype==1){comp="<="; }
2742-
else if (ctype==2){comp=">="; }
2743-
else if (ctype==3){comp="=="; }
2770+
if (ctype==1){comp="<="; bo = (sumprod <=RHS+REAL_SMALL); }
2771+
else if (ctype==2){comp=">="; bo = (sumprod >=RHS-REAL_SMALL); }
2772+
else if (ctype==3){comp="=="; bo = (fabs(sumprod-RHS)/fabs(0.5*(RHS+sumprod))<0.01); }
27442773

27452774
LPMAT<<comp<<",";
2746-
LPMAT<<lp_lib::get_rh(pLinProg,j)<<endl;
2775+
LPMAT<<RHS<<",";
2776+
LPMAT<<","<<sumprod<<",";
2777+
if (bo){LPMAT<<"TRUE";}else{LPMAT<<"FALSE"; }
2778+
LPMAT<< endl;
2779+
}
2780+
LPMAT<<endl;
2781+
LPMAT<<"last_solution,";
2782+
for (int i=0;i<_nDecisionVars;i++){
2783+
LPMAT<<_pDecisionVars[i]->value<<",";
27472784
}
2785+
LPMAT<<endl;
2786+
27482787
LPMAT.close();
27492788
delete [] val;
27502789
}

src/LatFlush.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ void CmvLatFlush::GetParticipatingParamList(string *aP,class_type *aPC,int &nP)
155155
{
156156
nP=0;
157157
if (_divert) {
158-
aP[0]="DIVERT_FRACTION"; aPC[0]=CLASS_LANDUSE; nP++;
158+
aP[0]="DIVERT_FRACT"; aPC[0]=CLASS_LANDUSE; nP++;
159159
}
160160
}
161161
//////////////////////////////////////////////////////////////////

src/Model.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,6 @@ class CModel: public CModelABC
297297

298298
bool ForcingGridIsInput (const forcing_type &ftype) const;
299299
bool ForcingGridIsAvailable (const forcing_type &ftype) const;
300-
double GetAverageSnowFrac (const int idx, const double t, const int n) const;
301300

302301
void AddFromPETParamList (string *aP,class_type *aPC,int &nP,
303302
const evap_method &evaporation, const netSWRad_method &SW_radia_net) const;

src/ModelForcingGrids.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -452,25 +452,4 @@ void CModel::GenerateZeroSnow(const optStruct &Options)
452452
AddForcingGrid(pSnow,F_SNOWFALL);
453453
}
454454

455-
//////////////////////////////////////////////////////////////////
456-
/// \brief Returns average fraction of snow in precipitation between time t and following n timesteps
457-
/// \param x_col [in] Column index
458-
/// \param y_row [in] Row index
459-
/// \param t [in] Time index
460-
/// \param n [in] Number of time steps
461-
/// \return average fraction of snow in precipitation between time t and following n timesteps
462-
//
463-
double CModel::GetAverageSnowFrac(const int ic, const double t, const int n) const
464-
{
465455

466-
CForcingGrid *pSnow,*pRain;
467-
pSnow=GetForcingGrid((F_SNOWFALL));
468-
pRain=GetForcingGrid((F_RAINFALL));
469-
470-
double snow = pSnow->GetValue_avg(ic, t, n);
471-
double rain = pRain->GetValue_avg(ic, t, n);
472-
473-
if ((snow+rain)==0.0){return 0.0;}
474-
return snow/(snow+rain);
475-
476-
}

src/Reservoir.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void CReservoir::BaseConstructor(const string Name,const long long SBID)
6969

7070
_crest_ht=0.0;
7171
_crest_width=DOESNT_EXIST;
72+
_Qunder_sill=RAV_BLANK_DATA;
7273

7374
_max_capacity=0.0;
7475

@@ -202,7 +203,8 @@ CReservoir::CReservoir(const string Name, const long long SBID,
202203
if(a_Qund==NULL){ _aQunder[i]=0.0; }
203204
else { _aQunder[i]=a_Qund[i]; }
204205

205-
if (_aQ[i]==0){_crest_ht=_aStage[i];}
206+
if (_aQ [i]==0.0){_crest_ht =_aStage[i];}
207+
if ((_aQunder[i]==0.0) && (a_Qund!=NULL)){_Qunder_sill=_aStage[i];}
206208

207209
// QA/QC:
208210
if ((i > 0) && ((_aStage[i]-_aStage[i-1])<0)){
@@ -439,15 +441,19 @@ double CReservoir::GetMaxStage (const int nn) const {
439441
double CReservoir::GetDryStage () const { return _min_stage;}
440442

441443
//////////////////////////////////////////////////////////////////
442-
/// \returns sill elevation [m]
444+
/// \returns sill elevation [m] (elevation at which outflow should be zero)
443445
/// supports time-variable discharge curves and weir height adjustments
444446
//
445447
double CReservoir::GetSillElevation(const int nn) const
446448
{
449+
447450
double weir_adj=0.0;
448451
if (_pWeirHeightTS!=NULL){
449452
weir_adj=_pWeirHeightTS->GetSampledValue(nn);
450453
}
454+
if (_Qunder_sill!=RAV_BLANK_DATA){
455+
return min(_crest_ht+weir_adj,_Qunder_sill);
456+
}
451457
return _crest_ht+weir_adj;
452458
}
453459

src/Reservoir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class CReservoir
124124

125125
double _crest_ht; ///< absolute crest height, m.a.s.l (0 by default)
126126
double _crest_width; ///< crest width [m]
127+
double _Qunder_sill; ///< elevation at which underflow ceases
127128

128129
int _Np; ///< number of points on rating curves
129130
double *_aStage; ///< Rating curve for stage elevation [m]

src/StandardOutput.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,9 @@ void CModel::WriteMajorOutput(const time_struct &tt, string solfile, bool final)
14651465
BAS.close();
14661466
}
14671467

1468-
if (Options->write_basinauto){
1468+
if (Options->write_basinauto)
1469+
{
1470+
//THIS SHOULD NOT END UP IN DOCUMENTATION; WATERLOO USE ONLY
14691471
ofstream BAS;
14701472

14711473
tmpFilename=CorrectForRelativePath("SubbasinProperties_Auto.rvh", Options->rvh_filename);
@@ -1474,17 +1476,17 @@ void CModel::WriteMajorOutput(const time_struct &tt, string solfile, bool final)
14741476
WriteWarning(("CModel::WriteMinorOutput: Unable to open output file "+tmpFilename+" for writing.").c_str(),Options->noisy);
14751477
}
14761478
BAS<<":SubBasinProperties"<<endl;
1477-
BAS<<" :Parameters, Q_REFERENCE, TIME_CONC, TIME_TO_PEAK, GAMMA_SHAPE, GAMMA_SCALE, CELERITY, DIFFUSIVITY"<<endl;
1479+
BAS<<" :Parameters, Q_REFERENCE, TIME_CONC, TIME_TO_PEAK"<<endl;//, GAMMA_SHAPE, GAMMA_SCALE, CELERITY, DIFFUSIVITY"<<endl;
14781480
for(int pp=0;pp<_nSubBasins;pp++)
14791481
{
14801482
BAS<<" "<<_pSubBasins[pp]->GetID();
14811483
BAS<<","<<_pSubBasins[pp]->GetReferenceFlow();
14821484
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("TIME_CONC");
14831485
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("TIME_TO_PEAK");
1484-
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("GAMMA_SHAPE");
1485-
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("GAMMA_SCALE");
1486-
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("CELERITY");
1487-
BAS<<","<<_pSubBasins[pp]->GetBasinProperties("DIFFUSIVITY");
1486+
//BAS<<","<<_pSubBasins[pp]->GetBasinProperties("GAMMA_SHAPE");
1487+
//BAS<<","<<_pSubBasins[pp]->GetBasinProperties("GAMMA_SCALE");
1488+
//BAS<<","<<_pSubBasins[pp]->GetBasinProperties("CELERITY");
1489+
//BAS<<","<<_pSubBasins[pp]->GetBasinProperties("DIFFUSIVITY");
14881490
BAS<<endl;
14891491
}
14901492
BAS<<":EndSubBasinProperties"<<endl;

0 commit comments

Comments
 (0)