Skip to content

Commit c4f291a

Browse files
James CraigJames Craig
authored andcommitted
v492b- proper diversion of delivered demand; FEWS revisions for management
support for return flow to other basin new routine ParseNetCDFManagementFile() (ParseFEWSRunInfo.cpp) new command :FEWSManagmentInfoFile (ParseInput.cpp;RavenInclude.h) support for :LookupTableFromCSV (ParseManagementFile.cpp) support for :DEclareWorkflowVariable (ParseManagemetnFile.cpp)
1 parent fd1f29e commit c4f291a

File tree

9 files changed

+221
-18
lines changed

9 files changed

+221
-18
lines changed

src/DemandExpressionHandling.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,21 @@ double CDemandOptimizer::GetWorkflowVariable(const string s, int &index) const
194194
}
195195
return RAV_BLANK_DATA;
196196
}
197+
//////////////////////////////////////////////////////////////////
198+
/// \brief retrieves workflow structure from list of workflow variables
199+
/// \params i [in] - index
197200

201+
/// \returns ith workflow variable
202+
//
203+
workflowVar* CDemandOptimizer::GetWorkflowVarStruct(int i) {
204+
return _pWorkflowVars[i];
205+
}
206+
workflowVar* CDemandOptimizer::GetWorkflowVarStruct(string s) {
207+
for (int i = 0; i < _nWorkflowVars; i++) {
208+
if (s==_pWorkflowVars[i]->name){ return _pWorkflowVars[i]; }
209+
}
210+
return NULL;
211+
}
198212
//////////////////////////////////////////////////////////////////
199213
/// \brief retrieves value of decision variable index
200214
/// \params s [in] - string

src/DemandOptimization.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,13 +367,13 @@ void CDemandOptimizer::AddUserConstant(const string name, const double& val)
367367
void CDemandOptimizer::AddWorkflowVariable(const workflowVar *pWV)
368368
{
369369
if (VariableNameExists(pWV->name)) {
370-
string warn="CDemandOptimizer::AddWorkflowVariable: variable name "+pWV->name+" is already in use.";
370+
string warn="CDemandOptimizer::AddWorkflowVariable: variable name "+pWV->name+" already exists.";
371371
ExitGracefully(warn.c_str(),BAD_DATA_WARN);
372372
}
373-
374-
if (!DynArrayAppend((void**&)(_pWorkflowVars),(void*)(pWV),_nWorkflowVars)){
375-
ExitGracefully("CDemandOptimizer::AddWorkflowVariable: adding NULL Workflow Variable",BAD_DATA);}
376-
373+
else{
374+
if (!DynArrayAppend((void**&)(_pWorkflowVars),(void*)(pWV),_nWorkflowVars)){
375+
ExitGracefully("CDemandOptimizer::AddWorkflowVariable: adding NULL Workflow Variable",BAD_DATA);}
376+
}
377377
}
378378
//////////////////////////////////////////////////////////////////
379379
/// \brief adds user time series

src/DemandOptimization.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ class CDemandOptimizer
283283
double GetUnitConversion (const string s) const;
284284
int GetUserDVIndex (const string s) const;
285285
double GetWorkflowVariable (const string s, int &index) const;
286+
workflowVar *GetWorkflowVarStruct (int index);
287+
workflowVar *GetWorkflowVarStruct (const string s);
286288
int GetNumUserDVs () const;
287289
int GetDebugLevel () const;
288290
int GetIndexFromDVString (string s) const;

