Skip to content

MIKE 1D API

Introduction

MIKE 1D is a numerical simulation engine that simulates 1-dimensional water flow in river and sewer networks.

MIKE 1D is the calculation backend of several MIKE Products: MIKE+ (Catchment, Collection System and River Network modules), MIKE HYDRO River, MIKE 11, and MIKE URBAN.

MIKE 1D has re-engineered and merged calculation capabilities of the classical MIKE river and collection system packages: MIKE 11 and MIKE URBAN / MOUSE.

MIKE 1D features an extensive API (Application Programming Interface) that provides a high level of interaction and control of the MIKE 1D engine. Through the API it is possible to programmatically create or modify a setup and interact with the engine during simulation from user defined code. Everything you can do in a setup editor, you can do using the API.

The MIKE 1D API is a .NET API, and can be utilized in any .NET compatible environment.

Examples of API usage:

  • Modifying a setup, e.g. flipping a parameter, adding or modifying catchments, branches/links, manholes, structures, controls etc.

  • Customising and extracting result outputs.

  • Extending functionality, e.g. including user defined implementations of structures, catchments or boundaries.

  • Setting up user defined real time control strategies.

  • Integration with online systems, online censors or databases.

Accessing the API

There are two special ways to utilize the MIKE 1D API which runs integrated with MIKE 1D:

  • MIKE 1D Script: a text file with C# code (.cs file) that is loaded, compiled and executed at runtime by MIKE 1D.

  • MIKE 1D Plugin: a .NET library (dll) that is loaded and executed at runtime by MIKE 1D.

The MIKE 1D API can be accessed from any .NET compatible environment:

  • Program: You can make you own program or executable that can load, modify and/or run MIKE 1D simulations in any way you like.

  • Scripting: In scripting environments like python, you can load, modify and/or run MIKE 1D simulations in any way you like. It has been used with Python using the pythonnet package, and with MATLAB.

MIKE 1D Script vs. Plugin

There is a few benefits and drawbacks for both plugins and scripts:

  • MIKE 1D engine version compatibility:

    • A plugin works with a specific version of MIKE 1D. When upgrading MIKE 1D to a newer version, the plugin needs to be recompiled.

    • A script works with any version of MIKE 1D. When upgrading MIKE 1D to a newer version, a script will continue to work (assuming no breaking API changes, which happens seldom).

  • Complexity of code

    • A plugin can handle any number of source files and include any third party dependencies.

    • With a script, all functionality must be contained within a single source file, and usage of 3rd party dependencies is limited.

  • Tooling

    • A plugin must be compiled, and Visual Studio or similar is required.

    • A script needs no tooling (though a integrated development environment like Visual Studio can make life a lot easier when developing/debugging the script).

The recommendation is to use a script whenever possible.

Online documentation and examples

MIKE 1D Engine architecture

MIKE 1D is split up into many Data Components and an Engine component.

alt text

Figure 1: MIKE 1D components

The data components hold the setup data, similar to the data in the MIKE+ setup, MIKE Hydro River file, or the set of MIKE 11 files (sim11, nwk11, bnd11 etc.). They are individual components, as self-contained as possible and with a minimum of dependencies.

The Engine components does the actual computations. It contains a Controller which links the data components to the engine components and controls the simulation workflow. For HD simulation, the main engine component is the EngineNet, which holds static data, i.e. data that does not change while the simulation is running, like the model network, connectivity, coordinates, and geometries. The engine component also contains a number of modules, which holds dynamic data (state) and that are responsible for the actual computations.

Simulation phases and events

When running a simulation with the MIKE 1D engine, the Controller leads the engine through a number of different simulation phases:

  1. Load. The first phase loads setup data from some source: MIKE+ setup, MIKE HYDRO River setup, MIKE 11, or MIKE URBAN. The loading is done by a dedicated bridge, where the bridge translates the source into the MIKE 1D Data components, and the result is a set of populated MIKE 1D Data components. After loading of data, it is possible to modify the setup by editing the MIKE 1D Data components.

  2. Validate. The next phase is data validation. The MIKE 1D Data components are checked to see if the setup is valid for simulation. The result of the validation is collection of hints, warnings and errors. These are reported through the diagnostics system, using the IDiagnostics. If an error is found during validation, the simulation will not continue. It is possible to modify the MIKE 1D Data components and rerun the validation any number of times. In the perfect world all errors should be reported in the validation step, however, this is currently not the case. Some errors are only reported in the initialize or prepare step.

  3. Initialize. Sets up the "static" part of the engine, i.e. parts that does not change with each timestep. For HD simulation the EngineNet is set up, containing nodes, reaches, gridpoints, their coordinates and geometries etc.

  4. Prepare. Sets up the "dynamic" part, i.e. the part that changes with each time step, such as water level values, runoff values etc, called "state". The state is set up, initial conditions are applied, result output files are prepared.

  5. Run. Runs the simulation, performing a number of time steps.

  6. Finish. The last phase closes the simulation, prints out summary files, closes result output files etc.

If one phase fails, the next phase will not be initiated and the Diagnostics system reports the errors. One exception to this is the Finish phase: A simulation that has been initialized will always call Finish in an attempt to clean up any allocated resources.

The Controller.State tells tells how far the simulation has progressed. You can at any time query the controller for its current state, using.

IMike1DController controller ...
ControllerState state = controller.State;

The ControllerState comes in sets of values

  public enum ControllerState
  {
    Created,
    Validating, Validated, Invalid,
    Initializing , Initialized,
    Preparing, Prepared,
    Running, Paused, Stopped, Finished,
    Finalizing, Finalized,
    Failed,
  }

The *ing states are "active" states, meanning that the engine is doing that work. The other states are passive states where the engine is currently inactive, and those states are the "result" of completing one of the simulation phases. As an example Validating is the state of the engine while the validation work is going on, and when done, if valudation is successfull, the engine will enter the Validated state, and if validation failed, the engine will enter the Invalid state.

Controller events

The most common way to follow the state of the engine is by registering for the ControllerEvent, either directly on the controller, or alternatively on the SimulationWorker (see later for details on the SimulationWorker).

