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 volume model. In the end it should be possible to run the volume model and inspect some (dummy) 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.Plugins.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 derives the _ModelBase_ class in order to automatically implement some basic time dependent modeling logic.

Furthermore, the comments in the code should 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 backgrounds 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.Plugins.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, obtain the following WaterML2 XML file: [^WaterML2_precipitation_data.XML]










Also obtain and unzip the following shape files: [^Gemeenten.7z]

















Then run the application and start creating a new model item (right  click on project \| Add \| New Model ...). Ensure the new model is visible in the model selection dialog:

!SelectModelDialog.png!

After selecting the volume model, a new model item should be  added to the project with a structure like shown in the following image:


!AddedModel.png|border=1!


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

!errorMessages.png!


In order to perform a successful model run, some precipitation and catchment input data needs to be imported.

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 obtained WaterML2 XML file.

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

!importedTimeSeriesGraph.png|border=1!

Secondly, 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 like shown in the following images:

!wizardPage1.png! !wizardPage2.png! !wizardPage3.png! !wizardPage4.png! !wizardPage5.png!



After finishing the import action, the basin item should contain data like shown in the following image: !basinMap.png!


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

Open the volume output and ensure the model results are like shown in the following image:

{color:#ff0000}*\[TODO\]*{color} {color:#ff0000}Add screenshot of volume model output{color}


!outputCOverage.png|border=1!



{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.
{info}
\\
\\