Skip to content

Commit bb7add5

Browse files
James CraigJames Craig
authored andcommitted
v524 - EnKF random number generator bug fix
bug fix to GaussRandom() in ModelEnsemble.cpp - had one in 33,000 chance of throwing a -inf
1 parent c7ba819 commit bb7add5

File tree

7 files changed

+80
-57
lines changed

7 files changed

+80
-57
lines changed

src/EnKF.cpp

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ EnKF_mode CEnKFEnsemble::GetEnKFMode() const
188188

189189
//////////////////////////////////////////////////////////////////
190190
/// \brief initializes EnKF assimilation run
191+
/// - performs QA/QC on inputs
192+
/// - gets #s and names of state variables adjusted during assimilation
193+
/// - allocate & populate _output_matrix, _obs_matrix, _noise_matrix
194+
/// - open blank EnKFOutput.csv file
191195
/// \param &Options [out] Global model options information
192196
//
193197
void CEnKFEnsemble::Initialize(const CModel* pModel,const optStruct &Options)
@@ -197,8 +201,8 @@ void CEnKFEnsemble::Initialize(const CModel* pModel,const optStruct &Options)
197201

198202
// QA/QC
199203
//-----------------------------------------------
200-
if(_nMembers==0) {
201-
ExitGracefully("CEnKFEnsemble::Initialize: number of EnKF ensemble members must be >0",BAD_DATA);
204+
if(_nMembers<=1) {
205+
ExitGracefully("CEnKFEnsemble::Initialize: number of EnKF ensemble members must be >1",BAD_DATA);
202206
}
203207
if ((pModel->GetNumForcingPerturbations() == 0) && (_EnKF_mode != ENKF_FORECAST) && (_EnKF_mode != ENKF_OPEN_FORECAST)) {
204208
ExitGracefully("CEnKFEnsemble::Initialize: at least one forcing perturbation must be set using :ForcingPerturbation command",BAD_DATA);
@@ -358,7 +362,7 @@ void CEnKFEnsemble::Initialize(const CModel* pModel,const optStruct &Options)
358362
ExitGracefullyIf(_noise_matrix[e]==NULL,"EnKF Initialization: noise matrix",OUT_OF_MEMORY);
359363
}
360364

361-
//populate _output_matrix, _obs_matrix
365+
//populate _output_matrix, _obs_matrix, _noise_matrix
362366
//-----------------------------------------------
363367
int j;
364368
double eps;
@@ -427,7 +431,7 @@ void CEnKFEnsemble::StartTimeStepOps(CModel* pModel,optStruct& Options,const tim
427431
}
428432
}
429433
//////////////////////////////////////////////////////////////////
430-
/// \brief called at end of each time step
434+
/// \brief called at end of each time step - updates state matrix and builds output matrix
431435
/// \param pModel [out] pointer to global model instance
432436
/// \param &Options [out] Global model options information
433437
/// \params tt [in] time structure
@@ -439,7 +443,7 @@ void CEnKFEnsemble::CloseTimeStepOps(CModel* pModel,optStruct& Options,const tim
439443
AddToStateMatrix(pModel,Options,e);
440444
}
441445

442-
//Build output Matrix
446+
//Build output Matrix (typically final timestep of simulation)
443447
//----------------------------------------------------------
444448
int curr_nn=(int)((tt.model_time+TIME_CORRECTION)/Options.timestep);//current timestep index
445449

