...
Code Block |
---|
using System; using System.Collections.Generic; using System.Linq; using DelftTools.Functions; using DelftTools.Functions.Generic; using DelftTools.Shell.Core.Workflow; using DelftTools.Shell.Core.Workflow.DataItems; using GeoAPI.CoordinateSystems; using GeoAPI.Extensions.Feature; using GeoAPI.Geometries; using NetTopologySuite.Extensions.Coverages; namespace DeltaShell.Plugins.VolumeModel.Models { public class VolumeModel : ModelBase { 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<IFeature>("Catchment") { FixedSize = 0 } }, Components = { new Variable<double>("Volume") }, }; // Wrap fields as input/output data items DataItems.Add(new DataItem(precipitation, "Precipitation", typeof(TimeSeries), DataItemRole.Input, "PrecipitationTag")); DataItems.Add(new DataItem(basin, "Basin", typeof(DrainageBasin), DataItemRole.Input, "BasinTag")); DataItems.Add(new DataItem(volume, "Volume", typeof(FeatureCoverage), DataItemRole.Output, "VolumeTag")); } /// <summary> /// The precipitation time series: P = P(t) [L/T]. Input of the model. /// </summary> public TimeSeries Precipitation { get { return precipitation; } } /// <summary> /// The drainage basin (set of catchments). Input of the model. /// </summary> public DrainageBasin Basin { get { return basin; } } /// <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; // Ensure at least one catchment and one precipitation value is present ValidateInputData(); // 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 void 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(f => f.Geometry).Select(pol => pol.Area * p); // Add the calculated volume values to the output feature coverage volume[time] = volumes; } Status = ActivityStatus.Done; } private void ValidateInputData() { var hasCatchments = basin.Catchments.Any(); var hasPrecipitationData = precipitation.Time.Values.Any(); if (!hasCatchments && !hasPrecipitationData) { throw new InvalidOperationException("At least one catchment and one precipitation value should be present"); } if (!hasCatchments) { throw new InvalidOperationException("At least one catchment should be present"); } if (! basin.Catchments.All(c => c.Geometry is IPolygon || c.Geometry is IMultiPolygon)) { throw new InvalidOperationException("All catchment features should be polygons"); } if (!hasPrecipitationData) { throw new InvalidOperationException("At least one precipitation value should be present"); } } } } |
...
Delta Shell should now be able to create and run volume models.
Add importer for DrainageBasin
We now only need to add a small importer for importing our custom DrainageBasin from a shapefile. Add a new class DrainageBasinImporter in the folder importers and add the following code :
Code Block |
---|
using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using DelftTools.Shell.Core; using DeltaShell.Plugins.VolumeModel.Models; using GeoAPI.Extensions.Feature; using SharpMap.Data.Providers; namespace DeltaShell.Plugins.VolumeModel.Importers { public class DrainageBasinImporter : IFileImporter { public string Name { get { return "Shape file importer"; }} public string Category { get { return "General"; } } public Bitmap Image { get; private set; } public IEnumerable<Type> SupportedItemTypes { get{ yield return typeof(DrainageBasin);} } public bool CanImportOnRootLevel { get { return false; } } public string FileFilter { get { return "Shape file|*.shp"; }} public string TargetDataDirectory { get; set; } public bool ShouldCancel { get; set; } public ImportProgressChangedDelegate ProgressChanged { get; set; } public bool OpenViewAfterImport { get { return false; } } public bool CanImportOn(object targetObject) { return targetObject is DrainageBasin; } public object ImportItem(string path, object target = null) { var basin = target as DrainageBasin; if (basin == null) { throw new Exception("Can only import on drainage basins"); } basin.Catchments.Clear(); var shapeFile = new ShapeFile(path); foreach (var feature in shapeFile.Features.OfType<IFeature>()) { basin.Catchments.Add(feature); } basin.CoordinateSystem = shapeFile.CoordinateSystem; return basin; } } } |
...