Implementation steps
We will implement running of Sobek through a dll using the following approach:
Extend fortran code to allow for setting model parameters and data (ie "setvalues")
In C# the module wlacces implements running of sobek models that are defined in a file.
setvalues will be defined in new interface (not in iwlaccess !)
fortran c / code will implement methods in interface
General structure of the Deltshell - Sobeksim interface
The sobeksim interface now consists of the projects:
- DelftModelApi.Net
- delft_model_api
- delft_model_data
furthermore a module called GUI_communication is added to the project kernel_sobek_f
In DelftModelApi.Net the static class modelApi is defined. This class contains functions to transfer data from C# to the SOBEKSIM kernel. The functions in class modelApi are implemented in delft_model_api.dll. In module modelApi the exported functions of delft_model_api.dll are defined. The relevant data is stored in ModelGlobalData. ModelGlobalData uses derived types which are defined in ModelTypes and NetworkTypes. ModelTypes contains the run-time parameters and model state variables, whereas NetworkTypes contains the derived types to define a network. The module GUI_communication transfers the data from ModelGlobalData to the data structure of Sobeksim.
DelftModelApi.Net and GUI_Communication are described in the next subsections
DelftModelApi.Net
DelftModelApi.net contains the static class ModelApi. ModelApi in its turn contains functions to transfer data from C# to the SOBEKSIM kernel.
Available functions are:
Name |
Description |
---|---|
setUsePluginData |
Sets the flag for the computational kernel to use the modelapi |
NetworkSetDimensions |
Sets the dimensions of the network (number of branches, nodes, cross sections, ... |
NetworkSetNode |
Define a new node in the network |
NetworkSetBranch |
Define a new branch in the network |
NetworkGetBranch |
Get a branch |
NetworkSetQBoundary |
Set a Q-boundary at an end node of the network (limitation: at this time only constant boundary conditions are allowed) |
NetworkSetHBoundary |
Set an H-boundary at an end node of the network (limitation: at this time only constant boundary conditions are allowed) |
NetworkSetTabCrossSection |
Define a cross section in terms of widths with respect to height |
NetworkSetCS |
connect a cross section definition to a branch (limitation: Momentarily only one cross section per branch is allowed) |
ModelInitialize |
Start the SOBEK initialisation |
ModelSetSimulationTimes |
Set the simulation times for the model |
ModelFinalize |
Close/terminate the simulation |
ModelGetCurrentTime |
Gets the SOBEK current simulation time |
ModelPerformTimeStep |
Perform one time step |
GUI_communication
In GUI_communication the datastructure of Sobeksim is filled. Since the initialisation of the arrays is performed at different locations in Sobeksim, there is a number of subroutines that perform a part of the initialisation, namely setValues, setValuesinMempool, getcsnam, setFlsData, setIds and setArrays.
Subroutine dumppool of GUI_Communication can be used for debugging purposes. Because dumppool writes the datastructure of sobeksim to file.
Examples
In this example a network with three branches is defined.
[Test] public void RunABitLessSimpleModel() { int modelHandle = 0; int numSteps = 0; string workingDirectory = @"..\..\..\..\testdata\ModelApiTest\Simple\CMTWORK\"; Environment.CurrentDirectory = workingDirectory; // set current directory to output so that it will be the only one place where sobeksim writes data // the directory for now already contains files produced by parsen.exe // format for date is YYYYMMDD and for time HHMMSS int startDate = 19960101; int startTime = 10000; int endDate = 19960102; int endtTime = 150000; // time steps are given in seconds int timeStep = 300; int outputTimeStep = 3600; ModelApi.ModelSetSimulationTimes(ref startDate, ref startTime, ref endDate, ref endtTime, ref timeStep, ref outputTimeStep); // Define the dimensions of the model. In terms of number of Branches, number of nodes and number of cross // sections int branchesCount = 3; int nodesCount = 4; int crossSectionsCount = 3; float deltaX = 10.0f; ModelApi.NetworkSetDimensions(ref branchesCount, ref nodesCount, ref crossSectionsCount, ref deltaX); // ---------------------------------------------------- // set branch1, node1, node2, crs1, crs2, etc to model // A node has an ID, which must be a uniqe (key), a name (a description of the node) and coordinates, which // define the location of the node. The coordinates are used to calculate the length of a branch string id = "1"; string name = " "; double[] coor = new double[2]; coor[0] = -400; coor[1] = 0; ModelApi.NetworkSetNode(id, name, coor); id = "2"; name = " "; coor[0] = 200; coor[1] = 200; ModelApi.NetworkSetNode(id, name, coor); id = "3"; name = " "; coor[0] = 200; coor[1] = -200; ModelApi.NetworkSetNode(id, name, coor); id = "4"; name = " "; coor[0] = -9.967; coor[1] = 16.56; ModelApi.NetworkSetNode(id, name, coor); // Define the branches, using a from node and a to node. Length can be used to override // the length, defined by the distance between the fromNode and toNode. If length > 0, // this length is used. // With deltaX the A global value for the complete network is defined by DeltaX given in id = "1"; name = ""; int fromNode = 1; int toNode = 4; deltaX = 0.0f; float length = 0; ModelApi.NetworkSetBranch(id, name, ref fromNode, ref toNode, ref length, ref deltaX); id = "2"; name = ""; fromNode = 4; toNode = 2; deltaX = 0.0f; length = 0; ModelApi.NetworkSetBranch(id, name, ref fromNode, ref toNode, ref length, ref deltaX); id = "3"; name = ""; fromNode = 4; toNode = 3; deltaX = 0.0f; length = 0; ModelApi.NetworkSetBranch(id, name, ref fromNode, ref toNode, ref length, ref deltaX); // Set boundary conditions. Boundary conditions may only be set on nodes, that have only // one connection. NodeId is not the name of the id, but the sequence number, id = 1 is // the first node that is defined by the call NetworkSetNode. int nodeId = 1; double value = 2.0; ModelApi.NetworkSetQBoundary(ref nodeId, ref value); nodeId = 2; ModelApi.NetworkSetHBoundary(ref nodeId, ref value); nodeId = 3; value = 1.9; ModelApi.NetworkSetHBoundary(ref nodeId, ref value); // Define a cross section with two levels int levelCount = 2; double [] levels = new double[levelCount]; levels[0] = 0.0; levels[1] = 5.0; double [] flowWidth = new double[levelCount]; flowWidth[0] = 5.0; flowWidth[1] = 5.0; double [] storWidth = new double[levelCount]; storWidth[0] = 6.0; storWidth[1] = 10.0; int iref = ModelApi.NetworkSetTabCrossSection(ref levelCount, levels, flowWidth, storWidth); // Connect the cross section to the various branches int branch = 1; double location= 196.086; double bottomLevel = 0; double surfaceLevel = 2.0; int bedFrictionType = (int) Friction.ChezyConstant; int groundFrictionType = (int) Friction.WhiteColebrook; double bedFriction = 45.0; double groundFriction = 0.003; int storageType = 0; ModelApi.NetworkSetCS(ref branch, ref location, ref iref, ref bottomLevel, ref surfaceLevel, ref bedFrictionType, ref bedFriction, ref groundFrictionType, ref groundFriction, ref storageType); branch = 2; location = 139.364; bedFrictionType = (int)Friction.Mannings; bedFriction = 0.025; ModelApi.NetworkSetCS(ref branch, ref location, ref iref, ref bottomLevel, ref surfaceLevel, ref bedFrictionType, ref bedFriction, ref groundFrictionType, ref groundFriction, ref storageType); branch = 3; location = 160.33; bedFrictionType = (int)Friction.WhiteColebrook; bedFriction = 0.2; ModelApi.NetworkSetCS(ref branch, ref location, ref iref, ref bottomLevel, ref surfaceLevel, ref bedFrictionType, ref bedFriction, ref groundFrictionType, ref groundFriction, ref storageType); // Initialize SOBEKSIM ModelApi.ModelInitialize(ref modelHandle, ref numSteps); for (int step = 0; step <= numSteps; step++) { // Perform one time step ModelApi.ModelPerformTimeStep(ref modelHandle, ref step); } // End the simulation ModelApi.ModelFinalize(); }
Notes
- Sobek OpenMI module:
Useful function for initialising and performing one or more timesteps and finalizing.
-
- 'SE_OpenMI.f90' communicates with OEM buffer.
- 'SE_OpenMI.f90' has calls to module OMI_CF_control in (OMI_CF_control.f90), which in turn calls directly sobeksim subroutines
- Present SOBEK reads nefis files during initialisation (using m_nefisinput.mod). Nefis is used in subroutines: read_initial_values_strpar_etc, soedef, sogetm and wetcrs.
SOBEK variables read from NEFIS
integer :: nnode ! nr of sobek nodes integer :: nbran ! nr of branches integer :: nstdb integer :: nstru ! number of structures integer :: ntrigr ! number of triggers integer :: ncontr ! number of controllers integer :: ntcrel ! number of trigger-controller relations integer :: ncsrel ! number of controller-structure relations integer :: nqlat ! number of lateral inflows integer :: ngrid ! nr of sobek points integer :: nboun ! number of open boundaries integer :: nhstat ! number of 1D waterlevel boundaries integer :: nqstat ! number of 1D discharge boundaries integer :: ntabm integer :: maxtab integer :: maxlev integer :: ncross integer :: nevents integer :: mxstrpar ! leading dimension of strpar integer :: mxistrtyp ! leading dimension of istrtyp integer :: mxstrmu ! integer :: mxcross integer :: mxqltpar integer :: mxtriger ! leading dimension of triger integer :: mxcontrl ! leading dimension of contrl integer :: mxconhis = 5 ! leading dimension of conhis integer :: mxconhis ! leading dimension of conhis integer :: mxtrcnrl ! leading dimension of trcnrl integer :: mxcnstrl ! leading dimension of cnstrl = 2 integer :: mxengpar ! dimension of engpar integer :: mxbranch ! lead dim of branch integer :: nupt integer :: msect integer :: lcnvmax real , allocatable :: strpar (:,:) ! structure parameters (mxstrpar,nstru) real , allocatable :: strmu (:,:) ! structure mu (mxstrmu,nstru) integer, allocatable :: istrtyp(:,:) ! structure type (mxistrtyp,nstru) character(len=40), allocatable :: contrnam(:) ! names of controllers (ncontr) character(len=40), allocatable :: trigrnam(:) ! names of triggers (ntrigr) character(len=40), allocatable :: qlatnm(:) ! ids of qlats (nqlat) real , allocatable :: qlat (:) ! lateral inflow (nqlat) real , allocatable :: qltpar(:,:) ! lateral inflow parameters (mxqltpar,nqlat) integer, allocatable :: node(:,:) ! sobek node administration (nnode) integer, allocatable :: branch(:,:) ! sobek branch admin (mxbranch,nbran) integer, allocatable :: triger(:,:) ! trigger data (mxtriger,ntrigr) real , allocatable :: contrl(:,:) ! controller data (mxcontrl,ncontr) integer, allocatable :: trcnrl(:,:) ! trigger controller relation (mxtrcnrl,ntcrel) integer, allocatable :: cnstrl(:,:) ! controller structure relation (mxcnstrl,ncsrel) integer, allocatable :: hbdpar(:,:) ! integer parameters (3,*), 1=?, 2=iopt, 3=itab (3,nhstat) integer, allocatable :: qbdpar(:,:) ! integer parameters (3,*), 1=?, 2=iopt, 3=itab (3,nqstat) real , allocatable :: engpar(:) ! Engelund-Hansen parameters (mxengpar) real , allocatable :: hpack(:) ! s0 voor sobek points (ngrid) real , allocatable :: qpack(:) ! q voor sobek points (ngrid) double precision, allocatable :: xycoor(:,:) ! (2,ngrid) x,y coordinates for sobek points (2,ngrid) integer, allocatable :: nlevu (:) ! (nupt) real, allocatable :: chan_hu (:,:) ! (ngrid) real, allocatable :: chan_af (:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_wf (:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_pf (:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_co (:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_cn (:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_cz1(:,:,:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_cz2(:,:,:) ! (nupt,lcnvmax,msect) integer, allocatable :: nlevh (:) ! (nupt,lcnvmax,msect) real, allocatable :: chan_hh (:,:) ! (ngrid,lcnvmax) real, allocatable :: chan_at (:,:) ! (ngrid,lcnvmax) real, allocatable :: chan_wt (:,:) ! (ngrid,lcnvmax) character(len=CharLen ), allocatable, save :: nodenm ! (nnode) character(len=CharLen ), allocatable, save :: gridnnm ! (ngrid)
Q1: What is relation trigger-contoller, contoller-structure
integer, allocatable :: trcnrl(:,:) ! trigger controller relation (mxtrcnrl,ntcrel) integer, allocatable :: cnstrl(:,:) ! controller structure relation (mxcnstrl,ncsrel)
Q2: Engelund-Hansen parameters - isn't it morphology? is it required for flow
Q3: Give definition of a structure, controller, trigger and give full list of their parameter names.
Q4: Cross-section type currently of two types - describe them
- free form
- wetted-perimeter formula