Contents
Exercise outline
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:
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.Plugin.DemoApp.Models { public class VolumeModel : ModelBase { private static readonly ILog Log = LogManager.GetLogger(typeof(VolumeModel)); // Handle for writing log messages 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") }, }; // Actually add the input/output items to the model after wrapping them with data items DataItems.Add(new DataItem(basin, "Basin", typeof(DrainageBasin), DataItemRole.Input, "BasinTag")); DataItems.Add(new DataItem(precipitation, "Precipitation", typeof(TimeSeries), DataItemRole.Input, "PrecipitationTag")); DataItems.Add(new DataItem(volume, "Volume", typeof(FeatureCoverage), DataItemRole.Output, "VolumeTag")); } /// <summary> /// The basin of the volume model /// </summary> public DrainageBasin Basin { get { return basin; } } /// <summary> /// The precipitation time series of the volume model /// </summary> public TimeSeries Precipitation { get { return precipitation; } } /// <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()) { Log.Error("At least one catchment should be present"); Status = ActivityStatus.Failed; // Cancels the model run } // Check if at least one precipitation value is present if (precipitation.Time.Values.Count == 0) { Log.Error("At least one precipitation value should be present"); Status = ActivityStatus.Failed; // Cancels the model run } if (Status == ActivityStatus.Failed) { return; } // Initialize the volume output feature coverage volume.Features.AddRange(basin.Catchments); volume.FeatureVariable.FixedSize = basin.Catchments.Count; volume.FeatureVariable.AddValues(basin.Catchments); } /// <summary> /// The actual calculation during the model runs /// </summary> protected override bool OnExecute() { // Obtain all times of the precipitation time series var times = precipitation.Time.GetValues(); // Loop all times foreach (var time in times) { // Obtain the precipitation value for the current time var timeSeriesValue = (double) precipitation[time]; // Loop all catchments and calculate (a dummy) volume value based on catchment area and precipitation value var volumeValues = basin.Catchments.Select(c => c.AreaSize * timeSeriesValue); // Add the calculated volume values to the output feature coverage volume[time] = volumeValues; } return true; } } }
The model class derives the ModelBase class in order to automatically implement some basic time dependent modeling logic via derivation.
Furthermore, the comments in the code should explain the different parts of the model implementation.
The model uses some basic data stuctures 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.
[TODO]
Add links to some wiki pages?Fixme
[TODO] Fixme
Fixme
[TODO] Fixme
Exercise results
[TODO] Description of the exercise results
1. Add a new folder to the project named "Models"
2. Create a new class named "VolumeModel"
3. Add the following contents to this class:
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.Plugin.DemoApp.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; public VolumeModel() { // Create the input items of the model basin = new DrainageBasin(); precipitation = new TimeSeries { Components = { new Variable<double>("Precipitation") } }; // Create the output item of the model volume = new FeatureCoverage("Output data") { IsTimeDependent = true, Arguments = { new Variable<Catchment>("Catchment") { FixedSize = 0 } }, Components = { new Variable<double>("Volume") }, }; // Actually add the input/output items to the model by wrapping them with data items DataItems.Add(new DataItem(basin, "Basin", typeof(DrainageBasin), DataItemRole.Input, "BasinTag")); DataItems.Add(new DataItem(precipitation, "Precipitation", typeof(TimeSeries), DataItemRole.Input, "PrecipitationTag")); DataItems.Add(new DataItem(volume, "Volume", typeof(FeatureCoverage), DataItemRole.Output, "VolumeTag")); } /// <summary> /// The basin of the volume model /// </summary> public DrainageBasin Basin { get { return basin; } } /// <summary> /// The precipitation time series of the volume model /// </summary> public TimeSeries Precipitation { get { return precipitation; } } 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()) { Log.Error("At least one catchment should be present"); Status = ActivityStatus.Failed; } // Check if at least one precipitation value is present if (precipitation.Time.Values.Count == 0) { Log.Error("At least one precipitation value should be present"); Status = ActivityStatus.Failed; } if (Status == ActivityStatus.Failed) { return; } // Initialize the volume output feature coverage volume.Features.AddRange(basin.Catchments); volume.FeatureVariable.FixedSize = basin.Catchments.Count; volume.FeatureVariable.AddValues(basin.Catchments); } protected override bool OnExecute() { // Obtain all times of the precipitation time series var times = precipitation.Time.GetValues(); // Loop all times foreach (var time in times) { // Obtain the precipitation for the current time var timeSeriesValue = (double) precipitation[time]; // Loop all catchments and calculate (a dummy) volume value based on catchment area and precipitation value var volumeValues = basin.Catchments.Select(c => c.AreaSize * timeSeriesValue); // Add the calculated volume values to the output feature coverage volume[time] = volumeValues; } return true; } } }
4. Register the model in the application plugin class by adding the following code to DemoAppApplicationPlugin:
public override IEnumerable<ModelInfo> GetModelInfos() { yield return new ModelInfo { Name = "Volume Model", Category = "DemoApp models", CreateModel = (o) => new VolumeModel() }; }
5. Run the application, right click on Project and select Add | New model. Select the newly implemented model and press OK. [TODO: Image]
6. Run and check the log messages
7. Import catchments from GIS (standard Delta Shell functionality)
8. Run and check the log messages
9. Import
10. Run again
11. Open the output