IMike1DController controller ...;
controller.ControllerEvent += OnControllerEvent;

SimulationWorker worker = ...;
worker.ControllerEvent += OnControllerEvent;

A typical example of a OnControllerEvent method looks like:

private void OnControllerEvent(object sender, ControllerEventArgs eventArgs)
{
  var controller = sender as IMike1DController;
  if (sender == null) return;

  if (controllerEventArgs.State == ControllerState.Prepared)
  {
    [Do your stuff here]
  }
}

Time step events

While the engine is running, it is possible to interact with the engine in between time steps. To interact with the HD engine on a time step basis, the EngineNet has a number of events that can be utilized as follows, here for the PostTimeStepEvent:

controller.EngineNet.PostTimeStepEvent += UpdateWeirCoefficients;

private void UpdateWeirCoefficients(DateTime time)
{
    [Do stuff here]
}

The EngineNet has the following events:

  • PreTimeStepEvent : Triggered every time a time step is initiated

  • ApplyExternalSourcesEvent : Triggered when external sources are to be applied

  • PostIterationEvent : Triggered when an iteration within a time step was successfully performed

  • PostTimeStepEvent : Triggered when a time step was successfully performed

For more details on these events, visit EngineNet Events

Coding against MIKE 1D API

For details on how to use and enable a script, visit MIKE 1D SDK examples

For details on how to create a plugin, visit: MIKE 1D Plugins

Running a simulation with the MIKE 1D engine in own code

The examples here shows how to boot up the MIKE 1D engine using own code. The examples are in C#, but will also work in scripting environments.

The standard way of running a simulation setup is to use the SimulationWorker class with a few lines of code:

SimulationWorker worker = new SimulationWorker(new FilePath(setupFilePath))
{
  SimulationParameters = new SimulationParameters()
};
// Load data and run simulation
worker.Work();

There is no difference between using the SimulationWorker and running the setup from within e.g. the MIKE+ or MIKE HYDRO user interface. The SimulationWorker does everything that a normal simulation does, including writing log files, summary files, handling progress reporting etc.

When modifying setups before running a simulation, we simply replace the Work() method with the two separate methods Load() and Run():

// Load data
worker.Load();

// Now data is loaded and can be modified.
Mike1DData mike1DData = worker.Mike1DData;

// Run simulation
worker.Run();

The worker has a Controller created when Run is called. In order to get access to this Controller, you must register for the ControllerCreatedEvent on the Mike1DData object:

// Load data
worker.Load();

// Now data is loaded and can be modified.
Mike1DData mike1DData = worker.Mike1DData;
// Event that is triggered when a new controller is created
mike1DData.ControllerCreatedEvent += ControllerCreatedEvent;

// Run simulation
worker.Run();

The ControllerCreatedEvent method has the form:

private void ControllerCreatedEvent(object sender, ControllerCreatedEventArgs eventArgs)
{
  IMike1DController controller = controllerCreatedEventArgs.Controller;
  controller.ControllerEvent += OnControllerEvent;
}

where in this method we also register for the ControllerEvent, using the OnControllerEvent method similar as in previous section.

Run using the Controller

Another way of executing a simulation is by using the IMike1DController directly. The IMike1DController runs the simulation in its most raw form.

When using the controller directly, the user must also handle all phases of a simulation and is responsible for handling diagnostics messages, progress and summary files etc. This is usually only useful if you want to embed the execution of the MIKE 1D engine in a user defined system or user defined GUI.

The example RunExamples.cs shows how to lead the controller through the different simulation phases:

// The controller factory 
Mike1DControllerFactory controllerFactory = new Mike1DControllerFactory();
IMike1DController controller = null;

// Diagnostics object receiving errors, warning and hints
Diagnostics diagnostics = new Diagnostics("My Diagnostics");

// Load. Creates a new Mike 1D controller and loads the setup
var connection = Connection.Create(setupFilePath);
controller = controllerFactory.OpenAndCreate(connection, diagnostics);
if (diagnostics.ErrorCountRecursive > 0)
    throw new Exception("Loading errors, aborting");

// Now the MIKE 1D data is available and the model setup can be modified
Mike1DData mike1DData = controller.Mike1DData;

// Validate. Returns a new diagnostics object
IDiagnostics validated = controller.Validate();
if (validated.ErrorCountRecursive > 0)
    throw new Exception("Validation errors, aborting");

// Initialize simulation
controller.Initialize(diagnostics);
if (diagnostics.ErrorCountRecursive > 0)
    throw new Exception("Initialization errors, aborting");

// Run the simulation
controller.Prepare();
controller.Run();
controller.Finish();

DHI.Mike.Install

Any program or script working with the MIKE 1D engine must be able to locate the entire set of MIKE 1D engine libraries. The MIKE 1D engine libraries is a mixture of .NET assemblies, native libraries (all with the .dll file extension) and various configuration files. These files resides in the MIKE installation folder, i.e. it requries either a MIKE Zero or a MIKE+ installation in order to work. To ease the process of locationg these files, the DHI.Mike.Install is available. The following code will set up the searching for both .NET assemblies and native libraries, such that they are available for the program or script, in this case loading the latest version 20 (Release 2022) of MIKE 1D:

if (!DHI.Mike.Install.MikeImport.Setup(19, DHI.Mike.Install.MikeProducts.Mike1D))
    throw new Exception("Could not find a MIKE installation");

If your program or script is dependent on a specific MIKE installation, replace the DHI.Mike.Install.MikeProducts.Mike1D with either DHI.Mike.Install.MikeProducts.MikeZero or DHI.Mike.Install.MikeProducts.MikePlus.

This code must be executed before any code loading MIKE libraries. Often this can be achieved by having above code in the static constructor of your program.

Creating a Project in Visual Studio

This section describes how to make a small console program that runs a MIKE 1D setup.

Prerequisites:

  • A MIKE Powered by DHI product that includes the MIKE 1D engine

  • Visual Studio, the free Express version should suffice.

