@@ -34,6 +34,8 @@ void CModel::InitializeDataAssimilation(const optStruct &Options)
3434 _aDAtimesince =new double [_nSubBasins];
3535 _aDAoverride =new bool [_nSubBasins];
3636 _aDAobsQ =new double [_nSubBasins];
37+ _aDAobsQ2 =new double [_nSubBasins];
38+ _aDASinceLastBlank=new double [_nSubBasins];
3739 for (int p=0 ; p<_nSubBasins; p++) {
3840 _aDAscale [p]=1.0 ;
3941 _aDAscale_last[p]=1.0 ;
@@ -44,6 +46,8 @@ void CModel::InitializeDataAssimilation(const optStruct &Options)
4446 _aDAtimesince [p]=0.0 ;
4547 _aDAoverride [p]=false ;
4648 _aDAobsQ [p]=0.0 ;
49+ _aDAobsQ2 [p]=0.0 ;
50+ _aDASinceLastBlank[p]=0.0 ; // initialized to zero to ramp from IC (default)
4751 }
4852 int count=0 ;
4953 for (int p=0 ; p<_nSubBasins; p++) {
@@ -71,17 +75,28 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
7175
7276 // Get current, up-to-date flow and calculate scaling factor
7377 // ---------------------------------------------------------------------
78+ double Qobs;
7479 if (_aDAoverride[p])
7580 {
76- double Qobs ,Qmod,Qmodlast;
81+ double Qobs2 ,Qmod,Qmodlast;
7782 double alpha = _pGlobalParams->GetParams ()->assimilation_fact ;
7883
84+ // alpha*=(1.0-exp(-0.06*_aDASinceLastBlank[p])); //shock/oscillation prevention
85+
7986 Qobs = _aDAobsQ[p];
87+ Qobs2 = _aDAobsQ2[p];
8088 Qmod = _pSubBasins[p]->GetOutflowRate ();
8189 Qmodlast= _pSubBasins[p]->GetLastOutflowRate ();
8290 if (Qmod>PRETTY_SMALL) {
8391 _aDAscale [p]=1.0 +alpha*((Qobs-Qmod)/Qmod); // if alpha = 1, Q=Qobs in observation basin
84- _aDAQadjust[p]=0.5 *alpha*(2.0 *Qobs-Qmodlast-Qmod);// Option B: mean flow
92+ // _aDAQadjust[p]=alpha*(Qobs-Qmod); //Option A: end of time step flow
93+ // _aDAQadjust[p]=0.5*alpha*(2.0*Qobs-Qmodlast-Qmod);//Option B: mean flow - rapidly oscillatory Q - Qmean is perfect
94+ if (Qobs2 == RAV_BLANK_DATA) { // Option C: aim for midpoint of two observation flows (this is the way)
95+ _aDAQadjust[p]=alpha*(Qobs-Qmod);
96+ }
97+ else {
98+ _aDAQadjust[p]=alpha*(0.5 *(Qobs2+Qobs)-Qmod);
99+ }
85100 }
86101 else {
87102 _aDAscale [p]=1.0 ;
@@ -92,17 +107,16 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
92107
93108 // actually scale flows
94109 // ---------------------------------------------------------------------
95- double mass_added;
110+ double mass_added= 0.0 ;
96111 if (Options.assim_method ==DA_RAVEN_DEFAULT){
97112 mass_added=_pSubBasins[p]->ScaleAllFlows (_aDAscale[p]/_aDAscale_last[p],_aDAoverride[p],Options.timestep ,tt.model_time );
98113 }
99114 else if (Options.assim_method ==DA_ECCC) {
100115 if (_aDAoverride[p]){
101- mass_added=_pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],true ,Options.timestep ,tt.model_time );
116+ mass_added=_pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],true ,true , Options.timestep ,tt.model_time );
102117 }
103118 }
104119
105- //
106120 if (mass_added>0.0 ){_CumulInput +=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
107121 else {_CumulOutput-=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
108122
@@ -122,14 +136,17 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
122136 if (tt.model_time <(Options.assimilation_start -Options.timestep /2.0 )){return ;}// assimilates all data after or on assimilation date
123137
124138 int p,pdown;
125- double Qobs;
139+ double Qobs,Qobs2 ;
126140 double t_observationsOFF=ALMOST_INF;// Only used for debugging - keep as ALMOST_INF otherwise
141+ bool ObsExists; // observation available in THIS basin
127142
128143 for (p=0 ; p<_nSubBasins; p++) {
129144 _aDAscale_last[p]=_aDAscale[p];
130145 _aDADrainSum[p]=0.0 ;
131146 }
132147
148+ // check for observations in each basin
149+ // ----------------------------------------------------------------
133150 int nn=(int )((tt.model_time +TIME_CORRECTION)/Options.timestep )+1 ;// end of timestep index
134151
135152 for (int pp=_nSubBasins-1 ; pp>=0 ; pp--)// downstream to upstream
@@ -138,7 +155,7 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
138155
139156 pdown=GetDownstreamBasin (p);
140157
141- bool ObsExists=false ; // observation available in THIS basin
158+ ObsExists=false ;
142159
143160 if (_pSubBasins[p]->UseInFlowAssimilation ())
144161 {
@@ -147,6 +164,7 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
147164 if (IsContinuousFlowObs2 (_pObservedTS[i],_pSubBasins[p]->GetID ()))// flow observation is available and linked to this subbasin
148165 {
149166 Qobs = _pObservedTS[i]->GetSampledValue (nn); // mean timestep flow
167+ Qobs2 = _pObservedTS[i]->GetSampledValue (nn+1 ); // mean timestep flow
150168 ObsExists=true ;
151169 break ; // avoids duplicate observations
152170 }
@@ -165,6 +183,8 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
165183 _aDAtimesince[p]=0.0 ;
166184 _aDAoverride [p]=true ;
167185 _aDAobsQ [p]=Qobs;
186+ _aDAobsQ2 [p]=Qobs2;
187+ _aDASinceLastBlank[p]+=1.0 ;
168188 }
169189 else
170190 { // found a blank or zero flow value
@@ -173,14 +193,19 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
173193 _aDAtimesince[p]+=Options.timestep ;
174194 _aDAoverride [p]=false ;
175195 _aDAobsQ [p]=0.0 ;
196+ _aDAobsQ2 [p]=0.0 ;
197+ _aDASinceLastBlank[p]+=0.0 ;
176198 }
177199 }
178200 // no observations in this basin, get scaling from downstream
179201 // ----------------------------------------------------------------
180202 else if (!ObsExists) // observations may be downstream, propagate scaling upstream
181203 {
182204 // if ((pdown!=DOESNT_EXIST) && (!_aDAoverride[pdown])){ //alternate - allow information to pass through reservoirs
183- if ( (pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[p]) && (_pSubBasins[p]->IsEnabled ()) && (_pSubBasins[pdown]->IsEnabled ())) {
205+ if ( (pdown!=DOESNT_EXIST) &&
206+ (_pSubBasins[p]->GetReservoir ()==NULL ) &&
207+ (!_aDAoverride[p]) &&
208+ (_pSubBasins[p]->IsEnabled ()) && (_pSubBasins[pdown]->IsEnabled ())) {
184209 _aDAscale [p]= _aDAscale [pdown];
185210 _aDAlength [p]+=_pSubBasins [pdown]->GetReachLength ();
186211 _aDAtimesince [p]= _aDAtimesince[pdown];
@@ -258,54 +283,55 @@ void CModel::AssimilationBackPropagate(const optStruct &Options,const time_struc
258283
259284 if (!Options.assimilate_flow ) {return ;}
260285
286+ // Determine flow adjustment magnitude
287+ // ----------------------------------------------------------------
261288 for (int pp=_nSubBasins-1 ; pp>=0 ; pp--)// downstream to upstream
262289 {
263- p=GetOrderedSubBasinIndex (pp);
264-
265- pdown=DOESNT_EXIST;
266- if (_pSubBasins[p]->GetDownstreamID ()!=DOESNT_EXIST){
267- pdown = GetSubBasinByID (_pSubBasins[p]->GetDownstreamID ())->GetGlobalIndex ();
268- }
269-
270- // no observations in this basin, get scaling from downstream
271- // ----------------------------------------------------------------
290+ p =GetOrderedSubBasinIndex (pp);
272291 pdown=GetDownstreamBasin (p);
273- long long SBID=_pSubBasins[p]->GetID ();
274- if (!_aDAoverride[p]) { // observations may be downstream, propagate scaling upstream
275- if ( (pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[p]) && (_pSubBasins[p]->IsEnabled ()) && (_pSubBasins[pdown]->IsEnabled ())) {
276- _aDAQadjust [p]= _aDAQadjust [pdown] * (_pSubBasins[p]->GetDrainageArea () / _pSubBasins[pdown]->GetDrainageArea ());
277- // cout<<"PROPAGATING "<<SBID<<": " <<setprecision(3)<< _aDAQadjust[p] << " from " << _aDAQadjust[pdown] << endl;
292+
293+ if (!_aDAoverride[p]) { // observations may be downstream, get scaling from downstream
294+ if ( (pdown!=DOESNT_EXIST ) &&
295+ (!_aDAoverride[p] ) &&
296+ (_pSubBasins[p]->GetReservoir ()==NULL ) &&
297+ (_pSubBasins[p]->IsEnabled ()) && (_pSubBasins[pdown]->IsEnabled ()))
298+ {
299+ _aDAQadjust[p]= _aDAQadjust [pdown] * (_pSubBasins[p]->GetDrainageArea () / _pSubBasins[pdown]->GetDrainageArea ());
278300 }
279- else { // Nothing downstream or reservoir present in this basin, no assimilation
280- _aDAQadjust [p]=0.0 ;
301+ else { // Nothing downstream or reservoir present in this basin, no adjustment
302+ _aDAQadjust[p]= 0.0 ;
281303 }
282304 }
283- else if (_pSubBasins[p]->IsEnabled ()) {
284- // cout<<"ASSIMILATING AT "<<SBID<<": " << _aDAQadjust[p] << endl;
285- }
286- } // end downstream to upstream
305+ }
287306
288307 // Apply time and space correction factors
289308 // ----------------------------------------------------------------
290309 double distfact = _pGlobalParams->GetParams ()->assim_upstream_decay /M_PER_KM; // [1/km]->[1/m]
291310 double ECCCwt;
292311 for (p=0 ; p<_nSubBasins; p++)
293312 {
294- _aDAQadjust[p] *=exp (-distfact*_aDAlength[p]);
295- ECCCwt=1.0 ;
296- if (_aDADrainSum[p]!=0.0 ){
297- ECCCwt = (_pSubBasins[p]->GetDrainageArea () - _aDADrainSum[p])/(_aDADownSum[p]-_aDADrainSum[p]);
298- }
313+ if (!_aDAoverride[p])
314+ {
315+ pdown=GetDownstreamBasin (p);
316+ if (pdown!=DOESNT_EXIST){
317+ _aDAQadjust[p] *=exp (-distfact*_aDAlength[pdown]);
318+ }
299319
300- if (!_aDAoverride[p]) { // no scaling for stations being overridden, only upstream
301- _aDAQadjust[p] = _aDAQadjust[p]*ECCCwt;
320+ ECCCwt=1.0 ;
321+ if (_aDADrainSum[p]!=0.0 ){
322+ ECCCwt = (_pSubBasins[p]->GetDrainageArea () - _aDADrainSum[p])/(_aDADownSum[p]-_aDADrainSum[p]);
323+ }
324+
325+ if (!_aDAoverride[p]) { // no scaling for stations being overridden, only upstream
326+ _aDAQadjust[p] = _aDAQadjust[p]*ECCCwt;
327+ }
302328 }
303329 }
304330
305331 // Actually update flows
306332 // ----------------------------------------------------------------
307333 for (p=0 ; p<_nSubBasins; p++)
308334 {
309- _pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],false ,Options.timestep ,tt.model_time );
335+ _pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],false ,_aDAoverride[p], Options.timestep ,tt.model_time );
310336 }
311337}
0 commit comments