diff --git a/Install and Run ResourceSubstitutable.docx b/Install and Run ResourceSubstitutable.docx new file mode 100644 index 0000000..f6f5f7a Binary files /dev/null and b/Install and Run ResourceSubstitutable.docx differ diff --git a/README.md b/README.md index 4aba233..64d13d5 100644 --- a/README.md +++ b/README.md @@ -1 +1,27 @@ -ResourceSubstitutable +# Substitutable Resource Model + +The ResourceSubstitutable model couples ecosystem carbon (C), nitrogen (N), and phosphorus (P) and water (W) cycles and generates output for all stocks and fluxes for each time step. The differential equations that describe the mass balance for each of the simulated components of the ecosystem are solved numerically using a 4th-5th order Runge-Kutta integrator with an integrator time-step size that adapts with each pass through the integrator to optimize precision and computation time (Press et al. 1986). The model is coded in Lazarus 2.0.12 (2020) Free Pascal and runs on a PC or Mac computer. + +The ResourceSubstitutable model uses a simplified model structure to amplify the heuristic value of the analysis. As a framework from which to illustrate resource optimization for substitutable resources, we build a mass-balance model for C and N in the biomass of an idealized vegetation based on uptake, turnover, and respiration. We simulate the concentrations in the environment of various N sources based on a simple mass balance of inputs to the environment minus uptake by the vegetation minus losses from the environment. Asset allocation toward resource acquisition is represented by an abstract quantity called “effort”. This effort is distributed hierarchically; first the primary effort is allocated toward acquiring C versus N, then the primary effort allocated toward N is subdivided among sub-efforts targeted at the resources that are potential sources of N. + +A detailed model description is presented in Rastetter and Kwiatkowski, 2020 and the ResourceSubstitutable model equations are presented in the file, ResourceSubstitutable.txt. + +-------------------------------------------------------------------------- + +### Publications +Rastetter EB, and BL Kwiatkowski. 2020. An approach to modeling resource optimization for substitutable and interdependent resources. Ecological Modelling 425: 109033. DOI: /10.1016/j.ecolmodel.2020.109033 + +Rastetter, E. 2020. Model output, drivers and parameters for Ecosystem Recovery from Disturbance is Constrained by N Cycle Openness, Vegetation-Soil N Distribution, Form of N Losses, and the Balance Between Vegetation and Soil-Microbial Processes ver 1. Environmental Data Initiative. https://doi.org/10.6073/pasta/0af82d3c3d9d1710775cf9b1464ce70b (Accessed 2020-09-17). + +Rastetter, E. and B. Kwiatkowski. 2020. Model executable, output, drivers and parameters for modeling organism acclimation to changing availability of and requirements for substitutable and interdependent resources ver 1. Environmental Data Initiative. https://doi.org/10.6073/pasta/5f4f6fcfe9bf7e63adef00d0c9203327 (Accessed 2020-09-17). + +-------------------------------------------------------------------------- +### Code Instructions + +The ResourceSubstitutable model is written for modelshell, a model develepment package, which is written in Lazarus/Free Pascal. Modelshell allows the user to create a model by making creating a plain text file description of the model. Modelshell provides a GUI interface, an integrator, file IO, and a simple graph. All output files created by modelshell are comma delimited text files. + +Detailed instructions for compiling and running the model are in "Install and Run ResourceSubstitutable.docx" + +-------------------------------- +### Funding +This work was supported in part by the National Science Foundation under NSF grants 1651722, 1637459, 1603560, 1556772, 1841608. Any Opinions, findings and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect those of the National Science Foundation. diff --git a/ResourceSubstitutable.txt b/ResourceSubstitutable.txt new file mode 100644 index 0000000..68ea81d --- /dev/null +++ b/ResourceSubstitutable.txt @@ -0,0 +1,183 @@ +Model Definition File - 25 character maximum for all text strings +Model Name= substitutable resource +Model Version= 1.0.0 +Model Time Unit= day +Model Contact= Ed +Model Contact Address Line 1= Ecosystems +Model Contact Address Line 2= MBL +Model Contact Address Line 3= Woods Hole + +States +Name, Units, Symbol, Num array elements if applicable - Comma separated. +Plant C, g C m-2, BC +Plant N, g N m-2, BN +Avail N 1, g N m-2, N1 +Avail N 2, g N m-2, N2 +Avail N 3, g N m-2, N3 +Avail N 4, g N m-2, N4 +Effort C, effort, VC +Effort N, effort, VN +sub effort 1, effort, v1 +sub effort 2, effort, v2 +sub effort 3, effort, v3 +sub effort 4, effort, v4 +Int up C, g C m-2 day-1, UCbar +Int up N, g N m-2 day-1, UNbar +Int rec C, g C m-2 day-1, RCbar +Int rec N, g N m-2 day-1, RNbar +End + +Process +Process Name, Units, Symbol, Num of Parameters, Num array elements if applicable +Parameters for each process: Name, Units, Symbol +Photosynthesis, g C m-2 day-1, UC, 4 + max Ps, g C m-2 day-1, Pmax + half sat, MJ m-2 day-1, eta + beers coef, m2 m-2, kI + spec leaf area, m-2 g-1 C, lambda +Total N up, g N m-2 day-1, UN, 0 +N up 1, g N m-2 day-1, UN1, 2 + N up rate 1, g N g-1 C day-1, gN1 + half sat 1, g N m-2, kN1 +N up 2, g N m-2 day-1, UN2, 2 + N up rate 2, g N g-1 C day-1, gN2 + half sat 2, g N m-2, kN2 +N up 3, g N m-2 day-1, UN3, 2 + N up rate 3, g N g-1 C day-1, gN3 + half sat 3, g N m-2, kN3 +N up 4, g N m-2 day-1, UN4, 2 + N up rate 4, g N g-1 C day-1, gN4 + half sat 4, g N m-2, kN4 +Respiration, g C m-2 day-1, RC, 1 + resp rate const, day-1, rmC +C turnover, g C m-2 day-1, TC, 1 + C turnover rate const, day-1, mC +N turnover, g N m-2 day-1, TN, 1 + N turnover rate const, day-1, mN +PHI, none, PHI, 4 + acclim rate, day-1, a + sub acclim rate, day-1, omega + eps0, none,eps0 + int const, day-1, rho +psiC, g C m-2 day-1, psiC, 0 +psiN, g N m-2 day-1, psiN, 0 +allometry, g C m-2, S, 2 + alpha, m2 g-1 C, alpha + gamma, m2 g-1 C, gamma +stoichiometry, none, THETA, 1 + opt C:N, g C g-1 N, qB +max yield, g N m-2 effort-1 day-1, ymax, 0 +beta, none, beta, 0 +eps1, effort, eps1, 0 +eps2, effort, eps2, 0 +eps3, effort, eps3, 0 +eps4, effort, eps4, 0 +N leach 1, g N m-2 day-1, LN1, 1 + loss rate cosnt1, day-1, tau1 +N leach 2, g N m-2 day-1, LN2, 1 + loss rate cosnt2, day-1, tau2 +N leach 3, g N m-2 day-1, LN3, 1 + loss rate cosnt3, day-1, tau3 +N leach 4, g N m-2 day-1, LN4, 1 + loss rate cosnt4, day-1, tau4 +yeild 1, g N m-2 effort-1 day-1, y1, 1 + cost 1, g c g-1 N, phi1 +yeild 2, g N m-2 effort-1 day-1, y2, 1 + cost 2, g c g-1 N, phi2 +yeild 3, g N m-2 effort-1 day-1, y3, 1 + cost 3, g c g-1 N, phi3 +yeild 4, g N m-2 effort-1 day-1, y4, 1 + cost 4, g c g-1 N, phi4 +dUCdVC, g C m-2 day-1 effort-1, dUCdVC, 0 +End + +Drive +Name, Units, Symbol, Num array elements - Comma separated. +irradiance, MJ m-2 day-1, I +N input 1, g N m-2 day-1, IN1 +N input 2, g N m-2 day-1, IN2 +N input 3, g N m-2 day-1, IN3 +N input 4, g N m-2 day-1, IN4 +End + +Other Double Variables +Name, Units, Symbol - Comma separated. +End + +Other Integer Variables +Name, Units, Symbol - Comma separated. +End + +Functions +End Functions + +Equations See the Computer Programming handout for instructions on writing equations in Pascal. Semicolons must end each statement. +if VC<1e-20 then VC:=0; +if VN<1e-20 then VN:=0; +if v1<1e-20 then v1:=0; +if v2<1e-20 then v2:=0; +if v3<1e-20 then v3:=0; +if v4<1e-20 then v4:=0; +S:=VC+VN; +VC:=VC/S; +VN:=1-VC; +S:=v1+v2+v3+v4; +v1:=v1/S; +v2:=v2/S; +v3:=v3/S; +V4:=1-v1-v2-v3; + +S:=BC*((alpha*BC+1)/(gamma*BC+1)); +THETA:=BC/qB/BN; +UC:=(Pmax/kI)*ln((eta+I)/(eta+I*exp(-kI*lambda*S*VC))); +UN1:=S*gN1*N1*VN*v1/(kN1+N1); +UN2:=S*gN2*N2*VN*v2/(kN2+N2); +UN3:=S*gN3*N3*VN*v3/(kN3+N3); +UN4:=S*gN4*N4*VN*v4/(kN4+N4); +UN:=UN1+UN2+UN3+UN4; +RC:=rmC*THETA*BC+phi1*UN1+phi2*UN2+phi3*UN3+phi4*UN4; +TC:=mC*BC; +TN:=mN*BN/THETA; +PHI:=power(UCbar/RCbar,VC)*power(UNbar/RNbar,VN); +psiC:=((rmC+mC)*BC+phi1*UN1+phi2*UN2+phi3*UN3+phi4*UN4)/THETA; +psiN:=mN*THETA*BN; +LN1:=tau1*N1; +LN2:=tau2*N2; +LN3:=tau3*N3; +LN4:=tau4*N4; +dUCdVC:=lambda*S*Pmax*I*exp(-kI*lambda*S*VC)/(eta+I*exp(-kI*lambda*S*VC)); +y1:=S*gN1*N1*VN/(kN1+N1); +y1:=y1/(VN+y1*phi1/dUCdVC); +y2:=S*gN2*N2*VN/(kN2+N2); +y2:=y2/(VN+y2*phi2/dUCdVC); +y3:=S*gN3*N3*VN/(kN3+N3); +y3:=y3/(VN+y3*phi3/dUCdVC); +y4:=S*gN4*N4*VN/(kN4+N4); +y4:=y4/(VN+y4*phi4/dUCdVC); +ymax:=max(y1,max(y2,max(y3,y4))); +if y1=ymax then eps1:=eps0 else eps1:=0; +if y2=ymax then eps2:=eps0 else eps2:=0; +if y3=ymax then eps3:=eps0 else eps3:=0; +if y4=ymax then eps4:=eps0 else eps4:=0; +beta:=ymax*(max(v1,eps1)+max(v2,eps2)+max(v3,eps3)+max(v4,eps4)); +beta:=(y1*max(v1,eps1)+y2*max(v2,eps2)+y3*max(v3,eps3)+y4*max(v4,eps4))/beta; +End Equations + +Derivatives For array variables use jj as the array index. Same order as State var. +dBCdt := UC-TC-RC; +dBNdt := UN-TN; +dN1dt := IN1-UN1-LN1; +dN2dt := IN2-UN2-LN2; +dN3dt := IN3-UN3-LN3; +dN4dt := IN4-UN4-LN4; +dVCdt := a*ln(PHI*RCbar/UCbar)*VC; +dVNdt := a*ln(PHI*RNbar/UNbar)*VN; +dv1dt := omega*(y1/ymax-beta)*max(v1,eps1); +dv2dt := omega*(y2/ymax-beta)*max(v2,eps2); +dv3dt := omega*(y3/ymax-beta)*max(v3,eps3); +dv4dt := omega*(y4/ymax-beta)*max(v4,eps4); +dUCbardt := rho*(UC-UCbar); +dUNbardt := rho*(UN-UNbar); +dRCbardt := rho*(psiC-RCbar); +dRNbardt := rho*(psiN-RNbar); + diff --git a/modelshell/FileioGrid.pas b/modelshell/FileioGrid.pas new file mode 100644 index 0000000..c6e5061 --- /dev/null +++ b/modelshell/FileioGrid.pas @@ -0,0 +1,18 @@ +{ Contains the code for all file input and output. All I/O should be done using + these procedures. There is one exception. In the note.pas file the drivers are + written to the driver file directly from the memo component. It is done that + way because the memo component has a function to write to a file and using + that function is easier then converting the text in the memo to the correct + form for the writedriverfile function. } +unit fileiogrid; + +interface + +uses sysutils, classes, Dialogs, stypes; + +type TAction = (flRead, flWrite); + +// Grid shell I/O +function ReadDEMFile(fname:string; + +end. diff --git a/modelshell/FmGridMain.pas b/modelshell/FmGridMain.pas new file mode 100644 index 0000000..c97b0ab --- /dev/null +++ b/modelshell/FmGridMain.pas @@ -0,0 +1,1599 @@ +unit FmGridMain; + +interface + +uses Windows, Classes, Graphics, Forms, Controls, Menus, + Dialogs, StdCtrls, Buttons, ExtCtrls, ComCtrls, ImgList, StdActns, + ActnList, ToolWin, stypes, Grids, BaseGrid, AdvGrid, AdvObj; + +type + PCellProp = ^TCellProp; + TCellProp = record + RowPos: integer; + ColPos: integer; + elevation: double; + Runposition: integer; + VegClass: integer; + SoilClass: integer; + ParamFile: string; + DriverFile: string; + OuputFile: string; + RDocl: array[1..4] of Tstringlist; + RDonl: array[1..4] of Tstringlist; + Rnh4l: array[1..4] of Tstringlist; + Rno3l: array[1..4] of Tstringlist; + end; + TVegFiles = record + ParamFileName: string; + DriverFileName: string; + end; + FVegClassInfo = record + VegType: integer; + Filenames: TVegFiles; + RunOptions: TRunOptions; + end; + TFmGridMEL = class(TForm) + OpenDialog: TOpenDialog; + SaveDialog: TSaveDialog; + ActionList1: TActionList; + FileNew1: TAction; + FileOpen1: TAction; + FileSave1: TAction; + FileSaveAs1: TAction; + FileSend1: TAction; + FileExit1: TAction; + EditCut1: TEditCut; + EditCopy1: TEditCopy; + EditPaste1: TEditPaste; + HelpAbout1: TAction; + StatusBar: TStatusBar; + ImageList1: TImageList; + MainMenu1: TMainMenu; + File1: TMenuItem; + FileNewItem: TMenuItem; + FileOpenItem: TMenuItem; + FileSaveItem: TMenuItem; + FileSaveAsItem: TMenuItem; + N1: TMenuItem; + FileSendItem: TMenuItem; + N2: TMenuItem; + FileExitItem: TMenuItem; + Edit1: TMenuItem; + CutItem: TMenuItem; + CopyItem: TMenuItem; + PasteItem: TMenuItem; + Help1: TMenuItem; + HelpAboutItem: TMenuItem; + SaveDialog1: TSaveDialog; + ToolBar1: TToolBar; + ToolButton1: TToolButton; + ToolButton2: TToolButton; + ToolButton3: TToolButton; + ToolButton4: TToolButton; + ToolButton5: TToolButton; + ToolButton6: TToolButton; + ToolButton7: TToolButton; + ToolButton8: TToolButton; + ToolButton9: TToolButton; + PopupMenu1: TPopupMenu; + Cut1: TMenuItem; + Copy1: TMenuItem; + Paste1: TMenuItem; + LedRows: TLabeledEdit; + LedColumns: TLabeledEdit; + LedNoData: TLabeledEdit; + LedVeg1ParamFile: TLabeledEdit; + LedSoilClassFile: TLabeledEdit; + LedVegClassFile: TLabeledEdit; + LedSoilPropFile: TLabeledEdit; + BtnRun: TButton; + Button2: TButton; + LedDEMFile: TLabeledEdit; + LedVeg2ParamFile: TLabeledEdit; + LedCellOrderFile: TLabeledEdit; + LedDriver1File: TLabeledEdit; + LedDriver2File: TLabeledEdit; + LedRunOptionsFile: TLabeledEdit; + AsgCellDriver: TAdvStringGrid; + AsgGToutput: TAdvStringGrid; + procedure FileNew1Execute(Sender: TObject); + procedure FileOpen1Execute(Sender: TObject); + procedure FileSave1Execute(Sender: TObject); + procedure FileSaveAs1Execute(Sender: TObject); + procedure FileSend1Execute(Sender: TObject); + procedure FileExit1Execute(Sender: TObject); + procedure HelpAbout1Execute(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure ChooseDEMFile(Sender: TObject); + procedure ChooseVegClassFile(Sender: TObject); + procedure ChooseVeg1ParamFile(Sender: TObject); + procedure ChooseVeg2ParamFile(Sender: TObject); + procedure ChooseSoilClassFile(Sender: TObject); + procedure ChooseSoilPropFile(Sender: TObject); + procedure ChooseCellOrderFile(Sender: TObject); + procedure ChooseDriver1File(Sender: TObject); + procedure ChooseDriver2File(Sender: TObject); + procedure ChooseRunOptionsFile(Sender: TObject); + procedure UpdateForm(Sender: TObject); + procedure LedDriver2FileKeyPress(Sender: TObject; var Key: Char); + procedure LedDriver1FileKeyPress(Sender: TObject; var Key: Char); + procedure LedCellOrderFileKeyPress(Sender: TObject; var Key: Char); + procedure LedVeg1ParamFileKeyPress(Sender: TObject; var Key: Char); + procedure LedVeg2ParamFileKeyPress(Sender: TObject; var Key: Char); + procedure LedDEMFileKeyPress(Sender: TObject; var Key: Char); + procedure LedVegClassFileKeyPress(Sender: TObject; var Key: Char); + procedure LedSoilClassFileKeyPress(Sender: TObject; var Key: Char); + procedure LedSoilPropFileKeyPress(Sender: TObject; var Key: Char); + procedure BtnRunClick(Sender: TObject); + procedure LedRunOptionsFileKeyPress(Sender: TObject; var Key: Char); + procedure FormDestroy(Sender: TObject); + procedure ReadCellOrderFile; + procedure ReadRunOptionsFile; + function FindCellInList(RowNum, Colnum: integer): PCellProp; + procedure Button2Click(Sender: TObject); + private + FFileName, FDEMFilename, FSoilClassFilename, FVegClassFilename, + FSoilPropFilename, FVeg1ParamFilename, FVeg2ParamFilename, FCellOrderFilename, + FDriver1Filename, FDriver2Filename, FRunOptionsFilename: String; + FCellInfoList: TList; + FVegInfo: array[0..1] of FVegClassInfo; // fix need to make this dynamic + FTimeStart, FTimeStop: double; + NumLayers, GTSoilLayers: integer; + public + { Public declarations } + CurrentDirectory: String; + end; + +var + FmGridMEL: TFmGridMEL; + +implementation + +uses + SysUtils, Mapi, about, SHFolder, frontend, options, display; + +{$R *.dfm} + +resourcestring + SUntitled = 'Untitled'; + SOverwrite = 'OK to overwrite %s'; + SSendError = 'Error sending mail'; + +function DefaultSaveLocation: string; +var + P: PChar; +begin + { + returns the location of 'My Documents' if it exists, otherwise it returns + the current directory. + } + P := nil; + try + P := AllocMem(MAX_PATH); + if SHGetFolderPath(0, CSIDL_PERSONAL, 0, 0, P) = S_OK then + Result := P + else + Result := GetCurrentDir; + finally + FreeMem(P); + end; +end; + +procedure TFmGridMEL.FileNew1Execute(Sender: TObject); +begin + SaveDialog.InitialDir := DefaultSaveLocation; + FFileName := SUntitled; +// RichEdit1.Lines.Clear; +// RichEdit1.Modified := False; +end; + +procedure TFmGridMEL.FileOpen1Execute(Sender: TObject); +begin + if OpenDialog.Execute then + begin +// RichEdit1.Lines.LoadFromFile(OpenDialog.FileName); + FFileName := OpenDialog.FileName; +// RichEdit1.SetFocus; +// RichEdit1.Modified := False; +// RichEdit1.ReadOnly := ofReadOnly in OpenDialog.Options; + end; +end; + +procedure TFmGridMEL.FileSave1Execute(Sender: TObject); +begin + if (FFileName = SUntitled) or (FFileName = '') then + FileSaveAs1Execute(Sender) + else + begin +// RichEdit1.Lines.SaveToFile(FFileName); +// RichEdit1.Modified := False; + end; +end; + +procedure TFmGridMEL.FileSaveAs1Execute(Sender: TObject); +begin + with SaveDialog do + begin + FileName := FFileName; + if Execute then + begin + if FileExists(FileName) then + if MessageDlg(Format(SOverwrite, [FileName]), + mtConfirmation, mbYesNoCancel, 0) <> idYes then Exit; +// RichEdit1.Lines.SaveToFile(FileName); + FFileName := FileName; +// RichEdit1.Modified := False; + end; + end; +end; + +procedure TFmGridMEL.FileSend1Execute(Sender: TObject); +var + MapiMessage: TMapiMessage; + MError: Cardinal; +begin + with MapiMessage do + begin + ulReserved := 0; + lpszSubject := nil; +// lpszNoteText := PChar(RichEdit1.Lines.Text); + lpszMessageType := nil; + lpszDateReceived := nil; + lpszConversationID := nil; + flFlags := 0; + lpOriginator := nil; + nRecipCount := 0; + lpRecips := nil; + nFileCount := 0; + lpFiles := nil; + end; + + MError := MapiSendMail(0, Application.Handle, MapiMessage, + MAPI_DIALOG or MAPI_LOGON_UI or MAPI_NEW_SESSION, 0); + if MError <> 0 then MessageDlg(SSendError, mtError, [mbOK], 0); +end; + +procedure TFmGridMEL.FormCreate(Sender: TObject); +begin + FDEMFilename := 'NA'; + FVegClassFilename := 'NA'; + FVeg1ParamFilename := 'NA'; + FVeg2ParamFilename := 'NA'; + FSoilClassFilename := 'NA'; + FSoilPropFilename := 'NA'; + FDriver1Filename := 'NA'; + FDriver2Filename := 'NA'; + FCellOrderFilename := ''; + FRunOptionsFilename := ''; +// FmShellMain.Visible := False; +// FmShellMain.RunningInteractive := false; + + CurrentDirectory := GetCurrentDir; + NumLayers := 4; + + FCellInfoList := TList.Create; + GTSoilLayers := 2; +end; + +procedure TFmGridMEL.FormDestroy(Sender: TObject); +var + i, k: integer; + PACell: ^TCellProp; +begin + for I := FCellInfoList.Count - 1 downto 0 do + begin + PACell := FCellInfoList[i]; + for k := 1 to Numlayers do + begin + PACell^.RDocl[k].Clear; + PACell^.RDonl[k].Clear; + PACell^.Rnh4l[k].Clear; + PACell^.Rno3l[k].Clear; + PACell^.RDocl[k].Free; + PACell^.RDonl[k].Free; + PACell^.Rnh4l[k].Free; + PACell^.Rno3l[k].Free; + end; + end; + dispose(PACell); + FCellInfoLIst.Clear; + FCellInfoList.Free; +end; + +procedure TFmGridMEL.BtnRunClick(Sender: TObject); +var + i, j, k: integer; + PCurrCell: ^TCellProp; + PCellH1, PCellH2, PCellH3, PCellH4, PCellH5, PCellH6, PCellH7, PCellH8: PCellProp; + Wrcol, QwH1col, QwH2col, QwH3col, QwH4col, QwH5col, QwH6col, QwH7col, QwH8col, Qwd, + GTWrcol, GTQwH1col, GTQwH2col, GTQwH3col, GTQwH4col, GTQwH5col, GTQwH6col, + GTQwH7col, GTQwH8col, GTQwd, Lnh4lcol, Lno3lcol, Ldoclcol, Ldonlcol, Rnh4lcol, + Rno3lcol, Rdoclcol, Rdonlcol: array[1..4] of integer; + tempstring, tempstring2: string; + +function GetColumnNumber(asgname, colname:string):integer; +var + i,colnum:integer; + tempstring:string; +begin + i := 0; + colnum := 0; + if lowercase(asgname) = 'sgmodeloutput' then + repeat + tempstring := FmDisplayData.SgModelOutput.Cells[i,1]; + tempstring := trim(tempstring); + if tempstring = colname then colnum := i; + i := i + 1; + until (colnum <> 0) or (i > FmDisplayData.SgModelOutput.Colcount - 1) + else if lowercase(asgname) = 'asggtoutput' then + repeat + tempstring := AsgGToutput.Cells[i,0]; + tempstring := trim(tempstring); + if tempstring = colname then colnum := i; + i := i + 1; + until (colnum <> 0) or (i > AsgGToutput.Colcount - 1) + else {if lower(asgname) = 'asgcelldriver' then } + repeat + tempstring := AsgCellDriver.Cells[i,0]; + tempstring := trim(tempstring); + if tempstring = colname then colnum := i; + i := i + 1; + until (colnum <> 0) or (i > AsgCellDriver.Colcount - 1); + + if colnum = 0 then result := -1 else result := colnum; +end; + +begin + BtnRun.Enabled := False; + BtnRun.Caption := 'Running'; + ReadRunOptionsFile; // This procedure MUST be called before ReadCellOrderFile so the param and driver files are defined. + ReadCellOrderFile; + try + for I := 0 to FCellInfoList.Count - 1 do + begin + PCurrCell := FCellInfoList[i]; + AsgCellDriver.LoadFromCSV(CurrentDirectory + '\' + PCurrCell^.DriverFile); + AsgGToutput.LoadFromCSV(CurrentDirectory + '\Cell_' + inttostr(PCurrCell^.RowPos) + + '_' + inttostr(PCurrCell^.ColPos) + '.drr'); + // Add row to GT output to account for the units in driver file + AsgGToutput.InsertRows(1,1); + // Make sure the files are all the same length. + if AsgCellDriver.RowCount <> Ftimestop - Ftimestart + 2 {names, units} then + AsgCellDriver.RemoveRows(round(Ftimestop - Ftimestart + 2), + AsgCellDriver.RowCount - round(Ftimestop - Ftimestart + 2)); + if AsgGToutput.RowCount <> Ftimestop - Ftimestart + 2 {names, units} then + AsgGToutput.RemoveRows(round(Ftimestop - Ftimestart + 2), + AsgGToutput.RowCount - round(Ftimestop - Ftimestart + 2)); + // Copy soil moisture, lateral flows, and drainage to driver file + for k := 1 to 4 do + begin // Get source and destination column numbers for variables + GTWrcol[k] := GetColumnNumber('AsgGToutput', 'sm' + inttostr(k) + '(mm)'); + GTQwH1col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_1'); + GTQwH2col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_2'); + GTQwH3col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_3'); + GTQwH4col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_4'); + GTQwH5col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_5'); + GTQwH6col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_6'); + GTQwH7col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_7'); + GTQwH8col[k] := GetColumnNumber('AsgGToutput', 'Q' + inttostr(k) + '_8'); + GTQwd[k] := GetColumnNumber('AsgGToutput', 'G' + inttostr(k) + inttostr(k+1)); + + Wrcol[k] := GetColumnNumber('AsgCellDriver', '*D: H2O content' + inttostr(k)); + QwH1col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H1-' + inttostr(k)); + QwH2col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H2-' + inttostr(k)); + QwH3col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H3-' + inttostr(k)); + QwH4col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H4-' + inttostr(k)); + QwH5col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H5-' + inttostr(k)); + QwH6col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H6-' + inttostr(k)); + QwH7col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H7-' + inttostr(k)); + QwH8col[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O lateral H8-' + inttostr(k)); + Qwd[k] := GetColumnNumber('AsgCellDriver', '*D: FlxH2O drainage lay' + inttostr(k)); + + // Copy column title and units to GT output so that when I copy the columns over the name and units are right + if (Wrcol[k] <> -1) then + if (GTWrcol[k] <> -1) then + begin + AsgGToutput.Cells[GTWrcol[k], 0] := AsgCellDriver.Cells[Wrcol[k], 0]; + AsgGToutput.Cells[GTWrcol[k], 1] := AsgCellDriver.Cells[Wrcol[k], 1]; + AsgCellDriver.Cols[Wrcol[k]] := AsgGToutput.Cols[GTWrcol[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTWrcol[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH1col[k] <> -1) then + if GTQwH1col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH1col[k], 0] := AsgCellDriver.Cells[QwH1col[k], 0]; + AsgGToutput.Cells[GTQwH1col[k], 1] := AsgCellDriver.Cells[QwH1col[k], 1]; + AsgCellDriver.Cols[QwH1col[k]] := AsgGToutput.Cols[GTQwH1col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH1col[' + inttostr(k) + ']' + '. Run aborted.'); + + if (QwH2col[k] <> -1) then + if GTQwH2col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH2col[k], 0] := AsgCellDriver.Cells[QwH2col[k], 0]; + AsgGToutput.Cells[GTQwH2col[k], 1] := AsgCellDriver.Cells[QwH2col[k], 1]; + AsgCellDriver.Cols[QwH2col[k]] := AsgGToutput.Cols[GTQwH2col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH2col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH3col[k] <> -1) then + if GTQwH3col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH3col[k], 0] := AsgCellDriver.Cells[QwH3col[k], 0]; + AsgGToutput.Cells[GTQwH3col[k], 1] := AsgCellDriver.Cells[QwH3col[k], 1]; + AsgCellDriver.Cols[QwH3col[k]] := AsgGToutput.Cols[GTQwH3col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH3col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH4col[k] <> -1) then + if GTQwH4col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH4col[k], 0] := AsgCellDriver.Cells[QwH4col[k], 0]; + AsgGToutput.Cells[GTQwH4col[k], 1] := AsgCellDriver.Cells[QwH4col[k], 1]; + AsgCellDriver.Cols[QwH4col[k]] := AsgGToutput.Cols[GTQwH4col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH4col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH5col[k] <> -1) then + if GTQwH5col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH5col[k], 0] := AsgCellDriver.Cells[QwH5col[k], 0]; + AsgGToutput.Cells[GTQwH5col[k], 1] := AsgCellDriver.Cells[QwH5col[k], 1]; + AsgCellDriver.Cols[QwH5col[k]] := AsgGToutput.Cols[GTQwH5col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH5col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH6col[k] <> -1) then + if GTQwH6col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH6col[k], 0] := AsgCellDriver.Cells[QwH6col[k], 0]; + AsgGToutput.Cells[GTQwH6col[k], 1] := AsgCellDriver.Cells[QwH6col[k], 1]; + AsgCellDriver.Cols[QwH6col[k]] := AsgGToutput.Cols[GTQwH6col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH6col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH7col[k] <> -1) then + if GTQwH7col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH7col[k], 0] := AsgCellDriver.Cells[QwH7col[k], 0]; + AsgGToutput.Cells[GTQwH7col[k], 1] := AsgCellDriver.Cells[QwH7col[k], 1]; + AsgCellDriver.Cols[QwH7col[k]] := AsgGToutput.Cols[GTQwH7col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH7col[' + inttostr(k) + ']' + '. Run aborted.'); + if (QwH8col[k] <> -1) then + if GTQwH8col[k] <> -1 then + begin + AsgGToutput.Cells[GTQwH8col[k], 0] := AsgCellDriver.Cells[QwH8col[k], 0]; + AsgGToutput.Cells[GTQwH8col[k], 1] := AsgCellDriver.Cells[QwH8col[k], 1]; + AsgCellDriver.Cols[QwH8col[k]] := AsgGToutput.Cols[GTQwH8col[k]]; + end + else if k <= GTSoilLayers then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwH8col[' + inttostr(k) + ']' + '. Run aborted.'); + if (Qwd[k] <> -1) then + if GTQwd[k] <> -1 then + begin + AsgGToutput.Cells[GTQwd[k], 0] := AsgCellDriver.Cells[Qwd[k], 0]; + AsgGToutput.Cells[GTQwd[k], 1] := AsgCellDriver.Cells[Qwd[k], 1]; + AsgCellDriver.Cols[Qwd[k]] := AsgGToutput.Cols[GTQwd[k]]; + end + else if k <= GTSoilLayers - 1 then + raise Exception.Create('GT and MEL disagree on number of soil layers, variable ' + + 'GTQwd[' + inttostr(k) + ']' + '. Run aborted.'); + + // Copy lateral N and C inputs to driver file grid + if PCurrCell^.Rnh4l[k].Count <> 0 then // Assume if one input has values then they all have. + begin + Rnh4lcol[k] := GetColumnNumber('AsgCellDriver', '*D: NH4 lateral input' + inttostr(k)); + Rno3lcol[k] := GetColumnNumber('AsgCellDriver', '*D: NO3 lateral input' + inttostr(k)); + Rdonlcol[k] := GetColumnNumber('AsgCellDriver', '*D: DON lateral input' + inttostr(k)); + Rdoclcol[k] := GetColumnNumber('AsgCellDriver', '*D: DOC lateral input' + inttostr(k)); + for j := 1 to AsgCellDriver.RowCount - 1 do + begin + AsgCellDriver.Cells[Rnh4lcol[k], j] := PCurrCell^.Rnh4l[k].Strings[j]; + AsgCellDriver.Cells[Rno3lcol[k], j] := PCurrCell^.Rno3l[k].Strings[j]; + AsgCellDriver.Cells[Rdoclcol[k], j] := PCurrCell^.Rdocl[k].Strings[j]; + AsgCellDriver.Cells[Rdonlcol[k], j] := PCurrCell^.Rdonl[k].Strings[j]; + end; + end; + end; + tempstring := PCurrCell^.DriverFile; + tempstring2 := ExtractFileExt(tempstring); + delete(tempstring, pos(tempstring2, tempstring), length(tempstring)); + PCurrCell^.DriverFile := tempstring + '_Cell' + inttostr(PCurrCell^.RowPos) + + '_' + inttostr(PCurrCell^.ColPos) + '.drr'; + AsgCellDriver.SavetoCSV(CurrentDirectory + '\' + PCurrCell^.DriverFile); + + + // Run MEL for this cell + FmShellMain.RunningInteractive := False; // This tells Shellmain not to show dialog boxes + Time_start := FTimeStart; + Time_stop := FTimeStop; + Paramfilename := PCurrCell^.ParamFile; + FmShellMain.ChooseParamFile(BtnRun); + driverfilename := PCurrCell^.DriverFile; + outfilename := PCurrCell^.OuputFile; + if PCurrCell^.VegClass = FVegInfo[0].VegType then + FmOptions.RunOptions := FVegInfo[0].RunOptions + else if PCurrCell^.VegClass = FVegInfo[1].VegType then + FmOptions.RunOptions := FVegInfo[1].RunOptions + else + raise Exception.Create('No Run options for vegetaton type ' + + inttostr(PCurrCell^.VegClass) + '. Run aborted.'); + FmOptions.RunOptions := FmOptions.DefaultRunOptions; // This line is to initialize options that aren't in the batch file yet. + FmShellMain.BtnRunClick(BtnRun); + // Get Run output + FmDisplayData.Filename := outfilename; + FmDisplayData.UpdateStringGrid; +// Save N flows to eight neighbors + // Get Cell Locations for headings 1-8 + PCellH1 := + FindCellInList(PCurrCell^.RowPos, PCurrCell^.ColPos+1); + PCellH2 := + FindCellInList(PCurrCell^.RowPos+1, PCurrCell^.ColPos+1); + PCellH3 := + FindCellInList(PCurrCell^.RowPos+1, PCurrCell^.ColPos); + PCellH4 := + FindCellInList(PCurrCell^.RowPos+1, PCurrCell^.ColPos-1); + PCellH5 := + FindCellInList(PCurrCell^.RowPos, PCurrCell^.ColPos-1); + PCellH6 := + FindCellInList(PCurrCell^.RowPos-1, PCurrCell^.ColPos-1); + PCellH7 := + FindCellInList(PCurrCell^.RowPos-1, PCurrCell^.ColPos); + PCellH8 := + FindCellInList(PCurrCell^.RowPos-1, PCurrCell^.ColPos+1); + // Copy N flow to appropriate cellProp item + // H1 + for k := 1 to 4 do + begin + if PCellH1 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H1-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H1-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H1-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H1-' + + inttostr(k)); + if (PCellH1^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH1^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH1^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH1^.Rnh4l[k].Count - 1 do + PCellH1^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH1^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH1^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH1^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH1^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH1^.Rno3l[k].Count - 1 do + PCellH1^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH1^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH1^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH1^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH1^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH1^.Rdocl[k].Count - 1 do + PCellH1^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH1^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH1^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH1^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH1^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH1^.Rdonl[k].Count - 1 do + PCellH1^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH1^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H2 + if PCellH2 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H2-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H2-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H2-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H2-' + + inttostr(k)); + if (PCellH2^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH2^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH2^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH2^.Rnh4l[k].Count - 1 do + PCellH2^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH2^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH2^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH2^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH2^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH2^.Rno3l[k].Count - 1 do + PCellH2^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH2^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH2^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH2^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH2^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH2^.Rdocl[k].Count - 1 do + PCellH2^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH2^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH2^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH2^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH2^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH2^.Rdonl[k].Count - 1 do + PCellH2^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH2^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H3 + if PCellH3 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H3-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H3-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H3-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H3-' + + inttostr(k)); + if (PCellH3^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH3^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH3^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH3^.Rnh4l[k].Count - 1 do + PCellH3^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH3^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH3^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH3^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH3^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH3^.Rno3l[k].Count - 1 do + PCellH3^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH3^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH3^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH3^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH3^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH3^.Rdocl[k].Count - 1 do + PCellH3^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH3^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH3^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH3^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH3^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH3^.Rdonl[k].Count - 1 do + PCellH3^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH3^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H4 + if PCellH4 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H4-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H4-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H4-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H4-' + + inttostr(k)); + if (PCellH4^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH4^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH4^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH4^.Rnh4l[k].Count - 1 do + PCellH4^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH4^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH4^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH4^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH4^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH4^.Rno3l[k].Count - 1 do + PCellH4^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH4^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH4^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH4^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH4^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH4^.Rdocl[k].Count - 1 do + PCellH4^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH4^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH4^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH4^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH4^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH4^.Rdonl[k].Count - 1 do + PCellH4^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH4^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H5 + if PCellH5 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H5-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H5-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H5-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H5-' + + inttostr(k)); + if (PCellH5^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH5^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH5^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH5^.Rnh4l[k].Count - 1 do + PCellH5^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH5^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH5^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH5^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH5^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH5^.Rno3l[k].Count - 1 do + PCellH5^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH5^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH5^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH5^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH5^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH5^.Rdocl[k].Count - 1 do + PCellH5^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH5^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH5^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH5^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH5^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH5^.Rdonl[k].Count - 1 do + PCellH5^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH5^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H6 + if PCellH6 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H6-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H6-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H6-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H6-' + + inttostr(k)); + if (PCellH6^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH6^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH6^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH6^.Rnh4l[k].Count - 1 do + PCellH6^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH6^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH6^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH6^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH6^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH6^.Rno3l[k].Count - 1 do + PCellH6^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH6^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH6^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH6^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH6^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH6^.Rdocl[k].Count - 1 do + PCellH6^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH6^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH6^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH6^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH6^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH6^.Rdonl[k].Count - 1 do + PCellH6^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH6^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H7 + if PCellH7 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H7-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H7-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H7-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H7-' + + inttostr(k)); + if (PCellH7^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH7^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH7^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH7^.Rnh4l[k].Count - 1 do + PCellH7^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH7^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH7^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH7^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH7^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH7^.Rno3l[k].Count - 1 do + PCellH7^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH7^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH7^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH7^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH7^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH7^.Rdocl[k].Count - 1 do + PCellH7^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH7^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH7^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH7^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH7^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH7^.Rdonl[k].Count - 1 do + PCellH7^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH7^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + + // H8 + if PCellH8 <> nil then + begin + Lnh4lcol[k] := GetColumnNumber('sgmodeloutput', '*N NH4 loss lateral H8-' + + inttostr(k)); + Lno3lcol[k] := GetColumnNumber('sgmodeloutput', '*N NO3 loss lateral H8-' + + inttostr(k)); + Ldoclcol[k] := GetColumnNumber('sgmodeloutput', '*C DOC loss lateral H8-' + + inttostr(k)); + Ldonlcol[k] := GetColumnNumber('sgmodeloutput', '*N DON loss lateral H8-' + + inttostr(k)); + if (PCellH8^.Rnh4l[k].Count = 0) and (Lnh4lcol[k] <> -1) then + begin + PCellH8^.Rnh4l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lnh4lcol[k]]); + PCellH8^.Rnh4l[k].Delete(0); + end + else if (Lnh4lcol[k] <> -1) then + for j := 2 to PCellH8^.Rnh4l[k].Count - 1 do + PCellH8^.Rnh4l[k].Strings[j] := + floattostr(strtofloat(PCellH8^.Rnh4l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lnh4lcol[k],j+1])); + if (PCellH8^.Rno3l[k].Count = 0) and (Lno3lcol[k] <> -1) then + begin + PCellH8^.Rno3l[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Lno3lcol[k]]); + PCellH8^.Rno3l[k].Delete(0); + end + else if (Lno3lcol[k] <> -1) then + for j := 2 to PCellH8^.Rno3l[k].Count - 1 do + PCellH8^.Rno3l[k].Strings[j] := + floattostr(strtofloat(PCellH8^.Rno3l[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Lno3lcol[k],j+1])); + if (PCellH8^.Rdocl[k].Count = 0) and (Ldoclcol[k] <> -1) then + begin + PCellH8^.Rdocl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldoclcol[k]]); + PCellH8^.Rdocl[k].Delete(0); + end + else if (Ldoclcol[k] <> -1) then + for j := 2 to PCellH8^.Rdocl[k].Count - 1 do + PCellH8^.Rdocl[k].Strings[j] := + floattostr(strtofloat(PCellH8^.Rdocl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldoclcol[k],j+1])); + if (PCellH8^.Rdonl[k].Count = 0) and (Ldonlcol[k] <> -1) then + begin + PCellH8^.Rdonl[k].AddStrings(FmDisplayData.SgModelOutput.Cols[Ldonlcol[k]]); + PCellH8^.Rdonl[k].Delete(0); + end + else if (Ldonlcol[k] <> -1) then + for j := 2 to PCellH8^.Rdonl[k].Count - 1 do + PCellH8^.Rdonl[k].Strings[j] := + floattostr(strtofloat(PCellH8^.Rdonl[k].Strings[j]) + + strtofloat(FmDisplayData.SgModelOutput.Cells[Ldonlcol[k],j+1])); + end; + end; + end; + finally + Dispose(PCurrCell); + if PCellH1 <> nil then Dispose(PCellH1); + if PCellH2 <> nil then Dispose(PCellH2); + if PCellH3 <> nil then Dispose(PCellH3); + if PCellH4 <> nil then Dispose(PCellH4); + if PCellH5 <> nil then Dispose(PCellH5); + if PCellH6 <> nil then Dispose(PCellH6); + if PCellH7 <> nil then Dispose(PCellH7); + if PCellH8 <> nil then Dispose(PCellH8); + BtnRun.Caption := 'Done'; + end; +end; + +function TFmGridMEL.FindCellInList(RowNum, Colnum: integer): PCellProp; +var + j: integer; + cellfound: Boolean; + PCurrCell: PCellProp; +begin + j := 0; + cellfound := false; + repeat + PCurrCell := FCellInfoList[j]; + if (PCurrCell.rowpos = rownum) and (PCurrCell.colpos = colnum) then + cellfound := True; + j := j + 1; + until cellfound or (j = FCellInfoList.Count - 1); + if cellfound then result := PCurrCell else result := nil; +end; + +procedure TFmGridMEL.UpdateForm(Sender: TObject); +begin + //check if files selected + // update currentdirectory. + CurrentDirectory := GetCurrentDir; + if {(LedDEMFile.text <> '') and (LedVegClassFile.text <> '') and + (LedSoilClassFile.text <> '') and (LedVeg1ParamFile.text <> '') and + (LedVeg2ParamFile.text <> '') and (LedSoilPropFile.text <> '') and } + (LedCellOrderFile.text <> ''){ and (LedDriver1File.Text <> '') and + (LedDriver2File.Text <> '') }and (LedRunOptionsFile.text <> '') + then BtnRun.Enabled := True; +end; + +procedure TFmGridMEL.ReadCellOrderFile; +var + CellOrderFile, Aline: TStringList; + PACell: ^TCellProp; + j, k: integer; +begin + CellOrderFile := TstringList.create; + Aline := Tstringlist.Create; + Aline.Delimiter := ','; + try + CellOrderFile.LoadFromFile(FCellOrderFilename); + for j := 1 to CellOrderFile.Count - 1 do // Skip first line of file, it contains column headings + begin + Aline.DelimitedText := CellOrderFile[j]; + New(PACell); + PACell^.RowPos := strtoint(Aline[0]); + PACell^.ColPos := strtoint(Aline[1]); + PACell^.elevation := strtofloat(Aline[2]); + // FIX Need to enter Runposition here +{ PACellInfoItem^.SoilClass := Aline[3]; + PACellInfoItem^. := Aline[4]; + PACellInfoItem^.RowPos := Aline[5]; + PACellInfoItem^.RowPos := Aline[6]; + PACellInfoItem^.RowPos := Aline[7]; } + PACell^.VegClass := strtoint(Aline[8]); + case strtoint(Aline[8]) {VegClass} of + 501: PACell^.ParamFile := FVegInfo[0].Filenames.ParamFilename; + 502: PACell^.ParamFile := FVegInfo[1].Filenames.ParamFilename; + end; + case strtoint(Aline[8]) {VegClass} of + 501: PACell^.DriverFile := FVegInfo[0].Filenames.DriverFilename; + 502: PACell^.DriverFile := FVegInfo[1].Filenames.DriverFilename; + end; + PACell^.OuputFile := CurrentDirectory + + '\Cell' + Aline[0] + '_' + Aline[1] + '.out'; + for k := 1 to 4 do // Create lists to hold lateral inputs + begin + PACell^.RDocl[k] := Tstringlist.Create; + PACell^.RDonl[k] := Tstringlist.Create; + PACell^.Rnh4l[k] := Tstringlist.Create; + PACell^.Rno3l[k] := Tstringlist.Create; + end; + FCellInfoList.Add(PACell); + end; + finally +// dispose(PACell); + CellOrderFile.Clear; + CellOrderFile.Free; + Aline.Clear; + Aline.Free; + end; +end; + +procedure TFmGridMEL.ReadRunOptionsFile; +var + RunOptionsFile, Aline: TStringList; + j: integer; +begin + RunOptionsFile := TstringList.create; + Aline := Tstringlist.Create; + Aline.Delimiter := ','; + try + RunOptionsFile.LoadFromFile(FRunOptionsFilename); + for j := 0 to RunOptionsFile.Count - 1 - 1 do // One less than total count because first line of file is column headings + begin + Aline.DelimitedText := RunOptionsFile[j+1]; //Skip first line of the file because it contains column headings + FVegInfo[j].VegType := strtoint(Aline[0]); + FVegInfo[j].Filenames.ParamFilename := Aline[1]; + FVegInfo[j].Filenames.DriverFilename := Aline[2]; + FTimeStart := strtofloat(Aline[4]); + FTimeStop := strtofloat(Aline[5]); + FVegInfo[j].RunOptions.Time_step := strtofloat(Aline[6]); + FVegInfo[j].RunOptions.DiscreteStep := strtofloat(Aline[7]); + if (Aline[8][1] = 't') or (Aline[8][1] = 'T') then + FVegInfo[j].RunOptions.NormalRun := True + else + FVegInfo[j].RunOptions.NormalRun := False; + if (Aline[9][1] = 't') or (Aline[9][1] = 'T') then + FVegInfo[j].RunOptions.RepeatDrivers := True + else + FVegInfo[j].RunOptions.RepeatDrivers := False; +// FVegInfo[j].RunOptions.RepeatDrivers := Aline[9]; + FVegInfo[j].RunOptions.RepeatDriveTIme := strtoint(Aline[10]); + if (Aline[11][1] = 't') or (Aline[11][1] = 'T') then + FVegInfo[j].RunOptions.ResetStates := True + else + FVegInfo[j].RunOptions.ResetStates := False; +// FVegInfo[j].RunOptions.ResetStates := Aline[11]; + FVegInfo[j].RunOptions.ResetStateTime := strtoint(Aline[12]); + if (Aline[13][1] = 't') or (Aline[13][1] = 'T') then + FVegInfo[j].RunOptions.RuntoSS := True + else + FVegInfo[j].RunOptions.RuntoSS := False; +// FVegInfo[j].RunOptions.RuntoSS := Aline[13]; + FVegInfo[j].RunOptions.SSCriteria := strtofloat(Aline[14]); + FVegInfo[j].RunOptions.SSTime := strtoint(Aline[15]); + if (Aline[16][1] = 't') or (Aline[16][1] = 'T') then + FVegInfo[j].RunOptions.HoldStatesConstant := True + else + FVegInfo[j].RunOptions.HoldStatesConstant := False; +// FVegInfo[j].RunOptions.HoldStatesConstant := Aline[16]; + FVegInfo[j].RunOptions.Outputstep := strtoint(Aline[17]); + FVegInfo[j].RunOptions.Outputoffset := strtoint(Aline[18]); + if (Aline[17][1] = 't') or (Aline[17][1] = 'T') then + FVegInfo[j].RunOptions.OutputEORonly := True + else + FVegInfo[j].RunOptions.OutputEORonly := False; +// FVegInfo[j].RunOptions.OutputEORonly := Aline[19]; +// FVegInfo[j].RunOptions.OutputAnnually := Aline[7]; +// FVegInfo[j].RunOptions.OutputAnnuallyDay := Aline[7]; + if (Aline[20][1] = 't') or (Aline[20][1] = 'T') then + FVegInfo[j].RunOptions.AppendOutputFile := True + else + FVegInfo[j].RunOptions.AppendOutputFile := False; +// FVegInfo[j].RunOptions.AppendOutputFile := Aline[20]; +// FVegInfo[j].RunOptions.StepCounter := Aline[7]; + // FVegInfo[j].RunOptions.OutCounter := Aline[7]; + FVegInfo[j].RunOptions.errormult := strtoint(Aline[21]); + end; + finally + RunOptionsFile.Free; + Aline.Free; + end; +end; + +procedure TFmGridMEL.LedCellOrderFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseCellOrderFile(Sender); +end; + +procedure TFmGridMEL.LedDEMFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseDEMFile(Sender); +end; + +procedure TFmGridMEL.LedDriver1FileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseDriver1File(Sender); +end; + +procedure TFmGridMEL.LedDriver2FileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseDriver2File(Sender); +end; + +procedure TFmGridMEL.LedRunOptionsFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseRunOptionsFile(Sender); +end; + +procedure TFmGridMEL.LedSoilClassFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseSoilClassFile(Sender); +end; + +procedure TFmGridMEL.LedSoilPropFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseSoilPropFile(Sender); +end; + +procedure TFmGridMEL.LedVeg1ParamFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseVeg1ParamFile(Sender); +end; + +procedure TFmGridMEL.LedVeg2ParamFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseVeg2ParamFile(Sender); +end; + +procedure TFmGridMEL.LedVegClassFileKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseVegClassFile(Sender); +end; + +procedure TFmGridMEL.ChooseDEMFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FDEMFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FDEMFilename) then + begin + MessageDlg('Missing Data File: ' + FDEMFilename + '. Please reenter.', + mtError, [mbOK], 0); + FDEMFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FDEMFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the DEM file'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FDEMFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FDEMFilename := OpenDialog.filename; + ThisEdit.Text := FDEMFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseVegClassFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FVegClassFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FVegClassFilename) then + begin + MessageDlg('Missing Data File: ' + FVegClassFilename + '. Please reenter.', + mtError, [mbOK], 0); + FVegClassFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FVegClassFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the vegetation classification file'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FVegClassFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FVegClassFilename := OpenDialog.filename; + ThisEdit.Text := FVegClassFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseVeg1ParamFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FVeg1ParamFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FVeg1ParamFilename) then + begin + MessageDlg('Missing Data File: ' + FVeg1ParamFilename + '. Please reenter.', + mtError, [mbOK], 0); + FVeg1ParamFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FVeg1ParamFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the parameter file for vegetation class 1'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FVeg1ParamFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FVeg1ParamFilename := OpenDialog.filename; + ThisEdit.Text := FVeg1ParamFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseVeg2ParamFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FVeg2ParamFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FVeg2ParamFilename) then + begin + MessageDlg('Missing Data File: ' + FVeg2ParamFilename + '. Please reenter.', + mtError, [mbOK], 0); + FVeg2ParamFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FVeg2ParamFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the parameter file for vegetation class 2'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FVeg2ParamFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FVeg2ParamFilename := OpenDialog.filename; + ThisEdit.Text := FVeg2ParamFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseSoilClassFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FSoilClassFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FSoilClassFilename) then + begin + MessageDlg('Missing Data File: ' + FSoilClassFilename + '. Please reenter.', + mtError, [mbOK], 0); + FSoilClassFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FSoilClassFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the soil classification file'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FSoilClassFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FSoilClassFilename := OpenDialog.filename; + ThisEdit.Text := FSoilClassFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseSoilPropFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FSoilPropFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FSoilPropFilename) then + begin + MessageDlg('Missing Data File: ' + FSoilPropFilename + '. Please reenter.', + mtError, [mbOK], 0); + FSoilPropFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FSoilPropFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the soil properties file'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FSoilPropFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FSoilPropFilename := OpenDialog.filename; + ThisEdit.Text := FSoilPropFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.Button2Click(Sender: TObject); +begin + FmGridMEL.Close; +end; + +procedure TFmGridMEL.ChooseCellOrderFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FCellOrderFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FCellOrderFilename) then + begin + MessageDlg('Missing Data File: ' + FCellOrderFilename + '. Please reenter.', + mtError, [mbOK], 0); + FCellOrderFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FCellOrderFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the cell order file'; + OpenDialog.DefaultExt := '.dat'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FCellOrderFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FCellOrderFilename := OpenDialog.filename; + ThisEdit.Text := FCellOrderFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseDriver1File(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FDriver1Filename := ThisEdit.EditLabel.Caption; + if not FileExists(FDriver1Filename) then + begin + MessageDlg('Missing Data File: ' + FDriver1Filename + '. Please reenter.', + mtError, [mbOK], 0); + FDriver1Filename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FDriver1Filename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the driver file for vegetation class 1'; + OpenDialog.DefaultExt := '.drr'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FDriver1Filename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FDriver1Filename := OpenDialog.filename; + ThisEdit.Text := FDriver1Filename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseDriver2File(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FDriver2Filename := ThisEdit.EditLabel.Caption; + if not FileExists(FDriver2Filename) then + begin + MessageDlg('Missing Data File: ' + FDriver2Filename + '. Please reenter.', + mtError, [mbOK], 0); + FDriver2Filename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FDriver2Filename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the driver file for vegetation class 2'; + OpenDialog.DefaultExt := '.drr'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FDriver2Filename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FDriver2Filename := OpenDialog.filename; + ThisEdit.Text := FDriver2Filename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.ChooseRunOptionsFile(Sender: TObject); +var + ThisEdit:TLabeledEdit; + ThisLabel: TBoundLabel; +begin +// If the user typed directly in the edit box + if Sender is TLabeledEdit then + begin + ThisEdit := Sender as TLabeledEdit; + FRunOptionsFilename := ThisEdit.EditLabel.Caption; + if not FileExists(FRunOptionsFilename) then + begin + MessageDlg('Missing Data File: ' + FRunOptionsFilename + '. Please reenter.', + mtError, [mbOK], 0); + FRunOptionsFilename := ''; // Set the filename to no value + ThisEdit.EditLabel.Caption := FRunOptionsFilename; + end; + end + else // User clicked on the label + begin // Show the open file dialog + ThisLabel := Sender as TBoundLabel; + ThisEdit := ThisLabel.Owner as TLabeledEdit; + OpenDialog.Title := 'Select the Run Options File file'; + OpenDialog.DefaultExt := '.bch'; + OpenDialog.InitialDir := CurrentDirectory; + OpenDialog.Options := [ofFileMustExist]; + // First set the default filename to the current file + OpenDialog.filename := FRunOptionsFilename; + // Show the dialog and if the user clicks OK, set the new filename + if OpenDialog.execute then + begin + FRunOptionsFilename := OpenDialog.filename; + ThisEdit.Text := FRunOptionsFilename; + end; + end; + UpdateForm(Sender); +end; + +procedure TFmGridMEL.FileExit1Execute(Sender: TObject); +begin + Close; +end; + +procedure TFmGridMEL.HelpAbout1Execute(Sender: TObject); +begin + AboutBox.ShowModal; +end; + +end. diff --git a/modelshell/Options.lfm b/modelshell/Options.lfm new file mode 100644 index 0000000..926f364 --- /dev/null +++ b/modelshell/Options.lfm @@ -0,0 +1,469 @@ +object FmOptions: TFmOptions + Left = 939 + Height = 330 + Top = 392 + Width = 740 + BorderStyle = bsSingle + Caption = 'Run and Output Options' + ClientHeight = 330 + ClientWidth = 740 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + OnCreate = FormCreate + OnShow = FormShow + Position = poMainFormCenter + LCLVersion = '1.4.2.0' + object BtnCancel: TButton + Left = 500 + Height = 25 + Top = 272 + Width = 75 + Cancel = True + Caption = '&Cancel' + ModalResult = 2 + OnClick = BtnCancelClick + TabOrder = 2 + end + object BtnOK: TButton + Left = 408 + Height = 25 + Top = 272 + Width = 74 + Caption = 'O&K' + ModalResult = 1 + OnClick = BtnOKClick + TabOrder = 1 + end + object BtnDefaults: TButton + Left = 17 + Height = 24 + Top = 272 + Width = 88 + Caption = 'De&faults' + OnClick = BtnDefaultsClick + TabOrder = 3 + end + object PcOptions: TPageControl + Left = 0 + Height = 257 + Top = 0 + Width = 740 + ActivePage = TsRunOptions + Align = alTop + TabIndex = 0 + TabOrder = 0 + object TsRunOptions: TTabSheet + Caption = 'Run Options' + ClientHeight = 230 + ClientWidth = 732 + object LblTimeUnit2: TLabel + Left = 254 + Height = 14 + Top = 64 + Width = 49 + AutoSize = False + Caption = 'da&ys' + FocusControl = EdRepeatDriveTime + ParentColor = False + end + object LblTimeUnit1: TLabel + Left = 333 + Height = 14 + Top = 97 + Width = 44 + AutoSize = False + Caption = 'd&ays' + FocusControl = EdResetStateTime + ParentColor = False + end + object LblSSCriteria: TLabel + Left = 32 + Height = 14 + Top = 192 + Width = 174 + Alignment = taRightJustify + AutoSize = False + Caption = '&Percent error at steady state' + FocusControl = EdSSCriteria + ParentColor = False + Visible = False + end + object LblSSTime: TLabel + Left = 319 + Height = 14 + Top = 192 + Width = 171 + Alignment = taRightJustify + AutoSize = False + Caption = 'T&ime to check steady state' + FocusControl = EdSSTime + ParentColor = False + Visible = False + end + object RbNormalRun: TRadioButton + Left = 8 + Height = 19 + Top = 10 + Width = 75 + Caption = '&Normal Run' + Checked = True + OnClick = RbNormalRunClick + TabOrder = 0 + TabStop = True + end + object RbSpecialRun: TRadioButton + Left = 8 + Height = 19 + Top = 40 + Width = 189 + Caption = '&Special Run (Select options below)' + OnClick = RbNormalRunClick + TabOrder = 1 + end + object CbRepeatDrivers: TCheckBox + Left = 32 + Height = 19 + Top = 64 + Width = 125 + Caption = 'Repeat &drivers every ' + Enabled = False + OnClick = CbRepeatDriversClick + TabOrder = 2 + end + object EdRepeatDriveTime: TEdit + Left = 184 + Height = 22 + Top = 60 + Width = 65 + Enabled = False + OnExit = EdRepeatDriveTimeExit + OnKeyPress = EdRepeatDriveTimeKeyPress + TabOrder = 3 + end + object CbResetStates: TCheckBox + Left = 32 + Height = 19 + Top = 96 + Width = 200 + Caption = '&Reset selected state variables every ' + Enabled = False + OnClick = CbResetStatesClick + TabOrder = 4 + end + object EdResetStateTime: TEdit + Left = 264 + Height = 22 + Top = 93 + Width = 65 + Enabled = False + OnExit = EdResetStateTimeExit + OnKeyPress = EdResetStateTimeKeyPress + TabOrder = 5 + end + object BtnOpenStates: TButton + Left = 424 + Height = 41 + Top = 104 + Width = 297 + Caption = 'Ch&oose state variables to reset or hold constant...' + OnClick = BtnOpenStatesClick + TabOrder = 7 + end + object CbRuntoSS: TCheckBox + Left = 32 + Height = 19 + Top = 161 + Width = 119 + Caption = 'Run to S&teady State.' + OnClick = CbRuntoSSClick + OnKeyPress = CbRuntoSSKeyPress + TabOrder = 8 + Visible = False + end + object EdSSCriteria: TEdit + Left = 212 + Height = 22 + Top = 189 + Width = 65 + OnExit = EdSSCriteriaExit + OnKeyPress = EdSSCriteriaKeyPress + TabOrder = 9 + Visible = False + end + object EdSSTime: TEdit + Left = 496 + Height = 22 + Top = 189 + Width = 65 + OnExit = EdSSTimeExit + OnKeyPress = EdSSTimeKeyPress + TabOrder = 10 + Visible = False + end + object CbHoldStatesConstant: TCheckBox + Left = 32 + Height = 19 + Top = 128 + Width = 204 + Caption = '&Hold selected state variables constant' + Enabled = False + OnClick = CbHoldStatesConstantClick + TabOrder = 6 + end + end + object TsOutputOptions: TTabSheet + Caption = 'Output Options' + ClientHeight = 230 + ClientWidth = 732 + ImageIndex = 1 + object Panel1: TPanel + Left = 0 + Height = 114 + Top = 0 + Width = 732 + Align = alTop + BevelOuter = bvNone + BorderStyle = bsSingle + ClientHeight = 110 + ClientWidth = 728 + TabOrder = 0 + object LblTimeUnit3: TLabel + Left = 196 + Height = 15 + Top = 14 + Width = 135 + Alignment = taCenter + Caption = 'months, &beginning at month ' + FocusControl = EdOutputOffset + ParentColor = False + end + object LblYearlyCaution: TLabel + Left = 224 + Height = 15 + Top = 77 + Width = 496 + Caption = 'Only valid with daily models. Code must calculate the day of the year and store it in variable dayofyear.' + ParentColor = False + Visible = False + WordWrap = True + end + object RbOutputIntervals: TRadioButton + Left = 8 + Height = 19 + Top = 14 + Width = 86 + Caption = 'O&utput every ' + Checked = True + OnClick = RbOutputIntervalsClick + TabOrder = 0 + TabStop = True + end + object EdOutputTimeStep: TEdit + Left = 133 + Height = 22 + Top = 11 + Width = 57 + OnExit = EdOutputTimeStepExit + OnKeyPress = EdOutputTimeStepKeyPress + TabOrder = 1 + end + object EdOutputOffset: TEdit + Left = 400 + Height = 22 + Top = 11 + Width = 58 + OnExit = EdOutputOffsetExit + OnKeyPress = EdOutputOffsetKeyPress + TabOrder = 2 + end + object RbOutEndofRunOnly: TRadioButton + Left = 8 + Height = 19 + Top = 46 + Width = 128 + Caption = 'Output &end of run only' + OnClick = RbOutputIntervalsClick + TabOrder = 3 + end + object RbOutputIntervalsAnnual: TRadioButton + Left = 8 + Height = 19 + Top = 78 + Width = 124 + Caption = 'Output &yearly on day ' + OnClick = RbOutputIntervalsClick + TabOrder = 4 + Visible = False + end + object EdOutputDayofYear: TEdit + Left = 144 + Height = 22 + Top = 75 + Width = 68 + OnExit = EdOutputDayofYearExit + OnKeyPress = EdOutputDayofYearKeyPress + TabOrder = 5 + Visible = False + end + end + object CbAppendOutput: TCheckBox + Left = 12 + Height = 19 + Top = 193 + Width = 205 + Caption = '&Append subsequent runs to output file' + OnClick = CbAppendOutputClick + ParentBidiMode = False + TabOrder = 1 + Visible = False + end + object CbNoOutputFile: TCheckBox + Left = 13 + Height = 19 + Top = 161 + Width = 228 + Caption = '&No output file, output stored in memory only' + OnClick = CbNoOutputFileClick + TabOrder = 2 + end + object CbxWriteEvery: TCheckBox + Left = 13 + Height = 19 + Top = 127 + Width = 138 + Caption = '&Write output to file every' + OnClick = CbxWriteEveryClick + TabOrder = 3 + end + object EdWriteEvery: TEdit + Left = 156 + Height = 22 + Top = 125 + Width = 57 + OnExit = EdWriteEveryExit + OnKeyPress = EdWriteEveryKeyPress + TabOrder = 4 + Text = '0' + end + object LblTimeUnit6: TLabel + Left = 220 + Height = 15 + Top = 129 + Width = 39 + Alignment = taCenter + Caption = 'months.' + FocusControl = EdOutputOffset + ParentColor = False + end + end + object TsTimeSteps: TTabSheet + Caption = 'Time Steps' + ClientHeight = 230 + ClientWidth = 732 + ImageIndex = 2 + object LblTimeStep: TLabel + Left = 11 + Height = 14 + Top = 40 + Width = 134 + Alignment = taRightJustify + AutoSize = False + Caption = '&Integrator Time Step' + FocusControl = METimeStep + ParentColor = False + end + object LblDiscreteStep: TLabel + Left = 11 + Height = 14 + Top = 88 + Width = 134 + Alignment = taRightJustify + AutoSize = False + Caption = 'Discrete Time Step' + FocusControl = MEDiscreteStep + ParentColor = False + end + object LblTimeUnit4: TLabel + Left = 256 + Height = 14 + Top = 41 + Width = 121 + AutoSize = False + Caption = 'LblTimeUnit4' + ParentColor = False + end + object LblErrorMult: TLabel + Left = 11 + Height = 14 + Top = 168 + Width = 134 + Alignment = taRightJustify + AutoSize = False + Caption = 'Error Multiplier' + FocusControl = MeErrorMult + ParentColor = False + end + object LblErrorMult2: TLabel + Left = 256 + Height = 14 + Top = 169 + Width = 289 + AutoSize = False + Caption = 'integer, larger values allow larger errors' + ParentColor = False + end + object METimeStep: TMaskEdit + Left = 151 + Height = 22 + Top = 37 + Width = 99 + CharCase = ecNormal + MaxLength = 5 + TabOrder = 0 + OnExit = METimeStepExit + OnKeyPress = METimeStepKeyPress + EditMask = 'ccccc;0; ' + Text = '1' + SpaceChar = ' ' + end + object MEDiscreteStep: TMaskEdit + Left = 151 + Height = 22 + Top = 85 + Width = 99 + CharCase = ecNormal + MaxLength = 5 + TabOrder = 1 + OnExit = MEDiscreteStepExit + OnKeyPress = MEDiscreteStepKeyPress + EditMask = 'ccccc;0; ' + Text = '1' + SpaceChar = ' ' + end + object MeErrorMult: TMaskEdit + Left = 151 + Height = 22 + Top = 165 + Width = 99 + CharCase = ecNormal + MaxLength = 0 + TabOrder = 2 + OnExit = MeErrorMultExit + OnKeyPress = MeErrorMultKeyPress + Text = '1' + SpaceChar = '_' + end + end + end + object LblTimeUnit5: TLabel + Left = 264 + Height = 14 + Top = 112 + Width = 121 + AutoSize = False + Caption = 'LblTimeUnit5' + ParentColor = False + end +end diff --git a/modelshell/Options.pas b/modelshell/Options.pas new file mode 100644 index 0000000..eb25a4f --- /dev/null +++ b/modelshell/Options.pas @@ -0,0 +1,737 @@ +unit Options; + +{$MODE Delphi} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls, ComCtrls, Menus, MaskEdit, stypes; + +type + + { TFmOptions } + + TFmOptions = class(TForm) + BtnCancel: TButton; + BtnOK: TButton; + BtnDefaults: TButton; + CbxWriteEvery: TCheckBox; + EdWriteEvery: TEdit; + LblTimeUnit5: TLabel; + LblTimeUnit6: TLabel; + PcOptions: TPageControl; + TsRunOptions: TTabSheet; + TsOutputOptions: TTabSheet; + RbNormalRun: TRadioButton; + RbSpecialRun: TRadioButton; + CbRepeatDrivers: TCheckBox; + EdRepeatDriveTime: TEdit; + LblTimeUnit2: TLabel; + CbResetStates: TCheckBox; + EdResetStateTime: TEdit; + LblTimeUnit1: TLabel; + BtnOpenStates: TButton; + CbRuntoSS: TCheckBox; + LblSSCriteria: TLabel; + EdSSCriteria: TEdit; + LblSSTime: TLabel; + EdSSTime: TEdit; + TsTimeSteps: TTabSheet; + LblTimeStep: TLabel; + METimeStep: TMaskEdit; + LblDiscreteStep: TLabel; + MEDiscreteStep: TMaskEdit; + LblTimeUnit4: TLabel; + Panel1: TPanel; + CbHoldStatesConstant: TCheckBox; + CbAppendOutput: TCheckBox; + RbOutputIntervals: TRadioButton; + EdOutputTimeStep: TEdit; + LblTimeUnit3: TLabel; + EdOutputOffset: TEdit; + RbOutEndofRunOnly: TRadioButton; + LblErrorMult: TLabel; + MeErrorMult: TMaskEdit; + LblErrorMult2: TLabel; + RbOutputIntervalsAnnual: TRadioButton; + EdOutputDayofYear: TEdit; + LblYearlyCaution: TLabel; + CbNoOutputFile: TCheckBox; + procedure CbxWriteEveryClick(Sender: TObject); + procedure EdWriteEveryExit(Sender: TObject); + procedure EdWriteEveryKeyPress(Sender: TObject; var Key: char); + procedure FormCreate(Sender: TObject); + procedure CbRepeatDriversClick(Sender: TObject); + procedure CbResetStatesClick(Sender: TObject); + procedure EdRepeatDriveTimeExit(Sender: TObject); + procedure EdResetStateTimeExit(Sender: TObject); + procedure BtnCancelClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure UpdateFmRunOptions(Sender: TObject); + procedure RbNormalRunClick(Sender: TObject); + procedure BtnOKClick(Sender: TObject); + procedure RbOutputIntervalsClick(Sender: TObject); + procedure CbAppendOutputClick(Sender: TObject); + procedure CheckOutputStep(var newvalue:double); + procedure CheckDiscreteStep(var newvalue:double); + procedure CbRuntoSSClick(Sender: TObject); + procedure EdOutputTimeStepExit(Sender: TObject); + procedure CheckOutputOffset(newvalue:double); + procedure EdOutputOffsetExit(Sender: TObject); + procedure BtnDefaultsClick(Sender: TObject); + procedure EdRepeatDriveTimeKeyPress(Sender: TObject; var Key: Char); + procedure EdResetStateTimeKeyPress(Sender: TObject; var Key: Char); + procedure EdOutputTimeStepKeyPress(Sender: TObject; var Key: Char); + procedure EdOutputOffsetKeyPress(Sender: TObject; var Key: Char); + procedure CbRuntoSSKeyPress(Sender: TObject; var Key: Char); + procedure EdSSCriteriaExit(Sender: TObject); + procedure EdSSCriteriaKeyPress(Sender: TObject; var Key: Char); + procedure BtnOpenStatesClick(Sender: TObject); + procedure EdSSTimeExit(Sender: TObject); + procedure EdSSTimeKeyPress(Sender: TObject; var Key: Char); + procedure METimeStepExit(Sender: TObject); + procedure METimeStepKeyPress(Sender: TObject; var Key: Char); + procedure MEDiscreteStepKeyPress(Sender: TObject; var Key: Char); + procedure MEDiscreteStepExit(Sender: TObject); + procedure CbHoldStatesConstantClick(Sender: TObject); + procedure MeErrorMultExit(Sender: TObject); + procedure MeErrorMultKeyPress(Sender: TObject; var Key: Char); + procedure EdOutputDayofYearExit(Sender: TObject); + procedure EdOutputDayofYearKeyPress(Sender: TObject; var Key: Char); + procedure CbNoOutputFileClick(Sender: TObject); + private + { Private declarations } + fIntialRunOptions: TRunOptions; + public + { Public declarations } + DefaultRunOptions: TRunOptions; + RunOptions: TRunOptions; + end; + +var + FmOptions: TFmOptions; + +implementation + +{$R *.lfm} + +uses frontend, data; + +procedure TFmOptions.FormCreate(Sender: TObject); +begin + LblTimeUnit1.Caption := ModelDef.timeunit + '.'; + LblTimeUnit2.Caption := ModelDef.timeunit + '.'; + LblTimeUnit3.Caption := ModelDef.timeunit + '(s), beginning at ' + ModelDef.timeunit; + LblTimeUnit4.Caption := ModelDef.timeunit + '.'; + LblTimeUnit5.Caption := ModelDef.timeunit + '. Use with extreme caution.'; + LblTimeUnit6.Caption := ModelDef.timeunit + '.'; + with RunOptions do + begin + NormalRun := True; + Time_step := strtofloat(FmOptions.METimeStep.text); + DiscreteStep := Time_step; + RepeatDrivers := False; + RepeatDriveTime := 0; + ResetStates := False; + ResetStateTime := 0; + RuntoSS := False; + SSCriteria := 0; + SSTime := 0; + HoldStatesConstant := False; + Outputstep := time_step; + Outputoffset := 0; + OutputEORonly := False; + OutputAnnually := False; + OutputAnnuallyDay := 0; + AppendOutputFile := False; + OutputFile := True; + stepcounter := 1; + outcounter := 0; + WriteEvery := 0; + ErrorMult := 1; + end; + DefaultRunOptions := RunOptions; +end; + +procedure TFmOptions.CbxWriteEveryClick(Sender: TObject); +begin + if CbxWriteEvery.Checked then EdWriteEvery.SetFocus; +end; + +procedure TFmOptions.EdWriteEveryExit(Sender: TObject); +var + newwritestep:double; + begin + try + // try + if (EdWriteEvery.Text <> '') or (EdWriteEvery.Text <> '0')then + begin + RunOptions.NormalRun:=False; + newwritestep := strtofloat(EdWriteEvery.Text); + // Add code here to make the write step makes sense + RunOptions.WriteEvery := newwritestep; + end; +{ except on E: Exception do + begin + RunOptions.Outputstep := newoutstep; + EdOutputTimeStep.Text := floattostr(newoutstep); + MessageDlg('Invalid output time step. ' + E.message, + mtwarning, [mbOK], 0); + end; } + // end; + finally + UpdateFmRunOptions(sender); + end; + end; + +procedure TFmOptions.EdWriteEveryKeyPress(Sender: TObject; var Key: char); +begin + if (Key = Chr(13)) then EdWriteEveryExit(Sender); +end; + +procedure TFmOptions.CbRepeatDriversClick(Sender: TObject); +begin + RunOptions.RepeatDrivers := CbRepeatDrivers.Checked; + UpdateFmRunOptions(Sender); + if RunOptions.RepeatDrivers then EdRepeatDriveTime.SetFocus; +end; + +procedure TFmOptions.CbResetStatesClick(Sender: TObject); +var + i: integer; +begin + RunOptions.ResetStates := CbResetStates.Checked; + if not RunOptions.ResetStates then + for i := 1 to ModelDef.numstate do stat[i].Reset := false; + UpdateFmRunOptions(Sender); + if RunOptions.ResetStates then EdResetStateTime.SetFocus; +end; + +procedure TFmOptions.EdRepeatDriveTimeExit(Sender: TObject); +begin + try + if EdRepeatDriveTime.Text <> '0' then + begin + RunOptions.RepeatDriveTime := strtoint(EdRepeatDriveTime.Text); + CbRepeatDrivers.Checked := True; + end; + except + MessageDlg('Invalid driver repeat time. Run set to Normal run.', mtwarning, + [mbOK], 0); + RunOptions.NormalRun := True; + end; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.EdResetStateTimeExit(Sender: TObject); +begin + try + if EdResetStateTime.Text <> '0' then + begin + RunOptions.ResetStateTime := strtofloat(EdResetStateTime.Text); + CbResetStates.Checked := True; + end; + except + MessageDlg('Invalid state variable reset time. Run set to Normal run.', + mtwarning, [mbOK], 0); + RunOptions.NormalRun := True; + end; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.BtnCancelClick(Sender: TObject); +begin + RunOptions := fIntialRunOptions; + FmOptions.UpdateFmRunOptions(Sender); + FmOptions.Close; + FmShellMain.UpdateFmShellMain; +end; + +procedure TFmOptions.FormShow(Sender: TObject); +begin + if FmShellMain.lastitem.name = 'MITimeSteps' then + PcOptions.ActivePage := TsTimeSteps + else if FmShellMain.lastitem.name = 'MISpecialRun' then + PcOptions.ActivePage := TsRunOptions + else + PcOptions.ActivePage := TsOutputOptions; + UpdateFmRunOptions(Sender); + fIntialRunOptions := RunOptions; +end; + +procedure TFmOptions.UpdateFmRunOptions(Sender: TObject); +begin + if RunOptions.NormalRun then + begin + RbNormalRun.Checked := True; + CbRepeatDrivers.Checked := False; + CbRepeatDrivers.Enabled := False; + EdRepeatDriveTime.Text := floattostr(RunOptions.RepeatDriveTime); + EdRepeatDriveTime.Enabled := False; + CbResetStates.Checked := False; + CbResetStates.Enabled := False; + CbHoldStatesConstant.Checked := False; + CbHoldStatesConstant.Enabled := False; + BtnOpenStates.Enabled := False; + EdResetStateTime.Enabled := False; + EdResetStateTime.Text := floattostr(RunOptions.ResetStateTime); + CbRuntoSS.Checked := False; + CbRuntoSS.Enabled := False; + LblSSCriteria.Enabled := False; + EdSSCriteria.Enabled := False; + EdSSCriteria.Text := floattostr(RunOptions.SSCriteria); + LblSSTime.Enabled := False; + EdSSTime.Enabled := False; + EdSSTime.Text := floattostr(RunOptions.SSTime); + end + else // Special Run + begin + RbSpecialRun.Checked := True; + CbRepeatDrivers.Enabled := True; + EdRepeatDriveTime.Enabled := True; + CbResetStates.Enabled := True; + EdResetStateTime.Enabled := True; + CbHoldStatesConstant.Enabled := True; + BtnOpenStates.Enabled := True; + CbRuntoSS.Enabled := True; + LblSSCriteria.Enabled := True; + EdSSCriteria.Enabled := True; + EdSSTime.Enabled := True; + LblSSTime.Enabled := True; + + // Simulation options + CbRepeatDrivers.Checked := RunOptions.RepeatDrivers; + if RunOptions.RepeatDrivers then + EdRepeatDriveTime.Text := floattostr(RunOptions.RepeatDriveTime) + else + EdRepeatDriveTime.Text := floattostr(DefaultRunOptions.RepeatDriveTime); + + CbResetStates.Checked := RunOptions.ResetStates; + if RunOptions.ResetStates then + EdResetStateTime.Text := floattostr(RunOptions.ResetStateTime) + else + EdResetStateTime.Text := floattostr(DefaultRunOptions.ResetStateTime); + + CbHoldStatesConstant.Checked := RunOptions.HoldStatesConstant; + + CbRuntoSS.Checked := RunOptions.RuntoSS; + if RunOptions.RuntoSS then + begin + EdSSCriteria.Text := floattostr(100*RunOptions.SSCriteria); + EdSSTime.Text := floattostr(RunOptions.SSTime); + end + else + begin + EdSSCriteria.Text := floattostr(100*DefaultRunOptions.SSCriteria); + EdSSTime.Text := floattostr(DefaultRunOptions.SSTime); + end; + end; + + EdOutputOffset.Text := floattostr(RunOptions.Outputoffset); + EdOutputTimeStep.Text := floattostr(RunOptions.Outputstep); + EdOutputDayofYear.Text := floattostr(RunOptions.OutputAnnuallyDay); + if RunOptions.OutputEORonly then + begin + RbOutEndofRunOnly.Checked := True; + EdOutputTimeStep.Enabled := False; + EdOutputOffset.Enabled := False; + EdOutputDayofYear.Enabled := False; + FmShellMain.MIOutOptions.Checked := True; + end + else if (not RunOptions.OutputAnnually) then // Output intervals + begin + RbOutputIntervals.Checked := True; + EdOutputTimeStep.Enabled := True; + EdOutputOffset.Enabled := True; + EdOutputDayofYear.Enabled := False; + if (RunOptions.Outputstep = DefaultRunOptions.Outputstep) and + (RunOptions.Outputoffset = DefaultRunOptions.Outputoffset) then + FmShellMain.MIOutOptions.Checked := False + else + FmShellMain.MIOutOptions.Checked := True; + end + else // Output on specific calendar day + begin + RbOutputIntervalsAnnual.Checked := True; + EdOutputDayofYear.Text := floattostr(RunOptions.OutputAnnuallyDay); + EdOutputDayofYear.Enabled := True; + EdOutputTimeStep.Enabled := False; + EdOutputOffset.Enabled := False; + FmShellMain.MIOutOptions.Checked := True; + end; + + if RunOptions.AppendOutputFile then + begin + CbAppendOutput.Checked := True; + FmShellMain.MIOutOptions.Checked := True; + end + else + begin + CbAppendOutput.Checked := False; + end; + + if RunOptions.outputfile then + begin + CbNooutputfile.Checked := False; + FmShellMain.MIOutOptions.Checked := True; + end + else + begin + CbNooutputfile.Checked := True; + end; + + if RunOptions.WriteEvery <> 0 then + begin + CbxWriteEvery.Checked:=True; + FmShellMain.MIOutOptions.Checked := True; + EdWriteEvery.Text:= floattostr(RunOptions.WriteEvery); + end + else + begin + CbxWriteEvery.Checked:=False; + EdWriteEvery.Text:='0'; + end; +// FIX Add code here to set Output options mI to unchecked if all the options have been turned off. + + METimeStep.text := floattostr(RunOptions.time_step); + MEDiscreteStep.Text := floattostr(RunOptions.DiscreteStep); + if (RunOptions.time_step = DefaultRunOptions.Time_step) and + (RunOptions.DiscreteStep = DefaultRunOptions.DiscreteStep) then + FmShellMain.MITimeSteps.Checked := False + else + FmShellMain.MITimeSteps.Checked := True; + + MeErrorMult.text := inttostr(RunOptions.ErrorMult); +end; + +procedure TFmOptions.RbNormalRunClick(Sender: TObject); +begin + RunOptions.NormalRun := RbNormalRun.Checked; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.BtnOKClick(Sender: TObject); +begin + FmShellMain.UpdateFmShellMain; +end; + +procedure TFmOptions.RbOutputIntervalsClick(Sender: TObject); +begin + RunOptions.OutputEORonly := RbOutEndofRunOnly.Checked; + RunOptions.OutputAnnually := RbOutputIntervalsAnnual.Checked; + UpdateFmRunOptions(Sender); + if RunOptions.OutputAnnually then EdOutputDayofYear.SetFocus + else if (not RunOptions.OutputEORonly) then EdOutputTimeStep.SetFocus; +end; + +procedure TFmOptions.CbNoOutputFileClick(Sender: TObject); +begin + RunOptions.outputfile := not CbNoOutputFile.Checked; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.CbAppendOutputClick(Sender: TObject); +begin + RunOptions.AppendOutputFile := CbAppendOutput.Checked; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.CbRuntoSSClick(Sender: TObject); +begin + RunOptions.RuntoSS := CbRuntoSS.Checked; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.EdOutputTimeStepExit(Sender: TObject); +var + newoutstep:double; +begin + try + try + if (EdOutputTimeStep.Text <> ''){and (EdOutputTimeStep.Modified)}then + begin + newoutstep := strtofloat(EdOutputTimeStep.Text); + CheckOutputStep(newoutstep); + RunOptions.Outputstep := newoutstep; + end; + except on E: Exception do + begin + RunOptions.Outputstep := newoutstep; + EdOutputTimeStep.Text := floattostr(newoutstep); + MessageDlg('Invalid output time step. ' + E.message, + mtwarning, [mbOK], 0); + end; + end; + finally + UpdateFmRunOptions(sender); + end; +end; + +procedure TFmOptions.CheckOutputStep(var newvalue:double); +begin + if newvalue < Runoptions.time_step then + begin + newvalue := Runoptions.time_step; + raise EStepTooSmall.Create('Output time step is less than integrator ' + + 'time step. Output time step increased to time step. '); + end; + + if newvalue > time_stop - time_start then + begin + newvalue := time_stop - time_start; + raise EStepTooLarge.Create('Output time step is greater than run ' + + 'length. Output time step decreased to run length. '); + end; + + if abs(newvalue/RunOptions.Time_step - round(newvalue/RunOptions.Time_step)) > epsilon then + begin + newvalue := RunOptions.time_step; + raise EStepNotMultiple.Create('Output time step must be a multiple ' + + 'of integrator time step. Output time step changed to current ' + + 'integrator time_step. '); + end; +end; + +procedure TFmOptions.CheckOutputOffset(newvalue:double); +begin +{ if newvalue < RunOptions.time_step then + raise Exception.Create('Output offset is less than simulation time step. '); } + if newvalue > time_stop then + raise Exception.Create('Output offset is greater than simulation length. '); +end; + +procedure TFmOptions.EdOutputOffsetExit(Sender: TObject); +var + newoutoffset: double; +begin + try + try + if (EdOutputOffset.Text <> ''){and (EdOutputOffset.Modified)}then + begin + newoutoffset := strtoint(EdOutputOffset.Text); + CheckOutputOffset(newoutoffset); + RunOptions.Outputoffset := newoutoffset; + end; + except on E: Exception do + begin + RunOptions.Outputoffset := RunOptions.Time_step; + MessageDlg('Invalid output offset. ' + E.message + + 'Output offset reset to simulation time step. ', mtwarning, [mbOK], 0); + end; + end; + finally + UpdateFmRunOptions(sender); + end; +end; + +procedure TFmOptions.BtnDefaultsClick(Sender: TObject); +begin + if MessageDlg('Reset ALL options (Run, Output and Time step options) to the ' + + 'default values?', mtwarning, + [mbyes,mbno],0) = mryes then RunOptions := DefaultRunOptions; + UpdateFmRunOptions(BtnDefaults); +end; + +procedure TFmOptions.EdRepeatDriveTimeKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdRepeatDriveTimeExit(Sender); +end; + +procedure TFmOptions.EdResetStateTimeKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdResetStateTimeExit(Sender); +end; + +procedure TFmOptions.EdOutputTimeStepKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdOutputTimeStepExit(Sender); +end; + +procedure TFmOptions.EdOutputOffsetKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdOutputOffsetExit(Sender); +end; + +procedure TFmOptions.CbRuntoSSKeyPress(Sender: TObject; var Key: Char); +begin + CbRuntoSSClick(Sender); +end; + +procedure TFmOptions.EdSSCriteriaExit(Sender: TObject); +begin + try + if EdSSCriteria.Text <> '0' then + begin + RunOptions.SSCriteria := strtofloat(EdSSCriteria.Text)/100; + CbRuntoSS.Checked := True; + end; + except + MessageDlg('Invalid steady state criteria. Run set to Normal run.', + mtwarning, [mbOK], 0); + RunOptions.NormalRun := True; + end; + UpdateFmRunOptions(Sender); + if RunOptions.RuntoSS then EdSSTime.SetFocus; +end; + +procedure TFmOptions.EdSSCriteriaKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdSSCriteriaExit(Sender); +end; + +procedure TFmOptions.BtnOpenStatesClick(Sender: TObject); +begin + DataForm.ShowStates; // Show the data form containing state variables +end; + +procedure TFmOptions.EdSSTimeExit(Sender: TObject); +begin + try + if EdSSTime.Text <> '0' then + begin + RunOptions.SSTime := strtoint(EdSSTime.Text); + CbRuntoSS.Checked := True; + end; + except + MessageDlg('Invalid steady state time. Run set to Normal run.', + mtwarning, [mbOK], 0); + RunOptions.NormalRun := True; + end; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.EdSSTimeKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdSSTimeExit(Sender); +end; + +procedure TFmOptions.METimeStepExit(Sender: TObject); +var + newtimestep: double; // fix +begin // remove newtimestep once fix MEtimestep.modified + if (METimeStep.text <> '') then + begin + newtimestep := strtofloat(METimeStep.text); + if newtimestep <> RunOptions.Time_step then + try + try + RunOptions.Time_Step := newtimestep; + ReadytoRun := False; + RunComplete := False; // Previous runs are invalid. + FmShellMain.UpdateFmShellMain; // Update the form. + CheckOutputStep(RunOptions.Outputstep); + except + on E: EStepError do + begin + RunOptions.Outputstep := RunOptions.time_step; + FmOptions.EdOutputTimeStep.Text := floattostr(RunOptions.time_step); + MessageDlg(E.message, mtwarning, [mbOK], 0); + end; + end; + finally + UpdateFmRunOptions(sender); + end; + end; +end; + +procedure TFmOptions.METimeStepKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then MeTimeStepExit(Sender); +end; + +procedure TFmOptions.MEDiscreteStepKeyPress(Sender: TObject; + var Key: Char); +begin + if (Key = Chr(13)) then MeTimeStepExit(Sender); +end; + +procedure TFmOptions.MEDiscreteStepExit(Sender: TObject); +var + newtimestep: double; +begin // fix + if (MEDiscreteStep.text <> '') then + begin + newtimestep := strtofloat(MEDiscreteStep.text); + if newtimestep <> RunOptions.DiscreteStep then + try + try + RunOptions.DiscreteStep := newtimestep; + ReadytoRun := False; + RunComplete := False; // Previous runs are invalid. + FmShellMain.UpdateFmShellMain; // Update the form. + CheckDiscreteStep(RunOptions.DiscreteStep); + except + on E: EStepError do + begin + RunOptions.DiscreteStep := RunOptions.time_step; + FmOptions.MEDiscreteStep.Text := floattostr(RunOptions.time_step); + MessageDlg(E.message, mtwarning, [mbOK], 0); + end; + end; + finally + UpdateFmRunOptions(sender); + end; + end; +end; + +procedure TFmOptions.CheckDiscreteStep(var newvalue:double); +begin + if newvalue < Runoptions.time_step then + begin + newvalue := Runoptions.time_step; + raise EStepTooSmall.Create('Discrete time step is less than integrator ' + + 'time step. Discrete time step increased to time step. '); + end; + + if newvalue > time_stop - time_start then + begin + newvalue := time_stop - time_start; + raise EStepTooLarge.Create('Discrete time step is greater than run ' + + 'length. Discrete time step decreased to run length. '); + end; + + if abs(newvalue/RunOptions.Time_step - round(newvalue/RunOptions.Time_step)) > + epsilon then + begin + newvalue := RunOptions.time_step; + raise EStepNotMultiple.Create('Discrete time step must be a multiple ' + + 'of integrator time step. Discrete time step changed to current ' + + 'integrator time step. '); + end; +end; + +procedure TFmOptions.CbHoldStatesConstantClick(Sender: TObject); +begin + RunOptions.HoldStatesConstant := CbHoldStatesConstant.Checked; + UpdateFmRunOptions(Sender); +end; + +procedure TFmOptions.MeErrorMultExit(Sender: TObject); +begin // fix - add error checking here + RunOptions.ErrorMult := strtoint(MeErrorMult.Text); +end; + +procedure TFmOptions.MeErrorMultKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then MeErrorMultExit(Sender); +end; + +procedure TFmOptions.EdOutputDayofYearExit(Sender: TObject); +begin + if EdOutputDayofYear.Text <> '' then + begin + RunOptions.OutputAnnuallyDay := strtofloat(EdOutputDayofYear.text); + end; + UpdateFmRunOptions(sender); +end; + +procedure TFmOptions.EdOutputDayofYearKeyPress(Sender: TObject; + var Key: Char); +begin + if (Key = Chr(13)) then EdOutputDayofYearExit(Sender); +end; + +end. + + diff --git a/modelshell/ParamList.lfm b/modelshell/ParamList.lfm new file mode 100644 index 0000000..b21b4ec --- /dev/null +++ b/modelshell/ParamList.lfm @@ -0,0 +1,80 @@ +object FmParamList: TFmParamList + Left = 855 + Height = 642 + Top = 234 + Width = 758 + ActiveControl = btnSelect + BorderIcons = [] + BorderStyle = bsSingle + Caption = 'Choose a parameter to display' + ClientHeight = 642 + ClientWidth = 758 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + OnCreate = FormCreate + Position = poMainFormCenter + LCLVersion = '0.9.30' + object lbParamSymbols: TListBox + Left = 5 + Height = 529 + Top = 5 + Width = 758 + Columns = 3 + ItemHeight = 0 + OnClick = lbParamSymbolsClick + OnDblClick = btnSelectClick + TabOrder = 0 + end + object btnSelect: TButton + Left = 8 + Height = 25 + Top = 552 + Width = 100 + Caption = '&Select' + OnClick = btnSelectClick + TabOrder = 1 + end + object btnCancel: TButton + Left = 125 + Height = 25 + Top = 552 + Width = 100 + Caption = '&Cancel' + ModalResult = 2 + TabOrder = 2 + end + object lbParamNames: TListBox + Left = 0 + Height = 529 + Top = 0 + Width = 758 + Align = alTop + Columns = 3 + ItemHeight = 0 + OnClick = lbParamNamesClick + OnDblClick = btnSelectClick + TabOrder = 3 + end + object rbParameterSymbol: TRadioButton + Left = 552 + Height = 18 + Top = 551 + Width = 142 + Caption = 'Show parameter s&ymbols' + Checked = True + OnClick = rbParameterSymbolClick + TabOrder = 4 + TabStop = True + end + object rbParameterName: TRadioButton + Left = 552 + Height = 18 + Top = 574 + Width = 134 + Caption = 'Show parameter &names' + OnClick = rbParameterNameClick + TabOrder = 5 + end +end diff --git a/modelshell/ParamList.pas b/modelshell/ParamList.pas new file mode 100644 index 0000000..40b5fd7 --- /dev/null +++ b/modelshell/ParamList.pas @@ -0,0 +1,142 @@ +unit ParamList; + +{$MODE Delphi} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; + +type + TFmParamList = class(TForm) + lbParamSymbols: TListBox; + btnSelect: TButton; + btnCancel: TButton; + lbParamNames: TListBox; + rbParameterSymbol: TRadioButton; + rbParameterName: TRadioButton; + procedure btnSelectClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure rbParameterSymbolClick(Sender: TObject); + procedure rbParameterNameClick(Sender: TObject); + procedure lbParamSymbolsClick(Sender: TObject); + procedure lbParamNamesClick(Sender: TObject); + private + { Private declarations } + public + whichEdparselected: integer; + { Public declarations } + end; + +var + FmParamList: TFmParamList; + +implementation +uses frontend, Display, calculate, stypes; +{$R *.lfm} + +procedure TFmParamList.FormCreate(Sender: TObject); +var + i : integer; +begin + // fill the boxes with names and symbols + for i := 1 to modelDef.numparam do begin + lbParamSymbols.Items.Add(par[i].symbol); + lbParamNames.Items.Add(par[i].name); + end; + // select the first in the list + lbParamSymbols.ItemIndex := 0; + lbParamNames.ItemIndex := 0; + + // make sure the symbols box is on top + lbParamSymbols.visible := true; + lbParamNames.visible := false; + LbparamSymbols.Align:=alTop; + LbParamNames.Align:=alNone; +end; + +procedure TFmParamList.btnSelectClick(Sender: TObject); +var + tempString : string; + tempIndex : integer; + ParAlreadySelected:Boolean; +begin + +ParAlreadySelected:=False; +tempString := lbParamSymbols.items[lbParamSymbols.itemIndex]; +tempIndex := fmCalculate.getArrayIndex(vtParameter,tempString); + +// Check if the selected parameter is already displayed. +if (FmDisplayOutput.lblEdPar1.EditLabel.caption = tempString) or + (FmDisplayOutput.lblEdPar2.EditLabel.caption = tempString) or + (FmDisplayOutput.lblEdPar3.EditLabel.caption = tempString) or + (FmDisplayOutput.lblEdPar4.EditLabel.caption = tempString) then + begin + messageDlg('That parameter is already displayed', mtWarning, [mbOK], 0); + ParAlreadySelected:=True; + end +else + begin + // which of the four labels in the display form was selected + case whichEdparselected of + 1: begin + FmDisplayOutput.lblEdPar1.EditLabel.caption := tempString; + FmDisplayOutput.LblEdPar1.text := floatToStr(par[tempIndex].value); + FmDisplayOutput.LblEdPar1.Enabled := true; + end; + 2: begin + FmDisplayOutput.lblEdPar2.EditLabel.caption := tempString; + FmDisplayOutput.lblEdPar2.text := floatToStr(par[tempIndex].value); + FmDisplayOutput.lblEdPar2.Enabled := true; // fix necessary? + end; + 3: begin + FmDisplayOutput.lblEdPar3.EditLabel.caption := tempString; + FmDisplayOutput.lblEdPar3.text := floatToStr(par[tempIndex].value); + FmDisplayOutput.lblEdPar3.Enabled := true; + end; + 4: begin + FmDisplayOutput.lblEdPar4.EditLabel.caption := tempString; + FmDisplayOutput.lblEdPar4.text := floatToStr(par[tempIndex].value); + FmDisplayOutput.lblEdPar4.Enabled := true; + end; + else + begin + messageDlg('There`s a problem with the selection of a parameter', + mtInformation, [mbOK], 0); + end; + end; + end; +if not ParAlreadySelected then FmParamList.Close; +end; + +procedure TFmParamList.rbParameterSymbolClick(Sender: TObject); +begin + // make sure the symbols box is on top + lbParamSymbols.visible := true; + LbParamSymbols.Align:=alTop; + lbParamNames.visible := false; + LbParamNames.Align:=alNone; +end; + +procedure TFmParamList.rbParameterNameClick(Sender: TObject); +begin + // make sure the names box is on top + fmParamList.lbParamSymbols.visible := false; + LbParamSymbols.Align:=alNone; + fmParamList.lbParamNames.visible := true; + LbParamNames.Align:=alTop; +end; + +procedure TFmParamList.lbParamSymbolsClick(Sender: TObject); +begin + // to always have the same name and symbol selected + lbParamNames.itemIndex := lbParamSymbols.itemIndex; +end; + +procedure TFmParamList.lbParamNamesClick(Sender: TObject); +begin + // to always have the same name and symbol selected + lbParamSymbols.itemIndex := lbParamNames.itemIndex; +end; + +end. diff --git a/modelshell/ProgressBar.lfm b/modelshell/ProgressBar.lfm new file mode 100644 index 0000000..6b190a6 --- /dev/null +++ b/modelshell/ProgressBar.lfm @@ -0,0 +1,58 @@ +object FmProgress: TFmProgress + Left = 373 + Height = 74 + Top = 204 + Width = 494 + BorderIcons = [] + BorderStyle = bsDialog + Caption = 'FmProgress' + ClientHeight = 74 + ClientWidth = 494 + Color = clBtnFace + DefaultMonitor = dmMainForm + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + FormStyle = fsStayOnTop + OnCreate = FormCreate + OnShow = FormShow + Position = poOwnerFormCenter + LCLVersion = '1.8.4.0' + object LblBegin: TLabel + Left = 7 + Height = 14 + Top = 20 + Width = 63 + AutoSize = False + Caption = 'LblBegin' + ParentColor = False + end + object LblEnd: TLabel + Left = 401 + Height = 14 + Top = 20 + Width = 80 + Alignment = taRightJustify + AutoSize = False + Caption = 'LblEnd' + ParentColor = False + end + object PbRunStatus: TProgressBar + Left = 76 + Height = 13 + Top = 20 + Width = 319 + Smooth = True + TabOrder = 0 + BarShowText = True + end + object BtnCancel: TButton + Left = 221 + Height = 20 + Top = 46 + Width = 76 + Caption = '&Cancel' + OnClick = BtnCancelClick + TabOrder = 1 + end +end diff --git a/modelshell/ProgressBar.pas b/modelshell/ProgressBar.pas new file mode 100644 index 0000000..798c43b --- /dev/null +++ b/modelshell/ProgressBar.pas @@ -0,0 +1,62 @@ +unit ProgressBar; + +{$MODE Delphi} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls; +//type Tapp = (mainmodel, fuzzycal); +type Tcprocedure = procedure of object; +type + TFmProgress = class(TForm) + PbRunStatus: TProgressBar; + LblBegin: TLabel; + LblEnd: TLabel; + BtnCancel: TButton; + procedure BtnCancelClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } +// apprunning: Tapp; + CancelProcedure: Tcprocedure; + end; + +var + FmProgress: TFmProgress; + +implementation + +uses frontend; + +{$R *.lfm} + +procedure TFmProgress.BtnCancelClick(Sender: TObject); +begin + if messageDlg('Do you want to abort this run?', mtConfirmation, + [mbYes, mbNo], 0) = mrYes + then + begin +// raise EUserCancel.Create('User canceled run. '); +{ if apprunning = mainmodel then + FmShellMain.CancelRun + else if apprunning = fuzzycal then + FmCalMain.CancelRun; } + CancelProcedure; + end; +end; + +procedure TFmProgress.FormShow(Sender: TObject); +begin + PbRunStatus.Position := 0; +end; + +procedure TFmProgress.FormCreate(Sender: TObject); +begin + CancelProcedure := FmShellMain.CancelRun; +end; + +end. diff --git a/modelshell/ReloadDlg.lfm b/modelshell/ReloadDlg.lfm new file mode 100644 index 0000000..d8e33cc --- /dev/null +++ b/modelshell/ReloadDlg.lfm @@ -0,0 +1,82 @@ +object DlgReload: TDlgReload + Left = 565 + Height = 191 + Top = 197 + Width = 313 + BorderStyle = bsDialog + Caption = 'Dialog' + ClientHeight = 191 + ClientWidth = 313 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Position = poMainFormCenter + LCLVersion = '0.9.30' + object Bevel1: TBevel + Left = 8 + Height = 129 + Top = 8 + Width = 297 + Shape = bsFrame + end + object OKBtn: TButton + Left = 79 + Height = 25 + Top = 148 + Width = 75 + Caption = 'OK' + Default = True + ModalResult = 1 + OnClick = OKBtnClick + TabOrder = 0 + end + object CancelBtn: TButton + Left = 159 + Height = 25 + Top = 148 + Width = 75 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 1 + end + object MoDirections: TMemo + Left = 16 + Height = 82 + Top = 16 + Width = 281 + BorderStyle = bsNone + Color = clScrollBar + Font.Color = clBlack + Font.Height = -12 + Font.Name = 'Arial' + Lines.Strings = ( + 'Choose which items to reload from the parameter ' + 'file. Changes to parameters or state variables ' + 'which haven''t been saved will be lost when you ' + 'reload.' + ) + ParentFont = False + ReadOnly = True + TabOrder = 2 + end + object CbParams: TCheckBox + Left = 40 + Height = 18 + Top = 108 + Width = 73 + Caption = 'Parameters' + TabOrder = 3 + end + object CbState: TCheckBox + Left = 168 + Height = 18 + Top = 108 + Width = 92 + Caption = 'State Variables' + Checked = True + State = cbChecked + TabOrder = 4 + end +end diff --git a/modelshell/ReloadDlg.pas b/modelshell/ReloadDlg.pas new file mode 100644 index 0000000..4d478fc --- /dev/null +++ b/modelshell/ReloadDlg.pas @@ -0,0 +1,57 @@ +{ A modal dialog box to select what to read from the parameter file; state + variables, parameters or both. } +unit ReloadDlg; + +interface + +uses SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, + Buttons, ExtCtrls, Dialogs; + +type + TDlgReload = class(TForm) + OKBtn: TButton; + CancelBtn: TButton; + Bevel1: TBevel; + MoDirections: TMemo; + CbParams: TCheckBox; + CbState: TCheckBox; + procedure OKBtnClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + DlgReload: TDlgReload; + +implementation + +uses stypes, fileio, frontend; + +{$R *.lfm} + +// Reload the selected items from the parameter file +procedure TDlgReload.OKBtnClick(Sender: TObject); +var + temppar: paramarray; + tempstat: statearray; +begin + tempstat := stat; // to get names and units into the temporary array + temppar := par; // to get names and units into the temporary array + // Read data from the parameter file and store in the temporary arrays + ReadParamFile(paramfilename, modeldef.numparam, temppar, modeldef.numstate, + tempstat, FmShellMain.currentresid); + // Copy values read from the file into the global variables only if checkbox checked + if CbParams.Checked and CbState.Checked then + begin + stat := tempstat; + par := temppar; + end + else if CbParams.Checked then + par := temppar + else if CbState.Checked then + stat := tempstat; +end; + +end. diff --git a/modelshell/ScaleDlg.lfm b/modelshell/ScaleDlg.lfm new file mode 100644 index 0000000..3e21f9a --- /dev/null +++ b/modelshell/ScaleDlg.lfm @@ -0,0 +1,150 @@ +object DlgScale: TDlgScale + Left = 366 + Height = 223 + Top = 184 + Width = 313 + BorderStyle = bsDialog + Caption = 'Axis Parameters' + ClientHeight = 223 + ClientWidth = 313 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + OnShow = FormShow + Position = poOwnerFormCenter + LCLVersion = '0.9.30.2' + object Bevel1: TBevel + Left = 8 + Height = 176 + Top = 8 + Width = 297 + Shape = bsFrame + end + object LblMin: TLabel + Left = 24 + Height = 15 + Top = 106 + Width = 41 + Caption = '&Minimum' + FocusControl = EdMinValue + ParentColor = False + end + object LblMax: TLabel + Left = 24 + Height = 15 + Top = 138 + Width = 45 + Caption = 'Ma&ximum' + FocusControl = EdMaxValue + ParentColor = False + end + object LblScale: TLabel + Left = 120 + Height = 14 + Top = 78 + Width = 65 + Alignment = taCenter + AutoSize = False + Caption = 'Scale' + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object LblIncrem: TLabel + Left = 159 + Height = 15 + Top = 106 + Width = 48 + Caption = '&Increment' + FocusControl = EdIncrem + ParentColor = False + Visible = False + end + object OKBtn: TButton + Left = 79 + Height = 25 + Top = 190 + Width = 75 + Caption = '&OK' + Default = True + ModalResult = 1 + OnClick = OKBtnClick + TabOrder = 0 + end + object CancelBtn: TButton + Left = 159 + Height = 25 + Top = 190 + Width = 75 + Cancel = True + Caption = '&Cancel' + ModalResult = 2 + TabOrder = 1 + end + object EdMinValue: TEdit + Left = 80 + Height = 22 + Top = 104 + Width = 57 + OnExit = EditExit + TabOrder = 2 + end + object EdMaxValue: TEdit + Left = 80 + Height = 22 + Top = 136 + Width = 57 + OnExit = EditExit + TabOrder = 3 + end + object RGAxisType: TRadioGroup + Left = 24 + Height = 40 + Top = 16 + Width = 265 + AutoFill = True + Caption = 'Axis Type' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 + ClientHeight = 22 + ClientWidth = 261 + Columns = 2 + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + ItemIndex = 0 + Items.Strings = ( + 'Li&near' + 'Lo&garithmic' + ) + ParentFont = False + TabOrder = 4 + Visible = False + end + object EdIncrem: TEdit + Left = 224 + Height = 22 + Top = 104 + Width = 65 + OnExit = EditExit + TabOrder = 5 + Visible = False + end + object CBAuto: TCheckBox + Left = 159 + Height = 18 + Top = 132 + Width = 71 + Caption = '&Auto Scale' + TabOrder = 6 + end +end diff --git a/modelshell/ScaleDlg.pas b/modelshell/ScaleDlg.pas new file mode 100644 index 0000000..7c60ce4 --- /dev/null +++ b/modelshell/ScaleDlg.pas @@ -0,0 +1,132 @@ +{ A modal dialog box to modify the axis scales on the chart in the display.pas + file. The dialog box contains edit boxes for the axis minimum, maximum, and + increment; a radio group box to choose linear or logarithmic axis; and a + checkbox to enable/disable autoscaling. Any changes made to the edit boxes + automatically disable autoscaling. } +unit ScaleDlg; + +interface + +uses SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, + Buttons, ExtCtrls, stypes; + +type + TDlgScale = class(TForm) + OKBtn: TButton; + CancelBtn: TButton; + Bevel1: TBevel; + LblMin: TLabel; + LblMax: TLabel; + EdMinValue: TEdit; + EdMaxValue: TEdit; + LblScale: TLabel; + RGAxisType: TRadioGroup; + LblIncrem: TLabel; + EdIncrem: TEdit; + CBAuto: TCheckBox; + procedure OKBtnClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure EditExit(Sender:TObject); + private + { Private declarations } + public + { Public declarations } + BottomMinValue, BottomMaxValue, BottomIncrem:double; + LeftMinValue, LeftMaxValue, LeftIncrem:double; + end; + +var + DlgScale: TDlgScale; + +implementation + +uses display, dialogs; { TODO 2 -obk : remove dialogs from uses clause once chart is working } + +{$R *.lfm} + +{ Before showing the form set the Dialog box title and default values for all + objects. These values are dependent on which axis is the current axis in the + chart. } +procedure TDlgScale.FormShow(Sender: TObject); +begin + if FmDisplayOutput.CurrentAxis = axBottom then // Independent Axis + begin + DlgScale.Caption := 'Independent Axis'; + if FmDisplayOutput.ChBAxisLogarithm.Enabled then + RGAxisType.ItemIndex := 1 // Check logarithmic radio button + else + RGAxisType.ItemIndex := 0; // Check linear radio button + CBAuto.Checked := not FmDisplayOutput.ChOutput.Extent.UseXMin; + EdMinValue.text := floattostr(FmDisplayOutput.ChOutput.Extent.XMin); + EdMaxValue.text := floattostr(FmDisplayOutput.ChOutput.Extent.XMax); + end + else // CurrentAxis = axLeft Dependent Axis + begin + DlgScale.Caption := 'Dependent Axis' ; + if FmDisplayOutput.ChLAxisLogarithm.Enabled then + RGAxisType.ItemIndex := 1 // Check logarithmic radio button + else + RGAxisType.ItemIndex := 0; // Check linear radio button + CBAuto.Checked := not FmDisplayOutput.ChOutput.Extent.UseYMin; + EdMinValue.text := floattostr(FmDisplayOutput.ChOutput.Extent.YMin); + EdMaxValue.text := floattostr(FmDisplayOutput.ChOutput.Extent.YMax); + end; +end; + +// Implement any changes made in this dialog +procedure TDlgScale.OKBtnClick(Sender: TObject); +begin + { Changing the axis type won't work until the bug in TaChart that causes an access + violation when setting the axis for the lineseries is fixed. Sept 22, 2011 BK} +// Set the axis type + if RgAxisType.itemindex = 0 then // Linear axis + if FmDisplayOutput.CurrentAxis = axBottom then + FmDisplayOutput.ChBAxisLogarithm.Enabled:=false + else + FmDisplayOutput.ChLAxisLogarithm.Enabled:=false + else // Logarithmic axis + if FmDisplayOutput.CurrentAxis = axBottom then + FmDisplayOutput.ChBAxisLogarithm.Enabled:=true + else + FmDisplayOutput.ChLAxisLogarithm.Enabled:=true; + +//Set the minimum and maximum axis values + if CbAuto.checked then // Autoscale + begin + if FmDisplayOutput.CurrentAxis=axBottom then + begin + FmDisplayOutput.ChOutput.Extent.UseXMin := False; + FmDisplayOutput.ChOutput.Extent.UseXMax := False; + end + else // Left Axis + begin + FmDisplayOutput.ChOutput.Extent.UseYMin := False; + FmDisplayOutput.ChOutput.Extent.UseYMax := False; + end; + end + else // Manual axis scale + begin + if FmDisplayOutput.CurrentAxis=axBottom then + begin + FmDisplayOutput.ChOutput.Extent.UseXMin := True; + FmDisplayOutput.ChOutput.Extent.XMin := strtofloat(EdMinValue.Text); + FmDisplayOutput.ChOutput.Extent.UseXMax := True; + FmDisplayOutput.ChOutput.Extent.XMax := strtofloat(EdMaxValue.Text); + end + else // Left Axis + begin + FmDisplayOutput.ChOutput.Extent.UseYMin := True; + FmDisplayOutput.ChOutput.Extent.YMin := strtofloat(EdMinValue.Text); + FmDisplayOutput.ChOutput.Extent.UseYMax := True; + FmDisplayOutput.ChOutput.Extent.YMax := strtofloat(EdMaxValue.Text); + end; + end +end; + +procedure TDlgScale.EditExit(Sender:TObject); +begin + if (Sender as TEdit).modified = true then + CBAuto.Checked := false; +end; + +end. diff --git a/modelshell/SeriesForm.lfm b/modelshell/SeriesForm.lfm new file mode 100644 index 0000000..a52b279 --- /dev/null +++ b/modelshell/SeriesForm.lfm @@ -0,0 +1,82 @@ +object FmSeries: TFmSeries + Left = 361 + Top = 286 + Caption = 'Dialog' + ClientHeight = 263 + ClientWidth = 385 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Font.Style = [] + Position = poOwnerFormCenter + OnResize = FormResize + OnShow = FormShow + PixelsPerInch = 96 + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 385 + Height = 226 + Align = alClient + TabOrder = 0 + object LbxChooseSeries: TListBox + Left = 0 + Top = 0 + Width = 383 + Height = 224 + Align = alClient + Columns = 3 + ExtendedSelect = False + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Arial' + Font.Style = [] + ItemHeight = 16 + MultiSelect = True + ParentFont = False + Sorted = True + TabOrder = 0 + end + end + object Panel2: TPanel + Left = 0 + Top = 226 + Width = 385 + Height = 37 + Align = alBottom + TabOrder = 1 + object OKBtn: TButton + Left = 191 + Top = 2 + Width = 75 + Height = 24 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 0 + OnClick = OKBtnClick + end + object CancelBtn: TButton + Left = 276 + Top = 2 + Width = 75 + Height = 24 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 1 + end + object BtnClearSelection: TButton + Left = 20 + Top = 2 + Width = 104 + Height = 24 + Caption = 'Clear &Selection' + TabOrder = 2 + OnClick = BtnClearSelectionClick + end + end +end diff --git a/modelshell/SeriesForm.pas b/modelshell/SeriesForm.pas new file mode 100644 index 0000000..91e3b8c --- /dev/null +++ b/modelshell/SeriesForm.pas @@ -0,0 +1,104 @@ +{ This form is a dialog which contains a listbox. The listbox is used to hold + the list of all variables in the model. The user chooses items from the + to be shown in the chart on the Display form. } +unit SeriesForm; + +interface + +uses SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, + Buttons, ExtCtrls, Dialogs, stypes; + +type + TFmSeries = class(TForm) + Panel1: TPanel; + LbxChooseSeries: TListBox; + Panel2: TPanel; + OKBtn: TButton; + CancelBtn: TButton; + BtnClearSelection: TButton; + procedure FormShow(Sender: TObject); + procedure OKBtnClick(Sender: TObject); + procedure BtnClearSelectionClick(Sender: TObject); + procedure FormResize(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + FmSeries: TFmSeries; + +implementation + +{$R *.lfm} + +uses display; + +{ Depending on whether the user is choosing items for the x or y axis disable or + enable multiple selections accordingly. } +procedure TFmSeries.FormShow(Sender: TObject); +var + i, seriesindex:integer; + seriesname:string; +begin + FmDisplayOutput.FillListBox(FmSeries.LbxChooseSeries); + if FmDisplayOutput.CurrentAxis = axBottom then // Choosing Independent Axis + begin + // Set the form caption including instructions + FmSeries.Caption := 'Independent Axis - Choose one series.'; + // Can only choose one series for independent axis, disable multiselect + LbxChooseSeries.MultiSelect := False; + BtnClearSelection.Enabled := False; + BtnClearSelection.Visible := False; + seriesname := FmDisplayOutput.xAxis; + seriesindex := LbxChooseSeries.Items.Indexof(seriesname); + LbxChooseSeries.ItemIndex := seriesindex; + end + else // Dependent Axis + begin + // Set the form caption including instructions + FmSeries.Caption := 'Dependent Axis - Choose a maximum of 10 series.'; + // Can choose up to 10 series for the dependent axis, enable multiselect + LbxChooseSeries.MultiSelect := True; + BtnClearSelection.Enabled := True; + BtnClearSelection.Visible := True; + for i := 0 to LbxChooseSeries.Items.Count - 1 do + LbxChooseSeries.Selected[i] := FmDisplayOutput.LbxSeriesSelect.Selected[i]; + end; +end; + +{} +procedure TFmSeries.OKBtnClick(Sender: TObject); +var + i:integer; +begin + if FmDisplayOutput.CurrentAxis = axBottom then // Set the Independent Axis + begin + // Loop over the items in the list + for i := 0 to LbxChooseSeries.Items.Count - 1 do + if LbxChooseSeries.Selected[i] then + FmDisplayOutput.xAxis := LbxChooseSeries.Items[i]; + end + else // Set the Dependent Axes. CurrentAxis = axLeft + begin + for i := 0 to LbxChooseSeries.Items.Count - 1 do + FmDisplayOutput.LbxSeriesSelect.Selected[i]:=LbxChooseSeries.Selected[i]; + end; +end; + +procedure TFmSeries.BtnClearSelectionClick(Sender: TObject); +begin + FmDisplayOutput.ClearSeriestoPlot(FmSeries.LbxChooseSeries);; +end; + +procedure TFmSeries.FormResize(Sender: TObject); +var + numcol:integer; +begin + numcol := round(LbxChooseSeries.ClientWidth/(8*stringlength)); // assumes 8 units per character + if numcol < 1 then numcol := 1; + LbxChooseSeries.Columns:=round(numcol); +end; + +end. diff --git a/modelshell/aboutbox.lfm b/modelshell/aboutbox.lfm new file mode 100644 index 0000000..ed11425 --- /dev/null +++ b/modelshell/aboutbox.lfm @@ -0,0 +1,228 @@ +object FmAbout: TFmAbout + Left = 369 + Height = 472 + Top = 134 + Width = 756 + ActiveControl = BtnOK + BorderStyle = bsDialog + ClientHeight = 472 + ClientWidth = 756 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Position = poMainFormCenter + LCLVersion = '0.9.30.2' + object BtnOK: TButton + Left = 345 + Height = 20 + Top = 402 + Width = 60 + Cancel = True + Caption = '&OK' + Default = True + ModalResult = 1 + TabOrder = 0 + end + object Panel3: TPanel + Left = 0 + Height = 385 + Top = 0 + Width = 756 + Align = alTop + ClientHeight = 385 + ClientWidth = 756 + TabOrder = 1 + object Panel1: TPanel + Left = 380 + Height = 383 + Top = 0 + Width = 373 + Align = alRight + ClientHeight = 383 + ClientWidth = 373 + TabOrder = 0 + object LblVersion: TLabel + Left = 61 + Height = 19 + Top = 87 + Width = 89 + Alignment = taCenter + Caption = 'Version 1.0.0' + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object LblModel: TLabel + Left = 61 + Height = 19 + Top = 67 + Width = 55 + Alignment = taCenter + Caption = 'A Model' + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object Label5: TLabel + Left = 106 + Height = 23 + Top = 12 + Width = 121 + Caption = 'Current Model' + Font.Color = clWindowText + Font.Height = -19 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object MoContact: TMemo + Left = 62 + Height = 70 + Top = 119 + Width = 182 + BorderStyle = bsNone + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Arial' + Lines.Strings = ( + 'For more information contact:' + ) + ParentFont = False + ReadOnly = True + TabOrder = 0 + end + object Memo1: TMemo + Left = 0 + Height = 158 + Top = 222 + Width = 371 + Align = alBottom + BorderStyle = bsNone + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Arial' + Lines.Strings = ( + 'Enter any additional information about your model here.' + ) + ParentFont = False + ReadOnly = True + TabOrder = 1 + Visible = False + end + end + object Panel2: TPanel + Left = 0 + Height = 383 + Top = 0 + Width = 373 + Align = alLeft + ClientHeight = 383 + ClientWidth = 373 + TabOrder = 1 + object Label1: TLabel + Left = 61 + Height = 19 + Top = 87 + Width = 89 + Alignment = taCenter + Caption = 'Version 6.5.4' + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object Label2: TLabel + Left = 61 + Height = 19 + Top = 48 + Width = 191 + Alignment = taCenter + Caption = 'Marine Biological Laboratory' + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object Label3: TLabel + Left = 61 + Height = 19 + Top = 67 + Width = 149 + Alignment = taCenter + Caption = 'Modelshell Application' + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object Label4: TLabel + Left = 101 + Height = 23 + Top = 12 + Width = 100 + Caption = 'Model Shell' + Font.Color = clWindowText + Font.Height = -19 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object Memo2: TMemo + Left = 62 + Height = 94 + Top = 119 + Width = 239 + BorderStyle = bsNone + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Arial' + Lines.Strings = ( + 'For more information contact:' + 'Ed Rastetter or Bonnie Kwiatkowski' + 'Ecosystems Center - MBL' + '7 MBL St.' + 'Woods Hole, MA 02543' + ) + ParentFont = False + ReadOnly = True + TabOrder = 0 + end + object Memo3: TMemo + Left = 0 + Height = 158 + Top = 222 + Width = 371 + Align = alBottom + BorderStyle = bsNone + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Arial' + Lines.Strings = ( + 'This material is based upon work supported by the National ' + 'Science Foundation under grants #OPP-9318529 and ' + 'OPP-9732281, and the Environmental Protection Agency ' + 'under grants RFQ-RT-00-00107 and QT-RT-00-001667. Any ' + 'opinions, findings, conclusions, or recommendations expressed ' + 'in the material are those of the author(s) and do not necessarily ' + 'reflect the views of the National Science Foundation or the ' + 'Environmental Protection Agency.' + ) + ParentFont = False + ReadOnly = True + TabOrder = 1 + end + end + end +end diff --git a/modelshell/aboutbox.pas b/modelshell/aboutbox.pas new file mode 100644 index 0000000..6ddca5f --- /dev/null +++ b/modelshell/aboutbox.pas @@ -0,0 +1,46 @@ +{ This form displays a typical About Box. It contains the model name, version + number and contact information. } +unit aboutbox; + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; + +type + + { TFmAbout } + + TFmAbout = class(TForm) + BtnOK: TButton; + Panel3: TPanel; + Panel1: TPanel; + LblVersion: TLabel; + LblModel: TLabel; + MoContact: TMemo; + Memo1: TMemo; + Panel2: TPanel; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Memo2: TMemo; + Memo3: TMemo; + Label4: TLabel; + Label5: TLabel; + private + { Private declarations } + public + { Public declarations } + end; + +var + FmAbout: TFmAbout; + +implementation + +{$R *.lfm} + +{ TFmAbout } + + +end. diff --git a/modelshell/batchmain.lfm b/modelshell/batchmain.lfm new file mode 100644 index 0000000..f925c9d --- /dev/null +++ b/modelshell/batchmain.lfm @@ -0,0 +1,106 @@ +object FmBatchMain: TFmBatchMain + Left = 262 + Height = 294 + Top = 174 + Width = 558 + Caption = 'Modelshell Batch Mode Utility' + ClientHeight = 294 + ClientWidth = 558 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + OnCreate = FormCreate + OnShow = FormShow + LCLVersion = '2.0.6.0' + object LblBatchFile: TLabel + Left = 48 + Height = 13 + Top = 168 + Width = 73 + Caption = '&Batch file name' + FocusControl = EdBatchFile + ParentColor = False + OnClick = LblBatchFileClick + end + object LblNumSpecies: TLabel + Left = 48 + Height = 13 + Top = 232 + Width = 90 + Caption = '&Number of Species' + FocusControl = EdNumSpecies + ParentColor = False + Visible = False + OnClick = LblBatchFileClick + end + object EdBatchFile: TEdit + Left = 48 + Height = 21 + Top = 192 + Width = 361 + OnExit = ChooseBatchFile + TabOrder = 0 + end + object MmDescription: TMemo + Left = 8 + Height = 145 + Top = 8 + Width = 545 + Color = clScrollBar + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'MS Sans Serif' + Lines.Strings = ( + 'This Utility runs modelshell in batch mode. Batch mode allows the user to run multiple simulations without user ' + 'intervention.' + '' + 'Enter the batch file name below, specifing the full path to the file. The batch file is a comma delimited ASCII file. ' + 'The first row of the batch file is used for variable headings and is ignored. The parameter and driver files must be ' + 'located in the same directory as the batch file. The output files will be created in the same directory as the batch ' + 'file. Do not specify the full path names in the batch file. ' + '' + 'CAUTION: Any existing output files in the output directory will be overwritten without warning!' + ) + ParentFont = False + ReadOnly = True + TabOrder = 1 + end + object BtnRunBatch: TButton + Left = 224 + Height = 25 + Top = 248 + Width = 97 + Caption = '&Run Batch Job' + Enabled = False + OnClick = BtnRunBatchClick + TabOrder = 2 + end + object BtnCancelBatch: TButton + Left = 336 + Height = 25 + Top = 248 + Width = 75 + Cancel = True + Caption = '&Close' + OnClick = BtnCancelBatchClick + TabOrder = 3 + end + object EdNumSpecies: TEdit + Left = 48 + Height = 21 + Top = 248 + Width = 41 + OnChange = EdNumSpeciesChange + TabOrder = 4 + Visible = False + end + object DlgOpenBatch: TOpenDialog + Title = 'Choose Batch File' + DefaultExt = '.bch' + Filter = 'Comma Delimited Files|*.csv|Batch File (*.bch)|*.bch|All Files|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist] + left = 496 + top = 176 + end +end diff --git a/modelshell/batchmain.pas b/modelshell/batchmain.pas new file mode 100644 index 0000000..c6646a3 --- /dev/null +++ b/modelshell/batchmain.pas @@ -0,0 +1,698 @@ +unit batchmain; + +interface + +uses + LCLIntf, LCLType, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, fileutil, Lazfileutils, strutils,stypes; + +const + numlayers = 4; + DefaultUnixDirectory = '/user/share/CrEquations'; + BundleResourceDirectory = '/Contents/Resources/'; + +type + + { TFmBatchMain } + + TFmBatchMain = class(TForm) + LblBatchFile: TLabel; + EdBatchFile: TEdit; + MmDescription: TMemo; + BtnRunBatch: TButton; + BtnCancelBatch: TButton; + DlgOpenBatch: TOpenDialog; + EdNumSpecies: TEdit; + LblNumSpecies: TLabel; + procedure LblBatchFileClick(Sender: TObject); + procedure ChooseBatchFile(Sender: TObject); + procedure BtnRunBatchClick(Sender: TObject); + procedure BtnCancelBatchClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure EdNumSpeciesChange(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure CreateNextDriver(ofilename, dfilename: string); + procedure CreateNextDriver4L(ofilename, dfilename: string); + function GetResourcePath(): string; + procedure RunSpinup(pfile, dfile, ofile:string); + private + { Private declarations } + fregrowopt:TRunOptions; + public + { Public declarations } + BatchFilename: string; + Defpath: string; + + end; + +var + FmBatchMain: TFmBatchMain; + +implementation + +{$R *.lfm} + +uses frontend, fileio, Options, calculate, Display; + +procedure TFmBatchMain.LblBatchFileClick(Sender: TObject); +begin + ChooseBatchFile(Sender); + if not (batchfilename = '') then + FmBatchMain.ActiveControl := BtnRunBatch; +end; + +procedure TFmBatchMain.ChooseBatchFile(Sender: TObject); +var + ThisEdit: TEdit; +begin + DlgOpenBatch.InitialDir:=DefPath; +// If the user typed directly in the edit box + if Sender is TEdit then + begin + ThisEdit := Sender as TEdit; + BatchFilename:=ThisEdit.text // Set the batch file + end + else // User clicked on the label + begin // Show the open file dialog + ThisEdit := ((Sender as TLabel).Focuscontrol as TEdit); + // First set the default filename to the current file + DlgOpenBatch.filename := BatchFilename; + // Show the dialog and if the user clicks OK, set the new filename + if DlgOpenBatch.execute then + begin + BatchFilename := DlgOpenBatch.filename; + ThisEdit.text := Batchfilename; + end; + end; + + if (BatchFilename <> '') then + if ((sender as Tcomponent).name <> 'LblBatchFilec') or + ((sender as Tcomponent).name <> 'EdBatchFilec') then + BtnRunBatch.Enabled := True; + DefPath := ExtractFilePath(batchfilename); + LazFileUtils.SetCurrentDirUTF8(ExtractFilePath(batchfilename)); +end; + +procedure TFmBatchMain.BtnRunBatchClick(Sender: TObject); +var + LogFilename, parname, lastsec:string; + temp: double; + RunCrashed:Boolean; + dotpos,Caidx, Tidx, T35Idx, Pptidx: integer; +begin + FmShellMain.RunningInteractive := False; + BtnRunBatch.Enabled := False; + BtnCancelBatch.Enabled := False; + RunCrashed := False; + LogFilename := ChangeFileExt(BatchFilename,'.log'); +// ChangeExtension(LogFilename,'log'); + OpenLogFile(LogFilename, BatchFilename); + OpenBatchFile(BatchFilename); + try + ReadBatchFile(paramfilename,driverfilename,outfilename,time_start,time_stop, + stat,FmOptions.RunOptions); + if (Application.Title = 'sensitivity') and (paramfilename <> 'senstest.par') + then raise Exception.Create('Invalid parameter file for sensitivity test.'); + repeat + try + ReadParamFile(paramfilename, ModelDef.numparam,par, ModelDef.numstate,stat,temp); + + // MEL Multisite Code, create subsequent parameter files and spin up efforts for regrow simulations + parname:=ExtractFileNameOnly(paramfilename); + dotpos:=rpos('.',parname); + lastsec:=copy(parname,dotpos+1,5); + if lastsec='SS' then + begin + // Create climate driver files + //CO2 + Caidx:=FmCalculate.GetArrayIndex(vtParameter, 'FlagCa'); + Tidx:=FmCalculate.GetArrayIndex(vtParameter, 'FlagT'); + T35idx:=FmCalculate.GetArrayIndex(vtParameter,'FlagT35'); + Pptidx:=FmCalculate.GetArrayIndex(vtParameter, 'FlagPpt'); + + par[Tidx].value:=0; + par[T35idx].value:=0; + par[Pptidx].value:=0; + par[Caidx].value:=1; + WriteParamFile(parname+'.Ca.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //T + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=0; + par[Caidx].value:=0; + WriteParamFile(parname+'.T.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //Ppti + par[Pptidx].value:=1; + par[Tidx].value:=0; + par[T35idx].value:=0; + par[Caidx].value:=0; + WriteParamFile(parname+'.Ppti.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //Pptd + par[Pptidx].value:=-1; + par[Tidx].value:=0; + par[T35idx].value:=0; + par[Caidx].value:=0; + WriteParamFile(parname+'.Pptd.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //PptiT + par[Caidx].value:=0; + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=1; + WriteParamFile(parname+'.PptiT.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //PptdT + par[Caidx].value:=0; + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=-1; + WriteParamFile(parname+'.PptdT.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //CaT + par[Caidx].value:=1; + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=0; + WriteParamFile(parname+'.CaT.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //CaPpti + par[Caidx].value:=1; + par[Tidx].value:=0; + par[T35idx].value:=0; + par[Pptidx].value:=1; + WriteParamFile(parname+'.CaPpti.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //CaPptd + par[Caidx].value:=1; + par[Tidx].value:=0; + par[T35idx].value:=0; + par[Pptidx].value:=-1; + WriteParamFile(parname+'.CaPptd.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //Calli + par[Caidx].value:=1; + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=1; + WriteParamFile(parname+'.Calli.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); + + //Calld + par[Caidx].value:=1; + par[Tidx].value:=1; + par[T35idx].value:=1; + par[Pptidx].value:=-1; + WriteParamFile(parname+'.Calld.par',ModelDef.numparam,par,ModelDef.numstate,stat,FmShellMain.Currentresid); +end; + + // Spin up efforts for regrow simulations and save par file for actual regrow run + if AnsiContainsStr(lowercase(parname),'spinup regrow') and stat[1].Reset then + begin + RunSpinup(paramfilename,driverfilename,outfilename); + end + else + begin + FmShellMain.BtnRunClick(Sender); + end; + + WriteLogFile(LogFilename,outfilename,'Run Complete - '+ DateTimeToStr(Now)); + // single layer version + /// CreateNextDriver(outfilename, driverfilename); + // 4 layer version + // CreateNextDriver4L(outfilename, driverfilename); + except + on E: Exception do + begin + WriteLogFile(LogFilename, outfilename, E.Message + ' - ' + + DateTimeToStr(Now)); + if not (Application.Title = 'modelbatch') then RunCrashed := True; + end; + end; + until (ReadBatchFile(paramfilename,driverfilename,outfilename, + time_start,time_stop,stat,FmOptions.RunOptions) = False) or + (RunCrashed); + WriteLogFile(LogFilename,batchfilename,'Batch Job Complete.'); + finally + CloseBatchFile; + CloseLogFile; + BtnRunBatch.Enabled := True; + BtnCancelBatch.Enabled := True; + FmBatchMain.ActiveControl := BtnRunBatch; + if RunCrashed then Abort{raise Exception.Create('Error in batch program')}; + end; +end; + +procedure TFmBatchMain.BtnCancelBatchClick(Sender: TObject); +begin + FmBatchMain.Close; +end; + +procedure TFmBatchMain.FormCreate(Sender: TObject); +begin + SetCurrentDirUTF8(GetResourcePath()); + DefPath:=GetResourcePath(); + FmBatchMain.ActiveControl := EdBatchFile; + with fregrowOpt do + begin + NormalRun:=false; + Time_step:=1; + DiscreteStep:=1; + RepeatDrivers:=true; + RepeatDriveTime:=365; + ResetStates:=true; + ResetStateTime:=365; + RuntoSS:=false; + SSCriteria:=0; + SSTime:=0; + HoldStatesConstant:=false; // Used in fuzzy calibrator + Outputstep:=365; // The timestep specified by the user for output + Outputoffset:=0; // No output for time less than outputoffset + OutputEORonly:=false; // output only if time = stop_time + Time_step + OutputAnnually:=false; + OutputAnnuallyDay:=0; + AppendOutputFile:=false; + stepcounter := 1; + outcounter := 0; + WriteEvery := 0; + ErrorMult := 1; + OutputFile:=false; + end; +end; + +procedure TFmBatchMain.EdNumSpeciesChange(Sender: TObject); +begin + FmShellMain.SetNumSpecies(FmBatchMain.EdNumSpecies); +end; + +procedure TFmBatchMain.FormShow(Sender: TObject); +begin + if not (pos('MEL',ModelDef.modelname) > 0) then + begin + LblNumSpecies.Visible := False; + LblNumSpecies.Enabled := False; + EdNumSpecies.Visible := False; + EdNumSpecies.Enabled := False; + end; +end; + +procedure TFmBatchMain.CreateNextDriver(ofilename, dfilename: string); +var + catchnum, sgrownum, colLnh4d, colLno3d, colLdocd, colLdond, numRnh4u, numRno3u: integer; + numRdonu, numRdocu, numWr, numDrd, numDrc, num, j:integer; + tempstring, tempstring2, filename, basedrivename: string; + Wrfile, Drdfile, Drcfile, Drlfile, oldDrive, newDrive: textfile; + tempdrive: drivearray; + temptime: double; + +function GetColumnNumber(name:string):integer; +var + i,colnum:integer; + tempstring:string; +begin + i := 1; + colnum := 0; + repeat + tempstring := FmDisplayOutput.SgModelOutput.Cells[i,1]; + tempstring := trim(tempstring); + if tempstring = name then colnum := i; + i := i + 1; + until (colnum <> 0) or (i > FmDisplayOutput.SgModelOutput.Colcount - 1); + result := colnum; +end; + +begin + // Set up names and units of drive array + tempdrive := drive; + + // Get catchment number + tempstring := trim(ofilename); + num := pos('cell',tempstring); + delete(tempstring,1,num+3); + catchnum := strtoint(tempstring[1]) + 1; // Add 1 because calculating drivers for NEXT catchment + + // Get base driver filename + basedrivename := dfilename; + num := pos('cell',basedrivename); + delete(basedrivename,num+4,length(basedrivename)); + + // Read in outputfile for this catchment, get column numbers for N fluxes to downslope catchment + // Note that I've assumed that the output file has output at the same time points as the driver!! + // FIX + sgrownum := 3; // 1 row for column numbers, 1 for names and 1 for units, 0 based + colLnh4d := GetColumnNumber('N NH4 loss downslope'); + colLno3d := GetColumnNumber('N NO3 loss downslope'); + colLdocd := GetColumnNumber('C DOC loss downslope'); + colLdond := GetColumnNumber('N DON loss downslope'); + + // Get array index of drivers that will be changed + numWr := FmCalculate.GetArrayIndex(vtdriver, 'Wr'); + numDrd := FmCalculate.GetArrayIndex(vtdriver, 'Drd'); + numDrc := FmCalculate.GetArrayIndex(vtdriver, 'Drc'); + numRnh4u := FmCalculate.GetArrayIndex(vtdriver, 'Rnh4u'); + numRno3u := FmCalculate.GetArrayIndex(vtdriver, 'Rno3u'); + numRdocu := FmCalculate.GetArrayIndex(vtdriver, 'Rdocu'); + numRdonu := FmCalculate.GetArrayIndex(vtdriver, 'Rdonu'); + + if (catchnum > 2) and (catchnum < 7) then + try + // Open Wr file + filename := 'soil mois.xs' + inttostr(catchnum) + '1.dat'; + assignfile(Wrfile, filename); + reset(Wrfile); + + // Open Drd file + if catchnum < 5 then + begin + filename := 'lateral.xq' + inttostr(catchnum) + '1.dat'; + assignfile(Drdfile, filename); + reset(Drdfile); + end; + + // Open Drc file + filename := 'lateral.xqc' + inttostr(catchnum) + '1.dat'; + assignfile(Drcfile, filename); + reset(Drcfile); + + // Open Drl file, in this version the drainage is added to the lateral flow + filename := 'drainage.xg' + inttostr(catchnum) + '1.dat'; + assignfile(Drlfile, filename); + reset(Drlfile); + + // Open original driver file to get Temp, CO2, etc + filename := dfilename; + assignfile(OldDrive, filename); + reset(OldDrive); + + // Create new driver file + filename := basedrivename + inttostr(catchnum) + '.drr'; + assignfile(newDrive, filename); + rewrite(newDrive); + + // Copy names and units from olddriver to the new driver + readln(oldDrive, tempstring); + writeln(NewDrive, tempstring); + readln(oldDrive, tempstring); + writeln(NewDrive, tempstring); + + // Advance all hydrology files to 1 Jan 1999 + for j := 1 to 1029 do + begin + if catchnum < 5 then readln(Drdfile, tempstring); + readln(Drcfile, tempstring); + readln(Drlfile, tempstring); + readln(Wrfile, tempstring); + end; + + while not eof(OldDrive) do + begin + read(oldDrive, temptime); // Read drive time + for j:=1 to ModelDef.numdrive do + read(oldDrive, tempdrive[j].value); // Read drivers + readln(oldDrive); // Advance to next line + + // Replace Wr, Drd and Drc with values for this catchment from hydrology model + readln(Wrfile, tempstring); + tempdrive[numWr].value := strtofloat(tempstring); + if catchnum < 5 then readln(Drdfile, tempstring) else tempstring := '0'; + readln(Drlfile, tempstring2); + tempdrive[numDrd].value := strtofloat(tempstring) + strtofloat(tempstring2); + readln(Drcfile, tempstring); + tempdrive[numDrc].value := strtofloat(tempstring); + + // Replace Rnh4u, Rno3u, Rdocu and Rdonu with values calculated for upslope catchment by MEL + tempdrive[numRnh4u].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLnh4d, sgrownum]); + tempdrive[numRno3u].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLno3d, sgrownum]); + tempdrive[numRdocu].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLdocd, sgrownum]); + tempdrive[numRdonu].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLdond, sgrownum]); + sgrownum := sgrownum + 1; // Increment row for next round + + // Write the drivers to the new driver file + write(NewDrive,format('%-25.13e',[temptime]),' '); // Write drive time + for j := 1 to ModelDef.numdrive do + write(NewDrive,format('%-25.13e',[tempdrive[j].value]),' '); // Write drivers + writeln(NewDrive); // Write return + end; + finally + CloseFile(oldDrive); + CloseFile(newDrive); + if catchnum < 5 then CloseFile(DrdFile); + CloseFile(DrcFile); + CloseFile(DrlFile); + CloseFile(WrFile); + end; +end; + +procedure TFmBatchMain.CreateNextDriver4L(ofilename, dfilename: string); +var + catchnum, sgrownum, num, j, k:integer; + colLnh4d, colLno3d, colLdocd, colLdond, numRnh4u, numRno3u, numRdonu, numRdocu, + numWr, numDrd, numDrc, numDrl: array[1..numlayers] of integer; + tempstring, filename, basedrivename: string; + oldDrive, newDrive: textfile; + Wrfile, Drdfile, Drcfile, Drlfile: array[1..numlayers] of textfile; + tempdrive: drivearray; + temptime: double; + +function GetColumnNumber(name:string):integer; +var + i,colnum:integer; + tempstring:string; +begin + i := 1; + colnum := 0; + repeat + tempstring := FmDisplayOutput.SgModelOutput.Cells[i,1]; + tempstring := trim(tempstring); + if tempstring = name then colnum := i; + i := i + 1; + until (colnum <> 0) or (i > FmDisplayOutput.SgModelOutput.Colcount - 1); + result := colnum; +end; + +begin + // Set up names and units of drive array + tempdrive := drive; + + // Get catchment number + tempstring := trim(ofilename); + num := pos('cell', tempstring); + delete(tempstring, 1, num+3); + catchnum := strtoint(tempstring[1]) + 2; // Add 2 because calculating drivers for every other catchment + // i.e. 1 flows to 3, 2 to 4, etc. + // Get base driver filename + basedrivename := dfilename; + num := pos('cell', basedrivename); + delete(basedrivename, num+4, length(basedrivename)); + + // Read in outputfile for this catchment, get column numbers for N fluxes to downslope catchment + // Note that I've assumed that the output file has output at the same time points as the driver!! + // FIX + sgrownum := 3; // 1 row for column numbers, 1 for names and 1 for units, 0 based + for j := 1 to numlayers do + begin + colLnh4d[j] := GetColumnNumber('*N NH4 loss downslope' + inttostr(j)); + colLno3d[j] := GetColumnNumber('*N NO3 loss downslope' + inttostr(j)); + colLdocd[j] := GetColumnNumber('*C DOC loss downslope' + inttostr(j)); + colLdond[j] := GetColumnNumber('*N DON loss downslope' + inttostr(j)); + + // Get array index of drivers that will be changed + numWr[j] := FmCalculate.GetArrayIndex(vtdriver, 'Wr' + '[' + inttostr(j) + ']'); + numDrd[j] := FmCalculate.GetArrayIndex(vtdriver, 'Drd' + '[' + inttostr(j) + ']'); + numDrc[j] := FmCalculate.GetArrayIndex(vtdriver, 'Drc' + '[' + inttostr(j) + ']'); + numDrl[j] := FmCalculate.GetArrayIndex(vtdriver, 'Drl' + '[' + inttostr(j) + ']'); + numRnh4u[j] := FmCalculate.GetArrayIndex(vtdriver, 'Rnh4u' + '[' + inttostr(j) + ']'); + numRno3u[j] := FmCalculate.GetArrayIndex(vtdriver, 'Rno3u' + '[' + inttostr(j) + ']'); + numRdocu[j] := FmCalculate.GetArrayIndex(vtdriver, 'Rdocu' + '[' + inttostr(j) + ']'); + numRdonu[j] := FmCalculate.GetArrayIndex(vtdriver, 'Rdonu' + '[' + inttostr(j) + ']'); + end; + + if (catchnum > 2) and (catchnum < 7) then + try + for j := 1 to numlayers do + begin + // Open Wr file + filename := 'soil mois.xs' + inttostr(catchnum) + inttostr(j) + '.dat'; + assignfile(Wrfile[j], filename); + reset(Wrfile[j]); + + // Open Drd file + if catchnum < 5 then + begin + filename := 'lateral.xq' + inttostr(catchnum) + inttostr(j) + '.dat'; + assignfile(Drdfile[j], filename); + reset(Drdfile[j]); + end; + + // Open Drc file + filename := 'lateral.xqc' + inttostr(catchnum) + inttostr(j) + '.dat'; + assignfile(Drcfile[j], filename); + reset(Drcfile[j]); + + // Open Drl file + if j <> numlayers then + begin + filename := 'drainage.xg' + inttostr(catchnum) + inttostr(j) + '.dat'; + assignfile(Drlfile[j], filename); + reset(Drlfile[j]); + end; + end; + + // Open original driver file to get Temp, CO2, etc + filename := dfilename; + assignfile(OldDrive, filename); + reset(OldDrive); + + // Create new driver file + filename := basedrivename + inttostr(catchnum) + '.drr'; + assignfile(newDrive, filename); + rewrite(newDrive); + + // Copy names and units from olddriver to the new driver + readln(oldDrive, tempstring); + writeln(NewDrive, tempstring); + readln(oldDrive, tempstring); + writeln(NewDrive, tempstring); + + // Advance all hydrology files to 1 Jan 1999 + for j := 1 to 1029 do + for k := 1 to numlayers do + begin + readln(Wrfile[k], tempstring); + if catchnum < 5 then readln(Drdfile[k], tempstring); + readln(Drcfile[k], tempstring); + if k <> numlayers then readln(Drlfile[k], tempstring); + end; + + while not eof(OldDrive) do + begin + read(oldDrive, temptime); // Read drive time + for j:=1 to ModelDef.numdrive do + read(oldDrive, tempdrive[j].value); // Read drivers + readln(oldDrive); // Advance to next line + + // Replace Wr, Drd, Drc and Drl with values for this catchment from hydrology model + for j := 1 to numlayers do + begin + readln(Wrfile[j], tempstring); + tempdrive[numWr[j]].value := strtofloat(tempstring); + if catchnum < 5 then readln(Drdfile[j], tempstring) else tempstring := '0'; + tempdrive[numDrd[j]].value := strtofloat(tempstring); + if j <> numlayers then readln(Drlfile[j], tempstring) else tempstring := '0'; + tempdrive[numDrl[j]].value := strtofloat(tempstring); + readln(Drcfile[j], tempstring); + tempdrive[numDrc[j]].value := strtofloat(tempstring); + + // Replace Rnh4u, Rno3u, Rdocu and Rdonu with values calculated for upslope catchment by MEL + tempdrive[numRnh4u[j]].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLnh4d[j], sgrownum]); + tempdrive[numRno3u[j]].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLno3d[j], sgrownum]); + tempdrive[numRdocu[j]].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLdocd[j], sgrownum]); + tempdrive[numRdonu[j]].value := + strtofloat(FmDisplayOutput.SgModelOutput.Cells[colLdond[j], sgrownum]); + end; + sgrownum := sgrownum + 1; // Increment row for next round + + // Write the drivers to the new driver file + write(NewDrive,format('%-25.13e',[temptime]),' '); // Write drive time + for j := 1 to ModelDef.numdrive do + write(NewDrive,format('%-25.13e',[tempdrive[j].value]),' '); // Write drivers + writeln(NewDrive); // Write return + end; + finally + CloseFile(oldDrive); + CloseFile(newDrive); + for j := 1 to numlayers do + begin + CloseFile(WrFile[j]); + if catchnum < 5 then CloseFile(DrdFile[j]); + CloseFile(DrcFile[j]); + if j <> numlayers then CloseFile(DrlFile[j]); + end; + end; +end; + +function TFmBatchMain.GetResourcePath(): string; +{$ifdef Darwin} +var + pathRef:CFURLRef; + pathCFStr: CFStringRef; + pathStr: shortstring; +{$endif} +begin +{$ifdef Unix} +{$ifdef Darwin} + pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle()); + pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle); + CFStringGetPascalString(pathCFStr, @pathStr, 255, CFStringGetSystemEncoding()); + CFRelease(pathRef); + CFRelease(pathCFStr); + + Result := pathStr + BundleResourceDirectory; +{$else} + Result := DefaultUnixDirectory; +{$endif} +{$else} // Windows + Result := ExtractFilePath(Application.exeName); +{$endif} +end; + +procedure TFmBatchMain.RunSpinup(pfile, dfile, ofile:string); +var + holdstart, holdstop:double; + holdopt:TRunOptions; +begin + holdstart:=time_start; + holdstop:=time_stop; + holdopt:=FmOptions.RunOptions; + time_start:=1; + time_stop:=7300; + FmOptions.RunOptions:=fregrowOpt; + + FmShellMain.BtnRunClick(FmBatchMain); + + // Turn off resets + stat[FmCalculate.GetArrayIndex(vtState, 'BC')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'BN')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'BP')].reset:=false; + + + stat[FmCalculate.GetArrayIndex(vtState, 'DC')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'DN')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'DP')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'WC')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'WN')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'WP')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'SC')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'SN')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'SP')].reset:=false; + + stat[FmCalculate.GetArrayIndex(vtState, 'ENH4')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'ENO3')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'EPO4')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'Pa')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'Pno')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'Poccl')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'W')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'WSnow')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'fc')].reset:=false; + stat[FmCalculate.GetArrayIndex(vtState, 'SQ')].reset:=false; + + paramfilename:=stringreplace(paramfilename,'spinup regrow','regrow',[rfIgnoreCase,rfReplaceAll]); + + WriteParamFile(paramfilename, ModelDef.numparam,par, ModelDef.numstate,stat,FmShellMain.Currentresid); + + // Set run options back to what was specified in the batch file + time_start:=holdstart; + time_stop:=holdstop; + FmOptions.RunOptions:=holdOpt; +end; + +end. diff --git a/modelshell/calculate.lfm b/modelshell/calculate.lfm new file mode 100644 index 0000000..51a146a --- /dev/null +++ b/modelshell/calculate.lfm @@ -0,0 +1,98 @@ +object FmCalculate: TFmCalculate + Left = 243 + Top = 16 + Caption = 'Calculate Steady State - Enter values for all underlined items' + ClientHeight = 631 + ClientWidth = 732 + Color = clInactiveCaption + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Font.Style = [] + Position = poMainFormCenter + OnCreate = FormSetup + OnShow = FormShow + PixelsPerInch = 96 + object PnTop: TPanel + Left = 0 + Top = 0 + Width = 732 + Height = 63 + Align = alTop + TabOrder = 0 + object BtnShowallProc: TButton + Left = 198 + Top = 16 + Width = 104 + Height = 22 + Caption = 'Show all &processes' + TabOrder = 1 + end + object BtnCancel: TButton + Left = 627 + Top = 16 + Width = 60 + Height = 22 + Cancel = True + Caption = '&Cancel' + ModalResult = 2 + TabOrder = 2 + end + object RgLabelType: TRadioGroup + Left = 0 + Top = 0 + Width = 186 + Height = 50 + Caption = 'Show labels as' + Columns = 2 + ItemIndex = 0 + Items.Strings = ( + '&Names' + '&Symbols' + ) + TabOrder = 0 + end + object BtnOK: TButton + Left = 556 + Top = 16 + Width = 59 + Height = 22 + Caption = '&OK' + ModalResult = 1 + TabOrder = 3 + end + object GbStatus: TGroupBox + Left = 465 + Top = 6 + Width = 45 + Height = 39 + Caption = 'Status' + TabOrder = 4 + object ShStatus: TShape + Left = 9 + Top = 0 + Width = 18 + Height = 18 + Brush.Color = clRed + Shape = stCircle + end + end + object BtnSaveParamFile: TButton + Left = 316 + Top = 16 + Width = 105 + Height = 22 + Caption = 'Save parameter &file' + TabOrder = 5 + end + end + object ScrollBox1: TScrollBox + Left = 0 + Top = 63 + Width = 732 + Height = 568 + Align = alClient + TabOrder = 1 + end +end diff --git a/modelshell/calculate.pas b/modelshell/calculate.pas new file mode 100644 index 0000000..dfe7b5f --- /dev/null +++ b/modelshell/calculate.pas @@ -0,0 +1,108 @@ +unit calculate; + +interface + +uses + Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, MaskEdit, ExtCtrls, stypes; + +type + TFmCalculate = class(TForm) + PnTop: TPanel; + ScrollBox1: TScrollBox; + BtnShowallProc: TButton; + BtnCancel: TButton; + RgLabelType: TRadioGroup; + BtnOK: TButton; + GbStatus: TGroupBox; + ShStatus: TShape; + BtnSaveParamFile: TButton; + procedure FormSetup(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure UpdateForm(Sender: TObject; CalSteadyState:Boolean); + function GetArrayIndex(VarType:TVarType; symbol: string):Integer; + private + { Private declarations } + public + { Public declarations } + end; + +var + FmCalculate: TFmCalculate; + +implementation + +uses frontend, equations, fileio, data; + +{$R *.lfm} + +{ This procedure changes the original generic names of objects on the form to + names that match the real life names of the variables. To do this the + procedure loops over all components in the form looking for labels and + maskedits. For each label or maskedit it determines whether it refers to + a state variable, driver variable, process variable, or parameter. Then it + searches the appropriate array (stat, drive, proc, or par respectively) to + find the array index, the appropriate name and units, and, if a parameter + file and driver file were chosen, the current values. } +procedure TFmCalculate.FormSetup(Sender: TObject); +begin +end; // end FormSetup procedure + +{ This procedure updates all the values on the form before showing it. } +procedure TFmCalculate.FormShow(Sender: TObject); +begin // FormShow procedure + +end; // FormShow procedure + +{ Update the values and the Status button on the form. } +procedure TFmCalculate.UpdateForm(Sender: TObject; CalSteadyState: Boolean); +begin +end; + +{ Function to search the global arrays for a particular variable. Returns the + array index of the specified variable. Returns a zero if the variable was not + found. } +function TFmCalculate.GetArrayIndex(VarType:TVarType; symbol: string):Integer; +var + i, number:integer; +begin + number := 0; + case VarType of + vtParameter: + begin + for i := 1 to ModelDef.numparam do + begin + if symbol = par[i].symbol then number := i; + end; + end; + vtDriver: + begin + for i := 1 to ModelDef.numdrive do + begin + if symbol = drive[i].symbol then number := i; + end; + end; + vtState: + begin + for i := 1 to ModelDef.numstate do + begin + if symbol = stat[i].symbol then number := i; + end; + end; + vtProcess: + begin + for i := ModelDef.numstate to ModelDef.numprocess do + begin + if symbol = proc[i].symbol then number := i; + end; + end; + end; + + if number <> 0 then + GetArrayIndex := number + else + raise Exception.Create('Could not find symbol, ' + symbol + ' in array.'); +end; + +end. + diff --git a/modelshell/create_equations/CrEquations.ico b/modelshell/create_equations/CrEquations.ico new file mode 100644 index 0000000..0341321 Binary files /dev/null and b/modelshell/create_equations/CrEquations.ico differ diff --git a/modelshell/create_equations/CrEquations.lpi b/modelshell/create_equations/CrEquations.lpi new file mode 100644 index 0000000..c5b7157 --- /dev/null +++ b/modelshell/create_equations/CrEquations.lpi @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modelshell/create_equations/CrEquations.lpr b/modelshell/create_equations/CrEquations.lpr new file mode 100644 index 0000000..40b3e2f --- /dev/null +++ b/modelshell/create_equations/CrEquations.lpr @@ -0,0 +1,19 @@ +program CrEquations; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, Crmain, stypes; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TFmMain, FmMain); + Application.Run; +end. + diff --git a/modelshell/create_equations/CrEquations.res b/modelshell/create_equations/CrEquations.res new file mode 100644 index 0000000..f6e8499 Binary files /dev/null and b/modelshell/create_equations/CrEquations.res differ diff --git a/modelshell/create_equations/Model description.txt b/modelshell/create_equations/Model description.txt new file mode 100644 index 0000000..d26f465 --- /dev/null +++ b/modelshell/create_equations/Model description.txt @@ -0,0 +1,49 @@ +Model Definition File - 25 character maximum for all text strings +Model Name= +Model Version= +Model Time Unit= +Model Contact= +Model Contact Address Line 1= +Model Contact Address Line 2= +Model Contact Address Line 3= + +States +Name, Units, Symbol, Num array elements if applicable - Comma separated. + + +End + +Process +Process Name, Units, Symbol, Num of Parameters, Num array elements if applicable +Parameters for each process: Name, Units, Symbol + + + +End + +Drive +Name, Units, Symbol, Num array elements - Comma separated. + + +End + +Other Double Variables +Name, Units, Symbol - Comma separated. +End + +Other Integer Variables +Name, Units, Symbol - Comma separated. +End + +Functions +End Functions + +Equations See the Computer Programming handout for instructions on writing equations in Pascal. Semicolons must end each statement. + + + +End Equations + +Derivatives For array variables use jj as the array index. Same order as State var. + + diff --git a/modelshell/create_equations/crmain.lfm b/modelshell/create_equations/crmain.lfm new file mode 100644 index 0000000..18a2ec8 --- /dev/null +++ b/modelshell/create_equations/crmain.lfm @@ -0,0 +1,101 @@ +object FmMain: TFmMain + Left = 574 + Height = 238 + Top = 461 + Width = 699 + Anchors = [] + Caption = 'Translate text model description to a modelshell equations.pas file' + ClientHeight = 238 + ClientWidth = 699 + Color = clWindow + OnCreate = FormCreate + OnDestroy = FormDestroy + Position = poDefaultPosOnly + LCLVersion = '1.6.4.0' + object MmInstruct: TMemo + Left = 8 + Height = 72 + Top = 8 + Width = 672 + Lines.Strings = ( + 'Select the model description file by clicking on the word "File name" or double clicking in the edit box.' + 'Create Equations will create an equations.pas file and automatically save it in the same folder as the ' + 'model description file. Any existing equations.pas file will automatically be overwritten.' + '' + ) + ParentFont = False + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + TabStop = False + WantReturns = False + end + object LblEdFilename: TLabeledEdit + Left = 64 + Height = 23 + Top = 104 + Width = 600 + EditLabel.AnchorSideTop.Control = LblEdFilename + EditLabel.AnchorSideTop.Side = asrCenter + EditLabel.AnchorSideRight.Control = LblEdFilename + EditLabel.AnchorSideBottom.Control = LblEdFilename + EditLabel.AnchorSideBottom.Side = asrBottom + EditLabel.Left = 10 + EditLabel.Height = 15 + EditLabel.Top = 108 + EditLabel.Width = 51 + EditLabel.Caption = '&File name' + EditLabel.ParentColor = False + EditLabel.OnClick = ChooseDefFile + LabelPosition = lpLeft + TabOrder = 1 + OnDblClick = ChooseDefFile + end + object BtnCreateCode: TButton + Left = 176 + Height = 25 + Top = 143 + Width = 120 + Caption = '&Create code' + OnClick = BtnCreateCodeClick + TabOrder = 2 + end + object BtnClose: TButton + Left = 352 + Height = 25 + Top = 143 + Width = 75 + Caption = 'C&lose' + OnClick = BtnCloseClick + TabOrder = 3 + end + object StatusBar1: TStatusBar + Left = 0 + Height = 23 + Top = 215 + Width = 699 + Panels = <> + end + object HeaderControl1: THeaderControl + Left = 563 + Height = 30 + Top = 291 + Width = 170 + DragReorder = False + Sections = <> + end + object DlgOpenModelDef: TOpenDialog + Title = 'Open model description file' + DefaultExt = '.txt' + Filter = 'Text Files (*.txt)|*.txt|All Files (*.*)|*.*' + Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] + left = 528 + top = 136 + end + object DlgOpenEqPas: TOpenDialog + FileName = 'equationsblank.pas' + Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail] + left = 47 + top = 146 + end +end diff --git a/modelshell/create_equations/crmain.pas b/modelshell/create_equations/crmain.pas new file mode 100644 index 0000000..d630b36 --- /dev/null +++ b/modelshell/create_equations/crmain.pas @@ -0,0 +1,2010 @@ +unit Crmain; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, + {$ifdef Darwin} + MacOSAll, + {$endif} + ExtCtrls, ComCtrls, stypes; + +const + maxArrays = 150; + DefaultUnixDirectory = '/user/share/CrEquations'; + BundleResourceDirectory = '/Contents/Resources/'; + maxParperArray = 20; + +type + TPart = (stBeginning, stEnd); + TVarInfo = record + vType: TVarType; + IsArray: Boolean; + Name: string; + Units: string; + Symbol: string; + numParam: integer; + numRow: integer; + numCol: integer; + end; + + TMatrixInfo = record + VarName: string; + numRow: integer; + Numcol: integer; + NumUniqueParam: integer; + end; + TArrayList = array[1..MaxArrays] of Tmatrixinfo; + + { TFmMain } + + TFmMain = class(TForm) + BtnCreateCode: TButton; + BtnClose: TButton; + HeaderControl1: THeaderControl; + LblEdFilename: TLabeledEdit; + MmInstruct: TMemo; + DlgOpenModelDef: TOpenDialog; + DlgOpenEqPas: TOpenDialog; + StatusBar1: TStatusBar; + procedure ChooseDefFile(Sender: TObject); + procedure BtnCreatecodeClick(Sender: TObject); + procedure BtnCloseClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + function IsDigit(astring:string; index:integer): Boolean; + private + { private declarations } + fModelPath:string; + fResourcePath:string; + FequationsFileName:string; + ftempmodeldef:Tmodeldef; + ftempstate:statearray; + ftempprocess:processarray; + ftempdrive:drivearray; + ftemppar:paramarray; + fnumOtherDouble, numOtherInt, numBoolean:integer; + ftempotherDouble, tempotherInt:paramarray; + ftempBoolean: paramarray; + fModelDefFilename:String; + farrays: TArrayList; + fTotalNumArrays: integer; + fvarlist:Tstringlist; + fModelDef:Tstringlist; + fEquations:Tstringlist; + procedure DefModel; + procedure DefStates; + procedure DefProcess; + procedure DefDrive; + procedure DefOtherVar; + procedure DefBooleanVar; + procedure GetFunctions; + procedure CreateProcessesProc; + function LineSearch(AstringList: Tstringlist; Sstring:string):integer; + function DivideString(fromString, divider:string; WhichPart:TPart):string; + function ParseString(acsvstring: string; vtype: TVarType): TVarInfo; + // procedure ParseString(var tstring, tname, tunits, tsymbol: string; +// var tnpar:integer; var tptype:processtype; var tnrow, tncol: integer); + function ParCount(processnum:integer):integer; + function GetArrayNum(varname:string): integer; + function CheckDerivatives(fline: integer): integer; + function RemoveTrailingComma(lnum: integer): integer; + procedure RemoveFinalDouble; + function RemoveArrayIndex(tstring: string): string; + function GetResourcePath(): string; + public + { public declarations } + end; + +var + FmMain: TFmMain; + +implementation + +{$R *.lfm} + +{ TFmMain } + +{ Select the model description file } +procedure TFmMain.ChooseDefFile(Sender: TObject); +begin + // If the user typed directly in the box + if Sender is TEdit then fModelDefFilename := LblEdFilename.Caption // Set filename + else // The user clicked either the menu or the label + begin // Show the open file dialog + // First set the dialog box default filename to the current file + DlgOpenModelDef.filename := fModelDefFilename; + // If the user chooses OK in the dialog then set the new paramfilename + if DlgOpenModelDef.execute then fModelDefFilename := DlgOpenModelDef.filename; + end; + LblEdFilename.Caption := fModelDefFilename; + fModelPath := ExtractFilePath(fModelDefFilename); + if fModelDefFilename <> '' then BtnCreateCode.Enabled := True; +end; + +procedure TFmMain.BtnCreatecodeClick(Sender: TObject); +var + fs: TFileStream; +begin + fvarlist.Clear; + fModelDef:=Tstringlist.Create; + fEquations:=Tstringlist.Create; + try + if fModelDefFilename <> '' then + begin + try + fs := nil; + BtnCreateCode.Enabled := False; + BtnCreateCode.Caption := 'Running'; { TODO 3 -oBK -icicing : Why does the button caption not change on the Mac? } + if not FileExists(fEquationsFilename) then + repeat + MessageDlg('A required file, equationsblank.pas, is not in the expected ' + + 'location. Please locate the file using the dialog box.', mtError, [mbOK],0); + if DlgOpenEqPas.Execute then fEquationsFilename := DlgOpenEqPas.FileName; + until FileExists(fEquationsFilename); + +// Load the equations.pas file using the TStringList.LoadfromFile procedure because it's a plain text file +// and using the LoadRichText procedure of RichMemo only reads the comments at the beginning of the file. +// MmEquations.Clear; +// MmEquations.Lines.LoadFromFile(fEquationsFilename); + fEquations.LoadFromFile(fEquationsFilename); + +// MmModelDef.Clear; +// fModelDef.LoadFromFile(fModelDefFilename); + fModelDef.LoadFromFile(fModelDefFilename); + + fTotalNumArrays := 1; + DefModel; + DefStates; + DefProcess; + DefDrive; + DefOtherVar; + CreateProcessesProc; +// MmEquations.Lines.SavetoFile(fModelPath + 'equations.pas'); + fEquations.SaveToFile(fModelPath + 'equations.pas'); + BtnCreateCode.Enabled := True; + BtnCreateCode.Caption := '&Create code'; + MessageDlg('Your model is ready to compile. Using Windows Explorer, find ' + + 'and double click on the file modelshell6543.lpi, your model will open ' + + 'inside Lazarus. Click on the green triangle in the menu bar to run ' + + 'your model.', mtInformation, [mbOK], 0) + except + raise; +{ on EStringListError do + if E.Message = 'String list does not allow duplicates' then + MessageDlg('Duplicate variable names. Translation failed. Ensure that state, process and driver ' + + 'variable names differ in the first 25 characters and try again. ', mtError, [mbOK], 0); + if E.Message = 'Index out of bounds' then + Messag } + end; + end + else + MessageDlg('Invalid Model Definition File. Please reenter', + mtWarning, [mbOK], 0); + finally + if assigned(fModelDef) then FreeandNil(fModelDef); + if assigned(fEquations) then FreeandNil(fEquations); + end; +end; + +{ Determines the model name, version, and time unit based on the file read into + the ReModelDef memo component. The Model name, version and time unit are + copied to the RMmEquations memo and to the tempModelDef record. } +procedure TFmMain.DefModel; +var + tempstring:string; + fromLineNum, toLineNum:integer; +begin + fromLineNum := LineSearch(fModelDef,'Model Name'); + ftempmodeldef.modelname :=DivideString(fModelDef[fromLineNum],'=',stEnd); + if length(ftempmodeldef.modelname) > stringlength then + raise Exception.Create('Model name is too long. Decrease model name to 25 characters or less and rerun Create Equations.'); + + tempstring := 'ModelDef.modelname := ''' + ftempmodeldef.modelname + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.modelname :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Version'); + ftempmodeldef.versionnumber := + DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.versionnumber := ''' + ftempmodeldef.versionnumber + + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.versionnumber :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Time Unit'); + ftempmodeldef.timeunit := DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.timeunit := ''' + ftempmodeldef.timeunit + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.timeunit :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Contact'); + ftempmodeldef.contactperson :=DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.contactperson := ''' + ftempmodeldef.contactperson + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.contactperson :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Contact Address Line 1'); + ftempmodeldef.contactaddress1 :=DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.contactaddress1 := ''' + ftempmodeldef.contactaddress1 + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.contactaddress1 :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Contact Address Line 2'); + ftempmodeldef.contactaddress2 :=DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.contactaddress2 := ''' + ftempmodeldef.contactaddress2 + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.contactaddress2 :='); + fEquations[toLineNum] := tempstring; + + fromLineNum := LineSearch(fModelDef,'Model Contact Address Line 3'); + ftempmodeldef.contactaddress3 :=DivideString(fModelDef[fromLineNum],'=',stEnd); + tempstring := 'ModelDef.contactaddress3 := ''' + ftempmodeldef.contactaddress3 + ''';'; + toLineNum := LineSearch(fEquations,'ModelDef.contactaddress3 :='); + fEquations[toLineNum] := tempstring; +end; + +{ Defines the state variables of the model based on the file read into the + fModelDef memo. } +procedure TFmMain.DefStates; +var + i, j, m, fromline, toline:integer; + tempstring: string; + avar: tvarinfo; +// tname, tunits, tsymbol: Tshortstring; +begin +// Define the state variables + fromline := LineSearch(fModelDef, 'States'); + // Advance 1 lines in the memo to get to the line above the state variable listing + fromline := fromline + 2; + tempstring := fModelDef[fromline]; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + i := 1; + while tempstring <> 'End' do + begin + if i > maxstate then + raise Exception.Create('Too many state variables. Increase maxstate in stypes.'); + avar:=ParseString(tempstring,vtstate); + // ParseString(tempstring, tsname, tsunits, tssymbol, tnpar, tptype, tnrow, tncol); + fvarlist.Add(avar.name); + if avar.name[1] <> '*' then // Not an array variable + begin + ftempstate[i].name := avar.Name; + ftempstate[i].units := avar.Units; + ftempstate[i].symbol := avar.Symbol; + i := i + 1; + end + else // An array or matrix variable + begin + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + if avar.numCol = 0 then // An array + begin + for j := 1 to avar.numRow do + begin + ftempstate[i + j - 1].name := avar.Name + inttostr(j); + ftempstate[i + j - 1].units := avar.Units; + ftempstate[i + j - 1].symbol := avar.Symbol + '[' + inttostr(j) + ']'; + end; + i := i + avar.numRow; + end + else // A matrix + begin + for j := 1 to avar.numRow do + for m := 1 to avar.numCol do + begin + ftempstate[i + (j-1)*avar.numCol + m - 1].name := avar.Name + inttostr(j) + '-' + inttostr(m); + ftempstate[i + (j-1)*avar.numCol + m - 1].units := avar.Units; + ftempstate[i + (j-1)*avar.numCol + m - 1].symbol := avar.Symbol + '[' + inttostr(j) + '-' + inttostr(m) + ']'; + end; + i := i + avar.numRow*avar.numCol; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + farrays[fTotalNumArrays].Numcol := avar.numCol; + fTotalNumArrays := fTotalNumArrays + 1; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + ftempmodeldef.numstate := i - 1; // Need ftempmodeldef for the equations + +// Update the fEquations memo + toline := LineSearch(fEquations,'ModelDef.numstate :='); + tempstring := 'ModelDef.numstate := ' + inttostr(ftempmodeldef.numstate) + ';'; + fEquations[toline] := tempstring; + + toline := LineSearch(fEquations,'with stat[1] do'); + for i := 1 to 4 do fEquations.Delete(toline); // Delete the example code + + i := 1; + repeat + fEquations.Insert(toline, ' '); + fEquations.Insert(toline + 1,'with stat[' + inttostr(i) + '] do'); + fEquations.Insert(toline + 2, ' begin'); + tempstring := ' name:=''' + ftempstate[i].name + '''; ' + + 'units:=''' + ftempstate[i].units + '''; ' + + 'symbol:=''' + ftempstate[i].symbol + ''';'; + fEquations.Insert(toline + 3, tempstring); + fEquations.Insert(toline + 4, ' end;'); + toline := toline + 5; + i := i + 1; + until i = ftempmodeldef.numstate + 1; +end; + +{ Defines the processes and parameters of the model based on the file read into + the fModelDef memo. } +procedure TFmMain.DefProcess; +var + iproc, j, k, m, mm, num, fromline, toline, numprevpar, arraynum, + ipcol, iprow, ipar:integer; + tempstring, tempstring2, statename: string; + avar, apar: Tvarinfo; + holdprocess: Tprocessvariable; + holdparam: array[1..maxParperArray] of Tparamvariable; +begin + { The first numstate processes are the derivatives of the state variables. + These processes aren't used in this procedure but are used in the + CreateProcessesProc. } + iproc := 1; + while iproc <= ftempmodeldef.numstate do + //for iproc:= 1 to ftempmodeldef.numstate do + begin + if ftempstate[iproc].name[1] <> '*' then + begin + ftempprocess[iproc].name := 'd' + ftempstate[iproc].name + 'dt'; + ftempprocess[iproc].symbol := 'd' + ftempstate[iproc].symbol + 'dt'; + ftempprocess[iproc].units := ftempstate[iproc].units + ' t-1'; + iproc:=iproc+1; + end + else // An array or matrix + begin + arraynum := GetArrayNum(ftempstate[iproc].name); + statename := farrays[arraynum].VarName; + delete(statename,1,1); // Remove * + if farrays[arraynum].numcol = 0 then // An array + begin + for j := 1 to farrays[arraynum].numrow do + begin + ftempprocess[iproc + j - 1].name := '*d' + statename + 'dt' + inttostr(j); + tempstring := ftempstate[iproc + j -1].symbol; + num := pos('[', tempstring); + tempstring2 := copy(tempstring, num, length(tempstring) - num + 1); + delete(tempstring, num, length(tempstring) - num + 1); + ftempprocess[iproc + j - 1].symbol := 'd' + tempstring + 'dt' + tempstring2; + ftempprocess[iproc + j -1].units := ftempstate[iproc].units + ' t-1'; + end; + iproc := iproc + farrays[arraynum].numrow; + end + else // A matrix + begin + for j := 1 to farrays[arraynum].numrow do + for k := 1 to farrays[arraynum].numcol do + begin + ftempprocess[iproc+(j-1)*farrays[arraynum].Numcol+k-1].name := '*d' + statename + 'dt' + inttostr(j) + '-' + inttostr(k); + tempstring := ftempstate[iproc+(j-1)*farrays[arraynum].Numcol+k-1].symbol; + num := pos('[', tempstring); + tempstring2 := copy(tempstring, num, length(tempstring) - num + 1); + delete(tempstring, num, length(tempstring) - num + 1); + ftempprocess[iproc+(j-1)*farrays[arraynum].Numcol+k-1].symbol := 'd' + tempstring + 'dt' + tempstring2; + ftempprocess[iproc+(j-1)*farrays[arraynum].Numcol+k-1].units := ftempstate[iproc].units + ' t-1'; + end; + iproc := iproc + farrays[arraynum].numrow*farrays[arraynum].numcol; + end; + end; + end; + + // Define the processes + fromline := LineSearch(fModelDef, 'Process'); + // Advance 3 lines in the memo to get from numprocess to the line above the variable listing. + fromline := fromline + 3; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + iproc := ftempmodeldef.numstate + 1; // first process + while tempstring <> 'End' do + begin + if iproc > maxprocess then + raise Exception.Create('Too many processes. Increase maxprocess in stypes.'); + avar:=ParseString(tempstring,vtprocess); + //ParseString(tempstring, tprocname, tprocunits, tprocsymbol, tnpar, tptype, tnrow, tncol); + fvarlist.Add(avar.Name); + if avar.numRow = 0 then // Not an array or matrix variable + begin + ftempprocess[iproc].name := avar.Name; + ftempprocess[iproc].units := avar.Units; + ftempprocess[iproc].symbol := avar.Symbol; + ftempprocess[iproc].parameters := avar.numParam; + numprevpar := ParCount(iproc); + if numprevpar + avar.numParam > maxparam then + raise Exception.Create('Too many parameters. Increase maxparam in stypes.'); + for j := 1 to avar.numParam do + begin + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + apar:=ParseString(tempstring,vtParameter); + // ParseString(tempstring, tparname, tparunits, tparsymbol, num, tptype, num, num); + ftemppar[numprevpar + j].name := apar.Name; + ftemppar[numprevpar + j].units := apar.Units; + ftemppar[numprevpar + j].symbol := apar.Symbol; + end; + iproc := iproc + 1; + end + else // An array or matrix variable + begin + if avar.numCol = 0 then // An array + begin + for k := 1 to avar.numRow do + begin + if k = 1 then + begin + ftempprocess[iproc + k - 1].name := avar.Name; + ftempprocess[iproc + k - 1].units := avar.Units; + ftempprocess[iproc + k - 1].symbol := avar.Symbol; + ftempprocess[iproc + k - 1].parameters := 0; // Actual number of parameters will be calculated in param loop + holdprocess := ftempprocess[iproc + k - 1]; + ftempprocess[iproc + k - 1].name := avar.Name + inttostr(k); + ftempprocess[iproc + k - 1].symbol := avar.Symbol + '[' + inttostr(k) + ']'; + numprevpar := ParCount(iproc + k - 1); + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + farrays[fTotalNumArrays].numCol := avar.numCol; // To make sure it isn't undefined. + farrays[fTotalNumArrays].NumUniqueParam := avar.numParam; + fTotalNumArrays := fTotalNumArrays + 1; + if avar.numParam > maxParperArray then // To change this value, change the variable declaration for holdparam + raise exception.Create('Process, ' + + ftempprocess[iproc + k - 1].name + ', has too many parameters.'); + if numprevpar + avar.numParam*avar.numRow > maxparam then // Fix to account for matrices + raise Exception.Create('Too many parameters. Increase maxparam in stypes.'); + for ipar := 1 to avar.numParam do + begin + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + apar:=ParseString(tempstring,vtParameter); +// ParseString(tempstring, tparname, tparunits, tparsymbol, num, tptype, num, num); + holdparam[ipar].name:=apar.Name; + holdparam[ipar].units:=apar.Units; + holdparam[ipar].symbol:=apar.Symbol; + for iprow:=1 to avar.numRow do + begin + ftemppar[numprevpar+(ipar-1)*avar.numRow+iprow].name := + holdparam[ipar].name + inttostr(iprow); + ftemppar[numprevpar+(ipar-1)*avar.numRow+iprow].units := + holdparam[ipar].units; + ftemppar[numprevpar+(ipar-1)*avar.numRow+iprow].symbol := + holdparam[ipar].symbol + '[' + inttostr(iprow) + ']'; + end; + ftempprocess[iproc].parameters := ftempprocess[iproc].parameters + avar.numRow; + end; + end + else // Not the first process of an array so use saved info instead of reading from file + begin + ftempprocess[iproc + k - 1] := holdprocess; + ftempprocess[iproc + k - 1].name := holdprocess.name + inttostr(k); + ftempprocess[iproc + k - 1].symbol := holdprocess.symbol + '[' + inttostr(k) + ']'; + ftempprocess[iproc + k - 1].parameters := 0; + end; + end; + iproc := iproc + avar.numRow; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + end + else // A matrix + begin + for mm := 1 to avar.numCol do + for k := 1 to avar.numRow do + begin + if (k = 1) and (mm = 1) then // First element of process matrix + begin + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].name := avar.Name; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].units := avar.Units; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].symbol := avar.Symbol; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].parameters := avar.numRow; // Necessary for holdprocess and so that numprevpar gets calculated correctly + holdprocess := ftempprocess[iproc+(k-1)*avar.numCol+mm-1]; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].name := avar.Name + inttostr(k) + '-' + inttostr(mm); + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].symbol := avar.Symbol + '[' + inttostr(k) + '-' + inttostr(mm) + ']'; + numprevpar := ParCount(iproc+(k-1)*avar.numCol+mm-1); + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + farrays[fTotalNumArrays].NumCol := avar.numCol; + farrays[fTotalNumArrays].NumUniqueParam := avar.numParam; + fTotalNumArrays := fTotalNumArrays + 1; // Fix, why mm and not 1??? Changed to 1 because that makes more sense + if avar.numParam > maxParperArray then // To change this value, change the variable declaration for holdparam + raise exception.Create('Process, ' + + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].name + ', has too many parameters.'); + if numprevpar + avar.numParam*avar.numRow*avar.numCol > maxparam then + raise Exception.Create('Too many parameters. Increase maxparam in stypes.'); + ftempprocess[iproc].parameters := 0; + for ipar := 1 to avar.numParam do + begin + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + apar:=ParseString(tempstring,vtParameter); + // ParseString(tempstring, tparname, tparunits, tparsymbol, num, tptype, num, num); + holdparam[ipar].name:=apar.Name; + holdparam[ipar].units:=apar.Units; + holdparam[ipar].symbol:=apar.Symbol; + for iprow:=1 to avar.numRow do + for ipcol:=1 to avar.numCol do + begin + ftemppar[numprevpar+(ipar-1)*avar.numCol*avar.numRow+(iprow-1)*avar.numCol+ipcol].name := + holdparam[ipar].name + inttostr(iprow) + '-' + inttostr(ipcol); + ftemppar[numprevpar+(ipar-1)*avar.numCol*avar.numRow+(iprow-1)*avar.numCol+ipcol].units := + holdparam[ipar].units; + ftemppar[numprevpar+(ipar-1)*avar.numCol*avar.numRow+(iprow-1)*avar.numCol+ipcol].symbol := + holdparam[ipar].symbol + '[' + inttostr(iprow) + '-' + inttostr(ipcol) + ']'; + end; + ftempprocess[iproc].parameters := ftempprocess[iproc].parameters + avar.numRow*avar.numCol; + end; + end + else // Not the first element of a matrix so use saved info instead of reading from file + begin + ftempprocess[iproc+(k-1)*avar.numCol+mm-1] := holdprocess; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].name := holdprocess.name + inttostr(k) + '-' + inttostr(mm); + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].symbol := holdprocess.symbol + '[' + inttostr(k) + '-' +inttostr(mm)+ ']'; + ftempprocess[iproc+(k-1)*avar.numCol+mm-1].parameters := 0; + end; + end; + iproc := iproc + avar.numRow*avar.numCol; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + end; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + ftempmodeldef.numprocess := iproc - 1; + ftempmodeldef.numparam := ParCount(ftempmodeldef.numprocess); + +// Update the fEquations memo + toline := LineSearch(fEquations,'ModelDef.numprocess :='); + tempstring := 'ModelDef.numprocess := ModelDef.numstate + ' + + inttostr(ftempmodeldef.numprocess-ftempmodeldef.numstate) + ';'; + fEquations[toline] := tempstring; + + toline := LineSearch(fEquations,'CurrentProc := ModelDef.numstate'); + for j := 1 to 15 do fEquations.Delete(toline); // Delete example code. + iproc := 1; + repeat + fEquations.Insert(toline, ' '); + fEquations.Insert(toline + 1, 'CurrentProc := ModelDef.numstate + ' + + inttostr(iproc) + ';'); + fEquations.Insert(toline + 2, 'With proc[CurrentProc] do'); + fEquations.Insert(toline + 3, ' begin'); + fEquations.Insert(toline + 4, ' name := ''' + + ftempprocess[ftempmodeldef.numstate + iproc].name + ''';'); + fEquations.Insert(toline + 5, ' units := ''' + + ftempprocess[ftempmodeldef.numstate + iproc].units + ''';'); + fEquations.Insert(toline + 6, ' symbol := ''' + + ftempprocess[ftempmodeldef.numstate + iproc].symbol + ''';'); + fEquations.Insert(toline + 7, ' parameters := ' + + inttostr(ftempprocess[ftempmodeldef.numstate + iproc].parameters) + ';'); + case ftempprocess[ftempmodeldef.numstate + iproc].ptype of + ptGroup1: tempstring := 'ptGroup1'; + ptGroup2: tempstring := 'ptGroup2'; + ptGroup3: tempstring := 'ptGroup3'; + ptGroup4: tempstring := 'ptGroup4'; + ptGroup5: tempstring := 'ptGroup5'; + else + tempstring := 'ptGroup1'; + end; + fEquations.Insert(toline + 8, ' ptype := ' + tempstring + + ';'); + fEquations.Insert(toline + 9, ' end;'); + numprevpar := ParCount(ftempmodeldef.numstate + iproc); + toline := toline + 10; + if ftempprocess[ftempmodeldef.numstate + iproc].parameters > 0 then + begin + fEquations.Insert(toline, 'npar:=ParCount(CurrentProc);'); + for m := 1 to ftempprocess[ftempmodeldef.numstate + iproc].parameters do + begin + fEquations.Insert(toline + 1, 'with par[npar + ' + + inttostr(m) + '] do'); + fEquations.Insert(toline + 2, ' begin'); + tempstring := ' name:=''' + ftemppar[numprevpar + m].name + '''; ' + + 'units:=''' + ftemppar[numprevpar + m].units + '''; ' + + 'symbol:=''' + ftemppar[numprevpar + m].symbol + ''';'; + fEquations.Insert(toline + 3, tempstring); + fEquations.Insert(toline + 4, ' end;'); + toline := toline + 4; + end; + toline := toline + 1; + end; + iproc := iproc + 1; + until iproc = ftempmodeldef.numprocess - ftempmodeldef.numstate + 1; +end; + +{ Defines the driver variables of the model based on the file read into + the fModelDef memo. } +procedure TFmMain.DefDrive; +var + i, j, m, fromline, toline:integer; + tempstring: string; + avar: TvarInfo; +begin +// Define the driver variables + fromline := LineSearch(fModelDef, 'Drive'); + // Advance 2 lines in the memo to get to the line above the driver listing + fromline := fromline + 2; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + i := 1; + while tempstring <> 'End' do + begin + if i > maxdrive then + raise Exception.Create('Too many drivers. Increase maxdrive in stypes.'); + avar:=ParseString(tempstring,vtDriver); + // ParseString(tempstring, tname, tunits, tsymbol, tnpar, tptype, tnrow, tncol); + fvarlist.Add(avar.Name); + if avar.Name[1] <> '*' then // Not an array variable + begin + ftempdrive[i].name := avar.Name; + ftempdrive[i].units := avar.Units; + ftempdrive[i].symbol := avar.Symbol; + i := i + 1; + end + else // An array or matrix variable + begin + if avar.numCol=0 then // Array + begin + for j := 1 to avar.numRow do + begin + ftempdrive[i + j - 1].name := avar.Name + inttostr(j); + ftempdrive[i + j - 1].units := avar.Units; + ftempdrive[i + j - 1].symbol := avar.Symbol + '[' + inttostr(j) + ']'; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + fTotalNumArrays := fTotalNumArrays + 1; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + i := i + avar.numRow; + end + else // Matrix + begin + for j := 1 to avar.numRow do + for m := 1 to avar.numCol do + begin + ftempdrive[i + (j-1)*avar.numCol + m - 1].name := avar.Name + inttostr(j) + '-' + inttostr(m); + ftempdrive[i + (j-1)*avar.numCol + m - 1].units := avar.Units; + ftempdrive[i + (j-1)*avar.numCol + m - 1].symbol := avar.Symbol + '[' + inttostr(j) + '-' + inttostr(m) + ']'; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + farrays[fTotalNumArrays].Numcol:= avar.numCol; + fTotalNumArrays := fTotalNumArrays + 1; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + i := i + avar.numRow*avar.numCol; + end; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + ftempmodeldef.numdrive := i - 1; // Need ftempmodeldef for the equations + +// Update the fEquations memo + toline := LineSearch(fEquations,'ModelDef.numdrive :='); + tempstring := 'ModelDef.numdrive := ' + inttostr(ftempmodeldef.numdrive) + ';'; + fEquations[toline] := tempstring; + + toline := LineSearch(fEquations,'with drive[1] do'); + for i := 1 to 4 do fEquations.Delete(toline); // Delete the example code + + for i := 1 to ftempmodeldef.numdrive do + begin + fEquations.Insert(toline, ' '); + fEquations.Insert(toline + 1, 'with drive[' + inttostr(i) + '] do'); + fEquations.Insert(toline + 2, ' begin'); + tempstring := ' name:=''' + ftempdrive[i].name + '''; ' + + 'units:=''' + ftempdrive[i].units + '''; ' + + 'symbol:=''' + ftempdrive[i].symbol + ''';'; + fEquations.Insert(toline + 3, tempstring); + fEquations.Insert(toline + 4, ' end;'); + toline := toline + 5; + end; +end; + +{ Defines the other variables (non output variables) of the model based on the file read into + the fModelDef memo. } +procedure TFmMain.DefOtherVar; +var + i, j, fromline:integer; + tempstring: string; + avar: TvarInfo; +begin + fromline := LineSearch(fModelDef, 'Other Double Variables'); + // Advance 2 lines in the memo to get to the variable list + fromline := fromline + 2; + tempstring := fModelDef[fromline]; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until (tempstring <> '') or (fromline > fModelDef.Count); + if fromline > fModelDef.Count then + raise Exception.Create('Error - String "Other Double Variables" not found.'); + i := 1; + while tempstring <> 'End' do + begin + avar:=ParseString(tempstring,vtOther); + // ParseString(tempstring, tname, tunits, tsymbol, tnpar, tptype, tnrow, tncol); + if avar.Name[1] <> '*' then // Not an array variable + begin + ftempotherDouble[i].name := avar.Name; + ftempotherDouble[i].units := avar.Units; + ftempotherDouble[i].symbol := avar.Symbol; + i := i + 1; + end + else // An array variable + begin + for j := 1 to avar.numRow do + begin + ftempotherDouble[i + j - 1].name := avar.Name + inttostr(j); + ftempotherDouble[i + j - 1].units := avar.Units; + ftempotherDouble[i + j - 1].symbol := avar.Symbol; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + fTotalNumArrays := fTotalNumArrays + 1; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + i := i + avar.numRow; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + fnumOtherDouble := i - 1; + + fromline := LineSearch(fModelDef, 'Other Integer Variables'); + // Advance 2 lines in the memo to get to the variable list + fromline := fromline + 2; + tempstring := fModelDef[fromline]; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until (tempstring <> '') or (fromline > fModelDef.Count); + if fromline > fModelDef.Count then + raise Exception.Create('Error - String "Other Integer Variables" not found.'); + i := 1; + while tempstring <> 'End' do + begin + avar:=ParseString(tempstring,vtOther); +// ParseString(tempstring, tname, tunits, tsymbol, tnpar, tptype, tnrow, tncol); + if avar.Name[1] <> '*' then // Not an array variable + begin + tempotherInt[i].name := avar.Name; + tempotherInt[i].units := avar.Units; + tempotherInt[i].symbol := avar.Symbol; + i := i + 1; + end + else // An array variable + begin + for j := 1 to avar.numRow do + begin + tempotherInt[i + j - 1].name := avar.Name + inttostr(j); + tempotherInt[i + j - 1].units := avar.Units; + tempotherInt[i + j - 1].symbol := avar.Symbol; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + fTotalNumArrays := fTotalNumArrays + 1; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + i := i + avar.numRow; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + numotherInt := i - 1; +end; + +{ This procedure creates the processes procedure in equations.pas. First it + defines the local variable names using the symbol stored in the arrays. Then + the value in the global arrays is copied into the local variables. And then + the model equations are copied from the fModelDef memo. Finally the values + of the processes are copied from the local variables to the global variables. + } +procedure TFmMain.CreateProcessesProc; +var + toline, fromline1, fromline2, i, j, numprevpar, numemptylines, arraynum, + linecount, lastline, num, posrandom, numtotpar, ipar:integer; + tempstring, tempstring2, astring:string; + WithinCalcDiscrete: Boolean; +begin +// Define the local variable names + + // State variables and their derivatives. + toline := LineSearch(fEquations,'{States}'); + // fEquations.ma + fEquations.Delete(toline + 1); // Delete the example. + i := 1; + linecount := 1; + lastline := toline + linecount; + repeat + if ftempstate[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount, ftempstate[i].symbol + ', ' + + ftempprocess[i].symbol + ', '); + i := i + 1; + lastline := toline + linecount; + end + else // An array variable + begin // Remove comma and set var type to double before adding array. + if (i <> 1) and (ftempstate[i-1].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + // Add declaration for array or matrix variable + arraynum := GetArrayNum(ftempstate[i].name); + tempstring := RemovearrayIndex(ftempstate[i].symbol); + tempstring2 := RemoveArrayIndex(ftempprocess[i].symbol); + if farrays[arraynum].numcol = 0 then // Array + begin + fEquations.Insert(toline + linecount, tempstring + ', ' + + tempstring2 + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of double;'); + i := i + farrays[arraynum].numRow; + lastline := toline + linecount; + end + else // Matrix + begin + fEquations.Insert(toline + linecount, tempstring + ', ' + + tempstring2 + ': array[1..' + inttostr(farrays[arraynum].numRow) + + ',1..' + inttostr(farrays[arraynum].numcol) + '] of double;'); + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + lastline := toline + linecount; + end; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numstate + 1; + + // Processes and parameters. + toline := LineSearch(fEquations,'{processes and associated parameters}'); + fEquations.Delete(toline + 1); // Delete the example. + linecount := 1; + i := 1; + repeat + if ftempprocess[ftempmodeldef.numstate + i].name[1] <> '*' then // Not an array variable + begin + tempstring := ftempprocess[ftempmodeldef.numstate + i].symbol + ', '; + numprevpar := ParCount(ftempmodeldef.numstate + i); + for j := 1 to ftempprocess[ftempmodeldef.numstate + i].parameters do + begin + tempstring := tempstring + ftemppar[numprevpar + j].symbol + ', '; + end; + fEquations.Insert(toline + linecount, tempstring); + i := i + 1; + lastline := toline + linecount; + end + else // An array variable or matrix + begin + // Remove comma and set var type to double before adding array if previous variable was not an array. + if (i = 1) then + begin + RemoveTrailingComma(lastline); + if (ftempstate[ftempmodeldef.numstate].name[1] <> '*') then + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end + else if (ftempprocess[ftempmodeldef.numstate + i - 1].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + // Add declaration for array variable + arraynum := GetArrayNum(ftempprocess[ftempmodeldef.numstate + i].name); + tempstring := RemoveArrayIndex(ftempprocess[ftempmodeldef.numstate + i].symbol) + ', '; + numprevpar := ParCount(ftempmodeldef.numstate + i); + j := 1; + if farrays[arraynum].Numcol = 0 then + numtotpar := farrays[arraynum].NumUniqueParam*farrays[arraynum].numRow + else + numtotpar := farrays[arraynum].NumUniqueParam*farrays[arraynum].numRow*farrays[arraynum].Numcol; + while j <= numtotpar do + begin + tempstring := tempstring + RemoveArrayIndex(ftemppar[numprevpar+j].symbol) + ', '; + if farrays[arraynum].numcol = 0 then + j := j + farrays[arraynum].numrow + else + j := j + farrays[arraynum].numrow*farrays[arraynum].numcol; + end; + tempstring := trim(tempstring); + j := length(tempstring); // fix, use removetrailingcomma? won't work + if tempstring[j] = ',' then delete(tempstring,j,1); + if farrays[arraynum].numcol = 0 then // An array + begin + tempstring := tempstring + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of double;'; + i := i + farrays[arraynum].numRow; + end + else // A matrix + begin + tempstring := tempstring + ': array[1..' + + inttostr(farrays[arraynum].numrow) + ',1..' + + inttostr(farrays[arraynum].numcol) + '] of double;'; + i := i + farrays[arraynum].numrow*farrays[arraynum].numcol; + end; + fEquations.Insert(toline + linecount, tempstring); + lastline := toline + linecount; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numprocess - ftempmodeldef.numstate + 1; + + // Remove the comma after the last variable if there are no other variables. + if (ftempmodeldef.numdrive = 0) and (fnumOtherDouble = 0) then + RemoveTrailingComma(lastline); + + // Driver variables. + toline := LineSearch(fEquations,'{drivers}'); + fEquations.Delete(toline + 1); // Delete the example. + linecount := 1; + i := 1; + while i < ftempmodeldef.numdrive + 1 do + begin + if ftempdrive[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount, ftempdrive[i].symbol + ', '); + i := i + 1; + lastline := toline + linecount; + end + else // An array or matrix variable + begin + // Remove comma and set var type to double before adding array if previous variable was not an array. + if (i = 1) and (ftempprocess[ftempmodeldef.numprocess].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end + else if (i > 1) and (ftempdrive[i-1].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + // Add declaration for array or matrix variable + arraynum := GetArrayNum(ftempdrive[i].name); + tempstring := ftempdrive[i].symbol; + num := pos('[', tempstring); + delete(tempstring, num, length(tempstring) - num + 1); + if farrays[arraynum].Numcol=0 then + begin // Array + fEquations.Insert(toline + linecount, + tempstring + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of double;'); + i := i + farrays[arraynum].numRow; + end + else + begin // Marix + fEquations.Insert(toline + linecount, + tempstring + ': array[1..' + inttostr(farrays[arraynum].numRow) + + ',1..' + inttostr(farrays[arraynum].numcol) + '] of double;'); + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + end; + lastline := toline + linecount; + end; + linecount := linecount + 1; + end; + +// Other variables Doubles + toline := LineSearch(fEquations,'{Other double}'); + fEquations.Delete(toline + 1); // Delete the example. + linecount := 1; + i := 1; + if fnumOtherDouble = 0 then // Clean up because there are no other variables + begin + if ftempdrive[ftempmodeldef.numdrive].name[1] <> '*' then + RemoveTrailingComma(lastline) + else + RemoveFinalDouble; + end + else // There are other variables + begin + repeat + if ftempotherDouble[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount, ftempotherDouble[i].symbol + ', '); + i := i + 1; + lastline := toline + linecount; + if i = fnumOtherDouble + 1 then RemoveTrailingComma(lastline); + end + else // An array variable + begin // Remove comma and set var type to double before adding array if necessary + if i = 1 then + begin + if (ftempmodeldef.numdrive > 0) and (ftempdrive[ftempmodeldef.numdrive].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + if (ftempmodeldef.numdrive = 0) and (ftempprocess[ftempmodeldef.numprocess].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + end + else + begin + if ftempotherDouble[i-1].name[1] <> '*' then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :double;'; + end; + end; + // Add declaration for array variable + arraynum := GetArrayNum(ftempotherDouble[i].name); + fEquations.Insert(toline + linecount, + ftempotherDouble[i].symbol + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of double;'); + i := i + farrays[arraynum].numRow; + lastline := toline + linecount; + if (i = fnumOtherDouble + 1) then RemoveFinalDouble; + end; + linecount := linecount + 1; + until i = fnumOtherDouble + 1; + end; + +// Other variables integer + toline := LineSearch(fEquations,'{Other integers}'); + linecount := 1; + i := 1; + if numOtherInt <> 0 then // There are other variables + begin + repeat + if tempotherInt[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount, tempotherInt[i].symbol + ', '); + i := i + 1; + lastline := toline + linecount; + if i = numOtherInt + 1 then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ': integer;'; + end; + end + else // An array variable + begin + if i>1 then // Clean up comma and add :integer if previous other int existed + if tempOtherInt[i-1].name[1] <> '*' then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ': integer;'; + end; + // Add declaration for array variable + arraynum := GetArrayNum(tempotherInt[i].name); + fEquations.Insert(toline + linecount, + tempotherInt[i].symbol + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of integer;'); + i := i + farrays[arraynum].numRow; + lastline := toline + linecount; + end; + linecount := linecount + 1; + until i = numOtherInt + 1; + end; + +// Boolean variables + if numBoolean <> 0 then + begin + toline := LineSearch(fEquations,'{ Boolean Variables }'); + linecount := 1; + i := 1; + repeat + if ftempBoolean[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount, ftempBoolean[i].symbol + ', '); + i := i + 1; + lastline := toline + linecount; + if i = numBoolean + 1 then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ': Boolean;'; + end; + end + else // An array variable + begin + if (i>1) and (ftempBoolean[i-1].name[1] <> '*') then + begin + RemoveTrailingComma(lastline); + fEquations[lastline] := fEquations[lastline] + ' :Boolean;'; + end; + // Add declaration for array variable + arraynum := GetArrayNum(ftempBoolean[i].name); + fEquations.Insert(toline + linecount, + ftempBoolean[i].symbol + ': array[1..' + + inttostr(farrays[arraynum].numRow) + '] of Boolean;'); + i := i + farrays[arraynum].numRow; + lastline := toline + linecount; + if (i = numBoolean + 1) then RemoveFinalDouble; + end; + linecount := linecount + 1; + until i = numBoolean + 1; + end; + + // Copy any user defined functions into the processes procedure + GetFunctions; + +// Copy values from the global farrays to the local variables. + // Drivers + toline := LineSearch(fEquations,'{ Copy the drivers from the global array,'); + fEquations.Delete(toline + 1); // Delete the example. + linecount := 1; + i := 1; + while i < ftempmodeldef.numdrive + 1 do + begin + if ftempdrive[i].name[1] <> '*' then // Not an array + begin + fEquations.Insert(toline + linecount, ftempdrive[i].symbol + + ' := ' + 'tdrive[' + inttostr(i) + '].value;'); + i := i + 1; + end + else // An array or matrix variable + begin + arraynum := GetArrayNum(ftempdrive[i].name); + tempstring2 := ftempdrive[i].symbol; + num := pos('[', tempstring2); + delete(tempstring2, num, length(tempstring2) - num + 1); + if farrays[arraynum].numcol = 0 then + begin // Array + tempstring := 'for jj := 1 to ' + inttostr(farrays[arraynum].numRow) + + ' do ' + tempstring2 + '[jj] := tdrive[' + inttostr(i) + + ' + jj - 1].value;'; + fEquations.Insert(toline + linecount, tempstring); + i := i + farrays[arraynum].numRow; + end + else // Matrix + begin + tempstring := 'for jj := 1 to ' + inttostr(farrays[arraynum].numRow) + + ' do for kk := 1 to ' + inttostr(farrays[arraynum].numcol) + ' do ' + + tempstring2 + '[jj,kk] := tdrive[' + inttostr(i) + + ' + (jj-1)*' + inttostr(farrays[arraynum].numcol) + ' + kk - 1].value;'; + fEquations.Insert(toline + linecount, tempstring); + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + end; + end; + linecount := linecount + 1; + end; + + // State Variables + toline := LineSearch(fEquations, '{ Copy the state variables from the global array'); + fEquations.Delete(toline + 1); // Delete the example. + linecount := 1; + i := 1; + repeat + if ftempstate[i].name[1] <> '*' then // Not an array + begin + fEquations.Insert(toline + linecount, ftempstate[i].symbol + + ' := ' + 'tstat[' + inttostr(i) + '].value;'); + i := i + 1; + end + else // An array or matrix variable + begin + arraynum := GetArrayNum(ftempstate[i].name); + if farrays[arraynum].Numcol = 0 then // Array + begin + tempstring := 'for jj := 1 to ' + inttostr(farrays[arraynum].numRow) + + ' do ' + RemoveArrayIndex(ftempstate[i].symbol) + + '[jj] := tstat[' + inttostr(i-1) + + ' + jj].value;'; + fEquations.Insert(toline + linecount, tempstring); + i := i + farrays[arraynum].numRow; + end + else + begin // Matrix + tempstring := 'for jj := 1 to ' + inttostr(farrays[arraynum].numRow) + + ' do for kk := 1 to ' + inttostr(farrays[arraynum].numcol) + + ' do ' + RemoveArrayIndex(ftempstate[i].symbol) + + '[jj,kk] := tstat[' + inttostr(i) + + ' + (jj-1)*' + inttostr(farrays[arraynum].numcol) + '+kk-1].value;'; + fEquations.Insert(toline + linecount, tempstring); + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + end; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numstate + 1; + + // Parameters + toline := LineSearch(fEquations, ' copy the value of the first parameter'); + toline := toline + 2; + for i := 1 to 2 do fEquations.Delete(toline); // Delete the example. + i := ftempmodeldef.numstate + 1; + repeat + if ftempprocess[i].parameters > 0 then + begin + fEquations.Insert(toline, + 'npar:=ParCount(ModelDef.numstate + ' + + inttostr(i-ftempmodeldef.numstate) + ');'); + toline := toline + 1; + if ftempprocess[i].name[1] <> '*' then // Not an array variable + begin + numprevpar := ParCount(i); + for j := 1 to ftempprocess[i].parameters do + begin + begin + fEquations.Insert(toline, + ftemppar[numprevpar + j].symbol + ' := par[npar + ' + + inttostr(j) + '].value;'); + toline := toline + 1; + end; + end; + fEquations.Insert(toline + 1, ' '); + toline := toline + 1; + i := i + 1; + end + else // An array or matrix variable + begin + numprevpar := ParCount(i); + arraynum := GetArrayNum(ftempprocess[i].name); + if farrays[arraynum].numcol = 0 then // An array + begin + ipar := 0; + repeat + ipar:=ipar+1; + tempstring := 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do ' + + RemoveArrayIndex(ftemppar[numprevpar + farrays[arraynum].numRow*(ipar-1) + 1].symbol) + + '[jj] := par[npar + ' + + inttostr(farrays[arraynum].numRow) + '*' + inttostr(ipar-1) + ' + jj].value;'; + fEquations.Insert(toline, tempstring); + toline := toline + 1; + until ipar >= farrays[arraynum].NumUniqueParam; + fEquations.Insert(toline + 1, ' '); + toline := toline + 1; + i := i + farrays[arraynum].numRow; + end + else // A matrix + begin + ipar := 0; + repeat + ipar:=ipar+1; + tempstring := 'for jj := 1 to ' + inttostr(farrays[arraynum].numRow) + + ' do for kk := 1 to ' + inttostr(farrays[arraynum].numCol) + ' do ' + + RemoveArrayIndex(ftemppar[numprevpar + farrays[arraynum].numcol*farrays[arraynum].numRow*(ipar-1) + 1].symbol) + + '[jj, kk] := par[npar + ' + inttostr(farrays[arraynum].Numcol) + '*' + + inttostr(farrays[arraynum].numRow) + '*' + inttostr(ipar-1) + ' + (jj-1)*' + + inttostr(farrays[arraynum].numcol) + ' + kk].value;'; + fEquations.Insert(toline, tempstring); + toline := toline + 1; + until ipar >= farrays[arraynum].NumUniqueParam; + fEquations.Insert(toline + 1, ' '); + toline := toline + 1; + i := i + farrays[arraynum].numRow*farrays[arraynum].Numcol; + end; + end; + end + else + i := i + 1; + until i = ftempmodeldef.numprocess + 1; + +// Set all processes to -999 to catch undefined processes + for i:=1 to ftempmodeldef.numprocess do + begin + tempstring := ftempprocess[i].symbol; + tempstring := StringReplace(tempstring, '-', ',',[]); // Converts dashes in matrix notation to comma. + tempstring := tempstring + ' := -999;'; // This needs to be done after the replace so that the minus doesn't get replaced with a comma. + fEquations.Insert(toline, tempstring); + toline := toline+1; + end; + + // Enter the equations. + toline := LineSearch(fEquations, + '{ Enter the equations to calculate the processes here,'); + toline := toline + 2; + fEquations.Delete(toline); // Delete the example equation. + fromline1 := LineSearch(fModelDef, 'Equations'); + fromline2 := LineSearch(fModelDef, 'End Equations'); + +// Check for use of random function + i := fromline1+1; + WithinCalcDiscrete := False; + repeat + astring := fModelDef[i]; + if WithinCalcDiscrete = False then + if pos('CalculateDiscrete', astring) <> 0 then WithinCalcDiscrete := True; + posrandom := pos('random', astring); + if (posrandom <> 0) and (not WithinCalcDiscrete) then + raise Exception.Create('Random function can only be used within the CalculateDiscrete section.'); + i := i + 1; + until i = fromline2; + + numemptylines := 0; + i := 1; + repeat + tempstring := fModelDef[fromline1 + numemptylines + i]; + if tempstring <> 'End Equations' then + fEquations.Insert(toline + i, + fModelDef[fromline1 + numemptylines + i]); + i := i + 1; + until i + numemptylines >= fromline2 - fromline1; + +// Equations to calculate the derivatives + toline := LineSearch(fEquations, 'if tstat[1].HoldConstant'); + fromline1 := LineSearch(fModelDef, 'Derivatives'); + + CheckDerivatives(fromline1); + // Delete the example code + for i := 0 to 3 do fEquations.Delete(toline); + + // Write the derivatives + numemptylines := 0; + linecount := 1; + i := 1; + repeat + repeat + tempstring := fModelDef[fromline1 + numemptylines + linecount]; + tempstring := trim(tempstring); + linecount := linecount + 1; + until tempstring <> ''; + if ftempstate[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline, 'if (tstat[' + inttostr(i) + + '].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then'); + fEquations.Insert(toline + 1, ' ' + ftempprocess[i].symbol + + ' := 0'); + fEquations.Insert(toline + 2, 'else'); + fEquations.Insert(toline + 3, ' ' + + fModelDef[fromline1 + numemptylines + linecount - 1]); + fEquations.Insert(toline + 4, ' '); + toline := toline + 5; + i := i + 1; + end + else // An array or matrix variable + begin + arraynum := GetArrayNum(ftempstate[i].name); + tempstring2 := ftempprocess[i].symbol; + num := pos('[', tempstring2); + delete(tempstring2, num, length(tempstring2) - num + 1); + if farrays[arraynum].numcol = 0 then // Array + begin + fEquations.Insert(toline, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do'); + fEquations.Insert(toline + 1, 'begin'); + fEquations.Insert(toline + 2, ' if (tstat[' + inttostr(i - 1) + + ' + jj].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then'); + fEquations.Insert(toline + 3, ' ' + tempstring2 + + '[jj] := 0'); + fEquations.Insert(toline + 4, ' else'); + fEquations.Insert(toline + 5, ' ' + + fModelDef[fromline1 + numemptylines + linecount - 1]); + fEquations.Insert(toline + 6, 'end;'); + fEquations.Insert(toline + 7, ' '); + toline := toline + 8; + i := i + farrays[arraynum].numRow; + end + else // Matrix + begin + fEquations.Insert(toline, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do for kk:=1 to ' + + inttostr(farrays[arraynum].numcol) + ' do'); + fEquations.Insert(toline + 1, 'begin'); + fEquations.Insert(toline + 2, ' if (tstat[' + inttostr(i) + + ' + (jj-1)*' + inttostr(farrays[arraynum].Numcol) + + '+kk-1].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then'); + fEquations.Insert(toline + 3, ' ' + tempstring2 + + '[jj,kk] := 0'); + fEquations.Insert(toline + 4, ' else'); + fEquations.Insert(toline + 5, ' ' + + fModelDef[fromline1 + numemptylines + linecount - 1]); + fEquations.Insert(toline + 6, 'end;'); + fEquations.Insert(toline + 7, ' '); + toline := toline + 8; + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + + end; + end; + until i = ftempmodeldef.numstate + 1; + +// Copy the new values from the local variables back into the global farrays. + // State variables + toline := LineSearch(fEquations, 'tstat[1].value := '); + fEquations.Delete(toline); // Delete the example. + + i := 1; + linecount := 1; + repeat + if ftempstate[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount - 1, 'tstat[' + inttostr(i) + + '].value := ' + ftempstate[i].symbol + ';'); + i := i + 1; + end + else // An array or matrix variable + begin + arraynum := GetArrayNum(ftempstate[i].name); + tempstring2 := ftempstate[i].symbol; + num := pos('[', tempstring2); + delete(tempstring2, num, length(tempstring2) - num + 1); + if farrays[arraynum].numcol=0 then // Array + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do tstat[' + inttostr(i-1) + + ' + jj].value := ' + tempstring2 + '[jj];'); + i := i + farrays[arraynum].numRow; + end + else // Matrix + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do for kk := 1 to ' + + inttostr(farrays[arraynum].numcol) + ' do tstat[' + inttostr(i) + + ' + (jj-1)*' + inttostr(farrays[arraynum].Numcol) + '+kk-1].value := ' + tempstring2 + '[jj,kk];'); + i := i + farrays[arraynum].numRow*farrays[arraynum].Numcol; + end; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numstate + 1; + + // State variable derivatives + toline := LineSearch(fEquations, 'tproc[1].value := '); + fEquations.Delete(toline); // Delete the example. + + i := 1; + linecount := 1; + repeat + if ftempstate[i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount - 1, 'tproc[' + inttostr(i) + + '].value := ' + ftempprocess[i].symbol + ';'); + i := i + 1; + end + else // An array or matrix variable + begin + arraynum := GetArrayNum(ftempstate[i].name); + tempstring2 := ftempprocess[i].symbol; + num := pos('[', tempstring2); + delete(tempstring2, num, length(tempstring2) - num + 1); + if farrays[arraynum].numcol=0 then // Array + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do tproc[' + inttostr(i-1) + + ' + jj].value := ' + tempstring2 + '[jj];'); + i := i + farrays[arraynum].numRow; + end + else // Matrix + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do for kk := 1 to ' + + inttostr(farrays[arraynum].numcol) + ' do tproc[' + inttostr(i) + + ' + (jj-1)*' + inttostr(farrays[arraynum].Numcol) + '+kk-1].value := ' + tempstring2 + '[jj,kk];'); + i := i + farrays[arraynum].numRow*farrays[arraynum].Numcol; + end; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numstate + 1; + + // Processes + toline := LineSearch(fEquations, 'tproc[ModelDef.numstate + 1].value :='); + fEquations.Delete(toline); // Delete the example. + + i := 1; + linecount := 1; + repeat + if ftempprocess[ftempmodeldef.numstate + i].name[1] <> '*' then // Not an array variable + begin + fEquations.Insert(toline + linecount - 1, 'tproc[ModelDef.numstate + ' + + inttostr(i) + '].value := ' + + ftempprocess[ftempmodeldef.numstate + i].symbol + ';'); + i := i + 1; + end + else + begin + arraynum := GetArrayNum(ftempprocess[ftempmodeldef.numstate + i].name); + if farrays[arraynum].numcol = 0 then // An array + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numRow) + ' do tproc[ModelDef.numstate + ' + + inttostr(i - 1) + ' + jj].value := ' + + RemoveArrayIndex(ftempprocess[ftempmodeldef.numstate + i].symbol) + '[jj];'); + i := i + farrays[arraynum].numRow; + end + else // A matrix not an array + begin + fEquations.Insert(toline + linecount - 1, 'for jj := 1 to ' + + inttostr(farrays[arraynum].numrow{numcol}) + ' do for kk := 1 to ' + + inttostr(farrays[arraynum].numcol{numrow}) + ' do tproc[ModelDef.numstate + ' + + inttostr(i - 1) + ' + (jj{kk}-1)*' + inttostr(farrays[arraynum].numcol) + ' + kk{jj}].value := ' + + RemoveArrayIndex(ftempprocess[ftempmodeldef.numstate + i].symbol) + '[jj,kk];'); + i := i + farrays[arraynum].numRow*farrays[arraynum].numcol; + end; + end; + linecount := linecount + 1; + until i = ftempmodeldef.numprocess - ftempmodeldef.numstate + 1; +end; + + +{ Searches tempmemo for the string Sstring and returns the line number + containing Sstring. } +function TFmMain.Linesearch(AstringList: Tstringlist; Sstring:string):integer; +var + i,temp:integer; +begin + i := 0; + temp := 0; + while (i < AstringList.count - 1) and (temp = 0) do + begin + temp := pos(Sstring,AstringList[i]); + i := i + 1; + end; + linesearch := i - 1; +end; + +{ Divides the string, fromString, into two parts at the string, divider. Returns + either the beginning or the end of the string based on the value of WhichPart. + The string divider is not included in either part. } +function TFmMain.DivideString(fromString, divider:string; + WhichPart:TPart):string; +var + whereDivide, slength: integer; +begin + whereDivide := pos(divider, fromString); + slength := length(fromString); + if WhichPart = stBeginning then + begin + delete(fromString,whereDivide,slength-whereDivide+1); + fromString := trim(fromString); + end + else + begin + delete(fromString,1,whereDivide); + fromString := trim(fromString); + end; + DivideString := fromString; +end; + +{ Separates tstring into the name, units, symbol, and npar using a comma as delimiter. } +function TFmMain.ParseString(acsvstring: string; vtype: TVarType): TVarInfo; +var + tempstring: Tstringlist; + newmVar: TVarInfo; +begin +newmVar.vType:=vtype; +tempstring:=Tstringlist.create; +try + tempstring.Delimiter:=','; + tempstring.StrictDelimiter:=true; + tempstring.DelimitedText:=acsvstring; + + newmVar.Name:=trim(tempstring[0]); + newmVar.Units:=trim(tempstring[1]); + newmVar.Symbol:=trim(tempstring[2]); + +// Check for unflagged array/matrix variables + if (vtype<>vtprocess) and (tempstring.Count>3) and (newmVar.Name[1]<>'*') then + raise Exception.Create('Inconsistent variable description. Variable, '+ newmVar.Name + + ', is listed as an array or matrix but does not begin with *') + else if (tempstring.count>4) and (newmVar.Name[1]<>'*') then + raise Exception.Create('Inconsistent variable description. Variable, '+ newmVar.Name + + ', is listed as an array or matrix but does not begin with *'); + +// Array variable? + if newmVar.Name[1]='*' then + newmVar.IsArray:=true + else + newmVar.IsArray:=false; + + if vtype<>vtprocess then // Not a process variable + begin + if not newmVar.IsArray then + begin + newmVar.numParam:=0; + newmVar.numRow:=0; + newmVar.numCol:=0; + end + else // An array + begin + newmVar.numParam:=0; + if tempstring.Count<4 then // Missing array specification + raise Exception.Create('Missing number of array elements for variable '+ newmVar.Name + '.') + else + begin + newmVar.numRow:=strtoint(tempstring[3]); + if tempstring.Count=5 then + newmVar.numCol:=strtoint(tempstring[4]) + else + newmVar.numCol:=0; + end; + end; + end + else // A process + begin + newmVar.numParam:=strtoint(tempstring[3]); + if tempstring.Count>4 then // An array or matrix + begin + newmVar.numRow:=strtoint(tempstring[4]); + if tempstring.Count=6 then + newmVar.numCol:=strtoint(tempstring[5]) + else + newmVar.numCol:=0; + end + else + begin + newmVar.numRow:=0; + newmVar.numCol:=0; + end; + end; + + ParseString:=newmVar; +finally + if assigned(tempstring) then FreeandNil(tempstring); +end; +end; + +{procedure TFmMain.ParseString(var acsvstring, vname, vunits, vsymbol: string; + var npar:integer; var nrow, ncol: integer); +var + num, num2:integer; + tstring2:string; +begin + // Initialize variables that don't always get assigned so that that they are always defined on return + tnpar := 0; + tptype := ptGroup1; + tnrow := 0; + tncol := 0; + + num := pos(',',tstring); // Name + tname := DivideString(tstring, ',', stBeginning); + delete(tstring, 1, num); + + num := pos(',',tstring); // Units + tunits := DivideString(tstring, ',', stBeginning); + delete(tstring, 1, num); + + num := pos(',', tstring); // Symbol + tsymbol := DivideString(tstring, ',', stBeginning); + + if num <> 0 then // An array or matrix variable, a process, or both. + begin + delete(tstring, 1, num); + + // Check for the word 'group' to determine if this is a process or not + num2 := pos('group',lowercase(tstring)); + if num2 = 0 then // Not a process but an array or matrix variable + begin + num := pos(',',tstring); + if num = 0 then + begin + tnrow := strtoint(DivideString(tstring, ',', stBeginning)); + end + else + begin + tnrow := strtoint(DivideString(tstring, ',', stBeginning)); + delete(tstring, 1, num); + tncol := strtoint(DivideString(tstring, ',', stBeginning)); + end; + end + else + begin + num := pos(',',tstring); + tnpar := strtoint(DivideString(tstring, ',', stBeginning)); + delete(tstring, 1, num); + + tstring2 := DivideString(tstring, ',', stBeginning); + num2 := length('Group'); + delete(tstring2, 1, num2); + try + num2 := strtoint(tstring2); + case num2 of + 1: tptype := ptGroup1; + 2: tptype := ptGroup2; + 3: tptype := ptGroup3; + 4: tptype := ptGroup4; + 5: tptype := ptGroup5; + else + tptype := ptGroup1; + end; + except on E: Exception do + tptype := ptGroup1; + end; + num := pos(',',tstring); + if num = 0 then delete(tstring,pos('group',lowercase(tstring)),8) + else delete(tstring,1,num); + + num := pos(',', tstring); + if (num <> 0) then // A process array or matrix + begin + tnrow := strtoint(DivideString(tstring, ',', stBeginning)); + delete(tstring, 1, num); + + num := length(trim(tstring)); + if num <> 0 then tncol := strtoint(tstring); + end + else if (length(trim(tstring)) <> 0) then + begin + tnrow := strtoint(tstring); + end; + end; + end; +end; } + +{This function counts the parameters in all processes less than processnum.} +function TFmMain.ParCount(processnum:integer):integer; +var + NumberofParams, counter : integer; +begin + NumberofParams := 0; + for counter := ftempmodeldef.numstate + 1 to processnum - 1 do + begin + NumberofParams := NumberofParams + ftempprocess[counter].parameters; + end; + ParCount := NumberofParams; +end; // end of parcount function + +procedure TFmMain.BtnCloseClick(Sender: TObject); +begin + FmMain.Close; +end; + +procedure TFmMain.FormCreate(Sender: TObject); +begin + fResourcePath := GetResourcePath(); + fvarlist := Tstringlist.Create; + fvarlist.Sorted:=True; + fvarlist.Duplicates:=dupError; + // Set the default model path to the folder CrEquations is in. + {$ifdef Darwin} + fModelPath:=fResourcePath; + delete(fModelPath,pos(BundleResourceDirectory,fResourcePath),length(BundleResourceDirectory)); + {$else} // Windows, Unix + fModelPath:=fResourcePath; + {$endif} + DlgOpenModelDef.InitialDir := fModelPath; + fEquationsFilename := fResourcePath + 'equationsblank.pas'; + DlgOpenEqPas.InitialDir:= fResourcePath; +end; + +procedure TFmMain.FormDestroy(Sender: TObject); +begin + fvarlist.Free; +end; + +function TFmMain.GetArrayNum(varname:string): integer; +var + i, number:integer; +begin + number := pos('-',varname); + if number <> 0 then + begin + if isdigit(varname,number-2) then delete(varname,number-2,length(varname)) + else delete(varname,number-1,length(varname)); + end + else + begin + number := length(varname); + delete(varname,number,1); + end; + + number := 0; + for i := 1 to fTotalNumArrays do + begin + if varname = farrays[i].VarName then number := i; + end; + if number = 0 then + begin + delete(varname,length(varname),1); + for i := 1 to fTotalNumArrays do + if varname = farrays[i].varname then number := i; + end; + + if number <> 0 then + GetArrayNum := number + else + raise Exception.Create('Could not find variable, "' + varname + '" in arrays array.'); +end; + +procedure TFmMain.GetFunctions; +var + fromline, toline, numsourcelines, i: integer; +begin + fromline := LineSearch(fModelDef, 'Functions'); + toline := LineSearch(fModelDef, 'End Functions'); + numsourcelines := toline - fromline; + + toline := LineSearch(fEquations,'{ Functions or procedures }'); + if numsourcelines > 3 then + begin + i := 1; + repeat + fEquations.Insert(toline + i, fModelDef[fromline + i]); + i := i + 1; + until i = numsourcelines; + end; +end; + +function TFmMain.CheckDerivatives(fline: integer): integer; +var + i, j, arraynum: integer; + tempstring, tempstring2: string; +begin + i := 1; + fline := fline + 1; + repeat + repeat + tempstring := fModelDef[fline]; + fline := fline + 1; + until tempstring <> ''; + j := pos(':',tempstring); + delete(tempstring, j, length(tempstring)-j+1); + tempstring := trim(tempstring); + if ftempprocess[i].name[1] = '*' then // An array or matrix + begin + arraynum := GetArrayNum(ftempstate[i].name); + j := pos('[',tempstring); + delete(tempstring, j, length(tempstring)-j+1); + + tempstring2 := ftempprocess[i].symbol; + j := pos('[',tempstring2); + delete(tempstring2, j, length(tempstring2)-j+1); + + if lowercase(tempstring2) <> lowercase(tempstring) then + raise Exception.Create('Derivatives out of order. Model translation failed.'); + if farrays[arraynum].Numcol = 0 then // Array + begin + i := i + farrays[arraynum].numRow; + end + else // Matrix + begin + i := i + farrays[arraynum].numRow*farrays[arraynum].Numcol; + end; + end + else + begin + if lowercase(ftempprocess[i].symbol) <> + lowercase(tempstring) then + raise Exception.Create('Derivatives out of order. Model translation failed.'); + i := i + 1; + end; + until i = ftempmodeldef.numstate + 1; + CheckDerivatives := 1; +end; + +function TFmMain.RemoveTrailingComma(lnum: integer): integer; +var + tempstring: string; + ll: integer; +begin + RemoveTrailingComma := 0; + tempstring := fEquations[lnum]; + tempstring := trim(tempstring); + ll := length(tempstring); + if tempstring[ll] = ',' then delete(tempstring, ll, 1); + fEquations[lnum] := tempstring; + RemoveTrailingComma := 1; +end; + +procedure TFmMain.RemoveFinalDouble; +var + ll: integer; +begin + ll := LineSearch(fEquations,':double; {Final double}'); + fEquations[ll] := ''; +end; + +function TFmMain.RemoveArrayIndex(tstring: string): string; +var + i: integer; +begin + i := pos('[', tstring); + delete(tstring, i, length(tstring) - 1); + RemoveArrayIndex := tstring; +end; + +function TFmMain.GetResourcePath(): string; +{$ifdef Darwin} +var + pathRef:CFURLRef; + pathCFStr: CFStringRef; + pathStr: shortstring; +{$endif} +begin +{$ifdef Unix} +{$ifdef Darwin} + pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle()); + pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle); + CFStringGetPascalString(pathCFStr, @pathStr, 255, CFStringGetSystemEncoding()); + CFRelease(pathRef); + CFRelease(pathCFStr); + + Result := pathStr + BundleResourceDirectory; +{$else} + Result := DefaultUnixDirectory; +{$endif} +{$else} // Windows + Result := ExtractFilePath(Application.exeName); +{$endif} +end; + +function TFmMain.IsDigit(astring:string; index:integer): Boolean; +begin + result := False; + case astring[index] of + '0'..'9': result := True; + end; + +end; + + +procedure TFmMain.DefBooleanVar; +var + i, j, fromline:integer; + avar: TvarInfo; + tempstring: string; +begin + fromline := LineSearch(fModelDef, 'Boolean Variables'); + // Advance 2 lines in the memo to get to the variable list + fromline := fromline + 2; + tempstring := fModelDef[fromline]; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until (tempstring <> '') or (fromline > fModelDef.Count); + i := 1; + while tempstring <> 'End' do + begin + avar:=ParseString(tempstring,vtBoolean); + // ParseString(tempstring, tname, tunits, tsymbol, tnpar, tptype, tnrow, tncol); + if avar.Name[1] <> '*' then // Not an array variable + begin + ftempBoolean[i].name := avar.Name; + ftempBoolean[i].units := avar.Units; + ftempBoolean[i].symbol := avar.Symbol; + i := i + 1; + end + else // An array variable + begin + for j := 1 to avar.numRow do + begin + ftempBoolean[i + j - 1].name := avar.Name + inttostr(j); + ftempBoolean[i + j - 1].units := avar.Units; + ftempBoolean[i + j - 1].symbol := avar.Symbol; + end; + farrays[fTotalNumArrays].VarName := avar.Name; // Used in createprocessesproc procedure + farrays[fTotalNumArrays].numRow := avar.numRow; + fTotalNumArrays := fTotalNumArrays + 1; + if fTotalNumArrays > MaxArrays then + raise Exception.Create('Too many arrays. Increase MaxArrays.'); + i := i + avar.numRow; + end; + repeat + tempstring := fModelDef[fromline]; + tempstring := trim(tempstring); + fromline := fromline + 1; + until tempstring <> ''; + end; + numBoolean := i - 1; +end; + +end. + diff --git a/modelshell/create_equations/equationsblank.pas b/modelshell/create_equations/equationsblank.pas new file mode 100644 index 0000000..314b93a --- /dev/null +++ b/modelshell/create_equations/equationsblank.pas @@ -0,0 +1,302 @@ +{ This unit defines the structure of the model. There are four functions. The + first function, called counts, defines the number, names, and units of the + model, the state variables, the process variables, the driver variables and + the parameters. The second function, called processes, is the actual equations + which make up the model. The third function, derivs, calculates the + derivatives of state variables. And the fourth function, parcount, is used to + automatically number the parameters consecutively. + The state variables, driver variables, process variables and parameters are + all stored in global arrays, called stat, drive, proc, and par, respectively. + The function counts accesses the global arrays directly but the other functions + operate on copies of the global arrays. } +unit equations; + +interface + +uses stypes, math, sysutils; + +PROCEDURE counts; +PROCEDURE processes(time:double; dtime:double; var tdrive:drivearray; + var tpar:paramarray; var tstat:statearray; + var tproc:processarray; CalculateDiscrete:Boolean); +PROCEDURE derivs(t, drt:double; var tdrive:drivearray; var tpar:paramarray; + var statevalue:yValueArray; VAR dydt:yValueArray); +function ParCount(processnum:integer) : integer; + +var + tproc:processarray; + tstat:statearray; + sensflag:boolean; + newyear:Boolean = false; + DayofYear: double = 0; + h: array[1..4,1..4] of double; + +implementation + +uses frontend, calculate, options; + + { Do not make modifcations above this line. } +{*****************************************************************************} + +{ This procedure defines the model. The number of parameters, state, driver and + process variables are all set in this procedure. The model name, version + number and time unit are also set here. This procedure accesses the global + arrays containing the the parameters, state, driver and process variables and + the global structure ModelDef directly, to save memory space. } +PROCEDURE counts; +var + i,npar,CurrentProc:integer; +begin +{ Set the modelname, version and time unit. } +ModelDef.modelname := 'Blank'; +ModelDef.versionnumber := '1.0.0'; +ModelDef.timeunit := 'days'; +ModelDef.contactperson := 'Your Name'; +ModelDef.contactaddress1 := 'Address line 1'; +ModelDef.contactaddress2 := 'Address line 2'; +ModelDef.contactaddress3 := 'Address line 3'; + +{ Set the number of state variables in the model. The maximum number of state + variables is maxstate, in unit stypes. } +ModelDef.numstate := 1; + +{ Enter the name, units and symbol for each state variable. The maximum length + of the state variable name is 17 characters and the maximum length for units + and symbol is stringlength (specified in unit stypes) characters. } + +with stat[1] do + begin + name:='X'; units:='g'; symbol := 'X'; + end; + +{ Set the total number of processes in the model. The first numstate processes + are the derivatives of the state variables. The maximum number of processes is + maxparam, in unit stypes. } +ModelDef.numprocess := ModelDef.numstate + 105; + +{ For each process, set proc[i].parameters equal to the number of parameters + associated with that process, and set IsDiscrete to true or false. After each + process, set the name, units, and symbol for all parameters associated with + that process. Note that Parcount returns the total number of parameters in + all previous processes. } +CurrentProc := ModelDef.numstate + 1; +With proc[CurrentProc] do + begin + name := 'Process'; + units := 'g day-1'; + symbol := 'P'; + parameters := 1; + ptype := ptMisc; + IsDiscrete := False; + end; +npar:=ParCount(CurrentProc); +with par[npar+1] do + begin + name:='a'; units := 'day-1'; symbol := 'a'; + end; + +{ Set the total number of drivers in the model. The maximum number of drivers is + maxdrive, in unit stypes. } +ModelDef.numdrive := 1; + +{ Set the names, units, and symbols of the drivers. The maximum length for the + name, units and symbol is 20 characters. } +with drive[1] do + begin + name := 'Forcing variable'; units := 'g day-1'; symbol := 'F'; + end; + +{ The first numstate processes are the derivatives of the state variables. The + code sets the names, units and symbols accordingly.} +for i:= 1 to ModelDef.numstate do proc[i].name:='d'+stat[i].name+'dt'; +for i:= 1 to ModelDef.numstate do proc[i].units := stat[i].units + 't-1'; +for i:= 1 to ModelDef.numstate do proc[i].symbol := 'd' + stat[i].symbol + 'dt'; + +{ Code to sum up the total number of parameters in the model. Do not change the + next few lines. } +ModelDef.numparam := 0; +for i := 1 to ModelDef.NumProcess do + ModelDef.numparam := ModelDef.numparam + proc[i].parameters; + +end; // counts procedure + + +{ A procedure to calculate the value of all states and processes at the current + time. This function accesses time, state variables and process variables by + reference, ie it uses the same array as the calling routine. It does not use + the global variables time, stat and proc because values calculated during + integration might later be discarded. It does access the global variables par, + drive and ModelDef directly because those values are not modified. + + The model equations are written using variable names which correspond to the + actual name instead of using the global arrays (i.e. SoilWater instead of + stat[7].value). This makes it necessary to switch all values into local + variables, do all the calculations and then put everything back into the + global variables. Lengthy but worth it in terms of readability of the code. } + +// Choose either GlobalPs, ArcticPs, or none here so the appropriate Ps model is compiled below. +{$DEFINE none} + +PROCEDURE processes(time:double; dtime:double; var tdrive:drivearray; + var tpar:paramarray; var tstat:statearray; + var tproc:processarray; CalculateDiscrete:Boolean); +{$IFDEF GlobalPs} +const +// Global Ps parameters + x1 = 11.04; x2 = 0.03; + x5 = 0.216; x6 = 0.6; + x7 = 3.332; x8 = 0.004; + x9 = 1.549; x10 = 1.156; + gammastar = 0; kCO2 = 995.4; } +{$ENDIF} + +// Modify constant above (line above "procedure processes..." line )to specify +// which Ps model and it's constants should be compiled. Choosing a Ps model +// automatically includes the Et and Misc constants (i.e. Gem is assumed). + +{$IFDEF ArcticPs} +const +// Arctic Ps parameters +x1 = 0.192; x2 = 0.125; +x5 = 2.196; x6 = 50.41; +x7 = 0.161; x8 = 14.78; +x9 = 1.146; +gammastar = 0.468; kCO2 = 500.3; +{$ENDIF} + +{$IFDEF ArcticPs OR GlobalPs} +//const +// General Et parameters +aE1 = 0.0004; aE2 = 150; aE3 = 1.21; aE4 = 6.11262E5; + +// Other constants +cp = 1.012E-9; //specific heat air MJ kg-1 oC-1 +sigmaSB = 4.9e-9; //stefan-Boltzmann MJ m-2 day-1 K-4 +S0 = 117.5; //solar constant MJ m-2 day-1 +bHI1 =0.23; +bHI2 =0.48; +mw = 2.99; //kg h2o MJ-1 +alphaMS = 2; //mm oC-1 day-1 } +{$ENDIF} + +var +{ List the variable names you are going to use here. Generally, this list + includes all the symbols you defined in the procedure counts above. The order + in which you list them does not matter. } +{States} +X,dXdt, + +{processes and associated parameters} +P, a, + +{drivers} +F, + +{Other double} +O + +:double; {Final double} + +{Other integers} +npar, j, jj, kk, tnum:integer; + +{ Boolean Variables } + + +{ Functions or procedures } + +begin +{ Copy the drivers from the global array, drive, into the local variables. } +F := tdrive[1].value; + +{ Copy the state variables from the global array into the local variables. } +X := tstat[1].value; + +{ And now copy the parameters into the local variables. No need to copy the + processes from the global array into local variables. Process values will be + calculated by this procedure. + + Copy the parameters for each process separately using the function ParCount + to keep track of the number of parameters in the preceeding processes. + npar now contains the number of parameters in the preceding processes. + copy the value of the first parameter of this process into it's local + variable } +npar:=ParCount(ModelDef.numstate+1); +a := par[npar+1].value; + +{ Enter the equations to calculate the processes here, using the local variable + names defined above. } +P:=a*X; + +if CalculateDiscrete then +begin +// Add any discrete processes here +end; //discrete processes + + +{ Now calculate the derivatives of the state variables. If the holdConstant + portion of the state variable is set to true then set the derivative equal to + zero. } +if tstat[1].HoldConstant = False then + dXdt := dXdt:=F-P // Enter the equation for the derivative here. +else + dXdt := 0; // Set derivative equal to zero. + +{ Now that the calculations are complete, assign everything back into the arrays + so the rest of the code can access the values calculated here. (Local variables + are destroyed at the end of the procedure). + + Put the state variables back into the global arrays in case the state variable + was manually changed in this procedure (e.g. discrete state variables or steady state + calculations). } +tstat[1].value := X; + +{ Put all process values into process variable array. The first numstate + processes are the derivatives of the state variables (Calculated above).} +tproc[1].value := dXdt; + +{ Now the remaining processes. Be sure to number the processes the same here as + you did in the procedure counts above. } +tproc[ModelDef.numstate + 1].value := P; + +end; // End of processes procedure + + + { Do not make any modifications to code below this line. } +{****************************************************************************} + + +{This function counts the parameters in all processes less than processnum.} +function ParCount(processnum:integer) : integer; +var + NumberofParams, counter : integer; +begin + NumberofParams := 0; + for counter := ModelDef.numstate + 1 to processnum - 1 do + NumberofParams := NumberofParams + proc[counter].parameters; + ParCount := NumberofParams; +end; // end of parcount function + +{ This procedure supplies the derivatives of the state variables to the + integrator. Since the integrator deals only with the values of the variables + and not there names, units or the state field HoldConstant, this procedure + copies the state values into a temporary state array and copies the value of + HoldConstant into the temporary state array and passes this temporary state + array to the procedure processes. } +PROCEDURE derivs(t, drt:double; var tdrive:drivearray; var tpar:paramarray; + var statevalue:yValueArray; VAR dydt:yValueArray); +var + i:integer; + tempproc:processarray; + tempstate:statearray; +begin + tempstate := stat; // Copy names, units and HoldConstant to tempstate + // Copy current values of state variables into tempstate + for i := 1 to ModelDef.numstate do tempstate[i].value := statevalue[i]; + // Calculate the process values + processes(t, drt, tdrive, tpar, tempstate, tempproc, false); + // Put process values into dydt array to get passed back to the integrator. + for i:= 1 to ModelDef.numstate do dydt[i]:=tempproc[i].value; +end; // end of derivs procedure + +end. diff --git a/modelshell/create_equations/stypes.pas b/modelshell/create_equations/stypes.pas new file mode 100644 index 0000000..116f976 --- /dev/null +++ b/modelshell/create_equations/stypes.pas @@ -0,0 +1,257 @@ +{ This file defines new variable types and sets the limits on the various arrays + used in the model code. All units should include this file. } +unit stypes; + +interface + +uses sysutils, classes; + +const + maxstate = 150; // The maximum number of state variables. The state variable + // array contains maxstate elements. + maxdrive = 75; // The maximum number of driver variables. + maxprocess = maxstate + 350; // The maximum number of process variables. + maxparam = 500; // The maximum number of parameters. + maxresults = 102; + maxtreatments = 8; + stringlength = 25; + maxVarObserved = 100; + maxTimeMeasure = 100; + maxmatrix = 10000; + +type + Tshortstring = string[stringlength]; + processtype = (ptGroup1, ptGroup2, ptGroup3, ptGroup4, ptGroup5); +// processcolor = (clGreen, clTeal, clAqua, clBlue, clGray); + TModelDef = record // A structure used to hold the basic information + modelname:string; // about the model. Modelname is the name of + // model and appears on the title bar in the FmShellMain. + versionnumber:string; // Used to keep track of the version number of the model. + contactperson:string; // Used for the aboutbox + contactaddress1:string; // Used for the aboutbox + contactaddress2:string; // Used for the aboutbox + contactaddress3:string; // Used for the aboutbox + timeunit:string; // Timeunit is the time step of the model, ie day, year. + numdrive:integer; // Numparam, numdrive, numstate and numprocess are the + numstate:integer; // total number of parameters, drivers, state variables, + numprocess:integer; // and processes, respectively. + numparam:integer; + end; + + Tparamvariable = record // A structure to hold a parameter; it's name, value, + name:string; // and units. The name and units are for information + value:double; // only. They do not affect the running of the model. + units:string; // This structure type is also used for the + symbol:string; // driver variables. + end; + + Tstatevariable = record // A structure to hold a state variable; the name, + name:string; // value and units. As with Tparamvariable the name + value:double; // and units are for information only. HoldConstant + units:string; // determines if the state variable is held constant + symbol:string; // during the model run, i.e. dstatedt = 0. + HoldConstant:Boolean; + Reset:Boolean; + end; + + Tprocessvariable = record // A structure to hold a process variable; the + name:string; // name, value, and units. As above, the name and + value:double; // units are for information only. Parameters is + units:string; // number of parameters associated with this + symbol:string; // particular process. Every parameter must be + parameters:integer; // associated with a process. Ptype determines the + ptype:processtype; // color of the tab in the edit parameters page. + end; + + Tallstates = record + Cf:Tstatevariable; + Cw:Tstatevariable; + Cr:Tstatevariable; + Nf:Tstatevariable; + Nw:Tstatevariable; + Nr:Tstatevariable; + end; + + TCalSet = record + HaveRunInfo: Boolean; + ValidSet: Boolean; + rownum: integer; + Treatment: integer; + State: string; + StateIndex: integer; + Parameter: string; + ParamIndex: integer; + Alpha: double; + Beta: double; + DeltaPar: double; + end; + +// State variable array types. yValueArray, glindx and glpbynp are used during +// integration. They hold temporary values of the state variables and therefore +// don't need to be of type Tstatevariable. This saves memory. However they +// must be the same size as statearray. + yValueArray=array[1..maxstate] of double; + glindx = ARRAY [1..maxstate] OF integer; + glnpbynp = ARRAY [1..maxstate,1..maxstate] OF double; + statearray=array[1..maxstate] of Tstatevariable; +// Driver variable array type. Note that the type is Tparamvariable. + drivearray=array[1..maxdrive] of Tparamvariable; +// Parameter array type. + paramarray=array[1..maxparam] of Tparamvariable; +// Process variable array type. + processarray=array[1..maxprocess] of Tprocessvariable; + calsetarray = array[1..maxstate] of Tcalset; + stringarray = array[1..maxstate + 1] of string; + +// The types of data which can be displayed in the dataform + TDataType = (dtState, dtProcess, dtParameter); +// The possible axis' in the chart on the display form + TAxis = (axLeft, axBottom); +// The display options for the output data in the display form + TDisplayStyle = (dsChart, dsTable); +// The axis type for the chart on the display form + TAxisType = (tyLinear, tyLog); +// The type of variable being looked for in the arrays + TVarType = (vtDriver, vtState, vtParameter, vtProcess, vtBoolean, vtOther); + + TRunOptions = record + NormalRun: Boolean; + Time_step: double; + DiscreteStep: double; + RepeatDrivers: Boolean; + RepeatDriveTime: double; + ResetStates: Boolean; + ResetStateTime: double; + RuntoSS: Boolean; + SSCriteria: double; + SSTime: double; + HoldStatesConstant: Boolean; // Used in fuzzy calibrator + Outputstep: double; // The timestep specified by the user for output + Outputoffset: double; // No output for time less than outputoffset + OutputEORonly: Boolean; // output only if time = stop_time + Time_step + OutputAnnually: Boolean; + OutputAnnuallyDay: double; + AppendOutputFile: Boolean; + stepcounter: integer; + outcounter: integer; // The current number of timesteps since last output, output occurs when outcounter=outputfreq + OutputFile: Boolean; + errormult: integer; + end; + + TCalOptions = record + UseSecondOutFile: Boolean; + FinalOutFilename: string; + OrigOutputStep: double; + OrigOutputOffset: double; + OutputEORonly: Boolean; + caloutcounter: integer; + caloutputfreq: integer; + AppendFinalOutputFile: Boolean; + end; + + TTreatResults = record + Time: integer; + IndexList: array[1..Maxstate] of integer; + States: statearray; + end; + + TDerivSet = record + Time1: double; + States1: statearray; + Time2: double; + States2: statearray; + end; + + resultarray = array[1..maxresults] of TTreatResults; + + TTreatSet = record + drivefilename: string; + outputfilename: string; + timestart: double; + timestop: double; + Options: TRunOptions; + CalOptions: TCalOptions; + TotalMeasurements: integer; + measdata: resultarray; + currmeasurement: integer; + simdata: resultarray; + currdrive: drivearray; + currstate: statearray; + derivstates: TDerivSet; + NumCalSet: integer; + CalSetIndexList: array[1..maxstate] of integer; + FirstWrite: Boolean; + end; + + TreatSetarray = array[1..maxtreatments] of TTreatSet; + +// Ensemble Kalman Filter + EnKF2Dmat = array of array of double; + EnKFvec = array of double; + glindxEKF = array of integer; + mat = array[1..MaxMatrix] of double; + + TVariableIncluded = array of Boolean; + + TNameArray = array of string; + TTimeArray = array of double; + TDataArray = array of double; + T2dData = array of array of double; + // Rows are time points, columns are variables + + TPertData = array of double; + TPert = record + NumPert: integer; + Names: TNameArray; + Data: EnKF2Dmat; + end; + + TKstate = record + NumTotKalman: integer; + NumObservations: integer; + Names: TNameArray; + Units: TNameArray; + Symbol: TNameArray; + Time: TTimeArray; + Z: EnKF2dmat; + R: EnKF2dmat; + Xmean: T2dData; + Xmax: T2dData; + Xmin: T2dData; + Q: EnKF2Dmat; + Ymean: T2dData; + UnCorXmean: T2dData; + UncorXmax: T2dData; + UncorXmin: T2dData; + end; + +// Grid Shell Variables + TGridCellInfo = record + Row: integer; + Column: integer; + RunPosition: integer; + VegClass: integer; + SoilClass: integer; + ParamFilname: string; + Driverfilename: string; + OutputFilename: string; + end; + +// Errors + ERunTimeError = class(Exception); + EIntegratorError = class(ERunTimeError); + ETooManySteps = class(EIntegratorError); + EIntStepTooSmall = class(EIntegratorError); + EUserCancel = class(ERunTimeError); + ECalculateError = class(EMathError); + ECalcInitialProc = class(ECalculateError); + ECalcNewValue = class(ECalculateError); + ECalcNewProcess = class(ECalculateError); + EStepError = class(Exception); + EStepTooSmall = class(EStepError); + EStepTooLarge = class(EStepError); + EStepNotMultiple = class(EStepError); +implementation + +end. + diff --git a/modelshell/data.lfm b/modelshell/data.lfm new file mode 100644 index 0000000..5c4f246 --- /dev/null +++ b/modelshell/data.lfm @@ -0,0 +1,121 @@ +object DataForm: TDataForm + Left = 190 + Height = 292 + Top = 145 + Width = 733 + HorzScrollBar.Page = 560 + HorzScrollBar.Range = 560 + VertScrollBar.Page = 99 + VertScrollBar.Range = 99 + VertScrollBar.Visible = False + ActiveControl = StringGrid1 + ClientHeight = 292 + ClientWidth = 733 + Color = clBtnFace + DefaultMonitor = dmMainForm + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + OnCreate = FormCreate + Position = poOwnerFormCenter + LCLVersion = '1.6.4.0' + object PnlTop: TPanel + Left = 0 + Height = 49 + Top = 0 + Width = 733 + Align = alTop + ClientHeight = 49 + ClientWidth = 733 + TabOrder = 0 + object BtnOK: TButton + Left = 390 + Height = 20 + Top = 13 + Width = 71 + Caption = '&OK' + Default = True + ModalResult = 1 + OnClick = BtnOKClick + TabOrder = 0 + end + object BtnCancel: TButton + Left = 478 + Height = 20 + Top = 13 + Width = 81 + Cancel = True + Caption = '&Cancel' + ModalResult = 2 + OnClick = BtnCancelClick + TabOrder = 1 + end + object BtPrint: TButton + Left = 190 + Height = 19 + Top = 13 + Width = 61 + Caption = '&Print' + Enabled = False + OnClick = BtPrintClick + TabOrder = 2 + Visible = False + end + end + object StringGrid1: TStringGrid + Left = 0 + Height = 243 + Top = 49 + Width = 733 + Align = alClient + AutoAdvance = aaDown + ColCount = 6 + Columns = < + item + ButtonStyle = cbsCheckboxColumn + Title.Caption = 'Title' + ValueChecked = 'True' + ValueUnchecked = 'False' + end + item + ButtonStyle = cbsCheckboxColumn + Title.Caption = 'Title' + ValueChecked = 'True' + ValueUnchecked = 'False' + end + item + Title.Caption = 'Title' + end + item + Title.Caption = 'Title' + end + item + Title.Caption = 'Title' + end + item + Title.Caption = 'Title' + end> + DefaultColWidth = 150 + DefaultRowHeight = 25 + ExtendedSelect = False + FixedCols = 0 + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goEditing] + ParentFont = False + TabOrder = 1 + TitleFont.Color = clWindowText + TitleFont.Height = -11 + TitleFont.Name = 'Arial' + TitleStyle = tsStandard + OnCheckboxToggled = StringGrid1CheckboxToggled + OnDrawCell = StringGrid1DrawCell + OnSelectCell = StringGrid1SelectCell + end + object DlgPrint: TPrintDialog + Options = [poPageNums] + left = 160 + top = 8 + end +end diff --git a/modelshell/data.pas b/modelshell/data.pas new file mode 100644 index 0000000..ffe1b49 --- /dev/null +++ b/modelshell/data.pas @@ -0,0 +1,245 @@ +{ A form to view and edit data. Currently there are two types of data that can + be shown in this form, state variables and process variables. + The state variables form allows the user to view and edit the state variables. + The process variable form is used for viewing only. The user can not edit the + process variables directly. To change a process value it is necessary to + modify the parameters in the parameter form. The process values shown in this + form are automatically updated when the process values in the parameter form + are updated. + } +unit data; + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + Grids,stypes, StdCtrls, ExtCtrls, PrintersDlgs, math; + +type + + { TDataForm } + + TDataForm = class(TForm) + PnlTop: TPanel; + BtnOK: TButton; + BtnCancel: TButton; + DlgPrint: TPrintDialog; + BtPrint: TButton; + StringGrid1: TStringGrid; + procedure BtnOKClick(Sender: TObject); dynamic; + procedure BtPrintClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure ShowStates; + procedure SaveStates; + procedure ShowProcess; + procedure StringGrid1CheckboxToggled(sender: TObject; aCol, aRow: Integer; + aState: TCheckboxState); + procedure UpdateProcess; + procedure ClearGrid; + procedure BtnCancelClick(Sender: TObject); dynamic; + procedure StringGrid1SelectCell(Sender: TObject; Col, Row: Integer; + var CanSelect: Boolean); dynamic; + procedure StringGrid1DrawCell(Sender: TObject; Col, Row: Integer; + Rect: TRect; State: TGridDrawState); dynamic; + private + { Private declarations } + ftempState:Statearray; + public + { Public declarations } + end; + +var + DataForm : TDataForm; + DataShowing : TDataType; + +implementation + +uses fileio, frontend; + +{$R *.lfm} + + +// Set up the form +procedure TDataForm.FormCreate(Sender: TObject); +begin + StringGrid1.RowCount := ModelDef.numstate; + StringGrid1.FocusColor := clRed; + StringGrid1.cells[0,0]:='HoldConstant?'; + StringGrid1.cells[1,0]:='Reset?'; + StringGrid1.cells[2,0]:='Variable Symbol'; + StringGrid1.cells[3,0]:='Variable Name'; + StringGrid1.cells[4,0]:='Variable Value'; + StringGrid1.cells[5,0]:='Variable Units'; +end; + +procedure TDataForm.ShowStates; +var + i:integer; +begin + Ftempstate := Stat; + Caption := 'State Variables'; // Form Caption + DataShowing := dtstate; + StringGrid1.rowcount := ModelDef.numstate+1; + StringGrid1.Col := 1; + StringGrid1.Row := 1; + StringGrid1.Options := [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine, + goColSizing,goThumbTracking,goEditing]; + StringGrid1.ColWidths[0] := 150; + StringGrid1.ColWidths[1] := 150; + for i:= 1 to ModelDef.numstate do // Write state variables, names, values and + begin // units to grid + StringGrid1.cells[2,i] := stat[i].symbol; + StringGrid1.cells[3,i] := stat[i].name; + StringGrid1.Cells[5,i] := stat[i].units; + StringGrid1.cells[4,i] := floattostr(stat[i].value); + if stat[i].holdconstant then StringGrid1.Cells[0,i] := 'True' + else StringGrid1.Cells[0,i] := 'False'; + if stat[i].Reset then StringGrid1.Cells[1,i] := 'True' + else StringGrid1.Cells[1,i] := 'False'; + end; + DataForm.Width := min(round(0.9*Screen.Width), Stringgrid1.colcount*Stringgrid1.defaultcolwidth+10); + DataForm.Height := min(round(0.8*Screen.Height), StringGrid1.rowcount*Stringgrid1.defaultrowheight+ PnlTop.Height +10); + BtnOK.Visible := True; + BtnOK.Enabled := True; + BtnCancel.Caption := '&Cancel'; + BtnCancel.Left := 480; + DataForm.ActiveControl := StringGrid1; + ShowModal; // Show the form +end; + + +// Set up the form to show process variables then show the data +procedure tDataForm.ShowProcess; +begin + ftempState := stat; // Necessary so that initial state variable values are saved. + Caption := 'Process Variables'; // Form Caption + DataShowing := dtProcess; + StringGrid1.rowcount:=ModelDef.numprocess+1; + StringGrid1.Col := 1; + StringGrid1.Row := 1; + StringGrid1.ColWidths[0] := 0; + StringGrid1.ColWidths[1] := 0; + StringGrid1.Options := [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine, + goColSizing,goThumbTracking]; + UpdateProcess; + DataForm.Width := min(round(0.9*Screen.Width), (Stringgrid1.colcount-2)*Stringgrid1.defaultcolwidth+10); + DataForm.Height := min(round(0.8*Screen.Height), StringGrid1.rowcount*Stringgrid1.defaultrowheight+ PnlTop.Height +10); + BtnOK.Visible := False; + BtnOK.Enabled := False; + BtnCancel.Caption := '&Close'; + BtnCancel.Left:=20; + Show; +end; + +procedure TDataForm.StringGrid1CheckboxToggled(sender: TObject; aCol, + aRow: Integer; aState: TCheckboxState); +begin + if aCol = 0 then + if astate = cbchecked then stat[aRow].holdconstant := true + else stat[aRow].holdconstant := false; + if acol = 1 then + if astate = cbchecked then stat[aRow].reset := true + else stat[aRow].reset := false; +end; + +// Form has been modified, user wants to keep the changes +procedure TDataForm.BtnOKClick(Sender: TObject); // FIX what if processes are showing +begin +if DataShowing = dtState{ and StringGrid1Modified }then + begin + SaveStates; + NeedToSavePar := True; // State variables have been changed, parameter file + // needs to be saved + RunComplete := False; + end; + ClearGrid; +end; + +// Clear the grid when the form closes. When the form is showing process +// variables also close the form manually since it doesn't do it automatically. +procedure TDataForm.BtnCancelClick(Sender: TObject); +begin + if datashowing = dtstate then stat := ftempState; // Set states back to original values + ClearGrid; + if DataForm.Visible then DataForm.Close; +end; + +// Update global array of state variables with the changes made to the string grid +procedure tDataForm.SaveStates; +var + i:integer; +begin + for i:=1 to ModelDef.numstate do + begin // Copy value in grid to the global state array + stat[i].value := strtofloat(StringGrid1.Cells[4,i]); + // Holdconstant and reset values are saved as soon as they are changed so don't need to do them here + end; +end; + +{ The procedure updates the process variable values shown in the Dataform.} +procedure tDataForm.UpdateProcess; +var + i:integer; +begin + for i:= 1 to ModelDef.numprocess do // Write process variables, names, values and + begin // units to grid + StringGrid1.cells[3,i] := proc[i].name; + StringGrid1.Cells[5,i] := proc[i].units; + StringGrid1.Cells[2,i] := proc[i].symbol; + StringGrid1.cells[4,i] := floattostr(proc[i].value); + end; +end; + +// Clear the StringGrid so that new data can be written to it +procedure tDataForm.ClearGrid; +var + i,j : integer; +begin // Set grid cells to empty strings + for i := 0 to StringGrid1.RowCount - 1 do + for j := 2 to StringGrid1.ColCount - 1 do // Don't do columns 0 and 1 because their the check boxes + StringGrid1.Cells[j,i] := ''; + StringGrid1.RowCount := 3; // Reset row count +end; + +// Print out the state variables. +{ This procedure is currently not enabled because it will only print the visible + state variables. Needs to be fixed to print them all. } +procedure TDataForm.BtPrintClick(Sender: TObject); +begin +with DlgPrint do + if execute then + // Print StringGrid1.PaintTo(); + ; +end; + +procedure TDataForm.StringGrid1SelectCell(Sender: TObject; Col, + Row: Integer; var CanSelect: Boolean); +begin + if DataShowing = dtstate then + if (Col = 4) or (Col = 0) or (Col = 1) then + StringGrid1.Editor := StringGrid1.EditorbyStyle(cbsAuto) + else + StringGrid1.Editor := StringGrid1.EditorbyStyle(cbsNone) + else + StringGrid1.Editor := StringGrid1.EditorbyStyle(cbsNone); +end; + +procedure TDataForm.StringGrid1DrawCell(Sender: TObject; Col, + Row: Integer; Rect: TRect; State: TGridDrawState); +var + s:string; +begin + if DataShowing = dtstate then + begin + if Col <> 4 then + StringGrid1.Canvas.Brush.Color:= clScrollBar; + end + else + StringGrid1.Canvas.Brush.Color:= clScrollBar; + + StringGrid1.Canvas.FillRect(Rect); + S := StringGrid1.Cells[Col, Row]; + StringGrid1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, S); +end; + +end. diff --git a/modelshell/display.lfm b/modelshell/display.lfm new file mode 100644 index 0000000..1e89718 --- /dev/null +++ b/modelshell/display.lfm @@ -0,0 +1,614 @@ +object FmDisplayOutput: TFmDisplayOutput + Left = -1 + Height = 686 + Top = 50 + Width = 1070 + HorzScrollBar.Smooth = True + VertScrollBar.Smooth = True + ActiveControl = LblEdPar1 + Caption = 'FmDisplayOutput' + ClientHeight = 666 + ClientWidth = 1070 + DefaultMonitor = dmMainForm + Menu = MmDisplay + OnClose = FormClose + OnCreate = FormCreate + OnResize = FormResize + OnShow = FormShow + Position = poMainFormCenter + LCLVersion = '1.6.4.0' + object SgModelOutput: TStringGrid + Left = 0 + Height = 359 + Top = 0 + Width = 1070 + Align = alClient + FixedCols = 0 + TabOrder = 0 + Visible = False + end + object PnlTop: TPanel + Left = 0 + Height = 359 + Top = 0 + Width = 1070 + Align = alClient + ClientHeight = 359 + ClientWidth = 1070 + TabOrder = 1 + object PnlTopRight: TPanel + Left = 894 + Height = 357 + Top = 1 + Width = 175 + Align = alRight + Anchors = [] + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsHomogenousChildResize + ChildSizing.ShrinkVertical = crsHomogenousChildResize + ClientHeight = 357 + ClientWidth = 175 + Constraints.MinWidth = 100 + TabOrder = 0 + OnClick = PnlTopRightClick + object PnlRerun: TPanel + Left = 1 + Height = 94 + Top = 262 + Width = 173 + Align = alBottom + BorderSpacing.InnerBorder = 4 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsHomogenousChildResize + ChildSizing.ShrinkVertical = crsHomogenousChildResize + ClientHeight = 94 + ClientWidth = 173 + ParentColor = False + TabOrder = 0 + object BtnRun: TButton + Left = 53 + Height = 20 + Top = 60 + Width = 70 + Anchors = [] + BorderSpacing.Around = 2 + Caption = '&Run' + OnClick = BtnRunClick + TabOrder = 2 + end + object CbxStates: TCheckBox + Left = 10 + Height = 19 + Top = 8 + Width = 51 + BorderSpacing.Around = 2 + Caption = '&States' + Checked = True + OnClick = cbxStatesClick + State = cbChecked + TabOrder = 0 + end + object CbxParameters: TCheckBox + Left = 10 + Height = 19 + Top = 32 + Width = 79 + BorderSpacing.Around = 2 + Caption = '&Parameters' + OnClick = cbxParamsClick + TabOrder = 1 + end + end + object PnlParameters: TPanel + Left = 1 + Height = 261 + Top = 1 + Width = 173 + Align = alClient + ClientHeight = 261 + ClientWidth = 173 + ParentColor = False + TabOrder = 1 + object LblEdPar1: TLabeledEdit + Left = 10 + Height = 23 + Top = 31 + Width = 150 + Alignment = taCenter + Anchors = [] + EditLabel.AnchorSideLeft.Control = LblEdPar1 + EditLabel.AnchorSideRight.Control = LblEdPar1 + EditLabel.AnchorSideRight.Side = asrBottom + EditLabel.AnchorSideBottom.Control = LblEdPar1 + EditLabel.Left = 10 + EditLabel.Height = 15 + EditLabel.Top = 13 + EditLabel.Width = 150 + EditLabel.Caption = 'Parameter &1' + EditLabel.ParentColor = False + TabOrder = 0 + OnDblClick = lblParClick + OnExit = LblEdParExit + OnKeyPress = LblEdParKeyPress + end + object LblEdPar2: TLabeledEdit + Left = 10 + Height = 23 + Top = 85 + Width = 150 + Alignment = taCenter + Anchors = [] + EditLabel.AnchorSideLeft.Control = LblEdPar2 + EditLabel.AnchorSideRight.Control = LblEdPar2 + EditLabel.AnchorSideRight.Side = asrBottom + EditLabel.AnchorSideBottom.Control = LblEdPar2 + EditLabel.Left = 10 + EditLabel.Height = 15 + EditLabel.Top = 67 + EditLabel.Width = 150 + EditLabel.Caption = 'Parameter &2' + EditLabel.ParentColor = False + TabOrder = 1 + OnDblClick = lblParClick + OnExit = LblEdParExit + OnKeyPress = LblEdParKeyPress + end + object LblEdPar3: TLabeledEdit + Left = 10 + Height = 23 + Top = 139 + Width = 150 + Alignment = taCenter + Anchors = [] + EditLabel.AnchorSideLeft.Control = LblEdPar3 + EditLabel.AnchorSideRight.Control = LblEdPar3 + EditLabel.AnchorSideRight.Side = asrBottom + EditLabel.AnchorSideBottom.Control = LblEdPar3 + EditLabel.Left = 10 + EditLabel.Height = 15 + EditLabel.Top = 121 + EditLabel.Width = 150 + EditLabel.Caption = 'Parameter &3' + EditLabel.ParentColor = False + TabOrder = 2 + OnDblClick = lblParClick + OnExit = LblEdParExit + OnKeyPress = LblEdParKeyPress + end + object LblEdPar4: TLabeledEdit + Left = 10 + Height = 23 + Top = 185 + Width = 150 + Alignment = taCenter + Anchors = [] + EditLabel.AnchorSideLeft.Control = LblEdPar4 + EditLabel.AnchorSideRight.Control = LblEdPar4 + EditLabel.AnchorSideRight.Side = asrBottom + EditLabel.AnchorSideBottom.Control = LblEdPar4 + EditLabel.Left = 10 + EditLabel.Height = 15 + EditLabel.Top = 167 + EditLabel.Width = 150 + EditLabel.Caption = 'Parameter &4' + EditLabel.ParentColor = False + TabOrder = 3 + OnDblClick = lblParClick + OnExit = LblEdParExit + OnKeyPress = LblEdParKeyPress + end + end + end + object ChOutput: TChart + Left = 1 + Height = 357 + Top = 1 + Width = 893 + AxisList = < + item + Minors = <> + Title.LabelFont.Orientation = 900 + Title.Visible = True + end + item + Alignment = calBottom + Minors = <> + Title.Visible = True + end> + Foot.Brush.Color = clBtnFace + Foot.Font.Color = clBlue + Legend.Visible = True + Title.Brush.Color = clBtnFace + Title.Font.Color = clBlue + Title.Text.Strings = ( + 'TAChart' + ) + Align = alClient + Anchors = [] + object ChOutputLineSeries1: TLineSeries + LineType = ltNone + Pointer.Brush.Style = bsClear + Pointer.Style = psCircle + ShowPoints = True + Source = ListChartSource1 + end + object ChOutputLineSeries2: TLineSeries + Marks.LinkPen.Color = clRed + LinePen.Color = clRed + LineType = ltNone + Pointer.Brush.Color = clRed + Pointer.Pen.Color = clRed + ShowPoints = True + Source = ListChartSource2 + end + object ChOutputLineSeries3: TLineSeries + LinePen.Color = clBlue + LineType = ltNone + Pointer.Brush.Color = clBlue + Pointer.Pen.Color = clBlue + Pointer.Style = psCross + ShowPoints = True + Source = ListChartSource3 + end + object ChOutputLineSeries4: TLineSeries + LinePen.Color = clGreen + LineType = ltNone + Pointer.Brush.Color = clGreen + Pointer.Pen.Color = clGreen + Pointer.Style = psDiagCross + ShowPoints = True + Source = ListChartSource4 + end + object ChOutputLineSeries5: TLineSeries + LinePen.Color = clYellow + LineType = ltNone + Pointer.Brush.Color = clYellow + Pointer.Style = psTriangle + ShowPoints = True + Source = ListChartSource5 + end + object ChOutputLineSeries6: TLineSeries + LinePen.Color = clMaroon + LineType = ltNone + Pointer.Brush.Color = clMaroon + Pointer.Pen.Color = clMaroon + ShowPoints = True + Source = ListChartSource6 + end + object ChOutputLineSeries7: TLineSeries + LinePen.Color = clSilver + LineType = ltNone + Pointer.Brush.Color = clSilver + Pointer.Pen.Color = clSilver + Pointer.Style = psDiamond + ShowPoints = True + Source = ListChartSource7 + end + object ChOutputLineSeries8: TLineSeries + LinePen.Color = clAqua + LineType = ltNone + Pointer.Brush.Color = clAqua + Pointer.Style = psLeftBracket + ShowPoints = True + Source = ListChartSource8 + end + object ChOutputLineSeries9: TLineSeries + LinePen.Color = clPurple + LineType = ltNone + Pointer.Brush.Color = clPurple + Pointer.Pen.Color = clPurple + Pointer.Style = psStar + ShowPoints = True + Source = ListChartSource9 + end + object ChOutputLineSeries10: TLineSeries + LinePen.Color = clLime + LineType = ltNone + Pointer.Brush.Color = clLime + Pointer.Pen.Color = clLime + Pointer.Style = psCircle + ShowPoints = True + Source = ListChartSource10 + end + end + end + object SplTopBottom: TSplitter + Cursor = crVSplit + Left = 0 + Height = 7 + Top = 359 + Width = 1070 + Align = alBottom + ResizeAnchor = akBottom + end + object PnlBottom: TPanel + Left = 0 + Height = 300 + Top = 366 + Width = 1070 + Align = alBottom + ClientHeight = 300 + ClientWidth = 1070 + TabOrder = 3 + object PnlBottomLeft: TPanel + Left = 1 + Height = 298 + Top = 1 + Width = 892 + Align = alClient + ClientHeight = 298 + ClientWidth = 892 + TabOrder = 0 + object LblDirections: TLabel + Left = 4 + Height = 15 + Top = 4 + Width = 884 + Align = alTop + BorderSpacing.Around = 3 + Caption = 'Select a maximum of 10 series to plot.' + ParentColor = False + end + object LbxSeriesSelect: TListBox + Left = 3 + Height = 273 + Top = 22 + Width = 886 + Align = alClient + BorderSpacing.Around = 2 + Columns = 3 + ExtendedSelect = False + ItemHeight = 0 + MultiSelect = True + Sorted = True + Style = lbOwnerDrawFixed + TabOrder = 0 + end + end + object PnlBottomRight: TPanel + Left = 893 + Height = 298 + Top = 1 + Width = 176 + Align = alRight + Anchors = [] + AutoSize = True + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsHomogenousChildResize + ChildSizing.ShrinkVertical = crsHomogenousChildResize + ClientHeight = 298 + ClientWidth = 176 + TabOrder = 1 + object RgChartValues: TRadioGroup + Left = 1 + Height = 110 + Top = 1 + Width = 174 + Align = alTop + AutoFill = True + Caption = 'Plot values as' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsHomogenousChildResize + ChildSizing.ShrinkVertical = crsHomogenousChildResize + ChildSizing.Layout = cclTopToBottomThenLeftToRight + ChildSizing.ControlsPerLine = 3 + ClientHeight = 90 + ClientWidth = 170 + ColumnLayout = clVerticalThenHorizontal + ItemIndex = 0 + Items.Strings = ( + '&Actual Values (y)' + '&Relative Change (y/y0)' + 'Cu&mulative Change (y-y0) ' + ) + OnClick = RgChartValuesClick + TabOrder = 0 + end + object PnlChartButtons: TPanel + Left = 1 + Height = 186 + Top = 111 + Width = 174 + Align = alClient + BorderStyle = bsSingle + ClientHeight = 182 + ClientWidth = 170 + TabOrder = 1 + object BtnClearSeries: TButton + Left = 18 + Height = 25 + Top = 67 + Width = 137 + Anchors = [] + AutoSize = True + Caption = 'C&lear Series Selection' + OnClick = BtnClearSeriesClick + TabOrder = 1 + end + object BtnUpdateChart: TButton + Left = 38 + Height = 25 + Top = 19 + Width = 96 + Anchors = [] + AutoSize = True + Caption = '&Update Chart' + OnClick = BtnUpdateChartClick + TabOrder = 0 + end + object BtnCloseDisplay: TButton + Left = 38 + Height = 25 + Top = 115 + Width = 96 + Anchors = [] + AutoSize = True + Caption = '&Close Display' + OnClick = BtnCloseDisplayClick + TabOrder = 2 + end + end + end + object SplBottomLR: TSplitter + Left = 893 + Height = 298 + Top = 1 + Width = 0 + Align = alRight + ResizeAnchor = akRight + end + end + object MmDisplay: TMainMenu + left = 336 + top = 56 + object MIWindow: TMenuItem + Caption = '&Window' + object MIShow: TMenuItem + Caption = 'S&how' + object MIShowChart: TMenuItem + Caption = '&Chart' + OnClick = MIShowChange + end + object MIShowTable: TMenuItem + Caption = '&Table' + OnClick = MIShowChange + end + end + object MISaveOutput: TMenuItem + Caption = '&Save output to file' + OnClick = MISaveOutputClick + end + object MILoadFile: TMenuItem + Caption = '&Load from File' + OnClick = MILoadFileClick + end + object MIClose: TMenuItem + Caption = '&Close' + OnClick = BtnCloseDisplayClick + end + end + object MIChart: TMenuItem + Caption = 'C&hart' + object MIXaxis: TMenuItem + Caption = '&X-axis' + object MIXSelect: TMenuItem + Caption = '&Select' + OnClick = MISelectAxisClick + end + object MIXScale: TMenuItem + Caption = 'S&cale' + OnClick = MIScaleClick + end + end + object MIYaxis: TMenuItem + Caption = '&Y-axis' + object MIYSelect: TMenuItem + Caption = '&Select' + OnClick = MISelectAxisClick + end + object MIYScale: TMenuItem + Caption = 'S&cale' + OnClick = MIScaleClick + end + end + object MIUpdate: TMenuItem + Caption = '&Update' + end + object MIPrintChart: TMenuItem + Caption = '&Print Chart' + Enabled = False + Visible = False + end + end + end + object ListChartSource2: TListChartSource + Sorted = True + left = 48 + top = 80 + end + object ListChartSource1: TListChartSource + Sorted = True + left = 84 + top = 44 + end + object ListChartSource6: TListChartSource + Sorted = True + left = 172 + top = 50 + end + object ListChartSource7: TListChartSource + Sorted = True + left = 180 + top = 110 + end + object ListChartSource3: TListChartSource + Sorted = True + left = 81 + top = 169 + end + object ListChartSource8: TListChartSource + Sorted = True + left = 171 + top = 170 + end + object ListChartSource4: TListChartSource + Sorted = True + left = 71 + top = 242 + end + object ListChartSource9: TListChartSource + Sorted = True + left = 173 + top = 241 + end + object ListChartSource10: TListChartSource + Sorted = True + left = 175 + top = 303 + end + object ListChartSource5: TListChartSource + Sorted = True + left = 79 + top = 311 + end + object ChartToolset1: TChartToolset + left = 556 + top = 84 + object ChartToolset1ZoomClickTool1: TZoomClickTool + ZoomFactor = 2 + ZoomRatio = 2 + end + object ChartToolset1PanClickTool1: TPanClickTool + end + object ChartToolset1PanDragTool1: TPanDragTool + end + object ChartToolset1ZoomDragTool1: TZoomDragTool + end + end + object ChLAxisTransforms: TChartAxisTransformations + left = 518 + top = 207 + object ChLAxisLogarithm: TLogarithmAxisTransform + Enabled = False + Base = 10 + end + object ChLAxisAutoScale: TAutoScaleAxisTransform + end + end + object ChBAxisTransforms: TChartAxisTransformations + left = 511 + top = 283 + object ChBAxisLogarithm: TLogarithmAxisTransform + Enabled = False + Base = 10 + end + object ChBAxisAutoScale: TAutoScaleAxisTransform + end + end +end diff --git a/modelshell/display.pas b/modelshell/display.pas new file mode 100644 index 0000000..946d0b5 --- /dev/null +++ b/modelshell/display.pas @@ -0,0 +1,1528 @@ +unit Display; + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus, + ExtCtrls, StdCtrls, Grids, TAGraph, TASeries, + TASources, TATools, TACustomSource, TALegendPanel, TATransformations, stypes; + +const + Maxseries = 10; + FirstRow = 3; + +type + plotarray=array[1..MaxSeries] of string; + +type + + { TFmDisplayOutput } + + TFmDisplayOutput = class(TForm) + BtnClearSeries: TButton; + BtnCloseDisplay: TButton; + BtnUpdateChart: TButton; + BtnRun: TButton; + ChartToolset1: TChartToolset; + ChartToolset1PanClickTool1: TPanClickTool; + ChartToolset1PanDragTool1: TPanDragTool; + ChartToolset1ZoomClickTool1: TZoomClickTool; + ChartToolset1ZoomDragTool1: TZoomDragTool; + ChBAxisAutoScale: TAutoScaleAxisTransform; + ChBAxisLogarithm: TLogarithmAxisTransform; + ChBAxisTransforms: TChartAxisTransformations; + CbxParameters: TCheckBox; + CbxStates: TCheckBox; + ChLAxisAutoScale: TAutoScaleAxisTransform; + ChLAxisLogarithm: TLogarithmAxisTransform; + ChLAxisTransforms: TChartAxisTransformations; + ChOutput: TChart; + ChOutputLineSeries1: TLineSeries; + ChOutputLineSeries10: TLineSeries; + ChOutputLineSeries2: TLineSeries; + ChOutputLineSeries3: TLineSeries; + ChOutputLineSeries4: TLineSeries; + ChOutputLineSeries5: TLineSeries; + ChOutputLineSeries6: TLineSeries; + ChOutputLineSeries7: TLineSeries; + ChOutputLineSeries8: TLineSeries; + ChOutputLineSeries9: TLineSeries; + LblEdPar1: TLabeledEdit; + LblEdPar2: TLabeledEdit; + LblEdPar3: TLabeledEdit; + LblEdPar4: TLabeledEdit; + LblDirections: TLabel; + LbxSeriesSelect: TListBox; + ListChartSource1: TListChartSource; + ListChartSource10: TListChartSource; + ListChartSource2: TListChartSource; + ListChartSource3: TListChartSource; + ListChartSource4: TListChartSource; + ListChartSource5: TListChartSource; + ListChartSource6: TListChartSource; + ListChartSource7: TListChartSource; + ListChartSource8: TListChartSource; + ListChartSource9: TListChartSource; + MIYScale: TMenuItem; + MIYSelect: TMenuItem; + MIXScale: TMenuItem; + MIXSelect: TMenuItem; + MIShowTable: TMenuItem; + MIShowChart: TMenuItem; + MIShow: TMenuItem; + MIYaxis: TMenuItem; + MIUpdate: TMenuItem; + MIPrintChart: TMenuItem; + MIXaxis: TMenuItem; + MILoadFile: TMenuItem; + MIClose: TMenuItem; + MISaveOutput: TMenuItem; + MIChart: TMenuItem; + MmDisplay: TMainMenu; + MIWindow: TMenuItem; + PnlParameters: TPanel; + PnlRerun: TPanel; + PnlChartButtons: TPanel; + PnlTop: TPanel; + PnlTopRight: TPanel; + PnlBottom: TPanel; + PnlBottomLeft: TPanel; + PnlBottomRight: TPanel; + RgChartValues: TRadioGroup; + SgModelOutput: TStringGrid; + sLblPar1: TBoundLabel; + sLblPar2: TBoundLabel; + SLblPar3: TBoundLabel; + SplBottomLR: TSplitter; + SplTopBottom: TSplitter; + procedure BtnClearSeriesClick(Sender: TObject); + procedure BtnCloseDisplayClick(Sender: TObject); + procedure BtnRunClick(Sender: TObject); + procedure BtnUpdateChartClick(Sender: TObject); + procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure LblEdParKeyPress(Sender: TObject; var Key: char); + procedure MILoadFileClick(Sender: TObject); + procedure MISaveOutputClick(Sender: TObject); + procedure MIScaleClick(Sender: TObject); + procedure PnlTopRightClick(Sender: TObject); + procedure RgChartValuesClick(Sender: TObject); + procedure UpdateChart; + procedure lblParClick(sender: Tobject); + procedure LblEdParExit(sender: Tobject); + procedure refreshLblEdPar; + procedure cbxParamsClick(Sender: TObject); + procedure cbxStatesClick(Sender: TObject); + procedure MIShowChange(Sender: TObject); + procedure MISelectAxisClick(Sender: TObject); + private + { private declarations } + FFilename:String; + FCurrentAxis:TAxis; + FxAxis:string; + FDisplayStep:double; + FDisplayStyle:TDisplayStyle; + FInitialView:Boolean; + FNumberofSeries:integer; // Current number of series selected + FSeriestoPlot:plotarray; // The list of series to be plotted + procedure AddSeriestoPlot(ListBox: Tlistbox); + procedure RemoveSeriestoPlot(seriesname:string); + function GetColumnNumber(seriesname:string):integer; + public + { public declarations } + FirstWrite:Boolean; + CurrentRow: integer; + DisplayFilename:string; + AutoShowChart:Boolean; + DisplayStyle:TDisplayStyle; + property Filename:String read FFilename write FFilename; + property CurrentAxis:TAxis read FCurrentAxis write FCurrentAxis; + property displaystep:double read FDisplayStep write FDisplayStep; + property xAxis:string read FxAxis write FxAxis; + property NumberofSeries:integer read FNumberofSeries write FNumberofSeries; + procedure FillListBox(ListBox:TListBox); + procedure ClearSeriestoPlot(Listbox:TListBox); + procedure WriteOutputfromMem; + procedure WritePurgeOutputfromMem; + procedure ClearGrid; + procedure StoreResults(ctime:double; var darray:drivearray; var sarray:statearray; + var parray:processarray); + + end; + +var + FmDisplayOutput: TFmDisplayOutput; + +implementation + +uses frontend, ParamList, calculate, ReloadDlg, trouble, fileio, SeriesForm, ScaleDlg, options; +{$R *.lfm} + +{ TFmDisplayOutput } + +procedure TFmDisplayOutput.FormCreate(Sender: TObject); +var + i: integer; +begin + FInitialView := True; + FirstWrite := True; + chOutput.Title.Text.text := modeldef.modelname; // Chart title + + SgModelOutput.RowCount := FirstRow; + SgModelOutput.colcount := modeldef.numdrive + modeldef.numprocess + 1 +ModelDef.numstate; //***********HERE + // don't need numstate in the above count because the derivatives are no + // longer in the table so the count of the derivatives in numprocess takes + // care of numstate. + for i := 0 to SgModelOutput.colcount - 1 do SgModelOutput.cells[i,0] := inttostr(i); + SgModelOutput.cells[0,1] := 'Time'; // Column name + SgModelOutput.cells[0,2] := ModelDef.timeunit; // Column units + for i := 1 to modeldef.numdrive do // Add drivers to stringgrid + begin + SgModelOutput.cells[i,1] := drive[i].name; // Column name + SgModelOutput.cells[i,2] := drive[i].units; // Column units + end; + for i := 1 to modeldef.numstate do // Add state variables to grid + begin + SgModelOutput.cells[modeldef.numdrive + i,1] := stat[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive + i,2] := stat[i].units; // Column units + end; + for i := ModelDef.numstate + 1 to modeldef.numprocess do // Add process variables to grid + begin + SgModelOutput.cells[modeldef.numdrive + i,1] := proc[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive + i,2] := proc[i].units; // Column units + end; + for i := 1 to ModelDef.numstate do // Add derivatives to grid //************HERE + begin + SgModelOutput.cells[modeldef.numdrive+ modeldef.numprocess + i,1] := proc[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive+ modeldef.numprocess + i,2] := proc[i].units; // Column units + end; + + FillListBox(LbxSeriesSelect); + FxAxis := 'Time'; +// FDisplayStep := FmOptions.RunOptions.Time_step; +{ autoshowchart := false; } + CurrentRow := FirstRow; + DisplayFilename := 'Memory'; + DisplayStyle:=dsChart; + FmDisplayOutput.ActiveControl:=Lbxseriesselect; + + {$ifdef Darwin} + LblEdPar1.EditLabel.ShowAccelChar:=False; + LblEdPar1.EditLabel.Caption:= 'Parameter 1'; + LblEdPar2.EditLabel.ShowAccelChar:=False; + LblEdPar2.EditLabel.Caption := 'Parameter 2'; + LblEdPar3.EditLabel.ShowAccelChar:=False; + LblEdPar3.EditLabel.Caption := 'Parameter 3'; + LblEdPar4.EditLabel.ShowAccelChar:=False; + LblEdPar4.EditLabel.Caption := 'Parameter 4'; + {$endif} +end; + +procedure TFmDisplayOutput.FormResize(Sender: TObject); +var + numcol:double; +begin + if fInitialView then + begin + FmDisplayOutput.Height:=round(0.8*screen.Height); + FmDisplayOutput.Width := round(0.8*screen.width); + FmDisplayOutput.Top := 0; + fInitialView := False; + end; + if DisplayStyle = dsChart then + begin + PnlBottom.Constraints.MinHeight:=250; + PnlBottom.Height:=2*(FmDisplayOutput.Height div 5); + numcol := LbxSeriesSelect.ClientWidth/(8*stringlength); // assumes 8 units per character + if numcol < 1 then numcol := 1; + LbxSeriesSelect.Columns:=round(numcol); + end + else // Showing the table and not the chart + begin + // Shrink bottom panel and move the close buttom so it's visible + PnlBottom.Constraints.MinHeight:=0; + PnlBottom.Height:=BtnCloseDisplay.Height*3; + BtnCloseDisplay.Top := (PnlBottom.Height - BtnCloseDisplay.Height) div 2 - 1; + end; +end; + +procedure TFmDisplayOutput.FormShow(Sender: TObject); +begin + FmDisplayOutput.Caption := 'Model Output - File: ' + DisplayFilename; +// MessageDlg('number selected = ' + inttostr(LbxSeriesSelect.SelCount), mtInformation, [mbOK], 0); + if DisplayStyle = dsChart then + begin + SgModelOutput.Visible:=False; + PnlTop.Show; + PnlBottomLeft.Show; + BtnUpdateChart.Enabled := True; + BtnUpdateChart.Visible:=True; + BtnClearSeries.Enabled:=True; + BtnClearSeries.Visible:=True; + RgChartValues.Visible := True; + RgChartValues.Enabled := True; + end + else // Showing Data table not chart + begin + SgModelOutput.Visible:=True; + PnlTop.Hide; + PnlBottomLeft.Hide; + BtnUpdateChart.Enabled := False; + BtnUpdateChart.Visible:=False; + BtnClearSeries.Enabled:=False; + BtnClearSeries.Visible:=False; + RgChartValues.Visible := False; + RgChartValues.Enabled := False; + end; + FmDisplayOutput.FormResize(FmShellMain); + cbxParameters.Checked := DlgReload.cbParams.Checked; + cbxStates.Checked := DlgReload.cbState.Checked; +end; + + +procedure TFmDisplayOutput.LblEdParKeyPress(Sender: TObject; var Key: char); +begin + if (Key = Chr(13)) then LblEdParExit(Sender); +end; + +procedure TFmDisplayOutput.MILoadFileClick(Sender: TObject); +var + ttime:double; + tempdrive:drivearray; + tempstate:statearray; + tempprocess:processarray; +begin + tempdrive := drive; + tempstate := stat; + tempprocess := proc; + ClearGrid; + if FmShellMain.DlgOpenOutput.execute then + if FmShellMain.DlgOpenOutput.filename <> '' then + begin + DisplayFilename := FmShellMain.DlgOpenOutput.filename; + try + OpenOutputFile(FmShellMain.DlgOpenOutput.FileName, ModelDef.numdrive, drive, ModelDef.numstate, + stat, ModelDef.numprocess, proc, flread); + while not eof(outfile) do + begin + ReadOutputFile(ttime, ModelDef.numdrive, tempdrive, ModelDef.numstate, tempstate, + ModelDef.numprocess, tempprocess); + StoreResults(ttime, tempdrive, tempstate, tempprocess); + end; + finally + CloseOutputFile; + end; + end; +end; + +procedure TFmDisplayOutput.MISaveOutputClick(Sender: TObject); +begin + if DisplayFilename = 'Memory' then + begin + FmShellMain.ChooseParamFile(FmDisplayOutput); + WriteOutputfromMem; + end + else + MessageDlg('Data already saved in file ' + DisplayFilename, mtInformation, [mbOK], 0 ); +end; + +procedure TFmDisplayOutput.MIScaleClick(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIXScale' then + begin + CurrentAxis := axBottom; + end + else + begin + CurrentAxis := axLeft; + end; + DlgScale.ShowModal; +end; + +procedure TFmDisplayOutput.PnlTopRightClick(Sender: TObject); +begin + +end; + +procedure TFmDisplayOutput.RgChartValuesClick(Sender: TObject); +begin + +end; + +procedure TFmDisplayOutput.MISelectAxisClick(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIXSelect' then + CurrentAxis := axBottom + else + CurrentAxis := axLeft; + FmSeries.ShowModal; +end; + +procedure TFmDisplayOutput.MIShowChange(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIShowTable' then + DisplayStyle := dsTable + else + DisplayStyle := dsChart; + FmDisplayOutput.FormShow(Sender); +end; + +procedure TFmDisplayOutput.BtnCloseDisplayClick(Sender: TObject); +begin + FmDisplayOutput.Close; + DlgReload.cbParams.Checked := cbxParameters.Checked; + DlgReload.cbState.Checked := cbxStates.Checked; +end; + +procedure TFmDisplayOutput.BtnRunClick(Sender: TObject); +begin + if MessageDlg('Rerun model using current run options?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then + begin + SgModelOutput.BeginUpdate; + dlgReload.okBtn.click; + FmShellMain.btnRun.click; + if FmTrouble.visible then FmTrouble.BringToFront; + SgModelOutput.EndUpdate(True); + end; +end; + +procedure TFmDisplayOutput.BtnClearSeriesClick(Sender: TObject); +begin + ClearSeriestoPlot(LbxSeriesSelect); +end; + +procedure TFmDisplayOutput.BtnUpdateChartClick(Sender: TObject); +begin + UpdateChart; + refreshLblEdPar; +end; + +procedure TFmDisplayOutput.FormClose(Sender: TObject; + var CloseAction: TCloseAction); +begin + BtnCloseDisplayClick(sender); +end; + +procedure TFmDisplayOutput.UpdateChart; +var + i,j,xcolumn,ycolumn:integer; + CurrentChartSource:^TListChartSource; +begin +try + New(CurrentChartSource); + // Inactivate previous series + for i := 0 to MaxSeries - 1 do Choutput.series[i].active := false; + + // Put title on Bottom Axis + xcolumn := GetColumnNumber(xAxis); + ChOutput.BottomAxis.Title.Caption := SgModelOutput.cells[xcolumn,1]; + + // Clear the chart of previous plots +// for i:=0 to ChOutput.SeriesCount-1 do ChOutput.Series[i].Clear; +// If ChOutput.SeriesCount > 0 then ChOutput.ClearSeries; + ChOutputLineSeries1.Clear; + ChOutputLineSeries2.Clear; + ChOutputLineSeries3.Clear; + ChOutputLineSeries4.Clear; + ChOutputLineSeries5.Clear; + ChOutputLineSeries6.Clear; + ChOutputLineSeries7.Clear; + ChOutputLineSeries8.Clear; + ChOutputLineSeries9.Clear; + ChOutputLineSeries10.Clear; + + // Store series to plot in plotarray + AddSeriestoPlot(LbxSeriesSelect); + + // Activate the number of series to plot. + for i := 0 to FNumberofSeries - 1 do Choutput.series[i].active := true; + + // Check for divide by zero if relative change is selected + if (RgChartValues.ItemIndex=1) then + for j := 0 to FNumberofSeries - 1 do + begin + ycolumn := GetColumnNumber(FSeriestoPlot[j+1]); + if (RgChartValues.ItemIndex=1) and (strtofloat(SgModelOutput.Cells[ycolumn,FirstRow]) = 0) then // The if itemindex=1 needs to be here so that the code doesn't give the error for every series on the chart. It only needs to be corrected once. + begin + MessageDlg('Unable to display relative values because y0 is zero. Displaying actual values instead.', mtInformation, [mbOK], 0 ); + RgChartValues.ItemIndex:=0; + end; + end; + + // Add each series to the datasource. + for j := 0 to FNumberofSeries - 1 do + begin + ycolumn := GetColumnNumber(FSeriestoPlot[j+1]); + case j of + 0: begin + CurrentChartSource^:=ListChartSource1; + ChOutputLineSeries1.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 1: begin + CurrentChartSource^:=ListChartSource2; + ChOutputLineSeries2.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 2: begin + CurrentChartSource^:=ListChartSource3; + ChOutputLineSeries3.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 3: begin + CurrentChartSource^:=ListChartSource4; + ChOutputLineSeries4.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 4: begin + CurrentChartSource^:=ListChartSource5; + ChOutputLineSeries5.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 5: begin + CurrentChartSource^:=ListChartSource6; + ChOutputLineSeries6.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 6: begin + CurrentChartSource^:=ListChartSource7; + ChOutputLineSeries7.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 7: begin + CurrentChartSource^:=ListChartSource8; + ChOutputLineSeries8.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 8: begin + CurrentChartSource^:=ListChartSource9; + ChOutputLineSeries9.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 9: begin + CurrentChartSource^:=ListChartSource10; + ChOutputLineSeries10.Title := SgModelOutput.Cells[ycolumn,1]; + end; + end; + for i := FirstRow to SgModelOutput.RowCount - 1 do + begin + case RgChartValues.ItemIndex of + 0: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])); + 1: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])/strtofloat(SgModelOutput.Cells[ycolumn,FirstRow])); + 2: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])-strtofloat(SgModelOutput.cells[ycolumn,FirstRow])); + end; + end; + end; + refreshLblEdPar; +finally + Dispose(CurrentChartSource); +end; +end; + +procedure TFmDisplayOutput.FillListBox(ListBox:TListBox); +var + i:integer; +begin + ListBox.Items.Clear; + ListBox.Items.Add('Time'); + for i := 1 to ModelDef.numdrive do // Add driver names to listbox + ListBox.Items.Add(drive[i].name); + for i := 1 to ModelDef.numstate do // Add state variable names to listbox + ListBox.Items.Add(stat[i].name); + for i := ModelDef.numstate + 1 to ModelDef.numprocess do // Add process variable names to listbox + ListBox.Items.Add(proc[i].name); +end; + +// Adds a series to the FSeriestoPlot array +procedure TFmDisplayOutput.AddSeriestoPlot(ListBox: Tlistbox); +var + index:integer; +begin + FNumberofSeries := 0; + for index := 0 to Listbox.Items.Count - 1 do + begin + if Listbox.Selected[index] then + begin + if FNumberofSeries = MaxSeries then + MessageDlg('Cannot display series. Maximum is 10 series.', mtError, [mbOK], 0) + else + begin + FNumberofSeries := FNumberofSeries + 1; + FSeriestoPlot[FNumberofSeries] := ListBox.Items[index]; + end; + end; + end; +end; + +// Removes a series from the FSeriestoPlot array +procedure TFmDisplayOutput.RemoveSeriestoPlot(seriesname:string); +var + temparray:plotarray; + i,index:integer; +begin + index := 1; + temparray := FSeriestoPlot; + for i := 1 to FNumberofSeries do + begin + if temparray[i] = seriesname then + index := i; + end; + for i := index to FNumberofSeries - 1 do + begin + FSeriestoPlot[i] := temparray[i + 1]; + end; + FNumberofSeries := FNumberofSeries - 1; +end; + +// Clears the selections in a TListbox +procedure TFmDisplayOutput.ClearSeriestoPlot(Listbox:TListBox); +var + i:integer; +begin + for i := 0 to Listbox.Items.Count - 1 do + begin + if Listbox.Selected[i] then + begin + RemoveSeriestoPlot(Listbox.Items[i]); + Listbox.Selected[i] := False; + end; + end; +end; + +// Clear old data from the StringGrid to prevent data overlap when new data is added. +procedure TFmDisplayOutput.ClearGrid; +var + i,j:integer; +begin + for i := FirstRow to SgModelOutput.RowCount - 1 do + for j := 0 to SgModelOutput.ColCount - 1 do + SgModelOutput.Cells[j,i] := ''; // Set all cells to empty strings + SgModelOutput.RowCount := FirstRow; // Decrease size of grid + CurrentRow := FirstRow; +end; + +// Get the stringgrid column number for the variable in seriesname +function TFmDisplayOutput.GetColumnNumber(seriesname:string):integer; +var + j,num:integer; +begin + num := -1; + for j := 0 to SgModelOutput.Colcount - 1 do + begin + if SgModelOutput.Cells[j,1] = seriesname then num := j; + end; + GetColumnNumber := num; +end; + +procedure TFmDisplayOutput.lblParClick(sender: Tobject); +var + tempName : string; +begin +// Getting the number of the label, i.e. 1, 2, 3, or 4 so fmParamList knows which label/edit to modify + tempName := (sender as tcontrol).name; + delete(tempName, 1, 8); + fmParamList.whichEdparselected := strToInt(tempName); + fmParamList.showmodal; +end; + +{ Updates the parameter value shown in the maskedit. } +procedure TFmDisplayOutput.refreshLblEdPar; +var + thisLblEdit : tLabeledEdit; + i : integer; + parIndex : integer; + temp: string; +begin + with PnlParameters do + begin + for i := 0 to controlCount-1 do //look at all the LabeledEdits + begin + if controls[i] is TLabeledEdit then + begin + thisLblEdit := controls[i] as TLabeledEdit; + temp := thisLblEdit.EditLabel.Caption; + if pos('Parameter', temp) = 0 then + begin + parIndex := fmCalculate.getArrayIndex(vtParameter, thisLblEdit.EditLabel.Caption); + thisLblEdit.Text := floatToStr(par[parIndex].value); + end; + end; + end; + end; +end; + +{ Stores the new values of the parameters in the global array, par. } +procedure TFmDisplayOutput.LblEdParExit(Sender: TObject); +var + thisLblEd : TlabeledEdit; + parIndex : integer; +begin + thisLblEd := sender as TlabeledEdit; + if thisLblEd.modified then + begin + parIndex := fmCalculate.getArrayIndex(vtParameter, thisLblEd.editlabel.Caption); + try + par[parIndex].value := strToFloat(thisLblEd.text); + except + messageDlg('Please choose a number', mtWarning, [mbOK], 0); + FmDisplayOutput.ActiveControl := thisLblEd; + end; + refreshLblEdPar; + end; +end; + +procedure TFmDisplayOutput.cbxParamsClick(Sender: TObject); +begin + DlgReload.CbParams.Checked:=cbxParameters.Checked; +end; + +procedure TFmDisplayOutput.cbxStatesClick(Sender: TObject); +begin + DlgReload.cbState.Checked:=cbxStates.Checked; +end; + +procedure TFmDisplayOutput.WriteOutputfromMem; +var + i, j:integer; + tempstring: string; + outfile: textfile; +begin + assignfile(outfile, outfilename); + if (FmOptions.RunOptions.AppendOutputFile) and (not FirstWrite) then + append(outfile) + else + rewrite(outfile); // Create a new file + try + for j := 1 to SgModelOutput.RowCount - 1 do // Start at 1 to skip column numbers + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + finally + closefile(outfile); + end; +end; + +procedure TFmDisplayOutput.WritePurgeOutputfromMem; +var + i, j:integer; + tempstring: string; + outfile: textfile; +begin + assignfile(outfile, outfilename); + try + if FirstWrite then + begin + rewrite(outfile); // Create a new file + for j := 1 to SgModelOutput.RowCount - 1 do // Start at 1 to skip column numbers + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + FirstWrite := False; + end + else + begin + append(outfile); // Open existing file for writing + for j := 3 to SgModelOutput.RowCount - 1 do // Start at 3 to skip column numbers and variable names and units + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + end; + ClearGrid; + finally + closefile(outfile); + end; +end; + +procedure TFmDisplayOutput.StoreResults(ctime:double; var darray:drivearray; var sarray:statearray; + var parray:processarray); +var + j: integer; +begin + SgModelOutput.rowcount := SgModelOutput.rowcount + 1; + SgModelOutput.Cells[0,currentrow] := format('%g',[ctime]); // Write time + for j:= 1 to ModelDef.numdrive // Write drivers + do SgModelOutput.Cells[j,currentrow] := format('%.20g',[darray[j].value]); + + for j:= 1 to ModelDef.numstate // Write state variables + do SgModelOutput.Cells[ModelDef.numdrive + j,currentrow] + := format('%.20g',[sarray[j].value]); + for j:= ModelDef.numstate + 1 to ModelDef.numprocess // Write process variables + do SgModelOutput.Cells[ModelDef.numdrive + j, currentrow] + := format('%.20g',[parray[j].value]); + for j:= 1 to ModelDef.numstate do // Derivatives //****************HERE + SgModelOutput.Cells[ModelDef.numdrive + ModelDef.numprocess + j, currentrow] + := format('%.20g',[parray[j].value]); + currentrow := currentrow + 1; + if SgModelOutput.RowCount>=100000 then + begin + WritePurgeOutputFromMem; + FmShellMain.LargeOutput := True; + end; +end; + +end. + + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Menus, + ExtCtrls, StdCtrls, Grids, TAGraph, TASeries, + TASources, TATools, TACustomSource, TALegendPanel, TATransformations, stypes; + +const + Maxseries = 10; + FirstRow = 3; + +type + plotarray=array[1..MaxSeries] of string; + +type + + { TFmDisplayOutput } + + TFmDisplayOutput = class(TForm) + BtnClearSeries: TButton; + BtnCloseDisplay: TButton; + BtnUpdateChart: TButton; + BtnRun: TButton; + ChartToolset1: TChartToolset; + ChartToolset1PanClickTool1: TPanClickTool; + ChartToolset1PanDragTool1: TPanDragTool; + ChartToolset1ZoomClickTool1: TZoomClickTool; + ChartToolset1ZoomDragTool1: TZoomDragTool; + ChBAxisAutoScale: TAutoScaleAxisTransform; + ChBAxisLogarithm: TLogarithmAxisTransform; + ChBAxisTransforms: TChartAxisTransformations; + CbxParameters: TCheckBox; + CbxStates: TCheckBox; + ChLAxisAutoScale: TAutoScaleAxisTransform; + ChLAxisLogarithm: TLogarithmAxisTransform; + ChLAxisTransforms: TChartAxisTransformations; + ChOutput: TChart; + ChOutputLineSeries1: TLineSeries; + ChOutputLineSeries10: TLineSeries; + ChOutputLineSeries2: TLineSeries; + ChOutputLineSeries3: TLineSeries; + ChOutputLineSeries4: TLineSeries; + ChOutputLineSeries5: TLineSeries; + ChOutputLineSeries6: TLineSeries; + ChOutputLineSeries7: TLineSeries; + ChOutputLineSeries8: TLineSeries; + ChOutputLineSeries9: TLineSeries; + LblEdPar1: TLabeledEdit; + LblEdPar2: TLabeledEdit; + LblEdPar3: TLabeledEdit; + LblEdPar4: TLabeledEdit; + LblDirections: TLabel; + LbxSeriesSelect: TListBox; + ListChartSource1: TListChartSource; + ListChartSource10: TListChartSource; + ListChartSource2: TListChartSource; + ListChartSource3: TListChartSource; + ListChartSource4: TListChartSource; + ListChartSource5: TListChartSource; + ListChartSource6: TListChartSource; + ListChartSource7: TListChartSource; + ListChartSource8: TListChartSource; + ListChartSource9: TListChartSource; + MIYScale: TMenuItem; + MIYSelect: TMenuItem; + MIXScale: TMenuItem; + MIXSelect: TMenuItem; + MIShowTable: TMenuItem; + MIShowChart: TMenuItem; + MIShow: TMenuItem; + MIYaxis: TMenuItem; + MIUpdate: TMenuItem; + MIPrintChart: TMenuItem; + MIXaxis: TMenuItem; + MILoadFile: TMenuItem; + MIClose: TMenuItem; + MISaveOutput: TMenuItem; + MIChart: TMenuItem; + MmDisplay: TMainMenu; + MIWindow: TMenuItem; + PnlParameters: TPanel; + PnlRerun: TPanel; + PnlChartButtons: TPanel; + PnlTop: TPanel; + PnlTopRight: TPanel; + PnlBottom: TPanel; + PnlBottomLeft: TPanel; + PnlBottomRight: TPanel; + RgChartValues: TRadioGroup; + SgModelOutput: TStringGrid; + sLblPar1: TBoundLabel; + sLblPar2: TBoundLabel; + SLblPar3: TBoundLabel; + SplBottomLR: TSplitter; + SplTopBottom: TSplitter; + procedure BtnClearSeriesClick(Sender: TObject); + procedure BtnCloseDisplayClick(Sender: TObject); + procedure BtnRunClick(Sender: TObject); + procedure BtnUpdateChartClick(Sender: TObject); + procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure LblEdParKeyPress(Sender: TObject; var Key: char); + procedure MILoadFileClick(Sender: TObject); + procedure MISaveOutputClick(Sender: TObject); + procedure MIScaleClick(Sender: TObject); + procedure PnlTopRightClick(Sender: TObject); + procedure RgChartValuesClick(Sender: TObject); + procedure UpdateChart; + procedure lblParClick(sender: Tobject); + procedure LblEdParExit(sender: Tobject); + procedure refreshLblEdPar; + procedure cbxParamsClick(Sender: TObject); + procedure cbxStatesClick(Sender: TObject); + procedure MIShowChange(Sender: TObject); + procedure MISelectAxisClick(Sender: TObject); + private + { private declarations } + FFilename:String; + FCurrentAxis:TAxis; + FxAxis:string; + FDisplayStep:double; + FDisplayStyle:TDisplayStyle; + FInitialView:Boolean; + FNumberofSeries:integer; // Current number of series selected + FSeriestoPlot:plotarray; // The list of series to be plotted + procedure AddSeriestoPlot(ListBox: Tlistbox); + procedure RemoveSeriestoPlot(seriesname:string); + function GetColumnNumber(seriesname:string):integer; + public + { public declarations } + FirstWrite:Boolean; + CurrentRow: integer; + DisplayFilename:string; + AutoShowChart:Boolean; + property Filename:String read FFilename write FFilename; + property CurrentAxis:TAxis read FCurrentAxis write FCurrentAxis; + property displaystep:double read FDisplayStep write FDisplayStep; + property xAxis:string read FxAxis write FxAxis; + property DisplayStyle:TDisplayStyle read FDisplayStyle write FDisplayStyle; + property NumberofSeries:integer read FNumberofSeries write FNumberofSeries; + procedure FillListBox(ListBox:TListBox); + procedure ClearSeriestoPlot(Listbox:TListBox); + procedure WriteOutputfromMem; + procedure WritePurgeOutputfromMem; + procedure ClearGrid; + procedure StoreResults(ctime:double; var darray:drivearray; var sarray:statearray; + var parray:processarray); + + end; + +var + FmDisplayOutput: TFmDisplayOutput; + +implementation + +uses frontend, ParamList, calculate, ReloadDlg, trouble, fileio, SeriesForm, ScaleDlg, options; +{$R *.lfm} + +{ TFmDisplayOutput } + +procedure TFmDisplayOutput.FormCreate(Sender: TObject); +var + i: integer; +begin + FInitialView := True; + FirstWrite := True; + chOutput.Title.Text.text := modeldef.modelname; // Chart title + + SgModelOutput.RowCount := FirstRow; + SgModelOutput.colcount := modeldef.numdrive + modeldef.numprocess + 1 + modeldef.numstate; // ***********HERE************ + // don't need numstate in the above count because the derivatives are no + // longer in the table so the count of the derivatives in numprocess takes + // care of numstate. + for i := 0 to SgModelOutput.colcount - 1 do SgModelOutput.cells[i,0] := inttostr(i); + SgModelOutput.cells[0,1] := 'Time'; // Column name + SgModelOutput.cells[0,2] := ModelDef.timeunit; // Column units + for i := 1 to modeldef.numdrive do // Add drivers to stringgrid + begin + SgModelOutput.cells[i,1] := drive[i].name; // Column name + SgModelOutput.cells[i,2] := drive[i].units; // Column units + end; + for i := 1 to modeldef.numstate do // Add state variables to grid + begin + SgModelOutput.cells[modeldef.numdrive + i,1] := stat[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive + i,2] := stat[i].units; // Column units + end; + for i := ModelDef.numstate + 1 to modeldef.numprocess do // Add process variables to grid + begin + SgModelOutput.cells[modeldef.numdrive + i,1] := proc[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive + i,2] := proc[i].units; // Column units + end; + for i := 1 to ModelDef.numstate do // Add derivatives to grid + begin + SgModelOutput.cells[modeldef.numdrive + modeldef.numprocess+ i,1] := proc[i].name; // Column name + SgModelOutput.cells[modeldef.numdrive + modeldef.numprocess+i,2] := proc[i].units; // Column units + end; + + FillListBox(LbxSeriesSelect); + FxAxis := 'Time'; +// FDisplayStep := FmOptions.RunOptions.Time_step; +{ autoshowchart := false; } + CurrentRow := FirstRow; + DisplayFilename := 'Memory'; + DisplayStyle:=dsChart; + FmDisplayOutput.ActiveControl:=Lbxseriesselect; + + {$ifdef Darwin} + LblEdPar1.EditLabel.ShowAccelChar:=False; + LblEdPar1.EditLabel.Caption:= 'Parameter 1'; + LblEdPar2.EditLabel.ShowAccelChar:=False; + LblEdPar2.EditLabel.Caption := 'Parameter 2'; + LblEdPar3.EditLabel.ShowAccelChar:=False; + LblEdPar3.EditLabel.Caption := 'Parameter 3'; + LblEdPar4.EditLabel.ShowAccelChar:=False; + LblEdPar4.EditLabel.Caption := 'Parameter 4'; + {$endif} +end; + +procedure TFmDisplayOutput.FormResize(Sender: TObject); +var + numcol:double; +begin + if fInitialView then + begin + FmDisplayOutput.Height:=round(0.8*screen.Height); + FmDisplayOutput.Width := round(0.8*screen.width); + FmDisplayOutput.Top := 0; + fInitialView := False; + end; + if DisplayStyle = dsChart then + begin + PnlBottom.Constraints.MinHeight:=250; + PnlBottom.Height:=2*(FmDisplayOutput.Height div 5); + numcol := LbxSeriesSelect.ClientWidth/(8*stringlength); // assumes 8 units per character + if numcol < 1 then numcol := 1; + LbxSeriesSelect.Columns:=round(numcol); + end + else // Showing the table and not the chart + begin + // Shrink bottom panel and move the close buttom so it's visible + PnlBottom.Constraints.MinHeight:=0; + PnlBottom.Height:=BtnCloseDisplay.Height*3; + BtnCloseDisplay.Top := (PnlBottom.Height - BtnCloseDisplay.Height) div 2 - 1; + end; +end; + +procedure TFmDisplayOutput.FormShow(Sender: TObject); +begin + FmDisplayOutput.Caption := 'Model Output - File: ' + DisplayFilename; +// MessageDlg('number selected = ' + inttostr(LbxSeriesSelect.SelCount), mtInformation, [mbOK], 0); + if DisplayStyle = dsChart then + begin + SgModelOutput.Visible:=False; + PnlTop.Show; + PnlBottomLeft.Show; + BtnUpdateChart.Enabled := True; + BtnUpdateChart.Visible:=True; + BtnClearSeries.Enabled:=True; + BtnClearSeries.Visible:=True; + RgChartValues.Visible := True; + RgChartValues.Enabled := True; + end + else // Showing Data table not chart + begin + SgModelOutput.Visible:=True; + PnlTop.Hide; + PnlBottomLeft.Hide; + BtnUpdateChart.Enabled := False; + BtnUpdateChart.Visible:=False; + BtnClearSeries.Enabled:=False; + BtnClearSeries.Visible:=False; + RgChartValues.Visible := False; + RgChartValues.Enabled := False; + end; + FmDisplayOutput.FormResize(FmShellMain); + cbxParameters.Checked := DlgReload.cbParams.Checked; + cbxStates.Checked := DlgReload.cbState.Checked; +end; + + +procedure TFmDisplayOutput.LblEdParKeyPress(Sender: TObject; var Key: char); +begin + if (Key = Chr(13)) then LblEdParExit(Sender); +end; + +procedure TFmDisplayOutput.MILoadFileClick(Sender: TObject); +var + ttime:double; + tempdrive:drivearray; + tempstate:statearray; + tempprocess:processarray; +begin + tempdrive := drive; + tempstate := stat; + tempprocess := proc; + ClearGrid; + if FmShellMain.DlgOpenOutput.execute then + if FmShellMain.DlgOpenOutput.filename <> '' then + begin + DisplayFilename := FmShellMain.DlgOpenOutput.filename; + try + OpenOutputFile(FmShellMain.DlgOpenOutput.FileName, ModelDef.numdrive, drive, ModelDef.numstate, + stat, ModelDef.numprocess, proc, flread); + while not eof(outfile) do + begin + ReadOutputFile(ttime, ModelDef.numdrive, tempdrive, ModelDef.numstate, tempstate, + ModelDef.numprocess, tempprocess); + StoreResults(ttime, tempdrive, tempstate, tempprocess); + end; + finally + CloseOutputFile; + end; + end; +end; + +procedure TFmDisplayOutput.MISaveOutputClick(Sender: TObject); +begin + if DisplayFilename = 'Memory' then + begin + FmShellMain.ChooseParamFile(FmDisplayOutput); + WriteOutputfromMem; + end + else + MessageDlg('Data already saved in file ' + DisplayFilename, mtInformation, [mbOK], 0 ); +end; + +procedure TFmDisplayOutput.MIScaleClick(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIXScale' then + begin + CurrentAxis := axBottom; + end + else + begin + CurrentAxis := axLeft; + end; + DlgScale.ShowModal; +end; + +procedure TFmDisplayOutput.PnlTopRightClick(Sender: TObject); +begin + +end; + +procedure TFmDisplayOutput.RgChartValuesClick(Sender: TObject); +begin + +end; + +procedure TFmDisplayOutput.MISelectAxisClick(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIXSelect' then + CurrentAxis := axBottom + else + CurrentAxis := axLeft; + FmSeries.ShowModal; +end; + +procedure TFmDisplayOutput.MIShowChange(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIShowTable' then + DisplayStyle := dsTable + else + DisplayStyle := dsChart; + FmDisplayOutput.FormShow(Sender); +end; + +procedure TFmDisplayOutput.BtnCloseDisplayClick(Sender: TObject); +begin + FmDisplayOutput.Close; + DlgReload.cbParams.Checked := cbxParameters.Checked; + DlgReload.cbState.Checked := cbxStates.Checked; +end; + +procedure TFmDisplayOutput.BtnRunClick(Sender: TObject); +begin + if MessageDlg('Rerun model using current run options?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then + begin + SgModelOutput.BeginUpdate; + dlgReload.okBtn.click; + FmShellMain.btnRun.click; + if FmTrouble.visible then FmTrouble.BringToFront; + SgModelOutput.EndUpdate(True); + end; +end; + +procedure TFmDisplayOutput.BtnClearSeriesClick(Sender: TObject); +begin + ClearSeriestoPlot(LbxSeriesSelect); +end; + +procedure TFmDisplayOutput.BtnUpdateChartClick(Sender: TObject); +begin + UpdateChart; + refreshLblEdPar; +end; + +procedure TFmDisplayOutput.FormClose(Sender: TObject; + var CloseAction: TCloseAction); +begin + BtnCloseDisplayClick(sender); +end; + +procedure TFmDisplayOutput.UpdateChart; +var + i,j,xcolumn,ycolumn:integer; + CurrentChartSource:^TListChartSource; +begin +try + New(CurrentChartSource); + // Inactivate previous series + for i := 0 to MaxSeries - 1 do Choutput.series[i].active := false; + + // Put title on Bottom Axis + xcolumn := GetColumnNumber(xAxis); + ChOutput.BottomAxis.Title.Caption := SgModelOutput.cells[xcolumn,1]; + + // Clear the chart of previous plots +// for i:=0 to ChOutput.SeriesCount-1 do ChOutput.Series[i].Clear; +// If ChOutput.SeriesCount > 0 then ChOutput.ClearSeries; + ChOutputLineSeries1.Clear; + ChOutputLineSeries2.Clear; + ChOutputLineSeries3.Clear; + ChOutputLineSeries4.Clear; + ChOutputLineSeries5.Clear; + ChOutputLineSeries6.Clear; + ChOutputLineSeries7.Clear; + ChOutputLineSeries8.Clear; + ChOutputLineSeries9.Clear; + ChOutputLineSeries10.Clear; + + // Store series to plot in plotarray + AddSeriestoPlot(LbxSeriesSelect); + + // Activate the number of series to plot. + for i := 0 to FNumberofSeries - 1 do Choutput.series[i].active := true; + + // Check for divide by zero if relative change is selected + if (RgChartValues.ItemIndex=1) then + for j := 0 to FNumberofSeries - 1 do + begin + ycolumn := GetColumnNumber(FSeriestoPlot[j+1]); + if (RgChartValues.ItemIndex=1) and (strtofloat(SgModelOutput.Cells[ycolumn,FirstRow]) = 0) then // The if itemindex=1 needs to be here so that the code doesn't give the error for every series on the chart. It only needs to be corrected once. + begin + MessageDlg('Unable to display relative values because y0 is zero. Displaying actual values instead.', mtInformation, [mbOK], 0 ); + RgChartValues.ItemIndex:=0; + end; + end; + + // Add each series to the datasource. + for j := 0 to FNumberofSeries - 1 do + begin + ycolumn := GetColumnNumber(FSeriestoPlot[j+1]); + case j of + 0: begin + CurrentChartSource^:=ListChartSource1; + ChOutputLineSeries1.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 1: begin + CurrentChartSource^:=ListChartSource2; + ChOutputLineSeries2.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 2: begin + CurrentChartSource^:=ListChartSource3; + ChOutputLineSeries3.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 3: begin + CurrentChartSource^:=ListChartSource4; + ChOutputLineSeries4.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 4: begin + CurrentChartSource^:=ListChartSource5; + ChOutputLineSeries5.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 5: begin + CurrentChartSource^:=ListChartSource6; + ChOutputLineSeries6.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 6: begin + CurrentChartSource^:=ListChartSource7; + ChOutputLineSeries7.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 7: begin + CurrentChartSource^:=ListChartSource8; + ChOutputLineSeries8.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 8: begin + CurrentChartSource^:=ListChartSource9; + ChOutputLineSeries9.Title := SgModelOutput.Cells[ycolumn,1]; + end; + 9: begin + CurrentChartSource^:=ListChartSource10; + ChOutputLineSeries10.Title := SgModelOutput.Cells[ycolumn,1]; + end; + end; + for i := FirstRow to SgModelOutput.RowCount - 1 do + begin + case RgChartValues.ItemIndex of + 0: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])); + 1: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])/strtofloat(SgModelOutput.Cells[ycolumn,FirstRow])); + 2: CurrentChartSource.add(strtofloat(SgModelOutput.Cells[xcolumn,i]), + strtofloat(SgModelOutput.Cells[ycolumn,i])-strtofloat(SgModelOutput.cells[ycolumn,FirstRow])); + end; + end; + end; + refreshLblEdPar; +finally + Dispose(CurrentChartSource); +end; +end; + +procedure TFmDisplayOutput.FillListBox(ListBox:TListBox); +var + i:integer; +begin + ListBox.Items.Clear; + ListBox.Items.Add('Time'); + for i := 1 to ModelDef.numdrive do // Add driver names to listbox + ListBox.Items.Add(drive[i].name); + for i := 1 to ModelDef.numstate do // Add state variable names to listbox + ListBox.Items.Add(stat[i].name); + for i := ModelDef.numstate + 1 to ModelDef.numprocess do // Add process variable names to listbox + ListBox.Items.Add(proc[i].name); +end; + +// Adds a series to the FSeriestoPlot array +procedure TFmDisplayOutput.AddSeriestoPlot(ListBox: Tlistbox); +var + index:integer; +begin + FNumberofSeries := 0; + for index := 0 to Listbox.Items.Count - 1 do + begin + if Listbox.Selected[index] then + begin + if FNumberofSeries = MaxSeries then + MessageDlg('Cannot display series. Maximum is 10 series.', mtError, [mbOK], 0) + else + begin + FNumberofSeries := FNumberofSeries + 1; + FSeriestoPlot[FNumberofSeries] := ListBox.Items[index]; + end; + end; + end; +end; + +// Removes a series from the FSeriestoPlot array +procedure TFmDisplayOutput.RemoveSeriestoPlot(seriesname:string); +var + temparray:plotarray; + i,index:integer; +begin + index := 1; + temparray := FSeriestoPlot; + for i := 1 to FNumberofSeries do + begin + if temparray[i] = seriesname then + index := i; + end; + for i := index to FNumberofSeries - 1 do + begin + FSeriestoPlot[i] := temparray[i + 1]; + end; + FNumberofSeries := FNumberofSeries - 1; +end; + +// Clears the selections in a TListbox +procedure TFmDisplayOutput.ClearSeriestoPlot(Listbox:TListBox); +var + i:integer; +begin + for i := 0 to Listbox.Items.Count - 1 do + begin + if Listbox.Selected[i] then + begin + RemoveSeriestoPlot(Listbox.Items[i]); + Listbox.Selected[i] := False; + end; + end; +end; + +// Clear old data from the StringGrid to prevent data overlap when new data is added. +procedure TFmDisplayOutput.ClearGrid; +var + i,j:integer; +begin + for i := FirstRow to SgModelOutput.RowCount - 1 do + for j := 0 to SgModelOutput.ColCount - 1 do + SgModelOutput.Cells[j,i] := ''; // Set all cells to empty strings + SgModelOutput.RowCount := FirstRow; // Decrease size of grid + CurrentRow := FirstRow; +end; + +// Get the stringgrid column number for the variable in seriesname +function TFmDisplayOutput.GetColumnNumber(seriesname:string):integer; +var + j,num:integer; +begin + num := -1; + for j := 0 to SgModelOutput.Colcount - 1 do + begin + if SgModelOutput.Cells[j,1] = seriesname then num := j; + end; + GetColumnNumber := num; +end; + +procedure TFmDisplayOutput.lblParClick(sender: Tobject); +var + tempName : string; +begin +// Getting the number of the label, i.e. 1, 2, 3, or 4 so fmParamList knows which label/edit to modify + tempName := (sender as tcontrol).name; + delete(tempName, 1, 8); + fmParamList.whichEdparselected := strToInt(tempName); + fmParamList.showmodal; +end; + +{ Updates the parameter value shown in the maskedit. } +procedure TFmDisplayOutput.refreshLblEdPar; +var + thisLblEdit : tLabeledEdit; + i : integer; + parIndex : integer; + temp: string; +begin + with PnlParameters do + begin + for i := 0 to controlCount-1 do //look at all the LabeledEdits + begin + if controls[i] is TLabeledEdit then + begin + thisLblEdit := controls[i] as TLabeledEdit; + temp := thisLblEdit.EditLabel.Caption; + if pos('Parameter', temp) = 0 then + begin + parIndex := fmCalculate.getArrayIndex(vtParameter, thisLblEdit.EditLabel.Caption); + thisLblEdit.Text := floatToStr(par[parIndex].value); + end; + end; + end; + end; +end; + +{ Stores the new values of the parameters in the global array, par. } +procedure TFmDisplayOutput.LblEdParExit(Sender: TObject); +var + thisLblEd : TlabeledEdit; + parIndex : integer; +begin + thisLblEd := sender as TlabeledEdit; + if thisLblEd.modified then + begin + parIndex := fmCalculate.getArrayIndex(vtParameter, thisLblEd.editlabel.Caption); + try + par[parIndex].value := strToFloat(thisLblEd.text); + except + messageDlg('Please choose a number', mtWarning, [mbOK], 0); + FmDisplayOutput.ActiveControl := thisLblEd; + end; + refreshLblEdPar; + end; +end; + +procedure TFmDisplayOutput.cbxParamsClick(Sender: TObject); +begin + DlgReload.CbParams.Checked:=cbxParameters.Checked; +end; + +procedure TFmDisplayOutput.cbxStatesClick(Sender: TObject); +begin + DlgReload.cbState.Checked:=cbxStates.Checked; +end; + +procedure TFmDisplayOutput.WriteOutputfromMem; +var + i, j:integer; + tempstring: string; + outfile: textfile; +begin + assignfile(outfile, outfilename); + if (FmOptions.RunOptions.AppendOutputFile) and (not FirstWrite) then + append(outfile) + else + rewrite(outfile); // Create a new file + try + for j := 1 to SgModelOutput.RowCount - 1 do // Start at 1 to skip column numbers + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + finally + closefile(outfile); + end; +end; + +procedure TFmDisplayOutput.WritePurgeOutputfromMem; +var + i, j:integer; + tempstring: string; + outfile: textfile; +begin + assignfile(outfile, outfilename); + try + if FirstWrite then + begin + rewrite(outfile); // Create a new file + for j := 1 to SgModelOutput.RowCount - 1 do // Start at 1 to skip column numbers + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + FirstWrite := False; + end + else + begin + append(outfile); // Open existing file for writing + for j := 3 to SgModelOutput.RowCount - 1 do // Start at 3 to skip column numbers and variable names and units + begin + tempstring := SgModelOutput.Cells[0, j]; + for i := 1 to SgModelOutput.ColCount - 1 do tempstring := tempstring + ', ' + SgModelOutput.Cells[i, j]; + writeln(outfile, tempstring); + end; + end; + ClearGrid; + finally + closefile(outfile); + end; +end; + +procedure TFmDisplayOutput.StoreResults(ctime:double; var darray:drivearray; var sarray:statearray; + var parray:processarray); +var + j: integer; +begin + SgModelOutput.rowcount := SgModelOutput.rowcount + 1; + SgModelOutput.Cells[0,currentrow] := format('%g',[ctime]); // Write time + for j:= 1 to ModelDef.numdrive // Write drivers + do SgModelOutput.Cells[j,currentrow] := format('%.8g',[darray[j].value]); + + for j:= 1 to ModelDef.numstate // Write state variables + do SgModelOutput.Cells[ModelDef.numdrive + j,currentrow] + := format('%.8g',[sarray[j].value]); + for j:= ModelDef.numstate + 1 to ModelDef.numprocess // Write process variables + do SgModelOutput.Cells[ModelDef.numdrive + j, currentrow] + := format('%.8g',[parray[j].value]); + currentrow := currentrow + 1; + if SgModelOutput.RowCount>=100000 then + begin + WritePurgeOutputFromMem; + FmShellMain.LargeOutput := True; + end; +end; + +end. + diff --git a/modelshell/equations.pas b/modelshell/equations.pas new file mode 100644 index 0000000..da8e302 --- /dev/null +++ b/modelshell/equations.pas @@ -0,0 +1,1166 @@ +{ This unit defines the structure of the model. There are four functions. The + first function, called counts, defines the number, names, and units of the + model, the state variables, the process variables, the driver variables and + the parameters. The second function, called processes, is the actual equations + which make up the model. The third function, derivs, calculates the + derivatives of state variables. And the fourth function, parcount, is used to + automatically number the parameters consecutively. + The state variables, driver variables, process variables and parameters are + all stored in global arrays, called stat, drive, proc, and par, respectively. + The function counts accesses the global arrays directly but the other functions + operate on copies of the global arrays. } +unit equations; + +interface + +uses stypes, math, sysutils; + +PROCEDURE counts; +PROCEDURE processes(time:double; dtime:double; var tdrive:drivearray; + var tpar:paramarray; var tstat:statearray; + var tproc:processarray; CalculateDiscrete:Boolean); +PROCEDURE derivs(t, drt:double; var tdrive:drivearray; var tpar:paramarray; + var statevalue:yValueArray; VAR dydt:yValueArray); +function ParCount(processnum:integer) : integer; + +var + tproc:processarray; + tstat:statearray; + sensflag:boolean; + newyear:Boolean = false; + DayofYear: double = 0; + h: array[1..4,1..4] of double; + +implementation + +uses frontend, calculate, options; + + { Do not make modifcations above this line. } +{*****************************************************************************} + +{ This procedure defines the model. The number of parameters, state, driver and + process variables are all set in this procedure. The model name, version + number and time unit are also set here. This procedure accesses the global + arrays containing the the parameters, state, driver and process variables and + the global structure ModelDef directly, to save memory space. } +PROCEDURE counts; +var + i,npar,CurrentProc:integer; +begin +{ Set the modelname, version and time unit. } +ModelDef.modelname := 'substitutable resource'; +ModelDef.versionnumber := '1.0.0'; +ModelDef.timeunit := 'day'; +ModelDef.contactperson := 'Ed'; +ModelDef.contactaddress1 := 'Ecosystems'; +ModelDef.contactaddress2 := 'MBL'; +ModelDef.contactaddress3 := 'Woods Hole'; + +{ Set the number of state variables in the model. The maximum number of state + variables is maxstate, in unit stypes. } +ModelDef.numstate := 16; + +{ Enter the name, units and symbol for each state variable. The maximum length + of the state variable name is 17 characters and the maximum length for units + and symbol is stringlength (specified in unit stypes) characters. } + + +with stat[1] do + begin + name:='Plant C'; units:='g C m-2'; symbol:='BC'; + end; + +with stat[2] do + begin + name:='Plant N'; units:='g N m-2'; symbol:='BN'; + end; + +with stat[3] do + begin + name:='Avail N 1'; units:='g N m-2'; symbol:='N1'; + end; + +with stat[4] do + begin + name:='Avail N 2'; units:='g N m-2'; symbol:='N2'; + end; + +with stat[5] do + begin + name:='Avail N 3'; units:='g N m-2'; symbol:='N3'; + end; + +with stat[6] do + begin + name:='Avail N 4'; units:='g N m-2'; symbol:='N4'; + end; + +with stat[7] do + begin + name:='Effort C'; units:='effort'; symbol:='VC'; + end; + +with stat[8] do + begin + name:='Effort N'; units:='effort'; symbol:='VN'; + end; + +with stat[9] do + begin + name:='sub effort 1'; units:='effort'; symbol:='v1'; + end; + +with stat[10] do + begin + name:='sub effort 2'; units:='effort'; symbol:='v2'; + end; + +with stat[11] do + begin + name:='sub effort 3'; units:='effort'; symbol:='v3'; + end; + +with stat[12] do + begin + name:='sub effort 4'; units:='effort'; symbol:='v4'; + end; + +with stat[13] do + begin + name:='Int up C'; units:='g C m-2 day-1'; symbol:='UCbar'; + end; + +with stat[14] do + begin + name:='Int up N'; units:='g N m-2 day-1'; symbol:='UNbar'; + end; + +with stat[15] do + begin + name:='Int rec C'; units:='g C m-2 day-1'; symbol:='RCbar'; + end; + +with stat[16] do + begin + name:='Int rec N'; units:='g N m-2 day-1'; symbol:='RNbar'; + end; + +{ Set the total number of processes in the model. The first numstate processes + are the derivatives of the state variables. The maximum number of processes is + maxparam, in unit stypes. } +ModelDef.numprocess := ModelDef.numstate + 29; + +{ For each process, set proc[i].parameters equal to the number of parameters + associated with that process, and set IsDiscrete to true or false. After each + process, set the name, units, and symbol for all parameters associated with + that process. Note that Parcount returns the total number of parameters in + all previous processes. } + +CurrentProc := ModelDef.numstate + 1; +With proc[CurrentProc] do + begin + name := 'Photosynthesis'; + units := 'g C m-2 day-1'; + symbol := 'UC'; + parameters := 4; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='max Ps'; units:='g C m-2 day-1'; symbol:='Pmax'; + end; +with par[npar + 2] do + begin + name:='half sat'; units:='MJ m-2 day-1'; symbol:='eta'; + end; +with par[npar + 3] do + begin + name:='beers coef'; units:='m2 m-2'; symbol:='kI'; + end; +with par[npar + 4] do + begin + name:='spec leaf area'; units:='m-2 g-1 C'; symbol:='lambda'; + end; + +CurrentProc := ModelDef.numstate + 2; +With proc[CurrentProc] do + begin + name := 'Total N up'; + units := 'g N m-2 day-1'; + symbol := 'UN'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 3; +With proc[CurrentProc] do + begin + name := 'N up 1'; + units := 'g N m-2 day-1'; + symbol := 'UN1'; + parameters := 2; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='N up rate 1'; units:='g N g-1 C day-1'; symbol:='gN1'; + end; +with par[npar + 2] do + begin + name:='half sat 1'; units:='g N m-2'; symbol:='kN1'; + end; + +CurrentProc := ModelDef.numstate + 4; +With proc[CurrentProc] do + begin + name := 'N up 2'; + units := 'g N m-2 day-1'; + symbol := 'UN2'; + parameters := 2; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='N up rate 2'; units:='g N g-1 C day-1'; symbol:='gN2'; + end; +with par[npar + 2] do + begin + name:='half sat 2'; units:='g N m-2'; symbol:='kN2'; + end; + +CurrentProc := ModelDef.numstate + 5; +With proc[CurrentProc] do + begin + name := 'N up 3'; + units := 'g N m-2 day-1'; + symbol := 'UN3'; + parameters := 2; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='N up rate 3'; units:='g N g-1 C day-1'; symbol:='gN3'; + end; +with par[npar + 2] do + begin + name:='half sat 3'; units:='g N m-2'; symbol:='kN3'; + end; + +CurrentProc := ModelDef.numstate + 6; +With proc[CurrentProc] do + begin + name := 'N up 4'; + units := 'g N m-2 day-1'; + symbol := 'UN4'; + parameters := 2; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='N up rate 4'; units:='g N g-1 C day-1'; symbol:='gN4'; + end; +with par[npar + 2] do + begin + name:='half sat 4'; units:='g N m-2'; symbol:='kN4'; + end; + +CurrentProc := ModelDef.numstate + 7; +With proc[CurrentProc] do + begin + name := 'Respiration'; + units := 'g C m-2 day-1'; + symbol := 'RC'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='resp rate const'; units:='day-1'; symbol:='rmC'; + end; + +CurrentProc := ModelDef.numstate + 8; +With proc[CurrentProc] do + begin + name := 'C turnover'; + units := 'g C m-2 day-1'; + symbol := 'TC'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='C turnover rate const'; units:='day-1'; symbol:='mC'; + end; + +CurrentProc := ModelDef.numstate + 9; +With proc[CurrentProc] do + begin + name := 'N turnover'; + units := 'g N m-2 day-1'; + symbol := 'TN'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='N turnover rate const'; units:='day-1'; symbol:='mN'; + end; + +CurrentProc := ModelDef.numstate + 10; +With proc[CurrentProc] do + begin + name := 'PHI'; + units := 'none'; + symbol := 'PHI'; + parameters := 4; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='acclim rate'; units:='day-1'; symbol:='a'; + end; +with par[npar + 2] do + begin + name:='sub acclim rate'; units:='day-1'; symbol:='omega'; + end; +with par[npar + 3] do + begin + name:='eps0'; units:='none'; symbol:='eps0'; + end; +with par[npar + 4] do + begin + name:='int const'; units:='day-1'; symbol:='rho'; + end; + +CurrentProc := ModelDef.numstate + 11; +With proc[CurrentProc] do + begin + name := 'psiC'; + units := 'g C m-2 day-1'; + symbol := 'psiC'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 12; +With proc[CurrentProc] do + begin + name := 'psiN'; + units := 'g N m-2 day-1'; + symbol := 'psiN'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 13; +With proc[CurrentProc] do + begin + name := 'allometry'; + units := 'g C m-2'; + symbol := 'S'; + parameters := 2; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='alpha'; units:='m2 g-1 C'; symbol:='alpha'; + end; +with par[npar + 2] do + begin + name:='gamma'; units:='m2 g-1 C'; symbol:='gamma'; + end; + +CurrentProc := ModelDef.numstate + 14; +With proc[CurrentProc] do + begin + name := 'stoichiometry'; + units := 'none'; + symbol := 'THETA'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='opt C:N'; units:='g C g-1 N'; symbol:='qB'; + end; + +CurrentProc := ModelDef.numstate + 15; +With proc[CurrentProc] do + begin + name := 'max yield'; + units := 'g N m-2 effort-1 day-1'; + symbol := 'ymax'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 16; +With proc[CurrentProc] do + begin + name := 'beta'; + units := 'none'; + symbol := 'beta'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 17; +With proc[CurrentProc] do + begin + name := 'eps1'; + units := 'effort'; + symbol := 'eps1'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 18; +With proc[CurrentProc] do + begin + name := 'eps2'; + units := 'effort'; + symbol := 'eps2'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 19; +With proc[CurrentProc] do + begin + name := 'eps3'; + units := 'effort'; + symbol := 'eps3'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 20; +With proc[CurrentProc] do + begin + name := 'eps4'; + units := 'effort'; + symbol := 'eps4'; + parameters := 0; + ptype := ptGroup1; + end; + +CurrentProc := ModelDef.numstate + 21; +With proc[CurrentProc] do + begin + name := 'N leach 1'; + units := 'g N m-2 day-1'; + symbol := 'LN1'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='loss rate cosnt1'; units:='day-1'; symbol:='tau1'; + end; + +CurrentProc := ModelDef.numstate + 22; +With proc[CurrentProc] do + begin + name := 'N leach 2'; + units := 'g N m-2 day-1'; + symbol := 'LN2'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='loss rate cosnt2'; units:='day-1'; symbol:='tau2'; + end; + +CurrentProc := ModelDef.numstate + 23; +With proc[CurrentProc] do + begin + name := 'N leach 3'; + units := 'g N m-2 day-1'; + symbol := 'LN3'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='loss rate cosnt3'; units:='day-1'; symbol:='tau3'; + end; + +CurrentProc := ModelDef.numstate + 24; +With proc[CurrentProc] do + begin + name := 'N leach 4'; + units := 'g N m-2 day-1'; + symbol := 'LN4'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='loss rate cosnt4'; units:='day-1'; symbol:='tau4'; + end; + +CurrentProc := ModelDef.numstate + 25; +With proc[CurrentProc] do + begin + name := 'yeild 1'; + units := 'g N m-2 effort-1 day-1'; + symbol := 'y1'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='cost 1'; units:='g c g-1 N'; symbol:='phi1'; + end; + +CurrentProc := ModelDef.numstate + 26; +With proc[CurrentProc] do + begin + name := 'yeild 2'; + units := 'g N m-2 effort-1 day-1'; + symbol := 'y2'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='cost 2'; units:='g c g-1 N'; symbol:='phi2'; + end; + +CurrentProc := ModelDef.numstate + 27; +With proc[CurrentProc] do + begin + name := 'yeild 3'; + units := 'g N m-2 effort-1 day-1'; + symbol := 'y3'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='cost 3'; units:='g c g-1 N'; symbol:='phi3'; + end; + +CurrentProc := ModelDef.numstate + 28; +With proc[CurrentProc] do + begin + name := 'yeild 4'; + units := 'g N m-2 effort-1 day-1'; + symbol := 'y4'; + parameters := 1; + ptype := ptGroup1; + end; +npar:=ParCount(CurrentProc); +with par[npar + 1] do + begin + name:='cost 4'; units:='g c g-1 N'; symbol:='phi4'; + end; + +CurrentProc := ModelDef.numstate + 29; +With proc[CurrentProc] do + begin + name := 'dUCdVC'; + units := 'g C m-2 day-1 effort-1'; + symbol := 'dUCdVC'; + parameters := 0; + ptype := ptGroup1; + end; + +{ Set the total number of drivers in the model. The maximum number of drivers is + maxdrive, in unit stypes. } +ModelDef.numdrive := 5; + +{ Set the names, units, and symbols of the drivers. The maximum length for the + name, units and symbol is 20 characters. } + +with drive[1] do + begin + name:='irradiance'; units:='MJ m-2 day-1'; symbol:='I'; + end; + +with drive[2] do + begin + name:='N input 1'; units:='g N m-2 day-1'; symbol:='IN1'; + end; + +with drive[3] do + begin + name:='N input 2'; units:='g N m-2 day-1'; symbol:='IN2'; + end; + +with drive[4] do + begin + name:='N input 3'; units:='g N m-2 day-1'; symbol:='IN3'; + end; + +with drive[5] do + begin + name:='N input 4'; units:='g N m-2 day-1'; symbol:='IN4'; + end; + +{ The first numstate processes are the derivatives of the state variables. The + code sets the names, units and symbols accordingly.} +for i:= 1 to ModelDef.numstate do proc[i].name:='d'+stat[i].name+'dt'; +for i:= 1 to ModelDef.numstate do proc[i].units := stat[i].units + 't-1'; +for i:= 1 to ModelDef.numstate do proc[i].symbol := 'd' + stat[i].symbol + 'dt'; + +{ Code to sum up the total number of parameters in the model. Do not change the + next few lines. } +ModelDef.numparam := 0; +for i := 1 to ModelDef.NumProcess do + ModelDef.numparam := ModelDef.numparam + proc[i].parameters; + +end; // counts procedure + + +{ A procedure to calculate the value of all states and processes at the current + time. This function accesses time, state variables and process variables by + reference, ie it uses the same array as the calling routine. It does not use + the global variables time, stat and proc because values calculated during + integration might later be discarded. It does access the global variables par, + drive and ModelDef directly because those values are not modified. + + The model equations are written using variable names which correspond to the + actual name instead of using the global arrays (i.e. SoilWater instead of + stat[7].value). This makes it necessary to switch all values into local + variables, do all the calculations and then put everything back into the + global variables. Lengthy but worth it in terms of readability of the code. } + +// Choose either GlobalPs, ArcticPs, or none here so the appropriate Ps model is compiled below. +{$DEFINE none} + +PROCEDURE processes(time:double; dtime:double; var tdrive:drivearray; + var tpar:paramarray; var tstat:statearray; + var tproc:processarray; CalculateDiscrete:Boolean); +{$IFDEF GlobalPs} +const +// Global Ps parameters + x1 = 11.04; x2 = 0.03; + x5 = 0.216; x6 = 0.6; + x7 = 3.332; x8 = 0.004; + x9 = 1.549; x10 = 1.156; + gammastar = 0; kCO2 = 995.4; } +{$ENDIF} + +// Modify constant above (line above "procedure processes..." line )to specify +// which Ps model and it's constants should be compiled. Choosing a Ps model +// automatically includes the Et and Misc constants (i.e. Gem is assumed). + +{$IFDEF ArcticPs} +const +// Arctic Ps parameters +x1 = 0.192; x2 = 0.125; +x5 = 2.196; x6 = 50.41; +x7 = 0.161; x8 = 14.78; +x9 = 1.146; +gammastar = 0.468; kCO2 = 500.3; +{$ENDIF} + +{$IFDEF ArcticPs OR GlobalPs} +//const +// General Et parameters +aE1 = 0.0004; aE2 = 150; aE3 = 1.21; aE4 = 6.11262E5; + +// Other constants +cp = 1.012E-9; //specific heat air MJ kg-1 oC-1 +sigmaSB = 4.9e-9; //stefan-Boltzmann MJ m-2 day-1 K-4 +S0 = 117.5; //solar constant MJ m-2 day-1 +bHI1 =0.23; +bHI2 =0.48; +mw = 2.99; //kg h2o MJ-1 +alphaMS = 2; //mm oC-1 day-1 } +{$ENDIF} + +var +{ List the variable names you are going to use here. Generally, this list + includes all the symbols you defined in the procedure counts above. The order + in which you list them does not matter. } +{States} +BC, dBCdt, +BN, dBNdt, +N1, dN1dt, +N2, dN2dt, +N3, dN3dt, +N4, dN4dt, +VC, dVCdt, +VN, dVNdt, +v1, dv1dt, +v2, dv2dt, +v3, dv3dt, +v4, dv4dt, +UCbar, dUCbardt, +UNbar, dUNbardt, +RCbar, dRCbardt, +RNbar, dRNbardt, + +{processes and associated parameters} +UC, Pmax, eta, kI, lambda, +UN, +UN1, gN1, kN1, +UN2, gN2, kN2, +UN3, gN3, kN3, +UN4, gN4, kN4, +RC, rmC, +TC, mC, +TN, mN, +PHI, a, omega, eps0, rho, +psiC, +psiN, +S, alpha, gamma, +THETA, qB, +ymax, +beta, +eps1, +eps2, +eps3, +eps4, +LN1, tau1, +LN2, tau2, +LN3, tau3, +LN4, tau4, +y1, phi1, +y2, phi2, +y3, phi3, +y4, phi4, +dUCdVC, + +{drivers} +I, +IN1, +IN2, +IN3, +IN4 + +{Other double} + +:double; {Final double} + +{Other integers} +npar, j, jj, kk, ll, tnum:integer; + +{ Boolean Variables } + + +{ Functions or procedures } + +begin +{ Copy the drivers from the global array, drive, into the local variables. } +I := tdrive[1].value; +IN1 := tdrive[2].value; +IN2 := tdrive[3].value; +IN3 := tdrive[4].value; +IN4 := tdrive[5].value; + +{ Copy the state variables from the global array into the local variables. } +BC := tstat[1].value; +BN := tstat[2].value; +N1 := tstat[3].value; +N2 := tstat[4].value; +N3 := tstat[5].value; +N4 := tstat[6].value; +VC := tstat[7].value; +VN := tstat[8].value; +v1 := tstat[9].value; +v2 := tstat[10].value; +v3 := tstat[11].value; +v4 := tstat[12].value; +UCbar := tstat[13].value; +UNbar := tstat[14].value; +RCbar := tstat[15].value; +RNbar := tstat[16].value; + +{ And now copy the parameters into the local variables. No need to copy the + processes from the global array into local variables. Process values will be + calculated by this procedure. + + Copy the parameters for each process separately using the function ParCount + to keep track of the number of parameters in the preceeding processes. + npar now contains the number of parameters in the preceding processes. + copy the value of the first parameter of this process into it's local + variable } +npar:=ParCount(ModelDef.numstate + 1); +Pmax := par[npar + 1].value; +eta := par[npar + 2].value; +kI := par[npar + 3].value; +lambda := par[npar + 4].value; + +npar:=ParCount(ModelDef.numstate + 3); +gN1 := par[npar + 1].value; +kN1 := par[npar + 2].value; + +npar:=ParCount(ModelDef.numstate + 4); +gN2 := par[npar + 1].value; +kN2 := par[npar + 2].value; + +npar:=ParCount(ModelDef.numstate + 5); +gN3 := par[npar + 1].value; +kN3 := par[npar + 2].value; + +npar:=ParCount(ModelDef.numstate + 6); +gN4 := par[npar + 1].value; +kN4 := par[npar + 2].value; + +npar:=ParCount(ModelDef.numstate + 7); +rmC := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 8); +mC := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 9); +mN := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 10); +a := par[npar + 1].value; +omega := par[npar + 2].value; +eps0 := par[npar + 3].value; +rho := par[npar + 4].value; + +npar:=ParCount(ModelDef.numstate + 13); +alpha := par[npar + 1].value; +gamma := par[npar + 2].value; + +npar:=ParCount(ModelDef.numstate + 14); +qB := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 21); +tau1 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 22); +tau2 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 23); +tau3 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 24); +tau4 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 25); +phi1 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 26); +phi2 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 27); +phi3 := par[npar + 1].value; + +npar:=ParCount(ModelDef.numstate + 28); +phi4 := par[npar + 1].value; + +dBCdt := -999; +dBNdt := -999; +dN1dt := -999; +dN2dt := -999; +dN3dt := -999; +dN4dt := -999; +dVCdt := -999; +dVNdt := -999; +dv1dt := -999; +dv2dt := -999; +dv3dt := -999; +dv4dt := -999; +dUCbardt := -999; +dUNbardt := -999; +dRCbardt := -999; +dRNbardt := -999; +UC := -999; +UN := -999; +UN1 := -999; +UN2 := -999; +UN3 := -999; +UN4 := -999; +RC := -999; +TC := -999; +TN := -999; +PHI := -999; +psiC := -999; +psiN := -999; +S := -999; +THETA := -999; +ymax := -999; +beta := -999; +eps1 := -999; +eps2 := -999; +eps3 := -999; +eps4 := -999; +LN1 := -999; +LN2 := -999; +LN3 := -999; +LN4 := -999; +y1 := -999; +y2 := -999; +y3 := -999; +y4 := -999; +dUCdVC := -999; + +{ Enter the equations to calculate the processes here, using the local variable + names defined above. } + + +S:=VC+VN; +VC:=VC/S; +VN:=1-VC; +S:=v1+v2+v3+v4; +v1:=v1/S; +v2:=v2/S; +v3:=v3/S; +V4:=1-v1-v2-v3; + +S:=BC*((alpha*BC+1)/(gamma*BC+1)); +THETA:=BC/qB/BN; +UC:=(Pmax/kI)*ln((eta+I)/(eta+I*exp(-kI*lambda*S*VC))); +UN1:=S*gN1*N1*VN*v1/(kN1+N1); +UN2:=S*gN2*N2*VN*v2/(kN2+N2); +UN3:=S*gN3*N3*VN*v3/(kN3+N3); +UN4:=S*gN4*N4*VN*v4/(kN4+N4); +UN:=UN1+UN2+UN3+UN4; +RC:=rmC*THETA*BC+phi1*UN1+phi2*UN2+phi3*UN3+phi4*UN4; +TC:=mC*BC; +TN:=mN*BN/THETA; +PHI:=power(UCbar/RCbar,VC)*power(UNbar/RNbar,VN); +psiC:=((rmC+mC)*BC+phi1*UN1+phi2*UN2+phi3*UN3+phi4*UN4)/THETA; +psiN:=mN*THETA*BN; +LN1:=tau1*N1; +LN2:=tau2*N2; +LN3:=tau3*N3; +LN4:=tau4*N4; +dUCdVC:=lambda*S*Pmax*I*exp(-kI*lambda*S*VC)/(eta+I*exp(-kI*lambda*S*VC)); +y1:=S*gN1*N1*VN/(kN1+N1); +y1:=y1/(VN+y1*phi1/dUCdVC); +y2:=S*gN2*N2*VN/(kN2+N2); +y2:=y2/(VN+y2*phi2/dUCdVC); +y3:=S*gN3*N3*VN/(kN3+N3); +y3:=y3/(VN+y3*phi3/dUCdVC); +y4:=S*gN4*N4*VN/(kN4+N4); +y4:=y4/(VN+y4*phi4/dUCdVC); +ymax:=max(y1,max(y2,max(y3,y4))); +if y1=ymax then eps1:=eps0 else eps1:=0; +if y2=ymax then eps2:=eps0 else eps2:=0; +if y3=ymax then eps3:=eps0 else eps3:=0; +if y4=ymax then eps4:=eps0 else eps4:=0; +beta:=ymax*(max(v1,eps1)+max(v2,eps2)+max(v3,eps3)+max(v4,eps4)); +beta:=(y1*max(v1,eps1)+y2*max(v2,eps2)+y3*max(v3,eps3)+y4*max(v4,eps4))/beta; +if CalculateDiscrete then +begin +// Add any discrete processes here +end; //discrete processes + + +{ Now calculate the derivatives of the state variables. If the holdConstant + portion of the state variable is set to true then set the derivative equal to + zero. } +if (tstat[1].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dBCdt := 0 +else + dBCdt := UC-TC-RC; + +if (tstat[2].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dBNdt := 0 +else + dBNdt := UN-TN; + +if (tstat[3].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dN1dt := 0 +else + dN1dt := IN1-UN1-LN1; + +if (tstat[4].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dN2dt := 0 +else + dN2dt := IN2-UN2-LN2; + +if (tstat[5].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dN3dt := 0 +else + dN3dt := IN3-UN3-LN3; + +if (tstat[6].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dN4dt := 0 +else + dN4dt := IN4-UN4-LN4; + +if (tstat[7].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dVCdt := 0 +else + dVCdt := a*ln(PHI*RCbar/UCbar)*VC; + +if (tstat[8].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dVNdt := 0 +else + dVNdt := a*ln(PHI*RNbar/UNbar)*VN; + +if (tstat[9].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dv1dt := 0 +else + dv1dt := omega*(y1/ymax-beta)*max(v1,eps1); + +if (tstat[10].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dv2dt := 0 +else + dv2dt := omega*(y2/ymax-beta)*max(v2,eps2); + +if (tstat[11].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dv3dt := 0 +else + dv3dt := omega*(y3/ymax-beta)*max(v3,eps3); + +if (tstat[12].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dv4dt := 0 +else + dv4dt := omega*(y4/ymax-beta)*max(v4,eps4); + +if (tstat[13].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dUCbardt := 0 +else + dUCbardt := rho*(UC-UCbar); + +if (tstat[14].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dUNbardt := 0 +else + dUNbardt := rho*(UN-UNbar); + +if (tstat[15].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dRCbardt := 0 +else + dRCbardt := rho*(psiC-RCbar); + +if (tstat[16].HoldConstant) and (FmOptions.RunOptions.HoldStatesConstant) then + dRNbardt := 0 +else + dRNbardt := rho*(psiN-RNbar); + + +{ Now that the calculations are complete, assign everything back into the arrays + so the rest of the code can access the values calculated here. (Local variables + are destroyed at the end of the procedure). + + Put the state variables back into the global arrays in case the state variable + was manually changed in this procedure (e.g. discrete state variables or steady state + calculations). } +tstat[1].value := BC; +tstat[2].value := BN; +tstat[3].value := N1; +tstat[4].value := N2; +tstat[5].value := N3; +tstat[6].value := N4; +tstat[7].value := VC; +tstat[8].value := VN; +tstat[9].value := v1; +tstat[10].value := v2; +tstat[11].value := v3; +tstat[12].value := v4; +tstat[13].value := UCbar; +tstat[14].value := UNbar; +tstat[15].value := RCbar; +tstat[16].value := RNbar; + +{ Put all process values into process variable array. The first numstate + processes are the derivatives of the state variables (Calculated above).} +tproc[1].value := dBCdt; +tproc[2].value := dBNdt; +tproc[3].value := dN1dt; +tproc[4].value := dN2dt; +tproc[5].value := dN3dt; +tproc[6].value := dN4dt; +tproc[7].value := dVCdt; +tproc[8].value := dVNdt; +tproc[9].value := dv1dt; +tproc[10].value := dv2dt; +tproc[11].value := dv3dt; +tproc[12].value := dv4dt; +tproc[13].value := dUCbardt; +tproc[14].value := dUNbardt; +tproc[15].value := dRCbardt; +tproc[16].value := dRNbardt; + +{ Now the remaining processes. Be sure to number the processes the same here as + you did in the procedure counts above. } +tproc[ModelDef.numstate + 1].value := UC; +tproc[ModelDef.numstate + 2].value := UN; +tproc[ModelDef.numstate + 3].value := UN1; +tproc[ModelDef.numstate + 4].value := UN2; +tproc[ModelDef.numstate + 5].value := UN3; +tproc[ModelDef.numstate + 6].value := UN4; +tproc[ModelDef.numstate + 7].value := RC; +tproc[ModelDef.numstate + 8].value := TC; +tproc[ModelDef.numstate + 9].value := TN; +tproc[ModelDef.numstate + 10].value := PHI; +tproc[ModelDef.numstate + 11].value := psiC; +tproc[ModelDef.numstate + 12].value := psiN; +tproc[ModelDef.numstate + 13].value := S; +tproc[ModelDef.numstate + 14].value := THETA; +tproc[ModelDef.numstate + 15].value := ymax; +tproc[ModelDef.numstate + 16].value := beta; +tproc[ModelDef.numstate + 17].value := eps1; +tproc[ModelDef.numstate + 18].value := eps2; +tproc[ModelDef.numstate + 19].value := eps3; +tproc[ModelDef.numstate + 20].value := eps4; +tproc[ModelDef.numstate + 21].value := LN1; +tproc[ModelDef.numstate + 22].value := LN2; +tproc[ModelDef.numstate + 23].value := LN3; +tproc[ModelDef.numstate + 24].value := LN4; +tproc[ModelDef.numstate + 25].value := y1; +tproc[ModelDef.numstate + 26].value := y2; +tproc[ModelDef.numstate + 27].value := y3; +tproc[ModelDef.numstate + 28].value := y4; +tproc[ModelDef.numstate + 29].value := dUCdVC; + +end; // End of processes procedure + + + { Do not make any modifications to code below this line. } +{****************************************************************************} + + +{This function counts the parameters in all processes less than processnum.} +function ParCount(processnum:integer) : integer; +var + NumberofParams, counter : integer; +begin + NumberofParams := 0; + for counter := ModelDef.numstate + 1 to processnum - 1 do + NumberofParams := NumberofParams + proc[counter].parameters; + ParCount := NumberofParams; +end; // end of parcount function + +{ This procedure supplies the derivatives of the state variables to the + integrator. Since the integrator deals only with the values of the variables + and not there names, units or the state field HoldConstant, this procedure + copies the state values into a temporary state array and copies the value of + HoldConstant into the temporary state array and passes this temporary state + array to the procedure processes. } +PROCEDURE derivs(t, drt:double; var tdrive:drivearray; var tpar:paramarray; + var statevalue:yValueArray; VAR dydt:yValueArray); +var + i:integer; + tempproc:processarray; + tempstate:statearray; +begin + tempstate := stat; // Copy names, units and HoldConstant to tempstate + // Copy current values of state variables into tempstate + for i := 1 to ModelDef.numstate do tempstate[i].value := statevalue[i]; + // Calculate the process values + processes(t, drt, tdrive, tpar, tempstate, tempproc, false); + // Put process values into dydt array to get passed back to the integrator. + for i:= 1 to ModelDef.numstate do dydt[i]:=tempproc[i].value; +end; // end of derivs procedure + +end. diff --git a/modelshell/fileio.pas b/modelshell/fileio.pas new file mode 100644 index 0000000..8c5daf1 --- /dev/null +++ b/modelshell/fileio.pas @@ -0,0 +1,1310 @@ +{ Contains the code for all file input and output. All I/O should be done using + these procedures. There is one exception. In the note.pas file the drivers are + written to the driver file directly from the memo component. It is done that + way because the memo component has a function to write to a file and using + that function is easier then converting the text in the memo to the correct + form for the writedriverfile function. } +unit fileio; + +interface + +uses sysutils, classes, Dialogs, stypes, frontend, Options, Lazfileutils; + +type TAction = (flRead, flWrite); + EFileError = Class(Exception); + +// Model I/O +function ReadParamFile(var filename:string; const npar:integer; + var parray:paramarray; const nstat:integer; + var sarray:statearray; var Tresid:double):Boolean; +procedure WriteParamFile(filename:string; const npar:integer; + var parray:paramarray; const nstat:integer; var sarray:statearray; + var Tresid:double); +procedure GetCurrentDrivers(CurrTime:double; var CurrDrivers:DriveArray); +function openDriverFile(filename:string; dlist:Tstringlist):Boolean; +function WriteDriverFile(filename:string; dlist:Tstringlist):Boolean; +procedure OpenOutputFile(filename:string; const ndrive:integer; const darray:drivearray; + const numstat:integer; var sarray:statearray; const numproc:integer; + var parray:processarray; Action:TAction); +function ReadOutputFile(var time:double; const numdrive:integer; var darray: + drivearray; const numstat:integer; var sarray:statearray; const + numproc:integer; var parray:processarray):Boolean; +function WriteOutputFile(time:double; const numstat:integer; + var sarray:statearray; const numproc:integer; + var parray:processarray):Boolean; +procedure CloseOutputFile; + +// Batch I/O +procedure OpenBatchFile(filename:string); +function ReadBatchFile(var paramname, drivername, outputname:string; var begintime, + endtime:double; var tstat:statearray; var opt:TRunOptions):Boolean; +procedure CloseBatchFile; +procedure OpenLogFile(filename, batchfile:string); +function WriteLogFile(filename:string; outputname:string; + StatusMessage:string):Boolean; +procedure CloseLogFile; + +// Sensitivity I/O +procedure OpenListFile(filename:string); +function ReadListFile(var paramfilename, driverfilename, paramname:string; + var newparamvalue:double):Boolean; +procedure CloseListFile; +procedure OpenMeasFile(filename:string); +function ReadMeasFile(var thisline:string): Boolean; +procedure CloseMeasFile; +procedure OpenSensOutFile(filename:string); +function WriteSensOutFile(var paramfilename, paramname:string; + var newparamvalue:double; TestStatus:string; ResidCL, ResidCW, + ResidCR, ResidNL, ResidNW, ResidNR, ResidCT, ResidNT: + double):Boolean; +procedure CloseSensOutFile; + +// Modelshell I/O +procedure ReadModelDef(filename:string; var tempmodeldef:Tmodeldef; + var tstat:statearray; var tpar:paramarray; var tproc:processarray; + var tdrive:drivearray); + +// Ensemble Kalman Filter I/O +procedure OpenTextFile(filename:string; var filehandle:textfile); +function ReadTextFile(var filehandle: textfile; var aline:string):Boolean; +function CheckforOpenFiles(filename: string): Boolean; +function WriteKalmanOutFile(filename:string; var outdata:TKstate; saveuncorrupted:Boolean):Boolean; + + +// General procedures +procedure ChangeExtension(var filename:string; NewExt:string); +procedure RemoveSpaces(var somestring:string); +function ParCount(processnum:integer) : integer; + +var + last_time,next_time:double; + last_drive,next_drive: drivearray; + driverfile:textfile; + driverlist:Tstringlist; + currdline:integer; + timeFound:boolean; + outfile, outfile2:textfile; + batchfile:textfile; + logfile:textfile; + listfile:textfile; + sensOutfile:textfile; + calOutfile:textfile; + measfile:textfile; + ParamFileVersion:string; + +implementation + +// Parameter File I/O + +{ The parameter file is a space delimited ASCII file containing the parameter + values and the initial values of the state variables. Each line of the file + contains one parameter or state variable. The first item on the line is the + variable name (a string up to stringlength characters), the second item is the numerical + value of the item and the final item on the line is the units of the parameter + or state variable (also a string up to stringlength characters long). } + +{ This function reads the entire parameter file if it exists or creates a new + empty file. } +function ReadParamFile(var filename:string; const npar:integer; + var parray:paramarray; const nstat:integer; + var sarray:statearray; var Tresid:double):Boolean; +var + i,charnum:integer; + dum, dum2, dum3, dum4, tempvalue:string[stringlength+1]; + tempstring1, tempstring2 :string; + paramfile:textfile; + StatesRead, ParamsRead: Boolean; +begin + ReadParamFile := False; + assignfile(paramfile,filename); + NeedToSavePar := False; + reset(paramfile); + readln(paramfile, ParamFileVersion); + SetLength(tempstring1, stringlength + 2); + strlcopy(PChar(tempstring1), PChar(ParamFileVersion), stringlength + 1); + { Delete any spaces in the model name read from the parameter file and any + spaces in a copy of the modelname field of modeldef. This is to prevent + the invalid parameter file version error due to differences in spacing. } + tempstring1 := trim(tempstring1); + charnum := pos(' ',tempstring1); + while charnum <> 0 do + begin + delete(tempstring1,charnum,1); + charnum := pos(' ',tempstring1); + end; + // And now delete the spaces from the modelname. + tempstring2 := ModelDef.modelname; + charnum := pos(' ',tempstring2); + while charnum <> 0 do + begin + delete(tempstring2,charnum,1); + charnum := pos(' ',tempstring2); + end; + + // Compare the 2 strings containing the modelname. + if StrIComp(PChar(tempstring1),PChar(tempstring2)) <> 0 then + begin + reset(paramfile); + ParamFileVersion := 'Unknown'; // Model names don't match + end + else // Model names do match, now extract the version number and compare + begin + delete(ParamFileVersion,1,stringlength + 1); + ParamFileVersion := trim(ParamFileVersion); + charnum := pos(' ',ParamFileVersion); + if charnum <> 0 then + delete(ParamFileVersion,charnum,Length(ParamFileVersion)-charnum+1); + end; + + try + if ParamFileVersion <> ModelDef.versionnumber then + begin + raise EFileError.create('The parameter file selected is not compatible with this model. ' + + 'No parameters read.'); + end + else +{ Model name and version match the parameter file so read in the state variables + and parameters. } + begin + i := 0; + StatesRead:=false; + ParamsRead:=False; + repeat + i := i + 1; + readln(paramfile,dum3,tempvalue,dum4,dum,dum2); + if (i <= ModelDef.numstate) and (not StatesRead) then + begin + sarray[i].value := strtofloat(tempvalue); + dum := trim(dum); + dum2 := trim(dum2); + if (dum[1] = 'T') or (dum[1] = 't') then + sarray[i].holdconstant := True + else + sarray[i].holdconstant := False; + if (dum2[1] = 'T') or (dum2[1] = 't') then + sarray[i].reset := True + else + sarray[i].reset := False; + if i = ModelDef.numstate then + begin + StatesRead := True; + i := 0; + end; + end; + if StatesRead and (i>0) then + begin + parray[i].value := strtofloat(tempvalue); + if i = ModelDef.numparam then ParamsRead := True; + end; + if StatesRead and ParamsRead then + begin + readln(paramfile,dum,Tresid); + if Tresid = 0 then Tresid := 999; + end; + until eof(paramfile); + ReadParamFile := true; + if i <> ModelDef.numparam then + raise Exception.Create('Model and parameter file have a different number of parameters.'); + end; + finally + closefile(paramfile); + end; +end; // End readparamfile + +{ Writes the entire parameter file, overwriting any existing file. Frontend + does the checking to be sure you want to overwrite an existing file. See + DlgSaveParam. } +procedure WriteParamFile(filename:string; const npar:integer; + var parray:paramarray; const nstat:integer; + var sarray:statearray; var Tresid:double); +var + i:integer; + paramfile:textfile; + tstring1, tstring2: string; +begin + assignfile(paramfile,filename); + rewrite(paramfile); + // Write out the model name and version. + writeln(paramfile, format('%-25.25s',[ModelDef.modelname]), ' ', + format('%-25.25s',[ModelDef.VersionNumber]), ' ', + format('%-77s',['Units Holdconstant Reset'])); + // Write state variable name, value, units, holdconstant and reset + for i:= 1 to nstat do + begin + if sarray[i].holdconstant then + tstring1 := 'True' + else + tstring1 := 'False'; + if sarray[i].reset then + tstring2 := 'True' + else + tstring2 := 'False'; + writeln(paramfile,format('%-25.25s',[sarray[i].name]),' ', + format('%-25.25e',[sarray[i].value]),' ', + format('%-25.25s',[sarray[i].units]), ' ', + // sarray[i].holdconstant:-25, ' ', sarray[i].reset:-25); + format('%-25.25s',[tstring1{sarray[i].holdconstant}]), ' ', + format('%-25.25s',[tstring2{sarray[i].reset}])); + end; + // Write parameter name, value and units + for i:= 1 to npar do + writeln(paramfile,format('%-25.25s',[parray[i].name]),' ', + format('%-25e',[parray[i].value]),' ', + format('%-25.25s',[parray[i].units])); + writeln(paramfile,format('%-25.25s',['Total Residual ']),' ',format('%-25g',[Tresid])); + closefile(paramfile); + NeedToSavePar := false; +end; // end of writeparamfile + + +// Driver File I/O + +{ The driver file is a comma delimited ASCII file containing the driving + variables. The first line of the file contains the names of the drivers, + the second line contains the units, and subsequent lines contain the driver data. + Each line of the driver file contains simulation time as the first value, + followed by a value for each driver variable. A driver file must contain at + least one line of driver data. Lines after the first data line are optional. + If there are multiple driver data lines, the driver variables are held constant + at the last value read until the next the simulation time equals the time value + in the next driver data line. Negative time values are a flag that creates a + linear ramp from drivers specified on the line before the negative time to the + drivers specified on the line with the negative time. The function + GetCurrentDrivers calculates any ramping if necessary. + + All access to the drivers is done using GetCurrentDrivers. +} + +{ This procedure gets the values for the drivers at the time specified in + CurrTime. If the next_time read in from the driver file is negative, this + procedure calculates a linear ramp between the values in last_drive and + next_drive. } +procedure GetCurrentDrivers(CurrTime:double; var CurrDrivers:DriveArray); +var + tfrac: double; + ll:integer; + tempstring:tstringlist; + anint: integer; +begin + tempstring:=Tstringlist.create; + try + tempstring.Delimiter:=','; + tempstring.StrictDelimiter:=true; + +// No previous values have been read. Read two lines from drivers. + if (last_time = 0) and (next_time = 0) then + begin + currdline := 2; + tempstring.DelimitedText:=driverlist[currdline]; + last_time:=strtoint(tempstring[0]); + for ll:=1 to ModelDef.numdrive do last_drive[ll].value:=strtofloat(tempstring[ll]); + CurrDrivers:=last_drive; + next_time:=last_time; + next_drive:=last_drive; + end; + +// Advance to next line of drivers + while (CurrTime>=abs(next_time)) and (currdline<=driverlist.count-1) do + begin + last_time := next_time; + last_drive := next_drive; + CurrDrivers:=next_drive; + + currdline:=currdline+1; + tempstring.Clear; + if currdlineabs(last_time)) then + begin + tfrac := (CurrTime-abs(last_time))/(abs(next_time)-abs(last_time)); + for ll := 1 to ModelDef.numdrive do + CurrDrivers[ll].value := last_drive[ll].value + tfrac*(next_drive[ll].value - + last_drive[ll].value); + end; +end; // getcurrentdrivers + +// Opens and read entire driver file into stringlist +function openDriverFile(filename:string; dlist:Tstringlist):Boolean; +var + idx:integer; +begin + if not LazFileUtils.FileExistsUTF8(filename) then + begin + MessageDlg('Cannot read driver file. File does not exist.', mtError,[mbOK],0); + openDriverFile:=false; + end + else + begin + try + dlist.LoadFromFile(driverfilename); + // Remove any empty lines + for idx := dlist.count - 1 downto 0 do + begin + if Trim(dlist[idx]) = '' then + dlist.Delete(idx); + end; + openDriverFile:=true; + except + raise Exception.Create('Unable to read driver file.'); + end; + end; +end; // openDriverFile + +// Writes entire driver file. +function WriteDriverFile(filename:string; dlist:Tstringlist):Boolean; +begin + try + dlist.SaveToFile(filename); + WriteDriverFile:=true; + except + WriteDriverFile:=false; + raise; + end; +end; // writedriverfile + +// Output File I/O + +{ The output file is a space delimited ASCII file containing values for the + state variables and processes at each time step of the model run. The first + item on a line is the time followed by the state variables and then the + process variables. The first two lines of the file are header lines. The first + line contains the names of the variables and the second line contains the + units. + + The output file must be opened and closed using OpenOutputFile and + CloseOutputFile. Be sure to call CloseOutputFile when you are done.} + +// Opens the output file for reading or writing depending on the value of Action +procedure OpenOutputFile(filename:string; const ndrive:integer; const darray:drivearray; + const numstat:integer; var sarray:statearray; const numproc:integer; + var parray:processarray; Action:TAction); +var + j:integer; + temp:string; +begin + assignfile(outfile,filename); + if Action = flread then // Open output file for reading + begin + reset(outfile); + readln(outfile,temp); // Read variable names and throw them away + readln(outfile,temp); // Read variable units and throw them away + end + else // Open output file to write + begin + if FmOptions.RunOptions.AppendOutputFile then + begin + append(outfile); + end + else + begin + rewrite(outfile); // Create a new output file + temp := 'Time'; + for j := 1 to ModelDef.numdrive do temp := temp + ', ' + drive[j].name; + for j := 1 to numstat do temp := temp + ', ' + sarray[j].name; + for j := ModelDef.numstate + 1 to numproc do temp := temp + ', ' + parray[j].name; + writeln(outfile, temp); + temp := ModelDef.timeunit; + for j := 1 to ModelDef.numdrive do temp := temp + ', ' + drive[j].units; // Units + for j := 1 to numstat do temp := temp + ', ' + sarray[j].units; + for j := ModelDef.numstate + 1 to numproc do temp := temp + ', ' + parray[j].units; + writeln(outfile, temp); + end; + end; +end; // openoutputfile + +// Reads one line of the output file +function ReadOutputFile(var time:double; const numdrive:integer; var darray: + drivearray; const numstat:integer; var sarray:statearray; const + numproc:integer;var parray:processarray):Boolean; +var + j, num:integer; + tempstring: string; +begin + ReadOutputFile := False; + if (not eof(outfile)) then + begin + readln(outfile, tempstring); + num := pos(',', tempstring); + time := strtofloat(copy(tempstring, 1, num-1)); + for j:= 1 to ModelDef.numdrive do + begin + delete(tempstring, 1, num); + num := pos(',', tempstring); + darray[j].value := strtofloat(copy(tempstring, 1, num-1)); + end; + for j := 1 to numstat do + begin + delete(tempstring, 1, num); + num := pos(',', tempstring); + sarray[j].value := strtofloat(copy(tempstring, 1, num-1)); + end; + for j := ModelDef.numstate + 1 to numproc do + begin + delete(tempstring, 1, num); + num := pos(',', tempstring); + if num <> 0 then + parray[j].value := strtofloat(copy(tempstring, 1, num-1)) + else + parray[j].value := strtofloat(tempstring); + end; + ReadOutputFile := True; + end; +end; // readoutputfile + +// Writes one line to the output file +function WriteOutputFile(time:double; const numstat:integer; + var sarray:statearray; const numproc:integer; + var parray:processarray):Boolean; +var + j:integer; +begin + write(outfile, floattostr(time)); // Write time + for j := 1 to ModelDef.numdrive + do write(outfile, ', ' + floattostr(drive[j].value)); + for j := 1 to numstat // State variables + do write(outfile, ', ' + floattostr(sarray[j].value)); + for j := ModelDef.numstate + 1 to numproc // Process variables + do write(outfile, ', ' + floattostr(parray[j].value)); + writeln(outfile); // Write return + WriteOutputFile := True; +end; // writeoutputfile + +// Closes the output file +procedure CloseOutputFile; +begin + closefile(outfile); +end; + +// Batch File I/O + +{ The batch file is a comma delimited ASCII file containing all the information + necessary to do a model run. Each line represents one run of the model and + contains the parameter file, driver file, and output file names, the start + time, the stop time and the time step. The first is an example. + + The batch file must be opened and closed using OpenBatchFile and + CloseBatchFile. Be sure to call CloseBatchFile when you are done.} + +{ Opens the batch file, reads in the first line and discards it. } +procedure OpenBatchFile(filename:string); +var +tempstring:string; +begin + assignfile(batchfile,filename); + reset(batchfile); + readln(batchfile,tempstring); // Read names and throw away +end; + +{ Reads a line from the batch file. Returns true if the read was successful and + returns false otherwise. } +function ReadBatchFile(var paramname, drivername, outputname:string; var begintime, + endtime:double; var tstat:statearray; var opt:TRunOptions):Boolean; +var + tempstring1, tempstring2: string; + numbegin, numend:integer; +begin + if not eof(batchfile) then // Check for end of file + begin + readln(batchfile,tempstring1); // Read line + numbegin := 1; + numend := pos(',',tempstring1); // param filename + paramname := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(paramname,pos(',',paramname),1); + paramname := trim(paramname); + + numend := pos(',',tempstring1); // driver filename + drivername := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(drivername,pos(',',drivername),1); + drivername := trim(drivername); + + numend := pos(',',tempstring1); // output filename + outputname := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(outputname,pos(',',outputname),1); + outputname := trim(outputname); + + numend := pos(',',tempstring1); // Start time + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + begintime := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Stop time + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + endtime := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Time step + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + opt.Time_step := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Discrete step + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + opt.Discretestep := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Normal Run? + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.NormalRun := True + else + Opt.NormalRun := False; + + numend := pos(',',tempstring1); // Repeat Drivers? + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.RepeatDrivers := True + else + Opt.RepeatDrivers := False; + + numend := pos(',',tempstring1); // Repeat drive time + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.RepeatDriveTime := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Reset States? + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.ResetStates := True + else + Opt.ResetStates := False; + + numend := pos(',',tempstring1); // Reset State Time + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.ResetStateTime := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Run to SS + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.RuntoSS := True + else + Opt.RuntoSS := False; + + numend := pos(',',tempstring1); // SS Criteria + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.SSCriteria := strtofloat(tempstring2)/100; + + numend := pos(',',tempstring1); // SS Time + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.SSTime := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Hold States Constant + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.HoldStatesConstant := True + else + Opt.HoldStatesConstant := False; + + numend := pos(',',tempstring1); // Output Step + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.OutputStep := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Output Offset + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.OutputOffset := strtofloat(tempstring2); + + numend := pos(',',tempstring1); //Output EOR only + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.OutputEORonly := True + else + Opt.OutputEORonly := False; + + numend := pos(',',tempstring1); // Output Annually + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.OutputAnnually := True + else + Opt.OutputAnnually := False; + + numend := pos(',',tempstring1); // Day of Year for annual output + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + Opt.OutputAnnuallyDay := strtofloat(tempstring2); + + numend := pos(',',tempstring1); // Append Output File + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.AppendOutputFile := True + else + Opt.AppendOutputFile := False; + + numend := pos(',',tempstring1); // No Output File + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + tempstring2 := trim(tempstring2); + if (tempstring2[1] = 't') or (tempstring2[1] = 'T') then + Opt.OutputFile := True + else + Opt.OutputFile := False; + + Opt.ErrorMult := strtoint(tempstring1); // Error Mult + + ReadBatchFile := True; + end + else + ReadBatchFile := False; +end; + +{ Closes the batch file. } +procedure CloseBatchFile; +begin + closefile(batchfile); +end; + +// Log File I/O + +{ The log file is an ASCII file summarizing the batch job defined in the + batch file. It contains the date and time, the batch file + name, and for each run: the output file name and a message with the status + of the run. } + +{ Opens the Batch log file and writes out initial information. } +procedure OpenLogFile(filename, batchfile:string); +begin + assignfile(logfile,filename); + rewrite(logfile); + writeln(logfile, 'Output log for Modelshell Batch Utility Version ' + ModelDef.versionnumber); + writeln(logfile, 'Generated: ' + DateTimeToStr(Now)); + writeln(logfile, 'Output from batch file: ' + batchfile); +end; + +{ Write a line to the log file containing the output file name and a status + message. } +function WriteLogFile(filename:string; outputname:string; + StatusMessage:string):Boolean; +begin + writeln(logfile, outputname + ': ' + StatusMessage); + WriteLogFile := True; +end; + +procedure CloseLogFile; +begin + closefile(logfile); +end; + +// List File I/O + +{ The list file is a comma delimited ASCII file containing information + necessary for running a sensitivity analysis. Each line represents one + sensitivity test and contains the parameter file name, the driver file name + the parameter to vary, the new value for the parameter. The first line is + an example. + + The list file must be opened and closed using OpenListFile and + CloseListFile. Be sure to call CloseListFile when you are done.} + +{ Opens the list file, reads in the first line and discards it. } +procedure OpenListFile(filename:string); +var +tempstring:string; +begin + assignfile(listfile,filename); + reset(listfile); + readln(listfile,tempstring); // Read names and throw away +end; + +{ Reads a line from the list file. Returns true if the read was successful and + returns false otherwise. } +function ReadListFile(var paramfilename, driverfilename, paramname:string; + var newparamvalue:double):Boolean; +var + tempstring1,tempstring2: string; + numbegin,numend: integer; +begin + if not eof(listfile) then // Check for end of file + begin + readln(listfile, tempstring1); // Read line + removespaces(tempstring1); + numbegin := 1; + numend := pos(',',tempstring1); + paramfilename := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(paramfilename,pos(',',paramfilename),1); + + numend := pos(',',tempstring1); + driverfilename := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(driverfilename,pos(',',driverfilename),1); + + numend := pos(',',tempstring1); + paramname := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(paramname,pos(',',paramname),1); + + numend := length(tempstring1); + tempstring2 := copy(tempstring1,numbegin,numend-numbegin+1); + delete(tempstring1,numbegin,numend); + delete(tempstring2,pos(',',tempstring2),1); + newparamvalue := strtofloat(tempstring2); + + ReadListFile := True; + end + else + ReadListFile := False; +end; + +{ Closes the list file. } +procedure CloseListFile; +begin + closefile(listfile); +end; + +// Measured data file I/O + +{ The measured data file is a comma delimited ASCII file containing the + measured data to be compared with the model. Each line represents one + comparison and contains the treatment code, the simulation year, + the measured leaf C, wood C, root C, leaf N, wood N, and root N. Note that + the treatment code is used to identify the output file to read the data from. + Therefore, the treatment code must appear in the output filename and it must + appear in only one output filename. The year is the simulation year that + corresponds to the measured data on this line. + + The measured data file must be opened and closed using OpenMeasFile + and CloseMeasFile. Be sure to call CloseMeasFile when you are done.} + +{ This procedure opens the Measured data file for reading, reads in the first + line containing the headings and discards it.} +procedure OpenMeasFile(filename:string); +var + tempstring: string; +begin + assignfile(measfile,filename); + reset(measfile); + readln(measfile,tempstring); // Read names and throw away +end; + +{ Reads one line of the measured data file. Parsing of the line read in is done + in a different procedure to allow easy changing of the measured data. } +function ReadMeasFile(var thisline:string): Boolean; +begin + if not eof(measfile) then + begin + readln(measfile,thisline); + ReadMeasFile := true; + end + else + ReadMeasFile := false; +end; + +{ Closes the measured data file. } +procedure CloseMeasFile; +begin + CloseFile(measfile); +end; + + +// Comma File I/O + +{ Procedure to open and read one line of a comma delimited ASCII file. The first + line of the file is assumed to contain column headings and is read into the + variables headings. + + The comma data file must be opened and closed using OpenCommaFile + and CloseFile. Be sure to call CloseFile when you are done.} + +{ This procedure opens a comma delimited data file for reading, reads in the first + line containing the headings and discards it.} +procedure OpenTextFile(filename:string; var filehandle:textfile); +begin + assignfile(filehandle,filename); + reset(filehandle); +end; + +{ Reads one line of a comma delimited data file. Parsing of the line read in is + done by the calling routine. } +function ReadTextFile(var filehandle: textfile; var aline:string):Boolean; +begin + if not eof(filehandle) then + begin + readln(filehandle,aline); + ReadTextFile := true; + end + else + ReadTextFile := false; +end; + +function CheckforOpenFiles(filename: string): Boolean; +var + outhandle, outhandlex, outhandlen, outhandleq, outhandley: textfile; + answer: Word; + outfile, outfilex, outfilen, outfileq, outfiley: boolean; +begin + outfile := False; + outfilex := False; + outfilen := False; + outfileq := False; + outfiley := False; + try + try + if LazFileUtils.FileExistsUTF8(filename) then + begin + outfile := True; + assignfile(outhandle,filename); + rewrite(outhandle); + end; + if LazFileUtils.FileExistsUTF8(filename+'max') then + begin + outfilex := True; + assignfile(outhandlex,filename+'max'); + rewrite(outhandlex); + end; + if LazFileUtils.FileExistsUTF8(filename+'min') then + begin + outfilen := True; + assignfile(outhandlen,filename+'min'); + rewrite(outhandlen); + end; + if LazFileUtils.FileExistsUTF8(filename+'q') then + begin + outfileq := True; + assignfile(outhandleq,filename+'q'); + rewrite(outhandleq); + end; + if LazFileUtils.FileExistsUTF8(filename+'ymean') then + begin + outfiley := True; + assignfile(outhandley,filename+'ymean'); + rewrite(outhandley); + end; + CheckforOpenFiles := True; + finally + if outfile then CloseFile(outhandle); + if outfilex then CloseFile(outhandlex); + if outfilen then CloseFile(outhandlen); + if outfileq then CloseFile(outhandleq); + if outfiley then CloseFile(outhandley); + end; + except + answer := MessageDlg('Output files are in use. Close all output files and THEN click OK.' + + ' Click Cancel to abort the run.', mtWarning, [mbOK,mbCancel], 0); + CheckforOpenFiles := False; + if answer = 2 then raise; + end; +end; + +function WriteKalmanOutFile(filename:string; var outdata:TKstate; saveuncorrupted:Boolean):Boolean; +var + outhandle, outhandlex, outhandlen, outhandleq, outhandley, + outhandleunmean, outhandleuncorx, outhandleuncorn: textfile; + i, j: integer; +begin + WriteKalmanOutFile := false; + assignfile(outhandle,filename); + assignfile(outhandlex,filename+'max'); + assignfile(outhandlen,filename+'min'); + assignfile(outhandleq,filename+'q'); + assignfile(outhandley,filename+'Ymean'); + rewrite(outhandle); + rewrite(outhandlex); + rewrite(outhandlen); + rewrite(outhandleq); + rewrite(outhandley); + if saveuncorrupted then + begin + assignfile(outhandleunmean,filename+'uncor'); + assignfile(outhandleuncorx,filename+'uncormax'); + assignfile(outhandleuncorn,filename+'uncormin'); + rewrite(outhandleunmean); + rewrite(outhandleuncorx); + rewrite(outhandleuncorn); + end; + + try +// write time + write(outhandle, 'Time'); + write(outhandlex, 'Time'); + write(outhandlen, 'Time'); + write(outhandleq, 'Time'); + write(outhandley, 'Time'); +// Write Variable Names + for i := 0 to outdata.NumTotKalman - 1 do + begin + write(outhandle, ', ', outdata.names[i]); + write(outhandlex, ', ', outdata.names[i]); + write(outhandlen, ', ', outdata.names[i]); + write(outhandleq, ', ', outdata.names[i]); + write(outhandley, ', ', outdata.names[i]); + end; + writeln(outhandle); + writeln(outhandlex); + writeln(outhandlen); + writeln(outhandleq); + writeln(outhandley); + +//write time units + write(outhandle, ModelDef.timeunit); + write(outhandlex, ModelDef.timeunit); + write(outhandlen, ModelDef.timeunit); + write(outhandleq, ModelDef.timeunit); + write(outhandley, ModelDef.timeunit); +// Write Variable Units + for i := 0 to outdata.NumTotKalman - 1 do + begin + write(outhandle, ', ', outdata.units[i]); + write(outhandlex, ', ', outdata.units[i]); + write(outhandlen, ', ', outdata.units[i]); + write(outhandleq, ', ', outdata.units[i]); + write(outhandley, ', ', outdata.units[i]); + end; + writeln(outhandle); + writeln(outhandlex); + writeln(outhandlen); + writeln(outhandleq); + writeln(outhandley); + +// Write Data + for j := 0 to outdata.NumObservations - 1 do + begin + write(outhandle, outdata.time[j]); + write(outhandlex, outdata.time[j]); + write(outhandlen, outdata.time[j]); + write(outhandleq, outdata.time[j]); + write(outhandley, outdata.time[j]); + for i := 0 to outdata.NumTotKalman - 1 do + begin + write(outhandle, ', ', outdata.xmean[j,i]); + write(outhandlex, ', ', outdata.xmax[j,i]); + write(outhandlen, ', ', outdata.xmin[j,i]); + write(outhandleq, ', ', outdata.Q[j,i]); + write(outhandley, ', ', outdata.Ymean[j,i]); + end; + writeln(outhandle); + writeln(outhandlex); + writeln(outhandlen); + writeln(outhandleq); + writeln(outhandley); + end; + + if saveuncorrupted then + begin + // column titles + write(outhandleunmean, 'Time'); + write(outhandleuncorx, 'Time'); + write(outhandleuncorn, 'Time'); + for I := 0 to outdata.numtotkalman - 1 do + begin + write(outhandleunmean, ', ', outdata.names[i]); + write(outhandleuncorx, ', ', outdata.names[i]); + write(outhandleuncorn, ', ', outdata.names[i]); + end; + writeln(outhandleunmean); + writeln(outhandleuncorx); + writeln(outhandleuncorn); + + // column units + write(outhandleunmean, ModelDef.timeunit); + write(outhandleuncorx, ModelDef.timeunit); + write(outhandleuncorn, ModelDef.timeunit); + for i := 0 to outdata.NumTotKalman - 1 do + begin + write(outhandleunmean, ', ', outdata.units[i]); + write(outhandleuncorx, ', ', outdata.units[i]); + write(outhandleuncorn, ', ', outdata.units[i]); + end; + writeln(outhandleunmean); + writeln(outhandleuncorx); + writeln(outhandleuncorn); + + // output data + for j := 0 to outdata.NumObservations - 1 do + begin + write(outhandleunmean, outdata.time[j]); + write(outhandleuncorx, outdata.time[j]); + write(outhandleuncorn, outdata.time[j]); + for i := 0 to outdata.NumTotKalman - 1 do + begin + write(outhandleunmean, ', ', outdata.UnCorXmean[j,i]); + write(outhandleuncorx, ', ', outdata.UncorXmax[j,i]); + write(outhandleuncorn, ', ', outdata.UncorXmin[j,i]); + end; + writeln(outhandleunmean); + writeln(outhandleuncorx); + writeln(outhandleuncorn); + end; + end; + + WriteKalmanOutFile := true; + finally + CloseFile(outhandle); + CloseFile(outhandlex); + CloseFile(outhandlen); + CloseFile(outhandleq); + CloseFile(outhandley); + if saveuncorrupted then + begin + CloseFile(outhandleunmean); + CloseFile(outhandleuncorx); + CloseFile(outhandleuncorn); + end; + end; + +end; + +// Sensitivity Output File I/O + +{ The sensitivity output file is a comma delimited ASCII file containing the + results of the sensitivity analysis. Each line represents one sensitivity + test and contains the parameter file name, the parameter to vary, the new + value for the parameter and residuals for leaf, wood and root carbon and + nitrogen. + + The sensitivity output file must be opened and closed using OpenSensOutFile + and CloseSensOutFile. Be sure to call CloseSensOutFile when you are done.} + +{ Opens the sensitivity output file and writes out column headings. } +procedure OpenSensOutFile(filename:string); +var +tempstring:string; +begin + tempstring := 'Parameter File, Parameter, New Value, Test Status, ResidCL,' + + ' ResidCW, ResidCR, ResidNL, ResidNW, ResidNR, ResidCT, ResidNT'; + assignfile(sensoutfile,filename); + rewrite(sensoutfile); + writeln(sensoutfile,tempstring); +end; + +{ Write a line to the sens output file. } +function WriteSensOutFile(var paramfilename, paramname:string; + var newparamvalue:double; TestStatus:string; ResidCL, ResidCW, + ResidCR, ResidNL, ResidNW, ResidNR, ResidCT, ResidNT: + double):Boolean; +var + tempstring: string; +begin + tempstring := paramfilename + ',' + paramname + ',' + floattostr(newparamvalue) + + ',' + TestStatus + ',' + floattostr(ResidCL) + ',' + floattostr(ResidCW) + + ',' + floattostr(ResidCR) + ',' + floattostr(ResidNL) + ',' + + floattostr(ResidNW) + ',' + floattostr(ResidNR) + ',' + floattostr(ResidCT) + + ',' + floattostr(ResidNT); + writeln(sensoutfile,tempstring); + WriteSensOutFile := True; +end; + +{ Closes the Sensitivity output file. } +procedure CloseSensOutFile; +begin + closefile(SensOutFile); +end; + +procedure ChangeExtension(var filename:string; NewExt:string); +var + num:integer; +begin + num := pos('.',filename); + delete(filename,num,length(filename)-num+1); + filename := filename + '.' + NewExt; +end; + +procedure RemoveSpaces(var somestring:string); +var + num: integer; +begin + num := Pos(' ', somestring); + while num > 0 do + begin + delete(somestring,num,1); + num := Pos(' ', somestring); + end; +end; + +{ Reads in the model definition file to create a new model. } +procedure ReadModelDef(filename:string; var tempmodeldef:Tmodeldef; + var tstat:statearray; var tpar:paramarray; var tproc:processarray; + var tdrive:drivearray); +var + modelfile:textfile; + i,j,npar:integer; + tempstring, tname, tunits, tsymbol, tnpar:string; + +procedure SetString(var tfile:textfile; var tstring:string); +var + num:integer; +begin + readln(tfile,tstring); + num := pos('=',tstring); + delete(tstring,1,num); +end; + +procedure SetNUS(var tfile:textfile; var tstring, tname, tunits, + tsymbol:string); +var + num:integer; +begin + readln(tfile,tstring); + num := pos(',',tstring); + tname := copy(tstring,1,num-1); + delete(tstring,1,num); + num := pos(',',tstring); + tunits := copy(tstring,1,num-1); + delete(tstring,1,num); + num := pos(',',tstring); + if num = 0 then + begin + num := length(tstring); + tsymbol := copy(tstring,1,num); + end + else + begin + tsymbol := copy(tstring,1,num-1); + delete(tstring,1,num); + end; +end; + +procedure SetPD(var tstring, tnpar:string); +var + num:integer; +begin + num := pos(',',tstring); + tnpar := copy(tstring,1,num-1); + delete(tstring,1,num); +// num := length(tstring); +end; + +begin +try try + assignfile(modelfile,filename); + reset(modelfile); + readln(modelfile,tempstring); // Throw away the first line of the file +// ModelDef + SetString(modelfile,tempstring); + tempmodeldef.modelname := tempstring; + SetString(modelfile,tempstring); + tempmodeldef.versionnumber := tempstring; + SetString(modelfile,tempstring); + tempmodeldef.timeunit := tempstring; + readln(modelfile, tempstring); // Throw away blank line + +// States + SetString(modelfile,tempstring); + tempmodeldef.numstate := strtoint(tempstring); + readln(modelfile,tempstring); // Throw away comment line + for i := 1 to tempmodeldef.numstate do + begin + SetNUS(modelfile, tempstring, tname, tunits, tsymbol); + tstat[i].name := tname; + tstat[i].units := tunits; + tstat[i].symbol := tsymbol; + end; + readln(modelfile, tempstring); // Throw away blank line + +// Processes + SetString(modelfile,tempstring); + tempmodeldef.numprocess := tempModelDef.numstate + strtoint(tempstring); + readln(modelfile,tempstring); // Throw away comment line + for i := tempmodeldef.numstate + 1 to tempmodeldef.numprocess do + begin + SetNUS(modelfile, tempstring, tname, tunits, tsymbol); + tproc[i].name := tname; + tproc[i].units := tunits; + tproc[i].symbol := tsymbol; + SetPD(tempstring, tnpar); + tproc[i].parameters := strtoint(tnpar); + if tproc[i].parameters <> 0 then + begin + npar := ParCount(i); + for j := 1 to tproc[i].parameters do + begin + SetNUS(modelfile, tempstring, tname, tunits, tsymbol); + tpar[npar + j].name := tname; + tpar[npar + j].units := tunits; + tpar[npar + j].symbol := tsymbol; + end; + end; + end; + readln(modelfile, tempstring); // Throw away blank line + +// Drivers + SetString(modelfile,tempstring); + tempmodeldef.numdrive := strtoint(tempstring); + readln(modelfile,tempstring); // Throw away comment line + for i := 1 to tempmodeldef.numstate do + begin + SetNUS(modelfile, tempstring, tname, tunits, tsymbol); + tdrive[i].name := tname; + tdrive[i].units := tunits; + tdrive[i].symbol := tsymbol; + end; + + { Set the names, units, and symbols of the processes and the parameters. The + maximum length for the name, units and symbol is stringlength (currently 25) + characters. + + The first numstate processes are the derivatives of the state variables. Set + the names and units accordingly.} + for i:= 1 to tempmodeldef.numstate do tproc[i].name:='d'+tstat[i].name+'dt'; + for i:= 1 to tempmodeldef.numstate do tproc[i].units := tstat[i].units + 't-1'; + for i:= 1 to tempmodeldef.numstate do tproc[i].symbol := 'd' + tstat[i].symbol + 'dt'; + +{ Sum up the total number of parameters in the model and store it in the + tempmodeldef structure. } + tempmodeldef.numparam := 0; + for i := 1 to tempmodeldef.NumProcess do + tempmodeldef.numparam := tempmodeldef.numparam + tproc[i].parameters; + +finally + CloseFile(modelfile); +end; +except + raise EFileError.Create('Error reading Model Definition file. Application Terminated'); +end; +end; + +{This function counts the parameters in all processes less than processnum.} +function ParCount(processnum:integer) : integer; +var + NumberofParams, counter : integer; +begin + NumberofParams := 0; + for counter := ModelDef.numstate + 1 to processnum - 1 do + NumberofParams := NumberofParams + proc[counter].parameters; + ParCount := NumberofParams; +end; // end of parcount function + +end. diff --git a/modelshell/frontend.lfm b/modelshell/frontend.lfm new file mode 100644 index 0000000..8a5c404 --- /dev/null +++ b/modelshell/frontend.lfm @@ -0,0 +1,476 @@ +object FmShellMain: TFmShellMain + Left = 1215 + Height = 493 + Top = 357 + Width = 958 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'MBL Modelshell v6.5.4' + ClientHeight = 463 + ClientWidth = 958 + Color = 1416450 + DesignTimePPI = 144 + Font.Color = clBlack + Font.Height = -17 + Font.Name = 'Arial' + Font.Style = [fsBold] + Menu = MainMenu1 + OnCreate = FormCreate + OnDestroy = FormDestroy + Position = poScreenCenter + LCLVersion = '2.0.10.0' + object ParamLabel: TLabel + Left = 24 + Height = 21 + Top = 26 + Width = 117 + Alignment = taRightJustify + Caption = '&Parameter File' + FocusControl = ParamBox + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + OnClick = ChooseParamFile + end + object DriverLabel: TLabel + Left = 24 + Height = 21 + Top = 81 + Width = 82 + Alignment = taRightJustify + Caption = '&Driver File' + FocusControl = DriverBox + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + OnClick = ChooseDriver + end + object OutputLabel: TLabel + Left = 24 + Height = 21 + Top = 136 + Width = 88 + Alignment = taRightJustify + Caption = 'O&utput File' + FocusControl = OutputBox + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + OnClick = ChooseOutputFile + end + object StartLabel: TLabel + Left = 39 + Height = 21 + Top = 206 + Width = 82 + Alignment = taCenter + Caption = '&Start Time' + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object StopLabel: TLabel + Left = 324 + Height = 21 + Top = 206 + Width = 81 + Alignment = taCenter + Caption = 'S&top Time' + FocusControl = MEStopTime + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object PresentLabel: TLabel + Left = 648 + Height = 21 + Top = 206 + Width = 106 + Alignment = taCenter + Caption = 'Present Time' + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentColor = False + ParentFont = False + end + object LblWelcome: TLabel + Left = 316 + Height = 21 + Top = 81 + Width = 147 + Caption = 'Welcome to MEL' + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + Visible = False + end + object LblDirections: TLabel + Left = 396 + Height = 29 + Top = 388 + Width = 402 + Caption = 'Please enter the number of species' + Font.Color = clBlack + Font.Height = -24 + Font.Name = 'Arial' + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + Visible = False + end + object OutputBox: TEdit + Left = 226 + Height = 29 + Top = 135 + Width = 651 + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnExit = ChooseOutputFile + OnKeyPress = OutputBoxKeyPress + ParentFont = False + TabOrder = 1 + end + object DriverBox: TEdit + Left = 226 + Height = 29 + Top = 76 + Width = 651 + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnExit = ChooseDriver + OnKeyPress = DriverBoxKeyPress + ParentFont = False + TabOrder = 0 + end + object MEStopTime: TMaskEdit + Left = 300 + Height = 29 + Top = 232 + Width = 148 + CharCase = ecNormal + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + MaxLength = 7 + ParentFont = False + TabOrder = 2 + OnExit = MeStopTimeExit + OnKeyPress = MEStopTimeKeyPress + EditMask = '9999999;0; ' + Text = '2' + SpaceChar = ' ' + end + object ParamBox: TEdit + Left = 226 + Height = 29 + Top = 21 + Width = 651 + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnExit = ChooseParamFile + OnKeyPress = ParamBoxKeyPress + ParentFont = False + TabOrder = 6 + end + object BtnRun: TButton + Left = 120 + Height = 38 + Top = 312 + Width = 165 + Caption = '&Run' + Enabled = False + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnClick = BtnRunClick + ParentFont = False + ParentShowHint = False + TabOrder = 3 + end + object PresentBox: TEdit + Left = 636 + Height = 29 + Top = 232 + Width = 148 + AutoSelect = False + Color = clInactiveBorder + Enabled = False + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + ParentFont = False + TabStop = False + TabOrder = 5 + Text = '0' + end + object BtnReload: TButton + Left = 624 + Height = 38 + Top = 310 + Width = 182 + Caption = 'Re&load' + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnClick = BtnReloadClick + ParentFont = False + TabOrder = 4 + end + object EdNumSpecies: TEdit + Left = 816 + Height = 29 + Top = 384 + Width = 36 + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnChange = EdNumSpecieschange + OnExit = EdNumSpeciesExit + OnKeyPress = EdNumSpeciesKeyPress + ParentFont = False + TabOrder = 7 + Visible = False + end + object MEStartTime: TMaskEdit + Left = 24 + Height = 27 + Top = 234 + Width = 148 + CharCase = ecNormal + Font.Color = clBlack + Font.Height = -17 + Font.Name = 'Arial' + MaxLength = 7 + ParentFont = False + TabOrder = 8 + OnExit = MeStartTimeExit + OnKeyPress = MEStartTimeKeyPress + EditMask = '9999999;0; ' + Text = '1' + SpaceChar = ' ' + end + object BtnCloseShell: TButton + Left = 372 + Height = 38 + Top = 310 + Width = 112 + Caption = '&Close' + Font.Color = clBlack + Font.Height = -18 + Font.Name = 'Arial' + OnClick = BtnCloseShellClick + ParentFont = False + TabOrder = 9 + end + object MainMenu1: TMainMenu + Top = 480 + object MIFiles: TMenuItem + Caption = '&Files' + object MIParamFile: TMenuItem + Caption = '&Parameter File' + object MIChooseParam: TMenuItem + Caption = '&Open...' + OnClick = ChooseParamFile + end + object MISaveParam: TMenuItem + Caption = '&Save...' + Enabled = False + ShortCut = 16467 + OnClick = MISaveParamClick + end + object MISaveAsParam: TMenuItem + Caption = 'Save &As' + OnClick = MISaveAsParamClick + end + end + object MIDriverFile: TMenuItem + Caption = '&Driver File' + object MIChooseDrv: TMenuItem + Caption = '&Open...' + OnClick = ChooseDriver + end + object MIEditDrv: TMenuItem + Caption = '&Edit...' + OnClick = MIEditDrvClick + end + end + object MIOutput: TMenuItem + Caption = '&Output' + object MIChooseOutput: TMenuItem + Caption = '&Enter output filename' + OnClick = ChooseOutputFile + end + object MISaveMemOutput: TMenuItem + Caption = 'Save output in &memory to file' + OnClick = MISaveMemOutputClick + end + end + object MIBar: TMenuItem + Caption = '-' + end + object MIExit: TMenuItem + Caption = 'E&xit' + OnClick = MIExitClick + end + end + object MIEdit: TMenuItem + Caption = '&Edit' + object MIEditParam: TMenuItem + Caption = '&Parameters...' + OnClick = MIEditParamClick + end + object MIEditStates: TMenuItem + Caption = '&State Variables...' + OnClick = MIEditStatesClick + end + object MIEditDrv2: TMenuItem + Caption = '&Drivers...' + OnClick = MIEditDrvClick + end + end + object MICalculate: TMenuItem + Caption = 'C&alculate' + Enabled = False + Visible = False + object MICalTime: TMenuItem + Caption = '&At Time...' + OnClick = MICalTimeClick + end + object MICalcSS: TMenuItem + Caption = '&Steady State...' + OnClick = MICalcSSClick + end + end + object Run1: TMenuItem + Caption = 'O&ptions' + object MITimeSteps: TMenuItem + Caption = '&Time Steps' + GroupIndex = 1 + RadioItem = True + OnClick = MIOpenOptionsClick + end + object N3: TMenuItem + Caption = '-' + GroupIndex = 1 + RadioItem = True + end + object MINormalRun: TMenuItem + Caption = '&Normal Run' + Checked = True + GroupIndex = 1 + RadioItem = True + OnClick = MINormalRunClick + end + object MISpecialRun: TMenuItem + Caption = '&Special Run ...' + GroupIndex = 1 + RadioItem = True + OnClick = MIOpenOptionsClick + end + object N1: TMenuItem + Caption = '-' + GroupIndex = 1 + end + object MIOutOptions: TMenuItem + Caption = '&Output Options ...' + GroupIndex = 1 + OnClick = MIOpenOptionsClick + end + end + object MIView: TMenuItem + Caption = '&Output' + object MIShowChart: TMenuItem + Caption = 'C&hart' + OnClick = DisplayOutput + end + object MIShowTable: TMenuItem + Caption = 'Ta&ble' + OnClick = DisplayOutput + end + object MIViewOutFile: TMenuItem + Caption = 'From &File...' + OnClick = MIViewOutFileClick + end + object N2: TMenuItem + Caption = '-' + end + object MIAutoChart: TMenuItem + Caption = '&AutoChart' + Hint = 'Check this to automatically show the chart after a run' + OnClick = MIAutoChartClick + end + end + object Help1: TMenuItem + Caption = '&Help' + object MIAbout: TMenuItem + Caption = '&About' + OnClick = MIAboutClick + end + end + end + object DlgOpenParam: TOpenDialog + Title = 'Choose Parameter File' + DefaultExt = '.par' + Filter = 'Parameter FIles (*.par)|*.par|All Files|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofEnableSizing] + Left = 48 + Top = 480 + end + object DlgSaveParam: TSaveDialog + Title = 'Save Parameter File' + DefaultExt = '.par' + Filter = 'Parameter Files (*.par)|*.par|All Files|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofCreatePrompt, ofNoReadOnlyReturn] + Left = 96 + Top = 480 + end + object DlgOpenDriver: TOpenDialog + Title = 'Open Driver File' + DefaultExt = '.drr' + Filter = 'Driver files (*.drr)|*.drr|All files|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofCreatePrompt, ofNoReadOnlyReturn] + Left = 144 + Top = 480 + end + object DlgSaveDriver: TSaveDialog + Title = 'Save Driver File as' + DefaultExt = '.drr' + Filter = 'Driver Files (*.drr)|*.drr|All Files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofCreatePrompt, ofNoReadOnlyReturn] + Left = 192 + Top = 480 + end + object DlgSaveOutput: TSaveDialog + Title = 'Save Output File as' + DefaultExt = '.out' + Filter = 'Output Files (*.out)|*.out|All Files (*.*)|*.*' + Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn] + Left = 288 + Top = 480 + end + object DlgOpenOutput: TOpenDialog + Title = 'Open Output File' + DefaultExt = '.out' + Filter = 'Output Files (*.out)|*.out|All Files (*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofNoReadOnlyReturn, ofEnableSizing] + Left = 240 + Top = 480 + end +end diff --git a/modelshell/frontend.pas b/modelshell/frontend.pas new file mode 100644 index 0000000..3fb533d --- /dev/null +++ b/modelshell/frontend.pas @@ -0,0 +1,1029 @@ +{ This file creates and controls the main window of the modeling application. + This window is called FmShellMain in the code. Describe the use of ReadytoRun and + RunComplete here.} +unit frontend; + +{$MODE Delphi} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + {$ifdef Darwin} + MacOSAll, + {$endif} + StdCtrls, Menus, stypes, ExtCtrls, MaskEdit, Printers, TAGraph, Lazfileutils; + +const + epsilon = 1e-8; + fullstep = 1; + DefaultUnixDirectory = '/user/share/CrEquations'; + BundleResourceDirectory = '/Contents/Resources/'; + +type + + { TFmShellMain } + + TFmShellMain = class(TForm) + BtnCloseShell: TButton; + MainMenu1: TMainMenu; + MEStartTime: TMaskEdit; + MIFiles: TMenuItem; + MISaveParam: TMenuItem; + DlgOpenParam: TOpenDialog; + DlgSaveParam: TSaveDialog; + MIEdit: TMenuItem; + MIEditParam: TMenuItem; + MIEditStates: TMenuItem; + MIChooseDrv: TMenuItem; + MIOutput: TMenuItem; + DlgOpenDriver: TOpenDialog; + MIChooseParam: TMenuItem; + MICalculate: TMenuItem; + MIView: TMenuItem; + MIShowChart: TMenuItem; + MIParamFile: TMenuItem; + MIDriverFile: TMenuItem; + MIEditDrv: TMenuItem; + DlgSaveDriver: TSaveDialog; + DlgSaveOutput: TSaveDialog; + MISaveAsParam: TMenuItem; + MIExit: TMenuItem; + MIBar: TMenuItem; + MIShowTable: TMenuItem; + ParamLabel: TLabel; + DriverLabel: TLabel; + OutputLabel: TLabel; + StartLabel: TLabel; + StopLabel: TLabel; + PresentLabel: TLabel; + MICalcSS: TMenuItem; + MIEditDrv2: TMenuItem; + MEStopTime: TMaskEdit; + ParamBox: TEdit; + DriverBox: TEdit; + OutputBox: TEdit; + BtnRun: TButton; + PresentBox: TEdit; + BtnReload: TButton; + MICalTime: TMenuItem; + MIViewOutFile: TMenuItem; + DlgOpenOutput: TOpenDialog; + EdNumSpecies: TEdit; // MEL specific + LblWelcome: TLabel; // MEL specific + LblDirections: TLabel; + Run1: TMenuItem; + MISpecialRun: TMenuItem; + Help1: TMenuItem; + MIAbout: TMenuItem; + MINormalRun: TMenuItem; + N1: TMenuItem; + MIAutoChart: TMenuItem; + N2: TMenuItem; + MIOutOptions: TMenuItem; + N3: TMenuItem; + MITimeSteps: TMenuItem; + MISaveMemOutput: TMenuItem; + MIChooseOutput: TMenuItem; // MEL specific + procedure BtnCloseShellClick(Sender: TObject); + procedure ChooseParamFile(Sender: TObject); + procedure ChooseDriver(Sender: TObject); + procedure ChooseOutputFile(Sender: TObject); + procedure BtnRunClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure MIExitClick(Sender: TObject); + procedure MISaveParamClick(Sender: TObject); + procedure MISaveAsParamClick(Sender: TObject); + procedure MIEditParamClick(Sender: TObject); + procedure MIEditStatesClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure MeStartTimeExit(Sender: TObject); + procedure MeStopTimeExit(Sender: TObject); + procedure BtnReloadClick(Sender: TObject); + procedure UpdateFmShellMain; + procedure MIEditDrvClick(Sender: TObject); + procedure MIAboutClick(Sender: TObject); + procedure MICalcSSClick(Sender: TObject); + procedure DisplayOutput(Sender: TObject); + procedure SetNumSpecies(anEditBox: TEdit); // MEL specific + procedure EdNumSpecieschange(Sender: TObject); // MEL specific + procedure EdNumSpeciesExit(Sender: TObject); // MEL specific + procedure MICalTimeClick(Sender: TObject); + procedure MIViewOutFileClick(Sender: TObject); + procedure MEStopTimeKeyPress(Sender: TObject; var Key: Char); + procedure MEStartTimeKeyPress(Sender: TObject; var Key: Char); + procedure MIOpenOptionsClick(Sender: TObject); + procedure MINormalRunClick(Sender: TObject); + procedure MIAutoChartClick(Sender: TObject); + procedure ParamBoxKeyPress(Sender: TObject; var Key: Char); + procedure DriverBoxKeyPress(Sender: TObject; var Key: Char); + procedure OutputBoxKeyPress(Sender: TObject; var Key: Char); + procedure EdNumSpeciesKeyPress(Sender: TObject; var Key: Char); + procedure MISaveMemOutputClick(Sender: TObject); + function GetResourcePath(): string; + private + { Private declarations } + procedure ResetStatesNow(Sender: TObject); + public + { Public declarations } + CurrentPath:string; + RunningInteractive: Boolean; + lastitem: TComponent; + CurrentResid: Double; + BeginningofRun: Boolean; + LargeOutput: Boolean; + initialstates:statearray; + procedure ShowProgressBar; + procedure CancelRun; + end; + +var + FmShellMain: TFmShellMain; + time,time_start,Time_stop,CalTime: double; + ModelDef: TModelDef; + stat: statearray; + drive: drivearray; + par: paramarray; + proc: processarray; + paramfilename,driverfilename,outfilename: string; + NeedToSavePar: Boolean = False; + ReadyToRun: Boolean = False; + RunComplete: Boolean = False; + counttt:integer; +// NewParamFile: Boolean; +// NewDriverFile: Boolean; + stopRun: boolean = false; +// NumSpProc,NumSpPar:integer; // MEL specific +// numspp:integer; // MEL specific +implementation + +uses fileio, calculate, display, ReloadDlg, data, parameter, + equations, integrator, note, aboutbox, trouble, ProgressBar, Options; + +{$R *.lfm} + +{ This procedure sets up the modeling application. } +procedure TFmShellMain.FormCreate(Sender: TObject); +var + tempstring, tempstring2: string; + ll:integer; +begin +// Determine current path for dialog box initial directories + CurrentPath := GetResourcePath(); + + {CurrentPath := ExtractFilePath(Application.EXEName); } + LazFileUtils.SetCurrentDirUTF8(CurrentPath); + +// Set initial values for model timing + Time_start := strtofloat(MEStartTime.text); + Time_stop := strtofloat(MEStopTime.text); + CalTime := time_start; +// Set initial value for the number of species +// numspp := 1; // MEL specific + +{ Call the counts procedure which defines the model structure. This procedure + sets the names and units of the state variables, driver variables, process + variables, and parameters. It also sets the values of the ModelDef structure + which defines the number of state variables, driver variables, process + variables and parameters. +} + counts; + Application.Title := ModelDef.modelname; + next_drive := drive; // Initialize names and units of next_drive & last_drive + last_drive := drive; + FmShellMain.Caption := ModelDef.modelname; // Set the FmShellMain caption + tempstring := Application.Title; + tempstring := lowercase(tempstring); + RunningInteractive := True; + BeginningofRun := True; + fileio.driverlist:=tstringlist.create; + fileio.driverlist.StrictDelimiter:=true; + fileio.driverlist.Delimiter:=','; + // Initialize driver names and units + tempstring := 'Time, '; + tempstring2 := ModelDef.timeunit; + for ll:=1 to ModelDef.numdrive do + begin + tempstring := tempstring + drive[ll].name; + tempstring2 := tempstring2 + drive[ll].units; + end; + fileio.driverlist.Add(tempstring); + fileio.driverlist.Add(tempstring2); +end; + +{ This procedure enables the user to choose a parameter file using several + different methods. The user can click Choose Parameter file from the menu, + click on the label Parameter File, or type a filename directly in the box. + If the user chooses using either the menu or the label, an open file dialog + is displayed. } +procedure TFmShellMain.ChooseParamFile(Sender: TObject); +var + oldparamfilename : string; + replace: Word; +begin + oldparamfilename := paramfilename; + DlgOpenParam.InitialDir:=CurrentPath; + + // If the user typed directly in the box + if Sender is TEdit then paramfilename := parambox.text // Set paramfilename + else if RunningInteractive then // The user used either the menu or clicked on the label + begin // Show the open file dialog + // First set the dialog box default filename to the current paramfile + DlgOpenParam.filename := paramfilename; + // If the user chooses OK in the dialog then set the new paramfilename + if DlgOpenParam.execute then paramfilename := DlgOpenParam.filename; + end; + + if (paramfilename <> oldparamfilename) or not RunningInteractive then + begin + if paramfilename <> '' then // Be sure something was entered for the filename + try + if not LazFileUtils.FileExistsUTF8(paramfilename) then // If the paramter file doesn't exist + // Create a new parameter file using values in memory + begin + WriteParamFile(paramfilename, ModelDef.numparam, par, ModelDef.numstate, + stat, currentresid); +// NewParamFile := True; + end + else // Parameter file does exist, so read the values into the global arrays. + begin + if (oldparamfilename <> '') and RunningInteractive then + replace := MessageDlg('Replace current values with those in file, ' + + paramfilename + ' ?', mtConfirmation, [mbYes,mbNo], 0) + else + replace := mryes; + if replace = mryes then + begin + ReadParamFile(paramfilename,ModelDef.numparam,par,ModelDef.numstate, + stat, currentresid); +// NewParamFile := False; + end + else + begin + paramfilename := oldparamfilename; +// NewParamFile := False; // fix necessary here and if so what should the value be??? + end; + end; + except + paramfilename := oldparamfilename; + raise; + end; + RunComplete := False; + Readytorun := false; // Can't run the model. + end; + + CurrentPath := ExtractFilePath(paramfilename); + LazFileUtils.SetCurrentDirUTF8(CurrentPath); + UpdateFmShellMain; // Update the form +end; + +procedure TFmShellMain.BtnCloseShellClick(Sender: TObject); +begin + MIExitClick(Sender); +end; + +{ This procedure enables the user to choose a Driver file using several + different methods. The user can click Choose Driver file from the menu, + click on the label Driver File, or type a filename directly in the box. + If the user chooses using either the menu or the label, an open file dialog + is displayed. } +procedure TFmShellMain.ChooseDriver(Sender: TObject); +var + olddriverfilename : string; + i:integer; +begin + DlgOpenDriver.InitialDir:=CurrentPath; + + olddriverfilename := driverfilename; +// If the user typed directly in the edit box + if Sender is TEdit then driverfilename:=DriverBox.text // Set the driverfile + else // User used the menu or clicked on the Driver label + begin // Show the open file dialog + // First set the default filename to the current driverfile + DlgOpenDriver.filename := driverfilename; + // Show the dialog and if the user clicks OK, set the new driver filename + if DlgOpenDriver.execute then driverfilename := DlgOpenDriver.filename; + end; + + if driverfilename <> olddriverfilename then + begin + if driverfilename <> '' then // Create a new empty file { TODO : When a new file is created the edit driver window should automatically pop up } + if not LazFileUtils.FileExistsUTF8(driverfilename) then + fileio.WriteDriverFile(driverfilename, fileio.driverlist); + ReadytoRun := False; // This forces the edit boxes on the FmShellMain to be update with the new filename + RunComplete := False; + end; + + CurrentPath := ExtractFilePath(paramfilename); + LazFileUtils.SetCurrentDirUTF8(CurrentPath); + UpdateFmShellMain; +end; + +{ This procedure enables the user to choose an Output file using several + different methods. The user can click Choose Output file from the menu, + click on the label Output File, or type a filename directly in the box. + If the user chooses using either the menu or the label, an open file dialog + is displayed. } +procedure TFmShellMain.ChooseOutputFile(Sender: TObject); +var + oldoutfilename : string; +begin // If the user typed directly in the edit box + DlgSaveOutput.InitialDir:=CurrentPath; + + oldoutfilename := outfilename; + + if Sender is TEdit then Outfilename := OutputBox.text // Set the output file + else // User used the menu or clicked on the Output label + begin // Show the Save file dialog + // First set the default filename to the current output file. + DlgSaveOutput.filename := outfilename; + // Show the dialog and if the user chooses OK, set the outfilename to the new file. + if DlgSaveOutput.execute then outfilename := DlgSaveOutput.filename; + end; + +{ if outfilename <> oldoutfilename then + begin + if outfilename <> '' then // Make sure a value was entered for the filename + begin + if LazFileUtils.FileExistsUTF8(outfilename) then // If the file already exists + // Confirm that the user wants to overwrite the existing file. + if MessageDlg('Overwrite existing output file, ' + outfilename + '?', + mtConfirmation, [mbYes,mbNo], 0) = mrNo then + begin + outfilename := ''; // Set the outfile to no value + end; + end; + end; } + FmDisplayOutput.DisplayFilename:=outfilename; + CurrentPath := ExtractFilePath(paramfilename); + LazFileUtils.SetCurrentDirUTF8(CurrentPath); + RunComplete := False; + ReadytoRun := False; // Can't run without an output file. + UpdateFmShellMain; // Update the form. +end; + +{ This procedure saves the current values of the state variables and the + parameters to the current parameter file. } +procedure TFmShellMain.MISaveParamClick(Sender: TObject); +begin + WriteParamFile(paramfilename, ModelDef.numparam, par, ModelDef.numstate, stat, + currentresid); + RunComplete := False; +// NewParamFile := False; + UpdateFmShellMain; + Beep; +end; + +{ Procedure to save the state variables and parameters to a new parameter file. } +procedure TFmShellMain.MISaveAsParamClick(Sender: TObject); +begin // Show the Save dialog +DlgSaveParam.InitialDir:=CurrentPath; + +with DlgSaveParam do + begin + // Set the default filename in save dialog to the current parameter file. + filename := paramfilename; + if execute then // If the user chooses OK in the save dialog. + begin + paramfilename:=filename; // Set the paramfilename to the new filename. + // Save the state variables and parameters to the current file. + WriteParamFile(paramfilename, ModelDef.numparam, par, ModelDef.numstate, + stat, currentresid); + // Set Ready to Run to false so the the edit boxes on the form will be + // updated when UpdateFmShellMain is called. +// NewParamFile := False; + ReadytoRun := False; + RunComplete := False; + UpdateFmShellMain; + end; + end; +end; + +procedure TFmShellMain.MISaveMemOutputClick(Sender: TObject); +begin + FmDisplayOutput.WriteOutputfromMem; +end; + +{ Procedure to allow the user to edit the parameter values. This procedure calls + the Parameters Form defined in the parameters.pas unit. While the user is editing + the parameters the FmShellMain is disabled. } +procedure TFmShellMain.MIEditParamClick(Sender: TObject); +begin +{ Show the parameter form. If the user clicked OK on the parameter form, + meaning they changed the parameter values, update this form. } + CalTime := Time_start; + FmParameter.ShowParameters; + if FmParameter.showmodal = mrOK then + begin +// Parameters have been changed so any previous model runs are invalid. + RunComplete := False; + UpdateFmShellMain; // Update the form. + currentresid := 999; + end; +end; + +{ Procedure to allow the user to edit the state variables. This procedure calls + the Data Form defined in the data.pas unit. While the user is editing + the state variables the FmShellMain is disabled. } +procedure TFmShellMain.MIEditStatesClick(Sender: TObject); +begin + DataForm.ShowStates; // Show the data form containing state variables + UpdateFmShellMain; +end; + +{ Procedure to allow the user to edit the driver variables. This procedure calls + the Note Form defined in the note.pas unit. While the user is editing + the drivers the FmShellMain is disabled. } +procedure TFmShellMain.MIEditDrvClick(Sender: TObject); +begin +{ Show the note form. If the user clicked OK on the note form, + meaning they changed the driver values, update this form. } + FmNote.Show; +// Drivers have been changed so any previous model runs are invalid. + RunComplete := False; +// User may have changed driver files, so force the edit boxes and menu to be updated. + ReadytoRun := False; + UpdateFmShellMain; +end; + +{ Procedure to process changes made to the start time mask edit box. The mask + edit box only allows numeric input with up to 5 digits. Values entered must be + integers. To change the allowed values modify the mask using the object + inspector. } +procedure TFmShellMain.MeStartTimeExit(Sender: TObject); +begin + if MEStartTime.Text <> '' then + if (MEStartTime.Text <> floattostr(time_Start)) then +// if (MEStartTime.Text <> '') and (MEStartTime.Modified) then + begin + Time_Start := strtofloat(MEStartTime.text); // Set the start time of the model. + ReadytoRun := False; // Force checking of start and stop times in UpdateFmShellMain. + RunComplete := False; // Previous runs are invalid. + UpdateFmShellMain; + end; +end; + +{ Procedure to process changes made to the start time mask edit box. The mask + edit box only allows numeric input with up to 5 digits. Values entered must be + integers. To change the allowed values modify the mask using the object + inspector. } +procedure TFmShellMain.MeStopTimeExit(Sender: TObject); +begin + if MeStopTime.Text <> '' then + if (MeStopTime.Text <> floattostr(time_Stop)) then +// if (MEStopTime.text <> '') and (MeStopTime.Modified) then + begin + Time_Stop := strtofloat(MEStopTime.text); // Set the stop time of the model. + ReadytoRun := False; // Force checking of start and stop times in UpdateFmShellMain. + RunComplete := False; // Previous runs are invalid. + UpdateFmShellMain; + end; +end; + +{ This procedure shows the output from the model run in table or chart format. + It uses the form defined in display.pas. } +procedure TFmShellMain.DisplayOutput(Sender: TObject); +begin + if (Sender as TMenuItem).Name = 'MIShowTable' then + FmDisplayOutput.DisplayStyle := dsTable // Set the type of display. + else + FmDisplayOutput.DisplayStyle := dsChart; + FmDisplayOutput.Enabled := True; + if not FmDisplayOutput.Visible then + FmDisplayOutput.ShowModal + else + FmDisplayOutput.WindowState:=wsNormal; + // or is this what I want +// FmDisplayOutput.BringToFront; +end; + +{ Show an about box containing general information about the model. } +procedure TFmShellMain.MIAboutClick(Sender: TObject); +begin + FmAbout.Caption := 'About ' + ModelDef.modelname; + FmAbout.LblModel.Caption := ModelDef.modelname; + FmAbout.LblVersion.Caption := ModelDef.versionnumber; + FmAbout.MoContact.Lines.Add(ModelDef.contactperson); + FmAbout.MoContact.Lines.Add(ModelDef.contactaddress1); + FmAbout.MoContact.Lines.Add(ModelDef.contactaddress2); + FmAbout.MoContact.Lines.Add(ModelDef.contactaddress3); + FmAbout.ShowModal; +end; + +{ This procedure presents a dialog which allows the user to reread the state + variables and/or parameters from the parameter form. It uses the Reload + dialog defined in the ReloadDlg.pas unit.} +procedure TFmShellMain.BtnReloadClick(Sender: TObject); +begin // Show the Reload Dialog +if paramfilename <> '' then + begin + if DlgReload.ShowModal = mrOK then // If the user clicked OK, values were reloaded + begin + RunComplete := False; // so previous runs are invalid. + UpdateFmShellMain; + end; + end +else + MessageDlg('Invalid parameter file. No values reloaded.',mtWarning,[mbOK],0); +end; + +// This procedure is used to update the controls on the Main Form, i.e. enabling +// and disabling them when appropriate. +procedure TFmShellMain.UpdateFmShellMain; +begin + if not ReadytoRun then + begin + ParamBox.text := paramfilename; // save it's name in the paramfilename variable + if paramfilename <> '' then // if a parameter file has been chosen + begin + MISaveParam.Enabled := true; // enable the save parameter file menu item + end; + // if a driver variable has been chosen, save it's name to driverfilename + if driverfilename <> '' then DriverBox.text := driverfilename; + // if an output file name has been chosen, save it's name to outfilename + if outfilename <> '' then OutputBox.text := outfilename; +// If all files have been chosen then enable the run button and calculate menu. + if (DriverBox.text <> '') and (ParamBox.text <> '') then + begin +// MICalculate.enabled := true; // Enable the calculate menu + if (OutputBox.text <> '') and (Time_stop > Time_start) then + begin + ReadytoRun := true; + BtnRun.enabled := true; + FmOptions.RunOptions.stepcounter := FmOptions.DefaultRunOptions.stepcounter; + end; + end; + end; + if RunComplete then // If a run is complete + begin + MISaveMemOutput.Enabled := true; + last_time := 0; + next_time := 0; + end + else + begin // Run is not complete or previous run is now invalid + MISaveMemOutput.Enabled := false; + PresentBox.Text := floattostr(0); // Set the present time to 0 + end; + if FmShellMain.ActiveControl is TEdit then + if FmShellMain.ActiveControl.Name = 'ParamBox' then + FmShellMain.ActiveControl := BtnCloseShell; + if FmOptions.RunOptions.NormalRun then + MINormalRun.Checked := True + else + MISpecialRun.Checked := True; +end; + +// This procedure controls the actual running of a model scenario. +procedure TFmShellMain.BtnRunClick(Sender: TObject); +var + j, outputfreq, stepsperfullstep, nok, nbad, idx, endstate:integer; + tempstat:yValueArray; + drivetime, nextstep, remainder, errorest, SStest, SSstep, temp:double; + steadystate, ResetDriverFile: Boolean; + previousstat, tempstate: statearray; + basename,anewname,theext:string; +begin + BeginningofRun := True; + ResetDriverFile := False; + LargeOutput := False; + openDriverFile(driverfilename,fileio.driverlist); + if RunningInteractive then + begin + ShowProgressBar; + FmShellMain.Enabled := False; + end; + try try + stepsperfullstep := round(fullstep/FmOptions.RunOptions.Time_step); + initialstates := stat; + last_time := 0; + next_time := 0; + nextstep := FmOptions.RunOptions.Time_step; + time := time_start; + drivetime := time_start; + steadystate := false; +// Variables used to keep track of when to write to output file + outputfreq := round(FmOptions.RunOptions.Outputstep/FmOptions.RunOptions.Time_step); +// Calculate and write out the initial state of system. + GetCurrentDrivers(drivetime,drive); + processes(time,drivetime,drive,par,stat,proc,false); + FmDisplayOutput.FirstWrite := True; + FmDisplayOutput.ClearGrid; + if (not FmOptions.RunOptions.AppendOutputFile) and + (not FmOptions.RunOptions.OutputEORonly) and + (FmOptions.RunOptions.Outputoffset = FmOptions.DefaultRunOptions.Outputoffset) then + FmDisplayOutput.StoreResults(time_start-fullstep, drive, stat, proc); + randomize; // MEL specific + previousstat := stat; + while (time < time_stop + fullstep) and (not steadystate) do + begin +// if time-10 < epsilon then nextstep := FmOptions.RunOptions.Time_step; + for j:=1 to ModelDef.numstate do tempstat[j] := stat[j].value; + RK4_5_Integrator(tempstat, modeldef.numstate, time, time+FmOptions.RunOptions.Time_step, drivetime, + nextstep,drive, par); + for j:=1 to ModelDef.numstate do stat[j].value := tempstat[j]; + temp := abs((time+FmOptions.RunOptions.Time_step)/FmOptions.RunOptions.DiscreteStep - // time + round((time+FmOptions.RunOptions.Time_step)/FmOptions.RunOptions.DiscreteStep)); // time + BeginningofRun := False; + if temp > epsilon then + processes(time, drivetime, drive, par, stat, proc, false) + else + processes(time, drivetime, drive, par, stat, proc, true); +// Write output + FmOptions.RunOptions.outcounter := FmOptions.RunOptions.outcounter + 1; + if FmOptions.RunOptions.OutputEORonly then + begin + if time >= time_stop then FmDisplayOutput.StoreResults(time, drive, stat, proc); + end + else if FmOptions.RunOptions.OutputAnnually then + begin + if DayofYear = FmOptions.RunOptions.OutputAnnuallyDay then + FmDisplayOutput.StoreResults(time, drive, stat, proc); + end + else + begin // All output options except OutputEOR and OutputAnnually + if (time >= FmOptions.RunOptions.Outputoffset) then + begin + if (time = FmOptions.RunOptions.Outputoffset) or + (FmOptions.RunOptions.outcounter = outputfreq) then + begin + if (stepsperfullstep <> fullstep) and + (FmOptions.RunOptions.time_step <> FmOptions.RunOptions.Outputstep) then + FmDisplayOutput.StoreResults(time, drive, stat, proc) + else + FmDisplayOutput.StoreResults(time, drive, stat, proc); + FmOptions.RunOptions.outcounter := FmOptions.DefaultRunOptions.outcounter; + end; + end + else // Haven't reached the outputoffset yet + begin + FmOptions.RunOptions.outcounter := FmOptions.DefaultRunOptions.outcounter; + end; + end; +// Save output to file mid run + if FmOptions.RunOptions.WriteEvery <> 0 then + if frac(time/FmOptions.RunOptions.WriteEvery) < epsilon then + FmDisplayOutput.WritePurgeOutputfromMem; +// Reset State variables option + if FmOptions.RunOptions.ResetStates then + begin + remainder := time - int(time/FmOptions.RunOptions.ResetStateTime)*FmOptions.RunOptions.ResetStateTime; + if remainder = 0 then FmShellMain.ResetStatesNow(BtnRun); + end; +// Run to steady state option + if FmOptions.RunOptions.RuntoSS then + begin + SSstep := (FmOptions.RunOptions.Time_step - FmOptions.RunOptions.SSTime* + (round(FmOptions.RunOptions.Time_step/FmOptions.RunOptions.SSTime))); + SStest := (time - FmOptions.RunOptions.SSTime* + (round(time/FmOptions.RunOptions.SSTime))); + if (SStest >= 0) and (SStest < SSstep) then + begin + steadystate := true; + for j := 1 to ModelDef.numstate do + begin + errorest := abs(previousstat[j].value - + stat[j].value)/stat[j].value; + if errorest <= FmOptions.RunOptions.SSCriteria then + steadystate := steadystate and true + else + steadystate := steadystate and false; + end; + previousstat := stat; + // If outputEORonly then modify time_stop and steadystate so that + // loop executes one more time and then outputs results. + if steadystate and FmOptions.RunOptions.OutputEORonly then + begin + steadystate := false; + time_stop := time + FmOptions.RunOptions.Time_step; + end; + end; + end; +// Next time step + time := time_start + FmOptions.RunOptions.stepcounter*FmOptions.RunOptions.Time_step; + if (not FmOptions.RunOptions.RepeatDrivers) or (time <= FmOptions.RunOptions.RepeatDriveTime) then drivetime := time; + FmOptions.RunOptions.stepcounter := FmOptions.RunOptions.stepcounter + 1; +// Repeat drivers option + if ResetDriverFile then + begin + drivetime := time_start; + last_time := 0; next_time := 0; + ResetDriverFile := False; + end; + if (FmOptions.RunOptions.RepeatDrivers) and (time >= FmOptions.RunOptions.RepeatDriveTime) then + drivetime := time - int(time/FmOptions.RunOptions.RepeatDriveTime)*FmOptions.RunOptions.RepeatDriveTime; // mod function for doubles + if drivetime = 0 then + begin + drivetime := FmOptions.RunOptions.RepeatDriveTime; + ResetDriverFile := True; + end; +// Update progress bar + if RunningInteractive then + FmProgress.PbRunStatus.Position := (round(time - time_start)*100) + div round(time_stop - time_start); +// check for pending messages (for example, the cancel button) + application.ProcessMessages; + if stopRun then break; + end; + finally + if FmOptions.RunOptions.OutputFile then + if FmOptions.RunOptions.WriteEvery = 0 then FmDisplayOutput.WriteOutputfromMem; + stopRun := false; + RunComplete := True; + FmOptions.RunOptions.stepcounter := FmOptions.DefaultRunOptions.stepcounter; + FmOptions.RunOptions.outcounter := FmOptions.DefaultRunOptions.outcounter; + ResetStatesNow(BtnRun); + if RunningInteractive then + begin + UpdateFmShellMain; + FmShellMain.Enabled := True; + FmDisplayOutput.Enabled := True; + PresentBox.Text := floattostrf(Time,ffgeneral,5,1); + FmProgress.Hide; + if (FmDisplayOutput.autoShowChart) and (not FmDisplayOutput.Visible) then + DisplayOutput(MIShowChart); + if LargeOutput then + MessageDlg('Output was very large. To prevent a system crash, output was ' + + 'written to the output file and removed from memory during the run. ' + + 'Only the final portion of the run is in memory. You will need to ' + + 'use a different program to view the results.' ,mtWarning,[mbOK],0); + end + else + begin + // Save parameter file if running a calibration in batch mode + if par[FmCalculate.GetArrayIndex(vtparameter,'calibrate')].value<>-999 then + begin + basename:=ExtractFileName(paramfilename); + theext:=ExtractFileExt(paramfilename); + delete(basename,pos(theext,basename),length(basename)); + anewname:=basename+'.cal'+theext; + // Save the end of the calibration + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + stat, currentresid); + // Create a new parameter file for steady state run. + tempstate:=stat; + endstate:=FmCalculate.GetArrayIndex(vtstate,'RCa'); + for idx := 1 to endstate do + tempstate[idx].Reset:=false; + anewname:=basename+'.final'+theext; + par[FmCalculate.GetArrayIndex(vtparameter,'calibrate')].value:=-999; + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + tempstate, currentresid); + // Create climate parameter files + //CO2 + anewname:=basename+'.CO2'+theext; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagCa')].value:=1; + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + tempstate, currentresid); + //T + anewname:=basename+'.T'+theext; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagCa')].value:=0; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagT')].value:=1; + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + tempstate, currentresid); + //Ppt + anewname:=basename+'.Ppt'+theext; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagT')].value:=0; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagPpt')].value:=1; + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + tempstate, currentresid); + //Call + anewname:=basename+'.Call'+theext; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagCa')].value:=1; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagT')].value:=1; + par[FmCalculate.GetArrayIndex(vtparameter,'FlagPpt')].value:=1; + WriteParamFile(anewname, ModelDef.numparam, par, ModelDef.numstate, + tempstate, currentresid); + + end; + end; + end; + except + on EFileError do raise; + on E: Exception do + begin + if RunningInteractive then + begin + FmTrouble.MmError.Lines.Clear; + FmTrouble.MmError.Lines.Add(E.Message); + FmTrouble.ShowModal; + end + else + raise; + end; + end; +end; + +procedure TFmShellMain.FormDestroy(Sender: TObject); +begin + if Assigned(fileio.driverlist) then + FreeAndNil(fileio.driverlist); +end; + +procedure TFmShellMain.MIExitClick(Sender: TObject); +var + answer:word; +begin + if NeedToSavePar = True then + begin + answer := MessageDlg('Save parameter file before exiting?', + mtConfirmation, mbYesNoCancel, 0); + if answer <> mrCancel then + if answer = mrYes then + begin + DlgSaveParam.Filename := paramfilename; + if DlgSaveParam.execute then + WriteParamFile(paramfilename, ModelDef.numparam, par, + ModelDef.numstate, stat, currentresid); + end + else + close; + end + else close; +end; + +procedure TFmShellMain.MICalTimeClick(Sender: TObject); +begin +// Ask the user for the time to calculate a steady state at. + CalTime := strtofloat(InputBox('Steady State Time', + 'Enter the time from the driver file at which to calculate a steady state.', + floattostr(CalTime))); + RunComplete := False; +end; + +procedure TFmShellMain.MICalcSSClick(Sender: TObject); +begin + FmCalculate.showmodal; +end; + +procedure TFmShellMain.SetNumSpecies(anEditBox: TEdit); // MEL specific +begin +{ if anEditBox.text <> '' then // If a value has been entered. + begin + numspp:= strtoint(anEditBox.text); // Set the number of species + if numspp<1 then numspp:=1; + if numspp>Maxspecies then numspp:=Maxspecies; + anEditBox.text := inttostr(numspp); + counts; + LblWelcome.Visible:=false; + LblWelcome.Enabled:=false; + LblDirections.Visible:=false; + LblDirections.Enabled:=false; + EdNumSpecies.Enabled:=false; + + MIFiles.Enabled:=true; + MIEdit.Enabled:=true; + MIView.Enabled:=true; + ParamLabel.Visible:=true; + Parambox.Visible:=true; + DriverLabel.Visible:=true; + DriverBox.Visible:=true; + OutputLabel.Visible:=true; + OutputBox.Visible:=true; + StartLabel.Visible:=true; + MeStartTime.Visible:=true; + StopLabel.Visible:=true; + MeStopTime.Visible:=true; + StepLabel.Visible:=true; + MeTimeStep.Visible:=true; + BtnRun.Visible:=true; + PresentLabel.Visible:=true; + PresentBox.Visible:=true; + BtnReload.Visible:=true; + if RunningInteractive then + begin + Fmparameter.FormDestroy(EdNumSpecies); + Fmparameter.FormCreate(EdNumSpecies); + Fmdisplaydata.FormCreate(EdNumSpecies); + DataForm.FormCreate(EdNumSpecies); + end; + end; } +end; + +procedure TFmShellMain.EdNumSpeciesChange(Sender: TObject); +begin +{ FmShellMain.SetNumSpecies(FmShellMain.EdNumSpecies); } +end; + +procedure TFmShellMain.EdNumSpeciesExit(Sender: TObject); +begin +{ if EdNumSpecies.text = '' then FmShellMain.ActiveControl := EdNumSpecies; } +end; // MEL specific + +procedure TFmShellMain.MIViewOutFileClick(Sender: TObject); +begin + FmDisplayOutput.MILoadFileClick(Sender) +end; + +procedure TFmShellMain.MEStopTimeKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then MeStopTimeExit(Sender); +end; + +procedure TFmShellMain.MEStartTimeKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then MeStartTimeExit(Sender); +end; + +procedure TFmShellMain.MIOpenOptionsClick(Sender: TObject); +begin + if (Sender as TComponent).name = 'MITimeSteps' then + lastitem := MITimeSteps + else if (Sender as TComponent).name = 'MISpecialRun' then + lastitem := MISpecialRun + else + lastitem := MIOutOptions; + UpdateFmShellMain; + FmOptions.ShowModal; +end; + +procedure TFmShellMain.MINormalRunClick(Sender: TObject); +begin + FmOptions.RunOptions.NormalRun := True; + FmOptions.UpdateFmRunOptions(MINormalRun); + MINormalRun.Checked := True; + RunComplete := False; + Readytorun := False; +end; + +procedure TFmShellMain.ResetStatesNow(Sender: TObject); +var + i: integer; +begin + for i := 1 to ModelDef.numstate do + begin + if stat[i].reset then stat[i].value := initialstates[i].value; + end; +end; + +procedure TFmShellMain.MIAutoChartClick(Sender: TObject); +begin + if MIAutoChart.Checked then + MIAutoChart.Checked := False + else + MIAutoChart.Checked := True; + FmDisplayOutput.AutoShowChart:=MIAutoChart.Checked; +end; + +procedure TFmShellMain.ParamBoxKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseParamFile(Sender); +end; + +procedure TFmShellMain.DriverBoxKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseDriver(Sender); +end; + +procedure TFmShellMain.OutputBoxKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then ChooseOutputFile(Sender); +end; + +procedure TFmShellMain.EdNumSpeciesKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = Chr(13)) then EdNumSpeciesExit(Sender); +end; + +procedure TFmShellMain.ShowProgressBar; +begin + FmProgress.Caption := modeldef.modelname + ' run progress'; + FmProgress.LblBegin.Caption := floattostr(time_start); + FmProgress.LblEnd.Caption := floattostr(time_stop); + FmProgress.CancelProcedure := CancelRun; +// if FmDisplayOutput.Visible then FmProgress.Parent:= FmDisplayOutput; + FmProgress.Show; +end; + +procedure TFmShellMain.CancelRun; +begin + stopRun := True; + FmDisplayOutput.autoShowChart := false; +end; + +function TFmShellMain.GetResourcePath(): string; +{$ifdef Darwin} +var + pathRef:CFURLRef; + pathCFStr: CFStringRef; + pathStr: shortstring; +{$endif} +begin +{$ifdef Unix} +{$ifdef Darwin} + pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle()); + pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle); + CFStringGetPascalString(pathCFStr, @pathStr, 255, CFStringGetSystemEncoding()); + CFRelease(pathRef); + CFRelease(pathCFStr); + + Result := pathStr + BundleResourceDirectory; +{$else} + Result := DefaultUnixDirectory; +{$endif} +{$else} // Windows + Result := ExtractFilePath(Application.exeName); +{$endif} +end; + +end. diff --git a/modelshell/integrator.pas b/modelshell/integrator.pas new file mode 100644 index 0000000..97db007 --- /dev/null +++ b/modelshell/integrator.pas @@ -0,0 +1,143 @@ +{ Code to implement a 4th order Runge-Kutta integrator with adaptive step size + control. This integrator is used to integrate the differential equations in + the equations.pas file. } +unit integrator; + +interface + +uses sysutils, Dialogs, stypes, equations, fileio; + +PROCEDURE RK4_5_Integrator(VAR ystart: yValueArray; nvar: integer; + t1,t2,dr: double; var stepguess:double; + var tdrive:drivearray; var tpar:paramarray); + +implementation + +uses frontend, math, Options; + +PROCEDURE RungeKutta(y: yValueArray; n: integer; t,tstep,dr: double; flag:boolean; + VAR yout, dydt: yValueArray; var tpar:paramarray; var tdrive:drivearray); + +VAR + i: integer; + + ytemp,k,S:yValueArray; +BEGIN + try + if flag then + begin + derivs(t,dr,tdrive,tpar,y,k); // calk dirivs + dydt:=k; // save 1st k for next call + end + else k:=dydt; // use k input to routine + for i:=1 to n do S[i]:=k[i]/6; // 1st k + + FOR i := 1 to n DO ytemp[i] := y[i] + tstep*k[i]/2; // half step 1 + derivs(t+tstep/2,dr+tstep/2,tdrive,tpar,ytemp,k); // calk dirivs + for i:=1 to n do S[i]:=S[i]+k[i]/3; // 2nd k + + FOR i := 1 to n DO ytemp[i] := y[i] + tstep*k[i]/2; // half step 2 + derivs(t+tstep/2,dr+tstep/2,tdrive,tpar,ytemp,k); // calk dirivs + for i:=1 to n do S[i]:=S[i]+k[i]/3; // 3rd k + + FOR i := 1 to n DO ytemp[i] := y[i] + tstep*k[i]; // full step + derivs(t+tstep,dr+tstep,tdrive,tpar,ytemp,k); // calk dirivs + for i:=1 to n do S[i]:=S[i]+k[i]/6; // 4th k + + for i:=1 to n do yout[i]:=y[i]+S[i]*tstep; // estimate new y + except + raise; + end; +END; + + +PROCEDURE TimestepControl(VAR y:yValueArray; n: integer; VAR t, dr: double; + steptry: double; VAR stepdid,stepnext: double; + var tdrive:drivearray; var tpar:paramarray; var index: integer); +Const + eps= 0.0001; +VAR + tstep, emax,scale: double; + ytemp,yout,epsilon,dydt:yValueArray; + i:integer; + flag,flag2:boolean; + tdrivehalftime:drivearray; +Begin + emax:=2*eps; + flag:=true; + flag2:=true; + while flag2 do + begin + counttt:=counttt+1; + tstep:=steptry/2; + if (t = t+tstep) THEN + raise EIntStepTooSmall.Create('Step size too small in TimestepControl ' + + 'Error caused by state variable, ' + stat[index].name + '.'); { TODO -cVisual : Remove word state from error message so that the actual variable name shows up in the box. On some computers it gets cut off. } + RungeKutta(y, n, t,tstep,dr, Flag, ytemp, dydt, tpar, tdrive); + flag:=false; + tdrivehalftime:=tdrive; + GetCurrentDrivers(dr+tstep,tdrivehalftime); + RungeKutta(ytemp, n, t+tstep, tstep, dr+tstep, TRUE, yout, epsilon, tpar, tdrivehalftime); + RungeKutta(y, n, t, steptry, dr, FALSE, ytemp, dydt, tpar, tdrive); + emax:=0; + index:=0; + For i:=1 to n do + begin + epsilon[i]:=yout[i]-ytemp[i]; + scale := FmOptions.RunOptions.Errormult*max(abs(y[i]), eps)+1e-30; + if emax < abs(epsilon[i])/scale then + begin + emax:=abs(epsilon[i])/scale; + index:=i; + end; + end; + stepdid:=steptry; + if emax>eps then stepnext:=0.9*steptry*power(eps/emax,1/4) + else + begin + if emax>0 then stepnext:=1.1*steptry*power(eps/emax,1/5) + else stepnext:=2*steptry; + flag2:=false; + end; + steptry:=stepnext; + end; {while} + For i:=1 to n do y[i]:=yout[i]+epsilon[i]/15; +End; + + +PROCEDURE RK4_5_Integrator(VAR ystart: yValueArray; nvar: integer; + t1,t2,dr: double; var stepguess:double; + var tdrive:drivearray; var tpar:paramarray); + +VAR + numstep,i, index: integer; + t,stepnext,stepdid,step, stepmin:double; + y: yValueArray; +BEGIN + stepmin:=0.000001*FmOptions.RunOptions.Time_step; + t := t1; + step := stepguess; + y := ystart; + Numstep:=0; + While tt2 then step:=t2-t; // avoid overstep + TimestepControl(y,nvar,t,dr,step,stepdid,stepnext,tdrive,tpar,index); + t:=t+stepdid; + dr:=dr+stepdid; + step:=stepnext; + ystart := y; + stepguess := stepnext; + Numstep:=numstep+1; + IF (abs(stepnext) < stepmin) THEN + raise EIntStepTooSmall.Create('Step size too small in Integrator. ' + + 'Error caused by state variable, ' + stat[index].name + '.'); + IF numstep>10000 THEN + raise EIntStepTooSmall.Create('Too many steps in Integrator. ' + + 'Error caused by state variable, ' + stat[index].name + '.'); + end; + END; + + +end. diff --git a/modelshell/modelbatch.lpi b/modelshell/modelbatch.lpi new file mode 100644 index 0000000..c522b7c --- /dev/null +++ b/modelshell/modelbatch.lpi @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <BuildModes Count="1"> + <Item1 Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> + </RunParams> + <RequiredPackages Count="3"> + <Item1> + <PackageName Value="TAChartLazarusPkg"/> + </Item1> + <Item2> + <PackageName Value="Printer4Lazarus"/> + </Item2> + <Item3> + <PackageName Value="LCL"/> + </Item3> + </RequiredPackages> + <Units Count="20"> + <Unit0> + <Filename Value="modelbatch.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="batchmain.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmBatchMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + <Unit2> + <Filename Value="aboutbox.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit2> + <Unit3> + <Filename Value="calculate.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit3> + <Unit4> + <Filename Value="data.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit4> + <Unit5> + <Filename Value="display.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UnitName Value="Display"/> + </Unit5> + <Unit6> + <Filename Value="equations.pas"/> + <IsPartOfProject Value="True"/> + </Unit6> + <Unit7> + <Filename Value="fileio.pas"/> + <IsPartOfProject Value="True"/> + </Unit7> + <Unit8> + <Filename Value="frontend.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmShellMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit8> + <Unit9> + <Filename Value="integrator.pas"/> + <IsPartOfProject Value="True"/> + </Unit9> + <Unit10> + <Filename Value="note.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit10> + <Unit11> + <Filename Value="ProgressBar.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit11> + <Unit12> + <Filename Value="ReloadDlg.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit12> + <Unit13> + <Filename Value="ScaleDlg.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit13> + <Unit14> + <Filename Value="SeriesForm.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit14> + <Unit15> + <Filename Value="stypes.pas"/> + <IsPartOfProject Value="True"/> + </Unit15> + <Unit16> + <Filename Value="trouble.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UnitName Value="TROUBLE"/> + </Unit16> + <Unit17> + <Filename Value="ParamList.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit17> + <Unit18> + <Filename Value="Options.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + </Unit18> + <Unit19> + <Filename Value="parameter.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmParameter"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit19> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="..\ses2011\Modeling\code versions\modelshellv653 Weds morn crashing"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="delphi"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/modelshell/modelbatch.lpr b/modelshell/modelbatch.lpr new file mode 100644 index 0000000..9c29420 --- /dev/null +++ b/modelshell/modelbatch.lpr @@ -0,0 +1,37 @@ +program modelbatch; + +uses + Forms, Interfaces, + batchmain in 'batchmain.pas' {FmBatchMain}, + aboutbox in 'aboutbox.pas' {FmAbout}, + calculate in 'calculate.pas' {FmCalculate}, + data in 'data.pas' {DataForm}, + Display in 'Display.pas' {FmDisplayData}, + equations in 'equations.pas', + fileio in 'fileio.pas', + frontend in 'frontend.pas' {MainForm}, + integrator in 'integrator.pas', + note in 'note.pas' {FmNote}, + ProgressBar in 'ProgressBar.pas' {FmProgress}, + ReloadDlg in 'ReloadDlg.pas' {DlgReload}, + ScaleDlg in 'Scaledlg.pas' {DlgScale}, + SeriesForm in 'SeriesForm.pas' {FmSeries}, + stypes in 'stypes.pas', + trouble in 'Trouble.pas' {FmTrouble}, + ParamList in 'ParamList.pas' {FmParamList}, + Options in 'Options.pas' {FmOptions}; + +{$R *.res} + +begin + Application.Initialize; + Application.CreateForm(TFmBatchMain, FmBatchMain); + Application.CreateForm(TFmAbout, FmAbout); + Application.CreateForm(TFmShellMain, FmShellMain); + Application.CreateForm(TFmParamList, FmParamList); + Application.CreateForm(TFmDisplayOutput, FmDisplayOutput); + Application.CreateForm(TFmOptions, FmOptions); + FmShellMain.Visible := False; + FmShellMain.Enabled := False; + Application.Run; +end. diff --git a/modelshell/modelbatch.lps b/modelshell/modelbatch.lps new file mode 100644 index 0000000..15fc53b --- /dev/null +++ b/modelshell/modelbatch.lps @@ -0,0 +1,358 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <PathDelim Value="\"/> + <Version Value="11"/> + <BuildModes Active="Default"/> + <Units Count="22"> + <Unit0> + <Filename Value="modelbatch.lpr"/> + <IsPartOfProject Value="True"/> + <CursorPos X="91" Y="19"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit0> + <Unit1> + <Filename Value="batchmain.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmBatchMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="2"/> + <TopLine Value="195"/> + <CursorPos Y="217"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit1> + <Unit2> + <Filename Value="aboutbox.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="3"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit2> + <Unit3> + <Filename Value="calculate.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="4"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit3> + <Unit4> + <Filename Value="data.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="5"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit4> + <Unit5> + <Filename Value="display.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UnitName Value="Display"/> + <EditorIndex Value="6"/> + <TopLine Value="649"/> + <CursorPos Y="686"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit5> + <Unit6> + <Filename Value="equations.pas"/> + <IsPartOfProject Value="True"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="1"/> + <TopLine Value="7715"/> + <CursorPos X="17" Y="7742"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit6> + <Unit7> + <Filename Value="fileio.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="7"/> + <TopLine Value="91"/> + <CursorPos Y="117"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit7> + <Unit8> + <Filename Value="frontend.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmShellMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="9"/> + <TopLine Value="562"/> + <CursorPos X="118" Y="576"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit8> + <Unit9> + <Filename Value="integrator.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="8"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit9> + <Unit10> + <Filename Value="note.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit10> + <Unit11> + <Filename Value="ProgressBar.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit11> + <Unit12> + <Filename Value="ReloadDlg.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="10"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit12> + <Unit13> + <Filename Value="ScaleDlg.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="11"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit13> + <Unit14> + <Filename Value="SeriesForm.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <EditorIndex Value="12"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit14> + <Unit15> + <Filename Value="stypes.pas"/> + <IsPartOfProject Value="True"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit15> + <Unit16> + <Filename Value="trouble.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UnitName Value="TROUBLE"/> + <EditorIndex Value="13"/> + <UsageCount Value="81"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit16> + <Unit17> + <Filename Value="ParamList.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit17> + <Unit18> + <Filename Value="Options.pas"/> + <IsPartOfProject Value="True"/> + <HasResources Value="True"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit18> + <Unit19> + <Filename Value="parameter.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmParameter"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UsageCount Value="81"/> + </Unit19> + <Unit20> + <Filename Value="params.pas"/> + <HasResources Value="True"/> + <EditorIndex Value="-1"/> + <CursorPos X="46" Y="20"/> + <UsageCount Value="15"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit20> + <Unit21> + <Filename Value="..\ses2011\Modeling\code versions\modelshellv653 Weds morn crashing\bkPageControl.pas"/> + <CursorPos X="91" Y="18"/> + <UsageCount Value="15"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit21> + </Units> + <JumpHistory Count="30" HistoryIndex="29"> + <Position1> + <Filename Value="batchmain.pas"/> + <Caret Line="135" Column="25" TopLine="92"/> + </Position1> + <Position2> + <Filename Value="batchmain.pas"/> + <Caret Line="118" TopLine="92"/> + </Position2> + <Position3> + <Filename Value="batchmain.pas"/> + <Caret Line="217" TopLine="103"/> + </Position3> + <Position4> + <Filename Value="batchmain.pas"/> + <Caret Line="135" Column="25" TopLine="115"/> + </Position4> + <Position5> + <Filename Value="frontend.pas"/> + <Caret Line="592" Column="82" TopLine="574"/> + </Position5> + <Position6> + <Filename Value="frontend.pas"/> + <Caret Line="364" Column="91" TopLine="328"/> + </Position6> + <Position7> + <Filename Value="frontend.pas"/> + <Caret Line="543" Column="77" TopLine="500"/> + </Position7> + <Position8> + <Filename Value="frontend.pas"/> + <Caret Line="544" Column="59" TopLine="501"/> + </Position8> + <Position9> + <Filename Value="frontend.pas"/> + <Caret Line="148" Column="43" TopLine="123"/> + </Position9> + <Position10> + <Filename Value="frontend.pas"/> + <Caret Line="333" Column="31" TopLine="290"/> + </Position10> + <Position11> + <Filename Value="frontend.pas"/> + <Caret Line="335" Column="38" TopLine="292"/> + </Position11> + <Position12> + <Filename Value="frontend.pas"/> + <Caret Line="339" Column="41" TopLine="296"/> + </Position12> + <Position13> + <Filename Value="frontend.pas"/> + <Caret Line="340" Column="70" TopLine="297"/> + </Position13> + <Position14> + <Filename Value="frontend.pas"/> + <Caret Line="341" Column="45" TopLine="298"/> + </Position14> + <Position15> + <Filename Value="frontend.pas"/> + <Caret Line="344" Column="18" TopLine="301"/> + </Position15> + <Position16> + <Filename Value="frontend.pas"/> + <Caret Line="346" Column="17" TopLine="303"/> + </Position16> + <Position17> + <Filename Value="frontend.pas"/> + <Caret Line="348" Column="48" TopLine="305"/> + </Position17> + <Position18> + <Filename Value="frontend.pas"/> + <Caret Line="350" Column="70" TopLine="307"/> + </Position18> + <Position19> + <Filename Value="frontend.pas"/> + <Caret Line="353" Column="22" TopLine="310"/> + </Position19> + <Position20> + <Filename Value="frontend.pas"/> + <Caret Line="357" Column="46" TopLine="314"/> + </Position20> + <Position21> + <Filename Value="frontend.pas"/> + <Caret Line="543" Column="77" TopLine="500"/> + </Position21> + <Position22> + <Filename Value="frontend.pas"/> + <Caret Line="544" Column="59" TopLine="480"/> + </Position22> + <Position23> + <Filename Value="display.pas"/> + <Caret Line="147" Column="33" TopLine="113"/> + </Position23> + <Position24> + <Filename Value="display.pas"/> + <Caret Line="325" Column="23" TopLine="282"/> + </Position24> + <Position25> + <Filename Value="display.pas"/> + <Caret Line="686" TopLine="649"/> + </Position25> + <Position26> + <Filename Value="batchmain.pas"/> + <Caret Line="121" TopLine="95"/> + </Position26> + <Position27> + <Filename Value="batchmain.pas"/> + <Caret Line="122" TopLine="95"/> + </Position27> + <Position28> + <Filename Value="batchmain.pas"/> + <Caret Line="123" TopLine="95"/> + </Position28> + <Position29> + <Filename Value="batchmain.pas"/> + <Caret Line="217" TopLine="195"/> + </Position29> + <Position30> + <Filename Value="equations.pas"/> + <Caret Line="4593" Column="118" TopLine="4555"/> + </Position30> + </JumpHistory> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0" ActiveMode="default"/> + </RunParams> + </ProjectSession> + <Debugging> + <BreakPoints Count="3"> + <Item1> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="batchmain.pas"/> + <Line Value="217"/> + </Item1> + <Item2> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="batchmain.pas"/> + <Line Value="121"/> + </Item2> + <Item3> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="display.pas"/> + <Line Value="686"/> + </Item3> + </BreakPoints> + </Debugging> +</CONFIG> diff --git a/modelshell/modelbatch.res b/modelshell/modelbatch.res new file mode 100644 index 0000000..b684375 Binary files /dev/null and b/modelshell/modelbatch.res differ diff --git a/modelshell/modelshellv654.ico b/modelshell/modelshellv654.ico new file mode 100644 index 0000000..0341321 Binary files /dev/null and b/modelshell/modelshellv654.ico differ diff --git a/modelshell/modelshellv654.lpi b/modelshell/modelshellv654.lpi new file mode 100644 index 0000000..ee44fec --- /dev/null +++ b/modelshell/modelshellv654.lpi @@ -0,0 +1,562 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasUsesSectionForAllUnits Value="False"/> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + </Flags> + <MainUnit Value="0"/> + <Title Value="modelshellv654"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <Icon Value="0"/> + </General> + <LazDoc Paths="."/> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <BuildModes Count="3" Active="Release"> + <Item1 Name="Default" Default="True"/> + <Item2 Name="Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <Verbosity> + <ShoLineNum Value="True"/> + </Verbosity> + </Other> + </CompilerOptions> + </Item2> + <Item3 Name="Release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <Verbosity> + <ShoLineNum Value="True"/> + </Verbosity> + </Other> + </CompilerOptions> + </Item3> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> + </RunParams> + <RequiredPackages Count="3"> + <Item1> + <PackageName Value="Printer4Lazarus"/> + <MinVersion Minor="5" Valid="True"/> + </Item1> + <Item2> + <PackageName Value="TAChartLazarusPkg"/> + <MinVersion Major="1" Valid="True"/> + </Item2> + <Item3> + <PackageName Value="LCL"/> + </Item3> + </RequiredPackages> + <Units Count="22"> + <Unit0> + <Filename Value="modelshellv654.lpr"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="3"/> + <CursorPos Y="47"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit0> + <Unit1> + <Filename Value="frontend.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmShellMain"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <TopLine Value="44"/> + <CursorPos X="76" Y="61"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit1> + <Unit2> + <Filename Value="aboutbox.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmAbout"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit2> + <Unit3> + <Filename Value="trouble.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmTrouble"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="TROUBLE"/> + <EditorIndex Value="-1"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit3> + <Unit4> + <Filename Value="data.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="DataForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="6"/> + <TopLine Value="62"/> + <CursorPos Y="107"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit4> + <Unit5> + <Filename Value="equations.pas"/> + <IsPartOfProject Value="True"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="10"/> + <TopLine Value="1130"/> + <CursorPos X="17" Y="1166"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit5> + <Unit6> + <Filename Value="fileio.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="4"/> + <TopLine Value="135"/> + <CursorPos Y="162"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit6> + <Unit7> + <Filename Value="integrator.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="7"/> + <TopLine Value="88"/> + <CursorPos X="61" Y="127"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit7> + <Unit8> + <Filename Value="note.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmNote"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="5"/> + <TopLine Value="46"/> + <CursorPos Y="7"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit8> + <Unit9> + <Filename Value="Options.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmOptions"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit9> + <Unit10> + <Filename Value="ParamList.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmParamList"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <TopLine Value="21"/> + <CursorPos X="40" Y="38"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit10> + <Unit11> + <Filename Value="ProgressBar.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmProgress"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="2"/> + <CursorPos Y="55"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit11> + <Unit12> + <Filename Value="ReloadDlg.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="DlgReload"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <CursorPos Y="5"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit12> + <Unit13> + <Filename Value="ScaleDlg.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="DlgScale"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <CursorPos Y="8"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit13> + <Unit14> + <Filename Value="SeriesForm.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmSeries"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="-1"/> + <CursorPos X="56" Y="10"/> + <UsageCount Value="248"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit14> + <Unit15> + <Filename Value="stypes.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <CursorPos X="38" Y="20"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit15> + <Unit16> + <Filename Value="calculate.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmCalculate"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="9"/> + <TopLine Value="44"/> + <CursorPos X="50" Y="71"/> + <UsageCount Value="248"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit16> + <Unit17> + <Filename Value="display.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmDisplayOutput"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="Display"/> + <EditorIndex Value="1"/> + <CursorPos X="34" Y="27"/> + <UsageCount Value="270"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit17> + <Unit18> + <Filename Value="parameter.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FmParameter"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="8"/> + <TopLine Value="96"/> + <CursorPos X="29" Y="136"/> + <UsageCount Value="230"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit18> + <Unit19> + <Filename Value="C:\lazarusv164\lcl\grids.pas"/> + <UnitName Value="Grids"/> + <EditorIndex Value="-1"/> + <TopLine Value="10307"/> + <CursorPos Y="10334"/> + <UsageCount Value="81"/> + </Unit19> + <Unit20> + <Filename Value="C:\lazarusv206\lcl\grids.pas"/> + <UnitName Value="Grids"/> + <EditorIndex Value="-1"/> + <TopLine Value="9884"/> + <CursorPos Y="9902"/> + <UsageCount Value="6"/> + </Unit20> + <Unit21> + <Filename Value="C:\Users\bkwia\AppData\Local\Temp\equations.pas"/> + <EditorIndex Value="-1"/> + <UsageCount Value="7"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit21> + </Units> + <JumpHistory Count="30" HistoryIndex="29"> + <Position1> + <Filename Value="equations.pas"/> + <Caret Line="4533" Column="20" TopLine="4507"/> + </Position1> + <Position2> + <Filename Value="equations.pas"/> + <Caret Line="7723" Column="17" TopLine="7696"/> + </Position2> + <Position3> + <Filename Value="equations.pas"/> + <Caret Line="7668" Column="94" TopLine="7647"/> + </Position3> + <Position4> + <Filename Value="equations.pas"/> + <Caret Line="7679" Column="17" TopLine="7652"/> + </Position4> + <Position5> + <Filename Value="equations.pas"/> + <Caret Line="7681" Column="17" TopLine="7654"/> + </Position5> + <Position6> + <Filename Value="equations.pas"/> + <Caret Line="7672" Column="100" TopLine="7663"/> + </Position6> + <Position7> + <Filename Value="equations.pas"/> + <Caret Line="7696" Column="17" TopLine="7669"/> + </Position7> + <Position8> + <Filename Value="equations.pas"/> + <Caret Line="7834" Column="9" TopLine="7787"/> + </Position8> + <Position9> + <Filename Value="equations.pas"/> + <Caret Line="7836" Column="9" TopLine="7789"/> + </Position9> + <Position10> + <Filename Value="equations.pas"/> + <Caret Line="7977" Column="27" TopLine="7930"/> + </Position10> + <Position11> + <Filename Value="equations.pas"/> + <Caret Line="8112" Column="28" TopLine="8065"/> + </Position11> + <Position12> + <Filename Value="equations.pas"/> + <Caret Line="725" Column="64" TopLine="698"/> + </Position12> + <Position13> + <Filename Value="equations.pas"/> + <Caret Line="3297" Column="71" TopLine="3250"/> + </Position13> + <Position14> + <Filename Value="equations.pas"/> + <Caret Line="4349" Column="16" TopLine="4302"/> + </Position14> + <Position15> + <Filename Value="equations.pas"/> + <Caret Line="4531" Column="39" TopLine="4484"/> + </Position15> + <Position16> + <Filename Value="equations.pas"/> + <Caret Line="4975" Column="7" TopLine="4928"/> + </Position16> + <Position17> + <Filename Value="equations.pas"/> + <Caret Line="5232" Column="7" TopLine="5205"/> + </Position17> + <Position18> + <Filename Value="equations.pas"/> + <Caret Line="5497" Column="8" TopLine="5450"/> + </Position18> + <Position19> + <Filename Value="equations.pas"/> + <Caret Line="6481" Column="33" TopLine="6434"/> + </Position19> + <Position20> + <Filename Value="equations.pas"/> + <Caret Line="6665" Column="53" TopLine="6618"/> + </Position20> + <Position21> + <Filename Value="equations.pas"/> + <Caret Line="4619" Column="18" TopLine="4591"/> + </Position21> + <Position22> + <Filename Value="equations.pas"/> + <Caret Line="7759" Column="17" TopLine="7730"/> + </Position22> + <Position23> + <Filename Value="modelshellv654.lpr"/> + <Caret Line="47"/> + </Position23> + <Position24> + <Filename Value="equations.pas"/> + <Caret Line="4619" Column="7" TopLine="4591"/> + </Position24> + <Position25> + <Filename Value="modelshellv654.lpr"/> + <Caret Line="47"/> + </Position25> + <Position26> + <Filename Value="equations.pas"/> + <Caret Line="4619" Column="18" TopLine="4590"/> + </Position26> + <Position27> + <Filename Value="equations.pas"/> + <Caret Line="7766" TopLine="7736"/> + </Position27> + <Position28> + <Filename Value="equations.pas"/> + <Caret Line="4619" Column="18" TopLine="4591"/> + </Position28> + <Position29> + <Filename Value="equations.pas"/> + <Caret Line="7722" Column="17" TopLine="7693"/> + </Position29> + <Position30> + <Filename Value="equations.pas"/> + <Caret Line="4619" Column="18" TopLine="4591"/> + </Position30> + </JumpHistory> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + </Checks> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <Verbosity> + <ShoLineNum Value="True"/> + </Verbosity> + </Other> + </CompilerOptions> + <Debugging> + <BreakPoints Count="1"> + <Item1> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="display.pas"/> + <Line Value="1508"/> + </Item1> + </BreakPoints> + <Watches Count="6"> + <Item1> + <Expression Value="time"/> + </Item1> + <Item2> + <Expression Value="time"/> + </Item2> + <Item3> + <Expression Value="doy"/> + </Item3> + <Item4> + <Expression Value="Cumfbc"/> + </Item4> + <Item5> + <Expression Value="tstat[117].name"/> + </Item5> + <Item6> + <Expression Value="fbc"/> + </Item6> + </Watches> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/modelshell/modelshellv654.lpr b/modelshell/modelshellv654.lpr new file mode 100644 index 0000000..a871d0d --- /dev/null +++ b/modelshell/modelshellv654.lpr @@ -0,0 +1,47 @@ +program modelshellv654; + +{$MODE Delphi} + +uses + Forms, Interfaces, + frontend in 'frontend.pas' {FmShellMain}, + aboutbox in 'aboutbox.pas' {FmAbout}, +// bkPageControl in 'bkPageControl.pas', { TODO 2 -obk : add pagecontrol back in } + trouble in 'trouble.pas' {FmTrouble}, + data in 'data.pas' {DataForm}, + display in 'display.pas' {FmDisplayOutput}, + equations in 'equations.pas', + fileio in 'fileio.pas', + integrator in 'integrator.pas', + note in 'note.pas' {FmNote}, + Options in 'Options.pas' {FmOptions}, + ParamList in 'ParamList.pas' {FmParamList}, + parameter in 'parameter.pas' {FmParameter}, + ProgressBar in 'ProgressBar.pas' {FmProgress}, + ReloadDlg in 'ReloadDlg.pas' {DlgReload}, + ScaleDlg in 'ScaleDlg.pas' {DlgScale}, + SeriesForm in 'SeriesForm.pas' {FmSeries}, + stypes in 'stypes.pas', + calculate in 'calculate.pas' {FmCalculate}; + +{$R *.res} + +begin + Application.Initialize; + Application.Title := 'Modelshell'; + Application.CreateForm(TFmShellMain, FmShellMain); + Application.CreateForm(TFmOptions, FmOptions); + Application.CreateForm(TFmDisplayOutput, FmDisplayOutput); + Application.CreateForm(TDataForm, DataForm); + Application.CreateForm(TFmAbout, FmAbout); + Application.CreateForm(TFmTrouble, FmTrouble); + Application.CreateForm(TFmNote, FmNote); + Application.CreateForm(TFmParamList, FmParamList); + Application.CreateForm(TFmParameter, FmParameter); + Application.CreateForm(TFmProgress, FmProgress); + Application.CreateForm(TDlgReload, DlgReload); + Application.CreateForm(TDlgScale, DlgScale); + Application.CreateForm(TFmSeries, FmSeries); + Application.CreateForm(TFmCalculate, FmCalculate); + Application.Run; +end. diff --git a/modelshell/modelshellv654.res b/modelshell/modelshellv654.res new file mode 100644 index 0000000..f6e8499 Binary files /dev/null and b/modelshell/modelshellv654.res differ diff --git a/modelshell/note.lfm b/modelshell/note.lfm new file mode 100644 index 0000000..a58de3e --- /dev/null +++ b/modelshell/note.lfm @@ -0,0 +1,74 @@ +object FmNote: TFmNote + Left = 247 + Height = 488 + Top = 117 + Width = 688 + ClientHeight = 488 + ClientWidth = 688 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + OnShow = FormShow + Position = poDefault + LCLVersion = '1.6.0.4' + object MoDrivers: TMemo + Left = 0 + Height = 440 + Top = 0 + Width = 688 + Align = alClient + BorderStyle = bsNone + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Courier New' + Lines.Strings = ( + '' + '' + ) + ParentFont = False + ScrollBars = ssBoth + TabOrder = 0 + WordWrap = False + end + object Panel1: TPanel + Left = 0 + Height = 48 + Top = 440 + Width = 688 + Align = alBottom + ClientHeight = 48 + ClientWidth = 688 + TabOrder = 1 + object BtnSaveFile: TButton + Left = 408 + Height = 20 + Top = 8 + Width = 116 + Caption = '&Save File' + ModalResult = 1 + OnClick = BtnSaveFileClick + TabOrder = 0 + end + object BtnClose: TButton + Left = 568 + Height = 20 + Top = 8 + Width = 90 + Cancel = True + Caption = '&Close' + ModalResult = 2 + OnClick = BtnCloseClick + TabOrder = 1 + end + object BtnChooseFile: TButton + Left = 3 + Height = 20 + Top = 11 + Width = 160 + Caption = 'C&hoose Driver File' + OnClick = BtnChooseFileClick + TabOrder = 2 + end + end +end diff --git a/modelshell/note.pas b/modelshell/note.pas new file mode 100644 index 0000000..06e824f --- /dev/null +++ b/modelshell/note.pas @@ -0,0 +1,145 @@ +{ A notepad like editor which is used to view and edit the driver file. The + form consists of a memo component which displays the driver file and buttons + to save changes made to the drivers, choose a different driver file and close + the window. } +unit note; + +{$MODE Delphi} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls; + +type + + { TFmNote } + + TFmNote = class(TForm) + MoDrivers: TMemo; + Panel1: TPanel; + BtnSaveFile: TButton; + BtnClose: TButton; + BtnChooseFile: TButton; + procedure FormShow(Sender: TObject); + procedure BtnSaveFileClick(Sender: TObject); + procedure BtnChooseFileClick(Sender: TObject); + procedure BtnCloseClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + FmNote: TFmNote; + +implementation + +{$R *.lfm} + +uses frontend, fileio; + +{ Set the form title and read the driver variables from the driver file into the + memo component. } +procedure TFmNote.FormShow(Sender: TObject); +var + tempstring1,tempstring2: string; + ttstring:Tstringlist; + ll: integer; +begin +// Clear the memo component of old data + MoDrivers.Lines.Clear; + +// No driver file selected + if driverfilename = '' then + begin + FmNote.Caption := 'Driver Variables - No driver file selected'; + { Add driver names and units to the memo field even if no driver file was + specified. This allows the creation of new driver files. } + // Time column + tempstring1 := 'Time'; + tempstring2 := ModelDef.timeunit; + // Driver variable columns + for ll := 1 to ModelDef.numdrive do + begin + tempstring1 := tempstring1 + ', ' + drive[ll].name; + tempstring2 := tempstring2 + ', ' + drive[ll].units; + end; + // Copy temporary strings to memo component. + MoDrivers.Lines.Strings[0] := tempstring1; + MoDrivers.Lines.Add(tempstring2); + end + else + begin + Caption := 'Driver Variables - ' + driverfilename; + // If a driverfile was selected, read in the file + ttstring:=Tstringlist.Create; + try try + MoDrivers.Lines.LoadFromFile(driverfilename); + // Check to make sure the drivers read are consistent with the model + ttstring.Delimiter:=','; + ttstring.StrictDelimiter:=true; + ttstring.DelimitedText:=MoDrivers.Lines[0]; + for ll:=1 to ModelDef.numdrive do + begin + tempstring1:=lowercase(trim(ttstring[ll])); + if tempstring1 <> lowercase(drive[ll].name) then + raise Exception.Create('Drivers in the driver file do not match model drivers.'); + end; + finally + if Assigned(ttstring) then FreeAndNil(ttstring); + end; + except + raise; + end; + end; + MoDrivers.Modified := False; +end; + +{ Save changes made to the drivers in the memo component. } +procedure TFmNote.BtnSaveFileClick(Sender: TObject); +begin + FmShellMain.DlgSaveDriver.InitialDir := FmShellMain.CurrentPath; + // Set the default filename in the save dialog box to the current driverfile + if driverfilename <> '' then + FmShellMain.DlgSaveDriver.FileName := driverfilename; +// If the user chooses OK in the save dialog box + if FmShellMain.DlgSaveDriver.execute then + begin + // Save the driver filename from the save dialog + Driverfilename := FmShellMain.DlgSaveDriver.filename; + { Save the file. Note that this function does not use the WriteDriverFile + procedure provided in fileio.pas. This is because it is easier to save the + file from the memo component directly then to parse the lines in the memo + component into individual lines and then save them. } + MoDrivers.Lines.SavetoFile(DriverFileName); + MoDrivers.Modified:=False; +// NewDriverFile := False; + end; + FmNote.Close; +end; + +{ This procedure allows the user to choose a different driverfile without having + to exit the current form. } +procedure TFmNote.BtnChooseFileClick(Sender: TObject); +begin + FmShellMain.ChooseDriver(FmNote); + // Update the notepad form with the new driver variables + formshow(BtnChooseFile); +end; + +procedure TFmNote.BtnCloseClick(Sender: TObject); +begin + if MoDrivers.Modified then + begin + if MessageDlg('The changes you made to the drivers are about to be lost. ' + + 'Do you want to save the driver file before proceeding?' , + mtWarning,[mbyes,mbno],0) = mryes then BtnSaveFileClick(BtnClose); + end; +// FmNote.ModalResult := mrOK; + FmNote.Close; +end; + +end. diff --git a/modelshell/parameter.lfm b/modelshell/parameter.lfm new file mode 100644 index 0000000..2735f38 --- /dev/null +++ b/modelshell/parameter.lfm @@ -0,0 +1,80 @@ +object FmParameter: TFmParameter + Left = 628 + Height = 371 + Top = 211 + Width = 626 + HorzScrollBar.Visible = False + VertScrollBar.Visible = False + ActiveControl = BtnCancel + Caption = 'Model Parameters' + ClientHeight = 371 + ClientWidth = 626 + Constraints.MinHeight = 50 + Constraints.MinWidth = 500 + OnCreate = FormCreate + Position = poMainFormCenter + LCLVersion = '1.0.12.0' + object PnTop: TPanel + Left = 0 + Height = 56 + Top = 0 + Width = 626 + Align = alTop + ClientHeight = 56 + ClientWidth = 626 + TabOrder = 0 + object BtnOK: TButton + Left = 176 + Height = 25 + Top = 16 + Width = 75 + Caption = '&OK' + ModalResult = 1 + OnClick = BtnOKClick + TabOrder = 0 + end + object BtnCancel: TButton + Left = 264 + Height = 25 + Top = 16 + Width = 75 + Caption = '&Cancel' + ModalResult = 2 + OnClick = BtnCancelClick + TabOrder = 1 + end + object BtnProcessVar: TButton + Left = 8 + Height = 25 + Top = 16 + Width = 120 + Caption = '&Show Processes' + Enabled = False + OnClick = BtnProcessVarClick + TabOrder = 2 + end + end + object SgParameter: TStringGrid + Left = 0 + Height = 315 + Top = 56 + Width = 626 + Align = alClient + AutoAdvance = aaDown + AutoFillColumns = True + ColCount = 4 + DefaultColWidth = 150 + DefaultRowHeight = 25 + FixedCols = 0 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected] + TabOrder = 1 + OnDrawCell = SgParameterDrawCell + OnSelectCell = SgParameterSelectCell + ColWidths = ( + 155 + 155 + 155 + 157 + ) + end +end diff --git a/modelshell/parameter.pas b/modelshell/parameter.pas new file mode 100644 index 0000000..30c3dce --- /dev/null +++ b/modelshell/parameter.pas @@ -0,0 +1,179 @@ +unit parameter; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, + Grids, StdCtrls, stypes; + +type + + { TFmParameter } + + TFmParameter = class(TForm) + BtnOK: TButton; + BtnCancel: TButton; + BtnProcessVar: TButton; + PnTop: TPanel; + SgParameter: TStringGrid; + procedure BtnCancelClick(Sender: TObject); + procedure BtnOKClick(Sender: TObject); + procedure BtnProcessVarClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure SgParameterDrawCell(Sender: TObject; aCol, aRow: Integer; + aRect: TRect; aState: TGridDrawState); + procedure SgParameterSelectCell(Sender: TObject; aCol, aRow: Integer; + var CanSelect: Boolean); + private + { private declarations } + fOrigPar: paramarray; + public + { public declarations } + procedure ShowParameters; + procedure UpdateProcessWindow; + end; + +var + FmParameter: TFmParameter; + +implementation + +uses frontend, data, fileio, equations; +{$R *.lfm} + +{ TFmParameter } + +procedure TFmParameter.FormCreate(Sender: TObject); +var + i:integer; +begin + // Make sure form is visible and fits on the screen + with FmParameter do + begin + if Width>Screen.WorkAreaWidth then Width:=Screen.WorkAreaWidth; + if Height>Screen.WorkAreaHeight then Height:=Screen.WorkAreaHeight; + if Left<Screen.WorkAreaLeft then Left:=Screen.WorkAreaLeft; + if Top<Screen.WorkAreaTop then Top:=Screen.WorkAreaTop; + end; + + //Switch OK and cancel buttons on a Mac +{$ifdef Darwin} + BtnCancel.AnchorSideRight.Control:=PnTop; + BtnCancel.AnchorSideRight.Side:=asrRight; + BtnOK.AnchorSideRight.Control:=BtnCancel; + BtnOK.AnchorSideRight.Side:=asrLeft; +{$endif} + + SgParameter.RowCount:= ModelDef.numparam + 1; + SgParameter.AutoSizeColumns; + SgParameter.cells[0,0]:='Parameter Symbol'; + SgParameter.cells[1,0]:='Parameter Name'; + SgParameter.cells[2,0]:='Parameter Value'; + SgParameter.cells[3,0]:='Parameter Units'; + for i := 1 to ModelDef.numparam do + begin + SgParameter.cells[0,i] := par[i].symbol; + SgParameter.cells[1,i] := par[i].name; + SgParameter.cells[3,i] := par[i].units; + end; + SgParameter.row := 1; + SgParameter.col := 2; +end; + +procedure TFmParameter.SgParameterDrawCell(Sender: TObject; aCol, + aRow: Integer; aRect: TRect; aState: TGridDrawState); +var + S:string; +begin + if aCol <> 2 then SgParameter.Canvas.Brush.Color:= clScrollBar; + SgParameter.Canvas.FillRect(aRect); + S := SgParameter.Cells[aCol, aRow]; + SgParameter.Canvas.TextOut(aRect.Left + 2, aRect.Top + 2, S); +end; + +procedure TFmParameter.SgParameterSelectCell(Sender: TObject; aCol, + aRow: Integer; var CanSelect: Boolean); +begin + if aCol = 2 then + begin + CanSelect := True; + SgParameter.Editor := SgParameter.EditorbyStyle(cbsAuto) + end + else + SgParameter.Editor := SgParameter.EditorbyStyle(cbsNone) +end; + +procedure TFmParameter.BtnOKClick(Sender: TObject); +var + i:integer; +begin + for i:=1 to ModelDef.numparam do par[i].value := strtofloat(SgParameter.Cells[2,i]); + BtnProcessVar.Caption := '&Show Processes'; + if DataForm.visible then DataForm.BtnCancelClick(FmParameter); +end; + +procedure TFmParameter.BtnProcessVarClick(Sender: TObject); +begin + if not DataForm.Visible then + begin + DataForm.ShowProcess; + BtnProcessVar.Caption := '&Update Processes'; + end; + UpdateProcessWindow; +end; + +procedure TFmParameter.BtnCancelClick(Sender: TObject); +begin + par := fOrigPar; + BtnProcessVar.Caption := '&Show Processes'; + if DataForm.visible then DataForm.BtnCancelClick(FmParameter); +end; + +procedure TFmParameter.ShowParameters; +var + i:integer; +begin + if paramfilename = '' then + FmParameter.Caption := 'Edit Parameters - File: None Specified' + else + FmParameter.Caption := 'Edit Parameters - File: ' + paramfilename; + if (paramfilename = '') or (driverfilename = '') then + begin + BtnProcessVar.Enabled:=False; + end + else + begin + BtnProcessVar.Enabled:=True; + end; + fOrigPar := par; + SgParameter.AutoSizeColumns; + SgParameter.Options := [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine, + goColSizing,goThumbTracking,goEditing]; + for i := 1 to ModelDef.numparam do SgParameter.cells[2,i] := floattostr(par[i].value); +end; + +procedure TFmParameter.UpdateProcessWindow; +var + i:integer; +begin + for i:=1 to ModelDef.numparam do par[i].value := strtofloat(SgParameter.Cells[2,i]); + try + // Open driverfile, read first row of drivers, and then close the driver file. + openDriverFile(driverfilename,fileio.driverlist); + last_time := 0; + next_time := 0; + GetCurrentDrivers(Caltime,drive); + processes(Caltime,caltime,drive,par,stat,proc,false); // Calculate processes + except + on EfileError do + MessageDlg('Error reading driver file. Process values were not calculated.', mtWarning, [mbOK], 0); + on E: Exception do + MessageDlg('Invalid Parameter. Process values were not calculated.', mtWarning, [mbOK], 0); + end; + DataForm.UpdateProcess; +end; + +end. + diff --git a/modelshell/stypes.pas b/modelshell/stypes.pas new file mode 100644 index 0000000..4224fcd --- /dev/null +++ b/modelshell/stypes.pas @@ -0,0 +1,259 @@ +{ This file defines new variable types and sets the limits on the various arrays + used in the model code. All units should include this file. } +unit stypes; + +{$MODE Delphi} + +interface + +uses sysutils, classes; + +const + maxstate = 150; // The maximum number of state variables. The state variable + // array contains maxstate elements. + maxdrive = 75; // The maximum number of driver variables. + maxprocess = maxstate + 350; // The maximum number of process variables. + maxparam = 500; // The maximum number of parameters. + maxresults = 102; + maxtreatments = 8; + stringlength = 25; + maxVarObserved = 100; + maxTimeMeasure = 100; + maxmatrix = 10000; + +type + processtype = (ptGroup1, ptGroup2, ptGroup3, ptGroup4, ptGroup5); +// processcolor = (clGreen, clTeal, clAqua, clBlue, clGray); + TModelDef = record // A structure used to hold the basic information + modelname:string; // about the model. Modelname is the name of + // model and appears on the title bar in the FmShellMain. + versionnumber:string; // Used to keep track of the version number of the model. + contactperson:string; // Used for the aboutbox + contactaddress1:string; // Used for the aboutbox + contactaddress2:string; // Used for the aboutbox + contactaddress3:string; // Used for the aboutbox + timeunit:string; // Timeunit is the time step of the model, ie day, year. + numdrive:integer; // Numparam, numdrive, numstate and numprocess are the + numstate:integer; // total number of parameters, drivers, state variables, + numprocess:integer; // and processes, respectively. + numparam:integer; + end; + + Tparamvariable = record // A structure to hold a parameter; it's name, value, + name:string; // and units. The name and units are for information + value:double; // only. They do not affect the running of the model. + units:string; // This structure type is also used for the + symbol:string; // driver variables. + end; + + Tstatevariable = record // A structure to hold a state variable; the name, + name:string; // value and units. As with Tparamvariable the name + value:double; // and units are for information only. HoldConstant + units:string; // determines if the state variable is held constant + symbol:string; // during the model run, i.e. dstatedt = 0. + HoldConstant:Boolean; + Reset:Boolean; + end; + + Tprocessvariable = record // A structure to hold a process variable; the + name:string; // name, value, and units. As above, the name and + value:double; // units are for information only. Parameters is + units:string; // number of parameters associated with this + symbol:string; // particular process. Every parameter must be + parameters:integer; // associated with a process. Ptype determines the + ptype:processtype; // color of the tab in the edit parameters page. + end; + + Tallstates = record + Cf:Tstatevariable; + Cw:Tstatevariable; + Cr:Tstatevariable; + Nf:Tstatevariable; + Nw:Tstatevariable; + Nr:Tstatevariable; + end; + + TCalSet = record + HaveRunInfo: Boolean; + ValidSet: Boolean; + rownum: integer; + Treatment: integer; + State: string; + StateIndex: integer; + Parameter: string; + ParamIndex: integer; + Alpha: double; + Beta: double; + DeltaPar: double; + end; + +// State variable array types. yValueArray, glindx and glpbynp are used during +// integration. They hold temporary values of the state variables and therefore +// don't need to be of type Tstatevariable. This saves memory. However they +// must be the same size as statearray. + yValueArray=array[1..maxstate] of double; + glindx = ARRAY [1..maxstate] OF integer; + glnpbynp = ARRAY [1..maxstate,1..maxstate] OF double; + statearray=array[1..maxstate] of Tstatevariable; +// Driver variable array type. Note that the type is Tparamvariable. + drivearray=array[1..maxdrive] of Tparamvariable; +// Parameter array type. + paramarray=array[1..maxparam] of Tparamvariable; +// Process variable array type. + processarray=array[1..maxprocess] of Tprocessvariable; + calsetarray = array[1..maxstate] of Tcalset; + stringarray = array[1..maxstate + 1] of string; + +// The types of data which can be displayed in the dataform + TDataType = (dtState, dtProcess, dtParameter); +// The possible axis' in the chart on the display form + TAxis = (axLeft, axBottom); +// The display options for the output data in the display form + TDisplayStyle = (dsChart, dsTable); +// The axis type for the chart on the display form + TAxisType = (tyLinear, tyLog); +// The type of variable being looked for in the arrays + TVarType = (vtDriver, vtState, vtParameter, vtProcess); + + TRunOptions = record + NormalRun: Boolean; + Time_step: double; + DiscreteStep: double; + RepeatDrivers: Boolean; + RepeatDriveTime: double; + ResetStates: Boolean; + ResetStateTime: double; + RuntoSS: Boolean; + SSCriteria: double; + SSTime: double; + HoldStatesConstant: Boolean; // Used in fuzzy calibrator + Outputstep: double; // The timestep specified by the user for output + Outputoffset: double; // No output for time less than outputoffset + OutputEORonly: Boolean; // output only if time = stop_time + Time_step + OutputAnnually: Boolean; + OutputAnnuallyDay: double; + AppendOutputFile: Boolean; + stepcounter: integer; + outcounter: integer; // The current number of timesteps since last output, output occurs when outcounter=outputfreq + OutputFile: Boolean; + WriteEvery: double; + errormult: integer; + end; + + TCalOptions = record + UseSecondOutFile: Boolean; + FinalOutFilename: string; + OrigOutputStep: double; + OrigOutputOffset: double; + OutputEORonly: Boolean; + caloutcounter: integer; + caloutputfreq: integer; + AppendFinalOutputFile: Boolean; + end; + + TTreatResults = record + Time: integer; + IndexList: array[1..Maxstate] of integer; + States: statearray; + end; + + TDerivSet = record + Time1: double; + States1: statearray; + Time2: double; + States2: statearray; + end; + + resultarray = array[1..maxresults] of TTreatResults; + + TTreatSet = record + drivefilename: string; + outputfilename: string; + timestart: double; + timestop: double; + Options: TRunOptions; + CalOptions: TCalOptions; + TotalMeasurements: integer; + measdata: resultarray; + currmeasurement: integer; + simdata: resultarray; + currdrive: drivearray; + currstate: statearray; + derivstates: TDerivSet; + NumCalSet: integer; + CalSetIndexList: array[1..maxstate] of integer; + FirstWrite: Boolean; + end; + + TreatSetarray = array[1..maxtreatments] of TTreatSet; + +// Ensemble Kalman Filter + EnKF2Dmat = array of array of double; + EnKFvec = array of double; + glindxEKF = array of integer; + mat = array[1..MaxMatrix] of double; + + TVariableIncluded = array of Boolean; + + TNameArray = array of string; + TTimeArray = array of double; + TDataArray = array of double; + T2dData = array of array of double; + // Rows are time points, columns are variables + + TPertData = array of double; + TPert = record + NumPert: integer; + Names: TNameArray; + Data: EnKF2Dmat; + end; + + TKstate = record + NumTotKalman: integer; + NumObservations: integer; + Names: TNameArray; + Units: TNameArray; + Symbol: TNameArray; + Time: TTimeArray; + Z: EnKF2dmat; + R: EnKF2dmat; + Xmean: T2dData; + Xmax: T2dData; + Xmin: T2dData; + Q: EnKF2Dmat; + Ymean: T2dData; + UnCorXmean: T2dData; + UncorXmax: T2dData; + UncorXmin: T2dData; + end; + +// Grid Shell Variables + TGridCellInfo = record + Row: integer; + Column: integer; + RunPosition: integer; + VegClass: integer; + SoilClass: integer; + ParamFilname: string; + Driverfilename: string; + OutputFilename: string; + end; + +// Errors + ERunTimeError = class(Exception); + EIntegratorError = class(ERunTimeError); + ETooManySteps = class(EIntegratorError); + EIntStepTooSmall = class(EIntegratorError); + EUserCancel = class(ERunTimeError); + ECalculateError = class(EMathError); + ECalcInitialProc = class(ECalculateError); + ECalcNewValue = class(ECalculateError); + ECalcNewProcess = class(ECalculateError); + EStepError = class(Exception); + EStepTooSmall = class(EStepError); + EStepTooLarge = class(EStepError); + EStepNotMultiple = class(EStepError); +implementation + +end. + diff --git a/modelshell/trouble.lfm b/modelshell/trouble.lfm new file mode 100644 index 0000000..d46080a --- /dev/null +++ b/modelshell/trouble.lfm @@ -0,0 +1,1896 @@ +object FmTrouble: TFmTrouble + Left = 473 + Height = 220 + Top = 125 + Width = 453 + Caption = 'Error' + ClientHeight = 220 + ClientWidth = 453 + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + FormStyle = fsStayOnTop + OnShow = FormShow + Position = poOwnerFormCenter + LCLVersion = '0.9.30.2' + object Image1: TImage + Left = 5 + Height = 201 + Top = 16 + Width = 212 + OnClick = Image1Click + Picture.Data = { + 07544269746D617036E40000424D36E400000000000036000000280000009700 + 000080000000010018000000000000E400000000000000000000000000000000 + 0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFF00000039295239184A31294A31214A31294A39295229214A31 + 214A31214A31214A31294A31214A39295231294A31214A31294A39295231214A + 31214A29214239315A31294A31294A39295231214A31294A31214A31214A4239 + 5A39315239295239315A4242634A395A42426342315A39315A39315A39315A39 + 315A42426B42426339315A39315A39315A39315A39315A39315A39315A39315A + 39315A39315A1000299C9CBDEFEFFFEFE7FFEFEFFFEFEFFFEFE7FFF7EFFFEFE7 + FFF7EFFFE7DEFF4A4A84635A84847BA5847BA58C84AD8C84ADADA5D6BDB5DEBD + BDE7CEC6EFCEC6EFD6CEF7D6CEF7DED6F7DED6F7D6D6F7DED6F7E7DEFFCEC6EF + BDB5D6ADA5D6A59CC6ADA5D6BDBDDECECEEFC6BDE77B739C7B739C7373A56B6B + 8C7B739439293118100829182929182921101821101821101821101818102110 + 0000080008000000000000000000000000000000211018000000211010080008 + 1000080000000000000800083118210000002110182918291000081000000800 + 0808000821101018102110000808000800000000000021101839293129182929 + 1829291829291829291829211018291829392929291829211018291829291829 + 291829291829291829291829FFFFFF00000031214A31294A39184A3929523121 + 4A39315A31214A31214A31214A31214A29214231214A31294A39315A31214A31 + 294A31214A31294A31294A31214A39315239295239295231214A31315A31214A + 31214A39295242395A39315A39315A39315A42315A29215A39315A4242634231 + 5A39315A39317339315A39315A39315A39315A4A316B39315A4242634A316B39 + 397339295239315A39315A31315A181031BDBDDEF7EFFFEFEFFFEFE7FFEFEFFF + F7EFFFEFEFFFEFEFFFEFEFFFF7EFFF948CB542317B736B8C847BA5847BA58C84 + ADA59CCEB5ADD6BDB5DEBDBDE7C6BDE7CEC6EFCEC6EFD6CEF7DED6F7D6CEF7D6 + D6F7E7DEFFBDBDE7C6BDE7B5ADD6A5A5CEA5A5CEB5ADD6CECEEFA5A5CE6B6B8C + 8C849C7B739C6B637B736B8C4A425A1000002918292918292110182918292110 + 1821101821101021101021101821101821101821101821101821101821101829 + 1829211018211010211008291829291829291829392929291829311821311821 + 3118213929293118213929292118212918292110182918292918292918292118 + 2139293129182929182929182929182929182929182939292929182929182929 + 1829291829291829291829291829291829211018FFFFFF00000031214A31214A + 31294A31214A31214A42395A39295231214A31214A39295231214A31214A3129 + 4A39315A31214A31294A31214A31294A31214A31214A39315239315A31214A31 + 294A39315A39295229294A31294A39315239295231315A39315A31294A31315A + 39315A42315A39315A39315A39315A39315A42315A42426B39315A42315A3931 + 5A39315A39315A42315A31315A39315A42426331294A211031D6D6F7F7EFFFEF + EFFFEFE7FFEFEFFFEFE7FFEFE7FFEFE7FFEFE7FFF7EFFFDED6F739217B5A5284 + 7B739C847BA5847BA5A594C6ADA5D6B5ADD6B5B5DEBDBDE7C6BDE7CEC6EFD6CE + F7D6CEF7CEC6EFD6CEF7E7DEFFBDBDE7C6BDE7BDBDDEADA5CE9C94C6ADA5D6BD + BDE7847B9C7B739C8C84AD7B739C6B6B8C6B6B8C5A4A63180808211018181021 + 2110182110182110182110102110182110182110182110182110102110182110 + 1021101829182921101821101821101029182929182929182939292929182929 + 1829311821291829291829311821311821292939291829291829291829291829 + 2918292110102918293929292110182918292110182918292110102918293118 + 21211821291829291829211018211821291829291829211010211018FFFFFF00 + 000031214231214A31214A31214A31214A39295231294A31294A31214A31294A + 31214A31214A31294A39315A39295239184A31214A31294A31214A31214A3129 + 4A39315231214A39295231294A31214A39295231214A31315A42395A39295231 + 294A39315A42315A39315A42315A3931734A316B42315A39315A39315A39315A + 39315A42315A39315A31315A39315A39315A39315A31294A39315A1808396B63 + 8CF7EFFFEFEFFFE7DEFFEFEFFFEFE7FFF7EFFFEFEFFFEFEFFFF7EFFFEFE7FFFF + FFFF8C8CBD42317B736B8C847BA57B739C948CB5ADA5CEADA5CEB5ADD6BDBDE7 + BDBDE7BDBDE7CEC6EFD6CEF7CEC6EFD6CEF7DED6F7BDB5DEBDBDE7BDBDDEA5A5 + CE9C94C6ADA5D6B5ADD6736B8C847BA58C84AD8C849C736B8C6B637B63527318 + 0810211018392929211821211821211821211018211018211010211018211018 + 2110182110182110182110182110182110182110182110102110182110102918 + 2939292929182929182929182929182929182929182929182939292921101029 + 1829211018291829291829291829291829291829291829291829291829291829 + 2918292918292918292918292110182918292918292110182110182110182918 + 29392929FFFFFF00000031214A31214231214A31214A31214A31214A39315A31 + 214A31214A31294A31214A31214A31214A31294A39315A39315A31294A392952 + 31294A31214A31214A39315A31294A31214A39315A39295229215A31294A3929 + 5239315A39315A39315A39315A39315A42315A39315A39315A39315A39315A31 + 315A39315A31214A39315A39315A4A316B42315A39315A42315A4A425A424263 + 39315A181031CECEEFF7EFFFE7DEFFEFE7FFF7EFFFEFEFFFEFEFFFF7EFFFEFE7 + FFEFEFFFF7EFFFEFEFFFE7DEFF42317B5A528C736B8C736BA5847BA59C94BDA5 + 9CC6A59CCEBDB5DEBDB5DEB5ADD6BDBDE7CEC6EFCEC6EFCEC6EFD6D6F7ADA5D6 + BDB5DEC6BDE7A5A5CE8C8CBDB5B5DE948CB5736B8C8C84AD8C849C847BA56B6B + 8C635A7B6B637B29182918081021182121101821101821101821101821101821 + 1018211018211018211018211018211018211821211821211018211821211018 + 2110102918292110183929292110102918292918293118213118212918293118 + 2129182929182929182929182921101029182921101839292921101029182921 + 1010291829211010291829211018291829291829291829211821211010291829 + 2918294231314A31394A3139FFFFFF00000039295231214231214A3121423121 + 4A29214A31294A31214A31294A39295231294A31214A29214A39295239315231 + 214A39295231294A39295231214A31214A39315239315231214A31294A31294A + 31294A31315A31214A39315A31294A31294A39315A39315A42315A39315A3931 + 5A42315A4A316B42315A39315A424263424A73424A73524A6B4242634A395A42 + 426B524A6B39315A2110315A5273EFEFFFE7DEFFE7DEFFF7EFFFEFEFFFEFEFFF + F7EFFFEFE7FFF7EFFFEFEFFFEFE7FFEFE7FFFFFFFF7B73B531296B736B8C7B73 + 9C847BA58C8CB58C8CB5948CB5ADA5CEBDB5DEB5ADD6BDB5DEBDBDE7C6BDE7CE + C6EFCECEEFADA5D6BDB5DEBDBDDE9C94C67384BDBDBDDE7B73947B739C8C849C + 8C84AD847B9C635A84635A7B736B8C3929311810082118212110182110182110 + 1818081021101018081021101818102121101018102121101021101021101021 + 1018211010211010211018291829291829311821291829291829291829211010 + 2918292110183929292118212918292110102918292918292918292918292918 + 2929182929182929182929182929182929182929182929182918102121101829 + 18293929314231394A31394A31394231394A3139FFFFFF00000031214231294A + 31214231214A31214A31214A29214A31214A31214A31214A31214A31294A3129 + 4A31214A39315A39295231294A31294A31214A31214A31214A31214A42395A31 + 214A39295239295231294A31214A31214A39315A39295239315A39315A39315A + 39315A42426342426342426B42426B424A734A395A39317342426342315A3931 + 5A39315A31315A39315A42426339315A000000ADA5D6EFEFFFE7DEFFEFEFFFEF + E7FFF7EFFFEFE7FFEFEFFFEFEFFFEFEFFFEFEFFFEFEFFFF7EFFFF7EFFFDED6F7 + 31296B5A528C5A528C6B639C8C84AD847BA58C84AD8C8CB5949CCEA59CC6ADA5 + CEADA5D6B5ADD6B5ADDEC6BDE7ADA5D6ADA5D6B5ADD68C8CB5A5A5CEA59CC673 + 6B8C847B9C847BA58C849C847BA5635A7B635A7B635A7B42314A180808211018 + 1808102110181808102110181810212110102110101808102110182110102110 + 1821101021101021101821101821101821101829182931182131182129182921 + 1010291829291829291829291829311821211010291829291829211010211821 + 2918292918292918292110182918292918292118212110182110182110182918 + 293929294231394A31394A31394A31394A31394A31394A31394A3139FFFFFF00 + 000031183131214231294A31214229214231214A31214A292142312142292142 + 31214A31214A31214A31294A39315A39295231214A31294A31214A3929523129 + 4A29214A42315A31294A39295231294A39295239315A31214A42426339315242 + 315A4242634A395A4242634A395A42315A42426B39315A39315A39397339315A + 39315A42426B39315A39315A39315A39315A39315A31294A180829D6D6F7E7DE + FFE7DEFFEFE7FFEFEFFFEFEFFFEFEFFFEFE7FFEFEFFFEFE7FFF7EFFFEFEFFFEF + EFFFEFE7FFFFFFFF7B73B531296B4A4A846B639C8C84AD948CB58C8CB59C94BD + 948CB5948CB58C8CBD9C94BD9C94C69C94C6949CCE948CB59C94BD9C94C68C8C + BDB5B5DE7B739C7B7394847B9C847BA5847BA5847B9C6B6B8C5A52736352734A + 425A181008211018211018180810211010180810211010181021211018211010 + 1808102110102110102110182110182110102110102110182110182918293118 + 2121101029182929182921101021101821101031182129182929182921101029 + 1829291829211018291829291829291829291829291829211018211018291829 + 3929314231394A39424A39424A31394A31394A31394A31394231394231394A31 + 394A3139FFFFFF00000021101031182131183131294231294229214A31294A31 + 214A31214231214A29214231214A31294A39295239295242426331294A39184A + 29215A31294A31214A31214A39315A39295231214A31294A31214A39315A3121 + 4A31294A42315A31315A42315A39315A29215A39315A39315A39315A42315A39 + 315A42315A39315A39315A39315A39315A31315A39315A4A316B39315A18104A + 635A7BE7DEFFE7DEFFEFEFFFEFEFFFEFE7FFEFE7FFF7EFFFEFEFFFEFE7FFF7EF + FFEFEFFFEFE7FFF7EFFFEFE7FFFFFFFFD6CEF739217B4A4A847373A5948CB594 + 8CB5948CB58C8CB59C9CBDA59CC69C94BD9C94BD9C94BD9C94BD9C94C6948CB5 + 7384BD6B6BA5949CCEAD9CC6736B8C7B739C847B9C847BA5847BA5847BA56B6B + 8C635A7B6352734A425A18081021101021101018102121101018081021101818 + 0810211010181021211018211018211018211010211018211010211018211018 + 2110102918292918292918292110102918292918292110102918292918292110 + 1029182921101821101829182929182921182121182121101821101821182139 + 29294231394A31394A39424A39424A31394A39424A31394231394231394A3139 + 4A31394A31394A31394A3139FFFFFF0000003118213118212110083118213118 + 2139293129214231214A29214A31214231214A31294A31294A31294A31294A39 + 315A39295229214A31294A31294A31294A31294A31294A39315A31214A39315A + 31214A31315A31214A39315A42395A31214A39315A39315A39315A39315A3931 + 5A39315A42315A39315A39315A42315A4A316B39317339315A39315A39315A39 + 315A42426B1000298C84ADE7DEFFE7DEFFEFEFFFEFE7FFEFEFFFEFEFFFEFE7FF + EFEFFFF7EFFFEFEFFFEFEFFFF7EFFFEFEFFFF7EFFFEFEFFFFFFFFF948CB52929 + 7B734AA58C84AD8C84AD7B73A5847BA58C84AD9C94C6ADA5CEA5A5CE9C94C69C + 94C68C8CBD7384BD847BA56B73BDADA5D6847BA57B73947B739C7B739C847BA5 + 847B9C847B9C7B7394736B8C635A7B4A425A2110101808101808102110101808 + 1021101018081021101818081021101018081018081021101821101821101018 + 0810211018211018211018311821211018211018291829211010211018291829 + 2918292110102110102918292110102918292110182110182110182110183118 + 214231394A39424A39424A31394A31394A31394A31394A39424A31394A31394A + 31394A31394A31394231394A31394A3139423139FFFFFF000000311821311821 + 31182131182121101031182131182139292939293131294231294231294A3121 + 4A31214231214A31294A31294A31214A31294A39295231214A31214A31214A39 + 315A31214A39295231294A31214A31294A31315A42315A39315A31294A39315A + 39315A39315A39315A39315A42426B39317339315A39315A42426339315A3931 + 5A39315A39315A42426342315A1000299C94BDE7DEFFEFEFFFE7DEFFEFEFFFEF + E7FFEFE7FFEFEFFFEFE7FFEFEFFFEFE7FFEFEFFFF7EFFFEFE7FFEFEFFFF7EFFF + F7EFFFEFE7FF394284525A948C84AD7373A5847BA5847BA58C84AD8C84AD948C + B59C94C69C94C69C94C68C8CBD847BA5636BAD9C94C6A59CC67B739C7B739C7B + 739C847B9C847B9C847BA57B739C7B73947B7394736B8C4A425A180810180810 + 2110101810211808102110182110101808102110182110182110102110182110 + 1821101821101821101821101021101821101829182921101021101821101821 + 1018291829211010291829291829291829211018291829211010211018291829 + 3929294A31394A39424A39424A31394A31394A31394A31394A31394A31394A31 + 394A39424A31394A31394A39424A31394A31394A31394A31394A3139FFFFFF00 + 0000211010311821311821311821311821311821311821311821392929311821 + 29182939292931294231214229214231214A29214231214A31214A31294A3129 + 4A31214A31214A39315A39315A31294A31214A39295231294A31214A31315A4A + 395A29215A31315A42315A42315A39315A39315A39315A42315A39315A42315A + 39315A31315A4A316B42315A42395A39317339315A180839A59CC6E7DEFFEFE7 + FFEFEFFFEFE7FFEFEFFFEFE7FFF7EFFFEFEFFFF7EFFFEFEFFFEFE7FFEFEFFFEF + EFFFF7EFFFEFEFFFEFEFFFFFFFFFCEC6EF21297B8C84AD7373A5636BAD7B73A5 + 7B73A58C84AD7B7BAD948CB5948CB58C8CBD847BA55A639C8C8CBDADA5CE8C84 + AD8C849C847B9C7B739C847B9C847B9C7B739C7B73947B73947B73947B73945A + 4A63180808291829211018211010211010211010211018211018211010180810 + 2110182110182110182110182110182110102110182110102918292918292110 + 1029182921101829182921101029182921101821101821101821101818102131 + 18294231314A39424A39424A31394A31394A31394A31394A31394A31394A3139 + 4A31394A31394A31394A31394A31394A31394A31394A31394A31394A31394A31 + 394A3139FFFFFF00000031182131182131182131182131182131182131182131 + 182131182139292931182131182131182139292939292931294231294229214A + 31214A31214A39295231294A31214A31294A39315A31214A31315A29214A3121 + 4A31214A31315A39315A31294A39315A39315A39315A39315A39315A42315A39 + 315A39315A42315A42426342315A42426342426342315A42315A42315A21214A + A5A5CEE7DEFFEFE7FFE7DEFFEFE7FFEFE7FFEFEFFFEFE7FFEFEFFFEFEFFFF7EF + FFEFE7FFF7EFFFEFEFFFEFEFFFF7EFFFEFE7FFF7EFFFFFFFFF949CCE635AA59C + 94BD6B6BA55A6BAD7384BD7B7BAD6B638C7373A58C84AD736BA5525A947B73B5 + ADA5D6948CB58C84AD8C84AD847BA5847B9C847B9C847B9C847B9C7B73947B73 + 947B7394847B9C6B637B21101818081018102118102118081021101818081021 + 1010181021180810211010211010211018211010211018211010211821211018 + 2110182110102918292110102110102918292118212110182918292110182110 + 183118214A31314A39424A39424A31394A31394A39424A31394231394231394A + 31394A31394A31394A31394A31394A31394A39424A31394231394A31394A3139 + 4231394231394A31394A3139FFFFFF0000002918293118213118213118213118 + 2131182131182131182131182131182131182131182131182129182931182131 + 182131182139292929213931294A31294A31214A31214A31214A39315A39315A + 39295239315231294A31294A39295239315A39315A31214A42315A4242634242 + 6B42426B42426B424A734A316B42426339315A42426B4A316B42426B42426B42 + 426B39315A21184AB5ADDEE7DEFFEFEFFFEFE7FFEFEFFFF7EFFFEFEFFFEFEFFF + F7EFFFEFEFFFEFE7FFEFEFFFEFEFFFEFEFFFF7EFFFEFE7FFEFEFFFEFEFFFF7EF + FFF7EFFF9C94C6525A94948CB5847BA56B6BA56B6BA57373A5736B8C6B639C73 + 6BA59C94C6ADA5CE948CB58C849C8C849C8C84AD847BA5847B9C847B9C7B739C + 7B739C7B73947B73947B73947B7394736B8C3929311000002110182110102110 + 1018081018081021101018081021101018081018102118081021101821101021 + 1018211010211018211018291829211010291829291829211010211010211010 + 2110183118214A31394A394252424A4A31394A39424A39424A31394A31394A39 + 424231394A39424A31394A39424A31394A31394A39424A39424A39424A31394A + 39424A31394A31394231394A31394A31394A3139FFFFFF000000311821311821 + 3118213118213118212918293118213118213118213118213118213118213118 + 2139292931182139292931182131182131182131182129294A31294A31294A31 + 294A31294A39315A31294A29215A39295231214A29214A39295242395A31294A + 39315A42426B39315A42315A39315A42315A39315A31315A39315A42315A3931 + 5A39315A42315A39315A31315A211031BDBDE7EFE7FFEFEFFFF7EFFFEFEFFFEF + EFFFF7EFFFF7EFFFEFEFFFEFE7FFEFE7FFEFEFFFEFE7FFEFEFFFEFE7FFEFEFFF + EFEFFFEFEFFFE7DEFFE7DEFFE7DEFF948CB529297B7B73A58C8CB5847BA57B73 + A5635AA57373A5A59CCE9C94BD847B9C7B739C7B739C7B73A5847B9C847BA584 + 7B9C7B7394847B9C7B73947B73947B73947B73947B73947B73944A425A100000 + 2110101808101808102110182110101808102110101808102110102110182110 + 1021101021101821101021101821101821101829182929182929182921100818 + 08102918293929294A313152424A4A39424A31394A39424A39424A31394A3139 + 4A39424A39424A31394A39424A31394A39424A31394A31394A31394A31394A31 + 394A31394A39424A31394A31394A31394A31394A31394A31394A3139FFFFFF00 + 0000311821311821311821291829311821311821311821291829311821311821 + 3118213118213118213118213118213929293118213118213929293929293929 + 2931183931214A39295231214A39315A39315A31214A39315A39315A31214A31 + 294A39315A39295231214A39315A39315A39315A42315A39315A39315A39315A + 39315A42315A39315A42426339315A39315A31214A29214AD6D6F7EFE7FFEFEF + FFEFEFFFF7EFFFEFEFFFEFEFFFEFE7FFF7EFFFEFEFFFEFEFFFEFE7FFEFEFFFEF + E7FFEFE7FFEFEFFFE7DEFFE7DEFFE7DEFFE7DEFFDED6F7CECEEF7373A518215A + 4A4A846B6B9C7373A5847BA5948CB5736B8C635A846B638C6B6B8C7B73947B73 + 947B739C7B73947B739C7B739C7B73947B73947B73947B73947B73947B73947B + 7394635273211821181008211010211010180810180810211010181021211010 + 1808102110102110102110102110102110182110182110182110182110182110 + 102110102918294231314A313952424A4A39424A39424A31394A39424A31394A + 31394A39424A39424A31394A39424A31394A31394A39424A31394A39424A3942 + 4A313952424A4A39424A39424A31394A39424A31394A31394A31394A31394A31 + 394A3139FFFFFF00000021101031182131182131182131182131182131182131 + 1821311821311821311821311821311821311821311821392929392929311821 + 39292931182139292939292939292931294231214A31294A39315A31294A2921 + 4A31315A39295231214A31214A42426331214A39315A39315A39315A39315A39 + 315A39315A39317342315A39315A39317339315A39315A393973180839635A84 + E7DEFFEFE7FFEFEFFFF7EFFFEFEFFFF7EFFFEFEFFFEFEFFFEFE7FFEFEFFFF7EF + FFEFEFFFEFE7FFEFEFFFE7DEFFE7DEFFE7DEFFE7DEFFCECEEFCEC6EFBDBDE78C + 8CB55A527339315221102918082929293942395A4A425A424263424A73524A6B + 5A427B5A52846B638C6B6B8C7B73947B73947B73947B73947B73947B7394736B + 8C7B73947B7394736B8C6B637B39293110000018102118081018081021101018 + 0810211010180810211010180810181021211010211018211010211018211010 + 2110102110103118214A313152424A52424A52424A4A39424A39424A31394A31 + 394A313952424A4A31394A31394A39424A39424A31394A39424A39424A39424A + 39424A31394A31394A31394A39424A31394A39424A31394A39424A39424A3942 + 4A31394A31394A31394A3139FFFFFF0000003118213118213118213118213118 + 2129182931182131182131182131182131182139292929182931182131182131 + 1821392929392929311821392929392929311829392929392929392929311839 + 39184A31294A31294A31294A31294A31315A39295239315A39295231214A3931 + 5A39315A39315A39315A39315A39315A39315A39315A42426342315A39315A39 + 315A1000299C94C6F7EFFFEFEFFFF7EFFFEFE7FFEFEFFFEFE7FFEFEFFFEFE7FF + EFEFFFF7EFFFEFEFFFEFEFFFEFE7FFEFEFFFEFE7FFEFE7FFE7DEFFCEC6EFA5A5 + CE7B7BAD4A4A8429294A29213929213929293939292921103121101818081029 + 182939315A42315A42426B524A6B5A5273635A846B638C736B8C736B8C7B7394 + 7B73947B73947B7394736B8C7B7394736B8C736B8C3931521000002110102110 + 1821101818081021101018081021101021101821101821101021101821101821 + 10101808102110103118214A394252424A52424A52424A52424A4A313952424A + 4A31394A313952424A52424A4A31394A394252424A4A31394A39424A39424A31 + 394A39424A31394A39424A31394A31394A31394A31394A39424A31314A31394A + 39424A31394A39424A31394A31394A31394A3139FFFFFF000000311821311821 + 3118213118213118213118213118213118213118213118213118213118213118 + 2139292931182131182131182131182139292939292931182139292939292939 + 292931182139292939292939293131294231294A29214A31214A31214A31294A + 42315A31294A39315A4A316B31315A31315A39315A42426B39315A39315A3939 + 7342315A39315A39315A29214ACEC6EFEFEFFFEFE7FFEFEFFFEFEFFFEFEFFFEF + EFFFEFE7FFEFE7FFEFEFFFEFEFFFF7EFFFF7EFFFEFE7FFEFEFFFEFEFFFCECEEF + 8C8CBD4A4A8421214A2110312110312918292918292918292110292918292118 + 2129182921102921182129182929213939315A42426B524A6B5A52736B637B6B + 637B736B8C736B8C736B8C736B8C736B8C7B73947B7394736B8C736B8C4A394A + 1000001808101808101808102110182110181810212110101808102110102110 + 1821101818081029182939292952424A52424A52424A52424A52424A4A313952 + 424A4A394252424A4A394252424A4A31394A39424A39424A313952424A4A3139 + 4A31394A31394A39424A39424A39424A39424A31394A39424A31394A39424A31 + 3952424A52424A4A313952424A4A39424A31394A39424A31394A3139FFFFFF00 + 0000311821311821311821311821311821311821311821311821311821311821 + 3118213118213118213118213118213929293118213929293929293118213929 + 2931182939292939292939292939292931182939292939292931182939293139 + 295231294A31294A31294A31294A31294A42426B42315A42426342426B42426B + 4242634242634A316B42426B39315A39315A393973E7DEFFF7EFFFEFE7FFEFEF + FFEFE7FFEFE7FFEFE7FFEFE7FFEFEFFFF7EFFFEFEFFFEFE7FFEFEFFFEFEFFFE7 + DEFF9C94C639397321214A292939291829211010211018291829211010211018 + 1808101810212110102110101808102110102110101810082110103118394239 + 5A42426B5A5273635A7B6B6B8C736B8C736B8C736B8C7B7394736B8C736B8C73 + 6B8C736B8C524A52100000211010211018211010180810180810211010180810 + 21101018080818100829182942313152424A4A394A4A313952424A52424A5242 + 4A4A313952424A4A39424A313952424A4A39424A313952424A4A31394A313952 + 424A4A39424A313952424A52424A4A31394A39424A39424A39424A31394A3139 + 4A31394A313952424A4A394252424A52424A4A39424A31394A39424A31394A31 + 394A3139FFFFFF00000031182131182131182131182139292931182131182131 + 1821311821311821311821392929311821311821311821392929392929311829 + 3118213929293929293929293929293118293929293929293929293118293929 + 2939292939292939292939293139295231315A39295231214A31294A4A316B39 + 315A39315A39315A42426B4A316B42426B39315A42426331294A5A5A8CEFE7FF + EFEFFFEFE7FFEFEFFFEFEFFFEFEFFFEFE7FFEFEFFFEFE7FFEFE7FFEFEFFFEFEF + FFEFEFFFC6BDE74A4A8418215A31294239293121101021101821101821101021 + 1018181021211010211010180810211010211018180810211010180810180810 + 1810081808082118213931524A425A635273635A7B6B637B6B6B8C736B8C736B + 8C7B737B736B8C736B8C736B8C5A4A6310000018081018081021101021101018 + 081018100818100818100829182942313152424A52424A4A39424A39424A3942 + 4A39424A313952424A52424A4A313952424A4A31394A313952424A4A31395242 + 4A52424A4A31394A313952424A4A31394A31394A313952424A4A31394A39424A + 39424A39424A39424A31394A313952424A4A31394A39424A39424A31394A3942 + 4A39424A39424A39424A3942FFFFFF0000003118213118213118213929293118 + 2131182131182131182131182131182131182131182131182139292931182131 + 1821311821392929392929311821392929311829392929392929392929311829 + 3929293929293929313929313929293929314229313929294229313931523931 + 5231294A39315A42426B39315A39315A39315A39315A39315A39315A39315A18 + 104A847BA5F7EFFFEFE7FFEFEFFFEFE7FFE7DEFFEFE7FFEFE7FFEFE7FFEFEFFF + EFEFFFF7EFFFE7DEFF8C8CBD18215A29294A3129422918292918292918292918 + 2918100829182921101818081018081018102121101018081021101021101018 + 081018081021182121182121101818100818102142395A524A6B5A52736B637B + 736B8C736B8C736B8C736B8C736B8C6B637B7B737B6352731808081808102110 + 181808101810081808081808103929294A394252424A4A39424A39424A39424A + 39424A39424A39424A313952424A52424A4A313952424A52424A4A313952424A + 4A313952424A4A313952424A52424A52424A52424A4A394252424A4A31394A39 + 424A39424A39424A39424A39424A31394A39424A39424A394252424A4A31394A + 39424231394A39424A31394A31394A39424A3139FFFFFF000000311821311821 + 3118213118213118213118213118213118213118213118213118213118213118 + 2131182139292931182131182939292931182139292939292931182939292939 + 2929392929311829392929392931392929392929392929392929392929422931 + 39292942293142313139315239295239315A39317342315A39315A39315A3931 + 5A39315A31315A18104AA59CC6FFFFFFEFEFFFEFE7FFE7DEFFEFEFFFE7DEFFEF + EFFFEFE7FFEFEFFFF7EFFFD6D6F75A528C18295A31315A311831211018211821 + 2918292918292918292118212118212110182118212918292110101808102110 + 1021101021101818102121101821101018081018081021101818100821101042 + 314A524A6B6352736B637B6B6B8C736B8C736B8C736B8C736B8C736B8C5A5273 + 1000002110081808101808101808082918294A39424A39424A39424A31394A39 + 424A39424A39424A39424A39424A394252424A52424A52424A52424A52424A4A + 313952424A4A313952424A4A313152424A52424A4A313952424A4A31394A3139 + 52424A4A31394A31394A39424A39424A39424A31394A31394A39424A31394A39 + 424A39424A39424A39424A31394A39424A313952424A4A31394A3139FFFFFF00 + 0000311821311821311821311821311821311821311821311821311821311821 + 2918293118213929293929293118293929293929293118213929293118213929 + 2939292939292939292939292939292939292939292939292939292942293142 + 293142293139293142293142313139293142313142313139293139315239315A + 39315A39315A39315A39315A39295218104AB5B5DEF7EFFFE7DEFFEFEFFFE7DE + FFE7DEFFEFEFFFEFEFFFEFEFFFF7EFFFC6BDE731316B31315A31315A39292921 + 1821392931392929211018291829211018392929291829211821211018180810 + 2110182110101808102918292118212110182110182110182110101808102110 + 10180810181008100000393152635A7B635A7B6B637B6B637B736B8C736B8C73 + 6B8C736B8C635A631000002110081808101808082918294A39424A39424A3942 + 4A39424A39424A39424A39424A39424A39424A39424A39424A394252424A5242 + 4A4A313952424A4A313952424A52424A52424A52424A52424A4A313952424A4A + 394252424A52424A4A39424A394252424A4A39424A31394A39424A39424A3942 + 4A31394A31394A31394A31394A31394A39424A31394A39424A31394A39424A31 + 394A3139FFFFFF00000021100831182131182131182131182131182131182131 + 1821311821311821311821311821311821311821311821392929392929392929 + 3929293929293118213929293118213929293929293118293929293929293929 + 3139293139292939292942293139293142293142293142293142293142293142 + 313142293142313939397342426B39315A39315A39315A21184AC6BDE7F7EFFF + E7DEFFEFEFFFE7DEFFE7DEFFE7DEFFEFE7FFFFFFFFB5B5DE08105231315A3931 + 5221101029182929182929182921182139292931294221101829293939292929 + 1829211018180810291829211018211821211018180810180810211010180810 + 21101018081018102121101018081021101010000042314A635A7B6B637B6B6B + 8C6B637B6B637B736B8C736B8C63527318080818081010000829182952424A4A + 39424A39424A31394A39424A39424A39424A39424A39424A39424A39424A3139 + 4A313952424A52424A52424A52424A52424A52424A4A313952424A52424A5242 + 4A52424A4A39424A39424A394252424A4A31394A39424A394252424A4A39424A + 39424A31394A39424A31394A39424A39424A39424A31394A39424A31394A3942 + 4A39424A313952424A4A3139FFFFFF0000003118213118213118213118213118 + 2131182131182131182131182131182139292931182131182139292939292931 + 1821392929392929392929392929392929392929392929392929392929392929 + 3929293929293929293929293929313929314229314231314229314229314231 + 3142313942313942293142313139292942313939315A39315A39315A31294A21 + 184ACEC6EFEFEFFFE7DEFFE7DEFFE7DEFFE7DEFFEFEFFFFFFFFFB5B5DE21185A + 3939734242632929392918293129423929292118212918292918294231394231 + 3929213929182929182929182929182921101829213929182921101821101821 + 1018180810211018180810211010180810180810211018180810181008180808 + 4A425A635A7B635A7B6B637B736B8C6B637B736B8C5A52731000001000003929 + 3152424A4A39424A39424A31394A39424A39424A31394A31394A39424A39424A + 39424A39424A394252424A52424A52424A5A4A4A4A31394A313952424A52424A + 52424A52424A4A313952424A4A31394A31394A31394A39424A394252424A4A31 + 394A39424A394252424A4A39424A31394A31394A31394A31394A39424A39424A + 39424A39424A31394A31394A39424A31394A3942FFFFFF000000291829311821 + 3118213118213118213118213118213118213118213118213118213929293118 + 2139292931182139292939292939292931182939292939292939292939292939 + 2929392929422931392929392929392929392931422931392929423131392929 + 4229314231314231394231394231314231393929314231314231314231393929 + 5231315A31294A21184ACEC6EFEFEFFFE7DEFFE7DEFFE7DEFFE7DEFFFFFFFFA5 + A5CE08105A39397B424A73292139291829311821211010211821211010211018 + 3929313931523129422918293931522918292921394231392918292929392110 + 1821101821101818102121101821101821101018102118081018081018081021 + 1010181021180808180810524A6B635A7B6B637B6B637B736B8C736B8C5A525A + 0000002918295A4A4A4A39424A31394A39424A394252424A4A313952424A5242 + 4A52424A4A31394A39424A394252424A52424A4A313952424A4A31395A424A52 + 424A52424A52424A52424A52424A52424A52424A4A313952424A52424A52424A + 4A313952424A4A394252424A4A313952424A4A39424A31394A39424A39425242 + 4A4A31394A39424A31394A31394A39424A39424A39424A31394A3942FFFFFF00 + 0000311821311821311821311821311821311821311821311821392929392929 + 3118213118213929293118213929293118213929293929293929293929293929 + 2939292942293139292931182939292939293139292939292939293139292942 + 2931422931422931392931422931392931423131422931423139423139392931 + 4231394231314A313139295231294A21184ACEC6EFEFEFFFE7DEFFE7DEFFE7DE + FFFFFFFFC6BDE718215A42317B424A8442426329182921101029182921182139 + 292929182929182929293942395A31294231315A31294A392931292939312942 + 2118214231392918292110182118213929292110181810212110182110101808 + 10181008211018180810181008181008100000211821635273635A7B635A7B6B + 637B736B8C4A425A18100852424A4A39424A39424A39424A39424A39424A3942 + 52424A4A39424A39424A39424A394252424A4A39424A313952424A52424A5242 + 4A52424A52424A52424A4A39424A313952424A52424A52424A4A313952424A4A + 39424A39424A313952424A4A394252424A4A394252424A4A31394A394252424A + 4A31394A39424A313952424A4A394252424A4A39424A39424A31394A31394A39 + 424A3139FFFFFF00000031182131182131182131182131182139292931182131 + 1821311821392929311821311821392929392929392929392929311829392929 + 3929293929293118293929293118293929293929293929313929293929293929 + 2939293139292939293139293142293142313142313142293142313942313142 + 29314231394231394231313929314231394231314A3139181031BDBDE7EFE7FF + E7DEFFE7DEFFFFFFFFDED6F721296B39397B424A8442426B3929312110081808 + 1021101821101821101829182921102939293131294239315242426331294221 + 1821211018211018181021211018211010181021211018211018211018181021 + 1810212110101810211808102110101808102110101810212110100800084231 + 4A6B637B635A7B6B636B736B8C4A425A4A313152424A4A39424A39424A39424A + 39424A39424A39424A31394A39424A39424A39424A39424A39424A394252424A + 4A39424A313952424A5A424A52424A52424A52424A52424A4A39424A31395242 + 4A4A394252424A52424A4A313952424A4A313952424A4A313952424A52424A52 + 424A4A313952424A52424A4A31394A39424A31394A39424A39424A31394A3942 + 4A39424A39424A31394A3942FFFFFF0000003118213118213118213118213118 + 2131182131182139292939292931182139292939292931182131182131182139 + 2929392929311821392929311829392929392929392929392929392929392929 + 3929293929313929293929314229314229314229313929314229313929314231 + 314231394231394231394229314231394231394231394231314231394A313121 + 1018BDB5DEEFE7FFE7DEFFEFEFFFEFE7FF39397B31396B4A4A84424A7331316B + 3118292918292918292110182110181808082110292918292110182918293931 + 5239315229182921101818081021101021101018080818081018081021100818 + 0810211018211010211018180810211010211018180810180810180810181008 + 2110181810081808105A52736B637B6352736B637B5A525A4A31394A394A4A39 + 424A39424A39424A39424A39424A39424A394252424A4A39424A39424A39424A + 39424A39424A394252424A52424A52424A52424A52424A4A313952424A52424A + 52424A52424A52424A4A313952424A4A31394A39424A394252424A4A39425242 + 4A52424A4A394252424A52424A4A39424A394252424A4A313952424A4A31394A + 39424A39424A31394A39424A31394A39424A3139FFFFFF000000311821311821 + 3929293118213118213118213929293929293118213118213929293118213929 + 2939292939292939292931182139292939292939292939292939292939292939 + 2929392929392931422931392929392931422931392929392931392931422931 + 4231314231314229314231394229314231314231394231394229314231394231 + 39423139423139211008B5ADCEEFE7FFE7DEFFF7EFFF5A5A8C31316B4A4A8439 + 397B39317339315A312942211010211821211018211821211018211018392931 + 29213931214231315A2110292118211808101808081808081808082110102110 + 1018080818080818081021101018081018081018081021101018081018100821 + 10181810081808101808102110101000003929316B637B5A5273635273524A52 + 4A31394A39424A31394A39424A39424A39424A39424A394252424A4A39425242 + 4A4A31394A39424A39424A394252424A4A313952424A52424A4A394252424A52 + 424A52424A4A313952424A4A313952424A4A313952424A52424A4A313952424A + 52424A4A313952424A4A313952424A4A313952424A4A313952424A4A31394A39 + 424A39424A39424A39424A31394A39424A31394A39424A31394A3139FFFFFF00 + 0000311821392929392929311821392929311821311821311821392929392929 + 3118213929293118213929293118293929293929293118213929293929293929 + 2931182939292939292939292939292942293139292942293139293139292942 + 2931422931392929392931423131423139423131423139423139392931422931 + 4231394231394229314231394A31312108089C9CBDEFE7FFF7EFFF7373A51829 + 5A4A4A8439397339315A31396B39315A29182921101821101821101821101821 + 101029182931294A39295239315A31294A211018210808211010181021180810 + 2110102118211808081808081808081810081808101808101810211808101808 + 101810081808102110101808102110182110101808102110100800084A425A6B + 637B5A52734A394A4A313952424A4A39424A39424A39424A39424A39424A3942 + 4A39424A39424A394252424A4A39424A39424A39424A394252424A52424A5242 + 4A52424A4A313952424A4A313952424A52424A52424A52424A52424A52424A4A + 394252424A4A394252424A4A394252424A52424A4A394252424A52424A4A3942 + 4A313952424A4A39424A39424A39424A39424A39424A39424A39424A31395242 + 4A4A3942FFFFFF00000031182139292939292931182131182131182139292931 + 1821311821392929392929311821392929311821392929392929392929392929 + 3118293929293929293929293929293929293929294229313929293929294229 + 3139293139293139292942313142313142293142313942293142313942293142 + 31394231394231314231314231314231394231314A3139211008847BA5F7EFFF + BDBDDE0810524A4A8439397331315A39397339397331396B3929312118212110 + 1821101829182929182929213929214A31315A31315A29214A29295A31317B29 + 297B31398C39217B31317B39217B29215A29215A292139211021181008181008 + 2110102110101808101808102110101810212110101808102110101808102110 + 10181008180810635A7B6352734A394A4A39424A39424A39424A39424A39424A + 39424A31394A39424A39424A394252424A4A39424A39424A39424A39424A3942 + 4A313952424A4A394252424A52424A52424A52424A5A424A52424A52424A4A31 + 3952424A4A313952424A4A313952424A4A313952424A4A313952424A4A39424A + 313952424A52424A4A31394A39424A39424A39424A39424A394252424A4A3942 + 4A39424A39424A31394A3139FFFFFF0000003118213118213118213118213118 + 2131182139292931182139292931182139292939292931182939292931182939 + 2929311829392929392929392929392929392929392929392929422931392929 + 4229314229313929314229313929294229313929314229314231314231314231 + 3942293142313942313142313942293139293142313142313942313942313131 + 18216B636BEFEFFF4A4A8431396B4A4A8439397339397331396B39397B42426B + 39315A31294229182921101029182931294231294231294A31315A31316B4A5A + 9C5A5AB55A5AB55A5AB55A5AB54A5AA55263AD4A5A9C42529C39217B39217B29 + 294A211031211018180810180810211018181021211010180810180810180810 + 18081021101018081018081010000042314A6B637B4A394A4A39424A39424A39 + 424A39424A39424A39424A394252424A4A31394A39424A39424A394252424A4A + 39424A394252424A52424A52424A52424A4A39425A424A4A313952424A52424A + 52424A52424A52424A52424A52424A4A394252424A4A313952424A4A31395242 + 4A4A394252424A52424A4A31394A39424A394252424A4A39424A39424A39424A + 39424A31394A31394A39424A31394A313952424AFFFFFF000000311821311821 + 3929293118213929293118213929293929293118213929293929293118213929 + 2931182139292931182939292939292939292939292939292939292939293142 + 2931392929422931392929422931392929392929392931422931422931423131 + 4231394229314231314231394229314231394231314231394231394231314231 + 394231314231393929295A5273C6BDE721296B42427B39397331396B39428C39 + 397B39397B39397331315A31294221101821101829182939292929214231315A + 4A4A846373B57373C67373C68494D6949CCE848CCE848CCE7373C66B63B57373 + C65A63A539398C39217B31214A29213921101821101021101018081021101818 + 08102110102110102110101810212110101808101808102110185A52734A3942 + 4A39424A39424A39424A39424A39424A39424A39424A394252424A4A39424A39 + 424A39424A39424A394252424A4A313952424A52424A52424A52424A52424A52 + 424A52424A52424A52424A4A313952424A52424A52424A4A313952424A52424A + 4A313952424A4A313952424A4A39424A39424A313952424A4A31394A31394A39 + 424A31394A31394A39424A394252424A52424A4A313952424A4A3139FFFFFF00 + 0000392929311821311821311821392929311821392929311821392929392929 + 3929293929293929293929293929293929293929293929293929293929313929 + 3139292939292942293142293142293142293139293142293142293142293139 + 2929423131423131423131422931423131423139423139392931423139423131 + 4229314231394231394231394231393929314A39425A639C31396B42426B3139 + 6B39428C424A8C424A84424A84424A8442427B39315218081018081021101821 + 101831294A424A8C6B6BA5848CCE94A5DE9C94C69CADE78C9CDE7373C65A5AB5 + 5A639C39398C5A639C6B63B55263A539398C31296B29214A2921392118211810 + 2118081018081021101018102118081018081021101018102121101818081018 + 100842314A52424A4A39424A39424A39424A39424A394252424A4A394252424A + 4A39424A313952424A52424A52424A4A39424A394252424A4A313952424A5A42 + 4A4A313952424A52424A4A313952424A52424A52424A4A313952424A4A313952 + 424A4A39424A394252424A4A394252424A4A39424A313952424A52424A4A3139 + 52424A52424A4A313952424A52424A4A39424A31394A39424A313952424A4A31 + 394A3139FFFFFF00000031182131182139292931182131182139292939292939 + 2929392929392929311821392929311829392929392929311829392929392929 + 3929293929293929293929294229313929293929293929314229313929293929 + 3139293142293142293139293139293142313142313139293142313142313942 + 31394229314231394231394229314231394231314231314A313942313931396B + 39397331396B39397B39428C424A84424A8439397B5263A5424A8C2929392108 + 0818081021101029182910002131214A42426B635AA5635AA54A5AA539217B21 + 186B4A4A844A316B18083921103129213918083929215A31315A29215A292142 + 2110212118212118212110101808101808102110101808102110102110182110 + 1021101021101010000839293152424A4A313952424A4A394252424A4A39424A + 313952424A4A394252424A4A39424A39424A39424A39424A39424A313952424A + 52424A52424A52424A52424A52424A4A394252424A52424A4A313952424A5242 + 4A4A313952424A52424A52424A4A394252424A4A313952424A52424A52424A4A + 31394A394252424A4A313952424A52424A4A39424A31394A394252424A4A3942 + 4A394252424A4A39424A3942FFFFFF0000003118213929293118213929293929 + 2939292939292939292942293142293139292939292939292939292939292939 + 2929392929392929392929392929392929392929392929392929422931392929 + 3929294231314229313929293929293929314231314229314231314229314231 + 314231394231394231314231394231314231394231394A313142313942313942 + 313142314A42427B393973393973424A8C42529C424A843942844A52944A5294 + 3939733929311810211810211808081810216352736B636B312142524A6B524A + 6B5A5273635A7B6B637B9C9CA58C849C42426B311839635A63524A5221102129 + 1829180810000000180810181021100008100000180810211010180810180810 + 18102121101818081018102121101018100829182952424A52424A4A39424A39 + 424A394252424A52424A52424A4A313952424A52424A4A39424A39424A394252 + 424A4A39424A39424A39424A394252424A52424A52424A52424A4A39425A424A + 52424A4A394252424A52424A4A313952424A4A39424A313952424A52424A4A39 + 4252424A4A313952424A52424A4A31394A313952424A4A394252424A52424A4A + 39424A39424A394252424A4A31394A31394A3139FFFFFF000000311821311821 + 3118213929293929293118213929293929293929293929293929293929293929 + 2931182139292939292931182939292939292939293139292939292939292942 + 2931392929422931422931392929422931392931422931423131422931423131 + 4231314231314231394231394231314231394231394231314231394231314231 + 3942313942313942313142314A424A7331396B424A8442529C424A8C39428C39 + 42844A52944A5294424A733931522918294231394A39426B637B949494C6CED6 + 948CAD524A6B8C849CA594AD948CAD948CADADADB57B739C5A528442315A5A4A + 637B73732108213929318C848C736B7310000821101842313929182918080818 + 10211810081808102110182118212110182110102118211808102110184A3942 + 52424A4A394252424A4A39424A39424A39424A39424A39424A39424A39424A39 + 4252424A4A39424A39424A394252424A52424A52424A52424A52424A52424A4A + 394252424A4A39424A39424A394252424A4A313952424A4A39424A394252424A + 52424A4A313952424A4A394252424A52424A4A39424A394252424A52424A4A39 + 4252424A4A39424A39424A39424A39424A31394A394252424A52424AFFFFFF00 + 0000392929392929392929311821392929392929311821311821392929311821 + 3929293118293929293929293929293929293929293929293929293929293929 + 2942293139292939292942293139292942293139292939292942313142313139 + 29314231314231314231394A31394231314231394A3139423139422931423139 + 42313942313942313142313942313942313139315239397B39397B424A8C4A52 + 9439428439397B424A8442529C4A5294424A8439315A3129423129427B737B7B + 7394736B8CBDADC6A594ADA594AD8C849C524A6B6B637B8C84ADA594ADA594AD + CECED6736B8C5A4A63AD9CC65A525A100008635273A594AD6B636B4A3942635A + 6339292918080818100821101021101021101821182121101821101818081018 + 08101808084231394A394252424A4A39424A39424A39424A39424A39424A3942 + 52424A4A39424A394252424A4A394252424A4A31394A394252424A52424A5242 + 4A52424A52424A52424A5A424A52424A5A424A52424A52424A52424A4A313952 + 424A52424A52424A4A394252424A4A39424A394252424A4A39424A313952424A + 4A31394A31394A39424A39424A31394A31394A394252424A52424A52424A4A39 + 424A3942FFFFFF00000031182131182139292939292931182139292939292939 + 2929392929392929392929392929392929392929392929392929392929392929 + 3929293929293929293929294229314229313929294229314229314229313929 + 313929294231314229314231314231394231394A313942313942313142313942 + 313942313942293142313942313942313942313142313942313939315A39397B + 424A84424A8C4A5294424A84394284424A8C4A52944A529439428442426B3931 + 5A292142524A52847B846B637B847B9CA594ADBDADC67B7394A594AD8C848C8C + 849C9C9CA5BDADC6BDB5DEBDB5BD8C848C8C849CADADAD5A4A52635A6352424A + 635A635A4A523929291810212110182110182110182110182110182118212110 + 1821101821101821101810000839292952424A4A39424A39424A39424A39424A + 39424A39424A394252424A4A39424A39424A39424A394252424A52424A4A3942 + 52424A5A424A52424A52424A52424A5A424A4A39424A394252424A4A31395242 + 4A52424A52424A4A394252424A4A394252424A4A394252424A4A313952424A52 + 424A52424A52424A52424A4A394252424A4A394252424A4A394252424A4A3139 + 52424A52424A4A313952424AFFFFFF0000003118213929293118213118213929 + 2931182139292931182139292931182139292931182139292939292942293139 + 2929392929392929392931392929392929392931392929392931422931392929 + 3929314231314229314231313929314231314231314231394A31394231394231 + 3142313942313142313942313142313942313942313142313942313942313942 + 313939397339397B424A844A5294424A8C424A8C424A84424A8C4A52944A5294 + 4A5A9C4A4A84424A7331315A5A52737B73949494948C848CA594AD9C9CA5C6C6 + CEC6CED6B5ADCE9C9C9C6B636B7B737B9C9CA5BDB5BD6B636B847B848C848C63 + 5A63524A526B636B5A525A6B636B311829211008211018211018211010211018 + 21101821182121182118102121101818102118081029182952424A52424A4A39 + 424A394252424A4A394252424A52424A4A31394A394252424A4A313952424A4A + 39424A394252424A4A39425A424A52424A5A424A52424A4A394252424A52424A + 52424A52424A4A394252424A4A394252424A4A394252424A52424A4A31394A39 + 4252424A4A31394A39424A39424A39424A31394A39424A313952424A4A31394A + 39424A313952424A52424A4A313952424A52424AFFFFFF000000311821392929 + 3118213929293118213929293929293118213929293929293929294229313929 + 2939292939292939292939292939292939292939293142293139292939293142 + 2931392929422931422931422931392931392929423131423131422931423131 + 4231394229314231394231394231394231394231394231394231314231394231 + 314231394A313142313939397B39397B424A8C4A5294424A8C424A843942844A + 5294424A8C42529C4A5A9C5A6BAD5263A539397B635A7B847B9C8C849C948CAD + 948CAD736B8C8484847B7394949494736B8C4231394A394A6B637B736B732918 + 293118293929315A4A523929293929313929314A394A39293118102121101821 + 1018211018211821211821211821211018211018181021211018211018180810 + 4A394252424A4A394252424A4A39424A394252424A4A313952424A52424A4A39 + 4252424A4A39424A39424A394252424A52424A52424A52424A5A424A52424A52 + 424A52424A52424A52424A4A394252424A4A31395A424A52424A52424A4A3942 + 4A39424A394252424A4A313952424A52424A52424A4A31394A394252424A5242 + 4A4A39424A394252424A52424A52424A4A394252424A52424A4A3139FFFFFF00 + 0000392929311821392929311821392929311821392929392929392929392929 + 3929293929293929294229313929293929294229313929293929293929294229 + 3139292942293139292942293139293142293139292942313142313139293142 + 3131423131422931423139423139423131423139423139423139423131423139 + 42313942313942313942313942313139315239397B424A84424A8C4A52944A52 + 94424A8C424A8C4A52944A52944A4A844A52945A6BAD6B7BBD6B6BA57384BD8C + 8CB57B7BAD7B7BAD7373A54A4A8442426B39397342529C29295A100008211031 + 31315A1810212118212921392110182110182918291810211808102110292921 + 3921182121182129213929213929182921182129182921182121101821182121 + 101821101818081042313952424A4A394252424A52424A52424A4A394252424A + 4A394252424A4A394252424A4A394252424A52424A4A394252424A52424A5242 + 4A52424A5A424A52424A52424A52424A5A424A52424A52424A52424A52424A52 + 424A4A394252424A52424A52424A4A313952424A52424A4A313952424A52424A + 4A31394A394252424A4A313952424A4A394252424A4A394252424A4A31395242 + 4A4A3139FFFFFF00000039292931182139292939292931182139292939292931 + 1821392929422931422931392929392929392929392929392929392929392929 + 3929294229313929293929313929294229313929313929293929313929313929 + 293929314229314229314229314231314231314A313942313942313142313942 + 313942313942313942313942313942313942313142313142395A394284424A8C + 4A4A844A52944A5294424A8C4A52945A639C4A5A9C4A52944A5A9C525A945A6B + AD7B8CCE7B8CCE8494D68494CE8494CE7B8CCE5A63A54A52944A4A8442427B39 + 3973393973424A844A529429214239315229293929182931182929213929214A + 29214A31294A29294A29214A29294A29294A29214A2921392110292110292118 + 212110182110182110182110181808083929295A4A4A4A39424A39424A394252 + 424A4A39424A394252424A4A394252424A4A39424A39424A394252424A4A3942 + 4A394252424A5A424A5A424A52424A52424A52424A52424A4A394252424A4A39 + 4252424A4A39424A394252424A52424A52424A52424A52424A4A394252424A52 + 424A4A313952424A52424A4A313952424A52424A4A394252424A52424A4A3139 + 52424A52424A4A39424A3942FFFFFF0000003118213929293118213118213118 + 2139292931182139292939292939292939292939292939292939292939293139 + 2929392931392929392929392931392929392929422931392929392929422931 + 3929293929314231314231313929294231314231394229314231314231314231 + 394A31394A31394231394231314A31394231394A31394231394231394A313139 + 397342427B424A844A4A844A52944A52944A5294525A945263A5525A945263A5 + 525A944A5A9C5263A55A6BB57384BD7B8CCE8494D67B94D68C9CDE848CCE6B7B + BD6B73BD5A639C4A4A844A5A9C42529C4A5A9C39397339315239292929214231 + 294231294A29294A31315A29295A31296B31315A39317329295A31214A292142 + 29182921102921102921182121101821101821101818081029182952424A5242 + 4A4A39424A394252424A52424A52424A4A394252424A4A394252424A4A39424A + 394252424A52424A52424A52424A52424A52424A52424A52424A52424A52424A + 52424A4A39425A424A52424A5A424A52424A52424A52424A52424A52424A4A39 + 4252424A52424A52424A52424A52424A4A313952424A52424A4A313952424A52 + 424A4A313952424A4A313952424A4A31394A3942FFFFFF000000392929392929 + 3929293929293929293929293929293929293118213929293929293929293929 + 2931182139292939292939292939292939292939292939292942293142293139 + 2929422931392931422931423131422931392931423131422931423131423131 + 4229314231394231394A31394A31394231394231394231394231394A31314A31 + 314A313142313942427B3942844A4A844A52944A52944A5A9C5263A55263A563 + 6BAD5A63A55263A55263A55A63A55A6BAD5263AD6B73BD7B8CCE7B8CCE8494D6 + 7B8CCE6B73BD5A6BB56B73BD738CCE6B73BD42529C29295A29214A31214A2929 + 3929214239315231294A21103129294A31296B31296B31315A31296B31316B31 + 315A31315A29214A292139211031291829211821211018211018181021180810 + 29182952424A4A394252424A4A39424A39424A394252424A4A394252424A4A39 + 4252424A4A394252424A4A39424A313952424A52424A52424A52424A52424A52 + 424A52424A52424A52424A52424A52424A4A39424A39424A394252424A4A3942 + 52424A4A394252424A4A39424A394252424A4A313952424A52424A4A39424A39 + 4252424A52424A4A394252424A52424A52424A52424A52424A52424AFFFFFF00 + 0000311821392929311821392929311821392929311821392929392929392929 + 3929293929293929293929293929293118293929293929293929293929293929 + 3139292939293142293139293142313142313942313139292942293142313942 + 31314231394229314231394231394A3139423139423139423139423139423131 + 42313139295229215A3929314A313939397B42427B4A52944A52944A52945263 + A55263A55A6BB56373B55263A55263AD5A6BAD5A6BAD5263AD5263AD5A6BB573 + 84C67B8CCE848CCE5263A531398C4A5AA56B84C65A73BD42529C31296B211029 + 21080810000021102129182929182929214229182921102129214229295A3131 + 5A31315A31296B31396B31296B31294A29214229182929293921102921101818 + 10212110182110181808104A394A52424A4A394A4A394252424A4A394252424A + 4A394252424A4A394252424A52424A4A394252424A52424A52424A5A4A4A5A42 + 4A52424A5A424A52424A52424A52424A5A424A5A424A52424A52424A52424A52 + 424A4A394252424A4A39424A394252424A52424A52424A52424A52424A4A3942 + 4A313952424A52424A4A39424A39425A424A4A394252424A52424A4A31395242 + 4A4A3139FFFFFF00000039292931182139292939292939292931182139292939 + 2929311821392929392929392929392929392929392929392929392929392929 + 3929293929293929294229313929293929294231314231313929294231314231 + 314231313929314231314231314231314231314A31394231394A31394A313942 + 31394231314229314A4A845273BD4A63A531398C39397339397B424A84424A8C + 4A52945263A55A6BAD5A6BAD6373B56B7BBD6373B56373B56373BD5A6BB55A6B + AD5263AD526BB56B84C67B8CCE6373B531317B424A84424A8431315A31315A39 + 428C424A8431296B31296B29214A18080818080821182129214231315A211031 + 29182929214A31296B31396B39428431316B29295A31294A31294A2921422110 + 292110292118212118212110181810211808104A394252424A4A394252424A4A + 394252424A4A394252424A52424A4A394252424A4A394252424A4A394252424A + 4A39425A424A52424A52424A52424A52424A52424A52424A52424A52424A5242 + 4A5A424A4A394252424A52424A4A394252424A4A39424A39424A394252424A5A + 424A4A313952424A4A39424A394252424A52424A52424A52424A52424A52424A + 4A313952424A52424A4A3942FFFFFF0000003929293929293929293118213929 + 2939292939292931182139292939292931182139292942293139292939293139 + 2929392929392929392929392931392931392931422931422931422931423131 + 4229313929313929313929314231314229314231394231394229314A31394231 + 394A31394231394231393929314231395A73BD637BBD6B84C65273BD39398C39 + 39733942844A52944A52945A63A5636BAD7384BD6B7BBD7384BD6B7BBD6B7BBD + 6B7BBD7384BD6B73BD5A6BB5526BB56373B57384C65263AD21186B1000000800 + 0829214239428C4A5AA542529C394294424A8C39428431296B21102118080821 + 100829213929214A29182929214A31316B31396B39397B31315A31315A31296B + 29295A2921422921392110292118212110182110181810212110182110182118 + 2139293142314A4A394A52424A52424A4A394252424A4A394252424A4A394A52 + 424A52424A52424A52424A52424A52424A5A424A5A424A52424A52424A52424A + 52424A52424A5A424A52424A52424A52424A4A39424A394252424A52424A5242 + 4A52424A52424A4A313952424A52424A4A313952424A5A424A52424A52424A4A + 394252424A4A313952424A52424A4A31394A3139FFFFFF000000311821311821 + 3929293929293929293929293118213929293929293118213929293929294229 + 3139292939292939292939292939292939292939292939292939292942293139 + 2929423131423131422931392929422931423131422931423131423131423139 + 4231314231394A31394231394231394231394229314A425A6B84C67384C6637B + BD637BBD424A8C31396B4A52945263A55A63A55A63A56B7BBD7384BD7B8CCE7B + 8CCE7384C68494CE848CCE7384BD6B73BD6373B55A6BB55A6BB56B7BBD7384C6 + 4A5AA542427B7384BD8CA5E77B8CD66B84C64252A5394294424A8C3942943942 + 8C31315A29214A18081018080821103129213929295A39397339397B39397339 + 397331316B31315A31315A29214A292139211029211029211018181021211018 + 2110181810212110212110183129424A394252424A52424A52424A4A39425242 + 4A4A394252424A4A394252424A4A394252424A5A424A52424A52424A52424A52 + 424A52424A52424A52424A52424A4A394252424A4A39424A394252424A4A3942 + 52424A4A39424A394252424A4A394252424A4A394252424A4A394252424A5242 + 4A52424A52424A52424A52424A52424A52424A4A313952424A52424AFFFFFF00 + 0000311821392929311821392929311821392929392929311821392929392929 + 3929293929293118293929293929293929293929293929293929293929294229 + 3139293139292942313139293142293139293142313142313139293142313142 + 31314231314231394231394231394A31394A31394A3139423139422931524A6B + 7384C66B7BBD637BBD6B7BBD5A528C3939734A52945A63A5636BAD7384BD7384 + BD7B8CCE7B8CCE8494CE8C9CDE8C9CDE8494CE7B8CCE7384BD7384BD6B73BD5A + 6BB55A6BB58C9CDE9CADE79CADEF9CADEF9CADE79CADE794A5DE6B73BD4A5AA5 + 4A5AA55263A542529C31296B31296B39397329214A29214A2921423939733942 + 8439428439397B31396B39397331296B31315A31315A29214A29213921182121 + 182121101821101821101821182121102921102121102952424A52424A4A3942 + 52424A4A394252424A52424A4A394252424A4A394252424A52424A52424A5A42 + 4A52424A52424A52424A52424A52424A52424A52424A5A424A4A394252424A52 + 424A4A394252424A4A394252424A52424A4A394252424A52424A52424A4A3942 + 52424A4A394252424A52424A4A313952424A52424A4A313952424A52424A5242 + 4A4A3942FFFFFF00000039292939292939292939292939292931182139292939 + 2929392929311821392929392929392929392929392931392929392929392931 + 3929293929313929293929293929314229314229313929314231313929314231 + 314231313929314231394231394231314231314231314A31394231394A313942 + 31393929296B6B9C848CCE848CCE7384C67384BD42427B424A845263A55A63A5 + 636BAD6B7BBD7B8CCE7B8CCE8494CE8494CE8494CE8494D6949CCE8C9CDE7B8C + CE6B7BBD5A6BB55263AD4A5AA56373BD9CADE794A5DE849CDE7B8CCE8C9CDEAD + B5E794A5DE7384C67384BD7384BD4A5AA531296B3931735263A54A5AA531316B + 31296B394284424A8439397B39397339397331316B31296B29215A31315A2929 + 4A2921392110292110182110212110182110182110182110182118211810214A + 394252424A4A394252424A52424A4A394252424A4A39424A313952424A4A3942 + 52424A52424A52424A52424A52424A52424A4A394252424A5A424A52424A4A39 + 425A424A4A394252424A4A39424A394252424A4A394252424A4A394252424A4A + 394252424A52424A4A394252424A4A394252424A52424A4A39424A394252424A + 4A313952424A4A313952424AFFFFFF0000003118213929293929293118213929 + 2939292939292939292939292939292939292931182939292939292939292939 + 2929311829392929392929392929392931422931392929392929392929423131 + 4231314229313929313929314231314231314231394229314231394A31394231 + 394231394A31394231394231315A6BB56B7BBD8494CE6B84C65A6BAD39397B4A + 52945A6BAD636BAD7384BD7B8CCE8494CE8494D67B94D68C9CDE8CADE794A5DE + 849CDE7B8CCE6B7BBD6B7BBD637BBD5A6BB54A63A542529C5263AD7B8CD66B84 + C66B84C67B8CD6849CDE94A5DE848CCE7B8CCE6B73BD39428C29214A39428C5A + 6BB55263AD39397B31396B31316B31397B39397B39428C394284394284424A84 + 31316B31316B31294A2921422918292110292118212110182110182110182118 + 2121182121101842313952424A52424A4A39424A394252424A4A394252424A52 + 424A52424A52424A52424A5A424A52424A52424A52424A52424A52424A52424A + 5A424A52424A5A424A4A394252424A4A394252424A52424A4A394252424A4A39 + 4252424A4A394252424A4A394252424A4A313952424A52424A4A394252424A5A + 4A4A4A39424A394252424A52424A52424A4A3942FFFFFF000000392929392929 + 3118213929293929293929293929293929293929293118213929293929293929 + 2939292939293139292939292939292939293139293142293139292942293139 + 2931422931423131392929423131423131423131422931423131423139423131 + 4231314231394A31394A31394231394231314A394A6373B56373B56B7BBD4252 + A55263A5424A845263A55A6BB56373B57B8CCE7B8CCE7B8CCE8494D68CADE77B + 94D6636BAD5263A55A639C6B6BA56B7BBD6B7BBD6B6B9C6B6B8C525A9442529C + 3142945A6BAD8CA5E7849CDE738CCE849CDE8C9CDE7B8CCE6B84C65263AD3131 + 6B29214231317B39428C31315A29214A39317329295A31396B31315A39315A39 + 315A31315A31315A31396B21296B29295A29294A292139211031211821211021 + 211018211018211018211029211029291829524A524A394A52424A52424A5242 + 4A4A39424A394A52424A4A39424A394252424A5A424A5A424A52424A52424A52 + 424A52424A52424A4A39425A424A4A39425A424A4A394252424A4A39424A3942 + 4A394252424A4A394252424A4A394252424A52424A4A394252424A4A39425242 + 4A52424A4A313952424A52424A4A394252424A4A31394A39424A3942FFFFFF00 + 0000311821392929392929392929311821392929392929392929392929392929 + 3929293929293929293929293929293929293929293929293929293929294231 + 3139293139292939293142293139293142293139293139293142313142313942 + 31394231314A31394231394A31394231394A31394A31394231314A425A6B84C6 + 5A5AB531398C5A6BAD636BAD424A845263AD637BBD6B7BBD7B8CCE8494CE8494 + CE9CADEF5A639C524A6B6B7BBD8494D694A5DE8CADE78C9CDE8494D68C9CDE84 + 94CE949CCE948CAD4A4A8418217B637BBD8CA5E77B8CD6849CDE94A5DE8494D6 + 5A73BD39429429215A29214A31315A29215A29214A29294A21214A42395A524A + 6B4A4A845A52734A5294635A7B525A945A5273635A6339315218104A21214A29 + 18292118212118212110181810212110182110292110292110214A39425A424A + 4A39424A394252424A4A39424A394252424A52424A52424A52424A52424A5242 + 4A5A424A5A424A52424A52424A52424A52424A52424A52424A52424A52424A52 + 424A52424A52424A52424A4A394252424A52424A52424A52424A4A394252424A + 52424A4A39424A39424A394252424A4A394252424A4A31394A394252424A5A42 + 4A4A3942FFFFFF00000039292931182139292939292939292931182139292942 + 2931311821392929392929392929392929392929392929392929392929392929 + 3929293929313929294229314229313929294229313929294231314231314229 + 314229314231314231394231394231314231314231394A31394231394A313942 + 31314A425A6B84C639429421186B5A6BB55263A542529C636BAD6B7BBD738CCE + 8494CE8CADE78CADE7525A94424A738CADE7849CDE637BBD5A6BB55A6BB56B7B + BD6B84C67B94D67B94D67B8CCE8494D6BDBDDE5A527318217B849CDE849CDE8C + A5E794A5DE849CDE5A73BD39398C31296B31214A31296B31214A211031311831 + 524A6B42529C424A8C39428C39428C424A8439428C424A8C39428442427B6B6B + 8C736B7318103121214A21182129182921182121101818102121101821182118 + 102139293152424A52424A52424A4A394252424A52424A4A39424A39425A424A + 5A424A52424A5A424A52424A52424A5A4A4A52424A52424A52424A5A424A5A42 + 4A52424A52424A52424A4A39424A394252424A52424A4A39424A39424A394252 + 424A52424A4A394252424A52424A52424A52424A4A313952424A52424A52424A + 4A31394A39424A39424A3942FFFFFF0000003118213929293929293118213929 + 2939292939292931182139292939292939292939292939292939292939292939 + 2929392931392929392931392929392931392931392929423131423131422931 + 4229313929294231314231313929314231314A31394231314231314A31394A31 + 394231394A3139423131524A6B6B84C631398C29297B4A52944A52944A52945A + 6BB5637BBD7384C68494D68CADE7636BAD39315A7B94D66B84C64A63A54A63A5 + 4A5A9C39429431398C39398C5263A5738CCE7B94D67384C68494D6BDBDDE3131 + 5A5263AD8CA5E78CA5E78CA5E77B8CD65273BD39428429215A29215A31315A31 + 315A31315A424A7339428431397B39428439428439397B39317331396B31316B + 31315A21296B21185A6B638C847B841000212921392110292118212110182110 + 1818102121182121102131183152424A4A39424A39424A394252424A4A394252 + 424A52424A4A39424A39425A424A5A424A52424A52424A5A424A52424A52424A + 52424A52424A52424A52424A5A424A52424A52424A52424A4A394252424A5242 + 4A52424A52424A52424A52424A5A424A52424A4A394252424A52424A52424A52 + 424A4A313952424A4A394252424A4A31394A3942FFFFFF000000392929392929 + 3118213929293929293929293118213929293929293929293118213929293929 + 2939292939292939293139292939293139292942293139292939292942313142 + 31313929294231313929314231313929314231314231314231394231314A3139 + 4231394231394231394A31394A39424231314A425A6373BD39429421186B2929 + 7B424A8C5263A56B7BBD6B7BBD7384C68494D67B94D639315A7384C66B84C65A + 6BB55263A5424A8C39397B39397B39397B39397B21296B424A8C6B84C68494D6 + 738CCE849CDE9C9CBD18217B849CDE8CA5E794A5DE7B94D65A73BD3942942921 + 5A31315A29295A31214A39397B39397B39397B39397B31396B31296B29295A31 + 315A31294A29294A31294A29294A29294A081052635A846B636B100021211031 + 2118212110182118212118212118212110292118214A394252424A52424A5242 + 4A52424A4A394252424A4A394252424A52424A52424A52424A5A424A5A424A52 + 424A52424A5A424A5A4A5252424A5A424A52424A52424A5A424A52424A52424A + 4A394252424A4A394252424A52424A52424A52424A52424A52424A52424A5242 + 4A4A394252424A4A313952424A4A39424A394252424A52424A4A3942FFFFFF00 + 0000311821392929392929392929311821392929392929392929392929392929 + 3929293929293929293929313929293929293929313929293929293929294229 + 3142293139292942293139293142293142313942313142313139293142293142 + 31394231394231314A31394231394231394A31394A313942313142426B5A73BD + 39429429297B31296B42529C5263A57384BD7384C67B8CCE7B8CCE637BBD4A4A + 84738CCE5A6BB54A5294424A8C31397B31317B31316B31296B39317339317329 + 215A31317B6373BD738CCE6B84C6949CCE31315A5A73BD9CADEF9CADEF7B94D6 + 5273BD39429429214A31296B29214A29293939397339397B39397B31315A3129 + 6B31315A29214A29213921102929213921103129293929213929293921103173 + 73A52921392110292118212118212110182110182110292921391808294A3942 + 5A424A4A39424A39424A394252424A4A394252424A4A39425A424A5A424A5242 + 4A5A424A5A424A5A424A52424A5A424A5A4A525A4A5252424A52424A52424A52 + 424A52424A52424A4A394252424A52424A52424A5A4A4A5A424A52424A52424A + 4A39425A424A4A394252424A4A394252424A52424A4A313952424A4A31394A31 + 394A3942FFFFFF00000039292931182139292939292939292931182139292942 + 2931392929392929392929392929392929392929422931392929392929392929 + 4229313929313929293929314229313929314229314231314231314229314231 + 394231314231314231314231394231394231394A31394A31394A39424231394A + 313142427B5273BD526BB531429429297B4A52945A6BAD637BBD738CCE6B7BBD + 8CADE75A5A8C525A947384C64A529431317B31316B31296B31316B31296B2929 + 5A29215A39315A31315A29215A31296B5A63A56B84C68494CE39315A21297B9C + ADEF9CADEF849CDE5A73BD39398C31294A29294A21102931294231396B39397B + 39397331316B31315A29215A29214A2921422921392918292110182110182118 + 21291829180829524A6B39315221103121102921101821101821101821102929 + 18291810213929315A424A52424A52424A4A394252424A52424A4A394252424A + 52424A52424A5A424A52424A524A525A424A52424A52424A5A424A5A424A5A42 + 4A52424A52424A52424A4A394252424A52424A4A39424A394252424A5A424A4A + 394252424A4A39425A424A4A394252424A4A394252424A4A394252424A4A3942 + 52424A52424A52424A4A3139FFFFFF0000003929293929293929293118214229 + 3139292939292931182139292939292939292939292939292942293139293139 + 2929392929392929392929422931422931392929392931422931392929423131 + 3929314231314231314231313929314231394231394231314231394231394A39 + 424A39424A3139423131424A734A5AA56B84C66B84C64A5AA54A52945263A56B + 84C66B84C642427B7384BD5A639C4A4A845A6BB531396B39397B5263A57384BD + 7B7BAD5A639C525A9439317329215A29215A31315A29295A39397B6373B57384 + C6424A8431315A5263A58CADE77B94D65273BD31317B21103121102129182929 + 214239397342427B39397331296B31315A29295A31315A292142211031292139 + 291829211821211821211821211031393152524A6B3129422110102118212110 + 1821101821102921182121102129182952424A52424A4A394252424A4A394A52 + 424A52424A52424A4A39425A424A5A424A52424A5A424A524A525A424A52424A + 52424A52424A52424A52424A52424A5A424A52424A52424A52424A52424A5242 + 4A52424A4A39425A424A52424A4A394252424A52424A52424A52424A52424A4A + 394252424A4A39424A313952424A4A313952424AFFFFFF000000311821392929 + 3929293929293929293929293929293929293929294229313929293929294229 + 3142293139292942293142293139292939293139292939293139292942293139 + 2929422931423131422931423131392929423131422931423139423131423139 + 4A31394A31394A31394A39424A3942423131424A733142946B84C66B84C64A52 + 944A52945A6BAD5A73BD39315A31316B4A5AA5526BB5424A73424A8439397B63 + 73B5949CCE8C84AD31294221102942395A5A639C42427B29295A31315A31316B + 31316B5263AD6B6B9C4A5A9C7B94D629294A7B73B56B7BBD31396B1808102110 + 0829214A31315A21103142427B42427B42427B39397B31296B21185A31315A39 + 397339315A29214A29182921182121182121182121182139315242426B292142 + 21101821101821101821182121102921101821101821102952424A4A39425242 + 4A52424A4A394252424A4A394252424A52424A52424A52424A52424A5A424A52 + 424A52424A5A424A52424A52424A5A424A52424A5A424A52424A52424A4A3942 + 4A394252424A52424A4A39425A424A52424A4A39425A424A52424A4A39424A39 + 4252424A4A313952424A4A39424A394252424A52424A52424A4A3942FFFFFF00 + 0000392929392929392929392929392929392929392929392929392929392929 + 3929293929293929293929294229313929293929313929293929293929313929 + 2942313139293142313139293142313142313142313942293142313142313942 + 31314231394231394A31394231394A39424A31394231394A313939315A21185A + 21296B42529C4A4A845A639C5263AD39315A21296B42529C5263AD5A73BD4A4A + 8439315229294A5A639C8C8CBD423139000000180810100000393152525A9431 + 315A21103139295229214A6B7BBD31294A6B7BBD7B94D68494D6A5B5EF9CADE7 + 5A639C29214A31214A31315A29295A4231394A4A84525A945A5A8C5A528C424A + 846B6BA56B6B8C39315239315239315A31294A21102921101021101821101842 + 4A73292139291829211821211018211018211821211018181021211021211029 + 52424A52424A4A394252424A52424A52424A52424A4A394252424A52424A5A42 + 4A52424A52424A52424A52424A52424A52424A52424A5A424A52424A52424A52 + 424A52424A52424A52424A4A394252424A52424A4A394252424A4A394252424A + 4A394252424A52424A52424A52424A4A394252424A52424A4A313952424A4A31 + 394A3942FFFFFF00000031182139292939292939292939292931182139292939 + 2929392929392929392929392929311829392929392929422931392931392929 + 3929313929294229313929313929294229314231313929294229314231314231 + 314231314231394231394231314231314231394A31394A31394A31394A31394A + 39424A5294424A8439397B39315A42426B5263A521184A42426B526BB55273BD + 526BB54A63A542529C4A425A31294218081042314A3118213929311808081000 + 0018081021103121101821102129214A39397B3931525A52848C9CDE738CCE8C + 9CDE8CADE77B94D65A73BD31316B29214A31294A31316B42426B42314A31296B + 4A4A847B7BAD8494CE8C84AD29182910000818080831183142395A3129421808 + 1018080831294A31397B21102929182921182131183118081021102121101821 + 102118102129182952424A52424A4A39424A39424A39424A394252424A52424A + 52424A5A424A5A424A5A424A52424A5A424A5A424A52424A52424A52424A5242 + 4A52424A5A424A52424A52424A52424A52424A52424A4A394252424A52424A4A + 394252424A4A394252424A4A394252424A4A394252424A4A39424A394252424A + 52424A4A313952424A52424AFFFFFF0000003929293929293929293929293929 + 2939292939292939292939292939292939292939292939292939292939293139 + 2929422931392931422931392929422931392929423131423131423131422931 + 4231314231314229314231394231314231314231394A31394231314A31394231 + 394A31394A31394A39424A5A9C5263AD42426B211010291829292142424A8463 + 7BBD5A6BB5526BB54A63A54252A54A5AA54A63A56B638C42395A181021211031 + 31183118102129182929214231294A31315A31315A31315A29182929295A5A6B + B56B7BBD6B84C6738CCE94A5DE738CCE4A5AA521184A29182929214A39397342 + 427B5A52844A425A2918292921396B6B8C5A525A100000211010181008180810 + 2929392118211810212118212929392110292918292110312118212110182110 + 182110182118212110181808104A31395A424A4A394252424A52424A52424A52 + 424A52424A4A394252424A52424A52424A52424A5A424A52424A52424A52424A + 5A424A52424A52424A52424A4A394252424A52424A52424A52424A4A39425242 + 4A52424A4A39425A424A52424A52424A4A394252424A4A394252424A4A39424A + 394252424A4A39424A394252424A52424A4A3139FFFFFF000000311821392929 + 3929293929293929293929293929293118213929293929293929293118294229 + 3139292939292939292942293139292939292942293139293142313142313142 + 2931392929423131422931392931423131423131423131422931423139423131 + 4A31394231394231394231394A31394A31314A394A39315A2110212110101000 + 003939735263AD5263AD5263AD5263AD4A63A53142943942845A6BB56B7BBD73 + 73A55A5284424A7331294239317331183931294A292139211031211029211031 + 31296B39398C3942945263AD5273BD7B94D67B94D66B84C642529C2110312918 + 2929293931294A393173424A735A528C5A5A8C31315A21214A39315231294221 + 1821180810211021180810181008211018211018211010211821292139211821 + 21182118102121101821101818081021101818081052424A52424A4A39425242 + 4A52424A52424A4A39424A394252424A5A424A5A424A5A424A52424A52424A52 + 424A52424A52424A52424A52424A52424A52424A52424A52424A4A394A52424A + 52424A52424A4A39424A39425A424A4A39424A39425A424A4A394252424A4A39 + 4252424A52424A4A31394A39424A394252424A52424A4A313952424AFFFFFF00 + 0000392929392929392929422931311821392929392929392929392929392929 + 3929293929294229313929313929294229313929293929313929294229313929 + 2942313139293142313142293142313142313142293142313142293142313142 + 31314231394231394231314231394A31394A31394231394A3942392929211010 + 2110101810212110214A5294525A945263AD526BB5526BB54252A542529C3139 + 8C4A5A9C7384BD7384BD7384BD6B7BBD6B6BA55A639C42427B31315A31296B39 + 397B39428439428431317B394284424A8C394294526BB57B94D67B8CCE6373B5 + 42529C29214A21182121102921103129214A31296B424A734A4A84525A944A5A + A54A63A54A63A54A63A539428431315A21182121102921182121182121182121 + 182121182121182121182121101818081021101021101018081018102152424A + 52424A52424A5A424A4A394252424A52424A5A424A4A394252424A5A424A5A42 + 4A5A424A52424A52424A5A424A52424A52424A52424A52424A52424A52424A52 + 424A52424A52424A52424A52424A52424A52424A52424A52424A52424A4A3942 + 52424A52424A52424A5A424A4A394252424A4A39424A39424A313952424A5242 + 4A4A3139FFFFFF00000031182139292931182139292939292939292931182139 + 2929392929392929392929392929392929392929392929422931392929392929 + 3929313929293929314229313929294229314231314229314231314231314231 + 314231394231314231394231314A31394A31394231394231394A31394231394A + 3942392929180810211018210808312942424A8C4A52945A6BAD526BB55273BD + 526BB5526BB54252A531429439428C7384BD8494CE7B8CCE7384BD6B7BBD5A6B + B54A5AA54A5AA54A5A9C42529C39428439428439428C31397B314294526BB56B + 84C65A73BD5263A542529C31296B21102921182129182929213929295A393173 + 42427B4A4A844A4A844A4A845A528442427B39315A31315A29294A3129422118 + 2121182121101829213921102921102921101821102121101018100818081010 + 00083929315A424A52424A52424A52424A52424A52424A4A394252424A52424A + 52424A52424A52424A5A424A52424A52424A52424A5A4A5252424A52424A5242 + 4A52424A52424A52424A4A394A52424A52424A5A424A4A394252424A4A394252 + 424A52424A52424A4A313952424A4A394252424A4A394252424A52424A4A3942 + 52424A4A31395A424A4A3942FFFFFF0000003929293929293929293929293929 + 2939292939292939292939292939292942293139292939292939292942293139 + 2929422931392931392929422931392929392929422931423131422931423131 + 4231313929314231314231314231394231394231394231314231394A31394A31 + 394A31394A39424A3139291829180810211018211008312942424A8C42529C4A + 5AA54A63A5526BB55273BD5273BD526BB54A63A539429429297B424A8C6B6BA5 + 6B84C6637BBD6373B55A6BAD4A5AA542529C31317B39398C39428C3942843942 + 8442529C526BB5526BB54A63A542529C39428C31396B29214A21102921102921 + 102929214229295A393173393973424A844A52944A52944A4A8442427B31316B + 31294A2110312921392110182110292918292918292118212118212110182110 + 101808101808082918295A424A52424A52424A52424A52424A52424A52424A52 + 424A52424A52424A5A424A5A424A52424A5A424A52424A5A424A52424A52424A + 52424A5A424A52424A52424A52424A52424A5A424A52424A52424A4A394A5242 + 4A52424A52424A52424A5A424A52424A52424A52424A52424A4A394252424A4A + 394252424A4A394252424A4A31394A31394A3942FFFFFF000000392929392929 + 3929293118213929293118213929293929293929294229314229313929293929 + 2942293142293139292939293139292942313139293142313142293142313142 + 3131423131422931423131422931392931423139423139392931423131423139 + 4A31394A31394A31394A39424A39423118291808082110182110181808083129 + 4A424A844A52945263A55263A54A5A9C4A63A55A73BD637BBD5A73BD526BB54A + 63A531397B21186B31317B424A8C4A5AA54252A542529C39428439397B31397B + 31398C39428C42529C4A5A9C4A63A54A5AA542529C42529C39429431398C3131 + 5A29213921082121102929293929213929294A31316B39397B424A8C4A4A8442 + 4A8C42427B39397331315A292142211029211029291829211029291829211821 + 2110182110182110102110102110081808104A39425A424A52424A52424A5242 + 4A52424A52424A52424A52424A52424A52424A52424A5A424A5A424A5A424A52 + 424A52424A52424A5A424A52424A52424A5A424A5A424A52424A52424A52424A + 52424A52424A52424A52424A52424A52424A52424A5A424A52424A52424A5242 + 4A4A39424A394252424A4A394252424A4A31395A424A52424A52424AFFFFFF00 + 0000392929392929392929392929392929392929422931392929392929422931 + 3929293929293929293929293929294229314229313929313929294231313929 + 3139292942313139293139293142313142313142313142313142313942313142 + 31394231394231314231394A31394A31394A3139423131180810211018211018 + 21101018080831294A42427B424A8C525A945263AD4A5A9C4A63A5637BBD6B84 + C66B84C66B84C65A73BD5263AD39429431296B31296B31317B31397B31397B31 + 317B31397B39428439428C42529C39428C42529C4A5AA542529C4252A5424A8C + 39428C39428C31397B31296B29213921102921102921102929213929214A2929 + 5A31316B39397339397339317329295A29214221103129213929213929213929 + 213929182921101821102121101818081018080818081018080831182952424A + 52424A52424A52424A52424A52424A52424A52424A52424A52424A5A4A525242 + 4A5A424A52424A52424A52424A5A424A52424A52424A5A424A5A424A4A394252 + 424A52424A4A394252424A5A424A4A394252424A52424A5A424A52424A52424A + 5A424A4A313952424A52424A52424A52424A4A394252424A52424A4A39424A39 + 424A3942FFFFFF00000039292939292939292942293139292939292939292939 + 2929392929392929392929392929392929392931392931392931392929422931 + 3929313929294229313929313929294231314231313929314229314231314231 + 314231394231394231314231394231394A313142313952424A4A394231182921 + 101021101018081021101821080831315A39397B424A844A4A84525A945263A5 + 4A63A55A6BB55A6BB5637BBD738CCE738CCE6B84C65A6BB542529C3942843139 + 7B31317B39397B31397B39428439428C39428C394284424A8C39429442529C4A + 63A54A5AA5424A8C42529C424A8C39428C31397B31315A29214A211031211031 + 21182121102929213929213921184A29214A29214A29214229214A29214A3121 + 4A29213929213929182929182921182121101821101018102121100818081018 + 08101810084A313952424A52424A4A394A52424A52424A52424A4A394A52424A + 52424A5A424A52424A5A424A5A424A5A424A52424A5A424A52424A5A424A5242 + 4A52424A52424A52424A52424A52424A5A424A4A394252424A4A394252424A52 + 424A52424A4A394252424A52424A4A313952424A4A394252424A52424A4A3139 + 52424A52424A4A39424A3942FFFFFF0000003118213929293118213929293118 + 2139292939292939292939292939292939292939292939293139292939292939 + 2929392931422931392929392931422931392929423131422931392931423131 + 4231313929314231313929314A31394A31394A31394A31394A31394A31394A31 + 3942313121101821101018081021101821101021101031315A39397B42317B42 + 529C4A5A9C5263A55263A5424A8C4A52945263A5637BBD738CCE6B84C6637BBD + 5A6BB54A63A542529C39428C39428C39428431397B31316B39397339397B3942 + 8C4A5A9C5263A55263AD5263AD4252A54A63A54A5A9C39428C424A8C31316B31 + 214A29214A29213921103121102921102921103129214229294A31294A31315A + 29215A29215A29294A31214A2929392918292110182110182110181810211808 + 1018081021101018080818080839293152424A52424A52424A52424A52424A52 + 424A52424A52424A5A424A5A424A5A424A52424A5A424A5A4A4A5A424A52424A + 5A424A5A424A5A424A52424A52424A52424A52424A52424A4A394A52424A5242 + 4A52424A52424A52424A5A424A52424A4A394252424A52424A52424A52424A52 + 424A4A313952424A52424A4A313952424A52424AFFFFFF000000392929392929 + 3929293929293929293929293929293929293929293929293929293929293929 + 2939292939293139293142293139292939293142293139292942313139293142 + 31314229313929314231314229314A31314A3139423139392931311829311821 + 2110182110101808101808102110181808101808101808101808101810082921 + 4239397B39397B424A844A5A9C4A5AA55263A5424A734A4A844A52945263A54A + 5AA54A63A55A6BB54A63A54A5294424A8439428431396B31315A29214A393173 + 31316B39397B4A5A9C4A5A9C5263AD5263AD5A6BAD5263A55263AD5263A54252 + 9C4A5294424A8429294A29213929213921103129293929213929213929214A29 + 214A31296B29295A31296B31315A29294A292139211821211018211018211821 + 21101821101021101018081018081021101010000029182952424A52424A5242 + 4A52424A52424A52424A52424A52424A52424A5A424A5A424A5A4A525A424A5A + 424A5A424A52424A5A424A52424A52424A5A424A52424A4A394A52424A52424A + 52424A52424A4A394A52424A4A39425A424A4A394252424A52424A5A424A5242 + 4A52424A4A39425A424A52424A52424A4A313952424A4A39424A3942FFFFFF00 + 0000392929392929392929392929392929392929392929392929392929422931 + 3929293929294229313929293929313929293929294231313929314231313929 + 2942313142313139292942293142313142313142313139292929182918081018 + 0808180808180808180810180810211010211010211010211010211018211018 + 21101018080829213931315A31316B394284424A844A52945A6BAD5263A5424A + 734A4A8431294A29214231294A29214221102121182131315A39315A31294231 + 183931294A42426B393973424A845263A55263AD5A6BB55A6BB55A6BB55263AD + 5A6BAD5A6BAD525A94636BAD4A4A843939732110312118212918292918292918 + 2921102929213929294A31315A31315A31294A29294A29213921101818102121 + 1018211018211018211018181021211010180810180810181008180810100008 + 4A31394A39425A424A52424A52424A5A424A4A394252424A5A424A5A424A5242 + 4A5A424A5A424A5A4A5252424A52424A5A424A52424A52424A52424A5A424A5A + 424A52424A4A394252424A52424A52424A52424A52424A52424A52424A5A424A + 4A394252424A52424A52424A52424A52424A52424A52424A52424A52424A4A39 + 424A3942FFFFFF00000039292931182142293131182139292939292939292939 + 2929392929392929392929392929422931392929392929392931392929392929 + 4231313929314229313929294231314231314231314231313929312918291808 + 1018080821101018080821101018081021100821101021100821101018081021 + 101821101821101021101818081021182129214231296B393173394284424A8C + 5A6BAD5A6BAD5A639C3931523929313929313118213118293931523118392110 + 18312942291829292139424A73424A734A52945A63A55A6BAD5A6BB56373B563 + 73B56373B55A6BAD5263A55A6BAD5263A55A63A5525A9442426B393152292139 + 29182921182121101829182918081021101829213929214A2918292118212110 + 1821101018081021101821101821101821101818081018081018100818081018 + 08101808102108084A39425A4A525A424A5A424A52424A52424A52424A52424A + 52424A52424A52424A5A424A5A424A52424A5A424A52424A52424A5A424A5242 + 4A52424A52424A52424A52424A5A424A52424A5A424A4A394252424A52424A4A + 39425A424A4A394252424A4A39424A394252424A52424A5A4A4A4A39424A3942 + 52424A4A394252424A4A3942FFFFFF0000003929293929293929293929293929 + 2939292939292939292939292939292939292939292939292942293142293139 + 2929392929422931392929423131392929423131392931423131392931311831 + 1810212110181808102110101808102110101810212110081808101808101808 + 1018081021100821101821101821101821182121101818081021182131214A31 + 315A31316B424A8C525A946373B56B7BBD6B6B9C424A735A52735A5273424A73 + 5A52734A425A4A425A39315242395A424A735A5284525A946B6BA56B7BBD6B7B + BD7384BD6B73BD6373B55A639C5263A55263A55A63A55263A55263A55263A54A + 529431315A311839291829291829211018211018181021180808180808181008 + 2110101808101810081808102110101810212110181808102110102110102110 + 101808102110082110102110082110102918294231394A39424A39425A4A525A + 4A4A5A4A4A52424A5A424A52424A5A424A5A4A525A424A52424A5A424A5A424A + 52424A5A424A52424A52424A52424A52424A52424A4A39425A424A4A39425242 + 4A52424A52424A52424A4A394252424A52424A52424A5A424A4A31395A424A4A + 394252424A52424A52424A4A31395A424A52424AFFFFFF000000392929392929 + 3929293929293929293118213929293929293929293929294229314229314229 + 3139292939293139292942293139293142293139293142313142313139292942 + 313931294A211821211821211018211821211018211018211018211010180810 + 2110102110102110102110102110102110102110182110102110182110101808 + 0818080818081029182931294A393973424A84525A94636BAD6373B56B7BBD73 + 84BD6B7BBD636BAD636BAD6373B56B7BBD7384BD6B7BBD7384BD7B8CCE7384BD + 6B7BBD7384BD7384C67384BD6B7BBD6B7BBD636BAD5A63A55263A55263A5525A + 943942944A5AA5525A944A4A8431315A31294A31183921182121101818080818 + 0810181021180810180808180810180810211018211821211018211010211018 + 1808101808101808101810081808101808101808101810081808081000001000 + 0021101021101831182942313952424A5A4A4A5A4A525A424A5A424A52424A52 + 424A52424A52424A52424A5A424A52424A52424A5A424A52424A4A394252424A + 4A39425A424A52424A52424A4A394A52424A4A394252424A4A313952424A4A39 + 4252424A4A394252424A52424A5A424A52424A52424A4A39424A3942FFFFFF00 + 0000311821392929311821392929311821392929392929392929392929392929 + 3929293929293929294229314231314231313929293929294231313929314231 + 3139293142313142313931315A18102121101821102921182121182121182121 + 1018211018211018180810211018211018211010211018180810211010211010 + 18081018081021101018081018080818100818081021102129214231315A424A + 84525A94525A945A6BAD5A6BB55A73BD5A6BB5526BB5526BB55273BD637BBD6B + 84C66B7BBD6373B56373B56B7BBD6B84C67384BD6B7BBD635AA57384BD5A63A5 + 5263A54A529442529C394294424A8C424A8C4A5AA5525A94424A8439397B3931 + 5A31315A29213921182121101821102121101021101021101821102921101818 + 1021180810180810180810180810211008180810180810211008180808180810 + 1808101810081808101808081808081808081000001808082918294A39425A4A + 4A524A525A424A52424A52424A52424A52424A4A394A5A424A52424A52424A4A + 39425A424A52424A52424A52424A52424A52424A52424A4A394252424A4A3942 + 52424A4A394252424A5A424A4A394252424A52424A52424A4A31394A39425242 + 4A4A3942FFFFFF00000039292939292939292939292939292939292939292939 + 2929392929392929392929392929422931392929392929392931423131423131 + 39293142313139292942313139292942313142314A31396B2110292110182118 + 2121182129182921182121182121101821101821101821101829182921101821 + 1018181021211010181021211010180810180810211010180810180810180808 + 21080810000018081021102929213929214A29214A31296B39397B31317B3942 + 8439428C39429442529C4A52944A5A9C5263A55263AD5263A55263AD5263A552 + 63A55263A54A5A9C4A529439428C39428439397B31316B39397B394284394284 + 39428431316B31316B31316B31315A2921422921392110292118212118212110 + 2121101018081021101018081018080821101018100818081018080818081018 + 0810181008211008180810211010180810211010211008211018211010180810 + 1808081808082918294A39425A4A525A424A52424A52424A52424A52424A5242 + 4A52424A52424A52424A4A39424A39425A424A52424A5A424A52424A5A424A52 + 424A52424A52424A5A424A4A39425A424A4A394252424A52424A4A313952424A + 52424A52424A4A313952424AFFFFFF0000003118213929293929293929293118 + 2139292939292939292939292939292939292942293139292942293142293139 + 29293929293929313929294229313929314229313929293929314229314A3942 + 31315A2921422118212110182110292118212118212918292118212118212110 + 1821101821101821101821101821101821101821101818102121101821101818 + 0810180810211010180810180810211010180808180808100000100000100000 + 18080821101018081021102921103121103121184A29214229214A29214A3131 + 5A31296B31315A31315A29215A31315A29215A31294A29214A29214A29214229 + 214A29214229214A29214A292139211031211029211029211029211821211018 + 1808101808101810081808101808101810081808101810081808101808101810 + 0821101018081018100818081018081018080818081021101018081021101021 + 101018081021101021101021101018080818080831182152424A5A424A52424A + 5A424A52424A4A394252424A4A39425A424A52424A52424A4A39425A424A4A39 + 425A424A4A39424A394252424A4A31394A394252424A4A394252424A52424A4A + 31394A394252424A4A394252424A52424A4A3942FFFFFF000000392929392929 + 3929293929293929293929293929293929293929293929293929294229313929 + 2939292939292939293142293139292939293139293142293139292942293142 + 313142313142313142313142395A29294A211031211018211018211029211821 + 2118212118212110292118212918292110182110182110182110182110182110 + 1821182121101818102121101818102118102121101018081018081018102118 + 0810181021211010180810180810211010181008181008180808180808180808 + 1808081000001808081808081808081808081808081808081808081808081808 + 0818100818080818100818100818100821101018080818100818080818080818 + 1008181008181008180810180810180810211010181008180810211010180810 + 1808102110081808101808102110081808101808101810082110101808101808 + 0818081018102121080818081021101021101821101021101021101008000842 + 31315A424A5A424A52424A52424A52424A52424A52424A4A394252424A4A3139 + 5A424A52424A52424A4A394252424A52424A52424A52424A52424A52424A5242 + 4A52424A4A313952424A52424A4A313952424A4A313952424A4A3942FFFFFF00 + 0000392929392929392929392929392929422931422931392929392929392929 + 3929293929294229314229313929294229314229313929294229314229313929 + 294231314231313929313929314231314231314229314A394239315231315A29 + 2139211018211018211821211029291829211821211821211821211821211018 + 1810212110182118212110182110182110181810212110182110182110181810 + 2121102118081021101818102121101818081021101018102121101821101821 + 1018211018181021211018181021211021180810211018181021211010180810 + 1810211808101808102110101810212110181808101808101808102110181808 + 1018081021101018081018081018081021100818081018081018081018081018 + 0810181008180810181008180810180810180808180810180810180808180810 + 1808101808082110102110101808082110101808102110101808102108082110 + 101000003118295A424A52424A5A424A4A39425A424A4A39425A424A4A394252 + 424A5A424A4A394252424A4A394252424A52424A52424A4A313952424A4A3139 + 52424A52424A4A313952424A52424A4A394252424A52424A52424A52424A4A39 + 4252424AFFFFFF00000031182139292942293131182139292931182139292939 + 2929392929422931392929422931392929392929392931422931392931392929 + 3929313929314231313929314231314229314231314229314231314231314231 + 3142313142314A39315A29294A21214A21102121182121182129182929182921 + 1821291829291829291829291829211821211821211821211018211018181021 + 2110182110182110181808102110181808102110101808101810212110182110 + 1818102121101821102121101821101818102121101818081021101018102121 + 1021180810211018211010211010180810211010180810180810180810211018 + 1808101808101808101810081808101808101810081808101808101808102110 + 1021101018100818081018081021100818081018100818081021101018080818 + 0810211010181008211010180810180810211008180810180810211010211010 + 2110101808081810084229315A424A5A424A52424A5A424A52424A52424A5242 + 4A4A39425A424A4A394252424A4A394252424A5A424A4A313952424A52424A52 + 424A52424A52424A4A313952424A52424A4A313952424A52424A4A313952424A + 4A313952424A4A39424A3942FFFFFF0000003929293929293929293929293929 + 2939292939292939292939292939292939292939292939292939293142293139 + 2929422931423131392929392931423131423131392931423131423139423131 + 4231314229314231394231394231314A31314A394239315242426321214A2110 + 3121101821182121182121182129182929182921182129182929182921182121 + 1821211821211821211018211018181021211018181021211018211018211010 + 2110101808102110182110182110181808102110182110182110181810212110 + 1818102121101018081021102118081018081018102121101018102118081021 + 1010180810180810180810180810211010180810181008181021180810180810 + 1808101808101808101808101808101810081808101808101810081808101808 + 1018100818081018100818081018081018080818081018080818081021100821 + 10101808081808081000003118294A39425A4A5252424A52424A5A424A52424A + 52424A52424A52424A52424A4A394252424A4A39424A394252424A4A39425242 + 4A4A394252424A4A313952424A4A394252424A4A394252424A52424A5A424A4A + 31394A394252424A52424A4A394252424A52424AFFFFFF000000392929311821 + 3929293929293929293929293929293929293929293929293929293929293929 + 2942293139292939293139292939292942293139292942313139292942313142 + 2931423131392931423139423139423139423131423139423131423131423131 + 4A31394A425A42426331396B29294A2918292110212110182110292918292918 + 2929182921182129182929182921182121182121182121101821101821101821 + 1018181021181021181021211018180810181021211018211018181021211018 + 2110182110181808102110181810212110101808102110181810211808101808 + 1018081018081018102118081018081021101018102118081018081018081018 + 0810211010180810211010180810180810211008180810211010180810181008 + 1808102110101810081808102110101808101810081808102110101808082110 + 102110101808081000001808083118294A39425A4A525A424A5A424A52424A52 + 424A5A424A52424A52424A52424A4A394252424A4A394252424A52424A52424A + 4A394252424A52424A52424A52424A52424A4A394252424A52424A4A39425242 + 4A52424A5A424A52424A52424A52424A4A31395A424A5A424A4A3942FFFFFF00 + 0000392929392929392929422931392929392929392929392929392929392929 + 3929293929293929293929314229313929294229314231313929314231313929 + 3142313942293142313942313142313142293142313142313142313942313142 + 31394231394A31394A31314A31314A313952424A4A425A42426331315A31294A + 2110312110212118212918292918292918292110293929292918292118212118 + 2118102118102121101821182121101821101821101821101821101818102118 + 1021211018211018211018181021211018211018211018181021211018180810 + 2110101808101810212110182110181808101808102110101808102110181808 + 1018081021101818081018100821101818081018100818081018081018080818 + 0810181008180810180810180808180810181008180810211008180810181008 + 1808101810081000001000002110183929314A39425A4A525A424A52424A5242 + 4A52424A52424A52424A52424A5A424A52424A52424A52424A52424A52424A4A + 394252424A4A313952424A52424A4A313952424A4A313952424A4A394252424A + 52424A52424A5A424A5A424A4A394252424A4A31395A424A4A39424A39424A39 + 4252424AFFFFFF00000039292939292931182139292939292939292939292939 + 2929392929392929392929422931392929392929392929423131392929392931 + 4231314231314231394229314231314231314229314231314231314229314229 + 314231394231394A31314231394231314231394231314231394A31394A313939 + 292921102931294A42426B42426329294A211031211018211821291829211821 + 2918292918292918292118212110211810212110212110211810211810212118 + 2121182121101821101821101821182121101818102121101818102121101821 + 1018180810211010181021211018180810180810180810181021211010180810 + 1808102110102110102110101808101808101808101810081808101808102110 + 1018100821101018081018081018100818081021101018081018081018081018 + 08081810081808081000082110183118294A313952424A5A424A5A424A4A3942 + 52424A5A424A52424A52424A52424A52424A52424A52424A52424A52424A4A39 + 4252424A4A39425A424A52424A52424A4A394252424A52424A52424A52424A52 + 424A4A394252424A52424A52424A4A394252424A4A394252424A52424A4A3942 + 52424A5A424A4A394252424AFFFFFF0000003929293929293929293929293929 + 2939292939292939292939292939292939292939292939293142293142293139 + 2931422931423131392929392931423131423131423131423131423131423131 + 4231314231394231394229314231314231394231314231394231394A31394A31 + 394A31394A394239293110000010000021080829213931294A42426B31396B31 + 294A292939292939291829211018211018211821211821211821211821181021 + 2110182110182110182110182118212118212918292118212110182110181810 + 2121101821101818102121101818102118081021101018081021101018102121 + 1010211018181021211010180810181021211010180810180810211010180810 + 1808102110101810081808101810081808081808081808101810081808081808 + 1021101018081021101829182918102142313952424A52424A52424A4A39424A + 39424A39424A39425A424A4A39425A424A52424A52424A52424A5A424A52424A + 52424A5A424A5A424A4A394252424A4A39425A424A4A31395A424A52424A4A31 + 395A424A52424A4A313952424A52424A52424A4A313952424A52424A4A39424A + 31394A394252424A4A31394A39424A394252424AFFFFFF000000392929311821 + 3929294229314229313929293929293929293929293929294229314229313929 + 2939293142293139292942293139293142313142313142313139293142313142 + 29314231314229314231314229314231314231394231314231314231394A3131 + 4231314A31394A31394A31394A39423929311810082110182110102110082110 + 0829182939292931294239315A39315A31396B31315A29214229213921102921 + 1021211018211018181021211018211018181021211018211821291829211018 + 2118212110182110182110181810212110182110181808102110181810212110 + 1018102118081018081018081018081021101018081021101018081018081018 + 0810181008180810181008181008180810180810211010181021211018211018 + 2110182118212118212110212918292110181808101808084A394252424A4A39 + 424A394252424A52424A52424A5A424A52424A52424A52424A5A424A52424A52 + 424A5A424A52424A52424A4A39424A39424A39425A424A4A39424A394252424A + 4A39425A424A4A394252424A4A313952424A4A394252424A4A394252424A4A39 + 4252424A4A313952424A52424A4A313952424A4A394252424A52424AFFFFFF00 + 0000392929422931311821392929392929392929422931392929392929422931 + 3929294229313929294229313929314231313929294231313929294229314231 + 3142313142313142313142313142313142313142313142313142313942313942 + 31394231314231394231394231394A31394231394A31394A3139180810181008 + 2110182110182110102110103118213118212110102918293929294A39424239 + 5A31315A39315A31294A31315A29294A29293921103121102929182921182121 + 1821291829211018211018180810211010211010180810180810181008180810 + 1808081808101808101808102110182110182110182110182110182118212110 + 1821101821182121101821182121102921102929213921102921103121102921 + 1821211821181021211021180810211010181008181008180808180810100000 + 4A39424A394252424A52424A4A394252424A4A31395A424A4A39425A424A5242 + 4A5A424A52424A52424A52424A52424A5A424A5A424A52424A4A394252424A4A + 394252424A4A394252424A4A394252424A52424A52424A4A39424A394252424A + 4A39424A39424A39424A394252424A4A313152424A4A313952424A4A31394A39 + 424A3942FFFFFF00000039292939292939292939292942293139292942293139 + 2929392929392929392929392929422931392931392929392931423131392931 + 4231314231313929314229314231314229314231314231314231314A31394231 + 314231314231394231314231394231314231394A31394A31394A31394A31394A + 3139180810181008211010211010291829211010311821311821311821311821 + 29182931182939292939292939292931294242313939315242395A42395A4239 + 5A39315239315231294A39315239315231294A31315A29294A31294A31294229 + 2142292142392931292139292939292139292939292142292139312942312942 + 2918292921392918292110292110292118212110212110181808211808102110 + 1018081018080818080821100818080818100818100818081018081018080821 + 10101000002918295A424A52424A4A313952424A52424A4A313952424A52424A + 52424A5A424A5A424A52424A52424A5A424A5A424A5A424A4A39424A39424A39 + 425A424A4A39424A394252424A4A39424A31394A39424A31394A313952424A4A + 394252424A4A313952424A4A394252424A4A313952424A52424A52424A4A3139 + 52424A52424A4A39424A3942FFFFFF0000003929293929293929293929294229 + 3139292939292939292939292942293139292939292942293139292942293142 + 2931392929423131392929423131423131423131423131423139423131423139 + 4231394231314231394231394231394231394231394231394A31394A31394A31 + 394A31394A31394A313921101018080818102121101021101829182931182129 + 1829291829311821392929392931392931392931392931392929311821392931 + 3929314231394231313118293929313929293929313929313929313929313118 + 2129182931182131182131182129182929182921101021101821101821101818 + 0810180808180810181008181008180808210808211008181008181008181008 + 1808081810081808101810082110101808101808101810081808101808101808 + 081808101808101808081808084A394252424A4A39425A424A4A394252424A52 + 424A5A424A4A31395A424A5A424A4A39425A424A5A424A52424A52424A5A424A + 5A424A5A424A5A424A52424A4A39424A394252424A4A394252424A52424A5242 + 4A52424A52424A52424A4A39424A394252424A4A39424A31394A313952424A4A + 313952424A4A313952424A4A313952424A4A3942FFFFFF000000392929392929 + 4229313929293929294229313929294229314229313929293929294229313929 + 2942293142293139292942313142293142293139293142313142293139293142 + 31314231394231314231314231394231314231394A3131423131423139423131 + 4A31394231394A31394A31394A31394A31392110102110082110102110102110 + 1829182929182931182139292929182939292931182142313939293131182939 + 29313929293929294231394A3942392931392931392929311829392931392931 + 3929313929293118213118213118213118213118212110102918292110102110 + 1021101021101821101021101018081021101818081021101818100818102118 + 0810180810180810211010181008180810180810181008180810180808180810 + 21101018080821101018081018080818080829182952424A4A394252424A4A39 + 424A39424A39424A39424A394252424A5A424A4A394252424A5A424A52424A4A + 39425A424A52424A4A39424A39424A39424A39424A39424A39424A39424A3942 + 52424A4A313952424A4A313952424A4A313952424A4A39424A39424A39425242 + 4A52424A52424A52424A4A313952424A5A424A52424A4A39424A3942FFFFFF00 + 0000392929422931392929422931392929422931392929422931392929392929 + 4229314229313929293929293929294229313929293929314231313929314231 + 314231314231314231314231394231394231314231394231314231394231394A + 31394231394231314A31394A31394A31394A31394A313152424A291829180808 + 2110102110182110102918293118213118213118213929292918293929293929 + 313929313929313929313929313929313929314A394239293131183139293139 + 2929311821392931392931392929311821311821291829311821291829211010 + 2918292918292110102110182110182110102110181808102110101808102110 + 1821101018100821101018081018081018100818081018081021100818081018 + 08102110101810081808101808101810081808102110101000004229315A4A52 + 4A39425A424A4A394252424A52424A52424A52424A52424A4A39425A424A5A42 + 4A4A39425A424A4A39425A424A4A39425A424A5A424A52424A4A39424A394252 + 424A52424A4A31394A394252424A4A313952424A52424A52424A4A39424A3942 + 5A424A4A313952424A4A31395A424A4A313952424A4A313952424A4A31395242 + 4A4A3942FFFFFF00000042293139292939292942293142293139292942293139 + 2929422931423131423131392931422931422931392929423131423131392929 + 4231314231313929314231314A31314231394231314231314231314231314231 + 394A31314231394231394A31394231394231314A31394A31394A31394A31394A + 3139291829211010211010211010211010311821311821291829392929311821 + 3118213118293929293929313929293929293929314231393929293929313929 + 3139293139292939292931182939293142313931182139292931182129182931 + 1821291829211010211018211018211010211018211018211010211010180810 + 2110181808101808101808101808101808101810082110101808101810081808 + 1018081018100818081018100818081021101018080818081018080818081010 + 00084A39425A424A4A39424A39424A39424A39424A31394A39424A313952424A + 4A39424A39425A424A5A424A4A394252424A4A39425A424A4A394252424A4A39 + 425A424A4A39424A313952424A5A424A4A39424A394252424A4A31395A424A4A + 313952424A4A39424A39424A39424A394252424A52424A52424A4A39424A3942 + 4A39425A424A4A39424A3942FFFFFF0000003929293929293929293929293929 + 2939292942293139292942293139292942293139292942313139293142313142 + 2931392929423131392931423131423131423131423139423139423131423139 + 4A31314231314A31394A31394231394231314A31394A31394A31394A31394A31 + 394A31394A394252424A31182121101021101829182929182929182931182131 + 1821392929291829311821392929311829392931392931392929392931392929 + 3118213929293929313929313118293118213929293929313929313929292918 + 2929182921101031182129182929182929182921101021101821101021101021 + 1018180810211010180810211010211010181008211010180810180810180810 + 1810081808102110082110101808102110081808101808101810081808102110 + 101808101808082110105A424A52424A52424A4A39424A39424A394252424A52 + 424A4A394252424A4A31395A424A4A394252424A52424A4A394252424A52424A + 4A39425A424A4A39425A424A4A39425A424A4A39424A39424A394252424A4A39 + 424A394252424A52424A4A39425A424A4A31394A39424A39424A39424A39424A + 31395A424A4A39424A39425A424A4A39424A3942FFFFFF000000392929392929 + 4229313929293929293929293929294229313929294229313929294229314229 + 313929294231313929314231314231313929294231314231314A313142313942 + 31314A31394A31314231394231394A31394231394A31394A31394231394A3139 + 4A31394A31394A31394A31394A313952424A3118211000002110102110102110 + 1021101029182931182139292929182931182139292929182939293139293129 + 1829311821392929392929311821392929392931392929311829392929392929 + 3929313118212918293929292918293118212918292110102110102110102110 + 1021101821101021101021101018081021101018081018081018102118081018 + 0810180810211008180810180810211010180810181008180810180810181008 + 18081021101018100818100810000031182952424A52424A4A394252424A4A39 + 424A394252424A4A39424A394252424A5A424A5A424A4A39425A424A52424A52 + 424A52424A5A424A5A424A52424A5A424A4A39424A39425A424A4A39424A3942 + 4A394252424A4A31395A424A52424A4A313952424A4A39424A39424A39425A42 + 4A4A39425A424A4A39424A39424A39424A39424A39424A31394A3942FFFFFF00 + 0000392929422931392929392929422931392929392929422931422931392929 + 4229313929294229314231313929294229313929294231314231314231314231 + 394231394A31314231394231394231394A31394A31314A31394231394A313142 + 31394A31394A31394A31314A31394A31394A31394A31394A313942395A211031 + 1808081810082918292918292918292918293929293929292918293929293929 + 2939292939293139292929213939292939292939292931183139293131182939 + 2929392929392931291829311821392929311821291829311821311821211010 + 2918292110182110102110102110182110102110182110101808102110082110 + 0821100821101021101018081021101021101018081018081021101018081018 + 081021100818081018100818081018081010000839293152424A52424A4A3942 + 52424A52424A4A39424A39424A394252424A52424A4A39424A39425A424A5A42 + 4A52424A52424A52424A5A424A4A39424A39425A424A4A394252424A4A394252 + 424A4A313952424A52424A4A394252424A4A313952424A52424A4A39424A3942 + 4A39424A39424A39424A39424A39424A394252424A4A313952424A4A39425A42 + 4A4A3942FFFFFF00000042293139292939292939292939292942293142293139 + 2929422931392929392929422931392929423131423131392929423131392931 + 4229314231314231314231394231394A31314231394A31314231394A31394231 + 314231394231394231394A31394A31394A31394231394A31394A31394A31394A + 3131524A5239428431315A211018211008211008291829311821392929392929 + 2918293929293929293929293929313929313929313929313118293929293929 + 3139292939292931182939292939292929182929182939292931182131182131 + 1821211010291829211018211018211010211018180810180810180810211010 + 1808101810211808101808101808102110102110181808102110102110182110 + 101808102110101810081808101808102110182110101000083118295A424A52 + 424A4A394252424A4A394252424A52424A52424A4A39424A394252424A5A424A + 4A39424A39425A424A5A424A5A424A4A39425A424A5A424A4A394252424A5A42 + 4A4A31395A424A4A31394A39424A39424A39424A39424A394252424A4A31395A + 424A4A394252424A4A31394A39424A39424A394252424A4A31394A39424A3942 + 4A31394A39424A39424A3942FFFFFF0000003929293929294229314229313929 + 293929294229314229313929294229314229313929294231314229313929294A + 31314229314229314231314231314231314231314231314231394A31314A3139 + 4231314231394A31394A31394A31394231394A31394231314A31394A31394A31 + 394A31394A31394A313142314A31397B39397B424A7331315A29293921101821 + 1010311821311821311821311821311821311821392931392929392931392929 + 3929293118213929314229313118213929293929292918293929293929292918 + 2929182931182131182129182921100821101021101821101021101021101021 + 1018211010180810211010211008211010180810211010180810211010211010 + 2110182110102110182110182110101810212110101808102110101808101808 + 0842313952424A52424A4A394252424A4A394252424A52424A4A394252424A52 + 424A4A394252424A52424A52424A4A39424A39425A424A5A424A4A39424A3942 + 5A424A4A39424A394252424A52424A52424A5A424A4A39424A394252424A5242 + 4A4A394252424A52424A4A394252424A52424A4A39424A39424A39424A39424A + 39424A394252424A4A39425A424A4A39424A3942FFFFFF000000392929392929 + 4229313929293929294229313929293929294229314229313929294231314229 + 314231314229313929294231314231314231313929314231313929314A313142 + 31314231394231394231314A31394231314231394231394A3131423139423131 + 4A31394231394231394A31394A39424A313942314A31396B31396B31396B3139 + 6B39397B39397331396B31294A31294231182129182931182131182131182139 + 2929392931392929311821392929311829423131392929392929392929392929 + 3929293118213929293929292918293118212918292110102918292110102110 + 1018102121101021101021101818081018081018102118100821101021101018 + 1021211010211010180810180810211018211010180810180810180810211010 + 1810081810212110104A394A52424A4A394252424A4A394252424A4A39425242 + 4A52424A52424A4A394252424A4A39425A424A5A424A5A424A52424A5A424A4A + 39425A424A52424A52424A4A39425A424A5A424A4A39424A39424A39424A3942 + 52424A52424A4A31394A313952424A4A313952424A4A39424A31394A31395242 + 4A4A39424A39424A39424A39424A39424A31394A39424A39424A3942FFFFFF00 + 0000392929422931392929392929422931392929392929422931422931392929 + 4229313929314231313929294231314231314231313929294231314231314231 + 3142313139293142313142313942313142313142313942313942313142313942 + 31394231394231394A31394231314A31394A31394A31394A31394A394231396B + 31396B424A7339397339397331396B31396B31396B31397B42426B31396B3131 + 5A31294A39315231294239292939292931182139292939292939292931182139 + 2929311821311821311821311821311821392929211010291829211010211010 + 2110102110102110102110101808101810081808101808102110081808101810 + 0818081018081021101018081021101018081021101021101821101821101821 + 101018102121101818081018100829182952424A52424A4A394252424A4A3942 + 52424A4A394252424A52424A4A394252424A52424A52424A4A394252424A5A4A + 525A4A525A424A524A5252424A52424A52424A5A424A4A39424A39425A424A4A + 39424A394252424A4A313952424A52424A52424A52424A4A39424A39424A3942 + 4A394252424A4A313952424A4A31394A39424A39424A39424A39424A39424A39 + 424A3942FFFFFF00000039292942293139292939292942293142293139292939 + 2929392929392929422931392929422931423131392931422931392929422931 + 4231313929314231314231314231314229314231314231394231314231314231 + 394A31394A31394231394A31314231394A31314A31394A31394A31394A31394A + 3139423139424A7339397331396B31396B31396B31396B42426B31396B31396B + 424A7339397B39397331396B31396B31396B42426B31396B39315A39315A3931 + 5239315239315231294231294231183129213939293131294239292929182929 + 1829291829211021211018291829211018181021211018211018211018211018 + 2110182110182110182110181808102110182118212110182110182118212110 + 182110182110182110182110182110181810211808103929315A424A52424A52 + 424A4A39424A39424A39424A394252424A4A394252424A4A394252424A52424A + 5A424A52424A52424A5A424A5A424A5A424A52424A52424A52424A52424A5A42 + 4A4A39425A424A5A424A4A394252424A4A39425A424A4A313952424A4A394252 + 424A5A424A52424A4A313952424A4A39424A394252424A4A394252424A4A3942 + 4A39424A31394A39424A3942FFFFFF0000003929293929293929294229313929 + 2939292939292942293142293139292942293139293139292942313142293139 + 2929423131423131392931423131423131422931423131423131423139423131 + 4A31394231394231314231394231394231314231394A31394A31394A31394A31 + 394A31394A31394A31394A313931396B31396B424A7331396B42426B31396B31 + 396B31396B31396B31396B31396B31396B31396B31396B31396B31396B31396B + 39397331396B31396B31396B31315A31315A29295A31315A31315A29294A3131 + 5A31315A31315A31294A29294A31294229214229214229214229213929182929 + 2139292139211029211029211029211029211821211821211821211821211821 + 2110182110182110182110182110181810212110182110182110181808104231 + 3952424A4A39424A394252424A52424A4A394252424A4A394252424A4A394252 + 424A4A394252424A52424A5A424A5A424A52424A52424A52424A52424A52424A + 52424A52424A52424A4A39424A39424A39425A424A4A394252424A4A39425242 + 4A52424A4A313952424A4A313952424A4A39424A313952424A4A31394A394252 + 424A4A31394A394252424A4A394252424A4A3942FFFFFF000000422931392929 + 4229313929294229313929293929294229313929293929294229313929294231 + 3142293142313139293142293139292942313142313142293142313142313142 + 31314229314231394A31394231314A31394A31394231314231394A31394A3139 + 4231394A31394A31394A39424A31394A31394A3139424263424A7331396B3139 + 6B31396B31396B31396B39397342426B31396B42426B424A7331396B42426B31 + 396B31396B31396B31396B31396B31315A31315A31396B31315A31315A31315A + 29294A31315A31294A31315A31294A3129422921392921392921392921392921 + 3929213929213929182921102929182929182929182921182121182121182121 + 1821211018211821211018211821211018211018211018211018211018181021 + 18081021101852424A4A394A4A394252424A52424A4A39424A394252424A4A39 + 4252424A4A394252424A52424A52424A52424A52424A52424A52424A52424A52 + 424A5A424A52424A52424A52424A5A424A4A39425A424A4A39424A39424A3942 + 52424A4A394252424A4A394252424A5A424A52424A4A39424A31394A39425242 + 4A4A394252424A4A394252424A4A39424A313952424A4A31394A3942FFFFFF00 + 0000392929392929392929392929392929422931392929392929422931422931 + 3929294229313929294231314231314231313929314229314231314231314231 + 3142313142313142293142313142313942313142313942313142313942313942 + 31314231394231394A31394A39424231394A313952424A4A39424A313142395A + 31397B31396B424A7331396B42426B31396B31396B31396B31396B3939733139 + 6B39397331396B42426B31396B42426B31396B39397331396B31315A39315A31 + 396B29295A31315A31315A31315A39315A39315231294A312942292142312942 + 2921422921392921392110312929392921392929392918292110292918292918 + 2921182121182121182121101821182121182121101821182121101821101821 + 101821101821101818081029182952424A52424A52424A4A39424A39424A3942 + 52424A4A39424A394252424A4A394252424A52424A52424A5A424A5A424A5242 + 4A5A424A5A424A52424A52424A52424A5A424A5A424A4A39425A424A4A39425A + 424A52424A4A39424A394252424A4A313952424A52424A4A313952424A4A3139 + 52424A4A39424A394252424A4A313952424A4A313952424A4A39424A39425242 + 4A4A3942FFFFFF00000039292942293139292942293142293139292939292939 + 2929422931392929422931423131422931392931423131423131423131423131 + 3929293929314229314231314231314231314231314231314231314A31394231 + 394231314231394231394A31314231394A31394231394A31394A31394A39424A + 31394A313142395A31397B39397B39397B39397331396B42426B31396B31396B + 42426B31396B424A7331396B31396B31396B31396B31396B39315A31396B4242 + 6B31396B31396B42426B42426B31315A29295A31315A31396B39315231315A31 + 294A312942292142292939292139292139292939211031292139291829292139 + 2918292118212118212118212110182110182118212118212110182110182110 + 1821101821101818102118102121101818081039293152424A52424A52424A4A + 394252424A4A394252424A4A394252424A4A394252424A5A424A4A394252424A + 5A424A5A424A5A424A5A424A52424A5A424A5A424A4A394252424A4A39425242 + 4A52424A4A39424A39424A313952424A4A394252424A52424A4A313952424A4A + 394252424A4A394252424A4A39424A394252424A4A394252424A4A39424A3139 + 52424A4A39424A31394A3942FFFFFF0000003929294229313929293929294229 + 3139292942293142293139292942313142293139292942313142313142313139 + 2931392929423131423131422931423131423131423131423131423139423131 + 4231394231394231314231394231314231394231394231394A31394A31394A31 + 394A39424A31394A39424A31394A3942424A7331396B31396B31396B31396B31 + 396B39397342426B31396B31396B393973424A7339397342426B31396B424263 + 31396B39397331396B39315A42426B31396B29295A39315A31315A39315A3931 + 5239315A31315A31294229213931214229214229214229293929213929182929 + 2939291829211821291829211821291829211821211821211821211821211018 + 2110182110182110182110182110182110182110182110181808104A31395242 + 4A52424A4A394252424A4A39424A394252424A4A394252424A4A394252424A4A + 394252424A5A424A4A39425A424A5A424A5A424A52424A52424A52424A52424A + 52424A52424A52424A52424A52424A52424A52424A4A394252424A4A39425242 + 4A52424A52424A52424A4A39424A39424A394252424A4A313952424A4A39424A + 394252424A52424A4A31394A394252424A4A3942FFFFFF000000392929422931 + 3929294229313929294229314229313929294231314229314231314229313929 + 2939292939293139292942313139293139293142313142313142313142313142 + 31394231314231394231394231314231394A31394231394231314231394A3139 + 4A31394A31394A39424A39424A39424A31394A31394A3139424A7331396B3939 + 73424A7331396B42426B31396B39397331396B42426B31396B31396B424A7331 + 396B31396B31396B39315A31396B39315A39315A31396B31294A31315A31315A + 31315A31294A31315A31294A31315A31315A29214229294A29294A2921422921 + 4229293921102929182921102929293929182929182921102921182121182121 + 1821211821211821291829211018291829211018211018211821211018211010 + 18102152424A52424A52424A4A39425A424A4A394252424A4A394252424A4A39 + 4252424A4A394252424A4A394252424A52424A52424A52424A52424A52424A52 + 424A52424A5A424A52424A4A39424A39425A424A5A424A4A39424A39424A3942 + 52424A5A424A52424A4A313952424A4A313952424A52424A4A313952424A5242 + 4A52424A4A394252424A4A39424A313952424A52424A4A31394A3942FFFFFF00 + 0000422931392929422931422931392929392929392929422931392929423131 + 3929314231314231314231314231314231314231314231314231313929314231 + 314229314231314231314231394231314231394231394231314231314231394A + 31394A31394231394A31394A31394A31394A31394A31394A39424A31394A3139 + 42426B31396B31396B424A7331396B39397331396B31396B39315A3939733139 + 6B42426B31396B424A7342426B31396B31396B39315A31396B31315A31315A31 + 294A31315A31315A31315A31315A31315A31315A31294A31294A31294231294A + 31294A3129422921422921422929392918292918292918292918292118212118 + 2129182921182121101821182121182121101821101821101821101821101821 + 101821101821101831182152424A52424A4A394252424A4A394252424A4A3942 + 52424A4A394252424A4A394252424A4A394252424A52424A5A424A5A424A5242 + 4A52424A52424A52424A52424A52424A52424A5A424A5A424A4A39424A394252 + 424A4A313952424A4A39424A313952424A52424A52424A52424A52424A52424A + 4A313952424A4A313952424A4A39424A313952424A52424A4A313952424A5242 + 4A4A3942FFFFFF00000042293139292939292942293142313142293142313142 + 3131422931423131423131423131392929392931392931423131392931422931 + 4231394231314231314231394231314231394231314231394231314A31394231 + 394231394231314231394A31394A31394A31394A31394A313952424A4A31394A + 39424A31394A313142395A424A7331396B31396B424A7331396B42426B31396B + 31396B31315A31396B39397339397331396B31396B42426B31396B31396B4242 + 6B31315A31294A31315A29294A31294A31315A29294A31315A29294A31294A29 + 294A31294A292142312942292142312142292939292139292139292139291829 + 2110292110292118212918292918292918292918292118212110182110182918 + 2921101821101821101821101818102142313952424A4A394A52424A52424A52 + 424A52424A4A394252424A4A394252424A52424A4A394252424A4A39424A3942 + 52424A5A424A52424A5A424A52424A52424A5A424A52424A52424A4A39425242 + 4A52424A52424A52424A52424A5A424A4A394252424A4A313952424A4A313952 + 424A4A313952424A52424A4A313952424A52424A52424A52424A4A313952424A + 52424A4A31394A39424A3942FFFFFF0000003929293929294229313929294231 + 3142293139292942313142313142313142313139292942293142313142293139 + 29314231314231314229314231314229314231314231394231314A3139423131 + 4231394A31394231314231394231394A31394231394A31394A31394A31394A31 + 394A39424A31394A39424A31394A31394A394239397B42426B424A7331396B39 + 397331396B39315A42426B31396B42426B31396B39397339315A42426B31396B + 42426B31396B31315A31396B39315231315A31315A31315A31396B31315A3129 + 4A31294A29294A31294A31294231294229214231183929293929182929293929 + 2139292939292939291829291829291829291829291829291829291829211018 + 2918292110182118212110182118212110182118212110184A394A52424A5242 + 4A4A39424A394A4A394252424A4A394252424A4A394252424A4A394252424A4A + 394252424A52424A52424A52424A5A424A5A424A52424A52424A5A424A52424A + 5A424A5A424A52424A4A39425A424A4A313952424A4A313952424A52424A5242 + 4A52424A52424A52424A52424A4A39424A313952424A52424A4A31394A39424A + 31394A39424A313952424A52424A52424A4A3942FFFFFF000000422931422931 + 3929294231314229314231314A31314231313929294231314229314231314231 + 314231314231314231314A313139293142313142313142313142313942313942 + 31394231314231394A31314231394231394A31394A31394231394231314A3139 + 4A31394A31394A39424A31394A39424A31394A39424A31394A3139424A733139 + 7B39397331396B31396B31396B39397331396B31396B31396B31396B31396B31 + 396B31396B31396B31396B31396B39315A31315A31315A31315A31315A39315A + 39315A31315A31315A31294A31294A31315A31294A2929393121422929392921 + 3929213929213929293929182921102929182921102929182921182129182921 + 1821211821211821211821211821211018211018211018211821211018392929 + 52424A4A394252424A52424A52424A52424A52424A52424A4A394252424A4A39 + 4252424A5A424A4A394252424A52424A52424A5A424A52424A5A424A5A424A52 + 424A52424A52424A5A424A52424A52424A4A394252424A52424A4A394252424A + 52424A52424A4A31394A394252424A4A313952424A4A313952424A4A39424A39 + 4252424A52424A52424A4A313952424A52424A4A39424A39424A3942FFFFFF00 + 0000392929392929422931422931423131423131423131423131423131422931 + 4231313929314229314231314229314231313929314231314231314231314231 + 394231394231314231314A31394231314231394231394A31314231394231394A + 31394A31394231394A31394A39424A31394A31394A31394A39424A31394A3942 + 4A313142395A31396B42426B31396B42426B39397331396B42426B3939734242 + 6B31396B42426B31396B42426B39397342426B42426B39315A31396B31315A31 + 315A31315A31396B31315A31396B31315A31315A31315A31294A292142292142 + 2921392921392921392921392921392918292929392918292918292918292918 + 2929182921182121101821182121182121182121101829182921182121182121 + 10181810214A313952424A52424A4A39424A39425A424A4A39424A394252424A + 4A394252424A52424A4A394252424A4A39425A424A52424A52424A5A424A5A42 + 4A52424A52424A52424A52424A5A424A5A424A4A39425A424A52424A52424A4A + 394252424A52424A4A313952424A52424A5A424A52424A52424A4A394252424A + 4A313952424A4A313952424A4A313952424A52424A4A31394A39425A424A5242 + 4A4A3942FFFFFF00000042293142293139292942313142293142313139292942 + 2931422931423131392929422931423131392929423131423139423131392931 + 4229314231313929314229314231394231314231394231394231314A31394A31 + 394231314231394231394231314A31394A31394A39424A313952424A4A31394A + 39424A31394A39424A31394A3942424A7331396B31396B31396B39315A31396B + 42426B31396B31396B42426B31315A31396B31396B42426B31396B31396B3931 + 5A39315A31396B31315A39315A31315A31315A31294A31315A29294A31294A31 + 294A312942292939292139292939292939292139292939291829291829291829 + 2118212918292118212918292918292118212118212118212118212118212110 + 1821101821182121101829182952424A4A394252424A52424A4A394252424A52 + 424A52424A4A394252424A4A313952424A52424A52424A4A394252424A52424A + 52424A52424A5A424A5A4A4A5A424A52424A52424A52424A52424A52424A5A42 + 4A4A394252424A52424A4A313952424A52424A4A313952424A4A313952424A4A + 313952424A4A313952424A4A313952424A4A394252424A4A394252424A52424A + 4A39424A31394A39424A3942FFFFFF0000003929294229313929294231314231 + 3142293142313139292942293139292942313142313139292942313142293142 + 3131422931423131423131423131422931423131423131423139423131423131 + 4231394231394A31314231394231394A31394231394A31394A31394A31394A39 + 424A31394A31394A39424A31394A39424A31394A313142395A424A7331396B42 + 426B31396B31396B39397339315A42426B31396B31396B42426342426B31396B + 39397342426B31396B39315A39315A31396B31396B39315A31396B29294A3129 + 4A31294A31294229214229213929213929213929213921102929182929182929 + 2939291829291829291829291829291829211821211821211821291829211821 + 2918292918292918292110182118211808104A313952424A52424A4A39425A42 + 4A52424A4A394252424A4A39424A394252424A4A394252424A4A313952424A52 + 424A4A394252424A52424A52424A52424A52424A52424A5A424A52424A5A424A + 5A424A52424A5A424A52424A4A39425A424A4A394252424A52424A52424A5242 + 4A52424A52424A52424A52424A52424A4A313952424A52424A52424A52424A4A + 31394A39424A313952424A52424A52424A4A3942FFFFFF000000422931392929 + 4229314231314229313929294229314229314229313929294231313929294231 + 3142293142313142313142313142313142313142293142313142313142313142 + 31314231314231314A31394231314231394A31394A31394231394A31394A3139 + 4A31394A31394A31394A313952424A4A31394A31394A31394A39424A31394A39 + 4231396B31396B31396B39397342426B31396B31396B42426331396B31396B31 + 396B31396B31396B39315A31396B31396B31315A31315A31315A31315A31315A + 31315A31294A31294A31294A2921423129423129422921392921392921392918 + 2929293929213921102929182921102921102921182121102929182921101821 + 182121182121182129182921101829182921182121101829182952424A52424A + 4A394252424A4A39424A394252424A4A394252424A4A394252424A4A39425242 + 4A4A394252424A4A394252424A52424A52424A5A424A5A424A52424A52424A52 + 424A52424A52424A52424A52424A52424A4A39425A424A4A39425A424A52424A + 4A313952424A52424A4A313952424A4A313952424A4A313952424A52424A4A39 + 4252424A4A313952424A52424A52424A4A39424A39424A39424A3942FFFFFF00 + 0000392929422931422931422931422931422931392929422931392929423131 + 3929294231313929294231314231314229314231313929314231314231314231 + 394231314231394231314231394231394A31394231394A31314231394231394A + 31394A31394A31394A31394A31394A313952424A4A31394A31394A39424A3139 + 4A31394A3942423131524A5231396B42426B31396B31396B39397331396B3139 + 6B42426B31396B424A7342426B39397331396B42426331396B31315A31315A31 + 315A31294A29214231315A31315A31294A31315A31294A292142292139292139 + 2929392918292921392110292918292918292918292918292918292918292918 + 292918292918292118212118212918292918292918292118212110182110184A + 313952424A52424A4A394252424A52424A52424A4A394252424A52424A4A3942 + 4A394252424A4A394252424A4A394252424A4A394252424A52424A52424A5242 + 4A5A424A52424A52424A52424A5A424A5A424A52424A5A424A52424A5A424A4A + 39424A394252424A5A424A4A313952424A52424A52424A52424A52424A52424A + 4A39424A394252424A4A394252424A4A313952424A4A39424A313952424A4A39 + 424A3942FFFFFF00000042293139292942293139292939292939292942293139 + 2929423131422931423131423131422931392929423131423131423139423131 + 4229314231314231314231314231314231394231314A31314A31314231394A31 + 394A31394A31394A31394A31394A31394A31394A31394A39424A31394A39424A + 31394A31394A31394A39424A31394A394242313939315A31396B42426B31396B + 31396B42426B31396B31396B42426B39397331396B31396B31396B31396B3931 + 5A31315A31315A31294A31315A31315A31315A31294A31294231294A31294A31 + 2942312942292139291829292139291829292939211029292139211821291829 + 2918292918292918292918292918292918292918292118212118212118212918 + 2918102139293152424A4A39424A39424A39424A313952424A52424A4A394252 + 424A4A394252424A4A39424A394252424A4A394252424A52424A52424A52424A + 52424A5A424A52424A5A424A52424A52424A52424A52424A52424A52424A5A42 + 4A4A394252424A52424A4A39424A394252424A52424A4A39424A313952424A4A + 31394A39424A31394A394252424A4A313952424A52424A52424A4A31395A424A + 4A39424A394252424A52424AFFFFFF0000003929294229313929294229314229 + 3142293142293142293142293139292939292942293142313142313142293139 + 2929423131422931423131423139423131423131423131423131423139423139 + 4A31394A31394231314A31394A31394A31394A31394231314A31394A31394A31 + 394A39424A31394A39424A39424231394231394231394A31394A31394A313942 + 426331396B31396B424A7331396B393973424A7339397342426B31396B42426B + 31315A42426B31396B31396B31315A31315A31315A31315A31315A29294A2921 + 4229294A29294A29293929213929214229213929182929182921103129182929 + 1829292939291829291829291829291829291829291829211029291829211821 + 29182929182921182129182952424A52424A4A39424A39424A394252424A5242 + 4A4A394252424A4A394252424A52424A52424A4A394252424A4A394252424A4A + 39424A394252424A5A424A5A424A52424A52424A52424A52424A52424A5A424A + 5A424A5A424A52424A52424A4A39424A39424A394252424A52424A52424A5242 + 4A52424A52424A52424A52424A52424A4A39424A313952424A52424A4A31394A + 394252424A4A39424A394252424A4A39424A3942FFFFFF000000422931392929 + 3929294229313929293929293929293929294229314229314229314231314231 + 3142293142313142293142313142313142313142293142313142313942313942 + 31314231394A31314231394231314231394231394231394231394A3139423139 + 4231394A31394A31394A31394A39424A39424A31394231394A39424A39424A39 + 424A39424A31394A313942395A39397331396B31396B31396B31396B31396B31 + 396B31396B31396B31396B31396B39315A42395A42314A4A394A4A394A4A394A + 4A394A4A394A4A425A42395A39315231294A2921422921392921392921392921 + 3929182929293929213929182929182929213929182921182121102921182121 + 18212110292110292918291808292918294A394A52424A4A39424A39424A3942 + 52424A52424A4A394252424A4A394252424A4A39424A39424A394252424A4A39 + 4252424A52424A4A39425A424A52424A52424A4A39425A424A52424A52424A52 + 424A5A424A52424A4A313952424A4A394252424A4A394252424A52424A52424A + 52424A52424A4A313952424A4A313952424A4A313952424A4A313952424A5242 + 4A4A313952424A52424A4A39424A39424A39425A424A4A39424A3139FFFFFF00 + 0000392929422931392929392929422931422931422931422931392929422931 + 4229314231314229314231314231314231314231314229314231394231314231 + 314231314231314231394231314231394231314231314231394A313942313142 + 31394231394A31394A31394A31394A31394A31394A31394A31394231394A3139 + 4A31394A31394231394A31394A39424A31394A313142314A424263424A733139 + 6B424A73424A7342426B424A7339315A524A524A394A4A39424A31394A31394A + 31394A31394A39424A31394A39424A31394A31394A394252424A42395A424263 + 31315A29294A21214A2921422921422921422921392929392918292918292918 + 292118212918292918292110292118212110293929314A313952424A4A39424A + 39424A394252424A4A39424A394252424A4A394252424A4A394252424A52424A + 4A39424A394252424A4A394252424A4A394252424A5A424A52424A52424A5242 + 4A52424A5A424A4A394252424A52424A52424A52424A52424A4A394252424A4A + 39424A39424A313952424A52424A52424A52424A52424A5A424A52424A52424A + 4A39424A313952424A52424A52424A4A313952424A52424A4A39424A39425242 + 4A4A3942FFFFFF00000042293139292942293142293139292939292942293142 + 2931422931422931392929422931423131392931423131422931423131423131 + 4229314231314231314229314231314231394231314231394231394231314231 + 314231394A31394231394231394231394A31394A31394A31394A39424A31394A + 31394A31394231394231394A31394A31394231394231394A39424A31394A3139 + 4A31394A39424A394A4A425A4A394A4A39424A31394A31394A31394A31394A39 + 424A39424A39424A39424A31394A39424A31394A39424A39424A31394A39424A + 31394A31394A3942524A5242395A42426331396B29294A29294A292142292142 + 2921392921392921392921392929392110312921392929393931524A39425242 + 4A52424A4A39424A394252424A4A394252424A4A394252424A4A394252424A4A + 39424A39424A394252424A4A39424A394252424A4A394252424A4A394252424A + 52424A5A424A52424A52424A52424A52424A52424A52424A52424A4A31395A42 + 4A52424A4A394252424A52424A52424A4A313952424A52424A4A313952424A4A + 394252424A4A313952424A4A39424A39424A313952424A4A394252424A4A3139 + 52424A4A394252424A4A3942FFFFFF0000004229313929294229313929294229 + 3142293139292942293142293142293142293142293142313142293142313142 + 3131392931423131423131423131392931423131423139422931423139423131 + 4229314231314229314231394231314231394231314231314231394A31394A31 + 394A31394A31394A31394A31394A31394231394A31394A31394A31394A31394A + 31394A39424A31394A39424A31394A31394A31314A31394A31394A3942423139 + 4A39424A39424A31394A39424A39424A31394A39424A39424A39424A39424A39 + 424A39424A39424A39424A39424A39424A31394A31394A3942524A5242395A42 + 426342426342426331315A29294A29294A31315A29294A31315A42314A4A394A + 52424A52424A52424A4A394252424A4A39424A39424A39424A394252424A5242 + 4A4A394252424A4A394252424A4A39424A394252424A4A39424A394252424A4A + 39424A39424A394252424A52424A52424A5A424A4A394252424A4A39425A424A + 4A394252424A4A394252424A4A39424A39424A313952424A52424A4A39425242 + 4A5A424A52424A52424A52424A52424A4A394252424A52424A4A394252424A4A + 394252424A52424A4A39424A39424A39424A3942FFFFFF000000392929422931 + 3929293929294229313929294229313929294229313929294229313929294231 + 3942293142313142293142313142293142313139293142313142293142313142 + 31314231314231314231314231394231314231314231394231314231394A3131 + 4A31394A31394A31394A31394A31394A31394231394231394A31394A31394A31 + 394A31394A31394A31394A31394A31394A31394A31394A31394A39424231394A + 39424A31394A39424A31394A39424A31394A39424A31394A39424A39424A3942 + 4A39424A39424A39424A31394A39424A39424A39424A39424A39424A31394A39 + 424A31394A313952424A4A39424A394A524A524A425A4A425A4A394A4A394A52 + 424A4A39424A394252424A4A394252424A4A394252424A4A39424A39424A3942 + 4A39424A394252424A4A39424A39424A39424A39424A39424A394252424A4A39 + 424A394252424A4A394252424A52424A52424A52424A52424A52424A5A424A52 + 424A52424A52424A4A394252424A4A394252424A4A394252424A4A39424A3942 + 52424A4A394252424A4A39424A39425A424A4A39424A39424A39424A31394A39 + 4252424A4A394252424A4A39424A39424A394252424A4A39424A3942FFFFFF00 + 0000 + } + Stretch = True + end + object MoContact: TMemo + Left = 250 + Height = 72 + Top = 21 + Width = 182 + BorderStyle = bsNone + Color = clBtnFace + Font.Color = clWindowText + Font.Height = -16 + Font.Name = 'Arial' + Lines.Strings = ( + 'Having trouble ' + 'parameterizing?' + 'Click the icon on the left.' + ) + ParentFont = False + ReadOnly = True + TabOrder = 0 + end + object BtnOK: TButton + Left = 317 + Height = 20 + Top = 107 + Width = 60 + Cancel = True + Caption = '&OK' + Default = True + ModalResult = 1 + TabOrder = 1 + end + object MmError: TMemo + Left = 242 + Height = 72 + Top = 140 + Width = 190 + Color = clScrollBar + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'MS Sans Serif' + ParentFont = False + TabOrder = 2 + end +end diff --git a/modelshell/trouble.pas b/modelshell/trouble.pas new file mode 100644 index 0000000..d20694e --- /dev/null +++ b/modelshell/trouble.pas @@ -0,0 +1,79 @@ +unit TROUBLE; + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; + +type + TFmTrouble = class(TForm) + Image1: TImage; + MoContact: TMemo; + BtnOK: TButton; + MmError: TMemo; + procedure Image1Click(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + FmTrouble: TFmTrouble; + +implementation + +{$R *.lfm} + +procedure TFmTrouble.FormShow(Sender: TObject); +begin + // SetWindowPos(FmTrouble.Handle, HWND_TOPMOST, + // 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE); +end; + +procedure TFmTrouble.Image1Click(Sender: TObject); +begin + MessageDlg('Take a break, go get a snack.', mtConfirmation, [mbOK],0); +end; + +end. + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; + +type + TFmTrouble = class(TForm) + Image1: TImage; + MoContact: TMemo; + BtnOK: TButton; + MmError: TMemo; + procedure Image1Click(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + FmTrouble: TFmTrouble; + +implementation + +{$R *.lfm} + +procedure TFmTrouble.FormShow(Sender: TObject); +begin + // SetWindowPos(FmTrouble.Handle, HWND_TOPMOST, + // 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE); +end; + +procedure TFmTrouble.Image1Click(Sender: TObject); +begin + MessageDlg('Take a break, go get a snack.', mtConfirmation, [mbOK],0); +end; + +end.