To create and setup a project in Visual Studio:

  1. Open Visual Studio
  1. Visual Studio: Select ‘File’ – ‘New’ – ‘Project’ and select a ‘Visual C#’, ‘Windows Desktop’, ‘Console App (.NET Framework)’. Find an appropriate name and location for your project.

  2. Right click on the ‘References’ and select ‘Manage NuGet Packages’. Search for DHI.Mike1D, and install the latest version. Do the same for DHI.Mike.Install

Now the project is ready. It has created a ‘Program.cs’ file containing a Program class with a Main function. When adding the appropriate using directives, the MIKE 1D API is readily available.

Example, modify the ‘Program.cs’, to contain:

using System;
using DHI.Mike1D.Generic;
using DHI.Mike1D.Mike1DDataAccess;

namespace ConsoleApplication
{
  class Program
  {
    static Program()
    {
      // This setup method will make your application find 
      // the MIKE assemblies in the installation folder at runtime.
      // It must be called BEFORE any method using MIKE libraries 
      // is called, i.e. it is not sufficient to call it as the 
      // first thing in that method using the MIKE libraries. 
      // Often this can be achieved by having this code in the 
      // static constructor.
      if (!DHI.Mike.Install.MikeImport.Setup(19, DHI.Mike.Install.MikeProducts.Mike1D))
        throw new Exception("Could not find a MIKE installation");
    }

    static void Main(string[] args)
    {
      SimulationWorker worker = new SimulationWorker(new FilePath(args[0]))
      {
        SimulationParameters = new SimulationParameters()
      };

      // Load data and run simulation
      worker.Work();
    }
  }
}

This will run a simulation of the setup with the filepath specified in the input argument.

MIKE 1D NuGet packages

On (nuget.org) a number of MIKE 1D packages are available. The MIKE 1D NuGet packages are build-only packages, i.e. they contain what is required to build .NET applications in Visual Studio. They are not runtime packages, so in order to run or debug a program or a script, a full installation of MIKE is required.

An exception from that is the DHI.Mike1D.ResultDataAccess and DHI.Mike1D.Generic (reading of 1D result files, res1d, res11, prf, crf etc.), which are self contained and does not require a MIKE installation, making it is possible to make tools for reading and writing result files independent of a MIKE product.

When making a program or a script that runs the MIKE 1D engine, the .NET runtime will by default not find the MIKE installation and the missing runtime files. To ease that process, the DHI.Mike.Install is available. Check out the section on DHI.Mike.Install for details on how to use that.

MIKE 1D additional parameters

MIKE 1D supports some special additional parameters. These can be entered when starting the engine from the command line. In MIKE+ they can entered in Simulation - MIKE 1D Engine Configuration - Custom Options

The list below specifies for each additional parameter its name, type and default value in parenthesis.

  • AllowPMMultipleTailNodes : boolean (false) : Allow multiple tail nodes connected to the same pressurized section.
  • AutoPMOutlet : boolean (false) : Automatically mark an outlet as a tail node, in case the outlet is connected to a pressurized section.
  • CrfCatchmentConnections : boolean (false) : When RR input is in the form of a .crf file, use the catchment connection information inside the .crf file, and disregard catchment connection information in the setup.
  • FillUpPressurized : boolean (true) : Fill up depression inside the pressurized sections.
  • FillUpPressurizedToTop : boolean (false) : Fill up depression inside the pressurized sections, to the top of the pressure links.
  • HyperThreadingTest : boolean (true) : Perform test to check if hyper-threading is enabled.
  • HyperThreaded : boolean (false) : If you know your system is hyper-threaded, you can set this option to always take this into account.
  • UBG : boolean (false) : Store dfs0 and res1d result files in UBG units.
  • dfs0UBG : boolean (false) : Store dfs0 result files in UBG units.
  • ResultFilePostFix : string : Post-fix to append to all result file names. An easy way to change name of all result files in one go.
  • UHMLimitHydrographToSimulation : boolean (false) : Limit UHM hydrograph to length of simulation. Backward compatibility flag.
  • UHMMaxNumberOfCells : integer (0) : Maximum number of cells in UHM hydrograph. This will not override the property of each UHM catchment, but will be effectuated for all UHM catchments where this has not been specified.

MIKE 1D engine components

The MIKE 1D Data components comes in two variants, Data Access components and Data Module components. The goal of these components is to provide easy access to model setup, in programs or through scripting. The engine, the GUI and other users all access the model setup through these data components. They can alleviate the need to edit directly and/or manually in the setup files.

The Data Access components are, in principle, simple data containers without business logic, while Module components contain various functionality used elsewhere, especially by the engine.

For example, the HDParameterData class is in the HDParameterDataAccess namespace; it mainly contains information about initial conditions and solver settings which are all accessed via getters and setters. There are almost no functions in the classes.

In contrast, the CrossSectionData class in the CrossSectionModule namespace contains a host of functions that both operate on the cross sections data itself (for example to create processed data) and logic to help the HD module find specific cross sections and values on individual cross sections as a function of water level.

Data Access components:

  • HDParameterDataAccess
  • Mike1DDataAccess
  • NetworkDataAccess
  • ResultDataAccess

Data Module components:

  • BoundaryModule
  • ControlModule
  • CrossSectionModule
  • DataAssimilationModule
  • RainfallRunoffModule
  • StructureModule

Each of these components will be described in later sections.

DHI.Mike1D.Engine

The DHI.Mike1D.Engine is in charge of a network simulation. It contains a static part, the EngineNet, which defines the reaches and the nodes of the network. It contains data that does not change in time. The dynamic part of the engine, i.e. that which changes over time, is contained in a number of modules.

The HD Module is the central module. It is responsible for the hydro dynamics of the simulation. It is possible to navigate around in the HD Module and extract various values from the nodes and grid points.

Proxy system, extracting values from Engine

The proxy system eases getting and setting values to the engine. The proxy system works independently of where the value belongs (which module), and provides the user with a delegate (function pointer) that extracts value directly and efficiently from deeply inside the engine.

Be aware that the delegate extracts values efficiently, but it is somewhat expensive to get hold of the delegate. The proxy system is designed like this; the user should set up all functionality initially, and store all delegates that are required, and during the simulation, the delegates can be used without further use of the proxy system.

