@@ -84,7 +84,8 @@ void CModel::InitializeDataAssimilation(const optStruct &Options)
8484//
8585void CModel::AssimilationOverride (const int p,const optStruct& Options,const time_struct& tt)
8686{
87- if (!Options.assimilate_flow ) { return ; }
87+ if (!Options.assimilate_flow ) { return ; }
88+ if (!_pSubBasins[p]->IsEnabled ()){ return ; }
8889
8990 // Get current, up-to-date flow and calculate scaling factor
9091 // ---------------------------------------------------------------------
@@ -93,13 +94,14 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
9394 double Qobs,Qmod,Qmodlast;
9495 double alpha = _pGlobalParams->GetParams ()->assimilation_fact ;
9596
96- Qobs = _aDAobsQ[p];
97- Qmod = _pSubBasins[p]->GetOutflowRate ();
97+ Qobs = _aDAobsQ[p];
98+ Qmod = _pSubBasins[p]->GetOutflowRate ();
9899 Qmodlast= _pSubBasins[p]->GetLastOutflowRate ();
99100 if (Qmod>PRETTY_SMALL) {
100101 _aDAscale [p]=1.0 +alpha*((Qobs-Qmod)/Qmod); // if alpha = 1, Q=Qobs in observation basin
101- // _aDAQadjust[p]=alpha*(Qobs-Qmod);//Option A: instantaneous flow
102- _aDAQadjust[p]=alpha*(2.0 *Qobs-Qmodlast-Qmod);// Option B: mean flow
102+ // _aDAQadjust[p]=alpha*(Qobs-Qmod);//Option A: instantaneous flow (should set second argument to AdjustAllFlows() to true)
103+ _aDAQadjust[p]=0.5 *alpha*(2.0 *Qobs-Qmodlast-Qmod);// Option B: mean flow
104+ // _aDAQadjust[p]=1.0;//TMP DEBUG - TESTING
103105 }
104106 else {
105107 _aDAscale [p]=1.0 ;
@@ -115,7 +117,9 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
115117 mass_added=_pSubBasins[p]->ScaleAllFlows (_aDAscale[p]/_aDAscale_last[p],_aDAoverride[p],Options.timestep ,tt.model_time );
116118 }
117119 else if (Options.assim_method ==DA_ECCC) {
118- mass_added=_pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],_aDAoverride[p],Options.timestep ,tt.model_time );
120+ if (_aDAoverride[p]){
121+ mass_added=_pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],true ,Options.timestep ,tt.model_time );
122+ }
119123 }
120124
121125 //
@@ -141,127 +145,188 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
141145 double Qobs;
142146 double t_observationsOFF=ALMOST_INF;// Only used for debugging - keep as ALMOST_INF otherwise
143147
144- int nn=(int )((tt.model_time +TIME_CORRECTION)/Options.timestep )+1 ;// end of timestep index
145-
146148 for (p=0 ; p<_nSubBasins; p++) {
147149 _aDAscale_last[p]=_aDAscale[p];
148150 _aDADrainSum[p]=0.0 ;
149151 }
150152
153+ int nn=(int )((tt.model_time +TIME_CORRECTION)/Options.timestep )+1 ;// end of timestep index
154+
151155 for (int pp=_nSubBasins-1 ; pp>=0 ; pp--)// downstream to upstream
152156 {
153157 p=GetOrderedSubBasinIndex (pp);
154158
155- pdown=DOESNT_EXIST;
156- if (_pSubBasins[p]->GetDownstreamID ()!=DOESNT_EXIST){
157- pdown = GetSubBasinByID (_pSubBasins[p]->GetDownstreamID ())->GetGlobalIndex ();
158- }
159+ pdown=GetDownstreamBasin (p);
160+
159161 bool ObsExists=false ; // observation available in THIS basin
160- // observations in this basin, determine scaling variables based upon blank/not blank
161- // ----------------------------------------------------------------
162+
162163 if (_pSubBasins[p]->UseInFlowAssimilation ())
163164 {
164165 for (int i=0 ; i<_nObservedTS; i++) // determine whether flow observation is available
165166 {
166167 if (IsContinuousFlowObs2 (_pObservedTS[i],_pSubBasins[p]->GetID ()))// flow observation is available and linked to this subbasin
167168 {
168169 Qobs = _pObservedTS[i]->GetSampledValue (nn); // mean timestep flow
169-
170- // bool fakeblank=((tt.model_time>30) && (tt.model_time<40)) || ((tt.model_time>45) && (tt.model_time<47));//TMP DEBUG
171- // if (fakeblank){Qobs=RAV_BLANK_DATA;}
172-
173- if ((Qobs!=RAV_BLANK_DATA) && (tt.model_time <t_observationsOFF))
174- {
175- // _aDAscale[p] calculated live in AssimilationOverride when up-to-date modelled flow available
176- // same with _aDAQadjust[p]
177- _aDAlength [p]=0.0 ;
178- _aDAtimesince[p]=0.0 ;
179- _aDAoverride [p]=true ;
180- _aDAobsQ [p]=Qobs;
181- _aDADrainSum [p]=0.0 ; // ??? maybe doesnt matter
182- if (pdown != DOESNT_EXIST) {
183- _aDADrainSum [pdown]+=_pSubBasins[p]->GetDrainageArea (); // DOES THIS HANDLE NESTING RIGHT?
184- }
185- }
186- else
187- { // found a blank or zero flow value
188- _aDAscale [p]=_aDAscale[p];// same adjustment as before - scaling persists
189- _aDAQadjust [p]=_aDAQadjust[p];// same adjustment as before - flow magnitude persists
190- _aDAtimesince[p]+=Options.timestep ;
191- _aDAlength [p]=0.0 ;
192- _aDAoverride [p]=false ;
193- _aDAobsQ [p]=0.0 ;
194- if (pdown != DOESNT_EXIST) {
195- _aDADrainSum[pdown] += _aDADrainSum[p];
196- }
197- }
198170 ObsExists=true ;
199171 break ; // avoids duplicate observations
200172 }
201173 }
202174 }
203- else {
204- if (pdown != DOESNT_EXIST) {
205- _aDADrainSum[pdown] += _aDADrainSum[p];
175+
176+ pdown=GetDownstreamBasin (p);
177+
178+ // observations in this basin, determine scaling variables based upon blank/not blank
179+ // ----------------------------------------------------------------
180+ if (ObsExists) {
181+ if ((Qobs!=RAV_BLANK_DATA) && (tt.model_time <t_observationsOFF))
182+ {
183+ // _aDAscale[p] calculated live in AssimilationOverride when up-to-date modelled flow available
184+ _aDAlength [p]=0.0 ;
185+ _aDAtimesince[p]=0.0 ;
186+ _aDAoverride [p]=true ;
187+ _aDAobsQ [p]=Qobs;
188+ }
189+ else
190+ { // found a blank or zero flow value
191+ _aDAscale [p]=_aDAscale[p];// same adjustment as before - scaling persists
192+ _aDAlength [p]=0.0 ;
193+ _aDAtimesince[p]+=Options.timestep ;
194+ _aDAoverride [p]=false ;
195+ _aDAobsQ [p]=0.0 ;
206196 }
207197 }
208198 // no observations in this basin, get scaling from downstream
209199 // ----------------------------------------------------------------
210- pdown= GetDownstreamBasin (p);
211- if (ObsExists== false ) { // observations may be downstream, propagate scaling upstream
200+ else if (!ObsExists) // observations may be downstream, propagate scaling upstream
201+ {
212202 // if ((pdown!=DOESNT_EXIST) && (!_aDAoverride[pdown])){ //alternate - allow information to pass through reservoirs
213- if ((pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[pdown])) {
203+ if ( (pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[p]) && (_pSubBasins[p]-> IsEnabled ()) && (_pSubBasins[ pdown]-> IsEnabled () )) {
214204 _aDAscale [p]= _aDAscale [pdown];
215- _aDAQadjust [p]= _aDAQadjust [pdown] * (_pSubBasins[p]->GetDrainageArea () / _pSubBasins[pdown]->GetDrainageArea ());
216205 _aDAlength [p]+=_pSubBasins [pdown]->GetReachLength ();
217206 _aDAtimesince [p]= _aDAtimesince[pdown];
218- _aDAoverride [p]=false ;
207+ _aDAoverride [p]=false ;
219208 }
220209 else { // Nothing downstream or reservoir present in this basin, no assimilation
221210 _aDAscale [p]=1.0 ;
222- _aDAQadjust [p]=0.0 ;
223211 _aDAlength [p]=0.0 ;
224212 _aDAtimesince[p]=0.0 ;
225213 _aDAoverride [p]=false ;
226214 }
227215 }
228216 }// end downstream to upstream
229-
217+
218+ // Calculate _aDADrainSum, sum of assimilated drainage areas upstream of a subbasin outlet
219+ // and _aDADownSum, drainage of nearest assimilated flow observation
220+ // dynamic because data can disappear mid simulation
221+ // -------------------------------------------------------------------
222+ for (int pp=0 ;pp<_nSubBasins; pp++)
223+ {
224+ _aDADrainSum[p]=0.0 ;
225+ _aDADownSum [p]=0.0 ;
226+ }
230227 for (int pp=0 ;pp<_nSubBasins; pp++)// upstream to downstream
231228 {
232229 p=GetOrderedSubBasinIndex (pp);
230+ pdown=GetDownstreamBasin (p);
233231
234- pdown=DOESNT_EXIST;
235- if (_pSubBasins[p]->GetDownstreamID ()!=DOESNT_EXIST){
236- pdown = GetSubBasinByID (_pSubBasins[p]->GetDownstreamID ())->GetGlobalIndex ();
237- }
238232 if (_aDAoverride[p]) {
239233 _aDADrainSum[p]=_pSubBasins[p]->GetDrainageArea ();
240234 }
235+ /*
236+ else if (_pSubBasins[p]->GetReservoir()!=NULL){ //??
237+ _aDADrainSum[p]=0.0;
238+ }
239+ */
241240 else if (pdown!=DOESNT_EXIST){
242- _aDADrainSum[p] =_aDADrainSum[pdown ];
241+ _aDADrainSum[pdown]+ =_aDADrainSum[p ];
243242 }
244243 }
244+ for (int pp=_nSubBasins-1 ;pp>=0 ; pp--)// downstream to upstream
245+ {
246+ p=GetOrderedSubBasinIndex (pp);
247+ pdown=GetDownstreamBasin (p);
245248
249+ if (_aDAoverride[p]) {
250+ _aDADownSum[p]=_pSubBasins[p]->GetDrainageArea ();
251+ }
252+ else if (pdown!=DOESNT_EXIST){
253+ _aDADownSum[p]=_aDADownSum[pdown];
254+ }
255+ }
246256
247257 // Apply time and space correction factors
248258 // ----------------------------------------------------------------
249259 double time_fact = _pGlobalParams->GetParams ()->assim_time_decay ;
250260 double distfact = _pGlobalParams->GetParams ()->assim_upstream_decay /M_PER_KM; // [1/km]->[1/m]
251- double ECCCwt;
252261 for (p=0 ; p<_nSubBasins; p++)
253262 {
254- _aDAscale [p] =1.0 +(_aDAscale[p]-1.0 )*exp (-distfact*_aDAlength[p])*exp (-time_fact*_aDAtimesince[p]);
255- // _aDAQadjust[p] =_aDAQadjust[p]*exp(-distfact*_aDAlength[p])*exp(-time_fact*_aDAtimesince[p]);
263+ _aDAscale[p] =1.0 +(_aDAscale[p]-1.0 )*exp (-distfact*_aDAlength[p])*exp (-time_fact*_aDAtimesince[p]);
264+ }
265+ }
266+ // ///////////////////////////////////////////////////////////////
267+ // / \brief Calculates updated DA scaling coefficients for all subbasins for forthcoming timestep
268+ // / \note most scale coefficients will be 1.0 except:
269+ // / (1) gauges with valid observation data, which scale to override OR
270+ // / (2) basins at or upstream of missing observation data
271+ // / actual scaling performed in CModel::AssimilationOverride() during routing
272+ // / \param tt [in] current model time structure
273+ // / \param Options [in] current model options structure
274+ //
275+ void CModel::AssimilationBackPropagate (const optStruct &Options,const time_struct &tt)
276+ {
277+ int p,pdown;
256278
279+ if (!Options.assimilate_flow ) {return ;}
280+
281+ for (int pp=_nSubBasins-1 ; pp>=0 ; pp--)// downstream to upstream
282+ {
283+ p=GetOrderedSubBasinIndex (pp);
284+
285+ pdown=DOESNT_EXIST;
286+ if (_pSubBasins[p]->GetDownstreamID ()!=DOESNT_EXIST){
287+ pdown = GetSubBasinByID (_pSubBasins[p]->GetDownstreamID ())->GetGlobalIndex ();
288+ }
289+
290+ // no observations in this basin, get scaling from downstream
291+ // ----------------------------------------------------------------
292+ pdown=GetDownstreamBasin (p);
293+ long long SBID=_pSubBasins[p]->GetID ();
294+ if (!_aDAoverride[p]) { // observations may be downstream, propagate scaling upstream
295+ if ( (pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[p]) && (_pSubBasins[p]->IsEnabled ()) && (_pSubBasins[pdown]->IsEnabled ())) {
296+ _aDAQadjust [p]= _aDAQadjust [pdown] * (_pSubBasins[p]->GetDrainageArea () / _pSubBasins[pdown]->GetDrainageArea ());
297+ // cout<<"PROPAGATING "<<SBID<<": " <<setprecision(3)<< _aDAQadjust[p] << " from " << _aDAQadjust[pdown] << endl;
298+ }
299+ else { // Nothing downstream or reservoir present in this basin, no assimilation
300+ _aDAQadjust [p]=0.0 ;
301+ }
302+ }
303+ else if (_pSubBasins[p]->IsEnabled ()) {
304+ // cout<<"ASSIMILATING AT "<<SBID<<": " << _aDAQadjust[p] << endl;
305+ }
306+ } // end downstream to upstream
307+
308+ // Apply time and space correction factors
309+ // ----------------------------------------------------------------
310+ double time_fact = _pGlobalParams->GetParams ()->assim_time_decay ;
311+ double distfact = _pGlobalParams->GetParams ()->assim_upstream_decay /M_PER_KM; // [1/km]->[1/m]
312+ double ECCCwt;
313+ for (p=0 ; p<_nSubBasins; p++)
314+ {
315+ // _aDAQadjust[p] *=exp(-distfact*_aDAlength[p])*exp(-time_fact*_aDAtimesince[p]);
316+ ECCCwt=1.0 ;
257317 if (_aDADrainSum[p]!=0.0 ){
258318 ECCCwt = (_pSubBasins[p]->GetDrainageArea () - _aDADrainSum[p])/(_aDADownSum[p]-_aDADrainSum[p]);
259319 }
260- else {
261- ECCCwt=1.0 ;
262- }
320+
263321 if (!_aDAoverride[p]) { // no scaling for stations being overridden, only upstream
264322 _aDAQadjust[p] = _aDAQadjust[p]*ECCCwt;
265323 }
266324 }
267- }
325+
326+ // Actually update flows
327+ // ----------------------------------------------------------------
328+ for (p=0 ; p<_nSubBasins; p++)
329+ {
330+ _pSubBasins[p]->AdjustAllFlows (_aDAQadjust[p],false ,Options.timestep ,tt.model_time );
331+ }
332+ }
0 commit comments