11/* ----------------------------------------------------------------
22 Raven Library Source Code
3- Copyright (c) 2008-2021 the Raven Development Team
3+ Copyright (c) 2008-2025 the Raven Development Team
44 ----------------------------------------------------------------*/
55#include " RavenInclude.h"
66#include " Model.h"
77
88/* ****************************************************************
99 Model Streamflow Assimilation Routines
1010*****************************************************************/
11- bool IsContinuousFlowObs2 (const CTimeSeriesABC *pObs,long SBID)
11+ bool IsContinuousFlowObs2 (const CTimeSeriesABC *pObs,long long SBID)
1212{
1313 // clears up terribly ugly repeated if statements
1414 if (pObs==NULL ) { return false ; }
@@ -25,19 +25,21 @@ void CModel::InitializeDataAssimilation(const optStruct &Options)
2525 // Initialize Streamflow assimilation
2626 if (Options.assimilate_flow )
2727 {
28- _aDAscale =new double [_nSubBasins];
29- _aDAlength =new double [_nSubBasins];
30- _aDAtimesince=new double [_nSubBasins];
31- _aDAoverride =new bool [_nSubBasins];
32- _aDAobsQ =new double [_nSubBasins];
33- _aDAlast =new double [_nSubBasins];
28+ _aDAscale =new double [_nSubBasins];
29+ _aDAscale_last=new double [_nSubBasins];
30+ _aDAQadjust =new double [_nSubBasins];
31+ _aDAlength =new double [_nSubBasins];
32+ _aDAtimesince =new double [_nSubBasins];
33+ _aDAoverride =new bool [_nSubBasins];
34+ _aDAobsQ =new double [_nSubBasins];
3435 for (int p=0 ; p<_nSubBasins; p++) {
35- _aDAscale [p]=1.0 ;
36- _aDAlength [p]=0.0 ;
37- _aDAtimesince[p]=0.0 ;
38- _aDAoverride [p]=false ;
39- _aDAobsQ [p]=0.0 ;
40- _aDAlast [p]=1.0 ;
36+ _aDAscale [p]=1.0 ;
37+ _aDAscale_last[p]=1.0 ;
38+ _aDAQadjust [p]=0.0 ;
39+ _aDAlength [p]=0.0 ;
40+ _aDAtimesince [p]=0.0 ;
41+ _aDAoverride [p]=false ;
42+ _aDAobsQ [p]=0.0 ;
4143 }
4244 int count=0 ;
4345 for (int p=0 ; p<_nSubBasins; p++) {
@@ -93,17 +95,20 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
9395 // Option B: instantaneous flow
9496 Qmod = _pSubBasins[p]->GetOutflowRate ();
9597 if (Qmod>PRETTY_SMALL) {
96- _aDAscale[p]=1.0 +alpha*((Qobs-Qmod)/Qmod);
98+ _aDAscale [p]=1.0 +alpha*((Qobs-Qmod)/Qmod); // if alpha = 1, Q=Qobs in observation basin
99+ _aDAQadjust[p]=alpha*(Qobs-Qmod);
97100 }
98101 else {
99- _aDAscale[p]=1.0 ;
102+ _aDAscale [p]=1.0 ;
103+ _aDAQadjust[p]=0.0 ;
100104 }
101- _aDAlast [p]=1.0 ;// no need to scale previous
105+ _aDAscale_last [p]=1.0 ;// no need to scale previous
102106 }
103107
104108 // actually scale flows
105109 // ---------------------------------------------------------------------
106- double mass_added=_pSubBasins[p]->ScaleAllFlows (_aDAscale[p]/_aDAlast[p],_aDAoverride[p],Options.timestep ,tt.model_time );
110+ double mass_added=_pSubBasins[p]->ScaleAllFlows (_aDAscale[p]/_aDAscale_last[p],_aDAoverride[p],Options.timestep ,tt.model_time );
111+ // double mass_added=_pSubBasins[p]->AdjustAllFlows(_aDAadjust[p],_aDAoverride[p],Options.timestep,tt.model_time);
107112 if (mass_added>0.0 ){_CumulInput +=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
108113 else {_CumulOutput-=mass_added/(_WatershedArea*M2_PER_KM2)*MM_PER_METER;}
109114
@@ -119,17 +124,17 @@ void CModel::AssimilationOverride(const int p,const optStruct& Options,const tim
119124//
120125void CModel::PrepareAssimilation (const optStruct &Options,const time_struct &tt)
121126{
122- if (!Options.assimilate_flow ) {return ;}
123- if (tt.model_time <(Options.assimilation_start + Options.timestep /2.0 )){return ;}// assimilates all data after assimilation date
127+ if (!Options.assimilate_flow ) {return ;}
128+ if (tt.model_time <(Options.assimilation_start - Options.timestep /2.0 )){return ;}// assimilates all data after or on assimilation date
124129
125130 int p,pdown;
126131 double Qobs;
127132 double t_observationsOFF=ALMOST_INF;// Only used for debugging - keep as ALMOST_INF otherwise
128133
129- int nn=(int )((tt.model_time +TIME_CORRECTION)/Options.timestep );// current timestep index
134+ int nn=(int )((tt.model_time +TIME_CORRECTION)/Options.timestep )+ 1 ;// end of timestep index
130135
131136 for (p=0 ; p<_nSubBasins; p++) {
132- _aDAlast [p]=_aDAscale[p];
137+ _aDAscale_last [p]=_aDAscale[p];
133138 }
134139
135140 for (int pp=_nSubBasins-1 ; pp>=0 ; pp--)// downstream to upstream
@@ -145,22 +150,24 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
145150 {
146151 if (IsContinuousFlowObs2 (_pObservedTS[i],_pSubBasins[p]->GetID ()))// flow observation is available and linked to this subbasin
147152 {
148- Qobs = _pObservedTS[i]->GetSampledValue (nn+ 1 ); // +1: correction for period ending storage of hydrograph
153+ Qobs = _pObservedTS[i]->GetSampledValue (nn); // end of timestep flow
149154
150155 // bool fakeblank=((tt.model_time>30) && (tt.model_time<40)) || ((tt.model_time>45) && (tt.model_time<47));//TMP DEBUG
151156 // if (fakeblank){Qobs=RAV_BLANK_DATA;}
152157
153158 if ((Qobs!=RAV_BLANK_DATA) && (tt.model_time <t_observationsOFF))
154159 {
155160 // _aDAscale[p] calculated live in AssimilationOverride when up-to-date modelled flow available
161+ // same with _aDAQadjust[p]
156162 _aDAlength [p]=0.0 ;
157163 _aDAtimesince[p]=0.0 ;
158164 _aDAoverride [p]=true ;
159165 _aDAobsQ [p]=Qobs;
160166 }
161167 else
162168 { // found a blank or zero flow value
163- _aDAscale [p]=_aDAscale[p];
169+ _aDAscale [p]=_aDAscale[p];// same adjustment as before - scaling persists
170+ _aDAQadjust [p]=_aDAQadjust[p];// same adjustment as before - flow magnitude persists
164171 _aDAtimesince[p]+=Options.timestep ;
165172 _aDAlength [p]=0.0 ;
166173 _aDAoverride [p]=false ;
@@ -178,12 +185,14 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
178185 // if ((pdown!=DOESNT_EXIST) && (!_aDAoverride[pdown])){ //alternate - allow information to pass through reservoirs
179186 if ((pdown!=DOESNT_EXIST) && (_pSubBasins[p]->GetReservoir ()==NULL ) && (!_aDAoverride[pdown])) {
180187 _aDAscale [p]= _aDAscale [pdown];
188+ _aDAQadjust [p]= _aDAQadjust [pdown] * (_pSubBasins[p]->GetDrainageArea () / _pSubBasins[pdown]->GetDrainageArea ());
181189 _aDAlength [p]+=_pSubBasins [pdown]->GetReachLength ();
182190 _aDAtimesince [p]= _aDAtimesince[pdown];
183191 _aDAoverride [p]=false ;
184192 }
185193 else { // Nothing downstream or reservoir present in this basin, no assimilation
186194 _aDAscale [p]=1.0 ;
195+ _aDAQadjust [p]=0.0 ;
187196 _aDAlength [p]=0.0 ;
188197 _aDAtimesince[p]=0.0 ;
189198 _aDAoverride [p]=false ;
@@ -197,6 +206,7 @@ void CModel::PrepareAssimilation(const optStruct &Options,const time_struct &tt)
197206 double distfact = _pGlobalParams->GetParams ()->assim_upstream_decay /M_PER_KM; // [1/km]->[1/m]
198207 for (p=0 ; p<_nSubBasins; p++)
199208 {
200- _aDAscale[p] =1.0 +(_aDAscale[p]-1.0 )*exp (-distfact*_aDAlength[p])*exp (-time_fact*_aDAtimesince[p]);
209+ _aDAscale [p] =1.0 +(_aDAscale[p]-1.0 )*exp (-distfact*_aDAlength[p])*exp (-time_fact*_aDAtimesince[p]);
210+ _aDAQadjust[p] =_aDAQadjust[p]*exp (-distfact*_aDAlength[p])*exp (-time_fact*_aDAtimesince[p]);
201211 }
202212}
0 commit comments