It is possible to query the proxy system for what is available. The proxy.Offers() will list all quantities that a given entity offers. Similarly the proxy.Accepts() will list all quantities that can be set on that entity. When the appropriate quantity is found, use the value getter or value setter to get the delegate.

proxy.ValueGetter(quantityIndex);
proxy.ValueSetter(quantityIndex);

The list of offers matches the value getters, and the list of accepts matches the value setters.

Below is an example of how to extract a value getter.

// Extract a getter, and store that for later use. This should only be done once,
// and the getter should be reused. This should NOT be done everytime a value is required.

DDoubleGetter getter;

// Proxy system helper class.
var proxyUtil = new ProxyUtil(engineNet);

// Get proxy for some node
IDoubleProxy nodeProxy = proxyUtil.GetProxy(engineNet.Nodes[0]);

// Get index of water level quantity
quantityIndex = nodeProxy.Offers().IndexOf(Quantity.Create(PredefinedQuantity.WaterLevel))

// Getter for water level quantity
if (quantityIndex >= 0)
{
    getter = nodeProxy.ValueGetter(quantityIndex);
}

// To get the value.
double value = getter()

Value getters and setters can be extracted after the simulation has been initialized.

DHI.Mike1D.Generic

This component contains many individual classes that are used throughout the MIKE 1D engine.

Quantity

The quantity class describes a type of value in the engine. To describe a water level, the quantity has a unique id, a description and a EUM type and unit. By default the unit is the SI unit, or to be exact, the EUM first registered unit.

Some units are predefined. Reuse of the predefined units is important for performance reasons (since string comparisons are expensive). To create one of the predefined units, use

Quantity.Create(PredefinedQuantity.Discharge)

When selecting quantities for result files, they are selected based on ID. Two quantities with same ID and different description is perfectly fine, meaning that they describe the same kind of quantity but may belong to different objects, as e.g. if selecting the quantity id FlowVelocityInStructure, the description can contain the name of the structure and be different for different structures.

Diagnostics

The diagnostics system is used for reporting messages while running. The Diagnostics class can handle errors, warning and hints. A Diagnostics class usually contains child classes, build up in a tree-like structure, often matching the data structures being examined. In this way it is possible to trace messages and which data objects they belong to.

Messages are added to the Diagnostics as IDiagnosticItem, the current implementation being DiagnosticItemID, which extracts the error message from the internal set of error messages based on an id. A diagnostics item can have any number of values attached, that can be reported in the message string, inserted in the string as when formatting a string. An example of an error string could be:

"Start of reach {0}, {1} is {2} outside span of cross sections"

That message requires 3 values and can be added as follows:

diagnostics.Warning(
new DiagnosticItemID("EN_WAR_IdOfMessage",
reach.LocationSpan.ID,
new DiagnosticsValue(startChainage, eumItem.eumIRiverChainage),
new DiagnosticsValue(outChainage, eumItem.eumIRiverChainage)));

All values must be added in SI units, or to be precise, the EUM first registered unit. When values are copied into the message string, they are reported in user units.

For version 2016, user defined error messages are not implemented, but a user implementation of the IDiagnosticItem interface is fairly straight forward to make.

DHI.Mike1D.Mike1DDataAccess

The Mike1DData data Access component collects all data components in one instance. It contains reference to other data components, and holds central information on what to run and which modules to use:

  • Id and description of model, projection.
  • Which modules to use, i.e. HD, AD, RR etc.
  • References to data access and module components.
  • Result specifications, i.e. which files to write and what to put in them.
  • Simulation start and end, and timestepping info.

DHI.Mike1D.NetworkDataAccess

The network data component contains the network topology. Read Section 2 of the MIKE 1D Reference, “Overview of Network Geometry”, for an introduction to the various network components.

The network is available through the INetwork interface from the Mike1DData object.

mike1DData.Network

Overview of Network Geometry

A network consists of

  • Reaches
  • Nodes
  • Grid points
  • Digi points
  • Cross sections
  • Structures

Figure 2 shows an example of a small network with four nodes and three reaches, each having different grid points and digi points. The shapes of cross sections or structures are not shown.

alt text

Figure 2 Network example

A cross section is the 2D intersection of a channel, typically a river or a sewage pipe, perpendicular to the channel direction. Among other things, cross sections determine the volume of water in a channel for a given water depth.

A structure is a parameterised model that can calculate a flow over or through the structure based on an upstream and downstream water level. Examples are weirs, gates, orifices and pumps.

Reaches

A reach is a one-dimensional connection between two nodes in a network.

The reach has many synonyms within different domain applications. In sewer models it is often called a link or pipe, in river models a branch, stream, canal or channel, and in graph and network theory it is called a link or an edge.

A position along a reach is given as the distance from a reference “start” point on the reach. This distance is called a chainage.

The start of the reach is defined as the point in the reach with the lowest chainage. And the end of the reach is defined as the point with the highest chainage. The terms start and end of reach is therefore defined based on low and high chainage values, which does not necessarily correlate with the direction of water flow in the reach. HOwever, it is recommended to specify the start-end in the direction of predominant flows.

A reach also has an upstream end and a downstream end. These are defined based on the direction of natural flow (part of the reach specification): If the flow is naturally in the direction of increasing chainages, the upstream matches the start of the reach and the downstream matches the end of the reach. If the flow is naturally in the direction of decreasing chainages, the upstream matches the end of the reach and the downstream matches the start of the reach.

A location is a position along a reach, and is defined by the reach name and a chainage value.

The reach comes in three variants

  • Normal reach – Reach.
  • Structure reach – StructureReach.
  • Routing reach – RoutingReach.

The structure reach is a special reach that does not contain any volume and its length is arbitrary. It does not have any cross section info. It is used in sewers for connecting two sewer nodes (manholes) with a structure, and in rivers for link channels.

Nodes

Points associated with reach ends and reach junctions are called nodes. Each reach has one node in each end. A node is associated with at least one reach, but an arbitrary number of reaches can be attached to a single node, defining the junction of all the reaches. A node is always present in a junction in the network.