src/ParseFEWSRunInfo.cpp

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,8 @@ bool ParseNetCDFStateFile(CModel *&pModel,const optStruct &Options)
548548
// .The state variable corresponding to the model start time will be used for initialization of flow/stage; all other values in the time vector are ignored
549549
// The naming convention of this attribute is one of: {QOUT, STAGE, }
550550
//
551-
bool ParseNetCDFFlowStateFile(CModel*& pModel,const optStruct& Options) {
551+
bool ParseNetCDFFlowStateFile(CModel*& pModel,const optStruct& Options)
552+
{
552553
if(Options.flowinfo_filename=="") { return true; }
553554

554555
#ifdef _RVNETCDF_
@@ -708,6 +709,106 @@ bool ParseNetCDFFlowStateFile(CModel*& pModel,const optStruct& Options) {
708709
#endif
709710
}
710711

712+
//////////////////////////////////////////////////////////////////
713+
/// \brief Parses Deltares FEWS Management Time series file
714+
///
715+
/// \param *&pModel [out] Reference to model object
716+
/// \param &Options [out] Global model options information
717+
/// \return True if operation is successful
718+
//
719+
// The management update file includes:
720+
// 1) 'time' dimensions
721+
// 2) One or more vectors of size[1:time]
722+
723+
// .The state variable corresponding to the model start time will be used for initialization of flow/stage; all other values in the time vector are ignored
724+
// The naming convention of each vector is : {UserTimeSeries_NAME}
725+
//
726+
bool ParseNetCDFManagementFile(CModel*& pModel,const optStruct& Options)
727+
{
728+
if(Options.maninfo_filename=="") { return true; }
729+
730+
#ifdef _RVNETCDF_
731+
int ncid; // NetCDF file id
732+
int retval; // return value of NetCDF routines
733+
int ntime = 0; // size of time vector
734+
int time_dimid; // dimension id of time variable
735+
int start_time_index=0; // index of NetCDF time array which corresponds to Raven start time
736+
737+
// Open file
738+
//====================================================================
739+
string manfile=Options.maninfo_filename;
740+
741+
if(Options.noisy) { cout<<"Opening management info file "<<manfile<<endl; }
742+
retval = nc_open(manfile.c_str(),NC_NOWRITE,&ncid);
743+
if(retval != 0) {
744+
string warn = "ParseNetCDFManagementFile: :ParseNetCDFManagementFile command: Cannot find file "+ manfile;
745+
ExitGracefully(warn.c_str(),BAD_DATA_WARN);
746+
return false;
747+
}
748+
HandleNetCDFErrors(retval);
749+
750+
// Get information from time vector
751+
//====================================================================
752+
GetNetCDFTimeInfo(ncid,time_dimid,ntime,start_time_index,Options);
753+
754+
if ((start_time_index < 0) || (start_time_index >= ntime))
755+
{
756+
time_struct tt;
757+
JulianConvert(0, Options.julian_start_day, Options.julian_start_year, Options.calendar, tt);
758+
string warn = "ParseNetCDFFlowStateFile: Model start time ("+tt.date_string+" "+ DecDaysToHours(Options.julian_start_day)+") does not occur during time window provided in NetCDF state update file";
759+
ExitGracefully(warn.c_str(), BAD_DATA);
760+
return false;
761+
}
762+
763+
// Get Names of all UserTimeSeries_ vectors in model
764+
//====================================================================
765+
int N=0;
766+
string *userTSnames;
767+
int nvars;
768+
char varname[NC_MAX_NAME];
769+
retval=nc_inq_nvars(ncid,&nvars);
770+
771+
userTSnames=new string [nvars];
772+
773+
for (int i = 0; i < nvars; i++) {
774+
retval=nc_inq_varname(ncid,i,varname);
775+
776+
userTSnames[N]=varname;
777+
778+
if (userTSnames[N].substr(0,15)=="UserTimeSeries_")
779+
{
780+
userTSnames[N]=userTSnames[N].substr(15,userTSnames[N].length());
781+
N++;
782+
}
783+
}
784+
785+
//close file
786+
//====================================================================
787+
retval = nc_close(ncid); HandleNetCDFErrors(retval);
788+
789+
//Read data and store as time series
790+
//====================================================================
791+
792+
CTimeSeries *pTS;
793+
for (int i=0;i<N;i++)
794+
{
795+
pTS=CTimeSeries::ReadTimeSeriesFromNetCDF(Options, userTSnames[i],
796+
DOESNT_EXIST, "none",false, true, //assumes period ending format
797+
manfile, "UserTimeSeries_"+userTSnames[i],
798+
"None", "time", //this assumes "time" is FEWS standard for time dimension
799+
0, 0.0, 1.0, 0.0);
800+
801+
pModel->GetManagementOptimizer()->AddUserTimeSeries(pTS);
802+
}
803+
delete [] userTSnames;
804+
805+
return true;
806+
#else
807+
ExitGracefully("ParseNetCDFFlowStateFile: Deltares FEWS State Update file can only be read using NetCDF version of Raven",BAD_DATA_WARN);
808+
return false;
809+
#endif
810+
}
811+
711812
//////////////////////////////////////////////////////////////////
712813
/// \brief Parses Deltares FEWS Parameter update file
713814
///

src/ParseInput.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ bool ParseMainInputFile (CModel *&pModel,
335335
Options.stateinfo_filename ="";
336336
Options.paraminfo_filename ="";
337337
Options.flowinfo_filename ="";
338+
Options.maninfo_filename ="";
338339

339340
Options.NetCDF_chunk_mem =10; //MB
340341

@@ -483,6 +484,7 @@ bool ParseMainInputFile (CModel *&pModel,
483484
else if (!strcmp(s[0],":FEWSStateInfoFile" )){code=110;}
484485
else if (!strcmp(s[0],":FEWSParamInfoFile" )){code=111;}
485486
else if (!strcmp(s[0],":FEWSBasinStateInfoFile" )){code=112;}
487+
else if (!strcmp(s[0],":FEWSManagmentInfoFile" )){code=113;}
486488

487489
else if (!strcmp(s[0],":WriteGroundwaterHeads" )){code=510;}//GWMIGRATE -TO REMOVE
488490
else if (!strcmp(s[0],":WriteGroundwaterFlows" )){code=511;}//GWMIGRATE -TO REMOVE
@@ -1929,6 +1931,12 @@ bool ParseMainInputFile (CModel *&pModel,
19291931
Options.flowinfo_filename = CorrectForRelativePath(s[1], Options.rvi_filename);//with .nc extension!
19301932
break;
19311933
}
1934+
case(113): //
1935+
{/*:FEWSManagmentInfoFile [filename.nc]*/
1936+
if (Options.noisy) { cout << "FEWS management info file" << endl; }
1937+
Options.maninfo_filename = CorrectForRelativePath(s[1], Options.rvi_filename);//with .nc extension!
1938+
break;
1939+
}
19321940
case(160): //--------------------------------------------
19331941
{/*:rvh_Filename [filename.rvh]*/
19341942
if(Options.noisy) { cout <<"rvh filename: "<<s[1]<<endl; }

src/ParseManagementFile.cpp

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,10 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
156156
else if(!strcmp(s[0],":DeclareDecisionVariable")) { code=24; }
157157
else if(!strcmp(s[0],":DefineWorkflowVariable")) { code=25; }
158158
else if(!strcmp(s[0],":WorkflowVarDefinition")) { code=26; }
159+
else if(!strcmp(s[0],":DeclareWorkflowVariable")) { code=27; }
159160
else if(!strcmp(s[0],":LookupTable")) { code=30; }
160161
else if(!strcmp(s[0],":OverrideStageDischargeCurve")) { code=31; }
162+
else if(!strcmp(s[0],":LookupTableFromCSV")) { code=32; }
161163

162164
else if(!strcmp(s[0],":LoopThrough")) { code=40; }
163165
else if(!strcmp(s[0],":EndLoopThrough")) { code=41; }
@@ -652,11 +654,17 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
652654
:Expression [name] = [expression]
653655
:EndWorkflowVarDefinition
654656
*/
655-
if(Options.noisy) { cout <<"Workflow Variable Definition Statement"<<endl; }
657+
if (Options.noisy) { cout << "Workflow Variable Definition Statement" << endl; }
656658

657-
workflowVar *pWV =new workflowVar();
658-
pWV->name=to_string(s[1]);
659-
pDO->AddWorkflowVariable(pWV);
659+
workflowVar* pWV;
660+
if (pDO->GetWorkflowVarStruct(to_string(s[1])) != NULL){//already declared
661+
pWV=pDO->GetWorkflowVarStruct(to_string(s[1]));
662+
}
663+
else{
664+
pWV= new workflowVar();
665+
pWV->name = to_string(s[1]);
666+
pDO->AddWorkflowVariable(pWV);
667+
}
660668

661669
expressionStruct *pExp;
662670
bool is_first=true;
@@ -749,6 +757,14 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
749757
}
750758
break;
751759
}
760+
case(27): //----------------------------------------------
761+
{ /*:DeclareWorkflowVariable [name]*/
762+
if(Options.noisy) { cout <<"Declare Workflow Variable"<<endl; }
763+
workflowVar *pWV=new workflowVar();
764+
pWV->name=to_string(s[1]);
765+
pDO->AddWorkflowVariable(pWV);
766+
break;
767+
}
752768
case(30): //----------------------------------------------
753769
{/*:LookupTable [name]
754770
N
@@ -807,6 +823,63 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
807823

808824
break;
809825
}
826+
case(32): //----------------------------------------------
827+
{/*:LookupTableFromCSV [name] [filename.csv]
828+
format:
829+
HeaderX, HeaderY
830+
x1, y1
831+
x2, y2
832+
...
833+
xN, yN
834+
(eof)
835+
*/
836+
if(Options.noisy) { cout <<"LookupTableFromCSV"<<endl; }
837+
838+
const int MAX_LOOKUP_TABLE=256;
839+
840+
int N;
841+
double *aX = new double[MAX_LOOKUP_TABLE];
842+
double *aY = new double[MAX_LOOKUP_TABLE];
843+
int line2(0);
844+
bool eof(false);
845+
string name = s[1];
846+
string filename="";
847+
for (int i=2;i<Len;i++){filename+=to_string(s[i]); }
848+
849+
ifstream LUCSV;
850+
LUCSV.open(filename.c_str());
851+
if (LUCSV.fail()){cout << "ERROR opening file: "<<filename<<endl; return false;}
852+
853+
CParser *ppCSV=new CParser(LUCSV,filename,line2);
854+
855+
ppCSV->Tokenize(s,Len); //headers
856+
857+
N=0;
858+
do {
859+
eof=ppCSV->Tokenize(s,Len);
860+
if(IsComment(s[0],Len)) { }
861+
else {
862+
if(Len>=2) {
863+
aX[N] = s_to_d(s[0]);
864+
aY[N] = s_to_d(s[1]);
865+
N++;
866+
}
867+
else {
868+
WriteWarning("Incorrect line length (<2) in :LookupTableFromCSV table",Options.noisy);
869+
break;
870+
}
871+
}
872+
} while (!eof);
873+
874+
LUCSV.close();
875+
876+
CLookupTable *pLUT = new CLookupTable(name,aX,aY,N);
877+
pDO->AddUserLookupTable(pLUT);
878+
delete [] aX;
879+
delete [] aY;
880+
break;
881+
}
882+
810883
case(40): //----------------------------------------------
811884
{ /*:LoopThrough [SB_GROUP or DEMAND_GROUP] [group name] */
812885
if(Options.noisy) { cout <<"Start Loop"<<endl; }
@@ -1021,9 +1094,12 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
10211094
{/*:ReturnDestination [SBID] */
10221095
if(Options.noisy) { cout <<"Return destination ID"<<endl; }
10231096
if (pDemand==NULL){
1024-
ExitGracefully(":ReturnTimeSeries must be between :WaterDemand and :EndWaterDemand commands.",BAD_DATA_WARN);
1097+
ExitGracefully(":ReturnDestination must be between :WaterDemand and :EndWaterDemand commands.",BAD_DATA_WARN);
10251098
}
10261099
else {
1100+
if (pModel->GetSubBasinByID(s_to_ll(s[1])) == NULL) {
1101+
ExitGracefully("ParseManagementFile: Bad subbasin ID supplied to :ReturnDestination command.",BAD_DATA_WARN);
1102+
}
10271103
pDemand->SetTargetSBID(s_to_ll(s[1]));
10281104
}
10291105
break;
@@ -1147,7 +1223,6 @@ bool ParseManagementFile(CModel *&pModel,const optStruct &Options)
11471223
string warn ="Invalid expression in :DemandExpression command at line " + pp->GetLineNumber();
11481224
WriteWarning(warn.c_str(),Options.noisy);
11491225
}
1150-
11511226
}
11521227
break;
11531228
}

src/RavenInclude.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*----------------------------------------------------------------
22
Raven Library Source Code
3-
Copyright (c) 2008-2024 the Raven Development Team
3+
Copyright (c) 2008-2025 the Raven Development Team
44
55
Includes declaration of global constants, enumerated types, and
66
shared common & hydrological functions
@@ -1069,6 +1069,7 @@ struct optStruct
10691069
string stateinfo_filename; ///< fully qualified filename of state_mods.nc file from FEWS
10701070
string flowinfo_filename; ///< fully qualified filename of flowstate_mods.nc file from FEWS
10711071
string paraminfo_filename; ///< fully qualified filename of param_mods.nc file from FEWS
1072+
string maninfo_filename; ///< fully qualified filename of managment.nc file from FEWS
10721073
string warm_ensemble_run; ///< run name prefix in warm ensemble solution files
10731074

10741075
string main_output_dir; ///< primary output directory (RavenErrors.txt, =output_dir for non-ensemble)

src/TimeSeries.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ CTimeSeries **CTimeSeries::ParseEnsimTb0(string filename, int &nTS, forcing_type
13551355
/// \param loc_ID [in] location information about timeseries, e.g. subbasin ID or HRU ID
13561356
/// \param FileNameNC [in] file name of NetCDF
13571357
/// \param VarNameNC [in] name of variable in NetCDF
1358-
/// \param DimNamesNC_stations [in] name of station dimension (optional; default=None)
1358+
/// \param DimNamesNC_stations [in] name of station dimension (optional; default="None")
13591359
/// \param DimNamesNC_time [in] name of time dimension (mandatory)
13601360
/// \param StationIdx [in] idx of station to be read (or -1 if to be determined from FEWS station_id variable via FROM_STATION_VAR) (only used if DimNamesNC:stations not None)
13611361
/// \param TimeShift [in] time shift of data (fractional day by which read data should be shifted)
@@ -1364,7 +1364,9 @@ CTimeSeries **CTimeSeries::ParseEnsimTb0(string filename, int &nTS, forcing_type
13641364
/// \return array (size nTS) of pointers to time series
13651365
//
13661366
CTimeSeries *CTimeSeries::ReadTimeSeriesFromNetCDF(const optStruct &Options, string name,
1367-
long long loc_ID, string gauge_name,bool shift_to_per_ending, bool shift_from_per_ending, string FileNameNC, string VarNameNC,
1367+
long long loc_ID, string gauge_name,
1368+
bool shift_to_per_ending, bool shift_from_per_ending,
1369+
string FileNameNC, string VarNameNC,
13681370
string DimNamesNC_stations, string DimNamesNC_time,
13691371
int StationIdx, double TimeShift, double LinTrans_a, double LinTrans_b)
13701372
{
@@ -1671,7 +1673,7 @@ CTimeSeries *CTimeSeries::ReadTimeSeriesFromNetCDF(const optStruct &Options, str
16711673
retval=nc_get_vars_double(ncid,varid_f,nc_start,nc_length,nc_stride,&aTmp2D[0][0]); HandleNetCDFErrors(retval);
16721674
}
16731675
if (Options.noisy) {
1674-
cout<<" CForcingGrid::ReadTimeSeriesFromNetCDF - !none"<<endl;
1676+
cout<<" CTimeSeries::ReadTimeSeriesFromNetCDF - !none"<<endl;
16751677
printf(" Dim of chunk read: dim1 = %i dim2 = %i\n",dim1,dim2);
16761678
printf(" start chunk: (%zu, %zu)\n", nc_start[0], nc_start[1]);
16771679
printf(" length chunk: (%zu, %zu)\n", nc_length[0],nc_length[1]);
@@ -1688,7 +1690,7 @@ CTimeSeries *CTimeSeries::ReadTimeSeriesFromNetCDF(const optStruct &Options, str
16881690
nc_start [0] = 0; nc_length[0] = (size_t)(ntime); nc_stride[0] = 1;
16891691
retval=nc_get_vars_double(ncid,varid_f,nc_start,nc_length,nc_stride,&aTmp1D[0]); HandleNetCDFErrors(retval);
16901692
if (Options.noisy) {
1691-
cout<<" CForcingGrid::ReadTimeSeriesFromNetCDF - none"<<endl;
1693+
cout<<" CTimeSeries::ReadTimeSeriesFromNetCDF - none"<<endl;
16921694
printf(" Dim of chunk read: dim1 = %i \n",dim1);
16931695
printf(" start chunk: (%zu)\n", nc_start[0]);
16941696
printf(" length chunk: (%zu)\n", nc_length[0]);

src/WaterDemands.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ string CDemand::GetName() const
6565
}
6666
int CDemand::GetGlobalIndex() const
6767
{
68-
ExitGracefullyIf(_global_index==DOESNT_EXIST,"CDemand::GetLocalIndex(): didnt set local index",RUNTIME_ERR);
68+
ExitGracefullyIf(_global_index==DOESNT_EXIST,"CDemand::GetGlobalIndex(): didnt set global index",RUNTIME_ERR);
6969
return _global_index; //d
7070
}
7171
int CDemand::GetLocalIndex() const

0 commit comments

Comments
 (0)