Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
scrollbar

h2. Exercise outline

The goal of this exercise is to create a simple hydrological volume model. In the end it should be possible to run the volume model and inspect some (very simple) spatio-temporal output results.


h2. Create a new model class

Add a new folder to the plugin project named _Models_. In this folder, create a new class named _VolumeModel.cs_ and add the following code:

{code}
using System;
using System.Linq;
using DelftTools.Functions;
using DelftTools.Functions.Generic;
using DelftTools.Hydro;
using DelftTools.Shell.Core.Workflow;
using DelftTools.Shell.Core.Workflow.DataItems;
using log4net;
using NetTopologySuite.Extensions.Coverages;

namespace DeltaShell.PluginsPlugin.VolumeModel.Models
{
    public class VolumeModel : ModelBase
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(VolumeModel));

        private readonly DrainageBasin basin;
        private readonly TimeSeries precipitation;
        private readonly FeatureCoverage volume;

        /// <summary>
        /// Creates a volume model
        /// </summary>
        public VolumeModel()
        {
            // Create the input items of the volume model
            basin = new DrainageBasin();
            precipitation = new TimeSeries { Components = { new Variable<double>("Precipitation") } };

            // Create the output item of the volume model
            volume = new FeatureCoverage("Output data")
            {
                IsTimeDependent = true,
                Arguments = { new Variable<Catchment>("Catchment") { FixedSize = 0 } },
                Components = { new Variable<double>("Volume") },
            };

            // Wrap fields as input/output data items
            DataItems.Add(new DataItem(volume, "Volume", typeof(FeatureCoverage), DataItemRole.Output, "VolumeTag"));
            DataItems.Add(new DataItem(basin, "Basin", typeof(DrainageBasin), DataItemRole.Input, "BasinTag"));
            DataItems.Add(new DataItem(precipitation, "Precipitation", typeof(TimeSeries), DataItemRole.Input, "PrecipitationTag"));
        }

        /// <summary>
        /// The drainage basin (set of catchments). Input of the model.
        /// </summary>
        public DrainageBasin Basin { get { return basin; } }

        /// <summary>
        /// The precipitation time series: P = P(t) [L/T]. Input of the model.
        /// </summary>
        public TimeSeries Precipitation { get { return precipitation; } }

        /// <summary>
        /// Time-dependent feature coverage containing the volume of water per catchment: V = V(t, c) [L3/T]. Output of the model.
        /// </summary>
        public FeatureCoverage Volume { get { return volume; } }

        /// <summary>
        /// The initialization of model runs.
        /// </summary>
        protected override void OnInitialize()
        {
            // Clear any previous output
            volume.Clear();

            // Ensure the coordinate system of the volume output is the same as the catchments input (basin)
            volume.CoordinateSystem = basin.CoordinateSystem;

            // Check if at least one catchment is present
            if (!basin.Catchments.Any())
            {
                throw new InvalidOperationException("At least one catchment should be present");
            }

            // Check if at least one precipitation value is present
            if (precipitation.Time.Values.Count == 0)
            {
                throw new InvalidOperationException("At least one precipitation value should be present");
            }

            // Initialize the output feature coverage
            volume.Features.AddRange(basin.Catchments);
            volume.FeatureVariable.FixedSize = basin.Catchments.Count;
            volume.FeatureVariable.AddValues(basin.Catchments);
        }

        /// <summary>
        /// The actual calculation during model run.
        /// </summary>
        protected override bool OnExecute()
        {
            // Loop all times
            foreach (var time in precipitation.Time.Values)
            {
                // Obtain the precipitation value for the current time
                var p = (double)precipitation[time];

                // Calculate a volume value for every catchment based on catchment area and precipitation value
                var volumes = basin.Catchments.Select(c => c.AreaSize * p);

                // Add the calculated volume values to the output feature coverage
                volume[time] = volumes;
            }

            return true;
        }
    }
}

{code}

{info}

The model class is derived from the _ModelBase_ class in order to automatically implement some basic time dependent modeling logic.

The comments in the code explain the different parts of the model implementation.
{info}

{note}
The model uses some basic data structures like data items, (feature) coverages and timeseries (functions). A description on the background and usage of these data structures is not part of this tutorial.

{color:#ff0000}*\[TODO\]*{color} {color:#ff0000}Add links to some wiki pages?{color}
{note}

h2. Register the model in the application plugin class

Register the model in the application plugin by adding the following code to _VolumeModelApplicationPlugin.cs_:
{code}
using DeltaShell.PluginsPlugin.VolumeModel.Models;
{code}
and
{code}
        public override IEnumerable<ModelInfo> GetModelInfos()
        {
            yield return new ModelInfo
            {
                Name = "Volume Model",
                Category = "DemoApp models",
                CreateModel = o => new Models.VolumeModel()
            };
        }
{code}

Delta Shell should now be able to detect, create and run volume models.

h2. Exercise results

First of all, download the following WaterML2 XML file: [^WaterML2_precipitation_data.XML]&nbsp;Also download&nbsp;and unzip shape files contained in the following one: [^Gemeenten.7z]&nbsp;You will use all these data along the exercise.

Next, run the application and start creating a new model item (right  click on project \| Add \| New Model ...).&nbsp;Make sure that the new model is selected in the dialog:

!SelectModelDialog.png!

If you next click on OK, a new model item should be  added to the project with a structure as shown in the following image:


!AddedModel.png|border=1!


Try to run the model (right click on the volume model item \| Run Model) and check the _Messages_ window; some error messages should be generated:

!errorMessages.png!


In order to successfully run a model, some precipitation and catchment input data must be available (for example, by importing it).

First, start importing some WaterML2 data on the precipitation time series item (right click the precipitation item \| Import...). A file selection dialog automatically pops up. Select the previously downloaded WaterML2 XML file.

After finishing the import, the precipitation item should contain data as shown in the following image:

!importedTimeSeriesGraph.png|border=1!\\
\\
Next, start importing a shape file on the basin item (right click the basin item \| Import...). A GIS import wizard automatically pops up. Walk through the wizard as shown in the following images:

!wizardPage1.png!&nbsp; !Shape file import from GIS wizard page.png|border=1! !wizardPage3.png! !wizardPage4.png! !wizardPage5.png!
After finishing the import, the basin item should contain data as shown in the following image:

!basinMap.png!


Run the model again and  check the _Messages_ window; no error messages should be generated now.

Open the volume output and check that the model results are like the ones shown in the following image:


!outputCOverage.png!



{info}
In order to inspect time dependent (output) data, open the _Time Navigator_ window and move the slider or click one of the auto play buttons:
\\

!TimeNavigator.png|border=1!
{info}
\\
\\