Skip to content

Commit b81f29f

Browse files
James CraigJames Craig
authored andcommitted
v501 - ECCC Assimilation; Non-linear LP Solver; LP Diagnostics [BENCHMARKED]
Implementing ECCC Assimilation strategy (Assimilate.cpp) -CReservoir::AdjustStage() (Reservoir.cpp) -Options.assim_method (ParseInput.cpp;RavenInclude.h) -:AssimilationMethod command Non-linear management optimization.cpp -@pow() function in management optimization (DemandExpressionHandling.cpp) -new member data, _pNonLinVars, _maxIterations, _iterTolerance, _relaxCoeff, assoc parsing commands (DemandOptimization.cpp;ParseManagementFile.cpp) -new TERM_ITER, TERM_POW (Expression.h/DemandExpressionHandling.cpp) -adapt AddConstraintToLP -properly handle blanks in nested TS statements (DemandExpressionHandling.cpp) Better LP_SOLVE infeasible soln handling/diagnostics (DemandOptimization.cpp) retain UPSTREAM_OF_INCLUSIVE for backward compat (ParseHRUFile.cpp) improved warnings in ParseInitialConditionFile.cpp Minor changes triggered by strict debugging process: -GWRiverConnection.cpp/.h -EnergyTransport.cpp -SubBasin.cpp Renamed count to _count in CustomOutput.cpp/.h Renamed SolveDemandProblem to SolveManagementProblem() (DemandOptimization.cpp;Solvers.cpp) Minor renaming in IsotopeTransport.cpp
1 parent 0cd8f50 commit b81f29f

22 files changed

+472
-161
lines changed

src/Assimilate.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void CModel::InitializeDataAssimilation(const optStruct &Options)
7777

7878
}
7979
/////////////////////////////////////////////////////////////////
80-
/// \brief Overrides flows with observations at gauges, or
80+
/// \brief Overrides flows with observations at gauges and propagates adjustments upstream of gauges
8181
/// \param p [in] global subbasin index
8282
/// \param Options [in] current model options structure
8383
/// \param tt [in] current model time structure
@@ -111,8 +111,15 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
111111

112112
// actually scale flows
113113
//---------------------------------------------------------------------
114-
double mass_added=_pSubBasins[p]->ScaleAllFlows(_aDAscale[p]/_aDAscale_last[p],_aDAoverride[p],Options.timestep,tt.model_time);
115-
//double mass_added=_pSubBasins[p]->AdjustAllFlows(_aDAadjust[p],_aDAoverride[p],Options.timestep,tt.model_time);
114+
double mass_added;
115+
if (Options.assim_method==DA_RAVEN_DEFAULT){
116+
mass_added=_pSubBasins[p]->ScaleAllFlows(_aDAscale[p]/_aDAscale_last[p],_aDAoverride[p],Options.timestep,tt.model_time);
117+
}
118+
else if (Options.assim_method==DA_ECCC) {
119+
mass_added=_pSubBasins[p]->AdjustAllFlows(_aDAQadjust[p],_aDAoverride[p],Options.timestep,tt.model_time);
120+
}
121+
122+
//
116123
if(mass_added>0.0){_CumulInput +=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
117124
else {_CumulOutput-=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
118125

@@ -170,7 +177,7 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
170177
_aDAoverride [p]=true;
171178
_aDAobsQ [p]=Qobs;
172179
_aDADrainSum [p]=0.0; //??? maybe doesnt matter
173-
if (pdown != DOESNT_EXIST) {
180+
if (pdown != DOESNT_EXIST) {
174181
_aDADrainSum [pdown]+=_pSubBasins[p]->GetDrainageArea(); //DOES THIS HANDLE NESTING RIGHT?
175182
}
176183
}
@@ -182,17 +189,17 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
182189
_aDAlength [p]=0.0;
183190
_aDAoverride [p]=false;
184191
_aDAobsQ [p]=0.0;
185-
if (pdown != DOESNT_EXIST) {
192+
if (pdown != DOESNT_EXIST) {
186193
_aDADrainSum[pdown] += _aDADrainSum[p];
187194
}
188195
}
189196
ObsExists=true;
190197
break; //avoids duplicate observations
191198
}
192199
}
193-
}
200+
}
194201
else {
195-
if (pdown != DOESNT_EXIST) {
202+
if (pdown != DOESNT_EXIST) {
196203
_aDADrainSum[pdown] += _aDADrainSum[p];
197204
}
198205
}
@@ -247,6 +254,8 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
247254
else {
248255
ECCCwt=1.0;
249256
}
250-
_aDAQadjust[p] = _aDAQadjust[p]*ECCCwt;
257+
if (!_aDAoverride[p]) { //no scaling for stations being overridden, only upstream
258+
_aDAQadjust[p] = _aDAQadjust[p]*ECCCwt;
259+
}
251260
}
252261
}