Nodes can be volume free; then they function as simple junctions that connects two or more reaches, called a junction node. A junction node does not have any qualitative impact on the flow it passes the node

Nodes can also have a volume, as for example a manhole in a sewer, in which case the volume is considered during the calculation. When water flows through such a node, the node will usually impose additional flow resistance; the water will lose some energy while passing the node. Flow resistance and energy loss in a node is called headloss

Volume-free nodes with only one reach are called boundary nodes. In boundary nodes, a boundary condition must be specified. A boundary condition can, for example, specify a water level.

Nodes can be one of several different types:

  • Manholes
  • Basins
  • Outlets
  • Junction nodes, a volume free node (seldom used).

A node has a geographical (x,y) position. It can also have an identification string, which is used when inflow is to be added to the node, or attaching a structure to the node.

A node is a computational point, and contains a water level.

Grid Points

Grid points are the computational points in a reach. At each grid point a dependent variable is defined. For a flow model this is either water level or discharge.

Grid points are created automatically based on cross section data and the MaximumDx parameter, hence a Reach does not contain any grid point data.

A reach has several grid points along its length, at certain locations. Grid points do usually not coincide with the digi points. To get the geographical coordinate of a grid point, the grid point’s chainage value is used to interpolate along the digi point coordinates.

A flow model has different types of grid points:

  • H grid point. The water level is defined in the H grid point. It also has an associated cross section.
  • Q grid point. The discharge or flow velocity is defined in a Q grid point.
  • Structure grid point. A structure grid point has an associated structure, that calculates the discharge over the structure depending on the water levels on each side of the structure.
Digi Points

Digi points are the georeferencing of a reach, and are defined in cases when the reach is not a straight line between two nodes. A reach can have from two to any number of digi points, though the first and last digi point should (approximately) match the coordinate of the nodes (if not, coordinates of the nodes are added as the first/last digi points).

Each digi point has a (x,y) geographical coordinate and a reach chainage. The chainage defines the location of this digi point along the reach. In effect a digi point couples a reach location to a geographical (x,y) coordinate.

A digi point can also specify a z-coordinate, in which case it defines the bottom level of the reach. If the cross section data also specifies a bottom level, the cross section bottom level overrules the digi point bottom level.

A reach location span StartChainage and EndChainage values cannot be modified directly, they are derived from the chainage values in the digi points. Changing the digi point chainages will automatically update the start and end chainage values.

DHI.Mike1D.CrossSectionModule

A cross section defines the profile across the reach (perpendicular to the flow direction) at a location or for an entire reach. It provides the width, area and other properties of the profile for any water level. From the point of view of the engine a cross section is to provide the functionality defined by the ICrossSection interface.

The ICrossSection does not necessary know anything about the real geometry of the cross section, whether it is circular, rectangular open or closed, but can be based on tabulated values or formulas.

The ICrossSection can have a BaseCrossSection that it delegates its work to. The BaseCrossSection derives from the abstract XSBase class which is based on tabulated values, the “processed data”. In the MIKE 1D all cross sections have a base cross section.

The MIKE 1D engine distinguishes between the ICrossSection classes and the XSBase classes by whom is handling location specific functionality and who is handling non-location specific functionality, i.e. data in the ICrossSection implementation is location specific, while data in the XSBase need not be location specific. Example: A cross section profile that is common for several locations can be put in the base cross section, and a number of cross section at different locations can refer to the same base cross-section. A typical usage is sewer links, which has the same cross section throughout the link, and reusing the same XSBase instance.

Naming conventions is that all classes that implement the ICrossSection interface starts with CrossSection, while all classes extending the XSBase class starts with XS.

The XSBase class is an abstract class. Each of its extensions implement a special type of geometry:

  • XSOpen: Open cross section of any form
  • XSPolygon: Closed cross section of any form
  • XSCircular: Closed circular cross section (river version)
  • XSCircularPreprocessed: Closed circular cross section that comes in various versions, egg-shaped, o-shaped and circular (sewer version)
  • XSRectangular: Closed rectangular cross section (river version)
  • XSRectangularPreprocessed: Open rectangular cross section (sewer version)
  • XSProcessedInterp: A cross section that has been interpolated. It contains only processed data, i.e. no physical geometry.

Cross Section Database

Cross sections are stored in the CrossSectionData class. Data in the CrossSectionData class can be loaded from and written to the xns11 file format.

The CrossSectionData is a database of cross sections. A cross section is indexed by:

  • Topography id.
  • Reach id
  • Chainage

The topography id is used to handle different scenarios. Example: A river was measured in 1980 and again in 2000. Both set of data can be entered into the same cross section database, the first set with a topography id of 1980, the other with the topography id of 2000. Whenever searching for cross sections or interpolating between existing cross sections, the topography id must be provided to specify which data set to use.

Apart from the topography id, the cross sections can be indexed in two ways: either by their reach id and their chainage, or by their reach id only.

Reach id and chainage: On a given reach there can be many cross sections for different chainages. The bottom level is defined by each cross section individually.

Reach id only: On a given reach you can specify one cross section that is valid for the entire reach. The bottom level of the reach is specified by the network, setting z-coordinates for the digi-points.

In the cross section database a base cross section should never be reused for several locations.

DHI.Mike1D.HDParameterDataAccess

The HDParameterData object contains various parameters for the HD module of the engine. It contains

  • Initial conditions, hotstart files.
  • Wave approximation
  • Additional outputs
  • Flood map info.
  • HD solver settings and options.

The HDParameterDataAccess library contains the ADComponentData object, used for setting up component transport calculations in the MIKE 1D engine.

The HDParameterDataAccess library contains the EcoLabData object, used for setting up ECO Lab connections to the MIKE 1D engine.

DHI.Mike1D.BoundaryModule

The Boundary Module contains all external model inputs, as e.g. HD model boundaries and inflows.

For a HD model, it contains

  • Open and closed boundaries: Water level, discharge, Q-h relation.
  • Lateral inflow in point or on span.
  • Rain, evaporation and wind.
  • Input for structures: Dam breach time series.

For the AD module it contains component concentrations and loads for the various HD boundaries.

