Autodesk Technologist with Information about Stormwater Management Model (SWMM) for watershed water quality, hydrology and hydraulics modelers (Note this blog is not associated with the EPA). You will find Blog Posts on the Subjects of SWMM5, ICM SWMM, ICM InfoWorks, InfoSWMM and InfoSewer.
Saturday, August 26, 2017
Steps for Running RDII Analyst in H2OMap SWMM
Sunday, August 20, 2017
Runoff Surface Suggestions for Future #SWMM5 's and #SWMM6 - with added Emojis
Expanding Runoff Surface Types for Upcoming SWMM Versions 💧🌍🌆🌦
The Storm Water Management Model (SWMM) has been an instrumental tool in simulating urban hydrological processes. Over the years, SWMM has evolved, adding new features and capabilities 🚀. One area ripe for expansion is the classification of runoff surfaces 🌿🌃.
Current Runoff Surfaces in SWMM:
- Impervious with Depression Storage 🏢: Accounts for evaporation ☁ but not infiltration 🕳.
- Pervious 🌱: Considers depression storage, evaporation, infiltration, and potentially groundwater connection 🌊.
- Impervious without Depression Storage 🛣: Represents quick runoff from surfaces like roofs and gutters.
Enhancements in SWMM4 and SWMM5 introduced more intricate routing capabilities 🌐 and the integration of Low Impact Development (LID) methodologies 🌳🌼.
Proposed Enhancements for Future SWMM Iterations 🌟:
To reflect the complexity of urban terrains more accurately, there's a proposal to expand the number of runoff surfaces from the current 3 to a more comprehensive 12 📊. Each of these surfaces should have customizable properties, such as:
- Flag for depression storage 🚩.
- Flag for evaporation 🌬.
- Flag for infiltration 🌀.
- Flag for groundwater connection 🌍💧.
- Flag for RDII (Rainfall-Dependent Infiltration/Inflow) 🌧⚡.
- Flag for LID integration 🌸🏞.
- Customizable widths and slopes 📏📐.
The existing SWMM framework provides a single slope and width for various runoff surfaces, which doesn't always mirror real-world scenarios. By allowing each surface to have distinct characteristics, it could enhance the model's accuracy and simplify the calibration process 🎯📉.
Technical Implications ⚙🖥:
Implementing these changes would entail:
- Adapting the SWMM 5 file import process to accommodate the expanded surfaces 📂.
- Modifying the Enums.h file to account for the new SubAreaType classifications 📑.
- Adjusting the runoff linkages in various modules, including Subcatch.C, RDII.C, Gwater.C, and LID.C 🔄🔧.
cenum SubAreaType {
IMPERV0, // impervious surface without depression storage
IMPERV1, // impervious surface with depression storage
PERV // pervious surface
// ... Additional surfaces can be added here
};
While these enhancements would certainly increase the model's complexity, the benefits in terms of accuracy and representation of real-world conditions could be invaluable for urban hydrologists and planners 🌆🌍🌧🌳.
Wednesday, August 16, 2017
#SWMM 5 LID 185 message
Monday, August 7, 2017
EPA is happy to announce the publication of Volume II of the #SWMM Reference Manual (Hydraulics)
EPA is happy to announce the publication of Volume II of the SWMM Reference Manual (Hydraulics). It can be viewed and downloaded from the EPA SWMM web page:
https://www.epa.gov/water-
This completes the full set of reference manuals for SWMM 5 that also includes Volume I (Hydrology) and Volume III (Water Quality and LID). We hope that these manuals allow SWMM users to gain a better understanding of the computational methods and techniques used by the program.
These volumes were completed by Dr. Lewis A. Rossman, EPA Emeritus. In his extraordinary career, he has written three remarkable EPA public domain programs: SWMM, the National Stormwater Calculator (https://www.epa.gov/water-
Thanks, Lew, and thanks to all of you for your continued interest and support of SWMM.
Michelle Simon. Ph.D., P.E.
EPA Office of Research and Development
Water Systems Division
Associate Director of Science
Cincinnati, OH 45268
Sunday, July 30, 2017
This is how node interface files works in #SWMM5, Caveats and Tips
Wednesday, July 26, 2017
A Visual Studio Compiler for #SWMM5 Note
Figure 1. DLL Properties/General/Output file change the SWMM5.DLL creation directory |
Figure 2. Visual Studio project files from the default SWMM5 names to a more meaningful version name |
Sunday, July 23, 2017
#SWMM5 - Delphi Pascal unit that imports a SWMM project's data from a formatted text file
{-------------------------------------------------------------------}
{ Unit: Uimport.pas }
{ Project: EPA SWMM }
{ Version: 5.1 }
{ Date: 12/02/13 (5.1.001) }
{ 04/04/14 (5.1.003) }
{ 04/14/14 (5.1.004) }
{ 09/15/14 (5.1.007) }
{ 03/19/15 (5.1.008) }
{ 08/05/15 (5.1.010) }
{ 08/01/16 (5.1.011) }
{ Author: L. Rossman }
{ }
{ Delphi Pascal unit that imports a SWMM project's data from a }
{ a formatted text file. }
{ }
{ 5.1.011 - Support for reading [EVENTS] section added. }
{-------------------------------------------------------------------}
interface
uses
Classes, Forms, Controls, Dialogs, SysUtils, Windows, Math, StrUtils,
Uutils, Uglobals;
const
ITEMS_ERR = 1;
KEYWORD_ERR = 2;
SUBCATCH_ERR = 3;
NODE_ERR = 4;
LINK_ERR = 5;
LANDUSE_ERR = 6;
POLLUT_ERR = 7;
NUMBER_ERR = 8;
XSECT_ERR = 9;
TRANSECT_ERR = 10;
TIMESTEP_ERR = 11;
DATE_ERR = 12;
LID_ERR = 13;
MAX_ERRORS = 50;
type
TFileType = (ftInput, ftImport);
// These routines can be called from other units
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
function OpenProject(const Fname: String): TInputFileType;
function ReadInpFile(const Fname: String):Boolean;
procedure SetDefaultDates;
implementation
uses
Fmain, Fmap, Fstatus, Dxsect, Uexport, Uinifile, Uproject, Umap,
Ucoords, Uvertex, Uupdate, Dreporting, Ulid;
const
MSG_READING_PROJECT_DATA = 'Reading project data... ';
TXT_ERROR = 'Error ';
TXT_AT_LINE = ' at line ';
TXT_MORE_ERRORS = ' more errors found in file.';
TXT_ERROR_REPORT = 'Error Report for File ';
SectionWords : array[0..54] of PChar = //(5.1.011)
('[TITLE', //0
'[OPTION', //1
'[RAINGAGE', //2
'[HYDROGRAPH', //3
'[EVAPORATION', //4
'[SUBCATCHMENT', //5
'[SUBAREA', //6
'[INFILTRATION', //7
'[AQUIFER', //8
'[GROUNDWATER', //9
'[JUNCTION', //10
'[OUTFALL', //11
'[STORAGE', //12
'[DIVIDER', //13
'[CONDUIT', //14
'[PUMP', //15
'[ORIFICE', //16
'[WEIR', //17
'[OUTLET', //18
'[XSECTION', //19
'[TRANSECT', //20
'[LOSS', //21
'[CONTROL', //22
'[POLLUTANT', //23
'[LANDUSE', //24
'[BUILDUP', //25
'[WASHOFF', //26
'[COVERAGE', //27
'[INFLOW', //28
'[DWF', //29
'[PATTERN', //30
'[RDII', //31
'[LOAD', //32
'[CURVE', //33
'[TIMESERIES', //34
'[REPORT', //35
'[FILE', //36
'[MAP', //37
'[COORDINATES', //38
'[VERTICES', //39
'[POLYGONS', //40
'[SYMBOLS', //41
'[LABELS', //42
'[BACKDROP', //43
'[PROFILE', //44
'[TABLE', //45
'[TEMPERATURE', //46
'[SNOWPACK', //47
'[TREATMENT', //48
'[TAG', //49
'[LID_CONTROL', //50
'[LID_USAGE', //51
'[GWF', //52 //(5.1.007)
'[ADJUSTMENTS', //53 //(5.1.007)
'[EVENT'); //54 //(5.1.011)
var
FileType : TFileType;
InpFile : String;
ErrList : TStringlist;
SubcatchList : TStringlist;
NodeList : TStringlist;
LinkList : TStringlist;
TokList : TStringlist;
Ntoks : Integer;
Section : Integer;
LineCount : LongInt;
ErrCount : LongInt;
Line : String;
Comment : String;
TsectComment : String;
PrevID : String;
PrevIndex : Integer;
CurveType : Integer;
MapExtentSet : Boolean;
ManningsN : array[1..3] of String;
// These are deprecated attributes of a backdrop image
BackdropX : Extended;
BackdropY : Extended;
BackdropW : Extended;
BackdropH : Extended;
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
//-----------------------------------------------------------------------------
// Adds an error message for a specific error code to the list
// of errors encountered when reading an input file.
//-----------------------------------------------------------------------------
var
S: String;
begin
if ErrCount <= MAX_ERRORS then
begin
case ErrCode of
ITEMS_ERR: S := 'Too few items ';
KEYWORD_ERR: S := 'Unrecognized keyword (' + Name + ') ';
SUBCATCH_ERR: S := 'Undefined Subcatchment (' + Name + ') referenced ';
NODE_ERR: S := 'Undefined Node (' + Name + ') referenced ';
LINK_ERR: S := 'Undefined Link (' + Name + ') referenced ';
LANDUSE_ERR: S := 'Undefined Land Use (' + Name + ') referenced ';
POLLUT_ERR: S := 'Undefined Pollutant (' + Name + ') referenced ';
NUMBER_ERR: S := 'Illegal numeric value (' + Name + ') ';
XSECT_ERR: S := 'Illegal cross section for Link ' + Name + ' ';
TRANSECT_ERR: S := 'No Transect defined for these data ';
TIMESTEP_ERR: S := 'Illegal time step value ';
DATE_ERR: S := 'Illegal date/time value ';
LID_ERR: S := 'Undefined LID process (' + Name + ') referenced ';
else S := 'Unknown error ';
end;
S := S + 'at line ' + IntToStr(LineCount) + ':';
ErrList.Add(S);
if Section >= 0 then ErrList.Add(SectionWords[Section] + ']');
ErrList.Add(Line);
ErrList.Add('');
end;
Result := ErrCode;
end;
function FindSubcatch(const ID: String): TSubcatch;
//-----------------------------------------------------------------------------
// Finds a Subcatchment object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Atype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if SubcatchList.Find(ID, Index)
then Result := TSubcatch(SubcatchList.Objects[Index]);
end
else
begin
if (Project.FindSubcatch(ID, Atype, Index))
then Result := Project.GetSubcatch(Atype, Index);
end;
end;
function FindNode(const ID: String): TNode;
//-----------------------------------------------------------------------------
// Finds a Node object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Ntype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if NodeList.Find(ID, Index)
then Result := TNode(NodeList.Objects[Index]);
end
else
begin
if (Project.FindNode(ID, Ntype, Index))
then Result := Project.GetNode(Ntype, Index);
end;
end;
function FindLink(const ID: String): TLink;
//-----------------------------------------------------------------------------
// Finds a Link object given its ID name.
//-----------------------------------------------------------------------------
var
Index : Integer;
Ltype : Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if LinkList.Find(ID, Index)
then Result := TLink(LinkList.Objects[Index]);
end
else
begin
if (Project.FindLink(ID, Ltype, Index))
then Result := Project.GetLink(Ltype, Index);
end;
end;
function ReadTitleData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Adds Line of text to a project's title and notes.
//-----------------------------------------------------------------------------
begin
if Project.Lists[NOTES].Count = 0 then Project.Title := Line;
Project.Lists[NOTES].Add(Line);
Project.HasItems[NOTES] := True;
Result := 0;
end;
procedure ReadOldRaingageData(I: Integer; aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of parsed rain gage data using older format.
//-----------------------------------------------------------------------------
begin
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 2 then aGage.Data[GAGE_SERIES_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_DATA_FORMAT] := TokList[3];
if Ntoks > 4 then aGage.Data[GAGE_DATA_FREQ] := TokList[4];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 2 then aGage.Data[GAGE_FILE_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_STATION_NUM] := TokList[3];
end;
end;
procedure ReadNewRaingageData(aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of rain gage data using newer format.
//-----------------------------------------------------------------------------
var
I: Integer;
Fname: String;
begin
if Ntoks > 1 then aGage.Data[GAGE_DATA_FORMAT] := TokList[1];
if Ntoks > 2 then aGage.Data[GAGE_DATA_FREQ] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_SNOW_CATCH] := TokList[3];
if Ntoks > 4 then
begin
I := Uutils.FindKeyWord(TokList[4], RaingageOptions, 4);
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 5 then aGage.Data[GAGE_SERIES_NAME] := TokList[5];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 5 then
begin
Fname := TokList[5];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
aGage.Data[GAGE_FILE_NAME] := Fname;
end;
if Ntoks > 6 then aGage.Data[GAGE_STATION_NUM] := TokList[6];
if Ntoks > 7 then aGage.Data[GAGE_RAIN_UNITS] := TokList[7];
end;
end;
end;
function ReadRaingageData: Integer;
//-----------------------------------------------------------------------------
// Parses rain gage data from the input line.
//-----------------------------------------------------------------------------
var
aGage : TRaingage;
ID : String;
I : Integer;
begin
if Ntoks < 2 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end;
ID := TokList[0];
aGage := TRaingage.Create;
Uutils.CopyStringArray(Project.DefProp[RAINGAGE].Data, aGage.Data);
aGage.X := MISSING;
aGage.Y := MISSING;
aGage.Data[COMMENT_INDEX ] := Comment;
Project.Lists[RAINGAGE].AddObject(ID, aGage);
Project.HasItems[RAINGAGE] := True;
I := Uutils.FindKeyWord(TokList[1], RaingageOptions, 4);
if I >= 0
then ReadOldRaingageData(I, aGage)
else ReadNewRaingageData(aGage);
Result := 0;
end;
function ReadOldHydrographFormat(const I: Integer; UH: THydrograph): Integer;
//-----------------------------------------------------------------------------
// Reads older format of unit hydrograph parameters from a line of input.
//-----------------------------------------------------------------------------
var
J, K, N: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
N := 2;
for K := 1 to 3 do
begin
for J := 1 to 3 do
begin
UH.Params[I,J,K] := TokList[N];
Inc(N);
end;
end;
for J := 1 to 3 do
begin
UH.InitAbs[I,J,1] := '';
if Ntoks > N then UH.InitAbs[I,J,1] := TokList[N];
Inc(N);
for K := 2 to 3 do UH.InitAbs[I,J,K] := UH.InitAbs[I,J,1];
end;
end;
end;
function ReadHydrographData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII unit hydrograph data from a line of input.
//-----------------------------------------------------------------------------
var
I, J, K: Integer;
ID: String;
aUnitHyd: THydrograph;
Index: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Check if hydrograph ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[HYDROGRAPH].IndexOf(ID);
// If starting input for a new hydrograph then create it
if Index < 0 then
begin
aUnitHyd := THydrograph.Create;
Project.Lists[HYDROGRAPH].AddObject(ID, aUnitHyd);
Project.HasItems[HYDROGRAPH] := True;
Index := Project.Lists[HYDROGRAPH].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else aUnitHyd := THydrograph(Project.Lists[HYDROGRAPH].Objects[Index]);
// Parse rain gage name for 2-token line
if Ntoks = 2 then
begin
aUnitHyd.Raingage := TokList[1];
end
// Extract remaining hydrograph parameters
else if Ntoks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Determine month of year
I := Uutils.FindKeyWord(TokList[1], MonthLabels, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
// Determine if response type present - if not, process old format
K := Uutils.FindKeyWord(TokList[2], ResponseTypes, 3) + 1;
if K < 1 then Result := ReadOldHydrographFormat(I, aUnitHyd)
else
begin
// Extract R-T-K values
for J := 3 to 5 do
begin
aUnitHyd.Params[I,J-2,K] := TokList[J];
end;
// Extract IA parameters
for J := 6 to 8 do
begin
if J >= Ntoks then break
else aUnitHyd.InitAbs[I,J-5,K] := TokList[J];
end;
end;
end;
end;
end;
function ReadTemperatureData: Integer;
//-----------------------------------------------------------------------------
// Reads description of air temperature data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
I := Uutils.FindKeyWord(TokList[0], TempKeywords, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[0])
else case I of
0: begin // Time series
TempDataSource := 1;
TempTseries := TokList[1];
end;
1: begin // File
TempDataSource := 2;
TempFile := TokList[1];
if ExtractFilePath(TempFile) = '' then
TempFile := ExtractFilePath(Uglobals.InputFileName) + TempFile;
if Ntoks >= 3 then TempStartDate := TokList[2];
end;
2: begin // Wind speed
if SameText(TokList[1], 'MONTHLY') then
begin
if Ntoks < 14 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
WindType := MONTHLY_WINDSPEED;
for I := 1 to 12 do WindSpeed[I] := TokList[I+1];
end;
end
else if SameText(TokList[1], 'FILE') then WindType := FILE_WINDSPEED
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
3: begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 6 do SnowMelt[I] := TokList[I];
end;
4: begin
if Ntoks < 12 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
if SameText(TokList[1], 'IMPERVIOUS') then
for I := 1 to 10 do ADCurve[1][I] := TokList[I+1]
else if SameText(TokList[1], 'PERVIOUS') then
for I := 1 to 10 do ADCurve[2][I] := TokList[I+1]
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
end;
end;
function ReadEvaporationRates(Etype: Integer): Integer;
var
J: Integer;
begin
if (Etype <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
EvapType := Etype;
case EvapType of
CONSTANT_EVAP:
for J := 0 to 11 do EvapData[J] := TokList[1];
TSERIES_EVAP:
EvapTseries := TokList[1];
FILE_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
PanData[J-1] := TokList[J];
end;
MONTHLY_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
EvapData[J-1] := TokList[J];
end;
end;
Result := 0;
end;
end;
function ReadEvaporationData: Integer;
//-----------------------------------------------------------------------------
// Reads evaporation data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
I := Uutils.FindKeyWord(TokList[0], EvapOptions, 4);
if I >= 0 then Result := ReadEvaporationRates(I)
else if (I <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
if SameText(TokList[0], 'RECOVERY')
then RecoveryPat := TokList[1]
else if SameText(TokList[0], 'DRY_ONLY') then
begin
if SameText(TokList[1], 'NO') then EvapDryOnly := False
else if SameText(TokList[1], 'YES') then EvapDryOnly := True
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end
else Result := ErrMsg(KEYWORD_ERR, TokList[0]);
end;
end;
function ReadSubcatchmentData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := TSubcatch.Create;
SubcatchList.AddObject(ID, S);
S.X := MISSING;
S.Y := MISSING;
S.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[SUBCATCH].Data, S.Data);
S.Data[SUBCATCH_RAINGAGE_INDEX] := TokList[1];
S.Data[SUBCATCH_OUTLET_INDEX] := TokList[2];
S.Data[SUBCATCH_AREA_INDEX] := TokList[3];
S.Data[SUBCATCH_IMPERV_INDEX] := TokList[4];
S.Data[SUBCATCH_WIDTH_INDEX] := TokList[5];
S.Data[SUBCATCH_SLOPE_INDEX] := TokList[6];
S.Data[SUBCATCH_CURBLENGTH_INDEX] := TokList[7];
if Ntoks >= 9
then S.Data[SUBCATCH_SNOWPACK_INDEX] := TokList[8];
S.Data[COMMENT_INDEX ] := Comment;
Project.Lists[SUBCATCH].AddObject(ID, S);
Project.HasItems[SUBCATCH] := True;
Result := 0;
end;
end;
function ReadSubareaData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment sub-area data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
S.Data[SUBCATCH_IMPERV_N_INDEX] := TokList[1];
S.Data[SUBCATCH_PERV_N_INDEX] := TokList[2];
S.Data[SUBCATCH_IMPERV_DS_INDEX] := TokList[3];
S.Data[SUBCATCH_PERV_DS_INDEX] := TokList[4];
S.Data[SUBCATCH_PCTZERO_INDEX] := TokList[5];
S.Data[SUBCATCH_ROUTE_TO_INDEX] := TokList[6];
if Ntoks >= 8
then S.Data[SUBCATCH_PCT_ROUTED_INDEX] := TokList[7];
Result := 0;
end;
end;
end;
function ReadInfiltrationData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment infiltration data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
J : Integer;
Jmax : Integer;
begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
Jmax := Ntoks-1;
if Jmax > MAXINFILPROPS then Jmax := MAXINFILPROPS;
for J := 1 to Jmax do S.InfilData[J-1] := TokList[J];
Result := 0;
end;
end;
function ReadAquiferData: Integer;
//-----------------------------------------------------------------------------
// Reads aquifer data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
A : TAquifer;
I : Integer;
begin
if nToks < MAXAQUIFERPROPS then Result := ErrMsg(ITEMS_ERR, '') //(5.1.003)
else begin
ID := TokList[0];
A := TAquifer.Create;
//Uutils.CopyStringArray(Project.DefProp[AQUIFER].Data, A.Data); //(5.1.004)
Project.Lists[AQUIFER].AddObject(ID, A);
Project.HasItems[AQUIFER] := True;
for I := 0 to MAXAQUIFERPROPS-1 do A.Data[I] := TokList[I+1]; //(5.1.003)
if nToks >= MAXAQUIFERPROPS + 2 //(5.1.004)
then A.Data[MAXAQUIFERPROPS] := TokList[MAXAQUIFERPROPS+1] //(5.1.003)
else A.Data[MAXAQUIFERPROPS] := ''; //(5.1.003)
Result := 0;
end;
end;
function ReadGroundwaterData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment groundwater data from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
ID: String;
P: String;
J: Integer;
K: Integer;
begin
// Get subcatchment name
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else
begin
// Line contains GW flow parameters
if Ntoks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else begin
S.Groundwater.Clear;
// Read required parameters
for J := 1 to 9 do S.Groundwater.Add(TokList[J]);
// Read optional parameters
for K := 10 to 13 do
begin
if Ntoks > K then
begin
P := TokList[K];
if P = '*' then P := '';
S.Groundwater.Add(P);
end
else S.Groundwater.Add('');
end;
S.Data[SUBCATCH_GWATER_INDEX] := 'YES';
Result := 0;
end;
end;
end;
//// This function was re-written for release 5.1.007. //// //(5.1.007)
function ReadGroundwaterFlowEqn(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads GW flow math expression from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
N: Integer;
begin
// Check for enough tokens in line
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
// Get subcatchment object referred to by name
else begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
// Find position in Line where second token ends
N := Pos(TokList[1], Line) + Length(TokList[1]);
// Save remainder of line to correct type of GW flow equation
if SameText(TokList[1], 'LATERAL') then
S.GwLatFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else if SameText(TokList[1], 'DEEP') then
S.GwDeepFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
function ReadSnowpackData: Integer;
//-----------------------------------------------------------------------------
// Reads snowpack data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
P : TSnowpack;
I : Integer;
J : Integer;
Index: Integer;
begin
Result := 0;
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[1], SnowpackOptions, 7);
if I < 0
then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else begin
// Check if snow pack ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[SNOWPACK].IndexOf(ID);
// If starting input for a new snow pack then create it
if Index < 0 then
begin
P := TSnowpack.Create;
Project.Lists[SNOWPACK].AddObject(ID, P);
Project.HasItems[SNOWPACK] := True;
Index := Project.Lists[SNOWPACK].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else P := TSnowpack(Project.Lists[SNOWPACK].Objects[Index]);
// Parse line depending on data type
case I of
// Plowable area
0: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
for J := 1 to 6 do P.Data[1][J] := TokList[J+1];
P.FracPlowable := TokList[8];
end;
end;
// Impervious or Pervious area
1,
2: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else for J := 1 to 7 do P.Data[I+1][J] := TokList[J+1];
end;
// Plowing parameters
3: begin
for J := 1 to 6 do P.Plowing[J] := TokList[J+1];
if Ntoks >= 9 then P.Plowing[7] := TokList[8];
end;
end;
end;
end;
end;
function ReadJunctionData: Integer;
//-----------------------------------------------------------------------------
// Reads junction data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
begin
if Ntoks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := JUNCTION;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[JUNCTION].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
if Ntoks > 2 then aNode.Data[JUNCTION_MAX_DEPTH_INDEX] := TokList[2];
if Ntoks > 3 then aNode.Data[JUNCTION_INIT_DEPTH_INDEX] := TokList[3];
if Ntoks > 4 then aNode.Data[JUNCTION_SURCHARGE_DEPTH_INDEX] := TokList[4];
if Ntoks > 5 then aNode.Data[JUNCTION_PONDED_AREA_INDEX] := TokList[5];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[JUNCTION].AddObject(ID, aNode);
Project.HasItems[JUNCTION] := True;
Result := 0;
end;
end;
function ReadOutfallData: Integer;
//-----------------------------------------------------------------------------
// Reads outfall data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
I : Integer;
N : Integer; //(5.1.008)
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
N := 4; //(5.1.008)
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := OUTFALL;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTFALL].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
I := Uutils.FindKeyWord(TokList[2], OutfallOptions, 4);
if I < 0 then I := FREE_OUTFALL;
if (I > NORMAL_OUTFALL) and (Ntoks >= 4) then
begin
case I of
FIXED_OUTFALL: aNode.Data[OUTFALL_FIXED_STAGE_INDEX] := TokList[3];
TIDAL_OUTFALL: aNode.Data[OUTFALL_TIDE_TABLE_INDEX] := TokList[3];
TIMESERIES_OUTFALL: aNode.Data[OUTFALL_TIME_SERIES_INDEX] := TokList[3];
end;
N := 5;
if Ntoks >= 5 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[4]; // (5.1.008)
end
else if Ntoks >= 4 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[3]; //(5.1.008)
if Ntoks > N then aNode.Data[OUTFALL_ROUTETO_INDEX] := TokList[N]; //(5.1.008)
aNode.Data[OUTFALL_TYPE_INDEX] := OutfallOptions[I];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[OUTFALL].AddObject(ID, aNode);
Project.HasItems[OUTFALL] := True;
Result := 0;
end;
end;
//// The following function was modified for release 5.1.007. //// //(5.1.007)
function ReadStorageData: Integer;
//-----------------------------------------------------------------------------
// Reads storage unit data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
N : Integer;
X : Single;
begin
Result := 0;
N := 6;
if Ntoks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := STORAGE;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[STORAGE].Data, aNode.Data);
Project.Lists[STORAGE].AddObject(ID, aNode);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[STORAGE_MAX_DEPTH_INDEX] := TokList[2];
aNode.Data[STORAGE_INIT_DEPTH_INDEX] := TokList[3];
aNode.Data[STORAGE_GEOMETRY_INDEX] := TokList[4];
if CompareText(TokList[4], 'TABULAR') = 0 then
begin
aNode.Data[STORAGE_ATABLE_INDEX] := TokList[5];
end
else begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode.Data[STORAGE_ACOEFF_INDEX] := TokList[5];
aNode.Data[STORAGE_AEXPON_INDEX] := TokList[6];
if Ntoks >= 8 then aNode.Data[STORAGE_ACONST_INDEX] := TokList[7];
N := 8;
end;
end;
// Optional items
if (Result = 0) and (Ntoks > N) then
begin
// Ponded area
aNode.Data[STORAGE_PONDED_AREA_INDEX] := TokList[N];
// Evaporation factor
if Ntoks > N+1 then aNode.Data[STORAGE_EVAP_FACTOR_INDEX] := TokList[N+1];
// Constant seepage rate
if Ntoks = N+3 then
begin
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+2];
end
// Green-Ampt seepage parameters
else if Ntoks = N+5 then
begin
aNode.InfilData[STORAGE_SUCTION_INDEX] := TokList[N+2];
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+3];
aNode.InfilData[STORAGE_IMDMAX_INDEX] := TokList[N+4];
end;
end;
Uutils.GetSingle(aNode.InfilData[STORAGE_KSAT_INDEX ], X);
if (X > 0) then aNode.Data[STORAGE_SEEPAGE_INDEX] := 'YES'
else aNode.Data[STORAGE_SEEPAGE_INDEX] := 'NO';
aNode.Data[COMMENT_INDEX ] := Comment;
Project.HasItems[STORAGE] := True;
end;
end;
function ReadDividerData: Integer;
//-----------------------------------------------------------------------------
// Reads flow divider data from a line of input.
// (Corrected on 6/14/05)
//-----------------------------------------------------------------------------
var
N, J : Integer;
aNode: TNode;
ID : String;
begin
if Ntoks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Result := 0;
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := DIVIDER;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[DIVIDER].Data, aNode.Data);
Project.Lists[DIVIDER].AddObject(ID, aNode);
Project.HasItems[DIVIDER] := True;
aNode.Data[COMMENT_INDEX ] := Comment;
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[DIVIDER_LINK_INDEX] := TokList[2];
aNode.Data[DIVIDER_TYPE_INDEX] := TokList[3];
N := 5;
if SameText(TokList[3], 'OVERFLOW') then
begin
N := 4;
end
else if SameText(TokList[3], 'CUTOFF') then
begin
aNode.Data[DIVIDER_CUTOFF_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'TABULAR') then
begin
aNode.Data[DIVIDER_TABLE_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'WEIR') and (Ntoks >= 7) then
begin
aNode.Data[DIVIDER_QMIN_INDEX] := TokList[4];
aNode.Data[DIVIDER_DMAX_INDEX] := TokList[5];
aNode.Data[DIVIDER_QCOEFF_INDEX] := TokList[6];
N := 7;
end
else Result := ErrMsg(KEYWORD_ERR, TokList[3]);
if (Result = 0) and (Ntoks > N) then
begin
for J := N to Ntoks-1 do
aNode.Data[DIVIDER_MAX_DEPTH_INDEX + J - N] := TokList[J];
end;
end;
end;
function ReadConduitData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := CONDUIT;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[CONDUIT].Data, aLink.Data);
Project.Lists[CONDUIT].AddObject(ID, aLink);
Project.HasItems[CONDUIT] := True;
aLink.Data[CONDUIT_LENGTH_INDEX] := TokList[3];
aLink.Data[CONDUIT_ROUGHNESS_INDEX] := TokList[4];
aLink.Data[CONDUIT_INLET_HT_INDEX] := TokList[5];
aLink.Data[CONDUIT_OUTLET_HT_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_INIT_FLOW_INDEX] := TokList[7];
if Ntoks > 8 then aLink.Data[CONDUIT_MAX_FLOW_INDEX] := TokList[8];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadPumpData: Integer;
//-----------------------------------------------------------------------------
// Reads pump data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := PUMP;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[PUMP].Data, aLink.Data);
Project.Lists[PUMP].AddObject(ID, aLink);
Project.HasItems[PUMP] := True;
// Skip over PumpType if line has old format
if Uutils.FindKeyWord(TokList[3], PumpTypes, 5) >= 0 then N := 4
else N := 3;
if Ntoks <= N then Result := ErrMsg(ITEMS_ERR, '')
else
begin
aLink.Data[PUMP_CURVE_INDEX] := TokList[N];
if nToks > N+1 then aLink.Data[PUMP_STATUS_INDEX] := TokList[N+1];
if nToks > N+2 then aLink.Data[PUMP_STARTUP_INDEX] := TokList[N+2];
if nToks > N+3 then aLink.Data[PUMP_SHUTOFF_INDEX] := TokList[N+3];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
end;
function ReadOrificeData: Integer;
//-----------------------------------------------------------------------------
// Reads orifice data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := ORIFICE;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[ORIFICE].Data, aLink.Data);
Project.Lists[ORIFICE].AddObject(ID, aLink);
Project.HasItems[ORIFICE] := True;
aLink.Data[ORIFICE_TYPE_INDEX] := TokList[3];
aLink.Data[ORIFICE_BOTTOM_HT_INDEX] := TokList[4];
aLink.Data[ORIFICE_COEFF_INDEX] := TokList[5];
if nToks >= 7
then aLink.Data[ORIFICE_FLAPGATE_INDEX] := TokList[6];
if nToks >= 8
then aLink.Data[ORIFICE_ORATE_INDEX] := TokList[7];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadWeirData: Integer;
//-----------------------------------------------------------------------------
// Reads weir data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := WEIR;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[WEIR].Data, aLink.Data);
Project.Lists[WEIR].AddObject(ID, aLink);
Project.HasItems[WEIR] := True;
aLink.Data[WEIR_TYPE_INDEX] := TokList[3];
aLink.Data[WEIR_CREST_INDEX] := TokList[4];
aLink.Data[WEIR_COEFF_INDEX] := TokList[5];
//// Following section modified for release 5.1.007. //// //(5.1.007)
if (nToks >= 7) and not SameText(TokList[6], '*') then
aLink.Data[WEIR_FLAPGATE_INDEX] := TokList[6];
if (nToks >= 8) and not SameText(TokList[7], '*') then
aLink.Data[WEIR_CONTRACT_INDEX] := TokList[7];
if (nToks >= 9) and not SameText(TokList[8], '*') then
aLink.Data[WEIR_END_COEFF_INDEX] := TokList[8];
if (nToks >= 10) and not SameText(TokList[9], '*') then
aLink.Data[WEIR_SURCHARGE_INDEX] := TokList[9];
//// Following section added for release 5.1.010. //(5.1.010)
if (nToks >= 11) and not SameText(TokList[10], '*') then
aLink.Data[WEIR_ROAD_WIDTH_INDEX] := TokList[10];
if (nToks >= 12) and not SameText(TokList[11], '*') then
aLink.Data[WEIR_ROAD_SURF_INDEX] := TokList[11];
////
aLink.Data[COMMENT_INDEX] := Comment;
Result := 0;
end;
end;
end;
function ReadOutletData: Integer;
//-----------------------------------------------------------------------------
// Reads outlet data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := OUTLET;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTLET].Data, aLink.Data);
Project.Lists[OUTLET].AddObject(ID, aLink);
Project.HasItems[OUTLET] := True;
aLink.Data[OUTLET_CREST_INDEX] := TokList[3];
//... added for backwards compatibility
if SameText(TokList[4], 'TABULAR') then TokList[4] := 'TABULAR/DEPTH';
if SameText(TokList[4], 'FUNCTIONAL') then TokList[4] := 'FUNCTIONAL/DEPTH';
aLink.Data[OUTLET_TYPE_INDEX] := TokList[4];
if AnsiContainsText(TokList[4], 'TABULAR') then
begin
aLink.Data[OUTLET_QTABLE_INDEX] := TokList[5];
N := 6;
end
else begin
if Ntoks < 7 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end
else
begin
aLink.Data[OUTLET_QCOEFF_INDEX] := TokList[5];
aLink.Data[OUTLET_QEXPON_INDEX] := TokList[6];
N := 7;
end;
end;
if Ntoks > N then aLink.Data[OUTLET_FLAPGATE_INDEX] := TokList[N];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function GetXsectShape(const S: String): Integer;
//-----------------------------------------------------------------------------
// Finds the code number corresponding to cross section shape S.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
for I := 0 to High(Dxsect.XsectShapes) do
begin
if CompareText(S, Dxsect.XsectShapes[I].Text[1]) = 0 then
begin
Result := I;
Exit;
end;
end;
Result := -1;
end;
//// New procedure added to release 5.1.008. //// //(5.1.008)
procedure CheckForStdSize;
//-----------------------------------------------------------------------------
// Converts from old format for standard size ellipse and arch pipes
// to new format.
//-----------------------------------------------------------------------------
var
J: Integer;
X: Extended;
begin
// Old format had size code as 3rd token and 0 for 4th token
J := StrToIntDef(TokList[2], 0);
Uutils.GetExtended(TokList[3], X);
if (J > 0) and (X = 0) then
begin
// New format has 5th token as size code
TokList[4] := TokList[2];
TokList[2] := '0';
TokList[3] := '0';
end;
end;
function ReadXsectionData: Integer;
//-----------------------------------------------------------------------------
// Reads cross section data froma line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
ID : String;
aLink : TLink;
begin
if nToks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil)
then Result := ErrMsg(LINK_ERR, TokList[0])
else begin
I := GetXsectShape(TokList[1]);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else case aLink.Ltype of
CONDUIT:
begin
aLink.Data[CONDUIT_SHAPE_INDEX] := TokList[1];
if I = Dxsect.IRREG_SHAPE_INDEX then
begin
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM1_INDEX] := ''; //(5.1.008)
Result := 0;
end
else begin
if nToks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else begin
{
//// Added to release 5.1.008. //// //(5.1.008)
if I in [Dxsect.HORIZ_ELLIPSE_SHAPE_INDEX,
Dxsect.VERT_ELLIPSE_SHAPE_INDEX,
Dxsect.ARCH_SHAPE_INDEX]
then CheckForStdSize;
}
aLink.Data[CONDUIT_GEOM1_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM2_INDEX] := TokList[3];
aLink.Data[CONDUIT_GEOM3_INDEX] := TokList[4];
aLink.Data[CONDUIT_GEOM4_INDEX] := TokList[5];
if Ntoks > 6 then aLink.Data[CONDUIT_BARRELS_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_CULVERT_INDEX] := TokList[7];
if I = Dxsect.CUSTOM_SHAPE_INDEX then
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[3];
Result := 0;
end;
end;
end;
ORIFICE:
begin
if not I in [0, 1] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[ORIFICE_SHAPE_INDEX] := TokList[1];
aLink.Data[ORIFICE_HEIGHT_INDEX] := TokList[2];
aLink.Data[ORIFICE_WIDTH_INDEX] := TokList[3];
Result := 0;
end;
end;
WEIR:
begin
if not I in [2, 3, 4] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[WEIR_SHAPE_INDEX] := TokList[1];
aLink.Data[WEIR_HEIGHT_INDEX] := TokList[2];
aLink.Data[WEIR_WIDTH_INDEX] := TokList[3];
aLink.Data[WEIR_SLOPE_INDEX] := TokList[4];
Result := 0;
end;
end;
else Result := 0;
end;
end;
end;
end;
function ReadTransectData: Integer;
//-----------------------------------------------------------------------------
// Reads transect data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
K : Integer;
N : Integer;
ID : String;
Tsect : TTransect;
begin
Result := 0;
if SameText(TokList[0], 'NC') then
begin
if nToks < 4 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 3 do ManningsN[I] := TokList[I];
TsectComment := Comment;
Exit;
end;
if SameText(TokList[0], 'X1') then
begin
if nToks < 2 then Exit;
ID := TokList[1];
Tsect := TTransect.Create;
if Length(Comment) > 0 then TsectComment := Comment;
Tsect.Comment := TsectComment;
Project.Lists[TRANSECT].AddObject(ID, Tsect);
Project.HasItems[TRANSECT] := True;
Tsect.Data[TRANSECT_N_LEFT] := ManningsN[1];
Tsect.Data[TRANSECT_N_RIGHT] := ManningsN[2];
Tsect.Data[TRANSECT_N_CHANNEL] := ManningsN[3];
if nToks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
Tsect.Data[TRANSECT_X_LEFT] := TokList[3];
Tsect.Data[TRANSECT_X_RIGHT] := TokList[4];
Tsect.Data[TRANSECT_L_FACTOR] := TokList[7];
Tsect.Data[TRANSECT_X_FACTOR] := TokList[8];
Tsect.Data[TRANSECT_Y_FACTOR] := TokList[9];
end;
Exit;
end;
if SameText(TokList[0], 'GR') then
begin
N := Project.Lists[TRANSECT].Count;
if N = 0 then Result := ErrMsg(TRANSECT_ERR, '')
else begin
Tsect := TTransect(Project.Lists[TRANSECT].Objects[N-1]);
K := 1;
while K + 1 < Ntoks do
begin
Tsect.Ydata.Add(TokList[K]);
Tsect.Xdata.Add(TokList[K+1]);
K := K + 2;
end;
end;
Exit;
end;
end;
function ReadLossData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit loss data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLink : TLink;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil) then Result := ErrMsg(LINK_ERR, ID)
else if (aLink.Ltype <> CONDUIT) then Result := 0
else begin
aLink.Data[CONDUIT_ENTRY_LOSS_INDEX] := TokList[1];
aLink.Data[CONDUIT_EXIT_LOSS_INDEX] := TokList[2];
aLink.Data[CONDUIT_AVG_LOSS_INDEX] := TokList[3];
if nToks >= 5
then aLink.Data[CONDUIT_CHECK_VALVE_INDEX] := TokList[4];
if nToks >= 6
then aLink.Data[CONDUIT_SEEPAGE_INDEX] := TokList[5];
Result := 0;
end;
end;
end;
function ReadPollutantData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aPollut : TPollutant;
X : Single;
begin
if nToks < 5
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Add new pollutant to project
ID := TokList[0];
aPollut := TPollutant.Create;
Uutils.CopyStringArray(Project.DefProp[POLLUTANT].Data, aPollut.Data);
Project.Lists[POLLUTANT].AddObject(ID, aPollut);
Project.HasItems[POLLUTANT] := True;
// Parse units & concens.
aPollut.Data[POLLUT_UNITS_INDEX] := TokList[1];
aPollut.Data[POLLUT_RAIN_INDEX] := TokList[2];
aPollut.Data[POLLUT_GW_INDEX] := TokList[3];
// This is for old format
if (Ntoks = 5)
or ( (Ntoks = 7) and Uutils.GetSingle(TokList[6], X) ) then
begin
aPollut.Data[POLLUT_DECAY_INDEX] := TokList[4];
if nToks >= 7 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[5];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[6];
end;
end
// This is for new format
else
begin
aPollut.Data[POLLUT_II_INDEX] := TokList[4];
if Ntoks >= 6 then aPollut.Data[POLLUT_DECAY_INDEX] := TokList[5];
if nToks >= 7 then aPollut.Data[POLLUT_SNOW_INDEX] := TokList[6];
if Ntoks >= 9 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[7];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[8];
end;
if Ntoks >= 10 then aPollut.Data[POLLUT_DWF_INDEX] := TokList[9];
if Ntoks >= 11 then aPollut.Data[POLLUT_INIT_INDEX] := TokList[10];
end;
Result := 0;
end;
end;
function ReadLanduseData: Integer;
//-----------------------------------------------------------------------------
// Reads land use data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLanduse : TLanduse;
aNonPtSource : TNonpointSource;
J : Integer;
begin
ID := TokList[0];
aLanduse := TLanduse.Create;
for J := 0 to Project.Lists[POLLUTANT].Count - 1 do
begin
aNonPtSource := TNonpointSource.Create;
aLanduse.NonpointSources.AddObject(Project.Lists[POLLUTANT].Strings[J],
aNonPtSource);
end;
Project.Lists[LANDUSE].AddObject(ID, aLanduse);
Project.HasItems[LANDUSE] := True;
if Ntoks > 1 then aLanduse.Data[LANDUSE_CLEANING_INDEX] := TokList[1];
if Ntoks > 2 then aLanduse.Data[LANDUSE_AVAILABLE_INDEX] := TokList[2];
if Ntoks > 3 then aLanduse.Data[LANDUSE_LASTCLEAN_INDEX] := TokList[3];
aLanduse.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
function ReadBuildupData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant buildup function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.BuildupData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadWashoffData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant washoff function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.WashoffData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadCoverageData: Integer;
//-----------------------------------------------------------------------------
// Reads land use coverage data from a line of input.
//-----------------------------------------------------------------------------
var
MaxToks: Integer;
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
MaxToks := 3;
while (MaxToks <= nToks) do
begin
if not Uutils.GetSingle(TokList[MaxToks-1], X) then
begin
Result := ErrMsg(NUMBER_ERR, TokList[MaxToks-1]);
break;
end;
S1 := TokList[MaxToks-2];
I := S.LandUses.IndexOfName(S1);
S1 := TokList[MaxToks-2] + '=' + TokList[MaxToks-1];
if I < 0
then S.LandUses.Add(S1)
else S.Landuses[I] := S1;
MaxToks := MaxToks + 2;
end;
S.Data[SUBCATCH_LANDUSE_INDEX] := IntToStr(S.LandUses.Count);
end;
end;
function ReadTreatmentData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads pollutant treatment function from a line of input.
//-----------------------------------------------------------------------------
var
S : String;
aNode : TNode;
I : Integer;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0 then
Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
I := aNode.Treatment.IndexOfName(TokList[1]);
S := Copy(Line, Pos(TokList[1], Line)+Length(TokList[1]), Length(Line));
S := TokList[1] + '=' + Trim(S);
if I < 0 then
aNode.Treatment.Add(S)
else
aNode.Treatment[I] := S;
aNode.Data[NODE_TREAT_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadExInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads external inflow data from a line of input.
//-----------------------------------------------------------------------------
var
S : array[1..7] of String;
Inflow: String;
I : Integer;
aNode : TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S[1] := TokList[1]; // Constituent name
S[2] := TokList[2]; // Time Series name
S[3] := 'FLOW';
S[4] := '1.0';
if not SameText(S[1], 'FLOW') then
begin
if nToks >= 4 then S[3] := TokList[3] else S[3] := 'CONCEN';
if nToks >= 5 then S[4] := TokList[4] else S[4] := '1.0';
end;
if nToks >= 6 then S[5] := TokList[5] else S[5] := '1.0';
if nToks >= 7 then S[6] := TokList[6] else S[6] := '';
if nToks >= 8 then S[7] := TokList[7] else S[7] := '';
Inflow := S[1] + '=' + S[2] + #13 + S[3] + #13 + S[4] + #13 +
S[5] + #13 + S[6] + #13 + S[7];
I := aNode.DXInflow.IndexOfName(S[1]);
if I < 0 then aNode.DXInflow.Add(Inflow)
else aNode.DXInflow[I] := Inflow;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadDWInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads dry weather inflow data from a line of input.
//-----------------------------------------------------------------------------
var
M : Integer;
S : String;
S1 : String;
I : Integer;
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S1 := TokList[1];
S := S1 + '=' + TokList[2];
for M := 3 to Ntoks-1 do S := S + #13 + TokList[M];
I := aNode.DWInflow.IndexOfName(S1);
if I < 0
then aNode.DWInflow.Add(S)
else aNode.DWInflow[I] := S;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadPatternData: Integer;
//-----------------------------------------------------------------------------
// Reads time pattern data from a line of input.
//-----------------------------------------------------------------------------
var
ID: String;
Index: Integer;
aPattern: TPattern;
PatType: Integer;
J: Integer;
begin
if nToks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
J := 1;
ID := TokList[0];
Index := Project.Lists[PATTERN].IndexOf(ID);
if Index < 0 then
begin
aPattern := TPattern.Create;
aPattern.Comment := Comment;
Project.Lists[PATTERN].AddObject(ID, aPattern);
Project.HasItems[PATTERN] := True;
PatType := Uutils.FindKeyWord(TokList[1], PatternTypes, 7);
if PatType < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
exit;
end;
aPattern.PatternType := PatType;
J := 2;
end
else aPattern := TPattern(Project.Lists[PATTERN].Objects[Index]);
while (J < nToks) and (aPattern.Count <= High(aPattern.Data)) do
begin
aPattern.Data[aPattern.Count] := TokList[J];
Inc(J);
Inc(aPattern.Count);
end;
Result := 0;
end;
end;
function ReadIIInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII inflow data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
aNode.IIInflow.Clear;
aNode.IIInflow.Add(TokList[1]);
aNode.IIInflow.Add(TokList[2]);
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadLoadData: Integer;
//-----------------------------------------------------------------------------
// Reads initial pollutant loading data from a line of input.
//-----------------------------------------------------------------------------
var
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0
then Result := ErrMsg(POLLUT_ERR, TokList[1])
else if not Uutils.GetSingle(TokList[2], X)
then Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
S1 := TokList[1] + '=' + TokList[2];
I := S.Loadings.IndexOfName(TokList[1]);
if I < 0
then S.Loadings.Add(S1)
else S.Loadings[I] := S1;
S.Data[SUBCATCH_LOADING_INDEX] := 'YES';
Result := 0;
end;
end;
function ReadCurveData: Integer;
//-----------------------------------------------------------------------------
// Reads curve data from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
K : Integer;
L : Integer;
M : Integer;
ObjType : Integer;
ID : String;
aCurve : TCurve;
begin
// Check for too few tokens
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Check if curve ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then
begin
Index := PrevIndex;
ObjType := CurveType;
end
else Project.FindCurve(ID, ObjType, Index);
// Create new curve if ID not in data base
K := 2;
if Index < 0 then
begin
// Check for valid curve type keyword
M := -1;
for L := 0 to High(CurveTypeOptions) do
begin
if SameText(TokList[1], CurveTypeOptions[L]) then
begin
M := L;
break;
end;
end;
if M < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
Exit;
end;
// Convert curve type keyword index to a curve object category
case M of
0: ObjType := CONTROLCURVE;
1: ObjType := DIVERSIONCURVE;
2..5:
ObjType := PUMPCURVE;
6: ObjType := RATINGCURVE;
7: ObjType := SHAPECURVE;
8: ObjType := STORAGECURVE;
9: ObjType := TIDALCURVE;
end;
// Create a new curve object
aCurve := TCurve.Create;
aCurve.Comment := Comment;
aCurve.CurveType := TokList[1];
if ObjType = PUMPCURVE
then aCurve.CurveCode := M - 1
else aCurve.CurveCode := 0;
Project.Lists[ObjType].AddObject(ID, aCurve);
Project.HasItems[ObjType] := True;
Index := Project.Lists[ObjType].Count - 1;
PrevID := ID;
PrevIndex := Index;
CurveType := ObjType;
K := 3;
end;
// Add x,y values to the list maintained by the curve
aCurve := TCurve(Project.Lists[ObjType].Objects[Index]);
while K <= nToks-1 do
begin
aCurve.Xdata.Add(TokList[K-1]);
aCurve.Ydata.Add(TokList[K]);
K := K + 2;
end;
Result := 0;
end;
end;
function ReadTimeseriesData: Integer;
//-----------------------------------------------------------------------------
// Reads time series data from a line of input.
//-----------------------------------------------------------------------------
const
NEEDS_DATE = 1;
NEEDS_TIME = 2;
NEEDS_VALUE = 3;
var
Index : Integer;
State : Integer;
K : Integer;
ID : String;
StrDate : String;
aTseries : TTimeseries;
begin
// Check for too few tokens
Result := -1;
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '');
// Check if series ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then Index := PrevIndex
else Index := Project.Lists[TIMESERIES].IndexOf(ID);
// If starting input for a new series then create it
if Index < 0 then
begin
aTseries := TTimeseries.Create;
aTseries.Comment := Comment;
Project.Lists[TIMESERIES].AddObject(ID,aTseries);
Project.HasItems[TIMESERIES] := True;
Index := Project.Lists[TIMESERIES].Count - 1;
PrevID := ID;
PrevIndex := Index;
end;
aTseries := TTimeseries(Project.Lists[TIMESERIES].Objects[Index]);
// Check if external file name used
if SameText(TokList[1], 'FILE') then
begin
aTseries.Filename := TokList[2];
Result := 0;
Exit;
end;
// Add values to the list maintained by the timeseries
State := NEEDS_DATE;
K := 1;
while K < nToks do
begin
case State of
NEEDS_DATE:
begin
try
StrDate := Uutils.ConvertDate(TokList[K]);
StrToDate(StrDate, MyFormatSettings);
aTseries.Dates.Add(StrDate);
Inc(K);
if K >= nToks then break;
except
On EconvertError do aTseries.Dates.Add('');
end;
State := NEEDS_TIME;
end;
NEEDS_TIME:
begin
aTseries.Times.Add(TokList[K]);
Inc(K);
if K >= nToks then break;
State := NEEDS_VALUE;
end;
NEEDS_VALUE:
begin
aTseries.Values.Add(TokList[K]);
Result := 0;
State := NEEDS_DATE;
Inc(K);
end;
end;
end;
if Result = -1 then Result := ErrMsg(ITEMS_ERR, '');
end;
function ReadControlData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads a control rule statement from line of input.
//-----------------------------------------------------------------------------
begin
Project.ControlRules.Add(Line);
Result := 0;
end;
function ReadLidUsageData: Integer;
//-----------------------------------------------------------------------------
// Reads LID usage data from line of input.
//-----------------------------------------------------------------------------
var
aSubcatch: TSubcatch;
begin
aSubcatch := FindSubcatch(TokList[0]);
if aSubcatch = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else Result := Ulid.ReadLIDUsageData(aSubcatch, TokList, Ntoks);
end;
procedure ReadReportOption(Index: Integer);
begin
if (Ntoks >= 2) and SameText(TokList[1], 'YES') then
Project.Options.Data[Index] := 'YES'
else
Project.Options.Data[Index] := 'NO';
end;
function ReadReportData: Integer;
//-----------------------------------------------------------------------------
// Reads reporting options from a line of input.
//-----------------------------------------------------------------------------
begin
if SameText(TokList[0], 'CONTROLS')
then ReadReportOption(REPORT_CONTROLS_INDEX)
else if SameText(TokList[0], 'INPUT')
then ReadReportOption(REPORT_INPUT_INDEX)
else ReportingForm.Import(TokList, Ntoks);
Result := 0;
end;
function ReadFileData: Integer;
//-----------------------------------------------------------------------------
// Reads interface file usage from a line of input.
//-----------------------------------------------------------------------------
var
Fname: String;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Fname := TokList[2];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
Project.IfaceFiles.Add(TokList[0] + ' ' + TokList[1] + ' ' +
'"' + Fname + '"');
Result := 0;
end;
end;
//// This function was added to release 5.1.007. //// //(5.1.007)
function ReadAdjustmentData: Integer;
//-----------------------------------------------------------------------------
// Reads climate adjustments from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then exit;
if SameText(TokList[0], 'Temperature') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then TempAdjust[I] := ''
else TempAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Evaporation') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then EvapAdjust[I] := ''
else EvapAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Rainfall') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then RainAdjust[I] := ''
else RainAdjust[I] := TokList[I+1];
end;
end
//// Added to release 5.1.008. //// //(5.1.008)
else if SameText(TokList[0], 'Conductivity') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then CondAdjust[I] := ''
else CondAdjust[I] := TokList[I+1];
end;
end;
////////////////////////////////////////////////////////
end;
//// This function was added to release 5.1.011. //// //(5.1.011)
function ReadEventData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads hydraulic event data from a line of input.
//-----------------------------------------------------------------------------
begin
Result := 0;
if Length(Line) = 0 then exit;
if LeftStr(Line,2) = ';;' then exit;
Project.Events.Add(Line);
end;
function ReadOptionData: Integer;
//-----------------------------------------------------------------------------
// Reads an analysis option from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
S : String;
S2: String;
I : Integer;
X : Single;
T : Extended;
begin
// Check which keyword applies
Result := 0;
if Ntoks < 2 then exit;
Keyword := TokList[0];
if SameText(Keyword, 'TEMPDIR') then exit;
Index := Uutils.FindKeyWord(Keyword, OptionLabels, 17);
case Index of
-1: Result := ErrMsg(KEYWORD_ERR, Keyword);
ROUTING_MODEL_INDEX:
begin
if SameText(TokList[1], 'NONE') then
begin
Project.Options.Data[IGNORE_ROUTING_INDEX] := 'YES';
Exit;
end;
I := Uutils.FindKeyWord(TokList[1], OldRoutingOptions, 3);
if I >= 0 then TokList[1] := RoutingOptions[I];
end;
START_DATE_INDEX, REPORT_START_DATE_INDEX, END_DATE_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
try
StrToDate(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
START_TIME_INDEX, REPORT_START_TIME_INDEX, END_TIME_INDEX:
begin
S := TokList[1];
try
StrToTime(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
SWEEP_START_INDEX, SWEEP_END_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
S2 := S + '/1947';
try
StrToDate(S2, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
WET_STEP_INDEX, DRY_STEP_INDEX, REPORT_STEP_INDEX:
begin
S := TokList[1];
if Uutils.StrHoursToTime(S) = -1 then Result := ErrMsg(TIMESTEP_ERR, '');
end;
ROUTING_STEP_INDEX:
begin
S := TokList[1];
T := 0.0;
if not Uutils.GetExtended(S, T) then
begin
T := Uutils.StrHoursToTime(S)*86400.;
if T <= 0.0 then Result := ErrMsg(TIMESTEP_ERR, '')
else TokList[1] := Format('%.0f',[T]);
end;
end;
VARIABLE_STEP_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
TokList[1] := IntToStr(Round(100.0*X))
else
TokList[1] := '0';
end;
INERTIAL_DAMPING_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
begin
if X = 0 then TokList[1] := 'NONE'
else TokList[1] := 'PARTIAL';
end;
end;
// This option is now fixed to SWMM 4.
COMPATIBILITY_INDEX:
begin
TokList[1] := '4';
end;
MIN_ROUTE_STEP_INDEX, //(5.1.008)
LENGTHEN_STEP_INDEX,
MIN_SURFAREA_INDEX,
MIN_SLOPE_INDEX,
MAX_TRIALS_INDEX,
HEAD_TOL_INDEX,
SYS_FLOW_TOL_INDEX,
LAT_FLOW_TOL_INDEX:
begin
Uutils.GetSingle(TokList[1], X);
if X <= 0 then TokList[1] := '0';
end;
NORMAL_FLOW_LTD_INDEX:
begin
if SameText(TokList[1], 'NO') or SameText(TokList[1], 'SLOPE')
then TokList[1] := 'SLOPE'
else if SameText(TokList[1], 'YES') or SameText(TokList[1], 'FROUDE')
then TokList[1] := 'FROUDE'
else if SameText(TokList[1], 'BOTH') then TokList[1] := 'BOTH'
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
FORCE_MAIN_EQN_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], ForceMainEqnOptions, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := ForceMainEqnOptions[I];
end;
LINK_OFFSETS_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], LinkOffsetsOptions, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := LinkOffsetsOptions[I];
end;
IGNORE_RAINFALL_INDEX,
IGNORE_SNOWMELT_INDEX,
IGNORE_GRNDWTR_INDEX,
IGNORE_ROUTING_INDEX,
IGNORE_QUALITY_INDEX:
begin
if not SameText(TokList[1], 'YES') and not SameText(TokList[1], 'NO')
then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
//// Following section added to release 5.1.010. //// //(5.1.010)
NUM_THREADS_INDEX:
begin
I := StrToIntDef(TokList[1], 1);
if I < 0 then I := 1;
if (I = 0) or (I > Uutils.GetCPUs) then I := Uutils.GetCPUs;
TokList[1] := IntToStr(I);
end;
////
end;
if Result = 0 then Project.Options.Data[Index] := TokList[1];
end;
function ReadTagData: Integer;
//-----------------------------------------------------------------------------
// Reads in tag data from a line of input.
//-----------------------------------------------------------------------------
const
TagTypes: array[0..3] of PChar = ('Gage', 'Subcatch', 'Node', 'Link');
var
I, J : Integer;
aNode: TNode;
aLink: TLink;
begin
Result := 0;
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[0], TagTypes, 4);
case I of
-1: Result := ErrMsg(KEYWORD_ERR, TokList[0]);
0: begin
J := Project.Lists[RAINGAGE].IndexOf(TokList[1]);
if J >= 0 then with Project.GetGage(J) do Data[TAG_INDEX] := TokList[2];
end;
1: begin
J := Project.Lists[SUBCATCH].IndexOf(TokList[1]);
if J >= 0 then with Project.GetSubcatch(SUBCATCH, J) do
Data[TAG_INDEX] := TokList[2];
end;
2: begin
aNode := FindNode(TokList[1]);
if (aNode <> nil) then aNode.Data[TAG_INDEX] := TokList[2];
end;
3: begin
aLink := FindLink(TokList[1]);
if (aLink <> nil) then aLink.Data[TAG_INDEX] := TokList[2];
end;
end;
end;
end;
function ReadSymbolData: Integer;
//-----------------------------------------------------------------------------
// Reads rain gage coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
J : Integer;
X, Y : Extended;
aGage : TRaingage;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the gage ID in the database
J := Project.Lists[RAINGAGE].IndexOf(TokList[0]);
// If gage exists then assign it X & Y coordinates
if (J >= 0) then
begin
aGage := Project.GetGage(J);
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aGage.X := X;
aGage.Y := Y;
end;
end;
end;
end;
function ReadMapData: Integer;
//-----------------------------------------------------------------------------
// Reads map dimensions data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
Index : Integer;
Keyword : String;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, MapWords, 4);
case Index of
0: // Map dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for I := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Dimensions do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
MapExtentSet := True;
end;
end;
end;
1: //Map units
if Ntoks > 1 then
begin
I := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
with MapForm.Map.Dimensions do
begin
if Units = muDegrees then Digits := MAXDEGDIGITS
else Digits := Umap.DefMapDimensions.Digits;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadCoordData: Integer;
//-----------------------------------------------------------------------------
// Reads node coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aNode : TNode;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the node ID in the database
aNode := FindNode(TokList[0]);
// If node exists then assign it X & Y coordinates
if (aNode <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aNode.X := X;
aNode.Y := Y;
end;
end;
end;
end;
function ReadVertexData: Integer;
//-----------------------------------------------------------------------------
// Reads link vertex coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aLink : TLink;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the link ID in the database
aLink := FindLink(TokList[0]);;
// If link exists then assign it X & Y coordinates
if (aLink <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else aLink.Vlist.Add(X, Y);
end;
end;
end;
function ReadPolygonData: Integer;
//-----------------------------------------------------------------------------
// Reads polygon coordinates associated with subcatchment outlines.
//-----------------------------------------------------------------------------
var
Index : Integer;
X, Y : Extended;
S : TSubcatch;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the subcatchment ID in the database
S := nil;
Index := Project.Lists[SUBCATCH].IndexOf(TokList[0]);
if Index >= 0 then S := Project.GetSubcatch(SUBCATCH, Index);
// If subcatchment exists then add a new vertex to it
if (S <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else S.Vlist.Add(X, Y);
end;
end;
end;
function ReadLabelData: Integer;
//-----------------------------------------------------------------------------
// Reads map label data from a line of input.
//-----------------------------------------------------------------------------
var
Ntype : Integer;
Index : Integer;
X, Y : Extended;
S : String;
aMapLabel: TMapLabel;
begin
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
if not Uutils.GetExtended(TokList[0], X) then
Result := ErrMsg(NUMBER_ERR, TokList[0])
else if not Uutils.GetExtended(TokList[1], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else begin
S := TokList[2];
aMapLabel := TMapLabel.Create;
aMapLabel.X := X;
aMapLabel.Y := Y;
Project.Lists[MAPLABEL].AddObject(S, aMapLabel);
Index := Project.Lists[MAPLABEL].Count - 1;
aMapLabel.Text := PChar(Project.Lists[MAPLABEL].Strings[Index]);
Project.HasItems[MAPLABEL] := True;
if Ntoks >= 4 then
begin
if (Length(TokList[3]) > 0) and
Project.FindNode(TokList[3], Ntype, Index) then
aMapLabel.Anchor := Project.GetNode(Ntype, Index);
end;
if Ntoks >= 5 then aMapLabel.FontName := TokList[4];
if Ntoks >= 6 then aMapLabel.FontSize := StrToInt(TokList[5]);
if Ntoks >= 7 then
if StrToInt(TokList[6]) = 1 then aMapLabel.FontBold := True;
if Ntoks >= 8 then
if StrToInt(TokList[7]) = 1 then aMapLabel.FontItalic := True;
Result := 0;
end;
end;
end;
function ReadBackdropData: Integer;
//-----------------------------------------------------------------------------
// Reads map backdrop image information from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
I : Integer;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, BackdropWords, 4);
case Index of
0: //Backdrop file
if Ntoks > 1 then MapForm.Map.Backdrop.Filename := TokList[1];
1: // Backdrop dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for i := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Backdrop do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
end;
end;
end;
2: //Map units - deprecated
if Ntoks > 1 then
begin
i := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
end;
3, 4: //Backdrop offset or scaling -- deprecated
begin
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
else if not Uutils.GetExtended(TokList[1], X[1]) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], X[2]) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
if Index = 3 then
begin
BackdropX := X[1];
BackdropY := X[2];
end
else
begin
BackdropW := X[1];
BackdropH := X[2];
end;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadProfileData: Integer;
//-----------------------------------------------------------------------------
// Reads profile plot data from a line of input.
//-----------------------------------------------------------------------------
var
I, J: Integer;
S : String;
begin
Result := 0;
if (Ntoks < 2) then Exit;
// Locate the profile name in the database
I := Project.ProfileNames.IndexOf(TokList[0]);
// If profile does not exist then create it
if (I < 0) then
begin
Project.ProfileNames.Add(TokList[0]);
I := Project.ProfileNames.Count-1;
S := '';
Project.ProfileLinks.Add(S);
end
else S := Project.ProfileLinks[I] + #13;
// Add each remaining token to the list of links in the profile
S := S + TokList[1];
for J := 2 to Ntoks-1 do
S := S + #13 + TokList[J];
Project.ProfileLinks[I] := S;
end;
procedure SetMapDimensions;
//-----------------------------------------------------------------------------
// Determines map dimensions based on range of object coordinates.
//-----------------------------------------------------------------------------
begin
with MapForm.Map do
begin
// Dimensions not provided in [MAP] section
if not MapExtentSet then
begin
// Dimensions were provided in [BACKDROP] section
if (Backdrop.LowerLeft.X <> Backdrop.UpperRight.X) then
begin
// Interpret these as map dimensions
Dimensions.LowerLeft := Backdrop.LowerLeft;
Dimensions.UpperRight := Backdrop.UpperRight;
// Compute backdrop dimensions from Offset and Scale values
Backdrop.LowerLeft.X := BackdropX;
Backdrop.LowerLeft.Y := BackdropY - BackdropH;
Backdrop.UpperRight.X := BackdropX + BackdropW;
Backdrop.UpperRight.Y := BackdropY;
end
// No dimensions of any kind provided
else with Dimensions do
Ucoords.GetCoordExtents(LowerLeft.X, LowerLeft.Y,
UpperRight.X, UpperRight.Y);
end;
end;
end;
function ParseInpLine(S: String): Integer;
//-----------------------------------------------------------------------------
// Parses current input line depending on current section of input file.
//-----------------------------------------------------------------------------
begin
case Section of
1: Result := ReadOptionData;
2: Result := ReadRaingageData;
3: Result := ReadHydrographData;
4: Result := ReadEvaporationData;
5: Result := ReadSubcatchmentData;
6: Result := ReadSubareaData;
7: Result := ReadInfiltrationData;
8: Result := ReadAquiferData;
9: Result := ReadGroundwaterData;
10: Result := ReadJunctionData;
11: Result := ReadOutfallData;
12: Result := ReadStorageData;
13: Result := ReadDividerData;
14: Result := ReadConduitData;
15: Result := ReadPumpData;
16: Result := ReadOrificeData;
17: Result := ReadWeirData;
18: Result := ReadOutletData;
19: Result := ReadXsectionData;
20: Result := ReadTransectData;
21: Result := ReadLossData;
//22: ReadControlData called directly from ReadFile
23: Result := ReadPollutantData;
24: Result := ReadLanduseData;
25: Result := ReadBuildupData;
26: Result := ReadWashoffData;
27: Result := ReadCoverageData;
28: Result := ReadExInflowData;
29: Result := ReadDWInflowData;
30: Result := ReadPatternData;
31: Result := ReadIIInflowData;
32: Result := ReadLoadData;
33: Result := ReadCurveData;
34: Result := ReadTimeseriesData;
35: Result := ReadReportData;
36: Result := ReadFileData;
37: Result := ReadMapData;
38: Result := ReadCoordData;
39: Result := ReadVertexdata;
40: Result := ReadPolygonData;
41: Result := ReadSymbolData;
42: Result := ReadLabelData;
43: Result := ReadBackdropData;
44: Result := ReadProfileData;
45: Result := ReadCurveData;
46: Result := ReadTemperatureData;
47: Result := ReadSnowpackData;
48: Result := ReadTreatmentData(S);
49: Result := ReadTagData;
50: Result := Ulid.ReadLidData(TokList, Ntoks);
51: Result := ReadLidUsageData;
52: Result := ReadGroundwaterFlowEqn(S);
53: Result := ReadAdjustmentData; //(5.1.007)
else Result := 0;
end;
end;
function ParseImportLine(Line: String): Integer;
//-----------------------------------------------------------------------------
// Processes line of input from imported scenario or map file.
// (Not currently used.)
//-----------------------------------------------------------------------------
begin
Result := 0;
end;
procedure StripComment(const Line: String; var S: String);
//-----------------------------------------------------------------------------
// Strips comment (text following a ';') from a line of input.
// Ignores comment if it begins with ';;'.
//-----------------------------------------------------------------------------
var
P: Integer;
N: Integer;
C: String;
begin
C := '';
S := Trim(Line);
P := Pos(';', S);
if P > 0 then
begin
N := Length(S);
C := Copy(S, P+1, N);
if (Length(C) >= 1) and (C[1] <> ';') then
begin
if Length(Comment) > 0 then Comment := Comment + #13;
Comment := Comment + C;
end;
Delete(S, P, N);
end;
end;
function FindNewSection(const S: String): Integer;
//-----------------------------------------------------------------------------
// Checks if S matches any of the section heading key words.
//-----------------------------------------------------------------------------
var
K: Integer;
begin
for K := 0 to High(SectionWords) do
begin
if Pos(SectionWords[K], S) = 1 then
begin
Result := K;
Exit;
end;
end;
Result := -1;
end;
function StartNewSection(S: String): Integer;
//-----------------------------------------------------------------------------
// Begins reading a new section of the input file.
//-----------------------------------------------------------------------------
var
K : Integer;
begin
// Determine which new section to begin
K := FindNewSection(UpperCase(S));
if (K >= 0) then
begin
//Update section code
Section := K;
PrevID := '';
Result := 0;
end
else Result := ErrMsg(KEYWORD_ERR, S);
Comment := '';
end;
function ReadFile(var F: Textfile; const Fsize: Int64):Boolean;
//-----------------------------------------------------------------------------
// Reads each line of a SWMM input file.
//-----------------------------------------------------------------------------
var
Err : Integer;
ByteCount : Integer;
StepCount : Integer;
StepSize : Integer;
S : String;
begin
Result := True;
ErrCount := 0;
LineCount := 0;
Comment := '';
// Initialize progress meter settings
StepCount := MainForm.ProgressBar.Max div MainForm.ProgressBar.Step;
StepSize := Fsize div StepCount;
if StepSize < 1000 then StepSize := 0;
ByteCount := 0;
// Read each line of input file
Reset(F);
while not Eof(F) do
begin
Err := 0;
Readln(F, Line);
Inc(LineCount);
if StepSize > 0 then
begin
Inc(ByteCount, Length(Line));
MainForm.UpdateProgressBar(ByteCount, StepSize);
end;
// Strip out trailing spaces, control characters & comment
Line := TrimRight(Line);
StripComment(Line, S);
// Check if line begins a new input section
if (Pos('[', S) = 1) then Err := StartNewSection(S)
else
begin
//// Following code section modified for release 5.1.011. //// //(5.1.011)
// Check if line contains project title/notes
if (Section = 0) and (Length(Line) > 0) then
begin
if LeftStr(Line,2) <> ';;' then Err := ReadTitleData(Line);
end
// Check if line contains a control rule clause
else if (Section = 22) then Err := ReadControlData(Line)
// Check if line contains an event start/end dates
else if (Section = 54) then Err := ReadEventData(Trim(Line))
// If in some section, then process the input line
else
begin
// Break line into string tokens and parse their contents
Uutils.Tokenize(S, TokList, Ntoks);
if (Ntoks > 0) and (Section >= 0) then
begin
Err := ParseInpLine(S);
Comment := '';
end
// No current section -- file was probably not an EPA-SWMM file
else if (Ntoks > 0) then
begin
Result := False;
Exit;
end;
end;
end;
////
// Increment error count
if Err > 0 then Inc(ErrCount);
end; //End of file.
if ErrCount > MAX_ERRORS then ErrList.Add(
IntToStr(ErrCount-MAX_ERRORS) + TXT_MORE_ERRORS);
end;
procedure DisplayInpErrForm(const Fname: String);
//-----------------------------------------------------------------------------
// Displays Status Report form that lists any error messages.
//-----------------------------------------------------------------------------
begin
SysUtils.DeleteFile((TempReportFile));
TempReportFile := Uutils.GetTempFile(TempDir,'swmm');
ErrList.Insert(0, TXT_ERROR_REPORT + Fname + #13);
ErrList.SaveToFile(TempReportFile);
MainForm.MnuReportStatusClick(MainForm);
end;
procedure ReverseVertexLists;
//-----------------------------------------------------------------------------
// Reverses list of vertex points for each link in the project.
//-----------------------------------------------------------------------------
var
I, J: Integer;
begin
for I := 0 to MAXCLASS do
begin
if not Project.IsLink(I) then continue;
for J := 0 to Project.Lists[I].Count-1 do
if Project.GetLink(I, J).Vlist <> nil then
Project.GetLink(I, J).Vlist.Reverse;
end;
end;
procedure SetSubcatchCentroids;
//-----------------------------------------------------------------------------
// Determines the centroid of each subcatchment polygon.
//-----------------------------------------------------------------------------
var
I : Integer;
begin
for I := 0 to Project.Lists[SUBCATCH].Count - 1 do
begin
Project.GetSubcatch(SUBCATCH, I).SetCentroid;
end;
end;
procedure SetIDPtrs;
//-----------------------------------------------------------------------------
// Makes pointers to ID strings the ID property of objects.
//-----------------------------------------------------------------------------
var
I, J : Integer;
C : TSubcatch;
S : String;
begin
for I := 0 to MAXCLASS do
begin
if I = RAINGAGE then with Project.Lists[RAINGAGE] do
begin
for J := 0 to Count-1 do TRaingage(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsSubcatch(I) then with Project.Lists[SUBCATCH] do
begin
for J := 0 to Count-1 do
begin
C := TSubcatch(Objects[J]);
C.ID := PChar(Strings[J]);
S := Trim(C.Data[SUBCATCH_OUTLET_INDEX]);
C.OutSubcatch := FindSubcatch(S);
if C.OutSubcatch = nil then C.OutNode := FindNode(S);
end;
end
else if Project.IsNode(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TNode(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsLink(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TLink(Objects[J]).ID := PChar(Strings[J]);
end
else if I = TRANSECT then with Project.Lists[I] do
begin
for J := 0 to Count-1 do
begin
TTransect(Objects[J]).CheckData;
TTransect(Objects[J]).SetMaxDepth;
Project.SetTransectConduitDepth(Strings[J],
TTransect(Objects[J]).Data[TRANSECT_MAX_DEPTH]);
end;
end
else continue;
end;
end;
function ReadInpFile(const Fname: String):Boolean;
//-----------------------------------------------------------------------------
// Reads SWMM input data from a text file.
//-----------------------------------------------------------------------------
var
F : Textfile;
begin
// Try to open the file
Result := False;
AssignFile(F,Fname);
{$I-}
Reset(F);
{$I+}
if (IOResult = 0) then
begin
// Create stringlists
Screen.Cursor := crHourGlass;
MapExtentSet := False;
ErrList := TStringList.Create;
TokList := TStringList.Create;
SubcatchList := TStringList.Create;
NodeList := TStringList.Create;
LinkList := TStringList.Create;
FileType := ftInput;
InpFile := Fname;
try
// Read the file
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
SubcatchList.Sorted := True;
NodeList.Sorted := True;
LinkList.Sorted := True;
Section := -1;
Result := ReadFile(F, Uutils.GetFileSize(Fname));
if (Result = True) then
begin
// Establish pointers to ID names
SetIDPtrs;
end;
finally
// Free the stringlists
SubcatchList.Free;
NodeList.Free;
LinkList.Free;
TokList.Free;
MainForm.PageSetupDialog.Header.Text := Project.Title;
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
// Display errors if found & set map dimensions
if Result = True then
begin
if ErrList.Count > 0 then DisplayInpErrForm(Fname);
SetSubcatchCentroids;
SetMapDimensions;
end;
ErrList.Free;
end;
end;
// Close the input file
CloseFile(F);
end;
procedure ClearDefaultDates;
//-----------------------------------------------------------------------------
// Clears project's date/time settings.
//-----------------------------------------------------------------------------
begin
with Project.Options do
begin
Data[START_DATE_INDEX] := '';
Data[START_TIME_INDEX] := '';
Data[REPORT_START_DATE_INDEX] := '';
Data[REPORT_START_TIME_INDEX] := '';
Data[END_DATE_INDEX] := '';
Data[END_TIME_INDEX] := '';
end;
end;
procedure SetDefaultDates;
//-----------------------------------------------------------------------------
// Sets default values for project's date/time settings.
//-----------------------------------------------------------------------------
var
StartTime: TDateTime;
StartDate: TDateTime;
T: TDateTime;
D: TDateTime;
begin
with Project.Options do
begin
// Process starting date/time
try
StartDate := StrToDate(Data[START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do StartDate := Date;
end;
StartTime := Uutils.StrHoursToTime(Data[START_TIME_INDEX]);
if StartTime < 0 then StartTime := 0;
D := StartDate + StartTime;
Data[START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process reporting start date/time
try
D := StrToDate(Data[REPORT_START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[REPORT_START_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[REPORT_START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[REPORT_START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process ending date/time
try
D := StrToDate(Data[END_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[END_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[END_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[END_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
end;
end;
function OpenProject(const Fname: String): TInputFileType;
//-----------------------------------------------------------------------------
// Reads in project data from a file.
//-----------------------------------------------------------------------------
begin
// Show progress meter
ClearDefaultDates;
Screen.Cursor := crHourGlass;
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
// Use default map dimensions and backdrop settings
MapForm.Map.Dimensions := DefMapDimensions;
MapForm.Map.Backdrop := DefMapBackdrop;
// Do the following for non-temporary input files
if not SameText(Fname, Uglobals.TempInputFile) then
begin
// Create a backup file
if AutoBackup
then CopyFile(PChar(Fname), PChar(ChangeFileExt(Fname, '.bak')), FALSE);
// Retrieve project defaults from .INI file
if CompareText(ExtractFileExt(Fname), '.ini') <> 0
then Uinifile.ReadProjIniFile(ChangeFileExt(Fname, '.ini'));
end;
// Read and parse each line of input file
Result := iftNone;
if ReadInpFile(Fname) then Result := iftINP;
// Finish processing the input dataunit Uimport;
{-------------------------------------------------------------------}
{ Unit: Uimport.pas }
{ Project: EPA SWMM }
{ Version: 5.1 }
{ Date: 12/02/13 (5.1.001) }
{ 04/04/14 (5.1.003) }
{ 04/14/14 (5.1.004) }
{ 09/15/14 (5.1.007) }
{ 03/19/15 (5.1.008) }
{ 08/05/15 (5.1.010) }
{ 08/01/16 (5.1.011) }
{ Author: L. Rossman }
{ }
{ Delphi Pascal unit that imports a SWMM project's data from a }
{ a formatted text file. }
{ }
{ 5.1.011 - Support for reading [EVENTS] section added. }
{-------------------------------------------------------------------}
interface
uses
Classes, Forms, Controls, Dialogs, SysUtils, Windows, Math, StrUtils,
Uutils, Uglobals;
const
ITEMS_ERR = 1;
KEYWORD_ERR = 2;
SUBCATCH_ERR = 3;
NODE_ERR = 4;
LINK_ERR = 5;
LANDUSE_ERR = 6;
POLLUT_ERR = 7;
NUMBER_ERR = 8;
XSECT_ERR = 9;
TRANSECT_ERR = 10;
TIMESTEP_ERR = 11;
DATE_ERR = 12;
LID_ERR = 13;
MAX_ERRORS = 50;
type
TFileType = (ftInput, ftImport);
// These routines can be called from other units
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
function OpenProject(const Fname: String): TInputFileType;
function ReadInpFile(const Fname: String):Boolean;
procedure SetDefaultDates;
implementation
uses
Fmain, Fmap, Fstatus, Dxsect, Uexport, Uinifile, Uproject, Umap,
Ucoords, Uvertex, Uupdate, Dreporting, Ulid;
const
MSG_READING_PROJECT_DATA = 'Reading project data... ';
TXT_ERROR = 'Error ';
TXT_AT_LINE = ' at line ';
TXT_MORE_ERRORS = ' more errors found in file.';
TXT_ERROR_REPORT = 'Error Report for File ';
SectionWords : array[0..54] of PChar = //(5.1.011)
('[TITLE', //0
'[OPTION', //1
'[RAINGAGE', //2
'[HYDROGRAPH', //3
'[EVAPORATION', //4
'[SUBCATCHMENT', //5
'[SUBAREA', //6
'[INFILTRATION', //7
'[AQUIFER', //8
'[GROUNDWATER', //9
'[JUNCTION', //10
'[OUTFALL', //11
'[STORAGE', //12
'[DIVIDER', //13
'[CONDUIT', //14
'[PUMP', //15
'[ORIFICE', //16
'[WEIR', //17
'[OUTLET', //18
'[XSECTION', //19
'[TRANSECT', //20
'[LOSS', //21
'[CONTROL', //22
'[POLLUTANT', //23
'[LANDUSE', //24
'[BUILDUP', //25
'[WASHOFF', //26
'[COVERAGE', //27
'[INFLOW', //28
'[DWF', //29
'[PATTERN', //30
'[RDII', //31
'[LOAD', //32
'[CURVE', //33
'[TIMESERIES', //34
'[REPORT', //35
'[FILE', //36
'[MAP', //37
'[COORDINATES', //38
'[VERTICES', //39
'[POLYGONS', //40
'[SYMBOLS', //41
'[LABELS', //42
'[BACKDROP', //43
'[PROFILE', //44
'[TABLE', //45
'[TEMPERATURE', //46
'[SNOWPACK', //47
'[TREATMENT', //48
'[TAG', //49
'[LID_CONTROL', //50
'[LID_USAGE', //51
'[GWF', //52 //(5.1.007)
'[ADJUSTMENTS', //53 //(5.1.007)
'[EVENT'); //54 //(5.1.011)
var
FileType : TFileType;
InpFile : String;
ErrList : TStringlist;
SubcatchList : TStringlist;
NodeList : TStringlist;
LinkList : TStringlist;
TokList : TStringlist;
Ntoks : Integer;
Section : Integer;
LineCount : LongInt;
ErrCount : LongInt;
Line : String;
Comment : String;
TsectComment : String;
PrevID : String;
PrevIndex : Integer;
CurveType : Integer;
MapExtentSet : Boolean;
ManningsN : array[1..3] of String;
// These are deprecated attributes of a backdrop image
BackdropX : Extended;
BackdropY : Extended;
BackdropW : Extended;
BackdropH : Extended;
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
//-----------------------------------------------------------------------------
// Adds an error message for a specific error code to the list
// of errors encountered when reading an input file.
//-----------------------------------------------------------------------------
var
S: String;
begin
if ErrCount <= MAX_ERRORS then
begin
case ErrCode of
ITEMS_ERR: S := 'Too few items ';
KEYWORD_ERR: S := 'Unrecognized keyword (' + Name + ') ';
SUBCATCH_ERR: S := 'Undefined Subcatchment (' + Name + ') referenced ';
NODE_ERR: S := 'Undefined Node (' + Name + ') referenced ';
LINK_ERR: S := 'Undefined Link (' + Name + ') referenced ';
LANDUSE_ERR: S := 'Undefined Land Use (' + Name + ') referenced ';
POLLUT_ERR: S := 'Undefined Pollutant (' + Name + ') referenced ';
NUMBER_ERR: S := 'Illegal numeric value (' + Name + ') ';
XSECT_ERR: S := 'Illegal cross section for Link ' + Name + ' ';
TRANSECT_ERR: S := 'No Transect defined for these data ';
TIMESTEP_ERR: S := 'Illegal time step value ';
DATE_ERR: S := 'Illegal date/time value ';
LID_ERR: S := 'Undefined LID process (' + Name + ') referenced ';
else S := 'Unknown error ';
end;
S := S + 'at line ' + IntToStr(LineCount) + ':';
ErrList.Add(S);
if Section >= 0 then ErrList.Add(SectionWords[Section] + ']');
ErrList.Add(Line);
ErrList.Add('');
end;
Result := ErrCode;
end;
function FindSubcatch(const ID: String): TSubcatch;
//-----------------------------------------------------------------------------
// Finds a Subcatchment object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Atype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if SubcatchList.Find(ID, Index)
then Result := TSubcatch(SubcatchList.Objects[Index]);
end
else
begin
if (Project.FindSubcatch(ID, Atype, Index))
then Result := Project.GetSubcatch(Atype, Index);
end;
end;
function FindNode(const ID: String): TNode;
//-----------------------------------------------------------------------------
// Finds a Node object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Ntype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if NodeList.Find(ID, Index)
then Result := TNode(NodeList.Objects[Index]);
end
else
begin
if (Project.FindNode(ID, Ntype, Index))
then Result := Project.GetNode(Ntype, Index);
end;
end;
function FindLink(const ID: String): TLink;
//-----------------------------------------------------------------------------
// Finds a Link object given its ID name.
//-----------------------------------------------------------------------------
var
Index : Integer;
Ltype : Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if LinkList.Find(ID, Index)
then Result := TLink(LinkList.Objects[Index]);
end
else
begin
if (Project.FindLink(ID, Ltype, Index))
then Result := Project.GetLink(Ltype, Index);
end;
end;
function ReadTitleData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Adds Line of text to a project's title and notes.
//-----------------------------------------------------------------------------
begin
if Project.Lists[NOTES].Count = 0 then Project.Title := Line;
Project.Lists[NOTES].Add(Line);
Project.HasItems[NOTES] := True;
Result := 0;
end;
procedure ReadOldRaingageData(I: Integer; aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of parsed rain gage data using older format.
//-----------------------------------------------------------------------------
begin
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 2 then aGage.Data[GAGE_SERIES_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_DATA_FORMAT] := TokList[3];
if Ntoks > 4 then aGage.Data[GAGE_DATA_FREQ] := TokList[4];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 2 then aGage.Data[GAGE_FILE_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_STATION_NUM] := TokList[3];
end;
end;
procedure ReadNewRaingageData(aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of rain gage data using newer format.
//-----------------------------------------------------------------------------
var
I: Integer;
Fname: String;
begin
if Ntoks > 1 then aGage.Data[GAGE_DATA_FORMAT] := TokList[1];
if Ntoks > 2 then aGage.Data[GAGE_DATA_FREQ] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_SNOW_CATCH] := TokList[3];
if Ntoks > 4 then
begin
I := Uutils.FindKeyWord(TokList[4], RaingageOptions, 4);
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 5 then aGage.Data[GAGE_SERIES_NAME] := TokList[5];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 5 then
begin
Fname := TokList[5];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
aGage.Data[GAGE_FILE_NAME] := Fname;
end;
if Ntoks > 6 then aGage.Data[GAGE_STATION_NUM] := TokList[6];
if Ntoks > 7 then aGage.Data[GAGE_RAIN_UNITS] := TokList[7];
end;
end;
end;
function ReadRaingageData: Integer;
//-----------------------------------------------------------------------------
// Parses rain gage data from the input line.
//-----------------------------------------------------------------------------
var
aGage : TRaingage;
ID : String;
I : Integer;
begin
if Ntoks < 2 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end;
ID := TokList[0];
aGage := TRaingage.Create;
Uutils.CopyStringArray(Project.DefProp[RAINGAGE].Data, aGage.Data);
aGage.X := MISSING;
aGage.Y := MISSING;
aGage.Data[COMMENT_INDEX ] := Comment;
Project.Lists[RAINGAGE].AddObject(ID, aGage);
Project.HasItems[RAINGAGE] := True;
I := Uutils.FindKeyWord(TokList[1], RaingageOptions, 4);
if I >= 0
then ReadOldRaingageData(I, aGage)
else ReadNewRaingageData(aGage);
Result := 0;
end;
function ReadOldHydrographFormat(const I: Integer; UH: THydrograph): Integer;
//-----------------------------------------------------------------------------
// Reads older format of unit hydrograph parameters from a line of input.
//-----------------------------------------------------------------------------
var
J, K, N: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
N := 2;
for K := 1 to 3 do
begin
for J := 1 to 3 do
begin
UH.Params[I,J,K] := TokList[N];
Inc(N);
end;
end;
for J := 1 to 3 do
begin
UH.InitAbs[I,J,1] := '';
if Ntoks > N then UH.InitAbs[I,J,1] := TokList[N];
Inc(N);
for K := 2 to 3 do UH.InitAbs[I,J,K] := UH.InitAbs[I,J,1];
end;
end;
end;
function ReadHydrographData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII unit hydrograph data from a line of input.
//-----------------------------------------------------------------------------
var
I, J, K: Integer;
ID: String;
aUnitHyd: THydrograph;
Index: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Check if hydrograph ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[HYDROGRAPH].IndexOf(ID);
// If starting input for a new hydrograph then create it
if Index < 0 then
begin
aUnitHyd := THydrograph.Create;
Project.Lists[HYDROGRAPH].AddObject(ID, aUnitHyd);
Project.HasItems[HYDROGRAPH] := True;
Index := Project.Lists[HYDROGRAPH].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else aUnitHyd := THydrograph(Project.Lists[HYDROGRAPH].Objects[Index]);
// Parse rain gage name for 2-token line
if Ntoks = 2 then
begin
aUnitHyd.Raingage := TokList[1];
end
// Extract remaining hydrograph parameters
else if Ntoks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Determine month of year
I := Uutils.FindKeyWord(TokList[1], MonthLabels, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
// Determine if response type present - if not, process old format
K := Uutils.FindKeyWord(TokList[2], ResponseTypes, 3) + 1;
if K < 1 then Result := ReadOldHydrographFormat(I, aUnitHyd)
else
begin
// Extract R-T-K values
for J := 3 to 5 do
begin
aUnitHyd.Params[I,J-2,K] := TokList[J];
end;
// Extract IA parameters
for J := 6 to 8 do
begin
if J >= Ntoks then break
else aUnitHyd.InitAbs[I,J-5,K] := TokList[J];
end;
end;
end;
end;
end;
function ReadTemperatureData: Integer;
//-----------------------------------------------------------------------------
// Reads description of air temperature data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
I := Uutils.FindKeyWord(TokList[0], TempKeywords, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[0])
else case I of
0: begin // Time series
TempDataSource := 1;
TempTseries := TokList[1];
end;
1: begin // File
TempDataSource := 2;
TempFile := TokList[1];
if ExtractFilePath(TempFile) = '' then
TempFile := ExtractFilePath(Uglobals.InputFileName) + TempFile;
if Ntoks >= 3 then TempStartDate := TokList[2];
end;
2: begin // Wind speed
if SameText(TokList[1], 'MONTHLY') then
begin
if Ntoks < 14 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
WindType := MONTHLY_WINDSPEED;
for I := 1 to 12 do WindSpeed[I] := TokList[I+1];
end;
end
else if SameText(TokList[1], 'FILE') then WindType := FILE_WINDSPEED
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
3: begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 6 do SnowMelt[I] := TokList[I];
end;
4: begin
if Ntoks < 12 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
if SameText(TokList[1], 'IMPERVIOUS') then
for I := 1 to 10 do ADCurve[1][I] := TokList[I+1]
else if SameText(TokList[1], 'PERVIOUS') then
for I := 1 to 10 do ADCurve[2][I] := TokList[I+1]
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
end;
end;
function ReadEvaporationRates(Etype: Integer): Integer;
var
J: Integer;
begin
if (Etype <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
EvapType := Etype;
case EvapType of
CONSTANT_EVAP:
for J := 0 to 11 do EvapData[J] := TokList[1];
TSERIES_EVAP:
EvapTseries := TokList[1];
FILE_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
PanData[J-1] := TokList[J];
end;
MONTHLY_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
EvapData[J-1] := TokList[J];
end;
end;
Result := 0;
end;
end;
function ReadEvaporationData: Integer;
//-----------------------------------------------------------------------------
// Reads evaporation data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
I := Uutils.FindKeyWord(TokList[0], EvapOptions, 4);
if I >= 0 then Result := ReadEvaporationRates(I)
else if (I <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
if SameText(TokList[0], 'RECOVERY')
then RecoveryPat := TokList[1]
else if SameText(TokList[0], 'DRY_ONLY') then
begin
if SameText(TokList[1], 'NO') then EvapDryOnly := False
else if SameText(TokList[1], 'YES') then EvapDryOnly := True
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end
else Result := ErrMsg(KEYWORD_ERR, TokList[0]);
end;
end;
function ReadSubcatchmentData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := TSubcatch.Create;
SubcatchList.AddObject(ID, S);
S.X := MISSING;
S.Y := MISSING;
S.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[SUBCATCH].Data, S.Data);
S.Data[SUBCATCH_RAINGAGE_INDEX] := TokList[1];
S.Data[SUBCATCH_OUTLET_INDEX] := TokList[2];
S.Data[SUBCATCH_AREA_INDEX] := TokList[3];
S.Data[SUBCATCH_IMPERV_INDEX] := TokList[4];
S.Data[SUBCATCH_WIDTH_INDEX] := TokList[5];
S.Data[SUBCATCH_SLOPE_INDEX] := TokList[6];
S.Data[SUBCATCH_CURBLENGTH_INDEX] := TokList[7];
if Ntoks >= 9
then S.Data[SUBCATCH_SNOWPACK_INDEX] := TokList[8];
S.Data[COMMENT_INDEX ] := Comment;
Project.Lists[SUBCATCH].AddObject(ID, S);
Project.HasItems[SUBCATCH] := True;
Result := 0;
end;
end;
function ReadSubareaData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment sub-area data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
S.Data[SUBCATCH_IMPERV_N_INDEX] := TokList[1];
S.Data[SUBCATCH_PERV_N_INDEX] := TokList[2];
S.Data[SUBCATCH_IMPERV_DS_INDEX] := TokList[3];
S.Data[SUBCATCH_PERV_DS_INDEX] := TokList[4];
S.Data[SUBCATCH_PCTZERO_INDEX] := TokList[5];
S.Data[SUBCATCH_ROUTE_TO_INDEX] := TokList[6];
if Ntoks >= 8
then S.Data[SUBCATCH_PCT_ROUTED_INDEX] := TokList[7];
Result := 0;
end;
end;
end;
function ReadInfiltrationData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment infiltration data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
J : Integer;
Jmax : Integer;
begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
Jmax := Ntoks-1;
if Jmax > MAXINFILPROPS then Jmax := MAXINFILPROPS;
for J := 1 to Jmax do S.InfilData[J-1] := TokList[J];
Result := 0;
end;
end;
function ReadAquiferData: Integer;
//-----------------------------------------------------------------------------
// Reads aquifer data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
A : TAquifer;
I : Integer;
begin
if nToks < MAXAQUIFERPROPS then Result := ErrMsg(ITEMS_ERR, '') //(5.1.003)
else begin
ID := TokList[0];
A := TAquifer.Create;
//Uutils.CopyStringArray(Project.DefProp[AQUIFER].Data, A.Data); //(5.1.004)
Project.Lists[AQUIFER].AddObject(ID, A);
Project.HasItems[AQUIFER] := True;
for I := 0 to MAXAQUIFERPROPS-1 do A.Data[I] := TokList[I+1]; //(5.1.003)
if nToks >= MAXAQUIFERPROPS + 2 //(5.1.004)
then A.Data[MAXAQUIFERPROPS] := TokList[MAXAQUIFERPROPS+1] //(5.1.003)
else A.Data[MAXAQUIFERPROPS] := ''; //(5.1.003)
Result := 0;
end;
end;
function ReadGroundwaterData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment groundwater data from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
ID: String;
P: String;
J: Integer;
K: Integer;
begin
// Get subcatchment name
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else
begin
// Line contains GW flow parameters
if Ntoks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else begin
S.Groundwater.Clear;
// Read required parameters
for J := 1 to 9 do S.Groundwater.Add(TokList[J]);
// Read optional parameters
for K := 10 to 13 do
begin
if Ntoks > K then
begin
P := TokList[K];
if P = '*' then P := '';
S.Groundwater.Add(P);
end
else S.Groundwater.Add('');
end;
S.Data[SUBCATCH_GWATER_INDEX] := 'YES';
Result := 0;
end;
end;
end;
//// This function was re-written for release 5.1.007. //// //(5.1.007)
function ReadGroundwaterFlowEqn(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads GW flow math expression from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
N: Integer;
begin
// Check for enough tokens in line
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
// Get subcatchment object referred to by name
else begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
// Find position in Line where second token ends
N := Pos(TokList[1], Line) + Length(TokList[1]);
// Save remainder of line to correct type of GW flow equation
if SameText(TokList[1], 'LATERAL') then
S.GwLatFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else if SameText(TokList[1], 'DEEP') then
S.GwDeepFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
function ReadSnowpackData: Integer;
//-----------------------------------------------------------------------------
// Reads snowpack data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
P : TSnowpack;
I : Integer;
J : Integer;
Index: Integer;
begin
Result := 0;
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[1], SnowpackOptions, 7);
if I < 0
then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else begin
// Check if snow pack ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[SNOWPACK].IndexOf(ID);
// If starting input for a new snow pack then create it
if Index < 0 then
begin
P := TSnowpack.Create;
Project.Lists[SNOWPACK].AddObject(ID, P);
Project.HasItems[SNOWPACK] := True;
Index := Project.Lists[SNOWPACK].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else P := TSnowpack(Project.Lists[SNOWPACK].Objects[Index]);
// Parse line depending on data type
case I of
// Plowable area
0: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
for J := 1 to 6 do P.Data[1][J] := TokList[J+1];
P.FracPlowable := TokList[8];
end;
end;
// Impervious or Pervious area
1,
2: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else for J := 1 to 7 do P.Data[I+1][J] := TokList[J+1];
end;
// Plowing parameters
3: begin
for J := 1 to 6 do P.Plowing[J] := TokList[J+1];
if Ntoks >= 9 then P.Plowing[7] := TokList[8];
end;
end;
end;
end;
end;
function ReadJunctionData: Integer;
//-----------------------------------------------------------------------------
// Reads junction data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
begin
if Ntoks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := JUNCTION;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[JUNCTION].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
if Ntoks > 2 then aNode.Data[JUNCTION_MAX_DEPTH_INDEX] := TokList[2];
if Ntoks > 3 then aNode.Data[JUNCTION_INIT_DEPTH_INDEX] := TokList[3];
if Ntoks > 4 then aNode.Data[JUNCTION_SURCHARGE_DEPTH_INDEX] := TokList[4];
if Ntoks > 5 then aNode.Data[JUNCTION_PONDED_AREA_INDEX] := TokList[5];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[JUNCTION].AddObject(ID, aNode);
Project.HasItems[JUNCTION] := True;
Result := 0;
end;
end;
function ReadOutfallData: Integer;
//-----------------------------------------------------------------------------
// Reads outfall data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
I : Integer;
N : Integer; //(5.1.008)
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
N := 4; //(5.1.008)
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := OUTFALL;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTFALL].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
I := Uutils.FindKeyWord(TokList[2], OutfallOptions, 4);
if I < 0 then I := FREE_OUTFALL;
if (I > NORMAL_OUTFALL) and (Ntoks >= 4) then
begin
case I of
FIXED_OUTFALL: aNode.Data[OUTFALL_FIXED_STAGE_INDEX] := TokList[3];
TIDAL_OUTFALL: aNode.Data[OUTFALL_TIDE_TABLE_INDEX] := TokList[3];
TIMESERIES_OUTFALL: aNode.Data[OUTFALL_TIME_SERIES_INDEX] := TokList[3];
end;
N := 5;
if Ntoks >= 5 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[4]; // (5.1.008)
end
else if Ntoks >= 4 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[3]; //(5.1.008)
if Ntoks > N then aNode.Data[OUTFALL_ROUTETO_INDEX] := TokList[N]; //(5.1.008)
aNode.Data[OUTFALL_TYPE_INDEX] := OutfallOptions[I];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[OUTFALL].AddObject(ID, aNode);
Project.HasItems[OUTFALL] := True;
Result := 0;
end;
end;
//// The following function was modified for release 5.1.007. //// //(5.1.007)
function ReadStorageData: Integer;
//-----------------------------------------------------------------------------
// Reads storage unit data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
N : Integer;
X : Single;
begin
Result := 0;
N := 6;
if Ntoks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := STORAGE;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[STORAGE].Data, aNode.Data);
Project.Lists[STORAGE].AddObject(ID, aNode);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[STORAGE_MAX_DEPTH_INDEX] := TokList[2];
aNode.Data[STORAGE_INIT_DEPTH_INDEX] := TokList[3];
aNode.Data[STORAGE_GEOMETRY_INDEX] := TokList[4];
if CompareText(TokList[4], 'TABULAR') = 0 then
begin
aNode.Data[STORAGE_ATABLE_INDEX] := TokList[5];
end
else begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode.Data[STORAGE_ACOEFF_INDEX] := TokList[5];
aNode.Data[STORAGE_AEXPON_INDEX] := TokList[6];
if Ntoks >= 8 then aNode.Data[STORAGE_ACONST_INDEX] := TokList[7];
N := 8;
end;
end;
// Optional items
if (Result = 0) and (Ntoks > N) then
begin
// Ponded area
aNode.Data[STORAGE_PONDED_AREA_INDEX] := TokList[N];
// Evaporation factor
if Ntoks > N+1 then aNode.Data[STORAGE_EVAP_FACTOR_INDEX] := TokList[N+1];
// Constant seepage rate
if Ntoks = N+3 then
begin
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+2];
end
// Green-Ampt seepage parameters
else if Ntoks = N+5 then
begin
aNode.InfilData[STORAGE_SUCTION_INDEX] := TokList[N+2];
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+3];
aNode.InfilData[STORAGE_IMDMAX_INDEX] := TokList[N+4];
end;
end;
Uutils.GetSingle(aNode.InfilData[STORAGE_KSAT_INDEX ], X);
if (X > 0) then aNode.Data[STORAGE_SEEPAGE_INDEX] := 'YES'
else aNode.Data[STORAGE_SEEPAGE_INDEX] := 'NO';
aNode.Data[COMMENT_INDEX ] := Comment;
Project.HasItems[STORAGE] := True;
end;
end;
function ReadDividerData: Integer;
//-----------------------------------------------------------------------------
// Reads flow divider data from a line of input.
// (Corrected on 6/14/05)
//-----------------------------------------------------------------------------
var
N, J : Integer;
aNode: TNode;
ID : String;
begin
if Ntoks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Result := 0;
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := DIVIDER;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[DIVIDER].Data, aNode.Data);
Project.Lists[DIVIDER].AddObject(ID, aNode);
Project.HasItems[DIVIDER] := True;
aNode.Data[COMMENT_INDEX ] := Comment;
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[DIVIDER_LINK_INDEX] := TokList[2];
aNode.Data[DIVIDER_TYPE_INDEX] := TokList[3];
N := 5;
if SameText(TokList[3], 'OVERFLOW') then
begin
N := 4;
end
else if SameText(TokList[3], 'CUTOFF') then
begin
aNode.Data[DIVIDER_CUTOFF_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'TABULAR') then
begin
aNode.Data[DIVIDER_TABLE_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'WEIR') and (Ntoks >= 7) then
begin
aNode.Data[DIVIDER_QMIN_INDEX] := TokList[4];
aNode.Data[DIVIDER_DMAX_INDEX] := TokList[5];
aNode.Data[DIVIDER_QCOEFF_INDEX] := TokList[6];
N := 7;
end
else Result := ErrMsg(KEYWORD_ERR, TokList[3]);
if (Result = 0) and (Ntoks > N) then
begin
for J := N to Ntoks-1 do
aNode.Data[DIVIDER_MAX_DEPTH_INDEX + J - N] := TokList[J];
end;
end;
end;
function ReadConduitData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := CONDUIT;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[CONDUIT].Data, aLink.Data);
Project.Lists[CONDUIT].AddObject(ID, aLink);
Project.HasItems[CONDUIT] := True;
aLink.Data[CONDUIT_LENGTH_INDEX] := TokList[3];
aLink.Data[CONDUIT_ROUGHNESS_INDEX] := TokList[4];
aLink.Data[CONDUIT_INLET_HT_INDEX] := TokList[5];
aLink.Data[CONDUIT_OUTLET_HT_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_INIT_FLOW_INDEX] := TokList[7];
if Ntoks > 8 then aLink.Data[CONDUIT_MAX_FLOW_INDEX] := TokList[8];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadPumpData: Integer;
//-----------------------------------------------------------------------------
// Reads pump data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := PUMP;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[PUMP].Data, aLink.Data);
Project.Lists[PUMP].AddObject(ID, aLink);
Project.HasItems[PUMP] := True;
// Skip over PumpType if line has old format
if Uutils.FindKeyWord(TokList[3], PumpTypes, 5) >= 0 then N := 4
else N := 3;
if Ntoks <= N then Result := ErrMsg(ITEMS_ERR, '')
else
begin
aLink.Data[PUMP_CURVE_INDEX] := TokList[N];
if nToks > N+1 then aLink.Data[PUMP_STATUS_INDEX] := TokList[N+1];
if nToks > N+2 then aLink.Data[PUMP_STARTUP_INDEX] := TokList[N+2];
if nToks > N+3 then aLink.Data[PUMP_SHUTOFF_INDEX] := TokList[N+3];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
end;
function ReadOrificeData: Integer;
//-----------------------------------------------------------------------------
// Reads orifice data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := ORIFICE;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[ORIFICE].Data, aLink.Data);
Project.Lists[ORIFICE].AddObject(ID, aLink);
Project.HasItems[ORIFICE] := True;
aLink.Data[ORIFICE_TYPE_INDEX] := TokList[3];
aLink.Data[ORIFICE_BOTTOM_HT_INDEX] := TokList[4];
aLink.Data[ORIFICE_COEFF_INDEX] := TokList[5];
if nToks >= 7
then aLink.Data[ORIFICE_FLAPGATE_INDEX] := TokList[6];
if nToks >= 8
then aLink.Data[ORIFICE_ORATE_INDEX] := TokList[7];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadWeirData: Integer;
//-----------------------------------------------------------------------------
// Reads weir data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := WEIR;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[WEIR].Data, aLink.Data);
Project.Lists[WEIR].AddObject(ID, aLink);
Project.HasItems[WEIR] := True;
aLink.Data[WEIR_TYPE_INDEX] := TokList[3];
aLink.Data[WEIR_CREST_INDEX] := TokList[4];
aLink.Data[WEIR_COEFF_INDEX] := TokList[5];
//// Following section modified for release 5.1.007. //// //(5.1.007)
if (nToks >= 7) and not SameText(TokList[6], '*') then
aLink.Data[WEIR_FLAPGATE_INDEX] := TokList[6];
if (nToks >= 8) and not SameText(TokList[7], '*') then
aLink.Data[WEIR_CONTRACT_INDEX] := TokList[7];
if (nToks >= 9) and not SameText(TokList[8], '*') then
aLink.Data[WEIR_END_COEFF_INDEX] := TokList[8];
if (nToks >= 10) and not SameText(TokList[9], '*') then
aLink.Data[WEIR_SURCHARGE_INDEX] := TokList[9];
//// Following section added for release 5.1.010. //(5.1.010)
if (nToks >= 11) and not SameText(TokList[10], '*') then
aLink.Data[WEIR_ROAD_WIDTH_INDEX] := TokList[10];
if (nToks >= 12) and not SameText(TokList[11], '*') then
aLink.Data[WEIR_ROAD_SURF_INDEX] := TokList[11];
////
aLink.Data[COMMENT_INDEX] := Comment;
Result := 0;
end;
end;
end;
function ReadOutletData: Integer;
//-----------------------------------------------------------------------------
// Reads outlet data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := OUTLET;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTLET].Data, aLink.Data);
Project.Lists[OUTLET].AddObject(ID, aLink);
Project.HasItems[OUTLET] := True;
aLink.Data[OUTLET_CREST_INDEX] := TokList[3];
//... added for backwards compatibility
if SameText(TokList[4], 'TABULAR') then TokList[4] := 'TABULAR/DEPTH';
if SameText(TokList[4], 'FUNCTIONAL') then TokList[4] := 'FUNCTIONAL/DEPTH';
aLink.Data[OUTLET_TYPE_INDEX] := TokList[4];
if AnsiContainsText(TokList[4], 'TABULAR') then
begin
aLink.Data[OUTLET_QTABLE_INDEX] := TokList[5];
N := 6;
end
else begin
if Ntoks < 7 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end
else
begin
aLink.Data[OUTLET_QCOEFF_INDEX] := TokList[5];
aLink.Data[OUTLET_QEXPON_INDEX] := TokList[6];
N := 7;
end;
end;
if Ntoks > N then aLink.Data[OUTLET_FLAPGATE_INDEX] := TokList[N];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function GetXsectShape(const S: String): Integer;
//-----------------------------------------------------------------------------
// Finds the code number corresponding to cross section shape S.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
for I := 0 to High(Dxsect.XsectShapes) do
begin
if CompareText(S, Dxsect.XsectShapes[I].Text[1]) = 0 then
begin
Result := I;
Exit;
end;
end;
Result := -1;
end;
//// New procedure added to release 5.1.008. //// //(5.1.008)
procedure CheckForStdSize;
//-----------------------------------------------------------------------------
// Converts from old format for standard size ellipse and arch pipes
// to new format.
//-----------------------------------------------------------------------------
var
J: Integer;
X: Extended;
begin
// Old format had size code as 3rd token and 0 for 4th token
J := StrToIntDef(TokList[2], 0);
Uutils.GetExtended(TokList[3], X);
if (J > 0) and (X = 0) then
begin
// New format has 5th token as size code
TokList[4] := TokList[2];
TokList[2] := '0';
TokList[3] := '0';
end;
end;
function ReadXsectionData: Integer;
//-----------------------------------------------------------------------------
// Reads cross section data froma line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
ID : String;
aLink : TLink;
begin
if nToks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil)
then Result := ErrMsg(LINK_ERR, TokList[0])
else begin
I := GetXsectShape(TokList[1]);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else case aLink.Ltype of
CONDUIT:
begin
aLink.Data[CONDUIT_SHAPE_INDEX] := TokList[1];
if I = Dxsect.IRREG_SHAPE_INDEX then
begin
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM1_INDEX] := ''; //(5.1.008)
Result := 0;
end
else begin
if nToks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else begin
{
//// Added to release 5.1.008. //// //(5.1.008)
if I in [Dxsect.HORIZ_ELLIPSE_SHAPE_INDEX,
Dxsect.VERT_ELLIPSE_SHAPE_INDEX,
Dxsect.ARCH_SHAPE_INDEX]
then CheckForStdSize;
}
aLink.Data[CONDUIT_GEOM1_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM2_INDEX] := TokList[3];
aLink.Data[CONDUIT_GEOM3_INDEX] := TokList[4];
aLink.Data[CONDUIT_GEOM4_INDEX] := TokList[5];
if Ntoks > 6 then aLink.Data[CONDUIT_BARRELS_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_CULVERT_INDEX] := TokList[7];
if I = Dxsect.CUSTOM_SHAPE_INDEX then
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[3];
Result := 0;
end;
end;
end;
ORIFICE:
begin
if not I in [0, 1] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[ORIFICE_SHAPE_INDEX] := TokList[1];
aLink.Data[ORIFICE_HEIGHT_INDEX] := TokList[2];
aLink.Data[ORIFICE_WIDTH_INDEX] := TokList[3];
Result := 0;
end;
end;
WEIR:
begin
if not I in [2, 3, 4] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[WEIR_SHAPE_INDEX] := TokList[1];
aLink.Data[WEIR_HEIGHT_INDEX] := TokList[2];
aLink.Data[WEIR_WIDTH_INDEX] := TokList[3];
aLink.Data[WEIR_SLOPE_INDEX] := TokList[4];
Result := 0;
end;
end;
else Result := 0;
end;
end;
end;
end;
function ReadTransectData: Integer;
//-----------------------------------------------------------------------------
// Reads transect data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
K : Integer;
N : Integer;
ID : String;
Tsect : TTransect;
begin
Result := 0;
if SameText(TokList[0], 'NC') then
begin
if nToks < 4 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 3 do ManningsN[I] := TokList[I];
TsectComment := Comment;
Exit;
end;
if SameText(TokList[0], 'X1') then
begin
if nToks < 2 then Exit;
ID := TokList[1];
Tsect := TTransect.Create;
if Length(Comment) > 0 then TsectComment := Comment;
Tsect.Comment := TsectComment;
Project.Lists[TRANSECT].AddObject(ID, Tsect);
Project.HasItems[TRANSECT] := True;
Tsect.Data[TRANSECT_N_LEFT] := ManningsN[1];
Tsect.Data[TRANSECT_N_RIGHT] := ManningsN[2];
Tsect.Data[TRANSECT_N_CHANNEL] := ManningsN[3];
if nToks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
Tsect.Data[TRANSECT_X_LEFT] := TokList[3];
Tsect.Data[TRANSECT_X_RIGHT] := TokList[4];
Tsect.Data[TRANSECT_L_FACTOR] := TokList[7];
Tsect.Data[TRANSECT_X_FACTOR] := TokList[8];
Tsect.Data[TRANSECT_Y_FACTOR] := TokList[9];
end;
Exit;
end;
if SameText(TokList[0], 'GR') then
begin
N := Project.Lists[TRANSECT].Count;
if N = 0 then Result := ErrMsg(TRANSECT_ERR, '')
else begin
Tsect := TTransect(Project.Lists[TRANSECT].Objects[N-1]);
K := 1;
while K + 1 < Ntoks do
begin
Tsect.Ydata.Add(TokList[K]);
Tsect.Xdata.Add(TokList[K+1]);
K := K + 2;
end;
end;
Exit;
end;
end;
function ReadLossData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit loss data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLink : TLink;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil) then Result := ErrMsg(LINK_ERR, ID)
else if (aLink.Ltype <> CONDUIT) then Result := 0
else begin
aLink.Data[CONDUIT_ENTRY_LOSS_INDEX] := TokList[1];
aLink.Data[CONDUIT_EXIT_LOSS_INDEX] := TokList[2];
aLink.Data[CONDUIT_AVG_LOSS_INDEX] := TokList[3];
if nToks >= 5
then aLink.Data[CONDUIT_CHECK_VALVE_INDEX] := TokList[4];
if nToks >= 6
then aLink.Data[CONDUIT_SEEPAGE_INDEX] := TokList[5];
Result := 0;
end;
end;
end;
function ReadPollutantData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aPollut : TPollutant;
X : Single;
begin
if nToks < 5
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Add new pollutant to project
ID := TokList[0];
aPollut := TPollutant.Create;
Uutils.CopyStringArray(Project.DefProp[POLLUTANT].Data, aPollut.Data);
Project.Lists[POLLUTANT].AddObject(ID, aPollut);
Project.HasItems[POLLUTANT] := True;
// Parse units & concens.
aPollut.Data[POLLUT_UNITS_INDEX] := TokList[1];
aPollut.Data[POLLUT_RAIN_INDEX] := TokList[2];
aPollut.Data[POLLUT_GW_INDEX] := TokList[3];
// This is for old format
if (Ntoks = 5)
or ( (Ntoks = 7) and Uutils.GetSingle(TokList[6], X) ) then
begin
aPollut.Data[POLLUT_DECAY_INDEX] := TokList[4];
if nToks >= 7 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[5];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[6];
end;
end
// This is for new format
else
begin
aPollut.Data[POLLUT_II_INDEX] := TokList[4];
if Ntoks >= 6 then aPollut.Data[POLLUT_DECAY_INDEX] := TokList[5];
if nToks >= 7 then aPollut.Data[POLLUT_SNOW_INDEX] := TokList[6];
if Ntoks >= 9 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[7];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[8];
end;
if Ntoks >= 10 then aPollut.Data[POLLUT_DWF_INDEX] := TokList[9];
if Ntoks >= 11 then aPollut.Data[POLLUT_INIT_INDEX] := TokList[10];
end;
Result := 0;
end;
end;
function ReadLanduseData: Integer;
//-----------------------------------------------------------------------------
// Reads land use data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLanduse : TLanduse;
aNonPtSource : TNonpointSource;
J : Integer;
begin
ID := TokList[0];
aLanduse := TLanduse.Create;
for J := 0 to Project.Lists[POLLUTANT].Count - 1 do
begin
aNonPtSource := TNonpointSource.Create;
aLanduse.NonpointSources.AddObject(Project.Lists[POLLUTANT].Strings[J],
aNonPtSource);
end;
Project.Lists[LANDUSE].AddObject(ID, aLanduse);
Project.HasItems[LANDUSE] := True;
if Ntoks > 1 then aLanduse.Data[LANDUSE_CLEANING_INDEX] := TokList[1];
if Ntoks > 2 then aLanduse.Data[LANDUSE_AVAILABLE_INDEX] := TokList[2];
if Ntoks > 3 then aLanduse.Data[LANDUSE_LASTCLEAN_INDEX] := TokList[3];
aLanduse.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
function ReadBuildupData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant buildup function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.BuildupData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadWashoffData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant washoff function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.WashoffData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadCoverageData: Integer;
//-----------------------------------------------------------------------------
// Reads land use coverage data from a line of input.
//-----------------------------------------------------------------------------
var
MaxToks: Integer;
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
MaxToks := 3;
while (MaxToks <= nToks) do
begin
if not Uutils.GetSingle(TokList[MaxToks-1], X) then
begin
Result := ErrMsg(NUMBER_ERR, TokList[MaxToks-1]);
break;
end;
S1 := TokList[MaxToks-2];
I := S.LandUses.IndexOfName(S1);
S1 := TokList[MaxToks-2] + '=' + TokList[MaxToks-1];
if I < 0
then S.LandUses.Add(S1)
else S.Landuses[I] := S1;
MaxToks := MaxToks + 2;
end;
S.Data[SUBCATCH_LANDUSE_INDEX] := IntToStr(S.LandUses.Count);
end;
end;
function ReadTreatmentData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads pollutant treatment function from a line of input.
//-----------------------------------------------------------------------------
var
S : String;
aNode : TNode;
I : Integer;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0 then
Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
I := aNode.Treatment.IndexOfName(TokList[1]);
S := Copy(Line, Pos(TokList[1], Line)+Length(TokList[1]), Length(Line));
S := TokList[1] + '=' + Trim(S);
if I < 0 then
aNode.Treatment.Add(S)
else
aNode.Treatment[I] := S;
aNode.Data[NODE_TREAT_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadExInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads external inflow data from a line of input.
//-----------------------------------------------------------------------------
var
S : array[1..7] of String;
Inflow: String;
I : Integer;
aNode : TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S[1] := TokList[1]; // Constituent name
S[2] := TokList[2]; // Time Series name
S[3] := 'FLOW';
S[4] := '1.0';
if not SameText(S[1], 'FLOW') then
begin
if nToks >= 4 then S[3] := TokList[3] else S[3] := 'CONCEN';
if nToks >= 5 then S[4] := TokList[4] else S[4] := '1.0';
end;
if nToks >= 6 then S[5] := TokList[5] else S[5] := '1.0';
if nToks >= 7 then S[6] := TokList[6] else S[6] := '';
if nToks >= 8 then S[7] := TokList[7] else S[7] := '';
Inflow := S[1] + '=' + S[2] + #13 + S[3] + #13 + S[4] + #13 +
S[5] + #13 + S[6] + #13 + S[7];
I := aNode.DXInflow.IndexOfName(S[1]);
if I < 0 then aNode.DXInflow.Add(Inflow)
else aNode.DXInflow[I] := Inflow;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadDWInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads dry weather inflow data from a line of input.
//-----------------------------------------------------------------------------
var
M : Integer;
S : String;
S1 : String;
I : Integer;
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S1 := TokList[1];
S := S1 + '=' + TokList[2];
for M := 3 to Ntoks-1 do S := S + #13 + TokList[M];
I := aNode.DWInflow.IndexOfName(S1);
if I < 0
then aNode.DWInflow.Add(S)
else aNode.DWInflow[I] := S;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadPatternData: Integer;
//-----------------------------------------------------------------------------
// Reads time pattern data from a line of input.
//-----------------------------------------------------------------------------
var
ID: String;
Index: Integer;
aPattern: TPattern;
PatType: Integer;
J: Integer;
begin
if nToks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
J := 1;
ID := TokList[0];
Index := Project.Lists[PATTERN].IndexOf(ID);
if Index < 0 then
begin
aPattern := TPattern.Create;
aPattern.Comment := Comment;
Project.Lists[PATTERN].AddObject(ID, aPattern);
Project.HasItems[PATTERN] := True;
PatType := Uutils.FindKeyWord(TokList[1], PatternTypes, 7);
if PatType < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
exit;
end;
aPattern.PatternType := PatType;
J := 2;
end
else aPattern := TPattern(Project.Lists[PATTERN].Objects[Index]);
while (J < nToks) and (aPattern.Count <= High(aPattern.Data)) do
begin
aPattern.Data[aPattern.Count] := TokList[J];
Inc(J);
Inc(aPattern.Count);
end;
Result := 0;
end;
end;
function ReadIIInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII inflow data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
aNode.IIInflow.Clear;
aNode.IIInflow.Add(TokList[1]);
aNode.IIInflow.Add(TokList[2]);
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadLoadData: Integer;
//-----------------------------------------------------------------------------
// Reads initial pollutant loading data from a line of input.
//-----------------------------------------------------------------------------
var
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0
then Result := ErrMsg(POLLUT_ERR, TokList[1])
else if not Uutils.GetSingle(TokList[2], X)
then Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
S1 := TokList[1] + '=' + TokList[2];
I := S.Loadings.IndexOfName(TokList[1]);
if I < 0
then S.Loadings.Add(S1)
else S.Loadings[I] := S1;
S.Data[SUBCATCH_LOADING_INDEX] := 'YES';
Result := 0;
end;
end;
function ReadCurveData: Integer;
//-----------------------------------------------------------------------------
// Reads curve data from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
K : Integer;
L : Integer;
M : Integer;
ObjType : Integer;
ID : String;
aCurve : TCurve;
begin
// Check for too few tokens
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Check if curve ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then
begin
Index := PrevIndex;
ObjType := CurveType;
end
else Project.FindCurve(ID, ObjType, Index);
// Create new curve if ID not in data base
K := 2;
if Index < 0 then
begin
// Check for valid curve type keyword
M := -1;
for L := 0 to High(CurveTypeOptions) do
begin
if SameText(TokList[1], CurveTypeOptions[L]) then
begin
M := L;
break;
end;
end;
if M < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
Exit;
end;
// Convert curve type keyword index to a curve object category
case M of
0: ObjType := CONTROLCURVE;
1: ObjType := DIVERSIONCURVE;
2..5:
ObjType := PUMPCURVE;
6: ObjType := RATINGCURVE;
7: ObjType := SHAPECURVE;
8: ObjType := STORAGECURVE;
9: ObjType := TIDALCURVE;
end;
// Create a new curve object
aCurve := TCurve.Create;
aCurve.Comment := Comment;
aCurve.CurveType := TokList[1];
if ObjType = PUMPCURVE
then aCurve.CurveCode := M - 1
else aCurve.CurveCode := 0;
Project.Lists[ObjType].AddObject(ID, aCurve);
Project.HasItems[ObjType] := True;
Index := Project.Lists[ObjType].Count - 1;
PrevID := ID;
PrevIndex := Index;
CurveType := ObjType;
K := 3;
end;
// Add x,y values to the list maintained by the curve
aCurve := TCurve(Project.Lists[ObjType].Objects[Index]);
while K <= nToks-1 do
begin
aCurve.Xdata.Add(TokList[K-1]);
aCurve.Ydata.Add(TokList[K]);
K := K + 2;
end;
Result := 0;
end;
end;
function ReadTimeseriesData: Integer;
//-----------------------------------------------------------------------------
// Reads time series data from a line of input.
//-----------------------------------------------------------------------------
const
NEEDS_DATE = 1;
NEEDS_TIME = 2;
NEEDS_VALUE = 3;
var
Index : Integer;
State : Integer;
K : Integer;
ID : String;
StrDate : String;
aTseries : TTimeseries;
begin
// Check for too few tokens
Result := -1;
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '');
// Check if series ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then Index := PrevIndex
else Index := Project.Lists[TIMESERIES].IndexOf(ID);
// If starting input for a new series then create it
if Index < 0 then
begin
aTseries := TTimeseries.Create;
aTseries.Comment := Comment;
Project.Lists[TIMESERIES].AddObject(ID,aTseries);
Project.HasItems[TIMESERIES] := True;
Index := Project.Lists[TIMESERIES].Count - 1;
PrevID := ID;
PrevIndex := Index;
end;
aTseries := TTimeseries(Project.Lists[TIMESERIES].Objects[Index]);
// Check if external file name used
if SameText(TokList[1], 'FILE') then
begin
aTseries.Filename := TokList[2];
Result := 0;
Exit;
end;
// Add values to the list maintained by the timeseries
State := NEEDS_DATE;
K := 1;
while K < nToks do
begin
case State of
NEEDS_DATE:
begin
try
StrDate := Uutils.ConvertDate(TokList[K]);
StrToDate(StrDate, MyFormatSettings);
aTseries.Dates.Add(StrDate);
Inc(K);
if K >= nToks then break;
except
On EconvertError do aTseries.Dates.Add('');
end;
State := NEEDS_TIME;
end;
NEEDS_TIME:
begin
aTseries.Times.Add(TokList[K]);
Inc(K);
if K >= nToks then break;
State := NEEDS_VALUE;
end;
NEEDS_VALUE:
begin
aTseries.Values.Add(TokList[K]);
Result := 0;
State := NEEDS_DATE;
Inc(K);
end;
end;
end;
if Result = -1 then Result := ErrMsg(ITEMS_ERR, '');
end;
function ReadControlData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads a control rule statement from line of input.
//-----------------------------------------------------------------------------
begin
Project.ControlRules.Add(Line);
Result := 0;
end;
function ReadLidUsageData: Integer;
//-----------------------------------------------------------------------------
// Reads LID usage data from line of input.
//-----------------------------------------------------------------------------
var
aSubcatch: TSubcatch;
begin
aSubcatch := FindSubcatch(TokList[0]);
if aSubcatch = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else Result := Ulid.ReadLIDUsageData(aSubcatch, TokList, Ntoks);
end;
procedure ReadReportOption(Index: Integer);
begin
if (Ntoks >= 2) and SameText(TokList[1], 'YES') then
Project.Options.Data[Index] := 'YES'
else
Project.Options.Data[Index] := 'NO';
end;
function ReadReportData: Integer;
//-----------------------------------------------------------------------------
// Reads reporting options from a line of input.
//-----------------------------------------------------------------------------
begin
if SameText(TokList[0], 'CONTROLS')
then ReadReportOption(REPORT_CONTROLS_INDEX)
else if SameText(TokList[0], 'INPUT')
then ReadReportOption(REPORT_INPUT_INDEX)
else ReportingForm.Import(TokList, Ntoks);
Result := 0;
end;
function ReadFileData: Integer;
//-----------------------------------------------------------------------------
// Reads interface file usage from a line of input.
//-----------------------------------------------------------------------------
var
Fname: String;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Fname := TokList[2];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
Project.IfaceFiles.Add(TokList[0] + ' ' + TokList[1] + ' ' +
'"' + Fname + '"');
Result := 0;
end;
end;
//// This function was added to release 5.1.007. //// //(5.1.007)
function ReadAdjustmentData: Integer;
//-----------------------------------------------------------------------------
// Reads climate adjustments from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then exit;
if SameText(TokList[0], 'Temperature') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then TempAdjust[I] := ''
else TempAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Evaporation') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then EvapAdjust[I] := ''
else EvapAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Rainfall') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then RainAdjust[I] := ''
else RainAdjust[I] := TokList[I+1];
end;
end
//// Added to release 5.1.008. //// //(5.1.008)
else if SameText(TokList[0], 'Conductivity') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then CondAdjust[I] := ''
else CondAdjust[I] := TokList[I+1];
end;
end;
////////////////////////////////////////////////////////
end;
//// This function was added to release 5.1.011. //// //(5.1.011)
function ReadEventData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads hydraulic event data from a line of input.
//-----------------------------------------------------------------------------
begin
Result := 0;
if Length(Line) = 0 then exit;
if LeftStr(Line,2) = ';;' then exit;
Project.Events.Add(Line);
end;
function ReadOptionData: Integer;
//-----------------------------------------------------------------------------
// Reads an analysis option from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
S : String;
S2: String;
I : Integer;
X : Single;
T : Extended;
begin
// Check which keyword applies
Result := 0;
if Ntoks < 2 then exit;
Keyword := TokList[0];
if SameText(Keyword, 'TEMPDIR') then exit;
Index := Uutils.FindKeyWord(Keyword, OptionLabels, 17);
case Index of
-1: Result := ErrMsg(KEYWORD_ERR, Keyword);
ROUTING_MODEL_INDEX:
begin
if SameText(TokList[1], 'NONE') then
begin
Project.Options.Data[IGNORE_ROUTING_INDEX] := 'YES';
Exit;
end;
I := Uutils.FindKeyWord(TokList[1], OldRoutingOptions, 3);
if I >= 0 then TokList[1] := RoutingOptions[I];
end;
START_DATE_INDEX, REPORT_START_DATE_INDEX, END_DATE_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
try
StrToDate(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
START_TIME_INDEX, REPORT_START_TIME_INDEX, END_TIME_INDEX:
begin
S := TokList[1];
try
StrToTime(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
SWEEP_START_INDEX, SWEEP_END_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
S2 := S + '/1947';
try
StrToDate(S2, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
WET_STEP_INDEX, DRY_STEP_INDEX, REPORT_STEP_INDEX:
begin
S := TokList[1];
if Uutils.StrHoursToTime(S) = -1 then Result := ErrMsg(TIMESTEP_ERR, '');
end;
ROUTING_STEP_INDEX:
begin
S := TokList[1];
T := 0.0;
if not Uutils.GetExtended(S, T) then
begin
T := Uutils.StrHoursToTime(S)*86400.;
if T <= 0.0 then Result := ErrMsg(TIMESTEP_ERR, '')
else TokList[1] := Format('%.0f',[T]);
end;
end;
VARIABLE_STEP_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
TokList[1] := IntToStr(Round(100.0*X))
else
TokList[1] := '0';
end;
INERTIAL_DAMPING_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
begin
if X = 0 then TokList[1] := 'NONE'
else TokList[1] := 'PARTIAL';
end;
end;
// This option is now fixed to SWMM 4.
COMPATIBILITY_INDEX:
begin
TokList[1] := '4';
end;
MIN_ROUTE_STEP_INDEX, //(5.1.008)
LENGTHEN_STEP_INDEX,
MIN_SURFAREA_INDEX,
MIN_SLOPE_INDEX,
MAX_TRIALS_INDEX,
HEAD_TOL_INDEX,
SYS_FLOW_TOL_INDEX,
LAT_FLOW_TOL_INDEX:
begin
Uutils.GetSingle(TokList[1], X);
if X <= 0 then TokList[1] := '0';
end;
NORMAL_FLOW_LTD_INDEX:
begin
if SameText(TokList[1], 'NO') or SameText(TokList[1], 'SLOPE')
then TokList[1] := 'SLOPE'
else if SameText(TokList[1], 'YES') or SameText(TokList[1], 'FROUDE')
then TokList[1] := 'FROUDE'
else if SameText(TokList[1], 'BOTH') then TokList[1] := 'BOTH'
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
FORCE_MAIN_EQN_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], ForceMainEqnOptions, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := ForceMainEqnOptions[I];
end;
LINK_OFFSETS_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], LinkOffsetsOptions, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := LinkOffsetsOptions[I];
end;
IGNORE_RAINFALL_INDEX,
IGNORE_SNOWMELT_INDEX,
IGNORE_GRNDWTR_INDEX,
IGNORE_ROUTING_INDEX,
IGNORE_QUALITY_INDEX:
begin
if not SameText(TokList[1], 'YES') and not SameText(TokList[1], 'NO')
then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
//// Following section added to release 5.1.010. //// //(5.1.010)
NUM_THREADS_INDEX:
begin
I := StrToIntDef(TokList[1], 1);
if I < 0 then I := 1;
if (I = 0) or (I > Uutils.GetCPUs) then I := Uutils.GetCPUs;
TokList[1] := IntToStr(I);
end;
////
end;
if Result = 0 then Project.Options.Data[Index] := TokList[1];
end;
function ReadTagData: Integer;
//-----------------------------------------------------------------------------
// Reads in tag data from a line of input.
//-----------------------------------------------------------------------------
const
TagTypes: array[0..3] of PChar = ('Gage', 'Subcatch', 'Node', 'Link');
var
I, J : Integer;
aNode: TNode;
aLink: TLink;
begin
Result := 0;
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[0], TagTypes, 4);
case I of
-1: Result := ErrMsg(KEYWORD_ERR, TokList[0]);
0: begin
J := Project.Lists[RAINGAGE].IndexOf(TokList[1]);
if J >= 0 then with Project.GetGage(J) do Data[TAG_INDEX] := TokList[2];
end;
1: begin
J := Project.Lists[SUBCATCH].IndexOf(TokList[1]);
if J >= 0 then with Project.GetSubcatch(SUBCATCH, J) do
Data[TAG_INDEX] := TokList[2];
end;
2: begin
aNode := FindNode(TokList[1]);
if (aNode <> nil) then aNode.Data[TAG_INDEX] := TokList[2];
end;
3: begin
aLink := FindLink(TokList[1]);
if (aLink <> nil) then aLink.Data[TAG_INDEX] := TokList[2];
end;
end;
end;
end;
function ReadSymbolData: Integer;
//-----------------------------------------------------------------------------
// Reads rain gage coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
J : Integer;
X, Y : Extended;
aGage : TRaingage;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the gage ID in the database
J := Project.Lists[RAINGAGE].IndexOf(TokList[0]);
// If gage exists then assign it X & Y coordinates
if (J >= 0) then
begin
aGage := Project.GetGage(J);
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aGage.X := X;
aGage.Y := Y;
end;
end;
end;
end;
function ReadMapData: Integer;
//-----------------------------------------------------------------------------
// Reads map dimensions data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
Index : Integer;
Keyword : String;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, MapWords, 4);
case Index of
0: // Map dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for I := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Dimensions do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
MapExtentSet := True;
end;
end;
end;
1: //Map units
if Ntoks > 1 then
begin
I := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
with MapForm.Map.Dimensions do
begin
if Units = muDegrees then Digits := MAXDEGDIGITS
else Digits := Umap.DefMapDimensions.Digits;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadCoordData: Integer;
//-----------------------------------------------------------------------------
// Reads node coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aNode : TNode;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the node ID in the database
aNode := FindNode(TokList[0]);
// If node exists then assign it X & Y coordinates
if (aNode <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aNode.X := X;
aNode.Y := Y;
end;
end;
end;
end;
function ReadVertexData: Integer;
//-----------------------------------------------------------------------------
// Reads link vertex coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aLink : TLink;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the link ID in the database
aLink := FindLink(TokList[0]);;
// If link exists then assign it X & Y coordinates
if (aLink <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else aLink.Vlist.Add(X, Y);
end;
end;
end;
function ReadPolygonData: Integer;
//-----------------------------------------------------------------------------
// Reads polygon coordinates associated with subcatchment outlines.
//-----------------------------------------------------------------------------
var
Index : Integer;
X, Y : Extended;
S : TSubcatch;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the subcatchment ID in the database
S := nil;
Index := Project.Lists[SUBCATCH].IndexOf(TokList[0]);
if Index >= 0 then S := Project.GetSubcatch(SUBCATCH, Index);
// If subcatchment exists then add a new vertex to it
if (S <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else S.Vlist.Add(X, Y);
end;
end;
end;
function ReadLabelData: Integer;
//-----------------------------------------------------------------------------
// Reads map label data from a line of input.
//-----------------------------------------------------------------------------
var
Ntype : Integer;
Index : Integer;
X, Y : Extended;
S : String;
aMapLabel: TMapLabel;
begin
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
if not Uutils.GetExtended(TokList[0], X) then
Result := ErrMsg(NUMBER_ERR, TokList[0])
else if not Uutils.GetExtended(TokList[1], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else begin
S := TokList[2];
aMapLabel := TMapLabel.Create;
aMapLabel.X := X;
aMapLabel.Y := Y;
Project.Lists[MAPLABEL].AddObject(S, aMapLabel);
Index := Project.Lists[MAPLABEL].Count - 1;
aMapLabel.Text := PChar(Project.Lists[MAPLABEL].Strings[Index]);
Project.HasItems[MAPLABEL] := True;
if Ntoks >= 4 then
begin
if (Length(TokList[3]) > 0) and
Project.FindNode(TokList[3], Ntype, Index) then
aMapLabel.Anchor := Project.GetNode(Ntype, Index);
end;
if Ntoks >= 5 then aMapLabel.FontName := TokList[4];
if Ntoks >= 6 then aMapLabel.FontSize := StrToInt(TokList[5]);
if Ntoks >= 7 then
if StrToInt(TokList[6]) = 1 then aMapLabel.FontBold := True;
if Ntoks >= 8 then
if StrToInt(TokList[7]) = 1 then aMapLabel.FontItalic := True;
Result := 0;
end;
end;
end;
function ReadBackdropData: Integer;
//-----------------------------------------------------------------------------
// Reads map backdrop image information from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
I : Integer;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, BackdropWords, 4);
case Index of
0: //Backdrop file
if Ntoks > 1 then MapForm.Map.Backdrop.Filename := TokList[1];
1: // Backdrop dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for i := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Backdrop do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
end;
end;
end;
2: //Map units - deprecated
if Ntoks > 1 then
begin
i := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
end;
3, 4: //Backdrop offset or scaling -- deprecated
begin
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
else if not Uutils.GetExtended(TokList[1], X[1]) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], X[2]) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
if Index = 3 then
begin
BackdropX := X[1];
BackdropY := X[2];
end
else
begin
BackdropW := X[1];
BackdropH := X[2];
end;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadProfileData: Integer;
//-----------------------------------------------------------------------------
// Reads profile plot data from a line of input.
//-----------------------------------------------------------------------------
var
I, J: Integer;
S : String;
begin
Result := 0;
if (Ntoks < 2) then Exit;
// Locate the profile name in the database
I := Project.ProfileNames.IndexOf(TokList[0]);
// If profile does not exist then create it
if (I < 0) then
begin
Project.ProfileNames.Add(TokList[0]);
I := Project.ProfileNames.Count-1;
S := '';
Project.ProfileLinks.Add(S);
end
else S := Project.ProfileLinks[I] + #13;
// Add each remaining token to the list of links in the profile
S := S + TokList[1];
for J := 2 to Ntoks-1 do
S := S + #13 + TokList[J];
Project.ProfileLinks[I] := S;
end;
procedure SetMapDimensions;
//-----------------------------------------------------------------------------
// Determines map dimensions based on range of object coordinates.
//-----------------------------------------------------------------------------
begin
with MapForm.Map do
begin
// Dimensions not provided in [MAP] section
if not MapExtentSet then
begin
// Dimensions were provided in [BACKDROP] section
if (Backdrop.LowerLeft.X <> Backdrop.UpperRight.X) then
begin
// Interpret these as map dimensions
Dimensions.LowerLeft := Backdrop.LowerLeft;
Dimensions.UpperRight := Backdrop.UpperRight;
// Compute backdrop dimensions from Offset and Scale values
Backdrop.LowerLeft.X := BackdropX;
Backdrop.LowerLeft.Y := BackdropY - BackdropH;
Backdrop.UpperRight.X := BackdropX + BackdropW;
Backdrop.UpperRight.Y := BackdropY;
end
// No dimensions of any kind provided
else with Dimensions do
Ucoords.GetCoordExtents(LowerLeft.X, LowerLeft.Y,
UpperRight.X, UpperRight.Y);
end;
end;
end;
function ParseInpLine(S: String): Integer;
//-----------------------------------------------------------------------------
// Parses current input line depending on current section of input file.
//-----------------------------------------------------------------------------
begin
case Section of
1: Result := ReadOptionData;
2: Result := ReadRaingageData;
3: Result := ReadHydrographData;
4: Result := ReadEvaporationData;
5: Result := ReadSubcatchmentData;
6: Result := ReadSubareaData;
7: Result := ReadInfiltrationData;
8: Result := ReadAquiferData;
9: Result := ReadGroundwaterData;
10: Result := ReadJunctionData;
11: Result := ReadOutfallData;
12: Result := ReadStorageData;
13: Result := ReadDividerData;
14: Result := ReadConduitData;
15: Result := ReadPumpData;
16: Result := ReadOrificeData;
17: Result := ReadWeirData;
18: Result := ReadOutletData;
19: Result := ReadXsectionData;
20: Result := ReadTransectData;
21: Result := ReadLossData;
//22: ReadControlData called directly from ReadFile
23: Result := ReadPollutantData;
24: Result := ReadLanduseData;
25: Result := ReadBuildupData;
26: Result := ReadWashoffData;
27: Result := ReadCoverageData;
28: Result := ReadExInflowData;
29: Result := ReadDWInflowData;
30: Result := ReadPatternData;
31: Result := ReadIIInflowData;
32: Result := ReadLoadData;
33: Result := ReadCurveData;
34: Result := ReadTimeseriesData;
35: Result := ReadReportData;
36: Result := ReadFileData;
37: Result := ReadMapData;
38: Result := ReadCoordData;
39: Result := ReadVertexdata;
40: Result := ReadPolygonData;
41: Result := ReadSymbolData;
42: Result := ReadLabelData;
43: Result := ReadBackdropData;
44: Result := ReadProfileData;
45: Result := ReadCurveData;
46: Result := ReadTemperatureData;
47: Result := ReadSnowpackData;
48: Result := ReadTreatmentData(S);
49: Result := ReadTagData;
50: Result := Ulid.ReadLidData(TokList, Ntoks);
51: Result := ReadLidUsageData;
52: Result := ReadGroundwaterFlowEqn(S);
53: Result := ReadAdjustmentData; //(5.1.007)
else Result := 0;
end;
end;
function ParseImportLine(Line: String): Integer;
//-----------------------------------------------------------------------------
// Processes line of input from imported scenario or map file.
// (Not currently used.)
//-----------------------------------------------------------------------------
begin
Result := 0;
end;
procedure StripComment(const Line: String; var S: String);
//-----------------------------------------------------------------------------
// Strips comment (text following a ';') from a line of input.
// Ignores comment if it begins with ';;'.
//-----------------------------------------------------------------------------
var
P: Integer;
N: Integer;
C: String;
begin
C := '';
S := Trim(Line);
P := Pos(';', S);
if P > 0 then
begin
N := Length(S);
C := Copy(S, P+1, N);
if (Length(C) >= 1) and (C[1] <> ';') then
begin
if Length(Comment) > 0 then Comment := Comment + #13;
Comment := Comment + C;
end;
Delete(S, P, N);
end;
end;
function FindNewSection(const S: String): Integer;
//-----------------------------------------------------------------------------
// Checks if S matches any of the section heading key words.
//-----------------------------------------------------------------------------
var
K: Integer;
begin
for K := 0 to High(SectionWords) do
begin
if Pos(SectionWords[K], S) = 1 then
begin
Result := K;
Exit;
end;
end;
Result := -1;
end;
function StartNewSection(S: String): Integer;
//-----------------------------------------------------------------------------
// Begins reading a new section of the input file.
//-----------------------------------------------------------------------------
var
K : Integer;
begin
// Determine which new section to begin
K := FindNewSection(UpperCase(S));
if (K >= 0) then
begin
//Update section code
Section := K;
PrevID := '';
Result := 0;
end
else Result := ErrMsg(KEYWORD_ERR, S);
Comment := '';
end;
function ReadFile(var F: Textfile; const Fsize: Int64):Boolean;
//-----------------------------------------------------------------------------
// Reads each line of a SWMM input file.
//-----------------------------------------------------------------------------
var
Err : Integer;
ByteCount : Integer;
StepCount : Integer;
StepSize : Integer;
S : String;
begin
Result := True;
ErrCount := 0;
LineCount := 0;
Comment := '';
// Initialize progress meter settings
StepCount := MainForm.ProgressBar.Max div MainForm.ProgressBar.Step;
StepSize := Fsize div StepCount;
if StepSize < 1000 then StepSize := 0;
ByteCount := 0;
// Read each line of input file
Reset(F);
while not Eof(F) do
begin
Err := 0;
Readln(F, Line);
Inc(LineCount);
if StepSize > 0 then
begin
Inc(ByteCount, Length(Line));
MainForm.UpdateProgressBar(ByteCount, StepSize);
end;
// Strip out trailing spaces, control characters & comment
Line := TrimRight(Line);
StripComment(Line, S);
// Check if line begins a new input section
if (Pos('[', S) = 1) then Err := StartNewSection(S)
else
begin
//// Following code section modified for release 5.1.011. //// //(5.1.011)
// Check if line contains project title/notes
if (Section = 0) and (Length(Line) > 0) then
begin
if LeftStr(Line,2) <> ';;' then Err := ReadTitleData(Line);
end
// Check if line contains a control rule clause
else if (Section = 22) then Err := ReadControlData(Line)
// Check if line contains an event start/end dates
else if (Section = 54) then Err := ReadEventData(Trim(Line))
// If in some section, then process the input line
else
begin
// Break line into string tokens and parse their contents
Uutils.Tokenize(S, TokList, Ntoks);
if (Ntoks > 0) and (Section >= 0) then
begin
Err := ParseInpLine(S);
Comment := '';
end
// No current section -- file was probably not an EPA-SWMM file
else if (Ntoks > 0) then
begin
Result := False;
Exit;
end;
end;
end;
////
// Increment error count
if Err > 0 then Inc(ErrCount);
end; //End of file.
if ErrCount > MAX_ERRORS then ErrList.Add(
IntToStr(ErrCount-MAX_ERRORS) + TXT_MORE_ERRORS);
end;
procedure DisplayInpErrForm(const Fname: String);
//-----------------------------------------------------------------------------
// Displays Status Report form that lists any error messages.
//-----------------------------------------------------------------------------
begin
SysUtils.DeleteFile((TempReportFile));
TempReportFile := Uutils.GetTempFile(TempDir,'swmm');
ErrList.Insert(0, TXT_ERROR_REPORT + Fname + #13);
ErrList.SaveToFile(TempReportFile);
MainForm.MnuReportStatusClick(MainForm);
end;
procedure ReverseVertexLists;
//-----------------------------------------------------------------------------
// Reverses list of vertex points for each link in the project.
//-----------------------------------------------------------------------------
var
I, J: Integer;
begin
for I := 0 to MAXCLASS do
begin
if not Project.IsLink(I) then continue;
for J := 0 to Project.Lists[I].Count-1 do
if Project.GetLink(I, J).Vlist <> nil then
Project.GetLink(I, J).Vlist.Reverse;
end;
end;
procedure SetSubcatchCentroids;
//-----------------------------------------------------------------------------
// Determines the centroid of each subcatchment polygon.
//-----------------------------------------------------------------------------
var
I : Integer;
begin
for I := 0 to Project.Lists[SUBCATCH].Count - 1 do
begin
Project.GetSubcatch(SUBCATCH, I).SetCentroid;
end;
end;
procedure SetIDPtrs;
//-----------------------------------------------------------------------------
// Makes pointers to ID strings the ID property of objects.
//-----------------------------------------------------------------------------
var
I, J : Integer;
C : TSubcatch;
S : String;
begin
for I := 0 to MAXCLASS do
begin
if I = RAINGAGE then with Project.Lists[RAINGAGE] do
begin
for J := 0 to Count-1 do TRaingage(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsSubcatch(I) then with Project.Lists[SUBCATCH] do
begin
for J := 0 to Count-1 do
begin
C := TSubcatch(Objects[J]);
C.ID := PChar(Strings[J]);
S := Trim(C.Data[SUBCATCH_OUTLET_INDEX]);
C.OutSubcatch := FindSubcatch(S);
if C.OutSubcatch = nil then C.OutNode := FindNode(S);
end;
end
else if Project.IsNode(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TNode(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsLink(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TLink(Objects[J]).ID := PChar(Strings[J]);
end
else if I = TRANSECT then with Project.Lists[I] do
begin
for J := 0 to Count-1 do
begin
TTransect(Objects[J]).CheckData;
TTransect(Objects[J]).SetMaxDepth;
Project.SetTransectConduitDepth(Strings[J],
TTransect(Objects[J]).Data[TRANSECT_MAX_DEPTH]);
end;
end
else continue;
end;
end;
function ReadInpFile(const Fname: String):Boolean;
//-----------------------------------------------------------------------------
// Reads SWMM input data from a text file.
//-----------------------------------------------------------------------------
var
F : Textfile;
begin
// Try to open the file
Result := False;
AssignFile(F,Fname);
{$I-}
Reset(F);
{$I+}
if (IOResult = 0) then
begin
// Create stringlists
Screen.Cursor := crHourGlass;
MapExtentSet := False;
ErrList := TStringList.Create;
TokList := TStringList.Create;
SubcatchList := TStringList.Create;
NodeList := TStringList.Create;
LinkList := TStringList.Create;
FileType := ftInput;
InpFile := Fname;
try
// Read the file
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
SubcatchList.Sorted := True;
NodeList.Sorted := True;
LinkList.Sorted := True;
Section := -1;
Result := ReadFile(F, Uutils.GetFileSize(Fname));
if (Result = True) then
begin
// Establish pointers to ID names
SetIDPtrs;
end;
finally
// Free the stringlists
SubcatchList.Free;
NodeList.Free;
LinkList.Free;
TokList.Free;
MainForm.PageSetupDialog.Header.Text := Project.Title;
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
// Display errors if found & set map dimensions
if Result = True then
begin
if ErrList.Count > 0 then DisplayInpErrForm(Fname);
SetSubcatchCentroids;
SetMapDimensions;
end;
ErrList.Free;
end;
end;
// Close the input file
CloseFile(F);
end;
procedure ClearDefaultDates;
//-----------------------------------------------------------------------------
// Clears project's date/time settings.
//-----------------------------------------------------------------------------
begin
with Project.Options do
begin
Data[START_DATE_INDEX] := '';
Data[START_TIME_INDEX] := '';
Data[REPORT_START_DATE_INDEX] := '';
Data[REPORT_START_TIME_INDEX] := '';
Data[END_DATE_INDEX] := '';
Data[END_TIME_INDEX] := '';
end;
end;
procedure SetDefaultDates;
//-----------------------------------------------------------------------------
// Sets default values for project's date/time settings.
//-----------------------------------------------------------------------------
var
StartTime: TDateTime;
StartDate: TDateTime;
T: TDateTime;
D: TDateTime;
begin
with Project.Options do
begin
// Process starting date/time
try
StartDate := StrToDate(Data[START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do StartDate := Date;
end;
StartTime := Uutils.StrHoursToTime(Data[START_TIME_INDEX]);
if StartTime < 0 then StartTime := 0;
D := StartDate + StartTime;
Data[START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process reporting start date/time
try
D := StrToDate(Data[REPORT_START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[REPORT_START_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[REPORT_START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[REPORT_START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process ending date/time
try
D := StrToDate(Data[END_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[END_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[END_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[END_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
end;
end;
function OpenProject(const Fname: String): TInputFileType;
//-----------------------------------------------------------------------------
// Reads in project data from a file.
//-----------------------------------------------------------------------------
begin
// Show progress meter
ClearDefaultDates;
Screen.Cursor := crHourGlass;
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
// Use default map dimensions and backdrop settings
MapForm.Map.Dimensions := DefMapDimensions;
MapForm.Map.Backdrop := DefMapBackdrop;
// Do the following for non-temporary input files
if not SameText(Fname, Uglobals.TempInputFile) then
begin
// Create a backup file
if AutoBackup
then CopyFile(PChar(Fname), PChar(ChangeFileExt(Fname, '.bak')), FALSE);
// Retrieve project defaults from .INI file
if CompareText(ExtractFileExt(Fname), '.ini') <> 0
then Uinifile.ReadProjIniFile(ChangeFileExt(Fname, '.ini'));
end;
// Read and parse each line of input file
Result := iftNone;
if ReadInpFile(Fname) then Result := iftINP;
// Finish processing the input data
if Result <> iftNone then
begin
SetDefaultDates; // set any missing analysis dates
Uglobals.RegisterCalibData; // register calibration data files
Uupdate.UpdateUnits; // update choice of unit system
Uupdate.UpdateDefOptions; // update default analysis options
Uupdate.UpdateLinkHints; // update hints used for offsets
Project.GetControlRuleNames; // store control ruunit Uimport;
{-------------------------------------------------------------------}
{ Unit: Uimport.pas }
{ Project: EPA SWMM }
{ Version: 5.1 }
{ Date: 12/02/13 (5.1.001) }
{ 04/04/14 (5.1.003) }
{ 04/14/14 (5.1.004) }
{ 09/15/14 (5.1.007) }
{ 03/19/15 (5.1.008) }
{ 08/05/15 (5.1.010) }
{ 08/01/16 (5.1.011) }
{ Author: L. Rossman }
{ }
{ Delphi Pascal unit that imports a SWMM project's data from a }
{ a formatted text file. }
{ }
{ 5.1.011 - Support for reading [EVENTS] section added. }
{-------------------------------------------------------------------}
interface
uses
Classes, Forms, Controls, Dialogs, SysUtils, Windows, Math, StrUtils,
Uutils, Uglobals;
const
ITEMS_ERR = 1;
KEYWORD_ERR = 2;
SUBCATCH_ERR = 3;
NODE_ERR = 4;
LINK_ERR = 5;
LANDUSE_ERR = 6;
POLLUT_ERR = 7;
NUMBER_ERR = 8;
XSECT_ERR = 9;
TRANSECT_ERR = 10;
TIMESTEP_ERR = 11;
DATE_ERR = 12;
LID_ERR = 13;
MAX_ERRORS = 50;
type
TFileType = (ftInput, ftImport);
// These routines can be called from other units
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
function OpenProject(const Fname: String): TInputFileType;
function ReadInpFile(const Fname: String):Boolean;
procedure SetDefaultDates;
implementation
uses
Fmain, Fmap, Fstatus, Dxsect, Uexport, Uinifile, Uproject, Umap,
Ucoords, Uvertex, Uupdate, Dreporting, Ulid;
const
MSG_READING_PROJECT_DATA = 'Reading project data... ';
TXT_ERROR = 'Error ';
TXT_AT_LINE = ' at line ';
TXT_MORE_ERRORS = ' more errors found in file.';
TXT_ERROR_REPORT = 'Error Report for File ';
SectionWords : array[0..54] of PChar = //(5.1.011)
('[TITLE', //0
'[OPTION', //1
'[RAINGAGE', //2
'[HYDROGRAPH', //3
'[EVAPORATION', //4
'[SUBCATCHMENT', //5
'[SUBAREA', //6
'[INFILTRATION', //7
'[AQUIFER', //8
'[GROUNDWATER', //9
'[JUNCTION', //10
'[OUTFALL', //11
'[STORAGE', //12
'[DIVIDER', //13
'[CONDUIT', //14
'[PUMP', //15
'[ORIFICE', //16
'[WEIR', //17
'[OUTLET', //18
'[XSECTION', //19
'[TRANSECT', //20
'[LOSS', //21
'[CONTROL', //22
'[POLLUTANT', //23
'[LANDUSE', //24
'[BUILDUP', //25
'[WASHOFF', //26
'[COVERAGE', //27
'[INFLOW', //28
'[DWF', //29
'[PATTERN', //30
'[RDII', //31
'[LOAD', //32
'[CURVE', //33
'[TIMESERIES', //34
'[REPORT', //35
'[FILE', //36
'[MAP', //37
'[COORDINATES', //38
'[VERTICES', //39
'[POLYGONS', //40
'[SYMBOLS', //41
'[LABELS', //42
'[BACKDROP', //43
'[PROFILE', //44
'[TABLE', //45
'[TEMPERATURE', //46
'[SNOWPACK', //47
'[TREATMENT', //48
'[TAG', //49
'[LID_CONTROL', //50
'[LID_USAGE', //51
'[GWF', //52 //(5.1.007)
'[ADJUSTMENTS', //53 //(5.1.007)
'[EVENT'); //54 //(5.1.011)
var
FileType : TFileType;
InpFile : String;
ErrList : TStringlist;
SubcatchList : TStringlist;
NodeList : TStringlist;
LinkList : TStringlist;
TokList : TStringlist;
Ntoks : Integer;
Section : Integer;
LineCount : LongInt;
ErrCount : LongInt;
Line : String;
Comment : String;
TsectComment : String;
PrevID : String;
PrevIndex : Integer;
CurveType : Integer;
MapExtentSet : Boolean;
ManningsN : array[1..3] of String;
// These are deprecated attributes of a backdrop image
BackdropX : Extended;
BackdropY : Extended;
BackdropW : Extended;
BackdropH : Extended;
function ErrMsg(const ErrCode: Integer; const Name: String): Integer;
//-----------------------------------------------------------------------------
// Adds an error message for a specific error code to the list
// of errors encountered when reading an input file.
//-----------------------------------------------------------------------------
var
S: String;
begin
if ErrCount <= MAX_ERRORS then
begin
case ErrCode of
ITEMS_ERR: S := 'Too few items ';
KEYWORD_ERR: S := 'Unrecognized keyword (' + Name + ') ';
SUBCATCH_ERR: S := 'Undefined Subcatchment (' + Name + ') referenced ';
NODE_ERR: S := 'Undefined Node (' + Name + ') referenced ';
LINK_ERR: S := 'Undefined Link (' + Name + ') referenced ';
LANDUSE_ERR: S := 'Undefined Land Use (' + Name + ') referenced ';
POLLUT_ERR: S := 'Undefined Pollutant (' + Name + ') referenced ';
NUMBER_ERR: S := 'Illegal numeric value (' + Name + ') ';
XSECT_ERR: S := 'Illegal cross section for Link ' + Name + ' ';
TRANSECT_ERR: S := 'No Transect defined for these data ';
TIMESTEP_ERR: S := 'Illegal time step value ';
DATE_ERR: S := 'Illegal date/time value ';
LID_ERR: S := 'Undefined LID process (' + Name + ') referenced ';
else S := 'Unknown error ';
end;
S := S + 'at line ' + IntToStr(LineCount) + ':';
ErrList.Add(S);
if Section >= 0 then ErrList.Add(SectionWords[Section] + ']');
ErrList.Add(Line);
ErrList.Add('');
end;
Result := ErrCode;
end;
function FindSubcatch(const ID: String): TSubcatch;
//-----------------------------------------------------------------------------
// Finds a Subcatchment object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Atype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if SubcatchList.Find(ID, Index)
then Result := TSubcatch(SubcatchList.Objects[Index]);
end
else
begin
if (Project.FindSubcatch(ID, Atype, Index))
then Result := Project.GetSubcatch(Atype, Index);
end;
end;
function FindNode(const ID: String): TNode;
//-----------------------------------------------------------------------------
// Finds a Node object given its ID name.
//-----------------------------------------------------------------------------
var
Index: Integer;
Ntype: Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if NodeList.Find(ID, Index)
then Result := TNode(NodeList.Objects[Index]);
end
else
begin
if (Project.FindNode(ID, Ntype, Index))
then Result := Project.GetNode(Ntype, Index);
end;
end;
function FindLink(const ID: String): TLink;
//-----------------------------------------------------------------------------
// Finds a Link object given its ID name.
//-----------------------------------------------------------------------------
var
Index : Integer;
Ltype : Integer;
begin
Result := nil;
if (FileType = ftInput) then
begin
if LinkList.Find(ID, Index)
then Result := TLink(LinkList.Objects[Index]);
end
else
begin
if (Project.FindLink(ID, Ltype, Index))
then Result := Project.GetLink(Ltype, Index);
end;
end;
function ReadTitleData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Adds Line of text to a project's title and notes.
//-----------------------------------------------------------------------------
begin
if Project.Lists[NOTES].Count = 0 then Project.Title := Line;
Project.Lists[NOTES].Add(Line);
Project.HasItems[NOTES] := True;
Result := 0;
end;
procedure ReadOldRaingageData(I: Integer; aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of parsed rain gage data using older format.
//-----------------------------------------------------------------------------
begin
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 2 then aGage.Data[GAGE_SERIES_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_DATA_FORMAT] := TokList[3];
if Ntoks > 4 then aGage.Data[GAGE_DATA_FREQ] := TokList[4];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 2 then aGage.Data[GAGE_FILE_NAME] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_STATION_NUM] := TokList[3];
end;
end;
procedure ReadNewRaingageData(aGage: TRaingage);
//-----------------------------------------------------------------------------
// Reads a line of rain gage data using newer format.
//-----------------------------------------------------------------------------
var
I: Integer;
Fname: String;
begin
if Ntoks > 1 then aGage.Data[GAGE_DATA_FORMAT] := TokList[1];
if Ntoks > 2 then aGage.Data[GAGE_DATA_FREQ] := TokList[2];
if Ntoks > 3 then aGage.Data[GAGE_SNOW_CATCH] := TokList[3];
if Ntoks > 4 then
begin
I := Uutils.FindKeyWord(TokList[4], RaingageOptions, 4);
if I = 0 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[0];
if Ntoks > 5 then aGage.Data[GAGE_SERIES_NAME] := TokList[5];
end;
if I = 1 then
begin
aGage.Data[GAGE_DATA_SOURCE] := RaingageOptions[1];
if Ntoks > 5 then
begin
Fname := TokList[5];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
aGage.Data[GAGE_FILE_NAME] := Fname;
end;
if Ntoks > 6 then aGage.Data[GAGE_STATION_NUM] := TokList[6];
if Ntoks > 7 then aGage.Data[GAGE_RAIN_UNITS] := TokList[7];
end;
end;
end;
function ReadRaingageData: Integer;
//-----------------------------------------------------------------------------
// Parses rain gage data from the input line.
//-----------------------------------------------------------------------------
var
aGage : TRaingage;
ID : String;
I : Integer;
begin
if Ntoks < 2 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end;
ID := TokList[0];
aGage := TRaingage.Create;
Uutils.CopyStringArray(Project.DefProp[RAINGAGE].Data, aGage.Data);
aGage.X := MISSING;
aGage.Y := MISSING;
aGage.Data[COMMENT_INDEX ] := Comment;
Project.Lists[RAINGAGE].AddObject(ID, aGage);
Project.HasItems[RAINGAGE] := True;
I := Uutils.FindKeyWord(TokList[1], RaingageOptions, 4);
if I >= 0
then ReadOldRaingageData(I, aGage)
else ReadNewRaingageData(aGage);
Result := 0;
end;
function ReadOldHydrographFormat(const I: Integer; UH: THydrograph): Integer;
//-----------------------------------------------------------------------------
// Reads older format of unit hydrograph parameters from a line of input.
//-----------------------------------------------------------------------------
var
J, K, N: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
N := 2;
for K := 1 to 3 do
begin
for J := 1 to 3 do
begin
UH.Params[I,J,K] := TokList[N];
Inc(N);
end;
end;
for J := 1 to 3 do
begin
UH.InitAbs[I,J,1] := '';
if Ntoks > N then UH.InitAbs[I,J,1] := TokList[N];
Inc(N);
for K := 2 to 3 do UH.InitAbs[I,J,K] := UH.InitAbs[I,J,1];
end;
end;
end;
function ReadHydrographData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII unit hydrograph data from a line of input.
//-----------------------------------------------------------------------------
var
I, J, K: Integer;
ID: String;
aUnitHyd: THydrograph;
Index: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Check if hydrograph ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[HYDROGRAPH].IndexOf(ID);
// If starting input for a new hydrograph then create it
if Index < 0 then
begin
aUnitHyd := THydrograph.Create;
Project.Lists[HYDROGRAPH].AddObject(ID, aUnitHyd);
Project.HasItems[HYDROGRAPH] := True;
Index := Project.Lists[HYDROGRAPH].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else aUnitHyd := THydrograph(Project.Lists[HYDROGRAPH].Objects[Index]);
// Parse rain gage name for 2-token line
if Ntoks = 2 then
begin
aUnitHyd.Raingage := TokList[1];
end
// Extract remaining hydrograph parameters
else if Ntoks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
// Determine month of year
I := Uutils.FindKeyWord(TokList[1], MonthLabels, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
// Determine if response type present - if not, process old format
K := Uutils.FindKeyWord(TokList[2], ResponseTypes, 3) + 1;
if K < 1 then Result := ReadOldHydrographFormat(I, aUnitHyd)
else
begin
// Extract R-T-K values
for J := 3 to 5 do
begin
aUnitHyd.Params[I,J-2,K] := TokList[J];
end;
// Extract IA parameters
for J := 6 to 8 do
begin
if J >= Ntoks then break
else aUnitHyd.InitAbs[I,J-5,K] := TokList[J];
end;
end;
end;
end;
end;
function ReadTemperatureData: Integer;
//-----------------------------------------------------------------------------
// Reads description of air temperature data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
I := Uutils.FindKeyWord(TokList[0], TempKeywords, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[0])
else case I of
0: begin // Time series
TempDataSource := 1;
TempTseries := TokList[1];
end;
1: begin // File
TempDataSource := 2;
TempFile := TokList[1];
if ExtractFilePath(TempFile) = '' then
TempFile := ExtractFilePath(Uglobals.InputFileName) + TempFile;
if Ntoks >= 3 then TempStartDate := TokList[2];
end;
2: begin // Wind speed
if SameText(TokList[1], 'MONTHLY') then
begin
if Ntoks < 14 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
WindType := MONTHLY_WINDSPEED;
for I := 1 to 12 do WindSpeed[I] := TokList[I+1];
end;
end
else if SameText(TokList[1], 'FILE') then WindType := FILE_WINDSPEED
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
3: begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 6 do SnowMelt[I] := TokList[I];
end;
4: begin
if Ntoks < 12 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
if SameText(TokList[1], 'IMPERVIOUS') then
for I := 1 to 10 do ADCurve[1][I] := TokList[I+1]
else if SameText(TokList[1], 'PERVIOUS') then
for I := 1 to 10 do ADCurve[2][I] := TokList[I+1]
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
end;
end;
function ReadEvaporationRates(Etype: Integer): Integer;
var
J: Integer;
begin
if (Etype <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
EvapType := Etype;
case EvapType of
CONSTANT_EVAP:
for J := 0 to 11 do EvapData[J] := TokList[1];
TSERIES_EVAP:
EvapTseries := TokList[1];
FILE_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
PanData[J-1] := TokList[J];
end;
MONTHLY_EVAP:
for J := 1 to 12 do
begin
if J >= Ntoks then break;
EvapData[J-1] := TokList[J];
end;
end;
Result := 0;
end;
end;
function ReadEvaporationData: Integer;
//-----------------------------------------------------------------------------
// Reads evaporation data from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
I := Uutils.FindKeyWord(TokList[0], EvapOptions, 4);
if I >= 0 then Result := ReadEvaporationRates(I)
else if (I <> TEMP_EVAP) and (Ntoks < 2)
then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
if SameText(TokList[0], 'RECOVERY')
then RecoveryPat := TokList[1]
else if SameText(TokList[0], 'DRY_ONLY') then
begin
if SameText(TokList[1], 'NO') then EvapDryOnly := False
else if SameText(TokList[1], 'YES') then EvapDryOnly := True
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end
else Result := ErrMsg(KEYWORD_ERR, TokList[0]);
end;
end;
function ReadSubcatchmentData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := TSubcatch.Create;
SubcatchList.AddObject(ID, S);
S.X := MISSING;
S.Y := MISSING;
S.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[SUBCATCH].Data, S.Data);
S.Data[SUBCATCH_RAINGAGE_INDEX] := TokList[1];
S.Data[SUBCATCH_OUTLET_INDEX] := TokList[2];
S.Data[SUBCATCH_AREA_INDEX] := TokList[3];
S.Data[SUBCATCH_IMPERV_INDEX] := TokList[4];
S.Data[SUBCATCH_WIDTH_INDEX] := TokList[5];
S.Data[SUBCATCH_SLOPE_INDEX] := TokList[6];
S.Data[SUBCATCH_CURBLENGTH_INDEX] := TokList[7];
if Ntoks >= 9
then S.Data[SUBCATCH_SNOWPACK_INDEX] := TokList[8];
S.Data[COMMENT_INDEX ] := Comment;
Project.Lists[SUBCATCH].AddObject(ID, S);
Project.HasItems[SUBCATCH] := True;
Result := 0;
end;
end;
function ReadSubareaData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment sub-area data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
S.Data[SUBCATCH_IMPERV_N_INDEX] := TokList[1];
S.Data[SUBCATCH_PERV_N_INDEX] := TokList[2];
S.Data[SUBCATCH_IMPERV_DS_INDEX] := TokList[3];
S.Data[SUBCATCH_PERV_DS_INDEX] := TokList[4];
S.Data[SUBCATCH_PCTZERO_INDEX] := TokList[5];
S.Data[SUBCATCH_ROUTE_TO_INDEX] := TokList[6];
if Ntoks >= 8
then S.Data[SUBCATCH_PCT_ROUTED_INDEX] := TokList[7];
Result := 0;
end;
end;
end;
function ReadInfiltrationData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment infiltration data from a line of input.
//-----------------------------------------------------------------------------
var
S : TSubcatch;
ID : String;
J : Integer;
Jmax : Integer;
begin
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else begin
Jmax := Ntoks-1;
if Jmax > MAXINFILPROPS then Jmax := MAXINFILPROPS;
for J := 1 to Jmax do S.InfilData[J-1] := TokList[J];
Result := 0;
end;
end;
function ReadAquiferData: Integer;
//-----------------------------------------------------------------------------
// Reads aquifer data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
A : TAquifer;
I : Integer;
begin
if nToks < MAXAQUIFERPROPS then Result := ErrMsg(ITEMS_ERR, '') //(5.1.003)
else begin
ID := TokList[0];
A := TAquifer.Create;
//Uutils.CopyStringArray(Project.DefProp[AQUIFER].Data, A.Data); //(5.1.004)
Project.Lists[AQUIFER].AddObject(ID, A);
Project.HasItems[AQUIFER] := True;
for I := 0 to MAXAQUIFERPROPS-1 do A.Data[I] := TokList[I+1]; //(5.1.003)
if nToks >= MAXAQUIFERPROPS + 2 //(5.1.004)
then A.Data[MAXAQUIFERPROPS] := TokList[MAXAQUIFERPROPS+1] //(5.1.003)
else A.Data[MAXAQUIFERPROPS] := ''; //(5.1.003)
Result := 0;
end;
end;
function ReadGroundwaterData: Integer;
//-----------------------------------------------------------------------------
// Reads subcatchment groundwater data from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
ID: String;
P: String;
J: Integer;
K: Integer;
begin
// Get subcatchment name
ID := TokList[0];
S := FindSubcatch(ID);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, ID)
else
begin
// Line contains GW flow parameters
if Ntoks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else begin
S.Groundwater.Clear;
// Read required parameters
for J := 1 to 9 do S.Groundwater.Add(TokList[J]);
// Read optional parameters
for K := 10 to 13 do
begin
if Ntoks > K then
begin
P := TokList[K];
if P = '*' then P := '';
S.Groundwater.Add(P);
end
else S.Groundwater.Add('');
end;
S.Data[SUBCATCH_GWATER_INDEX] := 'YES';
Result := 0;
end;
end;
end;
//// This function was re-written for release 5.1.007. //// //(5.1.007)
function ReadGroundwaterFlowEqn(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads GW flow math expression from a line of input.
//-----------------------------------------------------------------------------
var
S: TSubcatch;
N: Integer;
begin
// Check for enough tokens in line
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
// Get subcatchment object referred to by name
else begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
// Find position in Line where second token ends
N := Pos(TokList[1], Line) + Length(TokList[1]);
// Save remainder of line to correct type of GW flow equation
if SameText(TokList[1], 'LATERAL') then
S.GwLatFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else if SameText(TokList[1], 'DEEP') then
S.GwDeepFlowEqn := Trim(AnsiRightStr(Line, Length(Line)-N))
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
end;
end;
function ReadSnowpackData: Integer;
//-----------------------------------------------------------------------------
// Reads snowpack data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
P : TSnowpack;
I : Integer;
J : Integer;
Index: Integer;
begin
Result := 0;
if Ntoks < 8
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[1], SnowpackOptions, 7);
if I < 0
then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else begin
// Check if snow pack ID is same as for previous line
ID := TokList[0];
if (ID = PrevID)
then Index := PrevIndex
else Index := Project.Lists[SNOWPACK].IndexOf(ID);
// If starting input for a new snow pack then create it
if Index < 0 then
begin
P := TSnowpack.Create;
Project.Lists[SNOWPACK].AddObject(ID, P);
Project.HasItems[SNOWPACK] := True;
Index := Project.Lists[SNOWPACK].Count - 1;
PrevID := ID;
PrevIndex := Index;
end
else P := TSnowpack(Project.Lists[SNOWPACK].Objects[Index]);
// Parse line depending on data type
case I of
// Plowable area
0: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
for J := 1 to 6 do P.Data[1][J] := TokList[J+1];
P.FracPlowable := TokList[8];
end;
end;
// Impervious or Pervious area
1,
2: begin
if Ntoks < 9 then Result := ErrMsg(ITEMS_ERR, '')
else for J := 1 to 7 do P.Data[I+1][J] := TokList[J+1];
end;
// Plowing parameters
3: begin
for J := 1 to 6 do P.Plowing[J] := TokList[J+1];
if Ntoks >= 9 then P.Plowing[7] := TokList[8];
end;
end;
end;
end;
end;
function ReadJunctionData: Integer;
//-----------------------------------------------------------------------------
// Reads junction data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
begin
if Ntoks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := JUNCTION;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[JUNCTION].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
if Ntoks > 2 then aNode.Data[JUNCTION_MAX_DEPTH_INDEX] := TokList[2];
if Ntoks > 3 then aNode.Data[JUNCTION_INIT_DEPTH_INDEX] := TokList[3];
if Ntoks > 4 then aNode.Data[JUNCTION_SURCHARGE_DEPTH_INDEX] := TokList[4];
if Ntoks > 5 then aNode.Data[JUNCTION_PONDED_AREA_INDEX] := TokList[5];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[JUNCTION].AddObject(ID, aNode);
Project.HasItems[JUNCTION] := True;
Result := 0;
end;
end;
function ReadOutfallData: Integer;
//-----------------------------------------------------------------------------
// Reads outfall data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
I : Integer;
N : Integer; //(5.1.008)
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
N := 4; //(5.1.008)
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := OUTFALL;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTFALL].Data, aNode.Data);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
I := Uutils.FindKeyWord(TokList[2], OutfallOptions, 4);
if I < 0 then I := FREE_OUTFALL;
if (I > NORMAL_OUTFALL) and (Ntoks >= 4) then
begin
case I of
FIXED_OUTFALL: aNode.Data[OUTFALL_FIXED_STAGE_INDEX] := TokList[3];
TIDAL_OUTFALL: aNode.Data[OUTFALL_TIDE_TABLE_INDEX] := TokList[3];
TIMESERIES_OUTFALL: aNode.Data[OUTFALL_TIME_SERIES_INDEX] := TokList[3];
end;
N := 5;
if Ntoks >= 5 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[4]; // (5.1.008)
end
else if Ntoks >= 4 then aNode.Data[OUTFALL_TIDE_GATE_INDEX] := TokList[3]; //(5.1.008)
if Ntoks > N then aNode.Data[OUTFALL_ROUTETO_INDEX] := TokList[N]; //(5.1.008)
aNode.Data[OUTFALL_TYPE_INDEX] := OutfallOptions[I];
aNode.Data[COMMENT_INDEX ] := Comment;
Project.Lists[OUTFALL].AddObject(ID, aNode);
Project.HasItems[OUTFALL] := True;
Result := 0;
end;
end;
//// The following function was modified for release 5.1.007. //// //(5.1.007)
function ReadStorageData: Integer;
//-----------------------------------------------------------------------------
// Reads storage unit data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
ID : String;
N : Integer;
X : Single;
begin
Result := 0;
N := 6;
if Ntoks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := STORAGE;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[STORAGE].Data, aNode.Data);
Project.Lists[STORAGE].AddObject(ID, aNode);
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[STORAGE_MAX_DEPTH_INDEX] := TokList[2];
aNode.Data[STORAGE_INIT_DEPTH_INDEX] := TokList[3];
aNode.Data[STORAGE_GEOMETRY_INDEX] := TokList[4];
if CompareText(TokList[4], 'TABULAR') = 0 then
begin
aNode.Data[STORAGE_ATABLE_INDEX] := TokList[5];
end
else begin
if Ntoks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode.Data[STORAGE_ACOEFF_INDEX] := TokList[5];
aNode.Data[STORAGE_AEXPON_INDEX] := TokList[6];
if Ntoks >= 8 then aNode.Data[STORAGE_ACONST_INDEX] := TokList[7];
N := 8;
end;
end;
// Optional items
if (Result = 0) and (Ntoks > N) then
begin
// Ponded area
aNode.Data[STORAGE_PONDED_AREA_INDEX] := TokList[N];
// Evaporation factor
if Ntoks > N+1 then aNode.Data[STORAGE_EVAP_FACTOR_INDEX] := TokList[N+1];
// Constant seepage rate
if Ntoks = N+3 then
begin
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+2];
end
// Green-Ampt seepage parameters
else if Ntoks = N+5 then
begin
aNode.InfilData[STORAGE_SUCTION_INDEX] := TokList[N+2];
aNode.InfilData[STORAGE_KSAT_INDEX] := TokList[N+3];
aNode.InfilData[STORAGE_IMDMAX_INDEX] := TokList[N+4];
end;
end;
Uutils.GetSingle(aNode.InfilData[STORAGE_KSAT_INDEX ], X);
if (X > 0) then aNode.Data[STORAGE_SEEPAGE_INDEX] := 'YES'
else aNode.Data[STORAGE_SEEPAGE_INDEX] := 'NO';
aNode.Data[COMMENT_INDEX ] := Comment;
Project.HasItems[STORAGE] := True;
end;
end;
function ReadDividerData: Integer;
//-----------------------------------------------------------------------------
// Reads flow divider data from a line of input.
// (Corrected on 6/14/05)
//-----------------------------------------------------------------------------
var
N, J : Integer;
aNode: TNode;
ID : String;
begin
if Ntoks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Result := 0;
ID := TokList[0];
aNode := TNode.Create;
NodeList.AddObject(ID, aNode);
aNode.Ntype := DIVIDER;
aNode.X := MISSING;
aNode.Y := MISSING;
aNode.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[DIVIDER].Data, aNode.Data);
Project.Lists[DIVIDER].AddObject(ID, aNode);
Project.HasItems[DIVIDER] := True;
aNode.Data[COMMENT_INDEX ] := Comment;
aNode.Data[NODE_INVERT_INDEX] := TokList[1];
aNode.Data[DIVIDER_LINK_INDEX] := TokList[2];
aNode.Data[DIVIDER_TYPE_INDEX] := TokList[3];
N := 5;
if SameText(TokList[3], 'OVERFLOW') then
begin
N := 4;
end
else if SameText(TokList[3], 'CUTOFF') then
begin
aNode.Data[DIVIDER_CUTOFF_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'TABULAR') then
begin
aNode.Data[DIVIDER_TABLE_INDEX] := TokList[4];
end
else if SameText(TokList[3], 'WEIR') and (Ntoks >= 7) then
begin
aNode.Data[DIVIDER_QMIN_INDEX] := TokList[4];
aNode.Data[DIVIDER_DMAX_INDEX] := TokList[5];
aNode.Data[DIVIDER_QCOEFF_INDEX] := TokList[6];
N := 7;
end
else Result := ErrMsg(KEYWORD_ERR, TokList[3]);
if (Result = 0) and (Ntoks > N) then
begin
for J := N to Ntoks-1 do
aNode.Data[DIVIDER_MAX_DEPTH_INDEX + J - N] := TokList[J];
end;
end;
end;
function ReadConduitData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if Ntoks < 7 then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := CONDUIT;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[CONDUIT].Data, aLink.Data);
Project.Lists[CONDUIT].AddObject(ID, aLink);
Project.HasItems[CONDUIT] := True;
aLink.Data[CONDUIT_LENGTH_INDEX] := TokList[3];
aLink.Data[CONDUIT_ROUGHNESS_INDEX] := TokList[4];
aLink.Data[CONDUIT_INLET_HT_INDEX] := TokList[5];
aLink.Data[CONDUIT_OUTLET_HT_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_INIT_FLOW_INDEX] := TokList[7];
if Ntoks > 8 then aLink.Data[CONDUIT_MAX_FLOW_INDEX] := TokList[8];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadPumpData: Integer;
//-----------------------------------------------------------------------------
// Reads pump data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := PUMP;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[PUMP].Data, aLink.Data);
Project.Lists[PUMP].AddObject(ID, aLink);
Project.HasItems[PUMP] := True;
// Skip over PumpType if line has old format
if Uutils.FindKeyWord(TokList[3], PumpTypes, 5) >= 0 then N := 4
else N := 3;
if Ntoks <= N then Result := ErrMsg(ITEMS_ERR, '')
else
begin
aLink.Data[PUMP_CURVE_INDEX] := TokList[N];
if nToks > N+1 then aLink.Data[PUMP_STATUS_INDEX] := TokList[N+1];
if nToks > N+2 then aLink.Data[PUMP_STARTUP_INDEX] := TokList[N+2];
if nToks > N+3 then aLink.Data[PUMP_SHUTOFF_INDEX] := TokList[N+3];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
end;
function ReadOrificeData: Integer;
//-----------------------------------------------------------------------------
// Reads orifice data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := ORIFICE;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[ORIFICE].Data, aLink.Data);
Project.Lists[ORIFICE].AddObject(ID, aLink);
Project.HasItems[ORIFICE] := True;
aLink.Data[ORIFICE_TYPE_INDEX] := TokList[3];
aLink.Data[ORIFICE_BOTTOM_HT_INDEX] := TokList[4];
aLink.Data[ORIFICE_COEFF_INDEX] := TokList[5];
if nToks >= 7
then aLink.Data[ORIFICE_FLAPGATE_INDEX] := TokList[6];
if nToks >= 8
then aLink.Data[ORIFICE_ORATE_INDEX] := TokList[7];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function ReadWeirData: Integer;
//-----------------------------------------------------------------------------
// Reads weir data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := WEIR;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[WEIR].Data, aLink.Data);
Project.Lists[WEIR].AddObject(ID, aLink);
Project.HasItems[WEIR] := True;
aLink.Data[WEIR_TYPE_INDEX] := TokList[3];
aLink.Data[WEIR_CREST_INDEX] := TokList[4];
aLink.Data[WEIR_COEFF_INDEX] := TokList[5];
//// Following section modified for release 5.1.007. //// //(5.1.007)
if (nToks >= 7) and not SameText(TokList[6], '*') then
aLink.Data[WEIR_FLAPGATE_INDEX] := TokList[6];
if (nToks >= 8) and not SameText(TokList[7], '*') then
aLink.Data[WEIR_CONTRACT_INDEX] := TokList[7];
if (nToks >= 9) and not SameText(TokList[8], '*') then
aLink.Data[WEIR_END_COEFF_INDEX] := TokList[8];
if (nToks >= 10) and not SameText(TokList[9], '*') then
aLink.Data[WEIR_SURCHARGE_INDEX] := TokList[9];
//// Following section added for release 5.1.010. //(5.1.010)
if (nToks >= 11) and not SameText(TokList[10], '*') then
aLink.Data[WEIR_ROAD_WIDTH_INDEX] := TokList[10];
if (nToks >= 12) and not SameText(TokList[11], '*') then
aLink.Data[WEIR_ROAD_SURF_INDEX] := TokList[11];
////
aLink.Data[COMMENT_INDEX] := Comment;
Result := 0;
end;
end;
end;
function ReadOutletData: Integer;
//-----------------------------------------------------------------------------
// Reads outlet data from a line of input.
//-----------------------------------------------------------------------------
var
aLink : TLink;
aNode1: TNode;
aNode2: TNode;
ID : String;
N : Integer;
begin
if nToks < 6
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aNode1 := FindNode(TokList[1]);
aNode2 := FindNode(TokList[2]);
if (aNode1 = nil) then Result := ErrMsg(NODE_ERR, TokList[1])
else if (aNode2 = nil) then Result := ErrMsg(NODE_ERR, TokList[2])
else begin
aLink := TLink.Create;
LinkList.AddObject(ID, aLink);
aLink.Ltype := OUTLET;
aLink.Node1 := aNode1;
aLink.Node2 := aNode2;
aLink.Zindex := -1;
Uutils.CopyStringArray(Project.DefProp[OUTLET].Data, aLink.Data);
Project.Lists[OUTLET].AddObject(ID, aLink);
Project.HasItems[OUTLET] := True;
aLink.Data[OUTLET_CREST_INDEX] := TokList[3];
//... added for backwards compatibility
if SameText(TokList[4], 'TABULAR') then TokList[4] := 'TABULAR/DEPTH';
if SameText(TokList[4], 'FUNCTIONAL') then TokList[4] := 'FUNCTIONAL/DEPTH';
aLink.Data[OUTLET_TYPE_INDEX] := TokList[4];
if AnsiContainsText(TokList[4], 'TABULAR') then
begin
aLink.Data[OUTLET_QTABLE_INDEX] := TokList[5];
N := 6;
end
else begin
if Ntoks < 7 then
begin
Result := ErrMsg(ITEMS_ERR, '');
Exit;
end
else
begin
aLink.Data[OUTLET_QCOEFF_INDEX] := TokList[5];
aLink.Data[OUTLET_QEXPON_INDEX] := TokList[6];
N := 7;
end;
end;
if Ntoks > N then aLink.Data[OUTLET_FLAPGATE_INDEX] := TokList[N];
aLink.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
end;
end;
function GetXsectShape(const S: String): Integer;
//-----------------------------------------------------------------------------
// Finds the code number corresponding to cross section shape S.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
for I := 0 to High(Dxsect.XsectShapes) do
begin
if CompareText(S, Dxsect.XsectShapes[I].Text[1]) = 0 then
begin
Result := I;
Exit;
end;
end;
Result := -1;
end;
//// New procedure added to release 5.1.008. //// //(5.1.008)
procedure CheckForStdSize;
//-----------------------------------------------------------------------------
// Converts from old format for standard size ellipse and arch pipes
// to new format.
//-----------------------------------------------------------------------------
var
J: Integer;
X: Extended;
begin
// Old format had size code as 3rd token and 0 for 4th token
J := StrToIntDef(TokList[2], 0);
Uutils.GetExtended(TokList[3], X);
if (J > 0) and (X = 0) then
begin
// New format has 5th token as size code
TokList[4] := TokList[2];
TokList[2] := '0';
TokList[3] := '0';
end;
end;
function ReadXsectionData: Integer;
//-----------------------------------------------------------------------------
// Reads cross section data froma line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
ID : String;
aLink : TLink;
begin
if nToks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil)
then Result := ErrMsg(LINK_ERR, TokList[0])
else begin
I := GetXsectShape(TokList[1]);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else case aLink.Ltype of
CONDUIT:
begin
aLink.Data[CONDUIT_SHAPE_INDEX] := TokList[1];
if I = Dxsect.IRREG_SHAPE_INDEX then
begin
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM1_INDEX] := ''; //(5.1.008)
Result := 0;
end
else begin
if nToks < 6 then Result := ErrMsg(ITEMS_ERR, '')
else begin
{
//// Added to release 5.1.008. //// //(5.1.008)
if I in [Dxsect.HORIZ_ELLIPSE_SHAPE_INDEX,
Dxsect.VERT_ELLIPSE_SHAPE_INDEX,
Dxsect.ARCH_SHAPE_INDEX]
then CheckForStdSize;
}
aLink.Data[CONDUIT_GEOM1_INDEX] := TokList[2];
aLink.Data[CONDUIT_GEOM2_INDEX] := TokList[3];
aLink.Data[CONDUIT_GEOM3_INDEX] := TokList[4];
aLink.Data[CONDUIT_GEOM4_INDEX] := TokList[5];
if Ntoks > 6 then aLink.Data[CONDUIT_BARRELS_INDEX] := TokList[6];
if Ntoks > 7 then aLink.Data[CONDUIT_CULVERT_INDEX] := TokList[7];
if I = Dxsect.CUSTOM_SHAPE_INDEX then
aLink.Data[CONDUIT_TSECT_INDEX] := TokList[3];
Result := 0;
end;
end;
end;
ORIFICE:
begin
if not I in [0, 1] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[ORIFICE_SHAPE_INDEX] := TokList[1];
aLink.Data[ORIFICE_HEIGHT_INDEX] := TokList[2];
aLink.Data[ORIFICE_WIDTH_INDEX] := TokList[3];
Result := 0;
end;
end;
WEIR:
begin
if not I in [2, 3, 4] then Result := ErrMsg(XSECT_ERR, TokList[0])
else begin
aLink.Data[WEIR_SHAPE_INDEX] := TokList[1];
aLink.Data[WEIR_HEIGHT_INDEX] := TokList[2];
aLink.Data[WEIR_WIDTH_INDEX] := TokList[3];
aLink.Data[WEIR_SLOPE_INDEX] := TokList[4];
Result := 0;
end;
end;
else Result := 0;
end;
end;
end;
end;
function ReadTransectData: Integer;
//-----------------------------------------------------------------------------
// Reads transect data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
K : Integer;
N : Integer;
ID : String;
Tsect : TTransect;
begin
Result := 0;
if SameText(TokList[0], 'NC') then
begin
if nToks < 4 then Result := ErrMsg(ITEMS_ERR, '')
else for I := 1 to 3 do ManningsN[I] := TokList[I];
TsectComment := Comment;
Exit;
end;
if SameText(TokList[0], 'X1') then
begin
if nToks < 2 then Exit;
ID := TokList[1];
Tsect := TTransect.Create;
if Length(Comment) > 0 then TsectComment := Comment;
Tsect.Comment := TsectComment;
Project.Lists[TRANSECT].AddObject(ID, Tsect);
Project.HasItems[TRANSECT] := True;
Tsect.Data[TRANSECT_N_LEFT] := ManningsN[1];
Tsect.Data[TRANSECT_N_RIGHT] := ManningsN[2];
Tsect.Data[TRANSECT_N_CHANNEL] := ManningsN[3];
if nToks < 10 then Result := ErrMsg(ITEMS_ERR, '')
else
begin
Tsect.Data[TRANSECT_X_LEFT] := TokList[3];
Tsect.Data[TRANSECT_X_RIGHT] := TokList[4];
Tsect.Data[TRANSECT_L_FACTOR] := TokList[7];
Tsect.Data[TRANSECT_X_FACTOR] := TokList[8];
Tsect.Data[TRANSECT_Y_FACTOR] := TokList[9];
end;
Exit;
end;
if SameText(TokList[0], 'GR') then
begin
N := Project.Lists[TRANSECT].Count;
if N = 0 then Result := ErrMsg(TRANSECT_ERR, '')
else begin
Tsect := TTransect(Project.Lists[TRANSECT].Objects[N-1]);
K := 1;
while K + 1 < Ntoks do
begin
Tsect.Ydata.Add(TokList[K]);
Tsect.Xdata.Add(TokList[K+1]);
K := K + 2;
end;
end;
Exit;
end;
end;
function ReadLossData: Integer;
//-----------------------------------------------------------------------------
// Reads conduit loss data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLink : TLink;
begin
if nToks < 4
then Result := ErrMsg(ITEMS_ERR, '')
else begin
ID := TokList[0];
aLink := FindLink(ID);
if (aLink = nil) then Result := ErrMsg(LINK_ERR, ID)
else if (aLink.Ltype <> CONDUIT) then Result := 0
else begin
aLink.Data[CONDUIT_ENTRY_LOSS_INDEX] := TokList[1];
aLink.Data[CONDUIT_EXIT_LOSS_INDEX] := TokList[2];
aLink.Data[CONDUIT_AVG_LOSS_INDEX] := TokList[3];
if nToks >= 5
then aLink.Data[CONDUIT_CHECK_VALVE_INDEX] := TokList[4];
if nToks >= 6
then aLink.Data[CONDUIT_SEEPAGE_INDEX] := TokList[5];
Result := 0;
end;
end;
end;
function ReadPollutantData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aPollut : TPollutant;
X : Single;
begin
if nToks < 5
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Add new pollutant to project
ID := TokList[0];
aPollut := TPollutant.Create;
Uutils.CopyStringArray(Project.DefProp[POLLUTANT].Data, aPollut.Data);
Project.Lists[POLLUTANT].AddObject(ID, aPollut);
Project.HasItems[POLLUTANT] := True;
// Parse units & concens.
aPollut.Data[POLLUT_UNITS_INDEX] := TokList[1];
aPollut.Data[POLLUT_RAIN_INDEX] := TokList[2];
aPollut.Data[POLLUT_GW_INDEX] := TokList[3];
// This is for old format
if (Ntoks = 5)
or ( (Ntoks = 7) and Uutils.GetSingle(TokList[6], X) ) then
begin
aPollut.Data[POLLUT_DECAY_INDEX] := TokList[4];
if nToks >= 7 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[5];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[6];
end;
end
// This is for new format
else
begin
aPollut.Data[POLLUT_II_INDEX] := TokList[4];
if Ntoks >= 6 then aPollut.Data[POLLUT_DECAY_INDEX] := TokList[5];
if nToks >= 7 then aPollut.Data[POLLUT_SNOW_INDEX] := TokList[6];
if Ntoks >= 9 then
begin
aPollut.Data[POLLUT_COPOLLUT_INDEX] := TokList[7];
aPollut.Data[POLLUT_FRACTION_INDEX] := TokList[8];
end;
if Ntoks >= 10 then aPollut.Data[POLLUT_DWF_INDEX] := TokList[9];
if Ntoks >= 11 then aPollut.Data[POLLUT_INIT_INDEX] := TokList[10];
end;
Result := 0;
end;
end;
function ReadLanduseData: Integer;
//-----------------------------------------------------------------------------
// Reads land use data from a line of input.
//-----------------------------------------------------------------------------
var
ID : String;
aLanduse : TLanduse;
aNonPtSource : TNonpointSource;
J : Integer;
begin
ID := TokList[0];
aLanduse := TLanduse.Create;
for J := 0 to Project.Lists[POLLUTANT].Count - 1 do
begin
aNonPtSource := TNonpointSource.Create;
aLanduse.NonpointSources.AddObject(Project.Lists[POLLUTANT].Strings[J],
aNonPtSource);
end;
Project.Lists[LANDUSE].AddObject(ID, aLanduse);
Project.HasItems[LANDUSE] := True;
if Ntoks > 1 then aLanduse.Data[LANDUSE_CLEANING_INDEX] := TokList[1];
if Ntoks > 2 then aLanduse.Data[LANDUSE_AVAILABLE_INDEX] := TokList[2];
if Ntoks > 3 then aLanduse.Data[LANDUSE_LASTCLEAN_INDEX] := TokList[3];
aLanduse.Data[COMMENT_INDEX ] := Comment;
Result := 0;
end;
function ReadBuildupData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant buildup function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.BuildupData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadWashoffData: Integer;
//-----------------------------------------------------------------------------
// Reads pollutant washoff function data from a line of input.
//-----------------------------------------------------------------------------
var
LanduseIndex : Integer;
PollutIndex : Integer;
aLanduse : TLanduse;
aNonpointSource: TNonpointSource;
J : Integer;
begin
if nToks < 7
then Result := ErrMsg(ITEMS_ERR, '')
else begin
LanduseIndex := Project.Lists[LANDUSE].IndexOf(TokList[0]);
PollutIndex := Project.Lists[POLLUTANT].IndexOf(TokList[1]);
if (LanduseIndex < 0) then Result := ErrMsg(LANDUSE_ERR, TokList[0])
else if (PollutIndex < 0) then Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
aLanduse := TLanduse(Project.Lists[LANDUSE].Objects[LanduseIndex]);
aNonpointSource :=
TNonpointSource(aLanduse.NonpointSources.Objects[PollutIndex]);
for J := 2 to 6 do
aNonpointSource.WashoffData[J-2] := TokList[J];
Result := 0;
end;
end;
end;
function ReadCoverageData: Integer;
//-----------------------------------------------------------------------------
// Reads land use coverage data from a line of input.
//-----------------------------------------------------------------------------
var
MaxToks: Integer;
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
Result := 0;
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else begin
MaxToks := 3;
while (MaxToks <= nToks) do
begin
if not Uutils.GetSingle(TokList[MaxToks-1], X) then
begin
Result := ErrMsg(NUMBER_ERR, TokList[MaxToks-1]);
break;
end;
S1 := TokList[MaxToks-2];
I := S.LandUses.IndexOfName(S1);
S1 := TokList[MaxToks-2] + '=' + TokList[MaxToks-1];
if I < 0
then S.LandUses.Add(S1)
else S.Landuses[I] := S1;
MaxToks := MaxToks + 2;
end;
S.Data[SUBCATCH_LANDUSE_INDEX] := IntToStr(S.LandUses.Count);
end;
end;
function ReadTreatmentData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads pollutant treatment function from a line of input.
//-----------------------------------------------------------------------------
var
S : String;
aNode : TNode;
I : Integer;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0 then
Result := ErrMsg(POLLUT_ERR, TokList[1])
else begin
I := aNode.Treatment.IndexOfName(TokList[1]);
S := Copy(Line, Pos(TokList[1], Line)+Length(TokList[1]), Length(Line));
S := TokList[1] + '=' + Trim(S);
if I < 0 then
aNode.Treatment.Add(S)
else
aNode.Treatment[I] := S;
aNode.Data[NODE_TREAT_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadExInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads external inflow data from a line of input.
//-----------------------------------------------------------------------------
var
S : array[1..7] of String;
Inflow: String;
I : Integer;
aNode : TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S[1] := TokList[1]; // Constituent name
S[2] := TokList[2]; // Time Series name
S[3] := 'FLOW';
S[4] := '1.0';
if not SameText(S[1], 'FLOW') then
begin
if nToks >= 4 then S[3] := TokList[3] else S[3] := 'CONCEN';
if nToks >= 5 then S[4] := TokList[4] else S[4] := '1.0';
end;
if nToks >= 6 then S[5] := TokList[5] else S[5] := '1.0';
if nToks >= 7 then S[6] := TokList[6] else S[6] := '';
if nToks >= 8 then S[7] := TokList[7] else S[7] := '';
Inflow := S[1] + '=' + S[2] + #13 + S[3] + #13 + S[4] + #13 +
S[5] + #13 + S[6] + #13 + S[7];
I := aNode.DXInflow.IndexOfName(S[1]);
if I < 0 then aNode.DXInflow.Add(Inflow)
else aNode.DXInflow[I] := Inflow;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadDWInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads dry weather inflow data from a line of input.
//-----------------------------------------------------------------------------
var
M : Integer;
S : String;
S1 : String;
I : Integer;
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
S1 := TokList[1];
S := S1 + '=' + TokList[2];
for M := 3 to Ntoks-1 do S := S + #13 + TokList[M];
I := aNode.DWInflow.IndexOfName(S1);
if I < 0
then aNode.DWInflow.Add(S)
else aNode.DWInflow[I] := S;
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadPatternData: Integer;
//-----------------------------------------------------------------------------
// Reads time pattern data from a line of input.
//-----------------------------------------------------------------------------
var
ID: String;
Index: Integer;
aPattern: TPattern;
PatType: Integer;
J: Integer;
begin
if nToks < 2
then Result := ErrMsg(ITEMS_ERR, '')
else begin
J := 1;
ID := TokList[0];
Index := Project.Lists[PATTERN].IndexOf(ID);
if Index < 0 then
begin
aPattern := TPattern.Create;
aPattern.Comment := Comment;
Project.Lists[PATTERN].AddObject(ID, aPattern);
Project.HasItems[PATTERN] := True;
PatType := Uutils.FindKeyWord(TokList[1], PatternTypes, 7);
if PatType < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
exit;
end;
aPattern.PatternType := PatType;
J := 2;
end
else aPattern := TPattern(Project.Lists[PATTERN].Objects[Index]);
while (J < nToks) and (aPattern.Count <= High(aPattern.Data)) do
begin
aPattern.Data[aPattern.Count] := TokList[J];
Inc(J);
Inc(aPattern.Count);
end;
Result := 0;
end;
end;
function ReadIIInflowData: Integer;
//-----------------------------------------------------------------------------
// Reads RDII inflow data from a line of input.
//-----------------------------------------------------------------------------
var
aNode: TNode;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
aNode := FindNode(TokList[0]);
if (aNode = nil) then Result := ErrMsg(NODE_ERR, TokList[0])
else begin
aNode.IIInflow.Clear;
aNode.IIInflow.Add(TokList[1]);
aNode.IIInflow.Add(TokList[2]);
aNode.Data[NODE_INFLOWS_INDEX] := 'YES';
Result := 0;
end;
end;
end;
function ReadLoadData: Integer;
//-----------------------------------------------------------------------------
// Reads initial pollutant loading data from a line of input.
//-----------------------------------------------------------------------------
var
X : Single;
S : TSubcatch;
S1 : String;
I : Integer;
begin
S := FindSubcatch(TokList[0]);
if S = nil
then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else if Project.Lists[POLLUTANT].IndexOf(TokList[1]) < 0
then Result := ErrMsg(POLLUT_ERR, TokList[1])
else if not Uutils.GetSingle(TokList[2], X)
then Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
S1 := TokList[1] + '=' + TokList[2];
I := S.Loadings.IndexOfName(TokList[1]);
if I < 0
then S.Loadings.Add(S1)
else S.Loadings[I] := S1;
S.Data[SUBCATCH_LOADING_INDEX] := 'YES';
Result := 0;
end;
end;
function ReadCurveData: Integer;
//-----------------------------------------------------------------------------
// Reads curve data from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
K : Integer;
L : Integer;
M : Integer;
ObjType : Integer;
ID : String;
aCurve : TCurve;
begin
// Check for too few tokens
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Check if curve ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then
begin
Index := PrevIndex;
ObjType := CurveType;
end
else Project.FindCurve(ID, ObjType, Index);
// Create new curve if ID not in data base
K := 2;
if Index < 0 then
begin
// Check for valid curve type keyword
M := -1;
for L := 0 to High(CurveTypeOptions) do
begin
if SameText(TokList[1], CurveTypeOptions[L]) then
begin
M := L;
break;
end;
end;
if M < 0 then
begin
Result := ErrMsg(KEYWORD_ERR, TokList[1]);
Exit;
end;
// Convert curve type keyword index to a curve object category
case M of
0: ObjType := CONTROLCURVE;
1: ObjType := DIVERSIONCURVE;
2..5:
ObjType := PUMPCURVE;
6: ObjType := RATINGCURVE;
7: ObjType := SHAPECURVE;
8: ObjType := STORAGECURVE;
9: ObjType := TIDALCURVE;
end;
// Create a new curve object
aCurve := TCurve.Create;
aCurve.Comment := Comment;
aCurve.CurveType := TokList[1];
if ObjType = PUMPCURVE
then aCurve.CurveCode := M - 1
else aCurve.CurveCode := 0;
Project.Lists[ObjType].AddObject(ID, aCurve);
Project.HasItems[ObjType] := True;
Index := Project.Lists[ObjType].Count - 1;
PrevID := ID;
PrevIndex := Index;
CurveType := ObjType;
K := 3;
end;
// Add x,y values to the list maintained by the curve
aCurve := TCurve(Project.Lists[ObjType].Objects[Index]);
while K <= nToks-1 do
begin
aCurve.Xdata.Add(TokList[K-1]);
aCurve.Ydata.Add(TokList[K]);
K := K + 2;
end;
Result := 0;
end;
end;
function ReadTimeseriesData: Integer;
//-----------------------------------------------------------------------------
// Reads time series data from a line of input.
//-----------------------------------------------------------------------------
const
NEEDS_DATE = 1;
NEEDS_TIME = 2;
NEEDS_VALUE = 3;
var
Index : Integer;
State : Integer;
K : Integer;
ID : String;
StrDate : String;
aTseries : TTimeseries;
begin
// Check for too few tokens
Result := -1;
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '');
// Check if series ID is same as for previous line
ID := TokList[0];
if (ID = PrevID) then Index := PrevIndex
else Index := Project.Lists[TIMESERIES].IndexOf(ID);
// If starting input for a new series then create it
if Index < 0 then
begin
aTseries := TTimeseries.Create;
aTseries.Comment := Comment;
Project.Lists[TIMESERIES].AddObject(ID,aTseries);
Project.HasItems[TIMESERIES] := True;
Index := Project.Lists[TIMESERIES].Count - 1;
PrevID := ID;
PrevIndex := Index;
end;
aTseries := TTimeseries(Project.Lists[TIMESERIES].Objects[Index]);
// Check if external file name used
if SameText(TokList[1], 'FILE') then
begin
aTseries.Filename := TokList[2];
Result := 0;
Exit;
end;
// Add values to the list maintained by the timeseries
State := NEEDS_DATE;
K := 1;
while K < nToks do
begin
case State of
NEEDS_DATE:
begin
try
StrDate := Uutils.ConvertDate(TokList[K]);
StrToDate(StrDate, MyFormatSettings);
aTseries.Dates.Add(StrDate);
Inc(K);
if K >= nToks then break;
except
On EconvertError do aTseries.Dates.Add('');
end;
State := NEEDS_TIME;
end;
NEEDS_TIME:
begin
aTseries.Times.Add(TokList[K]);
Inc(K);
if K >= nToks then break;
State := NEEDS_VALUE;
end;
NEEDS_VALUE:
begin
aTseries.Values.Add(TokList[K]);
Result := 0;
State := NEEDS_DATE;
Inc(K);
end;
end;
end;
if Result = -1 then Result := ErrMsg(ITEMS_ERR, '');
end;
function ReadControlData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads a control rule statement from line of input.
//-----------------------------------------------------------------------------
begin
Project.ControlRules.Add(Line);
Result := 0;
end;
function ReadLidUsageData: Integer;
//-----------------------------------------------------------------------------
// Reads LID usage data from line of input.
//-----------------------------------------------------------------------------
var
aSubcatch: TSubcatch;
begin
aSubcatch := FindSubcatch(TokList[0]);
if aSubcatch = nil then Result := ErrMsg(SUBCATCH_ERR, TokList[0])
else Result := Ulid.ReadLIDUsageData(aSubcatch, TokList, Ntoks);
end;
procedure ReadReportOption(Index: Integer);
begin
if (Ntoks >= 2) and SameText(TokList[1], 'YES') then
Project.Options.Data[Index] := 'YES'
else
Project.Options.Data[Index] := 'NO';
end;
function ReadReportData: Integer;
//-----------------------------------------------------------------------------
// Reads reporting options from a line of input.
//-----------------------------------------------------------------------------
begin
if SameText(TokList[0], 'CONTROLS')
then ReadReportOption(REPORT_CONTROLS_INDEX)
else if SameText(TokList[0], 'INPUT')
then ReadReportOption(REPORT_INPUT_INDEX)
else ReportingForm.Import(TokList, Ntoks);
Result := 0;
end;
function ReadFileData: Integer;
//-----------------------------------------------------------------------------
// Reads interface file usage from a line of input.
//-----------------------------------------------------------------------------
var
Fname: String;
begin
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
Fname := TokList[2];
if ExtractFilePath(Fname) = ''
then Fname := ExtractFilePath(Uglobals.InputFileName) + Fname;
Project.IfaceFiles.Add(TokList[0] + ' ' + TokList[1] + ' ' +
'"' + Fname + '"');
Result := 0;
end;
end;
//// This function was added to release 5.1.007. //// //(5.1.007)
function ReadAdjustmentData: Integer;
//-----------------------------------------------------------------------------
// Reads climate adjustments from a line of input.
//-----------------------------------------------------------------------------
var
I: Integer;
begin
Result := 0;
if Ntoks < 2 then exit;
if SameText(TokList[0], 'Temperature') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then TempAdjust[I] := ''
else TempAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Evaporation') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 0.0) = 0.0
then EvapAdjust[I] := ''
else EvapAdjust[I] := TokList[I+1];
end;
end
else if SameText(TokList[0], 'Rainfall') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then RainAdjust[I] := ''
else RainAdjust[I] := TokList[I+1];
end;
end
//// Added to release 5.1.008. //// //(5.1.008)
else if SameText(TokList[0], 'Conductivity') then
begin
if Ntoks < 13 then Result := ErrMsg(ITEMS_ERR, '')
else with Project.Climatology do
begin
for I := 0 to 11 do
if StrToFloatDef(TokList[I+1], 1.0) = 1.0
then CondAdjust[I] := ''
else CondAdjust[I] := TokList[I+1];
end;
end;
////////////////////////////////////////////////////////
end;
//// This function was added to release 5.1.011. //// //(5.1.011)
function ReadEventData(Line: String): Integer;
//-----------------------------------------------------------------------------
// Reads hydraulic event data from a line of input.
//-----------------------------------------------------------------------------
begin
Result := 0;
if Length(Line) = 0 then exit;
if LeftStr(Line,2) = ';;' then exit;
Project.Events.Add(Line);
end;
function ReadOptionData: Integer;
//-----------------------------------------------------------------------------
// Reads an analysis option from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
S : String;
S2: String;
I : Integer;
X : Single;
T : Extended;
begin
// Check which keyword applies
Result := 0;
if Ntoks < 2 then exit;
Keyword := TokList[0];
if SameText(Keyword, 'TEMPDIR') then exit;
Index := Uutils.FindKeyWord(Keyword, OptionLabels, 17);
case Index of
-1: Result := ErrMsg(KEYWORD_ERR, Keyword);
ROUTING_MODEL_INDEX:
begin
if SameText(TokList[1], 'NONE') then
begin
Project.Options.Data[IGNORE_ROUTING_INDEX] := 'YES';
Exit;
end;
I := Uutils.FindKeyWord(TokList[1], OldRoutingOptions, 3);
if I >= 0 then TokList[1] := RoutingOptions[I];
end;
START_DATE_INDEX, REPORT_START_DATE_INDEX, END_DATE_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
try
StrToDate(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
START_TIME_INDEX, REPORT_START_TIME_INDEX, END_TIME_INDEX:
begin
S := TokList[1];
try
StrToTime(S, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
SWEEP_START_INDEX, SWEEP_END_INDEX:
begin
S := Uutils.ConvertDate(TokList[1]);
S2 := S + '/1947';
try
StrToDate(S2, MyFormatSettings);
TokList[1] := S;
except
on EConvertError do Result := ErrMsg(DATE_ERR, '');
end;
end;
WET_STEP_INDEX, DRY_STEP_INDEX, REPORT_STEP_INDEX:
begin
S := TokList[1];
if Uutils.StrHoursToTime(S) = -1 then Result := ErrMsg(TIMESTEP_ERR, '');
end;
ROUTING_STEP_INDEX:
begin
S := TokList[1];
T := 0.0;
if not Uutils.GetExtended(S, T) then
begin
T := Uutils.StrHoursToTime(S)*86400.;
if T <= 0.0 then Result := ErrMsg(TIMESTEP_ERR, '')
else TokList[1] := Format('%.0f',[T]);
end;
end;
VARIABLE_STEP_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
TokList[1] := IntToStr(Round(100.0*X))
else
TokList[1] := '0';
end;
INERTIAL_DAMPING_INDEX:
begin
if Uutils.GetSingle(TokList[1], X) then
begin
if X = 0 then TokList[1] := 'NONE'
else TokList[1] := 'PARTIAL';
end;
end;
// This option is now fixed to SWMM 4.
COMPATIBILITY_INDEX:
begin
TokList[1] := '4';
end;
MIN_ROUTE_STEP_INDEX, //(5.1.008)
LENGTHEN_STEP_INDEX,
MIN_SURFAREA_INDEX,
MIN_SLOPE_INDEX,
MAX_TRIALS_INDEX,
HEAD_TOL_INDEX,
SYS_FLOW_TOL_INDEX,
LAT_FLOW_TOL_INDEX:
begin
Uutils.GetSingle(TokList[1], X);
if X <= 0 then TokList[1] := '0';
end;
NORMAL_FLOW_LTD_INDEX:
begin
if SameText(TokList[1], 'NO') or SameText(TokList[1], 'SLOPE')
then TokList[1] := 'SLOPE'
else if SameText(TokList[1], 'YES') or SameText(TokList[1], 'FROUDE')
then TokList[1] := 'FROUDE'
else if SameText(TokList[1], 'BOTH') then TokList[1] := 'BOTH'
else Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
FORCE_MAIN_EQN_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], ForceMainEqnOptions, 3);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := ForceMainEqnOptions[I];
end;
LINK_OFFSETS_INDEX:
begin
I := Uutils.FindKeyWord(TokList[1], LinkOffsetsOptions, 10);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else TokList[1] := LinkOffsetsOptions[I];
end;
IGNORE_RAINFALL_INDEX,
IGNORE_SNOWMELT_INDEX,
IGNORE_GRNDWTR_INDEX,
IGNORE_ROUTING_INDEX,
IGNORE_QUALITY_INDEX:
begin
if not SameText(TokList[1], 'YES') and not SameText(TokList[1], 'NO')
then Result := ErrMsg(KEYWORD_ERR, TokList[1]);
end;
//// Following section added to release 5.1.010. //// //(5.1.010)
NUM_THREADS_INDEX:
begin
I := StrToIntDef(TokList[1], 1);
if I < 0 then I := 1;
if (I = 0) or (I > Uutils.GetCPUs) then I := Uutils.GetCPUs;
TokList[1] := IntToStr(I);
end;
////
end;
if Result = 0 then Project.Options.Data[Index] := TokList[1];
end;
function ReadTagData: Integer;
//-----------------------------------------------------------------------------
// Reads in tag data from a line of input.
//-----------------------------------------------------------------------------
const
TagTypes: array[0..3] of PChar = ('Gage', 'Subcatch', 'Node', 'Link');
var
I, J : Integer;
aNode: TNode;
aLink: TLink;
begin
Result := 0;
if Ntoks < 3
then Result := ErrMsg(ITEMS_ERR, '')
else begin
I := Uutils.FindKeyWord(TokList[0], TagTypes, 4);
case I of
-1: Result := ErrMsg(KEYWORD_ERR, TokList[0]);
0: begin
J := Project.Lists[RAINGAGE].IndexOf(TokList[1]);
if J >= 0 then with Project.GetGage(J) do Data[TAG_INDEX] := TokList[2];
end;
1: begin
J := Project.Lists[SUBCATCH].IndexOf(TokList[1]);
if J >= 0 then with Project.GetSubcatch(SUBCATCH, J) do
Data[TAG_INDEX] := TokList[2];
end;
2: begin
aNode := FindNode(TokList[1]);
if (aNode <> nil) then aNode.Data[TAG_INDEX] := TokList[2];
end;
3: begin
aLink := FindLink(TokList[1]);
if (aLink <> nil) then aLink.Data[TAG_INDEX] := TokList[2];
end;
end;
end;
end;
function ReadSymbolData: Integer;
//-----------------------------------------------------------------------------
// Reads rain gage coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
J : Integer;
X, Y : Extended;
aGage : TRaingage;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the gage ID in the database
J := Project.Lists[RAINGAGE].IndexOf(TokList[0]);
// If gage exists then assign it X & Y coordinates
if (J >= 0) then
begin
aGage := Project.GetGage(J);
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aGage.X := X;
aGage.Y := Y;
end;
end;
end;
end;
function ReadMapData: Integer;
//-----------------------------------------------------------------------------
// Reads map dimensions data from a line of input.
//-----------------------------------------------------------------------------
var
I : Integer;
Index : Integer;
Keyword : String;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, MapWords, 4);
case Index of
0: // Map dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for I := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Dimensions do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
MapExtentSet := True;
end;
end;
end;
1: //Map units
if Ntoks > 1 then
begin
I := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
with MapForm.Map.Dimensions do
begin
if Units = muDegrees then Digits := MAXDEGDIGITS
else Digits := Umap.DefMapDimensions.Digits;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadCoordData: Integer;
//-----------------------------------------------------------------------------
// Reads node coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aNode : TNode;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the node ID in the database
aNode := FindNode(TokList[0]);
// If node exists then assign it X & Y coordinates
if (aNode <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
aNode.X := X;
aNode.Y := Y;
end;
end;
end;
end;
function ReadVertexData: Integer;
//-----------------------------------------------------------------------------
// Reads link vertex coordinate data from a line of input.
//-----------------------------------------------------------------------------
var
X, Y : Extended;
aLink : TLink;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the link ID in the database
aLink := FindLink(TokList[0]);;
// If link exists then assign it X & Y coordinates
if (aLink <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else aLink.Vlist.Add(X, Y);
end;
end;
end;
function ReadPolygonData: Integer;
//-----------------------------------------------------------------------------
// Reads polygon coordinates associated with subcatchment outlines.
//-----------------------------------------------------------------------------
var
Index : Integer;
X, Y : Extended;
S : TSubcatch;
begin
Result := 0;
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
// Locate the subcatchment ID in the database
S := nil;
Index := Project.Lists[SUBCATCH].IndexOf(TokList[0]);
if Index >= 0 then S := Project.GetSubcatch(SUBCATCH, Index);
// If subcatchment exists then add a new vertex to it
if (S <> nil) then
begin
if not Uutils.GetExtended(TokList[1], X) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else S.Vlist.Add(X, Y);
end;
end;
end;
function ReadLabelData: Integer;
//-----------------------------------------------------------------------------
// Reads map label data from a line of input.
//-----------------------------------------------------------------------------
var
Ntype : Integer;
Index : Integer;
X, Y : Extended;
S : String;
aMapLabel: TMapLabel;
begin
if (Ntoks < 3)
then Result := ErrMsg(ITEMS_ERR, '')
else begin
if not Uutils.GetExtended(TokList[0], X) then
Result := ErrMsg(NUMBER_ERR, TokList[0])
else if not Uutils.GetExtended(TokList[1], Y) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else begin
S := TokList[2];
aMapLabel := TMapLabel.Create;
aMapLabel.X := X;
aMapLabel.Y := Y;
Project.Lists[MAPLABEL].AddObject(S, aMapLabel);
Index := Project.Lists[MAPLABEL].Count - 1;
aMapLabel.Text := PChar(Project.Lists[MAPLABEL].Strings[Index]);
Project.HasItems[MAPLABEL] := True;
if Ntoks >= 4 then
begin
if (Length(TokList[3]) > 0) and
Project.FindNode(TokList[3], Ntype, Index) then
aMapLabel.Anchor := Project.GetNode(Ntype, Index);
end;
if Ntoks >= 5 then aMapLabel.FontName := TokList[4];
if Ntoks >= 6 then aMapLabel.FontSize := StrToInt(TokList[5]);
if Ntoks >= 7 then
if StrToInt(TokList[6]) = 1 then aMapLabel.FontBold := True;
if Ntoks >= 8 then
if StrToInt(TokList[7]) = 1 then aMapLabel.FontItalic := True;
Result := 0;
end;
end;
end;
function ReadBackdropData: Integer;
//-----------------------------------------------------------------------------
// Reads map backdrop image information from a line of input.
//-----------------------------------------------------------------------------
var
Index : Integer;
Keyword : String;
I : Integer;
X : array[1..4] of Extended;
begin
// Check which keyword applies
Result := 0;
Keyword := TokList[0];
Index := Uutils.FindKeyWord(Keyword, BackdropWords, 4);
case Index of
0: //Backdrop file
if Ntoks > 1 then MapForm.Map.Backdrop.Filename := TokList[1];
1: // Backdrop dimensions
begin
if Ntoks < 5 then Result := ErrMsg(ITEMS_ERR, '')
else begin
for i := 1 to 4 do
if not Uutils.GetExtended(TokList[I], X[I]) then
Result := ErrMsg(NUMBER_ERR, TokList[I]);
if Result = 0 then with MapForm.Map.Backdrop do
begin
LowerLeft.X := X[1];
LowerLeft.Y := X[2];
UpperRight.X := X[3];
UpperRight.Y := X[4];
end;
end;
end;
2: //Map units - deprecated
if Ntoks > 1 then
begin
i := Uutils.FindKeyWord(Copy(TokList[1], 1, 1), MapUnits, 1);
if I < 0 then Result := ErrMsg(KEYWORD_ERR, TokList[1])
else MapForm.Map.Dimensions.Units := TMapUnits(I);
end;
3, 4: //Backdrop offset or scaling -- deprecated
begin
if Ntoks < 3 then Result := ErrMsg(ITEMS_ERR, '')
else if not Uutils.GetExtended(TokList[1], X[1]) then
Result := ErrMsg(NUMBER_ERR, TokList[1])
else if not Uutils.GetExtended(TokList[2], X[2]) then
Result := ErrMsg(NUMBER_ERR, TokList[2])
else
begin
if Index = 3 then
begin
BackdropX := X[1];
BackdropY := X[2];
end
else
begin
BackdropW := X[1];
BackdropH := X[2];
end;
end;
end;
else Result := ErrMsg(KEYWORD_ERR, Keyword);
end;
end;
function ReadProfileData: Integer;
//-----------------------------------------------------------------------------
// Reads profile plot data from a line of input.
//-----------------------------------------------------------------------------
var
I, J: Integer;
S : String;
begin
Result := 0;
if (Ntoks < 2) then Exit;
// Locate the profile name in the database
I := Project.ProfileNames.IndexOf(TokList[0]);
// If profile does not exist then create it
if (I < 0) then
begin
Project.ProfileNames.Add(TokList[0]);
I := Project.ProfileNames.Count-1;
S := '';
Project.ProfileLinks.Add(S);
end
else S := Project.ProfileLinks[I] + #13;
// Add each remaining token to the list of links in the profile
S := S + TokList[1];
for J := 2 to Ntoks-1 do
S := S + #13 + TokList[J];
Project.ProfileLinks[I] := S;
end;
procedure SetMapDimensions;
//-----------------------------------------------------------------------------
// Determines map dimensions based on range of object coordinates.
//-----------------------------------------------------------------------------
begin
with MapForm.Map do
begin
// Dimensions not provided in [MAP] section
if not MapExtentSet then
begin
// Dimensions were provided in [BACKDROP] section
if (Backdrop.LowerLeft.X <> Backdrop.UpperRight.X) then
begin
// Interpret these as map dimensions
Dimensions.LowerLeft := Backdrop.LowerLeft;
Dimensions.UpperRight := Backdrop.UpperRight;
// Compute backdrop dimensions from Offset and Scale values
Backdrop.LowerLeft.X := BackdropX;
Backdrop.LowerLeft.Y := BackdropY - BackdropH;
Backdrop.UpperRight.X := BackdropX + BackdropW;
Backdrop.UpperRight.Y := BackdropY;
end
// No dimensions of any kind provided
else with Dimensions do
Ucoords.GetCoordExtents(LowerLeft.X, LowerLeft.Y,
UpperRight.X, UpperRight.Y);
end;
end;
end;
function ParseInpLine(S: String): Integer;
//-----------------------------------------------------------------------------
// Parses current input line depending on current section of input file.
//-----------------------------------------------------------------------------
begin
case Section of
1: Result := ReadOptionData;
2: Result := ReadRaingageData;
3: Result := ReadHydrographData;
4: Result := ReadEvaporationData;
5: Result := ReadSubcatchmentData;
6: Result := ReadSubareaData;
7: Result := ReadInfiltrationData;
8: Result := ReadAquiferData;
9: Result := ReadGroundwaterData;
10: Result := ReadJunctionData;
11: Result := ReadOutfallData;
12: Result := ReadStorageData;
13: Result := ReadDividerData;
14: Result := ReadConduitData;
15: Result := ReadPumpData;
16: Result := ReadOrificeData;
17: Result := ReadWeirData;
18: Result := ReadOutletData;
19: Result := ReadXsectionData;
20: Result := ReadTransectData;
21: Result := ReadLossData;
//22: ReadControlData called directly from ReadFile
23: Result := ReadPollutantData;
24: Result := ReadLanduseData;
25: Result := ReadBuildupData;
26: Result := ReadWashoffData;
27: Result := ReadCoverageData;
28: Result := ReadExInflowData;
29: Result := ReadDWInflowData;
30: Result := ReadPatternData;
31: Result := ReadIIInflowData;
32: Result := ReadLoadData;
33: Result := ReadCurveData;
34: Result := ReadTimeseriesData;
35: Result := ReadReportData;
36: Result := ReadFileData;
37: Result := ReadMapData;
38: Result := ReadCoordData;
39: Result := ReadVertexdata;
40: Result := ReadPolygonData;
41: Result := ReadSymbolData;
42: Result := ReadLabelData;
43: Result := ReadBackdropData;
44: Result := ReadProfileData;
45: Result := ReadCurveData;
46: Result := ReadTemperatureData;
47: Result := ReadSnowpackData;
48: Result := ReadTreatmentData(S);
49: Result := ReadTagData;
50: Result := Ulid.ReadLidData(TokList, Ntoks);
51: Result := ReadLidUsageData;
52: Result := ReadGroundwaterFlowEqn(S);
53: Result := ReadAdjustmentData; //(5.1.007)
else Result := 0;
end;
end;
function ParseImportLine(Line: String): Integer;
//-----------------------------------------------------------------------------
// Processes line of input from imported scenario or map file.
// (Not currently used.)
//-----------------------------------------------------------------------------
begin
Result := 0;
end;
procedure StripComment(const Line: String; var S: String);
//-----------------------------------------------------------------------------
// Strips comment (text following a ';') from a line of input.
// Ignores comment if it begins with ';;'.
//-----------------------------------------------------------------------------
var
P: Integer;
N: Integer;
C: String;
begin
C := '';
S := Trim(Line);
P := Pos(';', S);
if P > 0 then
begin
N := Length(S);
C := Copy(S, P+1, N);
if (Length(C) >= 1) and (C[1] <> ';') then
begin
if Length(Comment) > 0 then Comment := Comment + #13;
Comment := Comment + C;
end;
Delete(S, P, N);
end;
end;
function FindNewSection(const S: String): Integer;
//-----------------------------------------------------------------------------
// Checks if S matches any of the section heading key words.
//-----------------------------------------------------------------------------
var
K: Integer;
begin
for K := 0 to High(SectionWords) do
begin
if Pos(SectionWords[K], S) = 1 then
begin
Result := K;
Exit;
end;
end;
Result := -1;
end;
function StartNewSection(S: String): Integer;
//-----------------------------------------------------------------------------
// Begins reading a new section of the input file.
//-----------------------------------------------------------------------------
var
K : Integer;
begin
// Determine which new section to begin
K := FindNewSection(UpperCase(S));
if (K >= 0) then
begin
//Update section code
Section := K;
PrevID := '';
Result := 0;
end
else Result := ErrMsg(KEYWORD_ERR, S);
Comment := '';
end;
function ReadFile(var F: Textfile; const Fsize: Int64):Boolean;
//-----------------------------------------------------------------------------
// Reads each line of a SWMM input file.
//-----------------------------------------------------------------------------
var
Err : Integer;
ByteCount : Integer;
StepCount : Integer;
StepSize : Integer;
S : String;
begin
Result := True;
ErrCount := 0;
LineCount := 0;
Comment := '';
// Initialize progress meter settings
StepCount := MainForm.ProgressBar.Max div MainForm.ProgressBar.Step;
StepSize := Fsize div StepCount;
if StepSize < 1000 then StepSize := 0;
ByteCount := 0;
// Read each line of input file
Reset(F);
while not Eof(F) do
begin
Err := 0;
Readln(F, Line);
Inc(LineCount);
if StepSize > 0 then
begin
Inc(ByteCount, Length(Line));
MainForm.UpdateProgressBar(ByteCount, StepSize);
end;
// Strip out trailing spaces, control characters & comment
Line := TrimRight(Line);
StripComment(Line, S);
// Check if line begins a new input section
if (Pos('[', S) = 1) then Err := StartNewSection(S)
else
begin
//// Following code section modified for release 5.1.011. //// //(5.1.011)
// Check if line contains project title/notes
if (Section = 0) and (Length(Line) > 0) then
begin
if LeftStr(Line,2) <> ';;' then Err := ReadTitleData(Line);
end
// Check if line contains a control rule clause
else if (Section = 22) then Err := ReadControlData(Line)
// Check if line contains an event start/end dates
else if (Section = 54) then Err := ReadEventData(Trim(Line))
// If in some section, then process the input line
else
begin
// Break line into string tokens and parse their contents
Uutils.Tokenize(S, TokList, Ntoks);
if (Ntoks > 0) and (Section >= 0) then
begin
Err := ParseInpLine(S);
Comment := '';
end
// No current section -- file was probably not an EPA-SWMM file
else if (Ntoks > 0) then
begin
Result := False;
Exit;
end;
end;
end;
////
// Increment error count
if Err > 0 then Inc(ErrCount);
end; //End of file.
if ErrCount > MAX_ERRORS then ErrList.Add(
IntToStr(ErrCount-MAX_ERRORS) + TXT_MORE_ERRORS);
end;
procedure DisplayInpErrForm(const Fname: String);
//-----------------------------------------------------------------------------
// Displays Status Report form that lists any error messages.
//-----------------------------------------------------------------------------
begin
SysUtils.DeleteFile((TempReportFile));
TempReportFile := Uutils.GetTempFile(TempDir,'swmm');
ErrList.Insert(0, TXT_ERROR_REPORT + Fname + #13);
ErrList.SaveToFile(TempReportFile);
MainForm.MnuReportStatusClick(MainForm);
end;
procedure ReverseVertexLists;
//-----------------------------------------------------------------------------
// Reverses list of vertex points for each link in the project.
//-----------------------------------------------------------------------------
var
I, J: Integer;
begin
for I := 0 to MAXCLASS do
begin
if not Project.IsLink(I) then continue;
for J := 0 to Project.Lists[I].Count-1 do
if Project.GetLink(I, J).Vlist <> nil then
Project.GetLink(I, J).Vlist.Reverse;
end;
end;
procedure SetSubcatchCentroids;
//-----------------------------------------------------------------------------
// Determines the centroid of each subcatchment polygon.
//-----------------------------------------------------------------------------
var
I : Integer;
begin
for I := 0 to Project.Lists[SUBCATCH].Count - 1 do
begin
Project.GetSubcatch(SUBCATCH, I).SetCentroid;
end;
end;
procedure SetIDPtrs;
//-----------------------------------------------------------------------------
// Makes pointers to ID strings the ID property of objects.
//-----------------------------------------------------------------------------
var
I, J : Integer;
C : TSubcatch;
S : String;
begin
for I := 0 to MAXCLASS do
begin
if I = RAINGAGE then with Project.Lists[RAINGAGE] do
begin
for J := 0 to Count-1 do TRaingage(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsSubcatch(I) then with Project.Lists[SUBCATCH] do
begin
for J := 0 to Count-1 do
begin
C := TSubcatch(Objects[J]);
C.ID := PChar(Strings[J]);
S := Trim(C.Data[SUBCATCH_OUTLET_INDEX]);
C.OutSubcatch := FindSubcatch(S);
if C.OutSubcatch = nil then C.OutNode := FindNode(S);
end;
end
else if Project.IsNode(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TNode(Objects[J]).ID := PChar(Strings[J]);
end
else if Project.IsLink(I) then with Project.Lists[I] do
begin
for J := 0 to Count-1 do TLink(Objects[J]).ID := PChar(Strings[J]);
end
else if I = TRANSECT then with Project.Lists[I] do
begin
for J := 0 to Count-1 do
begin
TTransect(Objects[J]).CheckData;
TTransect(Objects[J]).SetMaxDepth;
Project.SetTransectConduitDepth(Strings[J],
TTransect(Objects[J]).Data[TRANSECT_MAX_DEPTH]);
end;
end
else continue;
end;
end;
function ReadInpFile(const Fname: String):Boolean;
//-----------------------------------------------------------------------------
// Reads SWMM input data from a text file.
//-----------------------------------------------------------------------------
var
F : Textfile;
begin
// Try to open the file
Result := False;
AssignFile(F,Fname);
{$I-}
Reset(F);
{$I+}
if (IOResult = 0) then
begin
// Create stringlists
Screen.Cursor := crHourGlass;
MapExtentSet := False;
ErrList := TStringList.Create;
TokList := TStringList.Create;
SubcatchList := TStringList.Create;
NodeList := TStringList.Create;
LinkList := TStringList.Create;
FileType := ftInput;
InpFile := Fname;
try
// Read the file
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
SubcatchList.Sorted := True;
NodeList.Sorted := True;
LinkList.Sorted := True;
Section := -1;
Result := ReadFile(F, Uutils.GetFileSize(Fname));
if (Result = True) then
begin
// Establish pointers to ID names
SetIDPtrs;
end;
finally
// Free the stringlists
SubcatchList.Free;
NodeList.Free;
LinkList.Free;
TokList.Free;
MainForm.PageSetupDialog.Header.Text := Project.Title;
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
// Display errors if found & set map dimensions
if Result = True then
begin
if ErrList.Count > 0 then DisplayInpErrForm(Fname);
SetSubcatchCentroids;
SetMapDimensions;
end;
ErrList.Free;
end;
end;
// Close the input file
CloseFile(F);
end;
procedure ClearDefaultDates;
//-----------------------------------------------------------------------------
// Clears project's date/time settings.
//-----------------------------------------------------------------------------
begin
with Project.Options do
begin
Data[START_DATE_INDEX] := '';
Data[START_TIME_INDEX] := '';
Data[REPORT_START_DATE_INDEX] := '';
Data[REPORT_START_TIME_INDEX] := '';
Data[END_DATE_INDEX] := '';
Data[END_TIME_INDEX] := '';
end;
end;
procedure SetDefaultDates;
//-----------------------------------------------------------------------------
// Sets default values for project's date/time settings.
//-----------------------------------------------------------------------------
var
StartTime: TDateTime;
StartDate: TDateTime;
T: TDateTime;
D: TDateTime;
begin
with Project.Options do
begin
// Process starting date/time
try
StartDate := StrToDate(Data[START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do StartDate := Date;
end;
StartTime := Uutils.StrHoursToTime(Data[START_TIME_INDEX]);
if StartTime < 0 then StartTime := 0;
D := StartDate + StartTime;
Data[START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process reporting start date/time
try
D := StrToDate(Data[REPORT_START_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[REPORT_START_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[REPORT_START_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[REPORT_START_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
// Process ending date/time
try
D := StrToDate(Data[END_DATE_INDEX], MyFormatSettings);
except
On EConvertError do D := StartDate;
end;
T := Uutils.StrHoursToTime(Data[END_TIME_INDEX]);
if T < 0 then T := StartTime;
D := D + T;
Data[END_DATE_INDEX] := DateToStr(D, MyFormatSettings);
Data[END_TIME_INDEX] := TimeToStr(D, MyFormatSettings);
end;
end;
function OpenProject(const Fname: String): TInputFileType;
//-----------------------------------------------------------------------------
// Reads in project data from a file.
//-----------------------------------------------------------------------------
begin
// Show progress meter
ClearDefaultDates;
Screen.Cursor := crHourGlass;
MainForm.ShowProgressBar(MSG_READING_PROJECT_DATA);
// Use default map dimensions and backdrop settings
MapForm.Map.Dimensions := DefMapDimensions;
MapForm.Map.Backdrop := DefMapBackdrop;
// Do the following for non-temporary input files
if not SameText(Fname, Uglobals.TempInputFile) then
begin
// Create a backup file
if AutoBackup
then CopyFile(PChar(Fname), PChar(ChangeFileExt(Fname, '.bak')), FALSE);
// Retrieve project defaults from .INI file
if CompareText(ExtractFileExt(Fname), '.ini') <> 0
then Uinifile.ReadProjIniFile(ChangeFileExt(Fname, '.ini'));
end;
// Read and parse each line of input file
Result := iftNone;
if ReadInpFile(Fname) then Result := iftINP;
// Finish processing the input data
if Result <> iftNone then
begin
SetDefaultDates; // set any missing analysis dates
Uglobals.RegisterCalibData; // register calibration data files
Uupdate.UpdateUnits; // update choice of unit system
Uupdate.UpdateDefOptions; // update default analysis options
Uupdate.UpdateLinkHints; // update hints used for offsets
Project.GetControlRuleNames; // store control rule names in a list
end;
// Hide progress meter.
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
end;
end.le names in a list
end;
// Hide progress meter.
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
end;
end.
if Result <> iftNone then
begin
SetDefaultDates; // set any missing analysis dates
Uglobals.RegisterCalibData; // register calibration data files
Uupdate.UpdateUnits; // update choice of unit system
Uupdate.UpdateDefOptions; // update default analysis options
Uupdate.UpdateLinkHints; // update hints used for offsets
Project.GetControlRuleNames; // store control rule names in a list
end;
// Hide progress meter.
MainForm.HideProgressBar;
Screen.Cursor := crDefault;
end;
end.
AI Rivers of Wisdom about ICM SWMM
Here's the text "Rivers of Wisdom" formatted with one sentence per line: [Verse 1] 🌊 Beneath the ancient oak, where shadows p...
-
@Innovyze User forum where you can ask questions about our Water and Wastewater Products http://t.co/dwgCOo3fSP pic.twitter.com/R0QKG2dv...
-
Subject: Detention Basin Basics in SWMM 5 What are the basic elements of a detention pond in SWMM 5? They are common in our back...
-
Soffit Level ( pipe technology ) The top point of the inside open section of a pipe or box conduit. The soffit is the ...