@@ -680,7 +684,7 @@ void CEnKFEnsemble::AddToStateMatrix(CModel* pModel,optStruct& Options,const int
680684
for(int i=0;i<_nAssimStates;i++)
681685
{
682686
kk=_aAssimGroupID[i];
683-
if(_aAssimStates[i]==STREAMFLOW)
687+
if (_aAssimStates[i]==STREAMFLOW)
684688
{
685689
//cout<<"RETRIEVE STATES : # subbasins: "<<pModel->GetSubBasinGroup(kk)->GetNumSubbasins()<<endl;
686690
for(int pp=0;pp<pModel->GetSubBasinGroup(kk)->GetNumSubbasins();pp++)
@@ -808,62 +812,66 @@ void CEnKFEnsemble::FinishEnsembleRun(CModel *pModel,optStruct &Options,const ti
808812

809813
if(e==_nEnKFMembers-1) //After all ensemble members have run
810814
{
811-
_ENKFOUT<<"PRE-ASSIMILATION STATE MATRIX:"<<endl;
812-
_ENKFOUT<<"member"<<",";
813-
for (int i = 0; i<_nStateVars; i++) {
814-
_ENKFOUT<<_state_names[i]<<",";
815-
}
816-
_ENKFOUT<<endl;
817-
for(int ee=0;ee<_nEnKFMembers;ee++) {
818-
_ENKFOUT<<ee+1<<",";
819-
for(int i=0;i<_nStateVars;i++) {
820-
_ENKFOUT<<_state_matrix[ee][i]<<",";
815+
{
816+
_ENKFOUT<<"PRE-ASSIMILATION STATE MATRIX:"<<endl;
817+
_ENKFOUT<<"member"<<",";
818+
for (int i = 0; i<_nStateVars; i++) {
819+
_ENKFOUT<<_state_names[i]<<",";
821820
}
822821
_ENKFOUT<<endl;
822+
for(int ee=0;ee<_nEnKFMembers;ee++) {
823+
_ENKFOUT<<ee+1<<",";
824+
for(int i=0;i<_nStateVars;i++) {
825+
_ENKFOUT<<_state_matrix[ee][i]<<",";
826+
}
827+
_ENKFOUT<<endl;
828+
}
823829
}
824830

825831
cout<<endl<<"ENKF: Performing Assimilation Calculations with "<<_nObsDatapoints<<" observation datapoints..."<<endl;
826832
AssimilationCalcs();
827833

828-
_ENKFOUT<<"POST-ASSIMILATION STATE MATRIX:"<<endl;
829-
_ENKFOUT<<"member"<<",";
830-
for (int i = 0; i<_nStateVars; i++) {
831-
_ENKFOUT<<_state_names[i]<<",";
832-
}
833-
_ENKFOUT<<endl;
834-
for(int ee=0;ee<_nEnKFMembers;ee++) {
835-
_ENKFOUT<<ee+1<<",";
836-
for(int i=0;i<_nStateVars;i++) {
837-
_ENKFOUT<<_state_matrix[ee][i]<<",";
834+
{
835+
_ENKFOUT<<"POST-ASSIMILATION STATE MATRIX:"<<endl;
836+
_ENKFOUT<<"member"<<",";
837+
for (int i = 0; i<_nStateVars; i++) {
838+
_ENKFOUT<<_state_names[i]<<",";
838839
}
839840
_ENKFOUT<<endl;
840-
}
841+
for(int ee=0;ee<_nEnKFMembers;ee++) {
842+
_ENKFOUT<<ee+1<<",";
843+
for(int i=0;i<_nStateVars;i++) {
844+
_ENKFOUT<<_state_matrix[ee][i]<<",";
845+
}
846+
_ENKFOUT<<endl;
847+
}
841848

842-
_ENKFOUT<<"NOISE MATRIX:"<<endl;
843-
for(int ee=0;ee<_nEnKFMembers;ee++) {
844-
_ENKFOUT<<ee+1<<",";
845-
for(int i=0;i<_nObsDatapoints;i++) {
846-
_ENKFOUT<<_noise_matrix[ee][i]<<",";
849+
_ENKFOUT<<"NOISE MATRIX:"<<endl;
850+
for(int ee=0;ee<_nEnKFMembers;ee++) {
851+
_ENKFOUT<<ee+1<<",";
852+
for(int i=0;i<_nObsDatapoints;i++) {
853+
_ENKFOUT<<_noise_matrix[ee][i]<<",";
854+
}
855+
_ENKFOUT<<endl;
847856
}
848-
_ENKFOUT<<endl;
849-
}
850-
_ENKFOUT<<"OBSERVATION MATRIX:"<<endl;
851-
for(int ee=0;ee<_nEnKFMembers;ee++) {
852-
_ENKFOUT<<ee+1<<",";
853-
for(int i=0;i<_nObsDatapoints;i++) {
854-
_ENKFOUT<<_obs_matrix[ee][i]<<",";
857+
_ENKFOUT<<"OBSERVATION MATRIX:"<<endl;
858+
for(int ee=0;ee<_nEnKFMembers;ee++) {
859+
_ENKFOUT<<ee+1<<",";
860+
for(int i=0;i<_nObsDatapoints;i++) {
861+
_ENKFOUT<<_obs_matrix[ee][i]<<",";
862+
}
863+
_ENKFOUT<<endl;
855864
}
856-
_ENKFOUT<<endl;
857-
}
858-
_ENKFOUT<<"SIMULATED OUTPUT MATRIX:"<<endl;
859-
for(int ee=0;ee<_nEnKFMembers;ee++) {
860-
_ENKFOUT<<ee+1<<",";
861-
for(int i=0;i<_nObsDatapoints;i++) {
862-
_ENKFOUT<<_output_matrix[ee][i]<<",";
865+
_ENKFOUT<<"SIMULATED OUTPUT MATRIX:"<<endl;
866+
for(int ee=0;ee<_nEnKFMembers;ee++) {
867+
_ENKFOUT<<ee+1<<",";
868+
for(int i=0;i<_nObsDatapoints;i++) {
869+
_ENKFOUT<<_output_matrix[ee][i]<<",";
870+
}
871+
_ENKFOUT<<endl;
863872
}
864-
_ENKFOUT<<endl;
873+
_ENKFOUT.close();
865874
}
866-
_ENKFOUT.close();
867875

868876
//Write EnKF-updated solution files
869877
// requires full re-reading of ensemble member solution files

src/Model.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2726,15 +2726,17 @@ void CModel::RecalculateHRUDerivedParams(const optStruct &Options,
27262726
//
27272727
void CModel::PrepareForcingPerturbation(const optStruct &Options, const time_struct &tt)
27282728
{
2729+
if (_nPerturbations==0){return;}
2730+
2731+
double partday = Options.julian_start_day-floor(Options.julian_start_day+TIME_CORRECTION);
2732+
int nn = (int)(rvn_round((tt.model_time+partday-floor(tt.model_time+partday+TIME_CORRECTION))/Options.timestep));
2733+
bool start_of_day = ((nn==0) || tt.day_changed); //nn==0 corresponds to midnight
27292734

2730-
for(int i=0;i<_nPerturbations;i++)
2731-
{
2735+
if (start_of_day) { //get all random perturbation samples for the day
27322736
int nStepsPerDay = (int)(rvn_round(1.0/Options.timestep));
2733-
double partday = Options.julian_start_day-floor(Options.julian_start_day+TIME_CORRECTION);
2734-
int nn = (int)(rvn_round((tt.model_time+partday-floor(tt.model_time+partday+TIME_CORRECTION))/Options.timestep));
2735-
bool start_of_day = ((nn==0) || tt.day_changed); //nn==0 corresponds to midnight
27362737

2737-
if (start_of_day) { //get all random perturbation samples for the day
2738+
for(int i=0;i<_nPerturbations;i++)
2739+
{
27382740
for (int n=0;n<nStepsPerDay;n++){
27392741
_pPerturbations[i]->eps[n]=SampleFromDistribution(_pPerturbations[i]->distribution,_pPerturbations[i]->distpar);
27402742
}

src/ModelEnsemble.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ double UniformRandom()
2323
//
2424
double GaussRandom()
2525
{
26-
double u1=(double)(rand())/RAND_MAX;
26+
double u1=(double)(rand()+1)/(RAND_MAX+1.0); //avoid zero
2727
double u2=(double)(rand())/RAND_MAX;
2828
return sqrt(-2.0*log(u1))*cos(2.0*PI*u2);
2929
}

src/ParseInput.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3619,6 +3619,8 @@ bool ParseMainInputFile (CModel *&pModel,
36193619
"ParseMainInputFile::Must have a postitive time step",BAD_DATA);
36203620
ExitGracefullyIf(Options.duration<0,
36213621
"ParseMainInputFile::Model duration less than zero. Make sure :EndDate is after :StartDate.",BAD_DATA_WARN);
3622+
ExitGracefullyIf(Options.julian_start_year==1666,
3623+
"ParseMainInputFile:: no :StartDate supplied in .rvi or runinfo.nc file.",BAD_DATA_WARN);
36223624

36233625
if((Options.nNetCDFattribs>0) && (Options.output_format!=OUTPUT_NETCDF)){
36243626
WriteAdvisory("ParseMainInputFile: NetCDF attributes were specified but output format is not NetCDF.",Options.noisy);

src/RavenMain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ int main(int argc, char* argv[])
189189
}
190190

191191
//////////////////////////////////////////////////////////////////
192-
/// \param argc [in] number of arguments to executable
192+
/// \param argc [in] number of command line arguments to executable
193193
/// \param argv[] [in] executable arguments; Raven.exe [filebase] [-p rvp_file] [-h hru_file] [-t rvt_file] [-c rvc_file] [-o output_dir]
194194
/// \details initializes input files and output directory
195195
/// \details filebase has no extension, all others require .rv* extension

src/UnitTesting.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void RavenUnitTesting(const optStruct &Options)
3636
//TestWetBulbTemps();
3737
//TestDateStrings();
3838
//IncGammaLimit();
39+
//TestRandomSampling();
3940
}
4041
/////////////////////////////////////////////////////////////////
4142
/// \brief Tests DateStringToTimeStruct() function
@@ -614,4 +615,13 @@ void IncGammaLimit() {
614615
cout<<x<<" "<<IncompleteGamma(xx,1.0)<<" "<<IncompleteGamma(xx,2.0)<<" "<<IncompleteGamma(xx,3.0)<<" "<<IncompleteGamma(xx,4.0)<<" "<<IncompleteGamma(xx,5.0)<<endl;
615616
}
616617
ExitGracefully("UnitTesting:: IncGammaLimit",SIMULATION_DONE);
617-
}
618+
}
619+
double GaussRandom();
620+
void TestRandomSampling() {
621+
ofstream TEST;
622+
TEST.open("GaussSample.csv");
623+
for(int m=0; m<10000;m++) {
624+
TEST<<GaussRandom()<<endl;
625+
}
626+
ExitGracefully("UnitTesting:: TestRandomSampling",SIMULATION_DONE);
627+
}

src/UnitTesting.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ void TestGammaSampling();
2626
void TestWetBulbTemps();
2727
void TestDateStrings();
2828
void IncGammaLimit();
29+
void TestRandomSampling();
2930
#endif

0 commit comments

Comments
 (0)