unit Ucalib;
{-------------------------------------------------------------------}
{ Unit: Ucalib.pas }
{ Project: EPA SWMM }
{ Version: 5.1 }
{ Date: 12/2/13 (5.1.000) }
{ 03/19/15 (5.1.008) }
{ Author: L. Rossman }
{ }
{ Delphi Pascal unit that retrieves a time series of measured }
{ observation data from a calibration file for use in a time }
{ series plot. }
{-------------------------------------------------------------------}
// Mapping of view variable indexes to calibration file +indexes:
// Variable Calibration File Index
// ------------ ----------------------
// Subcatchment RUNOFF 1
// Subcatchment SNOWDEPTH 10
// Subcatchment GW_FLOW 8
// Subcatchment GW_ELEV 9
// Subcatchment SUBCATCHQUAL 2
// Node NODEDEPTH 3
// Node LATFLOW 6
// Node OVERFLOW 7
// Node NODEQUAL 5
// Link FLOW 4
// Link DEPTH 11
// Link VELOCITY 12
interface
uses
Classes, SysUtils, TeEngine, Series, Chart, Uglobals, Uutils, Dialogs;
procedure GetCalibData(VarIndex: Integer; ObjType: Integer; LocID: String;
const aStartDate: TDateTime; const aEndDate: TDateTime;
const aTimeFactor: Double; const aDateTimeDisplay: Boolean;
ChartSeries: TChartSeries);
implementation
var
Toklist : TStringList;
StartDate: TDateTime;
EndDate : TDateTime;
TimeFactor: Double;
DateTimeDisplay: Boolean;
SimStartDate: TDateTime;
procedure GetCalibFileIndex(VarIndex: Integer; ObjType: Integer;
var FileIndex: Integer; var VarOffset: Integer);
begin
FileIndex := 0;
VarOffset := 0;
// Variable is for a subcatchment
if (ObjType = SUBCATCHMENTS) then
begin
if VarIndex = RUNOFF then FileIndex := 1;
if VarIndex = SNOWDEPTH then FileIndex := 10;
if VarIndex = GW_FLOW then FileIndex := 8;
if VarIndex = GW_ELEV then FileIndex := 9;
if VarIndex >= SUBCATCHQUAL then
begin
FileIndex := 2;
VarOffset := VarIndex - SUBCATCHQUAL;
end;
end
// Variable is for a node
else if (ObjType = NODES) then
begin
if VarIndex = NODEDEPTH then FileIndex := 3;
if VarIndex = LATFLOW then FileIndex := 6;
if VarIndex = OVERFLOW then FileIndex := 7;
if VarIndex >= NODEQUAL then
begin
FileIndex := 5;
VarOffset := VarIndex - NODEQUAL;
end;
end
// Variable is for a link
else if (ObjType = LINKS) then
begin
if VarIndex = FLOW then FileIndex := 4;
if VarIndex = LINKDEPTH then FileIndex := 11;
if VarIndex = VELOCITY then FileIndex := 12;
end;
end;
function AddCalibDataPoint(ChartSeries: TChartSeries; const DataTok: Integer): Boolean;
//-----------------------------------------------------------------------------
// Adds a calibration data value to the chart data series where
// DataTok = index of the token that contains the measurement value.
//-----------------------------------------------------------------------------
var
Value: Extended;
Days : Extended;
Hours: TDateTime;
X : TDateTime;
aDate: String;
begin
try
// Assume the data measurement time is a date/time value
// (If its not, an exception will occur which is handled below).
Result := False;
aDate := TokList[0];
Days := StrToDate(Uutils.ConvertDate(aDate), Uglobals.MyFormatSettings);
Hours := Uutils.StrHoursToTime(TokList[1]);
if Hours < 0 then Exit;
X := Days + Hours;
except
// An exception occurs if measurement time is actually elapsed days/hours
on EconvertError do
begin
Result := False;
if not Uutils.GetExtended(TokList[0], Days) then Exit;
Hours := Uutils.StrHoursToTime(TokList[1]);
if Hours < 0 then Exit;
// Adjust date to simulation start date.
X := SimStartDate + Days + Hours;
end;
end;
// Check that measurement time falls within plotting interval
if (X < StartDate) or (X > EndDate) then Exit;
// If the chart is not using date/time for X-axis,
// convert measurement time to elapsed time if need be
// Adjust date to simulation start date.
if not DateTimeDisplay then X := (X - SimStartDate)*TimeFactor;
Result := True;
// If the DataTok token contains a valid value then add
// that value and its time to the calibration point series
if Uutils.GetExtended(TokList[DataTok], Value)
then with ChartSeries as TPointSeries do AddXY(X, Value, '', clTeeColor);
end;
procedure GetCalibData(VarIndex: Integer; ObjType: Integer; LocID: String;
const aStartDate: TDateTime; const aEndDate: TDateTime;
const aTimeFactor: Double; const aDateTimeDisplay: Boolean;
ChartSeries: TChartSeries);
var
FileIndex: Integer; //Index of calibration file
VarOffset: Integer; //Offset of variable in file
P : Integer;
Ntoks : Integer;
DataTok : Integer;
UseData : Boolean;
F : TextFile;
Fname : String;
Line : String;
S : String;
begin
// Determine which calibration file corresponds to the variable of interest
GetCalibFileIndex(VarIndex, ObjType, FileIndex, VarOffset);
if FileIndex = 0 then Exit;
// Check if the calibration file for the variable of interest
// has data for the location of interest
if (Pos('"'+LocID+'"', CalibData[FileIndex].Locations) = 0) then Exit;
// Save shared variables
StartDate := aStartDate;
EndDate := aEndDate;
TimeFactor := aTimeFactor;
DateTimeDisplay := aDateTimeDisplay;
// Compute simulation start date which is one reporting
// period before the first reporting date.
SimStartDate := StartDateTime - DeltaDateTime;
//// Following code segment re-written for release 5.1.008. //// //(5.1.008)
// Try to open the calibration data file
Fname := CalibData[FileIndex].FileName;
if FileExists(Fname) then
try
// Create a list of string tokens
Toklist := TStringList.Create;
AssignFile(F,Fname);
{$I-}
Reset(F);
{$I+}
if IOResult = 0 then
begin
// Data token index is 2 + index of measurement variable
DataTok := 2 + VarOffset;
UseData := False;
// Read lines from file until reach end of file
while not EOF(F) do
begin
Readln(F, Line);
S := Line;
// Remove any comment & tokenize the line
P := Pos(';', S);
if (P > 0) then Delete(S, P, 256);
Uutils.Tokenize(S, Toklist, Ntoks);
// A single entry marks start of data for a new location.
// If this is the location of interest, set UseData to True
if (Ntoks = 1) then
begin
if (Toklist[0] = LocID) then
UseData := True
else
UseData := False;
end
// If line has enough items then add data point to data lists
else if (Ntoks > DataTok) and (UseData) then
begin
AddCalibDataPoint(ChartSeries, DataTok);
end;
end;
end;
// After finished reading the file, free the token list.
finally
Toklist.Free;
CloseFile(F);
end;
////////////////////////////////////////////////////////////////////////
end;
end.
{-------------------------------------------------------------------}
{ Unit: Ucalib.pas }
{ Project: EPA SWMM }
{ Version: 5.1 }
{ Date: 12/2/13 (5.1.000) }
{ 03/19/15 (5.1.008) }
{ Author: L. Rossman }
{ }
{ Delphi Pascal unit that retrieves a time series of measured }
{ observation data from a calibration file for use in a time }
{ series plot. }
{-------------------------------------------------------------------}
// Mapping of view variable indexes to calibration file +indexes:
// Variable Calibration File Index
// ------------ ----------------------
// Subcatchment RUNOFF 1
// Subcatchment SNOWDEPTH 10
// Subcatchment GW_FLOW 8
// Subcatchment GW_ELEV 9
// Subcatchment SUBCATCHQUAL 2
// Node NODEDEPTH 3
// Node LATFLOW 6
// Node OVERFLOW 7
// Node NODEQUAL 5
// Link FLOW 4
// Link DEPTH 11
// Link VELOCITY 12
interface
uses
Classes, SysUtils, TeEngine, Series, Chart, Uglobals, Uutils, Dialogs;
procedure GetCalibData(VarIndex: Integer; ObjType: Integer; LocID: String;
const aStartDate: TDateTime; const aEndDate: TDateTime;
const aTimeFactor: Double; const aDateTimeDisplay: Boolean;
ChartSeries: TChartSeries);
implementation
var
Toklist : TStringList;
StartDate: TDateTime;
EndDate : TDateTime;
TimeFactor: Double;
DateTimeDisplay: Boolean;
SimStartDate: TDateTime;
procedure GetCalibFileIndex(VarIndex: Integer; ObjType: Integer;
var FileIndex: Integer; var VarOffset: Integer);
begin
FileIndex := 0;
VarOffset := 0;
// Variable is for a subcatchment
if (ObjType = SUBCATCHMENTS) then
begin
if VarIndex = RUNOFF then FileIndex := 1;
if VarIndex = SNOWDEPTH then FileIndex := 10;
if VarIndex = GW_FLOW then FileIndex := 8;
if VarIndex = GW_ELEV then FileIndex := 9;
if VarIndex >= SUBCATCHQUAL then
begin
FileIndex := 2;
VarOffset := VarIndex - SUBCATCHQUAL;
end;
end
// Variable is for a node
else if (ObjType = NODES) then
begin
if VarIndex = NODEDEPTH then FileIndex := 3;
if VarIndex = LATFLOW then FileIndex := 6;
if VarIndex = OVERFLOW then FileIndex := 7;
if VarIndex >= NODEQUAL then
begin
FileIndex := 5;
VarOffset := VarIndex - NODEQUAL;
end;
end
// Variable is for a link
else if (ObjType = LINKS) then
begin
if VarIndex = FLOW then FileIndex := 4;
if VarIndex = LINKDEPTH then FileIndex := 11;
if VarIndex = VELOCITY then FileIndex := 12;
end;
end;
function AddCalibDataPoint(ChartSeries: TChartSeries; const DataTok: Integer): Boolean;
//-----------------------------------------------------------------------------
// Adds a calibration data value to the chart data series where
// DataTok = index of the token that contains the measurement value.
//-----------------------------------------------------------------------------
var
Value: Extended;
Days : Extended;
Hours: TDateTime;
X : TDateTime;
aDate: String;
begin
try
// Assume the data measurement time is a date/time value
// (If its not, an exception will occur which is handled below).
Result := False;
aDate := TokList[0];
Days := StrToDate(Uutils.ConvertDate(aDate), Uglobals.MyFormatSettings);
Hours := Uutils.StrHoursToTime(TokList[1]);
if Hours < 0 then Exit;
X := Days + Hours;
except
// An exception occurs if measurement time is actually elapsed days/hours
on EconvertError do
begin
Result := False;
if not Uutils.GetExtended(TokList[0], Days) then Exit;
Hours := Uutils.StrHoursToTime(TokList[1]);
if Hours < 0 then Exit;
// Adjust date to simulation start date.
X := SimStartDate + Days + Hours;
end;
end;
// Check that measurement time falls within plotting interval
if (X < StartDate) or (X > EndDate) then Exit;
// If the chart is not using date/time for X-axis,
// convert measurement time to elapsed time if need be
// Adjust date to simulation start date.
if not DateTimeDisplay then X := (X - SimStartDate)*TimeFactor;
Result := True;
// If the DataTok token contains a valid value then add
// that value and its time to the calibration point series
if Uutils.GetExtended(TokList[DataTok], Value)
then with ChartSeries as TPointSeries do AddXY(X, Value, '', clTeeColor);
end;
procedure GetCalibData(VarIndex: Integer; ObjType: Integer; LocID: String;
const aStartDate: TDateTime; const aEndDate: TDateTime;
const aTimeFactor: Double; const aDateTimeDisplay: Boolean;
ChartSeries: TChartSeries);
var
FileIndex: Integer; //Index of calibration file
VarOffset: Integer; //Offset of variable in file
P : Integer;
Ntoks : Integer;
DataTok : Integer;
UseData : Boolean;
F : TextFile;
Fname : String;
Line : String;
S : String;
begin
// Determine which calibration file corresponds to the variable of interest
GetCalibFileIndex(VarIndex, ObjType, FileIndex, VarOffset);
if FileIndex = 0 then Exit;
// Check if the calibration file for the variable of interest
// has data for the location of interest
if (Pos('"'+LocID+'"', CalibData[FileIndex].Locations) = 0) then Exit;
// Save shared variables
StartDate := aStartDate;
EndDate := aEndDate;
TimeFactor := aTimeFactor;
DateTimeDisplay := aDateTimeDisplay;
// Compute simulation start date which is one reporting
// period before the first reporting date.
SimStartDate := StartDateTime - DeltaDateTime;
//// Following code segment re-written for release 5.1.008. //// //(5.1.008)
// Try to open the calibration data file
Fname := CalibData[FileIndex].FileName;
if FileExists(Fname) then
try
// Create a list of string tokens
Toklist := TStringList.Create;
AssignFile(F,Fname);
{$I-}
Reset(F);
{$I+}
if IOResult = 0 then
begin
// Data token index is 2 + index of measurement variable
DataTok := 2 + VarOffset;
UseData := False;
// Read lines from file until reach end of file
while not EOF(F) do
begin
Readln(F, Line);
S := Line;
// Remove any comment & tokenize the line
P := Pos(';', S);
if (P > 0) then Delete(S, P, 256);
Uutils.Tokenize(S, Toklist, Ntoks);
// A single entry marks start of data for a new location.
// If this is the location of interest, set UseData to True
if (Ntoks = 1) then
begin
if (Toklist[0] = LocID) then
UseData := True
else
UseData := False;
end
// If line has enough items then add data point to data lists
else if (Ntoks > DataTok) and (UseData) then
begin
AddCalibDataPoint(ChartSeries, DataTok);
end;
end;
end;
// After finished reading the file, free the token list.
finally
Toklist.Free;
CloseFile(F);
end;
////////////////////////////////////////////////////////////////////////
end;
end.