Index: DamEngine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs
===================================================================
diff -u -r1192 -r1640
--- DamEngine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs (.../DAMEnumerations.cs) (revision 1192)
+++ DamEngine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs (.../DAMEnumerations.cs) (revision 1640)
@@ -274,9 +274,7 @@
///
public enum TimeSerieParameters
{
- [Obsolete("Use StabilityInsideFactor instead")]
- SafetyFactor, // <- Is same as StabilityInsideFactor, kept for legacy code
- PipingFactorWti,
+ PipingFactorWbiSellmeijerRevised,
PipingFactorBligh,
PipingFactorSellmeijer,
ProbabilityOfFailurePipingSellmeijer,
Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs
===================================================================
diff -u
--- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (revision 0)
+++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (revision 1640)
@@ -0,0 +1,334 @@
+// Copyright (C) Stichting Deltares 2018. All rights reserved.
+//
+// This file is part of the Dam Engine.
+//
+// The Dam Engine is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+// All names, logos, and references to "Deltares" are registered trademarks of
+// Stichting Deltares and remain full property of Stichting Deltares at all times.
+// All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using Deltares.DamEngine.Calculators.DikesDesign;
+using Deltares.DamEngine.Calculators.Sensors;
+using Deltares.DamEngine.Data.General;
+using Deltares.DamEngine.Data.General.Results;
+using Deltares.DamEngine.Data.General.Specifications.Extensions;
+using Deltares.DamEngine.Data.General.Specifications;
+using Deltares.DamEngine.Data.General.TimeSeries;
+using Deltares.DamEngine.Data.General.Sensors;
+using Deltares.DamEngine.Data.Standard;
+using Deltares.DamEngine.Data.Standard.Logging;
+
+namespace Deltares.DamEngine.Calculators.DikesOperational
+{
+ public class OperationalCalculator
+ {
+ ///
+ /// Specifies a location with valid sensor data. The objects that are satisfied by the
+ /// the specification (predicate) will be used in this calculator.
+ /// See ReadSensorDataAndPrepareOutputSeries and Locations.GetBySpecification(p)
+ ///
+ private class LocationsWithSensorData : PredicateSpecification
+ {
+ public LocationsWithSensorData()
+ : base(l => l.HasSensorLocation && l.SensorLocation.SensorCount > 0)
+ {
+ }
+ }
+ ///
+ /// Holds a reference to a dictionary of output date time entries
+ /// The keys represent the time step and the value part of the dictionary represents
+ /// the argument for the calculation
+ ///
+ /// TimeStep -> Location -> (Sensor, Value)
+ ///
+ /// Cardinality:
+ /// 1 -> N -> M
+ ///
+ private readonly IDictionary>> values =
+ new Dictionary>>();
+
+ private TimeSerieCollection inputTimeSerieCollection;
+ private TimeSerieCollection outputTimeSerieCollection;
+ private string outputParameter;
+
+ ///
+ /// Executes operational calculation.
+ ///
+ /// The dam project data.
+ public void Execute(DamProjectData damProjectData)
+ {
+ outputParameter = DetermineOutputParameter(damProjectData.DamProjectCalculationSpecification.CurrentSpecification);
+ // counter to determine if locations are processed
+ int locationCount = 0;
+
+ inputTimeSerieCollection = damProjectData.Dike.InputTimeSerieCollection;
+ outputTimeSerieCollection = new TimeSerieCollection();
+
+ var locations = damProjectData.Dike.Locations.GetBySpecification(new LocationsWithSensorData());
+ foreach (var location in locations)
+ {
+ PrepareSensorDataLookup(location);
+ InitializeOutputSeries(location);
+ locationCount++;
+ }
+ damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Info, null,
+ string.Format("There are {0} locations with sensor data", locationCount)));
+ if (!locations.Any())
+ {
+ damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Error, null, "No location to process."));
+ return;
+ }
+ var designCalculatorTasks = new List();
+ foreach (var series in outputTimeSerieCollection.Series)
+ {
+ foreach (var entry in series.Entries)
+ {
+ var location = locations.First(l => series.LocationId == l.Name);
+ var sensorValues = values[entry.DateTime][location];
+ if (!ContainsMissingValues(sensorValues, series.MissVal))
+ {
+ //var soiProfileProbability = location.Segment.GetMostProbableProfile2DStiFileName()
+
+ }
+ else
+ {
+ damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Warning, null,
+ String.Format("In location '{0}' missing values are found in timestep {1}", location.Name, entry.DateTime)));
+ }
+ }
+ }
+ damProjectData.OutputTimeSerieCollection = outputTimeSerieCollection;
+ }
+
+ private void RunDesignCalculatorTask(object designCalculatorTask)
+ {
+ DesignCalculatorTask task = (DesignCalculatorTask)designCalculatorTask;
+ Debug.WriteLine("Start calculation Location '{0}', soilprofile '{1}'", task.Location, task.SoiProfileProbability);
+ CalculateOneScenario(task.Location, task.SoiProfileProbability, task.ProjectPath,
+ task.CalculationMap, task.FailureMechanismeCalculationSpecification, task.DesignResults, task.CalculationMessages);
+ Debug.WriteLine("End calculation Location '{0}', soilprofile '{1}'", task.Location, task.SoiProfileProbability);
+ }
+ private void CalculateOneScenario(Location location, SoilGeometryProbability soiProfileProbability,
+ string projectPath, string calculationMap,
+ DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification,
+ List designResults, List calculationMessages)
+ {
+
+ }
+ private string DetermineOutputParameter(DamFailureMechanismeCalculationSpecification currentSpecification)
+ {
+ string parameter = "";
+ switch (currentSpecification.FailureMechanismSystemType)
+ {
+ case FailureMechanismSystemType.HorizontalBalance:
+ throw new NotImplementedException();
+ case FailureMechanismSystemType.StabilityOutside:
+ throw new NotImplementedException();
+ case FailureMechanismSystemType.StabilityInside:
+ parameter = TimeSerieParameters.StabilityInsideFactor.ToString();
+ break;
+ case FailureMechanismSystemType.Piping:
+ switch (currentSpecification.PipingModelType)
+ {
+ case PipingModelType.Bligh:
+ throw new NotImplementedException();
+ case PipingModelType.SellmeijerVnk:
+ throw new NotImplementedException();
+ case PipingModelType.Sellmeijer4Forces:
+ throw new NotImplementedException();
+ case PipingModelType.Wti2017:
+ throw new NotImplementedException();
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ return parameter;
+ }
+
+ ///
+ /// Initializes the output series.
+ ///
+ private void InitializeOutputSeries(Location location)
+ {
+ var firstTimeSeries = inputTimeSerieCollection.Series.First();
+ var copyOfSeries = firstTimeSeries.GetShallowCopy();
+ foreach (var entry in firstTimeSeries.Entries)
+ {
+ // get copy of the input entry
+ var copyOfEntry = entry.GetShallowCopy();
+
+ // set parameter and location id's and add the projected entry to the output
+ copyOfSeries.LocationId = location.Name;
+ copyOfSeries.ParameterId = outputParameter;
+ copyOfSeries.Entries.Add(copyOfEntry);
+ }
+
+ // add the output series to the output collection
+ outputTimeSerieCollection.Series.Add(copyOfSeries);
+ }
+
+ ///
+ /// Prepares the output time series and the calculation arguments (sensor data).
+ ///
+ /// The location.
+ private void PrepareSensorDataLookup(Location location)
+ {
+ ThrowIfSensorsAreMissingInInputFile(location);
+
+ // these variable are used to determine differences in time series entries
+ var firstSeriesEntries = new HashSet();
+ bool hasFirstSeriesEntries = false;
+
+ foreach (var sensor in location.SensorLocation.Sensors)
+ {
+ IEnumerable series = inputTimeSerieCollection.GetSeriesByLocationId(sensor.Name);
+ ThrowIfSensorNotExists(sensor, series.Any());
+
+ // Prepare the output time series and set sensor values
+ foreach (var timeSeries in series)
+ {
+ ThrowIfTimeEntryCountDontMatch(firstSeriesEntries, timeSeries, hasFirstSeriesEntries);
+
+ foreach (var entry in timeSeries.Entries)
+ {
+ var key = entry.DateTime;
+ if (hasFirstSeriesEntries)
+ {
+ ThrowIfTimeEntriesKeysDontMatch(key, firstSeriesEntries);
+ }
+
+ if (!hasFirstSeriesEntries)
+ {
+ firstSeriesEntries.Add(key);
+ }
+
+ // everything ok set data into internal lookup
+ SetSensorValue(key, entry.Value, sensor, location);
+ }
+ }
+ hasFirstSeriesEntries = true;
+ }
+ }
+
+ ///
+ /// Sets the sensor value.
+ ///
+ /// The time step.
+ /// The value.
+ /// The sensor.
+ /// The location.
+ private void SetSensorValue(DateTime timeStep, double value, Sensor sensor, Location location)
+ {
+ if (!values.ContainsKey(timeStep))
+ values.Add(timeStep, new Dictionary>());
+
+ if (!values[timeStep].ContainsKey(location))
+ values[timeStep].Add(location, new Dictionary());
+
+ if (values[timeStep][location].ContainsKey(sensor))
+ {
+ var message = string.Format("Values for sensor with id {0} and name {1} and location {2} and time step {3} already exists. Check the time series data.",
+ sensor.ID, sensor.Name, location.Name, timeStep);
+
+ throw new SensorTimeSeriesProcessorException(message);
+ }
+
+ values[timeStep][location].Add(sensor, value);
+ }
+
+ ///
+ /// Throws when the sensor not exists.
+ ///
+ /// The sensor.
+ /// if set to true [has series by sensor ID].
+ private static void ThrowIfSensorNotExists(Sensor sensor, bool hasSeriesBySensorID)
+ {
+ if (!hasSeriesBySensorID)
+ {
+ // TODO log info
+ string message =
+ string.Format("Sensor with name '{0}' and parameter id '{1}' not found in the input time series",
+ sensor.Name, TimeSerie.WaterPressureParameterId);
+
+ throw new SensorTimeSeriesProcessorException(message);
+ }
+ }
+
+ ///
+ /// Throws if time entry count dont match.
+ ///
+ /// The first series entries.
+ /// The time series.
+ /// if set to true [has first series entries].
+ /// Invalid data in time series entries. Number of entries differ on each sensor
+ private static void ThrowIfTimeEntryCountDontMatch(HashSet firstSeriesEntries, TimeSerie timeSeries,
+ bool hasFirstSeriesEntries)
+ {
+ if (hasFirstSeriesEntries)
+ {
+ // TODO log info
+ if (timeSeries.Entries.Count != firstSeriesEntries.Count)
+ throw new SensorTimeSeriesProcessorException("Invalid data in time series entries. Number of entries differ on each sensor");
+ }
+ }
+
+ private void ThrowIfSensorsAreMissingInInputFile(Location location)
+ {
+ var sensorsNotFound = (
+ from sensor in location.SensorLocation.Sensors
+ let series = inputTimeSerieCollection.GetSeriesByLocationId(sensor.Name)
+ where !series.Any()
+ select sensor.Name).ToList();
+
+ if (sensorsNotFound.Any())
+ {
+ // TODO log info
+ string message =
+ string.Format("Sensor with name '{0}' and parameter id '{1}' not found in the input time series",
+ string.Join(", ", sensorsNotFound.ToArray()), TimeSerie.WaterPressureParameterId);
+
+ throw new SensorTimeSeriesProcessorException(message);
+ }
+ }
+
+ private static void ThrowIfTimeEntriesKeysDontMatch(DateTime key, HashSet firstSeriesEntries)
+ {
+ // TODO log info
+ if (!firstSeriesEntries.Contains(key))
+ throw new SensorTimeSeriesProcessorException("Invalid data in time series entries. Time entries (date time values) don't match");
+ }
+ ///
+ /// Determines whether any of sensor values contains a missing value.
+ ///
+ /// The sensor values.
+ ///
+ ///
+ private bool ContainsMissingValues(IDictionary sensorValues, double missingValue)
+ {
+ foreach (var sensorValue in sensorValues)
+ {
+ if (sensorValues[sensorValue.Key].AlmostEquals(missingValue))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
Index: DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/TestFiles/OperationalSet2.xml
===================================================================
diff -u -r1635 -r1640
--- DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/TestFiles/OperationalSet2.xml (.../OperationalSet2.xml) (revision 1635)
+++ DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/TestFiles/OperationalSet2.xml (.../OperationalSet2.xml) (revision 1640)
@@ -1,28 +1,28 @@
-
+
-
+
-
+
-
+
@@ -195,63 +195,93 @@
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
-
+
+
+
Index: DamEngine/trunk/src/Deltares.DamEngine.Interface/EngineInterface.cs
===================================================================
diff -u -r1632 -r1640
--- DamEngine/trunk/src/Deltares.DamEngine.Interface/EngineInterface.cs (.../EngineInterface.cs) (revision 1632)
+++ DamEngine/trunk/src/Deltares.DamEngine.Interface/EngineInterface.cs (.../EngineInterface.cs) (revision 1640)
@@ -23,6 +23,7 @@
using System.Collections.Generic;
using Deltares.DamEngine.Calculators.DikesAssessmentRegional;
using Deltares.DamEngine.Calculators.DikesDesign;
+using Deltares.DamEngine.Calculators.DikesOperational;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.Standard.Calculation;
using Deltares.DamEngine.Data.Standard.Logging;
@@ -191,7 +192,9 @@
regionalScenariosCalculator.GetResults();
break;
case DamProjectType.Operational:
- throw new NotImplementedException();
+ var operationalCalculator = new OperationalCalculator();
+ operationalCalculator.Execute(DamProjectData);
+ break;
case DamProjectType.Design:
DesignCalculator designCalculator = new DesignCalculator();
designCalculator.RegisterProgress(progressDelegate);
Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs
===================================================================
diff -u -r1602 -r1640
--- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs (.../SensorTimeSeriesProcessor.cs) (revision 1602)
+++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs (.../SensorTimeSeriesProcessor.cs) (revision 1640)
@@ -24,7 +24,6 @@
using System.IO;
using System.Linq;
using Deltares.Dam.Data.Sensors;
-using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon;
using Deltares.DamEngine.Calculators.PlLinesCreator;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.PlLines;
@@ -33,7 +32,6 @@
using Deltares.DamEngine.Data.General.Specifications.Extensions;
using Deltares.DamEngine.Data.General.TimeSeries;
using Deltares.DamEngine.Data.Standard;
-using log4net.Repository.Hierarchy;
namespace Deltares.DamEngine.Calculators.Sensors
{
@@ -184,7 +182,7 @@
// requiredSafetyFactorPiping, location.GaugePlLines, location.Gauges, location.UpliftCriterionPiping.Value);
// PlLines = CreateAllPlLines(sensorValues, sensorSetup, lineTypes);
// double? pipingFactor = pipingCalculatorWti2017.CalculatePipingFactor(location, location.SurfaceLine,
-// location.Segment.GetMostProbableProfile(FailureMechanismSystemType.Piping), PlLines);
+// location.Segment.GetMostProbableProfile1D(FailureMechanismSystemType.Piping), PlLines);
// entry.Value = pipingFactor != null ? pipingFactor.Value: series.MissVal;
// // entry.Value = CalculationHelper.DetermineSafetyFactor(calculationQueue[entry], ref basisFileName, stabilityExePath);
// // entry.BasisFileName = Path.GetFileNameWithoutExtension(basisFileName);
@@ -323,7 +321,7 @@
if (parameterId == TimeSerieParameters.StabilityOutsideFactor.ToString())
return FailureMechanismSystemType.StabilityOutside;
- if (parameterId == TimeSerieParameters.PipingFactorWti.ToString())
+ if (parameterId == TimeSerieParameters.PipingFactorWbiSellmeijerRevised.ToString())
return FailureMechanismSystemType.Piping; // #the Here something should be done with piping models
throw new SensorTimeSeriesProcessorException("There is no failure mechanism mapping for parameterID " + parameterId);
@@ -378,7 +376,7 @@
return TimeSerieParameters.StabilityOutsideFactor.ToString();
case FailureMechanismSystemType.Piping:
// #The Piping now only supports 1 model: WTI 2017. But when more piping models are implemented, pipinggmodelType is needed here too!
- return TimeSerieParameters.PipingFactorWti.ToString();
+ return TimeSerieParameters.PipingFactorWbiSellmeijerRevised.ToString();
// case FailureMechanismType.PipingSellmeijer:
// return TimeSerieParameters.PipingFactorSellmeijer.ToString(); #Bka Piping not yet used. But when used, pipingmodelType is needed here too!
default:
Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationCalculatorTask.cs
===================================================================
diff -u
--- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationCalculatorTask.cs (revision 0)
+++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationCalculatorTask.cs (revision 1640)
@@ -0,0 +1,43 @@
+// Copyright (C) Stichting Deltares 2018. All rights reserved.
+//
+// This file is part of the Dam Engine.
+//
+// The Dam Engine is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+// All names, logos, and references to "Deltares" are registered trademarks of
+// Stichting Deltares and remain full property of Stichting Deltares at all times.
+// All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Deltares.DamEngine.Data.General;
+using Deltares.DamEngine.Data.General.Results;
+using Deltares.DamEngine.Data.Standard.Logging;
+
+namespace Deltares.DamEngine.Calculators.DikesOperational
+{
+ public class OperationCalculatorTask
+ {
+ public Location Location { get; set; }
+ public SoilGeometryProbability SoiProfileProbability { get; set; }
+ public string ProjectPath { get; set; }
+ public string CalculationMap { get; set; }
+ public DamFailureMechanismeCalculationSpecification FailureMechanismeCalculationSpecification { get; set; }
+ public List DesignResults { get; set; }
+ public List CalculationMessages { get; set; }
+ }
+}