For RR catchment, it contains all input time series, rain, evaporation, degree-day coefficients, abstraction etc.

The boundaries are available through the IBoundaryData interface from the Mike1DData object.

 SimulationWorker worker = new SimulationWorker(new FilePath(filename))
 \[...\]
 Mike1DData mike1DData = worker.Mike1DData;
 IBoundaryData boundaryData = mike1DData.BoundaryData;

It contains the following types of boundaries:

  • Open source boundaries: It contains boundary conditions for end points of the HD model.
  • Point source boundaries: Inflow at points to the HD model, at either nodes or locations.
  • Distributed source boundaries: Inflow at spans to the HD model.
  • Global boundaries: A typical global boundary is rain. These are used for both HD and RR.
  • Structure boundaries: Input to structures in the HD module.
  • Catchment boundaries: Input to catchments in the RR model.

All of these boundaries are implemented in a set of boundary source classes.

Open boundaries

An open network boundary is where the network in the model ends, but the real world case continues, i.e., the up or downstream end of a river, an outlet or similar. An open network boundary can be defined in two ways:

  1. As an open boundary specified at the end location of the reach.
  2. As an outlet in the network data and an open boundary for that outlet.

Note especially that a node with volume can never be an open network boundary.

There must be exactly one boundary source for each open network boundary. It is possible to specify the open boundary as Closed, which is the same as specifying that the open boundary should be handled as if it was not an open boundary, effectively putting a wall at the location.

Boundary sources

For each type of boundary source there is a dedicated implementation

  • OpenSourceBoundary

  • PointSourceBoundary

  • DistributedSourceBoundary

  • GlobalSourceBoundary

  • StructureSourceBoundary

  • CatchmentSourceBoundary

Each type of boundary implements the generic IBoundarySource interface. The IBoundarySource provides the basic functionality required by the engine. From the engine point of view, any implementation of the IBoundarySource suffices.

Figure 6.1 IBoundarySource interface

All boundary classes in the boundary module extend from the AbstractSourceBoundary. The AbstractSourceBoundary provides a list of IBoundaryItem‘s. A boundary item can be a constant, a timeseries etc. The AbstractSourceBoundary adds the ability to create a source utilizing several items. If a source has more than one item, it is up to the source type to decide whether it is allowed for the items to overlap in time, whether to sum up their contribution, or whether at any time only one item can be active.

Boundary Item

The IBoundaryItem holds one set of data.

Currently available boundary items are:

  • Constant – BoundaryItemConstant

  • Time series – BoundaryItemTimeSeries

  • Periodic daily – BoundaryItemPeriodic

  • Periodic montly – BoundaryItemPeriodicMonthly

There are also a few special boundary items

  • Q-h boundary – BoundaryItemQH, a boundary that does not vary in time.

  • RR result file time series – BoundaryItemRRResult.

Most items implements the IAdvancedBoundaryItem interface by extending the AbstractBoundaryItem class, which handles

  • Application interval

  • Soft start

  • Scaling factor

An IAdvancedBoundaryItem can tell whether the item is applicable for that given time and get a value for that time. A boundary source will usually loop over all its items, check which items are applicable and apply those items accordingly.

Periodic Boundary Item

A periodic boundary item is an item that repeats in a daily fashion, averaging over one day to a given value, but the value over the day varying by a specified profile.

A IBoundaryItemPeriodic contains an average day value and an IPeriodicScheduler with a set of pairs of IPeriodicSchedule and IOneDayProfile.

A IOneDayProfile is a pattern that varies over one day. And the IPeriodicSchedule defines which days a given IOneDayProfile is active.

For a given date/time, the periodic boundary item looks through its list of schedules, and for the first active schedule found, its profile will be used. The average value will be multiplied with the profile value for that time of the day.

One day profile

The OneDayTsProfile is the default implementation of the IOneDayProfile. It contains a list of pairs of time-of-day times and values. The times are assumed to cover an entire day (24 hours). Interpolation takes place over the 24 hour boundary as well.

The profile can be absolute or relative. In case it is relative, a scaling factor is applied, such that accumulated/integrated the profile over one day amounts to 1. Using a relative profile, the average value specified in the periodic boundary is a daily average value, allowing the value to vary within the day.

Schedule

In a schedule you define individually which of the days (1-31), months (1-12) and weekdays (Monday-Sunday) that the schedule it is active. All checks must return true before a schedule is active.

When checking for a given date/time, also the weekday is provided explicitly. The weekday of a given date may have been overridden by a special day.

Special day

The IPeriodicScheduler also contains a list of IPeriodicSpecialDay. In a special day, you can define a date that should be handled as another weekday. An example of usage is to specify that days like Christmas, holidays or similar should be handled as if they were a Sunday, even though they are not. A special day can be unique or repeat yearly.

DHI.Mike1D.StructureModule

A structure calculates either a discharge or an additional head loss between two water volumes. The structure calculation is based on the water levels, i.e. from the water levels of the two volumes, the structure calculates a discharge. For energy-loss structures, it may also depend on water velocity. The structure can be positioned in a few different ways:

  • On a reach: The structure will be located on a q-grid point, and the surrounding h-grid points are providing the water level and velocity for the structure. This is the river (MIKE HYDRO/MIKE 11) type of structure.

  • Between two reaches: The structure uses the water levels in each of the two reaches to calculate the discharge. The velocity is not available, since the structure is perpendicular to the common flow direction. This is the case for structures on link channels in rivers (MIKE HYDRO/MIKE 11).

  • Between two nodes, mostly manholes: The structure uses the water levels in each of the nodes to calculate the discharge. The velocity is not available. This is the MIKE URBAN type of structure.

For the first one, the structure is located on the reach, and it is a special q grid point on the reach that handles the structure. For the latter two, the structure is positioned at a special “structure-reach”. Compared to an ordinary reach, the structure reach does not contain any volume. A structure reach contains 3 grid points, the first and the last being “dummy” h-grid points containing the water levels of the start and end node, and the middle grid point is the structure grid point.

All structures implement the IStructure interface. The Structure class provides a basic implementation, and can be used as a base class for user defined structures.

