Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Interface.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/nl-NL/Deltares.DamEngine.Interface.resources.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Interface.pdb
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/src/Deltares.DamEngine.Version/GlobalAssembly.cs.svn
===================================================================
diff -u
--- DamEngine/tags/19.2.1/src/Deltares.DamEngine.Version/GlobalAssembly.cs.svn (revision 0)
+++ DamEngine/tags/19.2.1/src/Deltares.DamEngine.Version/GlobalAssembly.cs.svn (revision 3351)
@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Deltares")]
+[assembly: AssemblyCopyright("Copyright © Deltares 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: AssemblyVersion("19.2.1.SVNREV")]
+[assembly: AssemblyFileVersion("19.2.1.SVNREV")]
\ No newline at end of file
Index: DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/Uplift/UpliftLocationDeterminator.cs
===================================================================
diff -u
--- DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/Uplift/UpliftLocationDeterminator.cs (revision 0)
+++ DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/Uplift/UpliftLocationDeterminator.cs (revision 3351)
@@ -0,0 +1,296 @@
+// Copyright (C) Stichting Deltares 2019. 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.DamEngine.Calculators.General;
+using Deltares.DamEngine.Data.General;
+using Deltares.DamEngine.Data.General.PlLines;
+using Deltares.DamEngine.Data.Geometry;
+using Deltares.DamEngine.Data.Geotechnics;
+
+namespace Deltares.DamEngine.Calculators.Uplift
+{
+ ///
+ /// Determie uplift location and uplift factor
+ ///
+ public class UpliftLocationDeterminator
+ {
+ public bool IsUseOvenDryUnitWeight { get; set; }
+ public PlLines PlLines { get; set; }
+ public SurfaceLine2 SurfaceLine { get; set; }
+ public SoilProfile1D SoilProfile { get; set; }
+ public SoilProfile2D SoilProfile2D { get; set; }
+ public string SoilGeometry2DName { get; set; }
+
+ ///
+ /// Gets or sets the path for the sti file (SoilGeometry2DName).
+ ///
+ ///
+ /// The path for the sti file .
+ ///
+ public string PathForStiFile { get; set; }
+
+ public Soil DikeEmbankmentMaterial { get; set; }
+ // public SoilbaseDB SoilBaseDB { get; set; }
+ public SoilList SoilList { get; set; }
+ public double XSoilGeometry2DOrigin { get; set; }
+
+ ///
+ /// Constructor
+ ///
+ public UpliftLocationDeterminator()
+ {
+ IsUseOvenDryUnitWeight = false;
+ }
+
+ ///
+ /// Get location nearest dike with and upliftfactor lower than required
+ ///
+ /// location and upliftfactor
+ public UpliftLocationAndResult GetLocationAndResult(double upliftCriterion)
+ {
+ ThrowIfNoPlLinesDefined();
+ ThrowIfNoSurfaceLinDefined();
+ ThrowIfNoSoilProfileDefined();
+
+ return GetLocationInPolderNearestDikeWithUpliftFactorLowerThanRequired(upliftCriterion);
+ }
+
+ ///
+ /// Get location nearest dike with and upliftfactor lower than required
+ ///
+ /// location and upliftfactor
+ public UpliftLocationAndResult GetLocationInPolderNearestDikeWithUpliftFactorLowerThanRequired(double upliftCriterion)
+ {
+ ThrowIfNoPlLinesDefined();
+ ThrowIfNoSurfaceLinDefined();
+ ThrowIfNoSoilProfileDefined();
+
+ GeometryPoint startSurfacePoint = SurfaceLine.GetDikeToeInward();
+
+ IEnumerable relevantSurfacePointsList = from GeometryPoint point in SurfaceLine.Geometry.Points
+ where point.X >= startSurfacePoint.X
+ orderby point.X ascending
+ select point;
+
+ bool foundUpliftFactor = false;
+ UpliftLocationAndResult upliftLocationAndResult = null;
+ foreach (GeometryPoint surfacePoint in relevantSurfacePointsList)
+ {
+ upliftLocationAndResult = GetUpliftFactorAtPoint(surfacePoint);
+ if ((upliftLocationAndResult != null) && (upliftLocationAndResult.UpliftFactor < upliftCriterion))
+ {
+ foundUpliftFactor = true;
+ upliftLocationAndResult.X = surfacePoint.X;
+ upliftLocationAndResult.Z = surfacePoint.Z;
+ break;
+ }
+ }
+ return (foundUpliftFactor == true) ? upliftLocationAndResult : null;
+ }
+
+ ///
+ /// Create upliftcalculator at given point
+ ///
+ /// GeometryPoint for which to calculate upliftfactor
+ /// Top of layer where uplift occurs
+ /// location and upliftfactor
+ private UpliftCalculator CreateUpliftCalculator(GeometryPoint point, double topOfLayer, SoilProfile1D soilProfile)
+ {
+ PlLine phreaticLine = PlLines.Lines[PlLineType.Pl1];
+ return new UpliftCalculator
+ {
+
+ PhreaticLevel = phreaticLine.ZFromX(point.X),
+ SoilProfile = soilProfile,
+ TopOfLayerToBeEvaluated = topOfLayer,
+ SurfaceLevel = point.Z,
+ UnitWeightSoilEmbankment = (this.DikeEmbankmentMaterial == null) ? (double?) null : this.DikeEmbankmentMaterial.AbovePhreaticLevel,
+ IsUseOvenDryUnitWeight = this.IsUseOvenDryUnitWeight
+ };
+ }
+
+ ///
+ /// Calculate upliftfactor for given point
+ ///
+ ///
+ /// location and upliftfactor
+ public UpliftLocationAndResult GetUpliftFactorAtPoint(GeometryPoint point)
+ {
+ SoilProfile1D soilProfileInCurrentPoint = GetSoilProfileBelowPoint(point.X);
+ double upliftFactorForInBetweenSandLayer = double.MaxValue;
+ if (soilProfileInCurrentPoint.InBetweenAquiferLayer != null)
+ {
+ // Check if inbetween sandlayer below surface
+ double topInBetweenSandLayer = soilProfileInCurrentPoint.InBetweenAquiferLayer.TopLevel;
+ if (topInBetweenSandLayer < point.Z)
+ {
+ // There is an aquitard above the aquifer, for which we can determine the uplift factor
+ UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, topInBetweenSandLayer, soilProfileInCurrentPoint);
+ if ( (PlLines.Lines[PlLineType.Pl4] != null) && (PlLines.Lines[PlLineType.Pl4].Points.Count > 0 ))
+ upliftFactorForInBetweenSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl4].ZFromX(point.X));
+ }
+ else
+ {
+ if (soilProfileInCurrentPoint.GetBottomLevel(soilProfileInCurrentPoint.InBetweenAquiferLayer) < point.Z)
+ {
+ // The surface cuts into the aquifer so the level to be evaluated is at surfacelevel
+ UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, point.Z, soilProfileInCurrentPoint);
+ if ((PlLines.Lines[PlLineType.Pl4] != null) && (PlLines.Lines[PlLineType.Pl4].Points.Count > 0))
+ upliftFactorForInBetweenSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl4].ZFromX(point.X));
+
+ }
+ }
+ }
+
+ double upliftFactorForBottomSandLayer = double.MaxValue;
+ if (soilProfileInCurrentPoint.BottomAquiferLayer != null)
+ {
+ // Check if bottom sandlayer below surface
+ double topBottomSandLayer = soilProfileInCurrentPoint.BottomAquiferLayer.TopLevel;
+ if (topBottomSandLayer < point.Z)
+ {
+ UpliftCalculator upliftCalculatorForBottomSandLayer = CreateUpliftCalculator(point, soilProfileInCurrentPoint.BottomAquiferLayer.TopLevel, soilProfileInCurrentPoint);
+ if ((PlLines.Lines[PlLineType.Pl3] != null) && (PlLines.Lines[PlLineType.Pl3].Points.Count > 0))
+ upliftFactorForBottomSandLayer = upliftCalculatorForBottomSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl3].ZFromX(point.X));
+ }
+ else
+ {
+ if (soilProfileInCurrentPoint.GetBottomLevel(soilProfileInCurrentPoint.BottomAquiferLayer) < point.Z)
+ {
+ // The surface cuts into the aquifer so the level to be evaluated is at surfacelevel
+ UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, point.Z, soilProfileInCurrentPoint);
+ if ((PlLines.Lines[PlLineType.Pl3] != null) && (PlLines.Lines[PlLineType.Pl3].Points.Count > 0))
+ upliftFactorForBottomSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl3].ZFromX(point.X));
+
+ }
+ }
+
+ }
+
+ if((upliftFactorForBottomSandLayer == double.MaxValue) && (upliftFactorForInBetweenSandLayer == double.MaxValue))
+ return null;
+
+ if (SoilProfile == null)
+ {
+ SoilProfile = soilProfileInCurrentPoint;
+ }
+ if (upliftFactorForBottomSandLayer < upliftFactorForInBetweenSandLayer)
+ {
+ return new UpliftLocationAndResult(point, upliftFactorForBottomSandLayer, soilProfileInCurrentPoint.BottomAquiferLayer.Name);
+ }
+ else
+ {
+ return new UpliftLocationAndResult(point, upliftFactorForInBetweenSandLayer, soilProfileInCurrentPoint.InBetweenAquiferLayer.Name);
+ }
+ }
+
+ ///
+ /// Determine location with lowest upliftfactor
+ ///
+ /// location and upliftfactor
+ public UpliftLocationAndResult GetLocationAtWithLowestUpliftFactor()
+ {
+ double? lowestUpliftFactor = null;
+
+ ThrowIfNoPlLinesDefined();
+ ThrowIfNoSurfaceLinDefined();
+ ThrowIfNoSoilProfileDefined();
+
+ GeometryPoint startSurfacePoint = SurfaceLine.GetDikeToeInward();
+ IEnumerable relevantSurfacePointsList = from GeometryPoint point in SurfaceLine.Geometry.Points
+ where point.X >= startSurfacePoint.X
+ orderby point.X ascending
+ select point;
+ UpliftLocationAndResult upliftLocationAndResult = null;
+ UpliftLocationAndResult lowestUpliftLocationAndResult = null;
+ foreach (GeometryPoint surfacePoint in relevantSurfacePointsList)
+ {
+ upliftLocationAndResult = GetUpliftFactorAtPoint(surfacePoint);
+ if (upliftLocationAndResult != null)
+ {
+ if (!lowestUpliftFactor.HasValue || upliftLocationAndResult.UpliftFactor < lowestUpliftFactor)
+ {
+ lowestUpliftFactor = upliftLocationAndResult.UpliftFactor;
+ lowestUpliftLocationAndResult = upliftLocationAndResult;
+ }
+ }
+ }
+ return lowestUpliftLocationAndResult;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ private SoilProfile1D GetSoilProfileBelowPoint(double xCoordinate)
+ {
+ if (this.SoilProfile != null)
+ {
+ return this.SoilProfile;
+ }
+ if (SoilProfile2D != null)
+ {
+ return SoilProfile2D.GetSoilProfile1D(xCoordinate);
+ }
+
+ var soilGeometry2DName = SoilGeometry2DName;
+ if (!File.Exists(this.SoilGeometry2DName))
+ {
+ soilGeometry2DName = PathForStiFile + SoilGeometry2DName;
+ }
+ var geometry2DTo1DConverter = new Geometry2DTo1DConverter(soilGeometry2DName, this.SurfaceLine, this.DikeEmbankmentMaterial, this.SoilList, -this.XSoilGeometry2DOrigin);
+ return geometry2DTo1DConverter.Convert(xCoordinate);
+ }
+
+ ///
+ /// Check on precondition
+ ///
+ private void ThrowIfNoPlLinesDefined()
+ {
+ if (PlLines == null)
+ throw new UpliftLocationDeterminatorException("Required pllines not found");
+ }
+
+ ///
+ /// Check on precondition
+ ///
+ private void ThrowIfNoSurfaceLinDefined()
+ {
+ if (SurfaceLine == null)
+ throw new UpliftLocationDeterminatorException("Required surfaceLine line not found");
+ }
+
+ ///
+ /// Check on precondition
+ ///
+ private void ThrowIfNoSoilProfileDefined()
+ {
+ if (SoilProfile == null && (SoilGeometry2DName == null || SoilGeometry2DName == "") && SoilProfile2D == null)
+ throw new UpliftLocationDeterminatorException("Required soilProfile not found");
+ }
+
+ }
+}
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Calculators.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/OperationalWesterDijkPipingTests.cs
===================================================================
diff -u
--- DamEngine/tags/19.2.1/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/OperationalWesterDijkPipingTests.cs (revision 0)
+++ DamEngine/tags/19.2.1/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/OperationalWesterDijkPipingTests.cs (revision 3351)
@@ -0,0 +1,82 @@
+// Copyright (C) Stichting Deltares 2020. 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 System.Text;
+using Deltares.DamEngine.Interface;
+using Deltares.DamEngine.Io;
+using Deltares.DamEngine.TestHelpers;
+using NUnit.Framework;
+
+namespace Deltares.DamEngine.IntegrationTests.IntegrationTests
+{
+ [TestFixture]
+ class OperationalWesterDijkPipingTests
+ {
+ private const double Tolerance = 0.0005;
+
+ [Test]
+ public void Run_UsingTestFiles_HasExpectedResultsInOutputFileForDamPipingBligh()
+ {
+ const string calcDir = "TestOperationalWesterdijk";
+ const string workingDir = @"TestFiles\";
+ const string baseTestDirectory = @".\";
+ if (Directory.Exists(calcDir))
+ {
+ Directory.Delete(calcDir, true); // delete previous results
+ }
+
+ Directory.CreateDirectory(calcDir);
+ // Switch to TestFiles directory to check if DamLive can also run from another directory
+ Directory.SetCurrentDirectory(workingDir);
+
+ const string inputFileName = baseTestDirectory + @"WesterdijkPiping.xml";
+ const string outputFileName = baseTestDirectory + @"WesterdijkPiping.output.xml";
+ string inputString = File.ReadAllText(inputFileName);
+ inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used
+ inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used
+ inputString = XmlAdapter.ChangeValueInXml(inputString, "MapForSoilgeometries2D", baseTestDirectory + @"Operational\WesterDijkPiping\input.Geometries\");
+ inputString = XmlAdapter.ChangeValueInXml(inputString, "SoilDatabaseName", baseTestDirectory + @"Operational\WesterDijkPiping\HHNK_Westerdijk0.soilmaterials.mdb");
+ EngineInterface engineInterface = new EngineInterface(inputString);
+ Assert.IsNotNull(engineInterface.DamProjectData);
+
+ string result = engineInterface.Validate();
+ Assert.IsTrue(result == null, "Validation must succeed but does not, see validation output xml in debugger");
+ string outputString = engineInterface.Run();
+ File.WriteAllText(outputFileName, outputString, Encoding.Unicode);
+ Assert.IsNotNull(outputString);
+ var output = DamXmlSerialization.LoadOutputFromXmlString(outputString);
+
+ // These are now just the values that were produced by Dam itself. But these are checked by hand as well! So they are correct.
+ Assert.AreEqual(90, output.Results.OperationalOutputTimeSeries[0].Entries.TimeSerieEntry[0].Value, Tolerance);
+ // Second location has no soilprofiles for current mechanism, so no result (NaN). See the warning in the messages.
+ Assert.AreEqual(Double.NaN, output.Results.OperationalOutputTimeSeries[1].Entries.TimeSerieEntry[0].Value, Tolerance);
+ Assert.AreEqual(3.294, output.Results.OperationalOutputTimeSeries[2].Entries.TimeSerieEntry[0].Value, Tolerance);
+ Assert.AreEqual(2.4925, output.Results.OperationalOutputTimeSeries[9].Entries.TimeSerieEntry[0].Value, Tolerance);
+ Assert.AreEqual(2, output.Results.CalculationMessages.Length);
+ Assert.AreEqual(
+ "Location 'Dijk_20_DWP_16+102_gedraineerd_zonderBB' has no soil profiles defined for the current failure mechanism Piping",
+ output.Results.CalculationMessages[1].Message1);
+
+ }
+ }
+}
Index: DamEngine/tags/19.2.1/release/nl-NL/Deltares.DamEngine.Data.resources.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/nl-NL/Deltares.DamEngine.Calculators.resources.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Version.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Io.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/src/Deltares.DamEngine.Data/General/Dike.cs
===================================================================
diff -u
--- DamEngine/tags/19.2.1/src/Deltares.DamEngine.Data/General/Dike.cs (revision 0)
+++ DamEngine/tags/19.2.1/src/Deltares.DamEngine.Data/General/Dike.cs (revision 3351)
@@ -0,0 +1,438 @@
+// Copyright (C) Stichting Deltares 2019. 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.ComponentModel;
+using System.Linq;
+using Deltares.DamEngine.Data.Design;
+using Deltares.DamEngine.Data.General.Gauges;
+using Deltares.DamEngine.Data.General.PlLines;
+using Deltares.DamEngine.Data.General.TimeSeries;
+using Deltares.DamEngine.Data.Geotechnics;
+using Deltares.DamEngine.Data.Standard;
+using Deltares.DamEngine.Data.Standard.Language;
+using Deltares.DamEngine.Data.Standard.Logging;
+
+namespace Deltares.DamEngine.Data.General
+{
+ ///
+ /// Class for the dike parameter names
+ ///
+ public class DikeParameterNames
+ {
+ ///
+ /// The map for soilgeometries2d
+ ///
+ public const string MapForSoilGeometries2D = "MapForSoilGeometries2D";
+ }
+
+ ///
+ /// Class holding all info for a Dike.
+ ///
+ public class Dike
+ {
+ private string description = "";
+ public virtual string MapForSoilGeometries2D { get; set; }
+ private IList locations;
+
+ private IList pl1Lines;
+ private bool removeStiFiles;
+ private MStabShearStrength shearmodel;
+ private SoilList soilList;
+ private IList gauges = new List();
+ private IList gaugePlLines = new List();
+ private IList soilProfiles;
+ private IList soilProfiles2D;
+ private List databaseSoils = new List();
+ private TimeSerieCollection inputTimeSerieCollection = null;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Dike()
+ {
+ Name = "Dijkring";
+ MapForSoilGeometries2D = "";
+
+ locations = new List();
+ soilProfiles = new List();
+ soilProfiles2D = new List();
+ // this.surfaceLines = new DelegatedList { AddMethod = ConvertAddedOldSurfaceLineToNewFormat };
+ SurfaceLines2 = new List();
+ pl1Lines = new List();
+ soilList = new SoilList();
+ removeStiFiles = true;
+ }
+
+ public bool IsRemoveStiFiles { get { return removeStiFiles; } set { removeStiFiles = value; } }
+ public MStabShearStrength ShearStrengthModel { get { return shearmodel; } set { shearmodel = value; } }
+
+ public virtual string Name { get; set; }
+
+ ///
+ /// Gets the locations.
+ ///
+ ///
+ /// The locations.
+ ///
+ public virtual IList Locations
+ {
+ get { return this.locations; }
+ private set { this.locations = value; }
+ }
+
+ ///
+ /// Sorts the locations.
+ ///
+ public void SortLocations()
+ {
+ this.locations = this.Locations.OrderBy(o => o.Name).ToList();
+ }
+
+ public IList SurfaceLines2 { get; set; }
+
+ public virtual IList PL1Lines
+ {
+ get { return this.pl1Lines; }
+ set { this.pl1Lines = value; }
+ }
+
+ public virtual IList SoilProfiles
+ {
+ get { return this.soilProfiles; }
+ set { this.soilProfiles = value; }
+ }
+
+ ///
+ /// Gets or sets the soilprofiles2d.
+ ///
+ ///
+ /// The soilprofiles2d.
+ ///
+ public virtual IList SoilProfiles2D
+ {
+ get { return soilProfiles2D; }
+ set { soilProfiles2D = value; }
+ }
+
+ public virtual SoilList SoilList
+ {
+ get { return this.soilList; }
+ set { this.soilList = value; }
+ }
+
+ [Browsable(false)]
+ public virtual IList Gauges
+ {
+ get { return this.gauges; }
+ set { this.gauges = value; }
+ }
+
+ [Browsable(false)]
+ public virtual IList GaugePlLines
+ {
+ get { return this.gaugePlLines; }
+ set { this.gaugePlLines = value; }
+ }
+
+ public bool UsesGauges { get { return this.GaugePlLines != null && this.GaugePlLines.Count > 0 && this.Gauges != null; } }
+
+ public virtual List Scenarios
+ {
+ get
+ {
+ var scenarios = new List();
+ foreach (Location location in Locations)
+ {
+ scenarios.AddRange(location.Scenarios);
+ }
+ return scenarios;
+ }
+ }
+
+ public string Description
+ {
+ get { return description; }
+ set { description = value; }
+ }
+
+ ///
+ /// Gets or sets the input time serie collection.
+ ///
+ ///
+ /// Input time series for operational use
+ ///
+ public TimeSerieCollection InputTimeSerieCollection
+ {
+ get
+ {
+ return inputTimeSerieCollection;
+ }
+ set
+ {
+ inputTimeSerieCollection = value;
+ }
+ }
+
+ public void Validate(bool isOperational)
+ {
+ if (Locations == null || Locations.Count < 1)
+ {
+ throw new DikeException("The dike ring has no locations defined");
+ }
+ foreach (Location location in Locations)
+ {
+ if (location.SurfaceLine != null)
+ {
+ var validator = new SurfaceLine2Validator();
+ var validationResults = validator.ValidateCharacteristicPointsAreOrdered(location.SurfaceLine)
+ .Concat(validator.ValidateGeometryPointsAreOrdered(location.SurfaceLine)).ToArray();
+ if (validationResults.Length > 0)
+ {
+ throw new SurfaceLineException(validationResults[0].Text);
+ }
+ }
+
+ if (isOperational)
+ {
+ ValidateOperationalProject(location);
+ }
+ }
+ }
+
+ private static void ValidateOperationalProject(Location location)
+ {
+ if (location.Scenarios.Count < 1)
+ {
+ throw new DikeException("Location " + location.Name +
+ " has no scenarios, at least one scenario is required.");
+ }
+
+ if (location.Scenarios.Count > 1)
+ {
+ throw new DikeException(string.Format(
+ "For Operational (DamLive), location {0} has {1} scenarios but only one is allowed!",
+ location.Name, location.Scenarios.Count));
+ }
+
+ if (location.SensorLocation != null)
+ {
+ foreach (var sensor in location.SensorLocation.SensorGroup.SensorArray)
+ {
+ if (sensor.RelativeLocation < 0)
+ {
+ throw new DikeException(string.Format(
+ "For Operational (DamLive), location {0} has a sensor ({1}) which can not not be relative '+ " +
+ "to the starting point (0) as its coordinate {2} is < 0 .",
+ location.Name, sensor.Name, sensor.RelativeLocation));
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Adapt data so it is consistent
+ ///
+ public List MakeDataConsistent()
+ {
+ var errorSoils = TryToMakeSoilDataConsistent();
+ var logMessages = new List();
+ // Delete all locations without surfaceline
+ logMessages.AddRange(DeleteLocationsWithoutSurfaceLines());
+ // Delete all locations that have profiles (in their segment) which hold soils
+ // that are not in the soil database and so have no parameters.
+ logMessages.AddRange(DeleteLocationsWithProfilesWithUnknownSoils(errorSoils));
+ return logMessages;
+ }
+
+ ///
+ /// Tries to make the soil data as read for 1D profiles consistent with the data in the soil database.
+ /// In the end we have a neat soil list with parameters for every soil as read from the database.
+ /// We might have a list with errors (soils that were not to be found in the database so soils for which
+ /// no parameters could be found).
+ ///
+ ///
+ private List TryToMakeSoilDataConsistent()
+ {
+ var errorSoils = new List();
+ // Fill the list of errorSoils with soils that are in the current soillist (as result of importing
+ // 1D profiles) but that are not found in the soil database because that are errors
+ foreach (var soil in soilList.Soils)
+ {
+ var fs = databaseSoils.Find(t => String.Equals(t.Name, soil.Name, StringComparison.CurrentCultureIgnoreCase));
+ if (fs == null)
+ {
+ errorSoils.Add(soil);
+ }
+ }
+ // Remove the error soils form the list
+ foreach (var errorSoil in errorSoils)
+ {
+ soilList.Soils.Remove(errorSoil);
+ }
+ // Get the parameters for every soil in the now proper soil list from the database. Add soils
+ // that are in the database but not yet in the soil list.
+ foreach (Soil soil in databaseSoils)
+ {
+ Soil existingSoil = this.soilList.GetSoilByName(soil.Name);
+ if (existingSoil == null)
+ {
+ this.soilList.Soils.Add(soil);
+ }
+ else
+ {
+ existingSoil.Assign(soil);
+ }
+ }
+ return errorSoils;
+ }
+
+ ///
+ /// Removes all locations which have profiles that have invalid soils
+ ///
+ private List DeleteLocationsWithProfilesWithUnknownSoils(List invalidSoils)
+ {
+ var logMessages = new List();
+ var invalidLocations = new List();
+ string soilProf;
+ string invSoil;
+ foreach (var location in locations)
+ {
+ bool isInValid;
+ string message = "";
+ if (location.Segment == null)
+ {
+ isInValid = true;
+ message = String.Format(LocalizationManager.GetTranslatedText(this.GetType(), "LocationWitNameHasNoSegment"), location.Name);
+ }
+ else
+ {
+ isInValid = DoesLocationHaveInvalidSoils(invalidSoils, location, out soilProf, out invSoil);
+ if (isInValid)
+ {
+ message = String.Format(LocalizationManager.GetTranslatedText(this.GetType(), "locationHasProfileWithInvalidSoils"), location.Name, soilProf, invSoil);
+ }
+ }
+ if (isInValid)
+ {
+ invalidLocations.Add(location);
+ logMessages.Add(new LogMessage(LogMessageType.Warning, this, message));
+ }
+ }
+ foreach (var invalidLocation in invalidLocations)
+ {
+
+ locations.Remove(invalidLocation);
+ }
+ return logMessages;
+ }
+
+ ///
+ /// Checks wether a location (or rather the soilprofiles in the segement of the location) contains invalid soils.
+ /// A soil is hereby considered invalid if it is not found in the database.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private bool DoesLocationHaveInvalidSoils(List invalidSoils, Location location, out string soilProf, out string invSoil)
+ {
+ soilProf = " ";
+ invSoil = " ";
+ foreach (var spp in location.Segment.SoilProfileProbabilities)
+ {
+ foreach (var invalidSoil in invalidSoils)
+ {
+ var fl = spp.SoilProfile1D.Layers.Find(l => String.Equals(l.Soil.Name, invalidSoil.Name, StringComparison.CurrentCultureIgnoreCase));
+
+ if (fl != null)
+ {
+ soilProf = spp.SoilProfile1D.Name;
+ invSoil = invalidSoil.Name;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Delete all locations without surfacelines
+ ///
+ private List DeleteLocationsWithoutSurfaceLines()
+ {
+ var logMessages = new List();
+
+ //Add all locations with valid surfaceline
+ var newLocations = new List();
+ newLocations.AddRange(this.Locations.Where(loc => loc.SurfaceLine != null));
+
+ // Report which locations are not added because no valid surfaceline is found
+ var deletedLocations = new List();
+ deletedLocations.AddRange(this.Locations.Where(loc => loc.SurfaceLine == null));
+ foreach (var deletedLocation in deletedLocations)
+ {
+ var locationHasNoSurfaceLine = LocalizationManager.GetTranslatedText(this.GetType(), "LocationHasNoSurfaceLine");
+ logMessages.Add(new LogMessage(LogMessageType.Warning, this,
+ String.Format(locationHasNoSurfaceLine, deletedLocation.Name)));
+ }
+
+ this.Locations = newLocations;
+ return logMessages;
+ }
+
+ public override string ToString()
+ {
+ return this.Name;
+ }
+
+ public Dictionary GetParametersAsNameValuePairs()
+ {
+ var nameValuePairs = new Dictionary();
+ nameValuePairs.Add(DikeParameterNames.MapForSoilGeometries2D, MapForSoilGeometries2D);
+ return nameValuePairs;
+ }
+
+ public void SetParameterFromNameValuePair(string parameterName, string parameterValue)
+ {
+ if (parameterName.Equals(DikeParameterNames.MapForSoilGeometries2D))
+ this.MapForSoilGeometries2D = parameterValue;
+ }
+
+ public void UpdateLocation(Location location)
+ {
+ location.SoilList = this.SoilList;
+ if (location.StabilityOptions != null)
+ {
+ location.StabilityOptions.SoilGeometries2DPath = this.MapForSoilGeometries2D;
+ }
+
+ location.Gauges.Clear();
+ location.Gauges.AddRange(Gauges);
+
+ location.GaugePlLines.Clear();
+ location.GaugePlLines.AddRange(GaugePlLines);
+ }
+ }
+}
\ No newline at end of file
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Calculators.pdb
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Version.pdb
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Data.dll
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs
===================================================================
diff -u
--- DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (revision 0)
+++ DamEngine/tags/19.2.1/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (revision 3351)
@@ -0,0 +1,595 @@
+// Copyright (C) Stichting Deltares 2019. 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.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Deltares.DamEngine.Calculators.General;
+using Deltares.DamEngine.Calculators.KernelWrappers.Common;
+using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces;
+using Deltares.DamEngine.Calculators.Properties;
+using Deltares.DamEngine.Data.Design;
+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.Calculation;
+using Deltares.DamEngine.Data.Standard.Logging;
+
+namespace Deltares.DamEngine.Calculators.DikesOperational
+{
+
+ ///
+ /// Class for the Operational Calculator
+ ///
+ 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)
+ {
+ if (damProjectData.CalculationMessages == null)
+ {
+ damProjectData.CalculationMessages = new List();
+ }
+ else
+ {
+ damProjectData.CalculationMessages.Clear();
+ }
+ 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)
+ {
+ location.ModelParametersForPlLines.PlLineCreationMethod = PlLineCreationMethod.Sensors;
+
+ 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;
+ }
+
+ // Prepare the designCalculatorTasks
+ var operationalCalculatorTasks = new List();
+ foreach (var series in outputTimeSerieCollection.Series)
+ {
+ int entryIndex = 0;
+ foreach (var entry in series.Entries)
+ {
+ var location = locations.First(l => series.LocationId == l.Name);
+ DesignScenario designScenario = null;
+ if (location.Scenarios.Count > 0)
+ {
+ // For Operational only ONE scenario is allowed (decided by Irene/Bernard on 30-07-2020). So that's the one that must be used.
+ designScenario = location.Scenarios[0];
+ designScenario.Location = location;
+ }
+ var sensorValues = values[entry.DateTime][location];
+ if (!ContainsMissingValues(sensorValues, series.MissVal))
+ {
+ FailureMechanismSystemType soilProbabilityFailureMechanismSystemType = damProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType;
+ var soiProfileProbability = location.Segment.GetMostProbableSoilGeometryProbability(
+ ConversionHelper.ConvertToSegmentFailureMechanismType(soilProbabilityFailureMechanismSystemType));
+ if (soiProfileProbability != null)
+ {
+ var projectPath = damProjectData.ProjectPath != ""
+ ? damProjectData.ProjectPath
+ : Directory.GetCurrentDirectory();
+ var calculationMessages = new List();
+ operationalCalculatorTasks.Add(new OperationalCalculatorTask()
+ {
+ Location = location,
+ SoiProfileProbability = soiProfileProbability,
+ DesignScenario = designScenario,
+ ProjectPath = projectPath,
+ CalculationMap = damProjectData.CalculationMap,
+ FailureMechanismeCalculationSpecification = damProjectData
+ .DamProjectCalculationSpecification.CurrentSpecification,
+ TimeSerieEntry = entry,
+ TimeStepIndex = entryIndex,
+ CalculationMessages = calculationMessages
+ });
+ }
+ else
+ {
+ damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Warning, null,
+ String.Format("Location '{0}' has no soil profiles defined for the current failure mechanism {1}", location.Name,
+ soilProbabilityFailureMechanismSystemType.ToString())));
+ }
+ }
+ 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)));
+ }
+ entryIndex++;
+ }
+ }
+
+ if (operationalCalculatorTasks.Count > 0)
+ {
+ // Perform the calculation
+ Parallel.Run(operationalCalculatorTasks, RunOperationalCalculatorTask, null,
+ damProjectData.MaxCalculationCores);
+ foreach (var operationalCalculatorTask in operationalCalculatorTasks)
+ {
+ damProjectData.CalculationMessages.AddRange(operationalCalculatorTask.CalculationMessages);
+ }
+
+ damProjectData.OutputTimeSerieCollection = outputTimeSerieCollection;
+ }
+ else
+ {
+ var logMessage = new LogMessage
+ {
+ MessageType = LogMessageType.Error,
+ Subject = null,
+ Message = string.Format(Resources.DesignCalculatorNoSegmentsWithFailureMechanismTypePresent,
+ damProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType.ToString())
+ };
+ damProjectData.CalculationMessages.Add(logMessage);
+ }
+ }
+
+ private void RunOperationalCalculatorTask(object operationalCalculatorTask)
+ {
+ OperationalCalculatorTask task = (OperationalCalculatorTask) operationalCalculatorTask;
+ Debug.WriteLine("Start calculation Location '{0}', soilprofile '{1}'", task.Location,
+ task.SoiProfileProbability);
+ CalculateOneTimeEntry(task.Location, task.SoiProfileProbability, task.DesignScenario, task.ProjectPath,
+ task.CalculationMap, task.FailureMechanismeCalculationSpecification,
+ task.TimeSerieEntry, task.TimeStepIndex,
+ task.CalculationMessages, task.CalculationResult);
+ Debug.WriteLine("End calculation Location '{0}', soilprofile '{1}'", task.Location, task.SoiProfileProbability);
+ }
+
+ private void CalculateOneTimeEntry(Location location, SoilGeometryProbability soiProfileProbability,
+ DesignScenario designScenario,
+ string projectPath, string calculationMap,
+ DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification,
+ TimeSerieEntry timeSerieEntry, int timeStepIndex,
+ List calculationMessages, CalculationResult calculationResult)
+ {
+ try
+ {
+ // Prepare input
+ var damKernelInput = new DamKernelInput();
+ damKernelInput.ProjectDir = projectPath;
+ damKernelInput.CalculationDir = Path.Combine(projectPath, calculationMap);
+ damKernelInput.Location = location;
+ damKernelInput.SubSoilScenario = soiProfileProbability;
+ damKernelInput.TimeStepDateTime = timeSerieEntry.DateTime;
+ damKernelInput.DamFailureMechanismeCalculationSpecification = damFailureMechanismeCalculationSpecification;
+ damKernelInput.RiverLevelHigh = Double.NaN;
+ damKernelInput.RiverLevelLow = null;
+ damKernelInput.FilenamePrefix = String.Format("Dik(dike)_Loc({0})_Stp({1})_Mdl({2})_{3}",
+ location.Name,
+ timeStepIndex,
+ damFailureMechanismeCalculationSpecification.StabilityModelType,
+ DateToTimeStamp(timeSerieEntry.DateTime));
+ SynchronizeLocationDataWithScenarioData(designScenario, location);
+ IKernelDataInput kernelDataInput;
+ IKernelDataOutput kernelDataOutput;
+
+ // Create kernelwrapper
+ IKernelWrapper kernelWrapper = KernelWrapperHelper.CreateKernelWrapper(damFailureMechanismeCalculationSpecification);
+ if (kernelWrapper == null)
+ {
+ throw new NotImplementedException(Resources.DesignCalculatorKernelNotImplemented);
+ }
+
+ PrepareResult prepareResult = kernelWrapper.Prepare(damKernelInput, 0, out kernelDataInput, out kernelDataOutput);
+
+ // Sometimes the kernelDataInput is not created (p.e when soilprofileprobablility is meant for
+ // stability where Piping calc is wanted). In that case, do nothing but just skip.
+ if (prepareResult == PrepareResult.Successful)
+ {
+ PerformOperationalCalculation(
+ kernelWrapper, kernelDataInput, kernelDataOutput,
+ damKernelInput, timeStepIndex, timeSerieEntry, out calculationResult,
+ calculationMessages);
+ }
+ else
+ {
+ if (prepareResult == PrepareResult.NotRelevant)
+ {
+ // Do nothing. Calculation will be skipped.
+ }
+ if (prepareResult == PrepareResult.Failed)
+ {
+ calculationMessages.Add(new LogMessage(LogMessageType.Error, null,
+ string.Format(Resources.OperationalCalculatorPrepareError,
+ location.Name,
+ soiProfileProbability,
+ timeStepIndex,
+ DateToTimeStamp(timeSerieEntry.DateTime))));
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ calculationMessages.Add(new LogMessage(LogMessageType.Error, null,
+ string.Format(Resources.OperationalCalculatorGeneralException,
+ location.Name,
+ soiProfileProbability,
+ timeStepIndex,
+ DateToTimeStamp(timeSerieEntry.DateTime),
+ e.Message)));
+ }
+
+ }
+
+ private void PerformOperationalCalculation(IKernelWrapper kernelWrapper, IKernelDataInput kernelDataInput,
+ IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput,
+ int timeStepIndex, TimeSerieEntry timeSerieEntry,
+ out CalculationResult calculationResult,
+ List calculationMessages)
+ {
+ // Perform validation
+ var designResults = new List();
+ List locationCalculationMessages = new List();
+ List validationMessages;
+ calculationResult = CalculationResult.NoRun;
+ try
+ {
+ int errorCount = kernelWrapper.Validate(kernelDataInput, kernelDataOutput, out validationMessages);
+ if (errorCount > 0)
+ {
+ locationCalculationMessages.Add(new LogMessage(LogMessageType.Error, null,
+ string.Format(Resources.OperationalCalculatorValidationFailed,
+ damKernelInput.Location.Name,
+ damKernelInput.SubSoilScenario,
+ timeStepIndex,
+ DateToTimeStamp(timeSerieEntry.DateTime))));
+ locationCalculationMessages.AddRange(validationMessages);
+ }
+ else
+ {
+ // Perform calculation
+ kernelWrapper.Execute(kernelDataInput, kernelDataOutput, out locationCalculationMessages);
+ }
+ // Process output
+ calculationMessages.AddRange(locationCalculationMessages);
+ StringBuilder sb = new StringBuilder();
+ foreach (var message in locationCalculationMessages)
+ {
+ sb.Append(message.Message + Environment.NewLine);
+ }
+ string resultMessage = sb.ToString();
+
+ calculationResult = CalculationResult.Succeeded;
+ kernelWrapper.PostProcess(damKernelInput, kernelDataOutput, null, resultMessage, out designResults);
+ timeSerieEntry.Value = designResults[0].SafetyFactor.Value;
+ }
+ catch (Exception exception)
+ {
+ string resultMessage = exception.Message;
+ calculationResult = CalculationResult.RunFailed;
+ kernelWrapper.PostProcess(damKernelInput, kernelDataOutput, null, resultMessage, out designResults);
+ }
+ }
+
+ ///
+ /// Dates to time stamp.
+ ///
+ /// 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);
+ }
+
+ private string DetermineOutputParameter(DamFailureMechanismeCalculationSpecification currentSpecification)
+ {
+ string parameter = "";
+ switch (currentSpecification.FailureMechanismSystemType)
+ {
+ case FailureMechanismSystemType.HorizontalBalance:
+ throw new NotImplementedException();
+ case FailureMechanismSystemType.StabilityOutside:
+ if (currentSpecification.StabilityModelType == MStabModelType.Bishop)
+ {
+ parameter = TimeSerieParameters.StabilityOutsideFactor.ToString();
+ break;
+ }
+ throw new NotImplementedException();
+ case FailureMechanismSystemType.StabilityInside:
+ switch (currentSpecification.StabilityModelType)
+ {
+ case MStabModelType.Bishop:
+ case MStabModelType.UpliftVan:
+ case MStabModelType.BishopUpliftVan:
+ parameter = TimeSerieParameters.StabilityInsideFactor.ToString();
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ break;
+ case FailureMechanismSystemType.Piping:
+ switch (currentSpecification.PipingModelType)
+ {
+ case PipingModelType.Sellmeijer4Forces:
+ throw new NotImplementedException();
+ case PipingModelType.Bligh:
+ case PipingModelType.SellmeijerVnk:
+ case PipingModelType.Wti2017:
+ parameter = TimeSerieParameters.Piping.ToString();
+ break;
+ }
+ break;
+
+ }
+ 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();
+ copyOfEntry.Value = double.NaN;
+ // 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;
+ }
+ location.SensorLocation.SensorValues = values; // Todo #The: only set sensorvalues to values for this location
+ }
+
+ ///
+ /// 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 OperationalCalculatorException(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 OperationalCalculatorException(message);
+ }
+ }
+
+ ///
+ /// Throws if time entry count dont match.
+ ///
+ /// The first series entries.
+ /// The time series.
+ /// if set to true [has first series entries].
+ private static void ThrowIfTimeEntryCountDontMatch(HashSet firstSeriesEntries, TimeSerie timeSeries,
+ bool hasFirstSeriesEntries)
+ {
+ if (hasFirstSeriesEntries)
+ {
+ // TODO log info
+ if (timeSeries.Entries.Count != firstSeriesEntries.Count)
+ throw new OperationalCalculatorException("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 OperationalCalculatorException(message);
+ }
+ }
+
+ private static void ThrowIfTimeEntriesKeysDontMatch(DateTime key, HashSet firstSeriesEntries)
+ {
+ // TODO log info
+ if (!firstSeriesEntries.Contains(key))
+ throw new OperationalCalculatorException("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;
+ }
+
+ ///
+ /// Synchronizes the location data with scenario data.
+ /// Note that scenario data is leading when available.
+ ///
+ /// The scenario.
+ /// The location.
+ private void SynchronizeLocationDataWithScenarioData(DesignScenario designScenario, Location location)
+ {
+ if (designScenario != null)
+ {
+ location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope =
+ designScenario.RequiredSafetyFactorStabilityInnerSlope;
+ location.ModelFactors.RequiredSafetyFactorStabilityOuterSlope =
+ designScenario.RequiredSafetyFactorStabilityOuterSlope;
+ location.ModelFactors.UpliftCriterionStability = designScenario.UpliftCriterionStability;
+
+ location.ModelFactors.RequiredSafetyFactorPiping = designScenario.RequiredSafetyFactorPiping;
+ location.ModelFactors.UpliftCriterionPiping = designScenario.UpliftCriterionPiping;
+
+ if (designScenario.DikeTableHeight.HasValue)
+ {
+ location.DikeTableHeight = designScenario.DikeTableHeight ?? 0;
+ }
+ }
+ }
+ }
+}
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Io.pdb
===================================================================
diff -u
Binary files differ
Index: DamEngine/tags/19.2.1/release/Deltares.DamEngine.Data.pdb
===================================================================
diff -u
Binary files differ