src/CustomOutput.cpp

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ CCustomOutput::CCustomOutput( const diagnostic variable,
6969
_hist_max =10;
7070
_nBins =1; //Arbitrary default
7171

72-
count =0;
72+
_count =0;
7373

7474
kk_only =kk;
7575

@@ -870,19 +870,14 @@ void CCustomOutput::WriteCustomOutput(const time_struct &tt,
870870
else if (_spaceAgg==BY_SELECT_HRUS){val=pModel->GetHRUGroup (kk_only)->GetHRU(k)->GetCumulFluxBet(_svind,_svind2);}
871871
}
872872

873-
if (k==0){count++;}//increment number of data items stored
873+
if (k==0){_count++;}//increment number of data items stored
874874

875875
//---Update diagnostics--------------------------------------------------
876876
//-----------------------------------------------------------------------
877877
if (_aggstat==AGG_AVERAGE)
878878
{
879-
// \todo[funct] - should handle pointwise variables (e.g., state vars) differently from periodwise variables (e.g., forcings)
880-
if (_var == VAR_STATE_VAR){
881-
data[k][0]=(double)(count-1)/(double)(count)*data[k][0]+val/count; //NOT CURRENTLY STRICTLY VALID
882-
}
883-
else {
884-
data[k][0]=(double)(count-1)/(double)(count)*data[k][0]+val/count;
885-
}
879+
//incrementally adding to average - 1/N*((N-1)(old mean)+(val))
880+
data[k][0]=(double)(_count-1)/(double)(_count)*data[k][0]+val/(double)(_count);
886881
}
887882
else if (_aggstat==AGG_MAXIMUM)
888883
{
@@ -907,7 +902,7 @@ void CCustomOutput::WriteCustomOutput(const time_struct &tt,
907902
(_aggstat==AGG_HISTOGRAM))
908903
{
909904
//populate data
910-
data [k][count-1] = val;
905+
data [k][_count-1] = val;
911906
}
912907
else
913908
{
@@ -933,31 +928,31 @@ void CCustomOutput::WriteCustomOutput(const time_struct &tt,
933928
else if(_aggstat==AGG_MEDIAN)
934929
{
935930
double Q1,Q2,Q3;
936-
quickSort(data[k],0,count-1);
937-
GetQuartiles(data[k],count,Q1,Q2,Q3);
931+
quickSort(data[k],0,_count-1);
932+
GetQuartiles(data[k],_count,Q1,Q2,Q3);
938933
_CUSTOM<<FormatDouble(Q2)<<sep;
939934
}
940935
else if(_aggstat==AGG_QUARTILES) //find lower quartile, median, then upper quartile
941936
{
942937
double Q1,Q2,Q3;
943-
quickSort(data[k],0,count-1);
944-
GetQuartiles(data[k],count,Q1,Q2,Q3);
938+
quickSort(data[k],0,_count-1);
939+
GetQuartiles(data[k],_count,Q1,Q2,Q3);
945940
_CUSTOM<<FormatDouble(Q1)<<sep<<FormatDouble(Q2)<<sep<<FormatDouble(Q3)<<sep;
946941
}
947942
else if(_aggstat==AGG_95CI)
948943
{
949-
quickSort(data[k],0,count-1);//take floor and ceiling of lower and upper intervals to be conservative
950-
_CUSTOM << FormatDouble(data[k][(int)floor((double)(count-1)*0.025)])<<sep;
951-
_CUSTOM << FormatDouble(data[k][(int)ceil((double)(count-1)*0.975)])<<sep;
944+
quickSort(data[k],0,_count-1);//take floor and ceiling of lower and upper intervals to be conservative
945+
_CUSTOM << FormatDouble(data[k][(int)floor((double)(_count-1)*0.025)])<<sep;
946+
_CUSTOM << FormatDouble(data[k][(int)ceil((double)(_count-1)*0.975)])<<sep;
952947
}
953948
else if(_aggstat==AGG_HISTOGRAM)
954949
{
955-
quickSort(data[k],0,count-1);
950+
quickSort(data[k],0,_count-1);
956951
double binsize = (_hist_max-_hist_min)/_nBins;
957952
int bincount[MAX_HISTOGRAM_BINS];
958953

959954
for(int bin=0;bin<_nBins;bin++){ bincount[bin]=0; }
960-
for(int a=0;a<count;a++)
955+
for(int a=0;a<_count;a++)
961956
{
962957
for(int bin=0;bin<_nBins;bin++){
963958
if((data[k][a]>=(_hist_min+bin*binsize)) && (data[k][a]<(_hist_min+(bin+1)*binsize))){ bincount[bin]++; }
@@ -982,8 +977,8 @@ void CCustomOutput::WriteCustomOutput(const time_struct &tt,
982977
else if(_aggstat==AGG_MEDIAN)
983978
{
984979
double Q1,Q2,Q3;
985-
quickSort(data[k],0,count-1);
986-
GetQuartiles(data[k],count,Q1,Q2,Q3);
980+
quickSort(data[k],0,_count-1);
981+
GetQuartiles(data[k],_count,Q1,Q2,Q3);
987982
out=Q2;
988983
}
989984
output[k]=out;
@@ -1011,7 +1006,7 @@ void CCustomOutput::WriteCustomOutput(const time_struct &tt,
10111006
}
10121007
}
10131008
//...more stats here
1014-
if (k==num_data-1){count=0;}//don't reboot count until last HRU/basin is done
1009+
if (k==num_data-1){_count=0;}//don't reboot count until last HRU/basin is done
10151010
}//end if (reset)
10161011
}//end for (k=0;...
10171012

@@ -1218,4 +1213,4 @@ CCustomOutput *CCustomOutput::ParseCustomOutputCommand(char *s[MAXINPUTITEMS], c
12181213
}
12191214

12201215
return pCustom;
1221-
}
1216+
}

src/CustomOutput.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*----------------------------------------------------------------
22
Raven Library Source Code
3-
Copyright (c) 2008-2023 the Raven Development Team
3+
Copyright (c) 2008-2025 the Raven Development Team
44
----------------------------------------------------------------
55
Custom output generation
66
----------------------------------------------------------------*/
@@ -96,7 +96,7 @@ class CCustomOutput
9696
//(e.g., =2 if max and min are both tracked)
9797
int _time_index; ///< index tracking current output line (e.g., 3=3 years/months/days passed, dependent upon _timeAgg
9898

99-
int count; ///< counts accumulated data (# of timesteps since last output dump)
99+
int _count; ///< counts accumulated data (# of timesteps since last output dump)
100100

101101
int kk_only; ///< index of HRUGroup for which output is generated when spaceAgg==BY_SELECT_HRUS
102102

0 commit comments

Comments
 (0)