This example shows a simple implementation of the Honma weir structure.

DHI.Mike1D.ControlModule

The control module is a generic module capable of controlling various quantities as e.g. gate levels in gate structures.

Each controllable entity in a simulation is controlled by a state machine that is responsible for setting the control values of that controllable structure.

A State Machine can be in one of several pre-defined states. Each state performs one action (which can last several time steps). Examples of actions are to close a gate, or apply a PID control to the discharge over a weir.

Each state also has a transition table. At each time step, the current state will examine its transition table to evaluate whether another state should be activated and become the current state, and hence apply a new action.

alt text

Figure 3

Logical condition

The LogicalCondition is a mathematical expression that evaluates to true or false. The mathematical expression is very general; it supports a comprehensive set of mathematical functions and operators, special MIKE 1D engine functions, and can extract values from sensors in the model.

State transitions

The state transition table in a state has a list of LogicalCondition and matching states.

The transition table is evaluated from top down, and the first logical condition to evaluate to true will trigger a state transition (if the state is different from the current state). If no condition evaluates to true, no transition happens and the current state remains current.

MIKE 11, MIKE HYDRO and MIKE URBAN applies two practices

  • The last logical condition always returns true.

  • All states use the same state transition table.

Sensors

Sensors are capable of extracting values from the engine. In the expressions, sensors are variables and entered in square brackets, i.e. in a logical condition expression:

"[SensorD5] + 1.5 > [SensorD2]"

The text in the square bracket is the sensor id. The ControlData stores also the SensorDescription, which for a given sensor describes what to extract and where to extract it from. The SensorDescription has a quantity and a location or id. Examples of sensors:

  • Water level in a manhole

  • Discharge at a location (reach+chainage)

  • Gate level of structure.

  • Water level upstream of structure.

Actions

The actions are changing a control quantity in the model, as e.g. a gate level. An action is implementing the actual control algorithm.

The following types of actions are available:

  • No operation – ActionNoOperation. Does nothing.

  • Activate – ActionActivate. Starts a pump, closes a gate.

  • Set – ActionSet. Sets a value, gate level, pump start level.

  • Set-2 – ActionWith2Setters. Sets two values.

  • Change – ActionChange. Changes a value.

  • PID – ActionPID. Advanced PID control.

The ControlData stores a list of all actions, and a list of ActionTargetDescription.

The ActionTargetDescription describes where the action is to attach, usually the id of the structure, and what to control, the TargetControl. The TargetControl string is often just "set", in cases where there is only one thing to control. Some targets have several quantities that can be controlled, e.g. the pump has discharge, start level and stop level, which can all be controlled.

The Set and Change action has a mathematical expression for the value to set/to change with. The Set-2 action has two mathematical expressions.

The PID action has a reference expression, often called the set point, and a regulated expression which is measured from the model. It works by modifying the control trying to get the regulated expression match the reference set point expression.

The mathematical expressions in the actions are very general; they support a comprehensive set of mathematical functions and operators, special MIKE 1D engine functions, and can extract values from sensors in the model.

Tables and time series

In the mathematical expressions it is possible to look up in predefined tables and time series.

To look up a value in a time series, the ControlData stores a list of TimeSeriesInfo by id, i.e. a time series id refers to a time series file and an item in that file. To use that time series in an expression, use:

"TSLookup('ts-id')"

which will look up in the time series with the given id using the model simulation time.

Similarly, to look up a value in a table, the ControlData stores a list of tables by id in the form of IAnyTable. To use that table in an expression, use:

"TableLookup('table1', [dischargeSensor])"

which will look up in the table with the given id using the value of the [dischargeSensor] as look-up value. The common use of the IAnyTable is the XYTable, storing pairs of x and y values. It is assumed that the x values are monotonically increasing, making searching and interpolation possible.

Adding a user defined function

The MIKE 1D control module is utilizing the mathematical expressions of the MathExpression class for logical conditions and action values.

The DHI.Math.Expression library has a large set of mathematical standard function, time functions etc, see XXX for details.

On top of that the MIKE 1D engine adds a number of engine specific functions, for details view XXX

It is possible to add user defined functions to be used during the simulation, making it possible to enter expressions like:

"MyFunction([dischargeSensor])"

In a script or plugin, it is possible to register a user defined function. And then this new function can be used in expressions in e.g. the MIKE+ or MIKE HYDRO editor. The validation in the editors will usually fail, stating that the new function could not be found. But the registration will assure that the MIKE 1D engine recognises the new function and runs as expected.

For an example of such a function, take a look at the ControlFunctionTable2D.cs file.

DHI.Mike1D.RainfallRunoffModule

The DHI.Mike1D.RainfallRunoffModule component contains many catchment models. All catchment models implement the ICatchment interface.

The RainfallRunoffData class collects all catchment data for one simulation. It is available through the MIKE 1D data class

mike1DData.RainfallRunoffData

The rainfall runoff (RR) module can run either standalone or in parallel with an HD simulation. When run standalone, the RR module handles time stepping of all catchments. When run in parallel with an HD simulation, the RR module is a slave of the HD module: The HD module will request data at specified times, and the RR module updates accordingly.

Catchments in the RR module need not run with the same time step. Especially, there are catchment implementations which utilize adaptive time steps that can turn to very long time steps when there is no water in the model. Hence, each catchment runs individually, independent of other catchments in the simulation.

Connecting catchments to network

Connections from catchments to a HD network are specified in the Network. The Network contains the catchment-connections.

mike1DData.Network.CatchmentConnections

A catchment-connections specifies a catchment id, a connection point as a location or a span, and how big a fraction of the total catchment that is connected to this point. There can be more than one catchment connection associated with a single catchment.

There is a special flag on the catchment connection called IsOverlappingRiverArea. This can only be set if the connection type is a span. If that is set, it is assumed that the catchment and the river are overlapping along the span of the connection. The surface area of the river is subtracted from the catchment before runoff is calculated, effectively meaning that the area of the catchment varies in time.

In an AD simulation, it is possible to specify a concentration of the runoff flow. The concentration is specified in the boundary module,

