Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessor.cs (revision 1591) @@ -0,0 +1,611 @@ +// 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.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; +using Deltares.DamEngine.Data.General.Sensors; +using Deltares.DamEngine.Data.General.Specifications; +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 +{ + public class SensorTimeSeriesProcessor : TimeSeriesProcessor + { + private int seriesCount = 0; + private string currentWorkingPath = ""; + public const double NotCalculatedValue = -999; + + /// + /// Specifies a location with valid sensor data. The objects that are satisfied by the + /// the specification (predicate) will be used in this processor. + /// See ReadSensorDataAndPrepareOutputSeries and Locations.GetBySpecification(p) + /// + private class LocationsWithSensorData : PredicateSpecification + { + public LocationsWithSensorData() + : base(l => l.HasSensorData && l.SensorData.SensorCount > 0) + { + } + } + + public SensorTimeSeriesProcessor() + { + Calculator = new SensorLocationSafetyFactorCalculator(); + OutputParameters = new[] { TimeSerieParameters.StabilityInsideFactor.ToString() }; + } + + /// + /// Gets the output location ID collection used for creating the output time series. + /// Setter is not used and will throw an exception when set. Use the Location property instead + /// + public override IEnumerable OutputLocations + { + get { return Locations.GetBySpecification(new LocationsWithSensorData()).Select(l => l.Name); } + set { throw new SensorTimeSeriesProcessorException("Do not set this property directly. Set the Locations property instead"); } + } + + /// + /// Gets or sets the locations. + /// + /// + /// The DAM locations. + /// + public IEnumerable Locations { get; set; } + + /// + /// Gets or sets the calculation parameters. + /// + /// + /// The calculation parameters. + /// + public CalculationParameters CalculationParameters { get; set; } + + /// + /// 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>>(); + + /// + /// Holds a dictionary of time entries and project files that needs to be calculated (per entry a list of files) + /// + private readonly Dictionary> calculationQueue = new Dictionary>(); + + /// + /// Processes the actual input to the output collection. + /// This is a template method which will be called in the public Process() method of the super class + /// + protected override void CreateOutputSeries() + { + values.Clear(); + + // Set the output parameters (configured in the calculation parameter modules) + OutputParameters = GetFailureMechanisms().Select(GetOutputParameterId).ToList(); + + // counter to determine if locations are processed + int locationCount = 0; + + var locations = Locations.GetBySpecification(new LocationsWithSensorData()); + foreach (var location in locations) + { + PrepareSensorDataLookup(location); + InitializeOutputSeries(location); + locationCount++; + } + + //Logger.LogDebug(string.Format("There are {0} locations with sensor data", locationCount)); + if (locationCount == 0) + { + //Logger.LogDebug("No location to process."); + return; + } + + + foreach (var series in OutputTimeSeriesCollection.Series) + { + var failureMechanism = GetFailureMechanismByParameterID(series.ParameterId); + switch (failureMechanism) + { + case FailureMechanismSystemType.StabilityInside: + CreateStabilityOutputSeries(series); + break; + case FailureMechanismSystemType.Piping: + CreatePipingOutputSeries(series); + break; + default: + throw new SensorTimeSeriesProcessorException(String.Format("Failure mechanism {0} not implemented yet", failureMechanism.ToString())); + } + } + } + + /// + /// Creates the piping output series. + /// + /// The series. + private void CreatePipingOutputSeries(TimeSerie series) + { + throw new NotImplementedException(); +// int entryCount = 0; +// foreach (var entry in series.Entries) +// { +// entryCount++; +// try +// { +// PlLines PlLines = null; +// var location = Locations.First(l => series.LocationId == l.Name); +// var sensorValues = values[entry.DateTime][location]; +// var sensorSetup = location.SensorData; +// var lineTypes = location.SensorData.Sensors.SelectMany(s => s.PlLineMappings).Distinct().ToList(); +// +// var requiredSafetyFactorPiping = 0.0; // normally only needed for design; it is used here because it is part of the parameterlist of the constructor +// var modelParametersForPlLines = new ModelParametersForPlLines +// { +// PenetrationLength = location.ModelParametersForPlLines.PenetrationLength, +// DampingFactorPl3 = location.ModelParametersForPlLines.DampingFactorPl3, +// DampingFactorPl4 = location.ModelParametersForPlLines.DampingFactorPl4, +// PlLineCreationMethod = location.ModelParametersForPlLines.PlLineCreationMethod +// }; +// var pipingCalculatorWti2017 = new PipingCalculatorWti2017(modelParametersForPlLines, +// 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); +// entry.Value = pipingFactor != null ? pipingFactor.Value: series.MissVal; +// // entry.Value = CalculationHelper.DetermineSafetyFactor(calculationQueue[entry], ref basisFileName, stabilityExePath); +// // entry.BasisFileName = Path.GetFileNameWithoutExtension(basisFileName); +// } +// catch (Exception e) +// { +// var dateTime = entry.DateTime; +// var message = string.Format("Could not determine safety factor for entry nr. '{0}' and time step '{1}'", entryCount, dateTime); +// //Logger.LogError(message, e); +// } +// } + } + /// + /// Creates the stability output series. + /// + /// The series. + private void CreateStabilityOutputSeries(TimeSerie series) + { + seriesCount++; + int entryCount = 0; + bool calculateAllAtOnce = CalculationParameters.CalculateAllAtOnce; + currentWorkingPath = Path.Combine(CalculationParameters.StabilityWorkingPath, String.Format("Series{0:000}", seriesCount)); + string stabilityWorkingPath = Path.GetFullPath(currentWorkingPath); + System.IO.Directory.CreateDirectory(stabilityWorkingPath); + string stabilityExePath = CalculationParameters.StabilityExePath; + + PrepareStabilityCalculationQueue(series); + + // Calculate all project files + if (calculateAllAtOnce) + CalculationHelper.CalculateMStabProjects(stabilityWorkingPath, stabilityExePath); + foreach (var entry in series.Entries) + { + entryCount++; + try + { + if (!CalculationParameters.CalculateAllAtOnce) + CalculationHelper.CalculateMStabProjects(calculationQueue[entry], stabilityExePath); + + string basisFileName = ""; + entry.Value = series.MissVal; + entry.Value = CalculationHelper.DetermineSafetyFactor(calculationQueue[entry], ref basisFileName, + stabilityExePath); + entry.BasisFileName = Path.GetFileNameWithoutExtension(basisFileName); + } + catch (Exception e) + { + var dateTime = entry.DateTime; + var message = string.Format("Could not determine safety factor for entry nr. '{0}' and time step '{1}'", + entryCount, dateTime); + //Logger.LogError(message, e); + } + } + } + + /// + /// 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; + } + + /// + /// Prepares the calculation queue. + /// + private void PrepareStabilityCalculationQueue(TimeSerie series) + { + int entryIndex = 0; + foreach (var entry in series.Entries) + { + entryIndex++; + + IEnumerable files = null; + var location = Locations.First(l => series.LocationId == l.Name); + var sensorValues = values[entry.DateTime][location]; + if (!ContainsMissingValues(sensorValues, series.MissVal)) + { + try + { + //var failureMechanism = GetFailureMechanismByParameterID(series.ParameterId); + files = CreateCalculationFiles(location, sensorValues, entryIndex, entry.DateTime).ToList(); + } + catch (SensorPlLineCreatorException se) + { + throw se; + } + catch (Exception e) + { + string msg = string.Format("There was an error while preparing the calculation queue (stability project files)"); + + // Logger.LogFatal(msg, e); + throw new SensorTimeSeriesProcessorException(msg, e); + } + + foreach (var file in files) + { + if (!calculationQueue.ContainsKey(entry)) + calculationQueue.Add(entry, new List()); + + calculationQueue[entry].Add(file); + + // Logger.LogDebug(string.Format("Project file '{0}' created", file)); + } + } + else + { + //Logger.LogWarning(String.Format("In location '{0}' missing values are found in timestep {1}", location.Name, entry.DateTime)); + } + } + } + + /// + /// Gets the failure mechanism by parameter ID. + /// + /// The parameter id. + /// + private FailureMechanismSystemType GetFailureMechanismByParameterID(string parameterId) + { + if (string.IsNullOrWhiteSpace(parameterId)) + throw new ArgumentNullException("parameterId"); + + if (parameterId == TimeSerieParameters.StabilityInsideFactor.ToString()) + return FailureMechanismSystemType.StabilityInside; + + if (parameterId == TimeSerieParameters.StabilityOutsideFactor.ToString()) + return FailureMechanismSystemType.StabilityOutside; + + if (parameterId == TimeSerieParameters.PipingFactorWti.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); + } + + /// + /// Gets all the supported failure mechanisms based on the calculation modules. + /// + /// + private IEnumerable GetFailureMechanisms() + { + var calculationModules = CalculationParameters.CalculationModules; + if (calculationModules == null) + throw new SensorTimeSeriesProcessorException("No calculation modules defined"); + + if (calculationModules.StabilityOutside) + yield return FailureMechanismSystemType.StabilityOutside; + + if (calculationModules.Stability) + yield return FailureMechanismSystemType.StabilityInside; + + if (calculationModules.PipingWti) + yield return FailureMechanismSystemType.Piping; + // throw new NotImplementedException("Piping WTI 2017 not yet supported"); + + if (calculationModules.PipingSellmeijer) + throw new NotImplementedException("Piping Sellmeijer not yet supported"); + + if (calculationModules.PipingBligh) + throw new NotImplementedException("Piping Bligh not yet supported"); + + if (calculationModules.PipingSellmeijerProbabilistic) + throw new NotImplementedException("Piping Sellmeijer Probabilistic not yet supported"); + + if (calculationModules.Overtopping) + throw new NotImplementedException("Overtopping not yet supported"); + } + + + /// + /// Gets the ouput parameter ID. + /// + /// The type. + /// + private string GetOutputParameterId(FailureMechanismSystemType type) + { + switch (type) + { + case FailureMechanismSystemType.StabilityInside: + return TimeSerieParameters.StabilityInsideFactor.ToString(); + case FailureMechanismSystemType.StabilityOutside: + 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(); + // case FailureMechanismType.PipingSellmeijer: + // return TimeSerieParameters.PipingFactorSellmeijer.ToString(); #Bka Piping not yet used. But when used, pipingmodelType is needed here too! + default: + throw new ArgumentOutOfRangeException("type"); + } + } + + /// + /// Creates the calculation files. + /// + /// The location. + /// The sensor values. + /// Index of the time entry. + /// The entry date time. + /// + /// No stability parameters set. Processing terminated + private IEnumerable CreateCalculationFiles(Location location, IDictionary sensorValues, int timeEntryIndex, DateTime entryDateTime) + { + var stabilityParams = CalculationParameters.MStabParameters; + if (stabilityParams == null) + throw new SensorTimeSeriesProcessorException("No stability parameters set. Processing terminated"); + + PlLines PlLines = null; + bool isCombined = stabilityParams.IsCombinedBishopUpliftVanCalculation; + + var soilGeometry = CalculationHelper.GetSoilGeometryType(location, Path.GetDirectoryName(CalculationParameters.WorkingPath)); + var sensorSetup = location.SensorData; + var lineTypes = location.SensorData.Sensors.SelectMany(s => s.PlLineMappings).Distinct().ToList(); + //double waterLevel = sensorSetup.GetWaterLevelAtRiver(sensorValues); + + PlLines = CreateAllPlLines(sensorValues, sensorSetup, lineTypes); + + var models = CalculationHelper.GetStabilityModels(isCombined, location, PlLines, soilGeometry.SoilGeometryName, stabilityParams.Model); + + // create all stability project files and return a list of file names. + return models.Select( + model => CalculationHelper.CreateStabilityProjectFile( + new StabilityProjectFileCreationArguments + { + DikeName = "dike", + Location = location, + SoilGeometry2DName = soilGeometry.SoilGeometryName, + SoilGeometryType = soilGeometry.SoilProfileType, + PlLines = PlLines, + Model = model, + EntryCount = timeEntryIndex, + EntryDateTime = entryDateTime, + FailureMechanismType = FailureMechanismSystemType.StabilityInside, + StabilityWorkingPath = currentWorkingPath, + StabilityExePath = CalculationParameters.StabilityExePath, + StabilityParameters = CalculationParameters.MStabParameters + })); + } + + /// + /// Creates all the PL lines from the specified sensor values. + /// + /// The sensor values. + /// The sensor setup. + /// The line types. + /// The pl lines. + /// + /// + private static PlLines CreateAllPlLines(IDictionary sensorValues, SensorLocation sensorSetup, IEnumerable lineTypes) + { + PlLines PlLines; + var creator = SensorPlLineCreator.CreateInstance(sensorSetup, sensorValues, lineTypes); + try + { + PlLines = creator.CreateAllPlLines(); + } + catch (InvalidOperationException e) + { + throw new SensorPlLineCreatorException(e.Message, e); + } + return PlLines; + } + + /// + /// 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.SensorData.Sensors) + { + IEnumerable series = InputTimeSeriesCollection.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; + } + } + + /// + /// Initializes the output series. + /// + private void InitializeOutputSeries(Location location) + { + foreach (var parameterID in OutputParameters) + { + var firstTimeSeries = InputTimeSeriesCollection.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 = parameterID; + copyOfSeries.Entries.Add(copyOfEntry); + } + + // add the output series to the output collection + OutputTimeSeriesCollection.Series.Add(copyOfSeries); + } + } + + /// + /// 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, 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"); + } + + 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.SensorData.Sensors + let series = InputTimeSeriesCollection.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()), WaterPressureParameterID); + + throw new SensorTimeSeriesProcessorException(message); + } + } + } +} Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.Designer.cs =================================================================== diff -u -r1387 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 1387) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 1591) @@ -61,6 +61,15 @@ } /// + /// Looks up a localized string similar to The file name is not valid. Maybe due to a null or empty string and or invalid characters. Please use a valid file name. + /// + internal static string FileNameNotValid { + get { + return ResourceManager.GetString("FileNameNotValid", resourceCulture); + } + } + + /// /// Looks up a localized string similar to GetCotangentOfInnerSlope requires either of characteristic points ShoulderBaseInside or DikeToeAtPolder to be defined.. /// internal static string GetCotangentOfInnerSlopeDikeToeAtPolderRequired { Index: DamEngine/trunk/src/Deltares.DamEngine.Data/General/Location.cs =================================================================== diff -u -r1581 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Data/General/Location.cs (.../Location.cs) (revision 1581) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/General/Location.cs (.../Location.cs) (revision 1591) @@ -1603,5 +1603,19 @@ var factory = new SensorFactory(); SensorData = factory.CreateSensorLocation(this); } + /// + /// Creates an instance of model parameters for pl lines. + /// + /// + public ModelParametersForPlLines CreateModelParametersForPlLines() + { + return new ModelParametersForPlLines + { + PenetrationLength = ModelParametersForPlLines.PenetrationLength, + DampingFactorPl3 = ModelParametersForPlLines.DampingFactorPl3, + DampingFactorPl4 = ModelParametersForPlLines.DampingFactorPl4, + PlLineCreationMethod = ModelParametersForPlLines.PlLineCreationMethod + }; + } } } \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorLocationSafetyFactorCalculator.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorLocationSafetyFactorCalculator.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorLocationSafetyFactorCalculator.cs (revision 1591) @@ -0,0 +1,59 @@ +// 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.IO; +using Deltares.DamEngine.Calculators.Sensors; +using CalculationHelper = Deltares.DamEngine.Calculators.Sensors.CalculationHelper; + +namespace Deltares.Dam.Data.Sensors +{ + public class SensorLocationSafetyFactorCalculator : ICalculator + { + //internal LogHelper Logger = LogHelper.Create(); + public const double NoValue = -999.99; + + #region ICalculate Member + + double? ICalculator.Calculate(params object[] args) + { + var arg = args[0] as SensorCalculationArgument; + if (arg != null) + return Calculate(arg); + + return NoValue; + } + + #endregion + + public double? Calculate(SensorCalculationArgument args) + { + if (args == null) throw new ArgumentNullException("args"); + + string stabilityWorkingPath = Path.GetFullPath(args.StabilityWorkingPath); + CalculationHelper.CalculateMStabProjects(stabilityWorkingPath, args.StabilityExePath); + + return NoValue; + } + } + + +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.resx =================================================================== diff -u -r1387 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.resx (.../Resources.resx) (revision 1387) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.resx (.../Resources.resx) (revision 1591) @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The file name is not valid. Maybe due to a null or empty string and or invalid characters. Please use a valid file name + GetCotangentOfInnerSlope requires either of characteristic points ShoulderBaseInside or DikeToeAtPolder to be defined. Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationException.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationException.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationException.cs (revision 1591) @@ -0,0 +1,32 @@ +// 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; + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public class TimeSerieCalculationException : Exception + { + public TimeSerieCalculationException(string message) : base(message) + { + } + } +} Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/CalculationParameters.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/CalculationParameters.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/CalculationParameters.cs (revision 1591) @@ -0,0 +1,71 @@ +// 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.IO; +using Deltares.DamEngine.Data.General; + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public class CalculationModules + { + public bool Stability { get; set; } + public bool StabilityOutside { get; set; } + public bool PipingWti { get; set; } + public bool PipingBligh { get; set; } + public bool PipingSellmeijer { get; set; } + public bool PipingSellmeijerProbabilistic { get; set; } + public bool PipingIJkdijk { get; set; } + public bool Overtopping { get; set; } + } + + public class CalculationParameters + { + public string WorkingPath { get; set; } + public string StabilityWorkingPath { get; set; } + public string PipingWorkingPath { get; set; } + public string StabilityExePath { get; set; } + + public bool CalculateAllAtOnce + { + get { return MStabParameters == null || MStabParameters.IsCalculateAllStabilityProjectsAtOnce; } + set { MStabParameters.IsCalculateAllStabilityProjectsAtOnce = value; } + } + + public static CalculationParameters LoadFromFile(FileInfo xmlFile) + { + return LoadFromFile(xmlFile.FullName); + } + + public static CalculationParameters LoadFromFile(string xmlFileName) + { + throw new NotImplementedException(); +// if (string.IsNullOrWhiteSpace(xmlFileName)) throw new ArgumentException("xmlFileName"); +// +// XDocument calculationParametersFileDocument = XDocument.Load(xmlFileName); +// var assembler = new CalculationParametersAssembler(); +// return assembler.CreateDomainObject(calculationParametersFileDocument); + } + + public CalculationModules CalculationModules { get; set; } + public MStabParameters MStabParameters { get; set; } + } +} Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessorException.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessorException.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorTimeSeriesProcessorException.cs (revision 1591) @@ -0,0 +1,48 @@ +// 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.Runtime.Serialization; + +namespace Deltares.DamEngine.Calculators.Sensors +{ + [Serializable] + public class SensorTimeSeriesProcessorException : Exception + { + public SensorTimeSeriesProcessorException() + { + } + + public SensorTimeSeriesProcessorException(string message) : base(message) + { + } + + public SensorTimeSeriesProcessorException(string message, Exception inner) : base(message, inner) + { + } + + protected SensorTimeSeriesProcessorException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ThrowHelper.cs =================================================================== diff -u -r1040 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ThrowHelper.cs (.../ThrowHelper.cs) (revision 1040) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ThrowHelper.cs (.../ThrowHelper.cs) (revision 1591) @@ -20,6 +20,9 @@ // All rights reserved. using System; +using System.Resources; +using Deltares.DamEngine.Data; +using Deltares.DamEngine.Data.Properties; namespace Deltares.DamEngine.Data.Standard { @@ -55,5 +58,34 @@ throw new ArgumentNullException(message); } + /// + /// Throws if file name null or empty. + /// + /// Name of the file. + internal static void ThrowIfFileNameNullOrEmpty(string fileName) + { + ThrowIfFileNameNullOrEmpty(fileName, Resources.FileNameNotValid); + } + /// + /// Throws if file name null or empty. + /// + /// Name of the file. + /// The message. + internal static void ThrowIfFileNameNullOrEmpty(string fileName, string message) + { + ThrowIfFileNameNullOrEmpty(fileName, message); + } + /// + /// Throws if file name null or empty. + /// + /// The type of the exception. + /// Name of the file. + /// The message. + internal static void ThrowIfFileNameNullOrEmpty(string fileName, string message) + where TException : Exception + { + ThrowWhenConditionIsTrue(message, + () => string.IsNullOrEmpty(fileName) || fileName.Trim() == ""); + } } } Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/ICalculator.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/ICalculator.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/ICalculator.cs (revision 1591) @@ -0,0 +1,33 @@ +// 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. + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public interface ICalculator + { + double? Calculate(params object[] args); + } + + public interface ICalculator : ICalculator + { + double? Calculate(T args); + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj =================================================================== diff -u -r1586 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (.../Deltares.DamEngine.Calculators.csproj) (revision 1586) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (.../Deltares.DamEngine.Calculators.csproj) (revision 1591) @@ -159,6 +159,15 @@ Resources.resx + + + + + + + + + Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSeriesProcessor.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSeriesProcessor.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSeriesProcessor.cs (revision 1591) @@ -0,0 +1,202 @@ +// 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 Deltares.DamEngine.Data.General.TimeSeries; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public abstract class TimeSeriesProcessor + { +// internal readonly static LogHelper Logger = LogHelper.Create("Time Series Processor"); + + #region Constants + + /// + /// Defines the default output file + /// + private const string DefaultOutputFileName = "output.xml"; + + /// e + /// Defines the water level location id used in the FEWS time serie + /// + public const string WaterLevelInputLocationID = "outside"; + + /// + /// Defines the parameter id of the water level defined in the FEWS time serie + /// + public const string WaterLevelInputParameterID = "Waterlevel"; + + /// + /// Defines the parameter id for water pressure used in the FEWS time serie + /// + public const string WaterPressureParameterID = "Waterpressure"; + + /// + /// Defines the sensor state missing value + /// + internal const double MissingValue = -999; + + #endregion + + public ICalculator Calculator { protected get; set; } + + /// + /// Gets or sets the output parameter ID. + /// + /// This name or ID is used in the output (FEWS) time series + /// + /// The output parameter ID. + /// + public IEnumerable OutputParameters { get; set; } + + /// + /// Sets the input time series, used in the calculations + /// + public TimeSerieCollection InputTimeSeriesCollection { protected get; set; } + + /// + /// Gets or sets the output location ID colletion used for creating the output time series + /// + public virtual IEnumerable OutputLocations { get; set; } + + /// + /// Gets or the output time series + /// + public TimeSerieCollection OutputTimeSeriesCollection { get; set; } + + /// + /// Resets the monitoring point list + /// + public virtual void Initialize() + { + if (OutputTimeSeriesCollection == null) + OutputTimeSeriesCollection = InputTimeSeriesCollection.GetShallowCopy(); + else + OutputTimeSeriesCollection.Clear(); + } + + /// + /// Loads the input time series. + /// + /// Name of the file. + public void LoadInputTimeSeries(string fileName) + { + throw new NotImplementedException(); +// ThrowHelper.ThrowIfFileNameNullOrEmpty(fileName); +// try +// { +// // load the input time serie containing all water levels +// InputTimeSeriesCollection = TimeSerieCollection.LoadFromFile(fileName); +// } +// catch (Exception e) +// { +// throw new InvalidOperationException("There was an error loading the input time series", e); +// } + } + + /// + /// Saves the output time series to the specified file + /// + /// + /// The output file that will contain the monitored and calculated results for each time entry + public void SaveResultsToFile(string fileName) + { + throw new NotImplementedException(); +// if (OutputTimeSeriesCollection == null) +// throw new InvalidOperationException("No output time series collection to write"); +// +// if (string.IsNullOrWhiteSpace(fileName)) +// { +// fileName = DefaultOutputFileName; +// } +// +// // save the time serie to the output file +// OutputTimeSeriesCollection.Save(fileName); + } + + /// + /// Processes the FEWS input time series files to ouput + /// time series + /// + public virtual void Process() + { + if (InputTimeSeriesCollection == null) + return; + + if (OutputTimeSeriesCollection == null) + throw new InvalidOperationException("No output time series set to write the results to"); + + if (OutputLocations == null) + throw new InvalidOperationException("No output locations set. Set or override OutputLocations"); + + if (OutputParameters == null) + throw new InvalidOperationException("No output parameters set. Set or override OutputParameters"); + + try + { + // Process the time series entries for each sensor and set the + // value in the output time series + CreateOutputSeries(); + } + catch (Exception e) + { + const string message = "There was an error processing the time series"; + // Logger.LogFatal(message, e); + throw new InvalidOperationException(message, e); + } + } + + /// + /// Processes the actual input to the output collection. This is a template method which will + /// be called in the public ProcessSeries() method (if not overriden) + /// + protected virtual void CreateOutputSeries() + { + foreach (var timeSeries in InputTimeSeriesCollection.Series) + { + foreach (var location in OutputLocations) + { + foreach (var parameter in OutputParameters) + { + var copyOfSeries = timeSeries.GetShallowCopy(); + foreach (var entry in timeSeries.Entries) + { + // get copy of the input entry + var copyOfEntry = entry.GetShallowCopy(); + // calculate its value + copyOfEntry.Value = Calculator.Calculate(location, parameter) ?? MissingValue; + + // set parameter and location id's and add the projected entry to the output + copyOfSeries.LocationId = location; + copyOfSeries.ParameterId = parameter; + copyOfSeries.Entries.Add(copyOfEntry); + } + // add the output series to the output collection + OutputTimeSeriesCollection.Series.Add(copyOfSeries); + } + } + } + } + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorCalculationArgument.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorCalculationArgument.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/SensorCalculationArgument.cs (revision 1591) @@ -0,0 +1,29 @@ +// 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. + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public class SensorCalculationArgument + { + public string StabilityWorkingPath { get; set; } + public string StabilityExePath { get; set; } + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationHelper.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationHelper.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Sensors/TimeSerieCalculationHelper.cs (revision 1591) @@ -0,0 +1,500 @@ +// 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.Globalization; +using System.IO; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon.Assemblers; +using Deltares.DamEngine.Calculators.Stability; +using Deltares.DamEngine.Calculators.Uplift; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Calculators.Sensors +{ + public class StabilityProjectFileCreationArguments + { + public string DikeName { get; set; } + public Location Location { get; set; } + public int EntryCount { get; set; } + public DateTime EntryDateTime { get; set; } + public MStabModelType Model { get; set; } + public string StabilityWorkingPath { get; set; } + public string SoilGeometry2DName { get; set; } + public SoilProfileType SoilGeometryType { get; set; } + public PlLines PlLines { get; set; } + public FailureMechanismSystemType FailureMechanismType { get; set; } + public MStabParameters StabilityParameters { get; set; } + public string StabilityExePath { get; set; } + } + + internal class CalculationHelper + { + internal static string CreateStabilityProjectFile(StabilityProjectFileCreationArguments arg) + { + throw new NotImplementedException(); +// var location = arg.Location; +// var model = arg.Model; +// +// var fileName = GetProjectFileName(arg.DikeName, location, null, model, arg.StabilityWorkingPath, arg.EntryDateTime); +// +// // get all the parameters needed for the calculation +// var damCalculation = GetCalculationSpecification(arg, fileName); +// +// // Create the project file +// CreateMStabProjectFile(damCalculation.FailureMechanismeParamatersMStab, arg.StabilityExePath); +// +// return fileName; + } + + + internal static IEnumerable GetStabilityModels(bool isCombinedBishopUpliftVan, Location location, PlLines PlLines, string soilGeometry2DName, MStabModelType defaultModel) + { + double? upliftFactor = GetLowestUpliftFactor(location.SurfaceLine, + location.Segment.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), soilGeometry2DName, PlLines, location); + return !isCombinedBishopUpliftVan ? new List { defaultModel } : GetMStabModelsToCalculate(upliftFactor); + } + + internal static DamFailureMechanismeCalculationSpecification GetCalculationSpecification(StabilityProjectFileCreationArguments arguments, string projectFileName) + { + throw new NotImplementedException(); +// return GetCalculationSpecification(arguments.FailureMechanismType, arguments.Location, +// arguments.SoilGeometry2DName, arguments.SoilGeometryType, +// arguments.PlLines, arguments.StabilityParameters, arguments.Model, +// arguments.Location.SoildatabaseName, projectFileName); + } + + internal static DamFailureMechanismeCalculationSpecification GetCalculationSpecification( + FailureMechanismSystemType failureMechanismType, + Location location, string soilGeometry2DName, + SoilProfileType soilProfileType, + PlLines PlLines, + MStabParameters mstabParameters, MStabModelType model, + string soilDatabasePath, string projectFileName) + { + // Note: local use of new calculationSpecification for now ok but might be unwanted in future when you want to use multiple specifications + var calculationSpecification = new DamFailureMechanismeCalculationSpecification(); + BuildDamCalculation(failureMechanismType, location, soilGeometry2DName, soilProfileType, PlLines, mstabParameters, model, calculationSpecification, soilDatabasePath, projectFileName); + return calculationSpecification; + } + + /// + /// Fill damCalculation with the appropriate values + /// + internal static void BuildDamCalculation(FailureMechanismSystemType failureMechanismType, Location location, string soilGeometry2DName, SoilProfileType soilGeometryType, + PlLines PlLines, + MStabParameters mstabParameters, MStabModelType model, + DamFailureMechanismeCalculationSpecification damCalculation, string soilDatabasePath, string projectFileName) + { + throw new NotImplementedException(); +// damCalculation.FailureMechanismeParamatersMStab = +// new FailureMechanismeParamatersMStab +// { +// Location = location, +// SurfaceLine = location.LocalXZSurfaceLine2, +// PlLines = PlLines, +// DupuitPlLines = dupuitPlLines, +// SoilProfile = location.Segment.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), +// TrafficLoad = location.TrafficLoad, +// MStabParameters = +// new MStabParameters +// { +// SoilDatabaseName = soilDatabasePath, +// Model = model, +// ProjectFileName = projectFileName, +// GeometryCreationOptions = +// { +// SoilProfileType = soilGeometryType, +// SoilGeometry2DFilename = soilGeometry2DName, +// MaterialForDike = location.DikeEmbankmentMaterial, +// MaterialForShoulder = location.ShoulderEmbankmentMaterial, +// XOffsetSoilGeometry2DOrigin = -location.XSoilGeometry2DOrigin, +// IsUseOriginalPlLineAssignments = location.IsUseOriginalPlLineAssignments +// } +// } +// }; +// damCalculation.FailureMechanismeParamatersMStab.MStabParameters.GridPosition = +// failureMechanismType == FailureMechanismSystemType.StabilityOutside ? MStabGridPosition.Left : MStabGridPosition.Right; +// +// MStabParameters parameters = damCalculation.FailureMechanismeParamatersMStab.MStabParameters; +// parameters.GeometryCreationOptions.PlLineAssignment = PlLineCreationMethod2PlLineAssignment(location.PlLineCreationMethod); +// if (location.IsUseOriginalPlLineAssignments) +// parameters.GeometryCreationOptions.PlLineAssignment = PlLineAssignment.OrginalPlLines; +// parameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = location.IntrusionVerticalWaterPressure.Value; +// parameters.GeometryCreationOptions.PenetrationLength = location.PenetrationLength; +// switch (failureMechanismType) +// { +// case FailureMechanismSystemType.StabilityOutside: +// parameters.GridPosition = MStabGridPosition.Left; +// break; +// default: +// parameters.GridPosition = MStabGridPosition.Right; +// break; +// } +// +// parameters.ShearStrength = mstabParameters.ShearStrength; +// parameters.IsProbabilistic = mstabParameters.IsProbabilistic; +// parameters.SearchMethod = mstabParameters.SearchMethod; +// parameters.CalculationOptions = mstabParameters.CalculationOptions; +// parameters.CalculationOptions.MinimalCircleDepth = location.MinimalCircleDepth; +// +// if (location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope == null) +// { +// location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope = 1.0; +// } +// +// parameters.ZoneAreas = new MStabZoneAreas +// { +// SafetyFactorZone1A = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value, +// SafetyFactorZone1B = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value, +// DikeTableHeight = location.SurfaceLine.GetDefaultDikeTableHeight().Value, +// DikeTableWidth = location.ZoneAreaRestSlopeCrestWidth, +// XCoordinateDikeTopAtPolder = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, +// XCoordinateDikeTopAtRiver = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X, +// XCoordinateStartRestProfile = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X +// }; +// +// // Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculation +// parameters.SlipCircleDefinition.Assign(mstabParameters.SlipCircleDefinition); +// if (parameters.Model == MStabModelType.UpliftVan) +// { +// // Determine right side of slip plane grid (right grid) +// // This is the location with the lowest uplift factor or, if present, the second NWO point +// SurfaceLine2 surfaceLine = location.SurfaceLine; +// var upliftLocationAndResult = GetLocationWithLowestUpliftFactor(surfaceLine, location.Segment.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), soilGeometry2DName, PlLines, location); +// double upliftCriterion = location.UpliftCriterionStability.Value; +// bool isUplift = !(upliftLocationAndResult == null) && (upliftLocationAndResult.UpliftFactor < upliftCriterion); +// double xCoordinateLastUpliftPoint = isUplift ? upliftLocationAndResult.X : surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; +//// if (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2) != null) +//// { +//// xCoordinateLastUpliftPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2).X; +//// } +// parameters.SlipCircleDefinition.XCoordinateLastUpliftPoint = xCoordinateLastUpliftPoint; +// } +// +// if (parameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone)) +// { +// var surfaceLine = damCalculation.FailureMechanismeParamatersMStab.SurfaceLine; +// double maxZoneX = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X + +// location.ForbiddenZoneFactor * (surfaceLine.GetDikeToeInward().X - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X); +// parameters.ForbiddenZone = new MStabForbiddenZone +// { +// IsXEntryMinUsed = false, +// XEntryMin = 0.0, +// IsXEntryMaxUsed = true, +// XEntryMax = maxZoneX +// }; +// } + } + + /// + /// Converts PlLineCreationMethod (from location) to PlLineAssignment + /// + /// The pl line creation method. + /// the pl line assignment method + public static PlLineAssignment PlLineCreationMethod2PlLineAssignment(PlLineCreationMethod PlLineCreationMethod) + { + PlLineAssignment PlLineAssignment = PlLineAssignment.ExpertKnowledge; + switch (PlLineCreationMethod) + { +// case PlLineCreationMethod.DupuitDynamic: +// case PlLineCreationMethod.DupuitStatic: +// PlLineAssignment = PlLineAssignment.DikeFlow; +// break; + case PlLineCreationMethod.ExpertKnowledgeRRD: + case PlLineCreationMethod.ExpertKnowledgeLinearInDike: + case PlLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD: + PlLineAssignment = PlLineAssignment.ExpertKnowledge; + break; + } + return PlLineAssignment; + } + + /// + /// Gets the location with lowest uplift factor. + /// + /// The surface line. + /// The soil profile. + /// Name of the soil geometry2 D. + /// The pl lines. + /// The location. + /// + static public UpliftLocationAndResult GetLocationWithLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PlLines PlLines, Location location) + { + throw new NotImplementedException(); +// UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator() +// { +// SurfaceLine = surfaceLine, +// SoilProfile = soilProfile, +// SoilGeometry2DName = soilGeometry2DName, +// SoilBaseDB = location.SoilbaseDB, +// SoilList = location.SoilList, +// DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), +// PlLines = PlLines, +// XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin +// }; +// return upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); + } + + /// + /// Calculate all generated MStab files + /// + /// + /// + internal static void CalculateMStabProjects(string directory, string mstabExePath) + { + throw new NotImplementedException(); +// var agent = new StabilityServiceAgent { MStabExePath = mstabExePath }; +// agent.CalculateMStabDirectory(directory); + } + + /// + /// Calculate all generated MStab files + /// + internal static void CalculateMStabProjects(IEnumerable projectFilenames, string stabilityExePath) + { + throw new NotImplementedException(); +// var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath }; +// foreach (string mstabProjectFilename in projectFilenames) +// { +// string mstabProjectFullFilename = Path.GetFullPath(mstabProjectFilename); +// agent.CalculateMStabProject(mstabProjectFullFilename); +// } + } + + /// + /// Determine name of Stability project file + /// + internal static string GetProjectFileName(string dikeName, Location location, int? jobCount, MStabModelType? model, string stabilityWorkingPath, DateTime? dateTime) + { + string calculationName = String.Format("Dik({0})_Loc({1})", dikeName, location.Name); + if (jobCount != null) + { + calculationName = calculationName + String.Format("_Stp({0})", jobCount); + } + if (model != null) + { + calculationName = calculationName + String.Format("_Mdl({0})", model); + } + if (dateTime != null) + { + calculationName = calculationName + "_" + DateToTimeStamp(dateTime.Value); + } + calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); + // assemble the target project file name + return Path.Combine(stabilityWorkingPath, calculationName + ".sti"); + } + + /// + /// Convert Date to time stamp as needed by TNO AnySense. + /// + /// The date time. + /// + public static string DateToTimeStamp(DateTime dateTime) + { + // Following 2 lines is an example how to handle customization of this format. + // TNO at the last moment decided they did not need this change so we change it back to + // the default format + // string customFormat = "yyyy-MM-dd_HH-mm-ss"; + // return dateTime.ToString(customFormat); + return dateTime.ToString("s", DateTimeFormatInfo.InvariantInfo); + } + + /// + /// Select which models to calculate dependent on uplift factor + /// + internal static IList GetMStabModelsToCalculate(double? upliftFactor) + { + const double CBishopMinimum = 1.0; + const double CLiftVanMaximum = 1.2; + + var models = new List(); + + if (!upliftFactor.HasValue || upliftFactor >= CBishopMinimum) + models.Add(MStabModelType.Bishop); + if (!upliftFactor.HasValue || upliftFactor <= CLiftVanMaximum) + models.Add(MStabModelType.UpliftVan); + + return models; + } + + /// + /// Determine where lowest uplift factor occurs and the value of that factor + /// + internal static double? GetLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PlLines PlLines, Location location) + { + throw new NotImplementedException(); +// var upliftLocationDeterminator = new UpliftLocationDeterminator() +// { +// SurfaceLine = surfaceLine, +// SoilProfile = soilProfile, +// SoilGeometry2DName = soilGeometry2DName, +// SoilBaseDB = location.SoilbaseDB, +// SoilList = location.SoilList, +// DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), +// PlLines = PlLines, +// XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin +// }; +// +// UpliftLocationAndResult upliftLocationAndResult = upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); +// if (upliftLocationAndResult != null) +// return upliftLocationAndResult.UpliftFactor; +// +// return null; + } + + /// + /// Creates all PL lines. + /// + /// The water level. + /// The location. + /// Name of the soil geometry2 D. + /// Type of the soil geometry. + /// + internal static PlLines CreateAllPlLines(double waterLevel, Location location, string soilGeometry2DName, SoilProfileType soilGeometryType) + { + // When calculating with timeseries, we want PL3 and PL4 to derive the head from the waterlevel. + // We can force that by overruling the location HeadPl3 and HeadPl4 with null, + // because then in PlLinesCreator the waterlevel is used as head for Pl3 and Pl4 + // for stability this must set to true + var PlLinesCreator = new PlLinesCreator.PlLinesCreator + { + WaterLevelRiverHigh = waterLevel, + SurfaceLine = location.SurfaceLine, + WaterLevelPolder = location.PolderLevel, + HeadInPlLine2 = location.HeadPl2, + HeadInPlLine3 = null, + HeadInPlLine4 = null, + ModelParametersForPlLines = location.CreateModelParametersForPlLines(), + SoilProfile = location.Segment.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), + SoilGeometry2DName = soilGeometry2DName, + SoilProfileType = soilGeometryType, + GaugePlLines = location.GaugePlLines, + Gauges = location.Gauges, + GaugeMissVal = location.GaugeMissVal, + IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true, + PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver, + PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder, + PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle, + PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest, + UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle, + UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest, +// SoilBaseDB = location.SoilbaseDB, + SoilList = location.SoilList, + DikeEmbankmentMaterial = location.SoilList.GetSoilByName(location.DikeEmbankmentMaterial), + XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin + }; + + PlLines PlLines = PlLinesCreator.CreateAllPlLines(location); + return PlLines; + } + + /// + /// Create and write the XML definiton file for the MStab project + /// Call the stability agent to create the stability project file + /// + internal static void CreateMStabProjectFile()//FailureMechanismeParamatersMStab failureMechanismeParamatersMStab, string stabilityExePath) + { + throw new NotImplementedException(); +// var assembler = new DamMStabAssembler(); +// XDocument xDocument = assembler.CreateDataTransferObject(failureMechanismeParamatersMStab); +// var fileName = failureMechanismeParamatersMStab.MStabParameters.ProjectFileName + ".xml"; +// xDocument.Save(fileName); +// +// // call the stability agent to create a MStab specific (xml) file +// var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath }; +// agent.CreateProjectFile(xDocument.ToString()); + } + + /// + /// Determine the minimal safety factor for a set of MStab projects + /// + internal static double DetermineSafetyFactor(IEnumerable mstabProjectPaths, ref string basisFileName, string stabilityExePath) + { + throw new NotImplementedException(); +// var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath }; +// +// double? minimumSafetyFactor = null; +// +// foreach (string path in mstabProjectPaths) +// { +// MStabResults mStabResults = agent.ExtractStabilityResults(path); +// if (!minimumSafetyFactor.HasValue || mStabResults.zone1.safetyFactor < minimumSafetyFactor) +// { +// minimumSafetyFactor = mStabResults.zone1.safetyFactor; +// basisFileName = path; +// } +// } +// +// return minimumSafetyFactor ?? 0; + } + + public static SoilGeometryBase GetSoilGeometryType(Location location, string workingPath) + { + var geom = GetSoilGeometryType(location); + if (!geom.SoilGeometryName.Contains(workingPath)) + geom.SoilGeometryName = Path.Combine(workingPath, geom.SoilGeometryName); + return geom; + } + + private static SoilGeometryBase GetSoilGeometryType(Location location) + { + SoilProfileType soilGeometryType; + string soilGeometry2DName; + DetermineSoilGeometryType(location, out soilGeometryType, out soilGeometry2DName); + return new SoilGeometryBase { SoilProfileType = soilGeometryType, SoilGeometryName = soilGeometry2DName }; + } + + /// + /// Determines the type of the soil geometry (1D or 2D). + /// + /// The location. + /// Type of the soil geometry. + /// Name of the soil geometry2 D. + internal static void DetermineSoilGeometryType(Location location, out SoilProfileType soilGeometryType, out string soilGeometry2DName) + { + SoilProfile1D soilProfile = location.Segment.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside); + soilGeometry2DName = location.Segment.GetMostProbableGeometry2DName(FailureMechanismSystemType.StabilityInside); + string mapForSoilGeometries2D = location.StabilityOptions.SoilGeometries2DPath; + if ((soilGeometry2DName != null) && (mapForSoilGeometries2D != null)) + { + soilGeometry2DName = Path.Combine(mapForSoilGeometries2D, soilGeometry2DName); + } + if (soilProfile != null) + { + soilGeometryType = SoilProfileType.ProfileType1D; + } + else + { + if (soilGeometry2DName == null) + { + throw new TimeSerieCalculationException(String.Format("Location {0} does not have a soilprofile assigned", location.Name)); + } + soilGeometryType = SoilProfileType.ProfileTypeStiFile; + } + } + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.nl-NL.resx =================================================================== diff -u -r1387 -r1591 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 1387) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 1591) @@ -120,6 +120,9 @@ GetPointSegmentIncluding(): Eindwaarde is kleiner dan de startwaarde + + Bestandsnaam is ongeldig. Het bevat ofwel ongeldige karakters, of het is leeg. Geef een geldige naam op. + GetCotangentOfInnerSlope heeft karakteristiek punt insteek berm of dijk teen polderzijde nodig.