scrollbar |
---|
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.
Create a new model class
Add to the plugin project a new folder named Models. In this folder, create a new class named VolumeModel.cs and adapt the contents as shown below:
Code Block |
---|
using System; 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.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.PluginPlugins.DemoAppVolumeModel.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 Components = { new Variable<double>("Volume") }, }; // ActuallyWrap addfields theas input/output items to the model after wrapping them with data items DataItems.Add(new DataItem(basinprecipitation, "BasinPrecipitation", typeof(DrainageBasinTimeSeries), DataItemRole.Input, "BasinTagPrecipitationTag")); DataItems.Add(new DataItem(precipitationbasin, "PrecipitationBasin", typeof(TimeSeriesDrainageBasin), DataItemRole.Input, "PrecipitationTagBasinTag")); DataItems.Add(new DataItem(volume, "Volume", typeof(FeatureCoverage), DataItemRole.Output, "VolumeTag")); } /// <summary> /// The basinprecipitation oftime theseries: volumeP model = P(t) [L/T]. Input of the model. /// </summary> public DrainageBasin Basin { TimeSeries Precipitation { get { return basinprecipitation; } } /// <summary> /// The precipitationdrainage time seriesbasin (set of catchments). Input of the volume model. /// </summary> public DrainageBasin TimeSeriesBasin Precipitation { get { return precipitation; } }{ /// <summary> get { return basin; } /// The output of the volume model} /// </summary><summary> public FeatureCoverage Volume { get { return volume; } } /// <summary>/// Time-dependent feature coverage containing the volume of water per catchment: V = V(t, c) [L3/T]. Output of the model. /// The</summary> initialization of model runs public FeatureCoverage Volume /// </summary> { protected override void OnInitialize() get { return volume; } } // Clear any previous output /// <summary> volume.Clear(); /// The initialization of model runs /// Ensure</summary> the coordinate system of the volume output isprotected theoverride same as the catchments input (basinvoid OnInitialize() volume.CoordinateSystem = basin.CoordinateSystem; { // CheckClear ifany atprevious leastoutput one catchment is present if (!basin.Catchments.Any())volume.Clear(); { // Ensure the coordinate system of the volume output is the same as the catchments input Log.Error("At least one catchment should be present"); (basin) Status volume.CoordinateSystem = ActivityStatusbasin.FailedCoordinateSystem; // Cancels the model run // Ensure at least one } catchment and one precipitation value is present // Check if at least one precipitation value is present ValidateInputData(); // Initialize the if (precipitation.Time.Values.Count == 0)output feature coverage {volume.Features.AddRange(basin.Catchments); volume.FeatureVariable.FixedSize Log.Error("At least one precipitation value should be present"); = basin.Catchments.Count; Status = ActivityStatus.Failed; // Cancels the model run volume.FeatureVariable.AddValues(basin.Catchments); } /// } <summary> /// The actual calculation ifduring (Status == ActivityStatus.Failed)model run /// </summary> { protected override bool OnExecute() return; { } // Loop all times // Initialize theforeach volume(var outputtime feature coveragein precipitation.Time.Values) volume.Features.AddRange(basin.Catchments);{ volume.FeatureVariable.FixedSize = basin.Catchments.Count; // Obtain the precipitation value for the current time volume.FeatureVariable.AddValues(basin.Catchments); var p = }(double) precipitation[time]; /// <summary> /// The actual calculation during the model runs /// </summary> Calculate a volume value for every catchment based on catchment area and precipitation value protected override bool OnExecute() var volumes = basin.Catchments.Select(c => c.AreaSize * {p); // Add the Obtaincalculated allvolume timesvalues ofto the precipitationoutput timefeature seriescoverage var times volume[time] = precipitation.Time.GetValues(); volumes; // Loop all times } return true; foreach (var time in times) } private {void ValidateInputData() { // Obtain the precipitation valuevar forhasCatchments the current time = basin.Catchments.Any(); var timeSeriesValuehasPrecipitationData = precipitation.Time.Values.Any(double) precipitation[time]; if (!hasCatchments && !hasPrecipitationData) // Loop all catchments and calculate (a dummy) volume value based on{ catchment area and precipitation value throw new InvalidOperationException("At least one varcatchment volumeValuesand = basin.Catchments.Select(c => c.AreaSize * timeSeriesValue); one precipitation value should be present"); } // Add the calculated volume values to the output feature coverageif (!hasCatchments) volume[time] = volumeValues;{ } throw new InvalidOperationException("At least one catchment should return truebe present"); } } } {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.Plugin.DemoApp.Models; {code} and {code} if (!hasPrecipitationData) { throw new InvalidOperationException("At least one precipitation value should be present"); } } } } |
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. |
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. |
Register the model in the application plugin class
Register the model in the application plugin by adding the following code to VolumeModelApplicationPlugin.cs:
Code Block |
---|
public override IEnumerable<ModelInfo> GetModelInfos() { yield return new {ModelInfo { yield return new ModelInfo Name { Name = = "Volume Model", Category = "DemoAppVolume models", CreateModel = o => new Models.VolumeModel() }; } {code} |
Delta
...
Shell
...
should
...
now
...
be
...
able
...
to
...
create
...
and
...
run
...
volume
...
models.
...
Exercise
...
results
...
First
...
of
...
all,
...
download the
...
following
...
WaterML2
...
XML
...
file:
...
WaterML2_precipitation_data.XML. Also download and unzip the shape files contained in the following archive: Gemeenten.zip. 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 ...). Make sure that the new model is selected in the dialog:
If you now click on OK, a new model item should be added to the project with a structure as shown in the following image:
Try to run the model (right click on the volume model item | Run Model) and check the Messages window. The following error messages will be generated:
As indicated in the error messages, some precipitation and catchment input data must be available in order to successfully run the model.
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 (double click the precipitation item in the Project window):
Next, start importing a shape file on the basin item (right click the basin item | Import...). A GIS import wizard automatically pops up. Press on Next to enter the wizard:
Now, you have to specify what type of feature you are going to import and from where. In the drop down menu for Features, select the type Catchments (1). Next, click on the ... button (2) and browse to select the shape file at the location where you have previously unzipped it (3). Once this selection has been made, you need to add the combination of feature type and source file to the import list (4). The list will be updated with the previous selection (5). At this step, you could continue adding more features from other files to the import list. We don't need to do this, so simply continue with the wizard pressing the Next button (6).
You can now map the different properties of the imported GIS data into the model features. Map the Name property to GM_NAAM and continue with the import wizard.
In general, there can be some small differences between the coordinates of different features which are actually located in the same position. The snapping precision specifies the magnitude of this margin. Simply, leave it as default and continue with the wizard.
By clicking on Finish, the wizard will be completed and the import will be started.
After finishing the import, the basin item should contain data as shown in the following image (double click on the basin item in the Project window):
Now, run the model again and notice that, this time, no new error messages have been sent to the Messages window.
Open the volume output (double click the volume item in the Project window and select the Map view) and check that the model results agree with the ones shown in the following image:
Info |
---|
In order to inspect time dependent (output) data, open the Time Navigator window and move the slider or click one of the play buttons: |
scrollbar |
---|