mike1DData.BoundaryData.CatchmentComponentSourceBoundaries

Implementing custom catchment models

The MIKE 1D engine comes with a handfull of catchment models, but there is a big variety of catchment models being applied in different parts of the world. It is possible to implement a custom catchment model, and inject that into a MIKE 1D simulation. An example on how to implement a custom catchment model, somewhat similar to the Kinematic Wave catchment (Model B) is available here:

In the CatchmentComponentSourceBoundary it is possible to specify a concentration for one or more AD components and for one or more catchments.

DHI.Mike1D.ResultDataAccess

The DHI.Mike1D.ResultDataAccess component provides common access to a variety of network file formats. It is the main data access component for the MIKE 1D result files, having the .res1d extension. It does also provide support for reading result files from MIKE 11 and MIKE URBAN/MOUSE. Files supported, listed by extension:

  • .res1d: Result file from MIKE 1D engine. Can contain HD, AD or RR results.

  • .res11: Result file from MIKE 11 engine. Can contain HD, AD or RR results.

  • .prf: HD result file from MOUSE engine

  • .crf: RR result file from MOUSE engine.

  • .trf: AD result file from MOUSE engine

  • .xrf: Cannot remember.

  • .nof:

  • .?:

A result file is loaded as follows:

 IResultData resultData = new ResultData();
 resultData.Connection = Connection.Create(@"C:\\Work\\myResults.res1d");
 resultData.Load();

The IResultData contains static data and dynamic data. The static data is the network topology. The dynamic data are the actual simulation results; one or more quantities for several time steps. The network topology is called static because it does not change with time.

Dynamic data can exist on the following geometric types:

  • Nodes, through IRes1DNode.

  • Reaches, through Res1DReach. Each reach contains grid points.

  • Catchments, through IRes1DCatchment.

  • Global data, through IRes1DGlobalData.

The interfaces above all inherit from the IRes1DDataSet interface. Each data set contains a set of IDataItem.

A IDataItem handles data for one quantity. Data exists in time and in space. All data items in one IResultData component must have the same number of time steps, time specification for the data is to be found in the IResultData.TimesList.

The IDataItem for nodes, catchments and global data only contains one value per time step.

For reaches the IDataItem stores values for several grid points. The IDataItem.IndexList specifies which grid points each value in the IDataItem belongs to. I.e. on a reach with 5 grid points, 3 H points and 2 Q points, a water level item will have an IndexList with values [0, 2, 4] indicating that the 3 water level values values belong to grid point at index 0, 2 and 4, being all the H grid points in the reach. The discharge data item will have an IndexList with values [1, 3].

A typical HD result file contains all nodes and reaches. Each node will contain one data item containing water levels. Each reach will contain two data items, water level and discharge. The water levels are stored on the H grid points while the discharges are stored on the Q grid points.

UML diagrams for:

  • IRes1DDataSet with Nodes, Reaches, Catchments, Global Data

  • IRes1DNode with SewerNode, Outlet, Basin and Manhole

  • IRes1DCrossSection

Mention also

  • the IRes1DReach.DigiPoints which contains the actual reach geometry, the grid points also have x,y coordinates but they are interpolated from the digi points.

  • IsStructureReach

DataModule

The data module is a generic module for storing/providing data associated with the network. Data contained in the data module can also be stored to a result file (res1d).

The DataModule can store data for quantities. Each quantity is contained in an IEngineDataItem. The IEngineDataItem interface provides data for different geometric types:

  • Node

  • Reach – data is bound to grid points.

  • Generic/global data.

I.e. you can store or retrieve data on these geometric types.

You can ask an IEngineDataItem interface whether it contains data for a specific geometric type, and if so, you can request the data, which will return a type of IEngineData. The IEngineData holds/provides the actual data for the geometric type. The IEngineData implementor needs not support setting of the ElementValues, if data is read only.

The DataModule implements the IModule interface, thereby being able to provide its data through the Proxy functionality, e.g. for storing data in a result file.

In the DataModule there are default classes implementing above interfaces for storing data in the network. To make a new quantity available through the DataModule, there are two ways:

  • You can store the quantity data in the default implementing classes, where a vector of the data needs to be updated at the end of each time step.

  • You can create a class implementing the IEngineData interface and calculate the data on request (for lazy evaluation).

The DHI.Mik1D.Examples.DataModuleExamples.cs contains an example of how to store a value on all nodes.

MIKE 1D Plugins

The MIKE 1D engine provides a plugin functionality. A plugin injects user-defined functionality into the MIKE 1D engine.

A plugin must implement the IMike1DPlugin interface. Here is an example:

namespace DHI.Mike1D.Example.Plugins
{
  public class MyPlugin : IMike1DPlugin
  {
    public void Initialize(IList<Mike1DPluginArgument> arguments, Mike1DData mike1DData)
    {
      //  Change simulation end-date before running the simulation
      mike1DData.SimulationEnd = new DateTime(2017, 12, 19, 10, 30, 0);
    }
  }
}

See more examples here.

Using a .m1da file to enable the plugin

The .m1da file contains additional data for a setup. The .m1da file must have the same name as the original setup, but just have another extension.

The .m1da file is automatically loaded when starting a simulation, independently if starting the simulation from within MIKE+, MIKE HYDRO, from batch or from the command line.

Here is an example from the UnitFlow example of an .m1da file that loads a user defined plugin:

[MIKE1DAdditional]
   format_version = 100
   [Plugins]
      [Plugin]
         AssemblyName = '..\..\DHI.Mike1D.Examples\bin\Debug\DHI.Mike1D.Examples.dll'
         ClassName = 'DHI.Mike1D.Examples.PluginStruc.StructurePlugin'
         [Arguments]
            Struc = 'MyStruc-Main-500-UniqueId;Main;500;BranchTopoID;6;0.3;1.8'
         EndSect  // Arguments         
      EndSect  // Plugin
   EndSect  // Plugins
EndSect  // MIKE1DAdditional

The example shows how to inject a user defined structure into a MIKE 11 setup, and it will be included also when running the simulation from the MIKE 11 GUI.