Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/WaterpressureInterpolationModel.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/WaterpressureInterpolationModel.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/WaterpressureInterpolationModel.cs (revision 334) @@ -0,0 +1,41 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// Shear Strength model type enumerator + /// + public enum WaterpressureInterpolationModel + { + + /// + /// Automatic interpolation + /// + Automatic=1, + + /// + /// Hydrostatic interpolation + /// + Hydrostatic=2 + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/StabilityResultTypes.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/StabilityResultTypes.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/StabilityResultTypes.cs (revision 334) @@ -0,0 +1,89 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Data.General.Results +{ + public struct MStabResults + { + public MStabResultsSingleZone zone1; + public MStabResultsSingleZone? zone2; + public string CalculationName; + public string CalculationSubDir; + public int IterationNumber; + + public void Init() + { + zone1 = new MStabResultsSingleZone(); + zone1.Init(); + zone2 = new MStabResultsSingleZone(); + zone2.Value.Init(); + } + } + + public struct MStabResultsSingleZone + { + public double safetyFactor; + public double circleSurfacePointLeftXCoordinate; + public double circleSurfacePointRightXCoordinate; + public double entryPointXCoordinate; + public double exitPointXCoordinate; + public double beta; + public void Init() + { + safetyFactor = 0.0; + circleSurfacePointLeftXCoordinate = 0.0; + circleSurfacePointRightXCoordinate = 0.0; + entryPointXCoordinate = 0.0; + exitPointXCoordinate = 0.0; + beta = 0.0; + } + } + + public struct NonWaterRetainingObjectResults + { + public string NwoId; + public double LocationXrdStart; + public double LocationYrdStart; + public double LocationZrdStart; + public double LocationXrdEnd; + public double LocationYrdEnd; + public double LocationZrdEnd; + public MStabResults MStabResults; + public SurfaceLine2 AdaptedSurfaceLine; + public SoilGeometryProbability SoilProfileProbability; + public void Init() + { + NwoId = ""; + MStabResults = new MStabResults(); + MStabResults.Init(); + LocationXrdStart = 0.0; + LocationYrdStart = 0.0; + LocationZrdStart = 0.0; + LocationXrdEnd = 0.0; + LocationYrdEnd = 0.0; + LocationZrdEnd = 0.0; + AdaptedSurfaceLine = null; + } + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLines.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLines.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLines.cs (revision 334) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; + +namespace Deltares.DamEngine.Data.General.PlLines +{ + public class PLLines + { + IDictionary lines; + public PLLines() + { + lines = new Dictionary(); + foreach (PLLineType plLineType in PLLineType.GetValues(typeof(PLLineType))) + { + this.Lines[plLineType] = new PLLine(); + } + } + + public IDictionary Lines + { + get { return this.lines; } + private set { this.lines = value; } + } + public int PLLineCount { get { return PLLineType.GetValues(typeof(PLLineType)).GetLength(0); } } + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculatorCsvExportDataBuilder.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculatorCsvExportDataBuilder.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculatorCsvExportDataBuilder.cs (revision 334) @@ -0,0 +1,118 @@ +// Copyright (C) Stichting Deltares 2017. 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.Text; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; + +namespace Deltares.DamEngine.Calculators.General +{ + /// + /// This class helps to build cvs export data. Everytime the builder is ended by calling Build() method, + /// the builder is reset and can be used to construct a new CvsExportData item. + /// + internal class DamProjectCalculatorCsvExportDataBuilder + { + private Dike Dike { get; set; } + private Scenario Scenario { get; set; } + private DamFailureMechanismeCalculationSpecification FailureMechanismSystemType { get; set; } + private AnalysisType AnalysisType { get; set; } + private ProbabilisticType ProbabilisticType { get; set; } + private StringBuilder Message { get; set; } + + /// + /// Instantiate a new instance of the with general settings which to use in creating + /// . + /// + /// The for which to create . + /// The for which to create . + /// The for which to create . + /// The for which to create . + /// The for which to create + public DamProjectCalculatorCsvExportDataBuilder(Dike dike, Scenario scenario, DamFailureMechanismeCalculationSpecification damFailureMechanismCalculationSpecification, AnalysisType analysisType, ProbabilisticType probabilisticType) + { + Dike = dike; + Scenario = scenario; + FailureMechanismSystemType = damFailureMechanismCalculationSpecification; + AnalysisType = analysisType; + ProbabilisticType = probabilisticType; + Message = new StringBuilder(); + } + + /// + /// Returns a new instance of . Messages that were added using are added to the + /// and the message queue is cleared. + /// + /// The for which to create this . + /// The to set for the to be created . Default is the 0th . + /// The newly constructed with messages appended using . + public CsvExportData Build(SoilGeometryProbability soilGeometryProbability, StabilityKernelType kernelType = (StabilityKernelType) 0) + { + return Build(soilGeometryProbability, kernelType, 0); + } + + /// + /// Returns a new instance of . Messages that were added using are added to the + /// and the message queue is cleared. + /// + /// The for which to create this . + /// An optional index to associate the with some other object of a list. + /// The newly constructed with messages appended using . + public CsvExportData Build(SoilGeometryProbability soilGeometryProbability, int index) + { + return Build(soilGeometryProbability, 0, index); + } + + private CsvExportData Build(SoilGeometryProbability soilGeometryProbability, StabilityKernelType kernelType, int index) + { + var data = new CsvExportData( + Message.ToString(), + Dike, + FailureMechanismSystemType, + Scenario, + soilGeometryProbability.SoilProfile, + soilGeometryProbability.SoilGeometry2DName, + AnalysisType, + index, + ProbabilisticType); + data.SelectedStabilityKernelType = kernelType; + + Message.Clear(); + + return data; + } + + /// + /// Append a new message to the message queue. + /// + /// The messages to add to the queue. + /// This instance of the so that consecutive calls to methods + /// of can be chained. + public DamProjectCalculatorCsvExportDataBuilder Append(params object[] messageParts) + { + foreach (var messagePart in messageParts) + { + Message.Append(messagePart); + } + return this; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Properties/AssemblyInfo.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Properties/AssemblyInfo.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Properties/AssemblyInfo.cs (revision 334) @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Deltares.DamEngine.Calculators")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Deltares")] +[assembly: AssemblyProduct("Deltares.DamEngine.Calculators")] +[assembly: AssemblyCopyright("Copyright © Deltares 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("952e82dc-2107-4f5c-b1c7-327fceaa0cdd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("17.1.0.0")] +[assembly: AssemblyFileVersion("17.1.0.0")] Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Context.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Context.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Context.cs (revision 334) @@ -0,0 +1,117 @@ +// Copyright (C) Stichting Deltares 2017. 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; + +namespace Deltares.DamEngine.Calculators.General +{ + /// + /// Entry point for the current context + /// + public static class Context + { + [ThreadStatic] + private static IContext currentContext; + + /// + /// Application wide context + /// + public static IContext CurrentContext + { + get + { + return currentContext; + } + set + { + currentContext = value; + } + } + + public static bool? IsVisible(object source, string member) + { + bool? visibility = null; + if (currentContext != null) + { + visibility = currentContext.IsVisible(source, member); + } + return visibility; + } + + public static bool? IsEnabled(object source, string member) + { + bool? enabled = null; + if (currentContext != null) + { + enabled = currentContext.IsEnabled(source, member); + } + return enabled; + } + + public static bool ShouldValidate(object source, string member, bool defaultValidate) + { + if (currentContext == null) + { + return defaultValidate; + } + + bool? validate = currentContext.ShouldValidate(source, member); + return validate.HasValue ? validate.Value : defaultValidate; + } + + public static ICollection GetDomain(object source, string member, ICollection defaultDomain) + { + if (currentContext == null) + { + return defaultDomain; + } + + ICollection domain = currentContext.GetDomain(source, member); + return domain ?? defaultDomain; + } + + public static object GetFormat(Type type, object source, string property) + { + return currentContext != null ? currentContext.GetFormat(type, source, property) : null; + } + + public static int[] GetPropertyOrder(Type type, string property) + { + return currentContext != null ? currentContext.GetPropertyOrder(type, property) : null; + } + + public static double? GetMinimum(object source, string property) + { + return currentContext != null ? currentContext.GetMinimum(source, property) : null; + } + + public static double? GetMaximum(object source, string property) + { + return currentContext != null ? currentContext.GetMaximum(source, property) : null; + } + + public static object GetDefault(Type type, string property) + { + return currentContext != null ? currentContext.GetDefault(type, property) : null; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer1D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer1D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer1D.cs (revision 334) @@ -0,0 +1,202 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// 1D Soil Layer Object + /// + public class SoilLayer1D : SoilLayer, ISoilProfileProvider, ICloneable, IComparable + { + /// + /// Function delegate to get layer above/beneath via the 1D Profile + /// + /// The layer. + /// + protected delegate SoilLayer1D LayerGetFunction(SoilLayer1D layer); + + private SoilProfile1D soilProfile; + private double topLevel; + + /// + /// Initializes a new instance of the class. + /// + public SoilLayer1D() + { + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilLayer1D"); + } + + /// + /// Initializes a new instance of the class, using given soil and topLevel. + /// + /// The soil. + /// The top level. + public SoilLayer1D(Soil soil, double topLevel) + : this() + { + Soil = soil; + this.topLevel = topLevel; + } + + /// + /// Gets or sets the toplevel of the layer + /// + public virtual double TopLevel + { + get + { + return topLevel; + } + set + { + // don't do anything if top is already value + if (Math.Abs(value - topLevel) > GeometryConstants.Accuracy) + { + topLevel = value; + } + } + } + + /// + /// Gets or sets the bottom level of the layer + /// + /// + /// The bottom level. + /// + [XmlIgnore] + public virtual double BottomLevel + { + get + { + return SoilProfile == null ? 0d : SoilProfile.GetBottomLevel(this); + } + set + { + // don't do anything if bottom is already value + if (Math.Abs(value - BottomLevel) > GeometryConstants.Accuracy) + { + var layerBelow = LayerBelow(); + if (layerBelow != null) + { + layerBelow.topLevel = value; + } + else if (SoilProfile != null) + { + SoilProfile.BottomLevel = value; + } + + if (SoilProfile != null && value < SoilProfile.BottomLevel) + { + SoilProfile.BottomLevel = value; + } + } + } + } + + /// + /// Gets the distance between bottom and top. + /// + /// + /// The height. + /// + [Translation("LayerHeight")] + public double Height + { + get + { + return TopLevel - BottomLevel; + } + } + + /// Gets or sets the soil profile. + /// The soil profile is set automatically by the soil layers list in SoilProfile1D + [XmlIgnore] + public SoilProfile1D SoilProfile + { + get + { + return soilProfile; + } + set + { + soilProfile = value; + } + } + + /// + /// Clones this instance. + /// + /// Clone of this instance + public virtual object Clone() + { + var clone = new SoilLayer1D(); + clone.Assign(this); + return clone; + } + + /// + /// Returns the Layer below. + /// + /// layer below + private SoilLayer1D LayerBelow() + { + return SoilProfile.GetLayerBelow(this); + } + + /// + /// Assigns the specified layer. + /// + /// The layer. + public void Assign(SoilLayer1D layer) + { + Name = layer.Name; + TopLevel = layer.TopLevel; + Soil = layer.Soil; + IsAquifer = layer.IsAquifer; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + /// + /// Sorting will be applied by the mot uplift layer first + /// + /// Other soil layer + /// Comparable indication + public int CompareTo(SoilLayer1D other) + { + return - TopLevel.CompareTo(other.TopLevel); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Validator.cs (revision 334) @@ -0,0 +1,158 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Validator for . + /// + public class SurfaceLine2Validator + { + /// + /// Performs all validation checks for a surfaceline. + /// + /// The surfaceline being evaluated. + /// The collection of validation results. + public IEnumerable Validate(SurfaceLine2 surfaceline) + { + return ValidateGeometryPointsAreOrdered(surfaceline) + .Concat(ValidateCharacteristicPointsAreOrdered(surfaceline)) + .Concat(ValidateDikeShape(surfaceline)); + } + + /// + /// Checks if all instances in + /// are ordered on ascending X. + /// + /// The surfaceline being evaluated. + /// The collection of validation results. + public IEnumerable ValidateGeometryPointsAreOrdered(SurfaceLine2 surfaceline) + { + if (!ArePointsAscending(surfaceline)) + { + yield return new ValidationResult(ValidationResultType.Error, this.Translate("SurfacePointsNotAscending"), + surfaceline, surfaceline.GetMemberName(sl => sl.Geometry), ""); + } + } + + /// + /// Checks if all characteristic points that require proper ordering based on X coordinate + /// are indeed properly ordered. + /// + /// The surfaceline being evaluated. + /// The collection of validation results. + public IEnumerable ValidateCharacteristicPointsAreOrdered(SurfaceLine2 surfaceline) + { + if (!AreAllCharacteristicPointsXCoordinatesAscending(surfaceline)) + { + yield return new ValidationResult(ValidationResultType.Error, this.Translate("ChartPointsNotAscending"), + surfaceline, surfaceline.GetMemberName(sl => sl.CharacteristicPoints), ""); + } + } + + /// + /// Ares all characteristic points x coordinates ascending. + /// + /// The line. + /// + public static bool AreAllCharacteristicPointsXCoordinatesAscending(SurfaceLine2 line) + { + var points = line.GetCharacteristicPointsRequiringAscendingX().ToArray(); + return AreGeometryPointsXCoordinatesAscending(points); + } + + /// + /// Checks if the shape of the dike is proper. + /// + /// The surfaceline being evaluated. + /// The collection of validation results. + private IEnumerable ValidateDikeShape(SurfaceLine2 surfaceline) + { + if (!AreAllCharacteristicPointsInCorrectShape(surfaceline)) + { + yield return new ValidationResult(ValidationResultType.Error, + this.Translate("ImproperDikeShape"), surfaceline); + } + } + + /// + /// Determines whether all characteristic points are in correct shape. + /// + /// true if all characteristic are in correct shape, otherwise false + public static bool AreAllCharacteristicPointsInCorrectShape(SurfaceLine2 line) + { + // when there are no points to check, make sure true is returned. + var result = true; + + if (line.IsDefined(CharacteristicPointType.DikeToeAtRiver) && line.IsDefined(CharacteristicPointType.DikeTopAtRiver)) + { + result = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).Z < line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).Z; + } + + if (line.IsDefined(CharacteristicPointType.DikeToeAtPolder) && line.IsDefined(CharacteristicPointType.DikeTopAtPolder)) + { + result = result && line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z < line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z; + } + + return result; + } + + private bool ArePointsAscending(SurfaceLine2 line) + { + return AreGeometryPointsXCoordinatesAscending(line.Geometry.Points); + } + + private static bool AreGeometryPointsXCoordinatesAscending(IList points) + { + for (int i = 1; i < points.Count; i++) + { + if (points[i].X < points[i - 1].X + GeometryConstants.Accuracy) + { + // #Bka: if fact we now should return FALSE immediately but there is a snag. Due to faults with adding characteristic + // points to a surface line, some surface lines can have identical points (in Location) but with different + // characteristic (e.g. diktop and trafficload combined). These points should use the same refence to the point + // but it occurs that TWO fysical (and identical) points are added. + // So these points must now be ignored (so identical points must be seen as OK). This is in fact ok for the purpose + // of the validation ast the main problem is that points may never give a vertical part in the geometry. + if ((Math.Abs(points[i].X - points[i - 1].X) < GeometryConstants.Accuracy) && (Math.Abs(points[i].Z - points[i - 1].Z) < GeometryConstants.Accuracy)) + { + // Make sure points are made identical + points[i].X = points[i - 1].X; + points[i].Z = points[i - 1].Z; + } + else + { + return false; + } + } + } + return true; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLine.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLine.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PLLine.cs (revision 334) @@ -0,0 +1,129 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.PlLines +{ + public class PLLinePoint : GeometryPoint + { + public PLLinePoint() : this (0, 0) { } + + public PLLinePoint(double aX, double aZ) : base(aX, aZ) + { + } + } + + public class PLLine : PolyLine, ICloneable + { + private PLLineType plLineType; + + [XmlIgnore] + public PLLineType PLLineType + { + get { return plLineType; } + set + { + plLineType = value; + PLLineTypeSpecified = true; + } + } + + [XmlIgnore] + public bool PLLineTypeSpecified { get; private set; } + + + public bool IsPhreatic { get; set; } + + public int BoundaryLayer { get; set; } + + public PLLine Clone() + { + PLLine plLine = new PLLine() { IsPhreatic = this.IsPhreatic, BoundaryLayer = this.BoundaryLayer }; + foreach (PLLinePoint point in this.Points) + { + PLLinePoint newPoint = new PLLinePoint() { X = point.X, Y = point.Y, Z = point.Z }; + plLine.Points.Add(newPoint); + } + return plLine; + } + + /// + /// Gets the points in the segment between starting x and ending x + /// + /// + /// + /// + /// + /// + public IEnumerable GetPointSegmentBetween(double startX, double endX) + { + if (endX < startX) + throw new ArgumentException("End value is smaller then the start value"); + + return from point in this.PointsOrderdByX + where point != null && (point.X > startX && point.X < endX) + orderby point.X ascending + select point; + } + + /// + /// Determines whether the given point is above, beneath or on the surfaceline. + /// + /// + /// + public PLLinePointPositionXzType PositionXzOfPointRelatedToPLLine(GeometryPoint point) + { + // if point is out of scope of the surface line, return beyond + if ((point.X < points[0].X) || (point.X > points[points.Count - 1].X)) + return PLLinePointPositionXzType.BeyondPLLine; + + double z = ZFromX(point.X); + if (Math.Abs(point.Z - z) < GeometryPoint.Precision) + { + return PLLinePointPositionXzType.OnPLLine; + } + else + { + if (point.Z > z) + { + return PLLinePointPositionXzType.AbovePLLine; + } + else + { + return PLLinePointPositionXzType.BelowPLLine; + } + } + } + + private IEnumerable PointsOrderdByX + { + get { return this.Points.OrderBy(p => p.X); } + } + + } + +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPointString.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPointString.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPointString.cs (revision 334) @@ -0,0 +1,900 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Classifications of an objected with regards to a geometric line in the XZ-plane. + /// + public enum RelativeXzPosition + { + /// + /// Indicates that the object is considered 'on' the geometric line. + /// + OnGeometricLine, + /// + /// Indicates that the object is considered 'above' the geometric line (object Z + /// coordinate higher than that of the line). + /// + AboveGeometricLine, + /// + /// Indicates that the object is considered 'below' the geometric line (object Z + /// coordinates lower than that of the line). + /// + BelowGeometricLine, + /// + /// Indicates that the object is considered 'outside the scope' of the geometric line. + /// + BeyondGeometricLine + } + + /// + /// Type of extrapolation + /// + public enum ExtraPolationMode + { + /// + /// No extrapolation should be used. + /// + Beyond, + /// + /// Used constant (0th order) extrapolation at the extremes. + /// + Horizontal + } + + /// + /// Collection of points (X,Z) in world coordinates used for describing Surface lines + /// + public class GeometryPointString : GeometryObject + { + /// + /// Matching distance where a point within this range is considered on the same point. + /// + private const double epsilon = GeometryConstants.Accuracy; + private readonly List points = new List(); + /// + /// The calculate points as protected field (to be able to prevent recursive calls to CalcPoints) + /// + protected readonly List calcPoints = new List(); + private bool isFrozen; + private bool hasNaNx; + private double frozenMaxZ = double.NaN; + + // sortedPoints must never be used outside this class. Either the GPS concerned must have sorted points but then they already are + // (eg. surfaceline, headline) or they may be unsorted in which case using the sorted list in other classes leads to errors (eg. + // geometrysurfaces, waternetlines) + private List sortedPoints; + + /// + /// The calculate points (to be used in calcualtion instead of Points for better performance) + /// + public virtual List CalcPoints + { + get + { + return calcPoints; + } + } + + /// + /// Freezes this instance. + /// + public void Freeze() + { + if (!isFrozen) + { + sortedPoints = new List(calcPoints.Count); + foreach (Point2D point in calcPoints) + { + sortedPoints.Add(point); + hasNaNx = hasNaNx | double.IsNaN(point.X); + frozenMaxZ = Math.Max(frozenMaxZ, point.Z); + } + sortedPoints.Sort(); + } + isFrozen = true; + } + + /// + /// List of points that describe the physical surface line or surface. + /// + /// + /// The points. + /// + public virtual IList Points + { + get + { + return points; + } + } + + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// When less + /// than zero or is greater or equals to . + public Point2D this[int index] + { + get + { + return calcPoints[index]; + } + } + + /// + /// Gets the count of the points. + /// + /// + /// The count. + /// + public int Count + { + get + { + return calcPoints.Count; + } + } + + + /// + /// Clones this object except the points + /// + /// + public virtual GeometryPointString Clone() + { + var clone = new GeometryPointString(); + this.CloneProperties(clone); // exludes the points ! + clone.Points.Clear(); + foreach (var point in Points) + { + clone.Points.Add(new GeometryPoint(point)); + } + clone.SyncCalcPoints(); + return clone; + } + + /// + /// Gets the minimum z. + /// Note: CalcPoints must be used instead of calcPoints as otherwise unclear behaviour of Linq spoils the result + /// Change back to calcPoints and Benchmark4_01l in the WaternetCreatorTests will fail! + /// + /// + public double GetMinZ() + { + return CalcPoints.Any() + ? CalcPoints.Min(p => p.Z) + : double.NaN; + } + + /// + /// Gets the maximum z. + /// Note: CalcPoints must be used instead of calcPoints as otherwise unclear behaviour of Linq spoils the result + /// Change back to calcPoints and Benchmark4_01l in the WaternetCreatorTests will fail! + /// + /// + public double GetMaxZ() + { + if (isFrozen) return frozenMaxZ; + return CalcPoints.Any() + ? CalcPoints.Max(p => p.Z) + : double.NaN; + } + + /// + /// The minimal X value among . + /// Note: CalcPoints must be used instead of calcPoints as otherwise unclear behaviour of Linq spoils the result + /// Change back to calcPoints and Benchmark4_01l in the WaternetCreatorTests will fail! + /// + /// The minimal X value or in case there are no points. + public double GetMinX() + { + if (isFrozen && !hasNaNx) return sortedPoints[0].X; + return CalcPoints.Any(p => !double.IsNaN(p.X)) + ? CalcPoints.Where(p => !double.IsNaN(p.X)).Min(p => p.X) + : double.NaN; + } + + /// + /// Gets the maximum x. + /// Note: CalcPoints must be used instead of calcPoints as otherwise unclear behaviour of Linq spoils the result + /// Change back to calcPoints and Benchmark4_01l in the WaternetCreatorTests will fail! + /// + /// + public double GetMaxX() + { + if (isFrozen && !hasNaNx) return sortedPoints[sortedPoints.Count - 1].X; + return CalcPoints.Any(p => !double.IsNaN(p.X)) + ? CalcPoints.Where(p => !double.IsNaN(p.X)).Max(p => p.X) + : double.NaN; + } + + /// + /// Finds all vertical XZ intersections with this geometric point string, returning + /// the highest value among the intersections. + /// + /// X coordinate + /// + /// The z value determined by or + /// when is empty. + /// + /// + /// Uses constant extrapolation and linear interpolation. + /// + public double GetZAtUnsortedX(double x) + { + if (calcPoints.Count > 0) + { + var verticalLineAtX = new Line(new Point2D {X = x, Z= GetMaxZ()}, + new Point2D { X = x, Z = GetMinZ() }); + if (Math.Abs(verticalLineAtX.BeginPoint.Z - verticalLineAtX.EndPoint.Z) < GeometryConstants.Accuracy) + { + verticalLineAtX.BeginPoint.Z += 1.0; + verticalLineAtX.EndPoint.Z -= 1.0; + } + var intersectionPoints = IntersectionPointsXzWithLineXz(verticalLineAtX); + if (intersectionPoints.Count != 0) + { + return intersectionPoints.Max(gp => gp.Z); + } + + // Remain consistent with GetZAtX, do constant extrapolation: + double zAtX; + if (DoConstantExtrapolationXz(x, out zAtX)) + { + return zAtX; + } + } + return double.NaN; + } + + /// + /// Retrieves the Z value for the given x. + /// + /// X coordinate + /// + /// The z value determined by or + /// when is empty. + /// + /// + /// Uses constant extrapolation and linear interpolation. + /// + public virtual double GetZatX(double x) + { + if (calcPoints.Any()) + { + double zAtX; + if (DoConstantExtrapolationXz(x, out zAtX)) + { + return zAtX; + } + } + for (int i = 0; i < calcPoints.Count - 1; i++) + { + var current = calcPoints[i]; + var next = calcPoints[i + 1]; + + var leftOffset = x - current.X; + var rightOffset = next.X - x; + + if (Math.Abs(leftOffset) < epsilon) + { + return current.Z; + } + if (Math.Abs(rightOffset) < epsilon) + { + return next.Z; + } + if (leftOffset >= 0 && rightOffset >= 0) + { + var fraction = leftOffset / (leftOffset + rightOffset); + + return (1.0 - fraction) * current.Z + fraction * next.Z; + } + } + + return Double.NaN; + } + + /// + /// Gets the z at x starting from index i in the point list. + /// This is only meant as a fast(er) version for GetZAtX for lists that are sorted by X, so use with care. + /// + /// The x. + /// The i. + /// + public virtual double GetZatX(double x, ref int i) + { + for (; i < calcPoints.Count - 1; i++) + { + var current = calcPoints[i]; + var leftOffset = x - current.X; + var next = calcPoints[i + 1]; + var rightOffset = next.X - x; + + if (leftOffset < epsilon) + { + return current.Z; + } + if (rightOffset >= epsilon) + { + var fraction = leftOffset / (leftOffset + rightOffset); + return (1.0 - fraction) * current.Z + fraction * next.Z; + } + if (i + 1 == calcPoints.Count - 1) + { + return next.Z; + } + } + + return Double.NaN; + } + + /// + /// Gets all z-values at x for a line. + /// + /// The x. + /// + public List GetAllZatXForLine(double x) + { + return GetAllZatX(x, false); + } + + /// + /// Gets all z values at x for a surface. + /// + /// The x. + /// + public List GetAllZatXForSurface(double x) + { + return GetAllZatX(x, true); + } + + /// + /// Finds the first intersection of the line with a given horizontal line. + /// + /// The height level of the horizontal line. + /// Optional: Discard intersections whose X value is less then + /// or equal to this value. + /// The first intersection point matching the criteria. + /// + public double GetXatZ(double z, double xmin = Double.MinValue) + { + return GetXatZStartingAt(0, z, xmin); + } + + /// + /// Finds the first intersection of the line with a given horizontal line. + /// + /// Start considering instances from + /// starting from this index. + /// The height level of the horizontal line. + /// Optional: Discard intersections whose X value is less then + /// or equal to this value. + /// The first intersection point matching the criteria. + /// + public double GetXatZStartingAt(int start, double z, double xmin = Double.MinValue) + { + for (int i = start; i < calcPoints.Count - 1; i++) + { + var current = calcPoints[i]; + var next = calcPoints[i + 1]; + + if (IsSegmentNotCrossingZ(z, current, next)) // Performance micro-optimization + { + continue; + } + + var x = GetXIntersectingZ(z, current, next); + if (x > xmin) + { + return x; + } + } + + return Double.NaN; + } + + /// + /// Gets the points at x. + /// + /// The x. + /// + public IEnumerable GetPointsAtX(double x) + { + return (from Point2D point in calcPoints + where point.X.AlmostEquals(x, GeometryPoint.Precision) + select point); + } + + /// + /// Gets the point at. + /// + /// The x. + /// The z. + /// + public Point2D GetPointAt(double x, double z) + { + return calcPoints.FirstOrDefault( + point => point.X.AlmostEquals(x, GeometryPoint.Precision) && + point.Z.AlmostEquals(z, GeometryPoint.Precision)); + } + + //#Bka: this should never be 1 method! Split it into 2 methods + // It is used for sliplanes only and therefor uses Points instead of calcPoints + /// + /// Adds the or remove list object. + /// + /// a point. + /// if set to true [a to add]. + /// a index. + public virtual void AddOrRemoveListObject(object aPoint, bool aToAdd, int aIndex) + { + var point = aPoint as GeometryPoint; + if (point == null) + { + return; + } + + if (aToAdd) + { + Points.Insert(aIndex, point); //#bka what happens if index already exists? what if point exists? What if both??? + } + else + { + if (Points.Contains(point)) + { + Points.Remove(point); + } + } + } + + /// + /// Returns ALL intersection points that are found, including the double ones as the number of points can be relevant! + /// + /// + /// + public IList IntersectionPointsXzWithLineXzWithAllPoints(Line line) + { + return IntersectionPointsWithLineCore(line, true); + } + + /// + /// Returns the UNIQUE intersectionpoints (so can not be used where number of interscections is relevant) + /// + /// + /// + public IList IntersectionPointsXzWithLineXz(Line line) + { + return IntersectionPointsWithLineCore(line, false); + } + + private IList IntersectionPointsXzClosedStringWithLineXz(Line line) + { + IList intersectionPointsWithLine = IntersectionPointsXzWithLineXz(line); + + // close the poly line + if (calcPoints.Count > 0) + { + DoIntersectAndAddToCollection(line, calcPoints[calcPoints.Count - 1], calcPoints[0], + intersectionPointsWithLine, false); + } + + return intersectionPointsWithLine; + } + + /// + /// Find intersection (xz-plane) from this surface with another surface + /// or phratic line + /// + /// + /// + /// Considers all in to + /// such that they describe a closed loop. + /// + public IList ClosedGeometryIntersectionXzPointsWithGeometryPointList(IList list) + { + return IntersectWithPointsListCore(list, true); + } + + /// + /// Finds all intersections in the XZ-plane the given list. + /// + /// The list. + /// + /// + /// + private List IntersectionXzPointsWithGeometryPointList(IList list) + { + return IntersectWithPointsListCore(list, false); + } + + /// + /// Finds all intersections in the XZ-plane the given . + /// + /// The geometry point string. + /// + /// + public List IntersectionXzPointsWithGeometryString(GeometryPointString externalSurface) + { + return IntersectionXzPointsWithGeometryPointList(externalSurface.CalcPoints); + } + + /// + /// Sorts the points by x ascending (only to be used for Surface lines). + /// + public virtual void SortPointsByXAscending() + { + calcPoints.Sort(); + } + + /// + /// Gets a part of the geometry point string defined by a begin and end point + /// + /// + /// + /// + public GeometryPointString GetPart(double begin, double end) + { + var part = new GeometryPointString(); + bool filling = false; + bool filled = false; + + for (int i = 0; i < calcPoints.Count; i++) + { + if (!filling && !filled) + { + filling = calcPoints[i].X >= begin - epsilon; + } + else + { + filled = calcPoints[i].X >= end - epsilon; + if (filled) + { + filling = false; + } + } + + if (filling) + { + part.calcPoints.Add(calcPoints[i]); + } + } + + var beginPoint = new Point2D(begin, GetZatX(begin)); + var endPoint = new Point2D(end, GetZatX(end)); + + if (part.calcPoints.Count == 0) + { + part.calcPoints.Add(beginPoint); + part.calcPoints.Add(endPoint); + } + + if (!part.calcPoints[0].LocationEquals(beginPoint)) + { + part.calcPoints.Insert(0, beginPoint); + } + + if (!part.calcPoints[part.calcPoints.Count - 1].LocationEquals(endPoint)) + { + part.calcPoints.Add(endPoint); + } + SyncPoints(); + return part; + } + + /// + /// Removes all double points at a location, if consecutive + /// + public void CondensePoints() + { + for (int i = calcPoints.Count - 1; i > 0; i--) + { + if (calcPoints[i].LocationEquals(calcPoints[i - 1])) + { + calcPoints.RemoveAt(i); + } + } + } + + /// + /// Removes all points which don't influence the shape of the line + /// + public void RemoveUnnecessaryPoints() + { + const double slopeTolerance = 1E-10; + + CondensePoints(); + + for (int i = calcPoints.Count - 2; i > 1; i--) + { + // if the slope of the line before the point is equal to the slope after the point, the point can be removed + double slopeBefore = (calcPoints[i].Z - calcPoints[i - 1].Z) / (calcPoints[i].X - calcPoints[i - 1].X); + double slopeAfter = (calcPoints[i + 1].Z - calcPoints[i].Z) / (calcPoints[i + 1].X - calcPoints[i].X); + + if (Routines2D.AreEqual(slopeBefore, slopeAfter, slopeTolerance)) + { + calcPoints.RemoveAt(i); + } + } + } + + /// + /// Gets the surrounding rectangle around the geometry point string + /// + /// + public override GeometryBounds GetGeometryBounds() + { + if (!Points.Any()) + { + // Sync with calcPoints + SyncPoints(); + // if still no points, then return null + if (!Points.Any()) return null; + } + + GeometryBounds bounds = Points[0].GetGeometryBounds(); + for (var i = 1; i < Points.Count; i++) + { + GeometryPoint point = Points[i]; + + bounds.Left = Math.Min(bounds.Left, point.X); + bounds.Right = Math.Max(bounds.Right, point.X); + bounds.Top = Math.Max(bounds.Top, point.Z); + bounds.Bottom = Math.Min(bounds.Bottom, point.Z); + } + + return bounds; + } + + /// + /// Checks if constant extrapolation can be applied, and if so set the Z value. + /// + /// The evaluated X coordinate. + /// Output param: Extrapolated Z value, or + /// when no extrapolation is possible. + /// True if extrapolation possible; false otherwise. + private bool DoConstantExtrapolationXz(double x, out double z) + { + if (calcPoints.Count > 0) + { + var first = calcPoints[0]; + if (x < first.X || Math.Abs(x - first.X) < epsilon) + { + z = first.Z; + return true; + } + + var last = calcPoints[calcPoints.Count - 1]; + if (x > last.X) + { + z = last.Z; + return true; + } + } + + z = double.NaN; + return false; + } + + /// + /// Can be used for a Line or for a Surface where a surface is supposed to closed. + /// In case of a waternet line it is possible + /// to have more z values at a give x coor + /// Furthermore a z is not needed at al x values + /// + /// + /// + /// + private List GetAllZatX(double x, bool asSurface) + { + var result = new List(); + + if (calcPoints.Count == 1 && Math.Abs(calcPoints[0].X - x) < epsilon) + { + result.Add(calcPoints[0].Z); + } + + var pointsCount = calcPoints.Count - 1; + if (asSurface) + { + pointsCount = calcPoints.Count; + } + for (int i = 0; i < pointsCount; i++) + { + Point2D current; + Point2D next; + if (i == calcPoints.Count - 1) + { + current = calcPoints[i]; + next = calcPoints[0]; + } + else + { + current = calcPoints[i]; + next = calcPoints[i + 1]; + } + + var leftOffset = x - current.X; + var rightOffset = next.X - x; + + var matchedWithAPoint = false; + if (Math.Abs(leftOffset) < epsilon) + { + result.Add(current.Z); + matchedWithAPoint = true; + } + if (Math.Abs(rightOffset) < epsilon) + { + result.Add(next.Z); + matchedWithAPoint = true; + } + if (!matchedWithAPoint) + { + if (leftOffset > 0 && rightOffset > 0) + { + var fraction = leftOffset / (leftOffset + rightOffset); + + result.Add((1.0 - fraction) * current.Z + fraction * next.Z); + } + + // if both ofsets are negative the waterline goes back + if ((leftOffset < 0) && (rightOffset < 0)) + { + var fraction = rightOffset / (rightOffset + leftOffset); + + result.Add((1.0 - fraction) * next.Z + fraction * current.Z); + } + } + } + + return result.Distinct().ToList(); + } + + private static bool IsSegmentNotCrossingZ(double z, Point2D current, Point2D next) + { + if (double.IsNaN(z)) + { + return true; + } + + var leftOffset = Math.Abs(current.Z - z); + var rightOffset = Math.Abs(next.Z - z); + + int currentSign = leftOffset < epsilon ? 0 : Math.Sign(current.Z - z); + int nextSign = rightOffset < epsilon ? 0 : Math.Sign(next.Z - z); + return currentSign == nextSign && currentSign != 0; + } + + private static double GetXIntersectingZ(double z, Point2D current, Point2D next) + { + var leftOffset = Math.Abs(current.Z - z); + if (leftOffset < epsilon) + { + return current.X; + } + var rightOffset = Math.Abs(next.Z - z); + if (rightOffset < epsilon) + { + return next.X; + } + + var fraction = leftOffset / (leftOffset + rightOffset); + return GeneralMathRoutines.LinearInterpolate(current.X, next.X, fraction); + } + + private IList IntersectionPointsWithLineCore(Line line, bool allowDuplicates) + { + var intersectionPointsWithLine = new List(); + + for (int pointIndex = 0; pointIndex < calcPoints.Count - 1; pointIndex++) + { + DoIntersectAndAddToCollection(line, calcPoints[pointIndex], calcPoints[pointIndex + 1], + intersectionPointsWithLine, allowDuplicates); + } + return intersectionPointsWithLine; + } + + private static void DoIntersectAndAddToCollection(Line line, Point2D begin, Point2D end, ICollection intersectionPointsWithLine, bool allowDuplicates) + { + var lineInPoly = new Line + { + BeginPoint = begin, + EndPoint = end + }; + Point2D intersectionPoint = lineInPoly.GetIntersectPointXz(line); + if (intersectionPoint != null && (allowDuplicates || NoPointSameXzLocation(intersectionPointsWithLine, intersectionPoint))) + { + intersectionPointsWithLine.Add(intersectionPoint); + } + } + + private static bool NoPointSameXzLocation(IEnumerable collection, Point2D point) + { + return !collection.Any( + p => Math.Abs(p.X - point.X) < GeometryConstants.Accuracy && + Math.Abs(p.Z - point.Z) < GeometryConstants.Accuracy); + } + + private List IntersectWithPointsListCore(IList list, bool closePointString) + { + var result = new List(); + var line = new Line(); + for (int externalPointIndex = 0; externalPointIndex < list.Count - 1; externalPointIndex++) + { + line.BeginPoint = list[externalPointIndex]; + line.EndPoint = list[externalPointIndex + 1]; + + result.AddRange(!closePointString + ? IntersectionPointsXzWithLineXzWithAllPoints(line) + : IntersectionPointsXzClosedStringWithLineXz(line)); + } + + return result; + } + + /// + /// Synchronizes the calculation points. + /// + public void SyncCalcPoints() + { + calcPoints.Clear(); + foreach (var geometryPoint in Points) + { + var p2D = new Point2D + { + X = geometryPoint.X, + Z = geometryPoint.Z + + }; + calcPoints.Add(p2D); + } + } + + /// + /// Synchronizes the points. + /// + public void SyncPoints() + { + points.Clear(); + foreach (var p2D in calcPoints) + { + var geometryPoint = new GeometryPoint + { + X = p2D.X, + Z = p2D.Z + + }; + points.Add(geometryPoint); + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Parallel.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Parallel.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/Parallel.cs (revision 334) @@ -0,0 +1,306 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using Deltares.DamEngine.Data.Standard.Calculation; +//using Deltares.Standard.Logging; +using ThreadState = System.Threading.ThreadState; + +namespace Deltares.DamEngine.Calculators.General +{ + /// + /// Utility to run tasks in parallel + /// + public class Parallel + { + private static Queue queue = new Queue(); + private static TaskDelegate task = null; + private static ProgressDelegate progress = null; + private static int total = 0; + private static int executed = 0; + private static List threads = new List(); + private static List processes = new List(); + private static bool stopPressed = false; + private static bool errorOccured = false; + private static bool limitToAvailableProcessors = true; + + /// + /// Runs a number of tasks in parallel. Returns when all tasks have been executed. + /// + /// The objects on which the task is to be performed + /// The task to be executed + public static void Run(IList list, TaskDelegate parallelTask) + { + Run(list, parallelTask, null, -1); + } + + /// + /// Runs a number of tasks in parallel. Returns when all tasks have been executed. + /// + /// The objects on which the task is to be performed + /// The task to be executed + /// The maximum number of processes, will be equal to the number of cores if omitted + public static void Run(IList list, TaskDelegate parallelTask, int maxProcesses) + { + Run(list, parallelTask, null, maxProcesses); + } + + /// + /// Runs a number of tasks in parallel. Returns when all tasks have been executed. + /// + /// The objects on which the task is to be performed + /// The task to be executed + /// Optional delegate indicating the progress of the tasks + public static void Run(IList list, TaskDelegate parallelTask, ProgressDelegate progress) + { + Run(list, parallelTask, progress, -1); + } + + /// + /// Runs a number of tasks in parallel. Returns when all tasks have been executed. + /// + /// The objects on which the task is to be performed + /// The task to be executed + /// The maximum number of processes, will be equal to the number of cores if omitted + /// Optional delegate indicating the progress of the tasks + public static void Run(IList list, TaskDelegate parallelTask, ProgressDelegate progressDelegate, int maxProcesses) + { + if (list.Count == 0) + { + return; + } + + stopPressed = false; + processes.Clear(); + + if (maxProcesses <= 0) + { + maxProcesses = Int32.MaxValue; + } + + maxProcesses = Math.Min(list.Count, maxProcesses); + + if (limitToAvailableProcessors) + { + maxProcesses = Math.Min(Environment.ProcessorCount, maxProcesses); + } + + //DateTime start = DateTime.Now; + + if (progressDelegate != null) + { + progressDelegate(0); + } + + if (maxProcesses == 1) + { + total = list.Count; + RunSequential(list, parallelTask, progressDelegate); + } + else + { + try + { + queue.Clear(); + task = parallelTask; + progress = progressDelegate; + + foreach (var argument in list) + { + queue.Enqueue(argument); + } + + total = queue.Count; + executed = 0; + + threads.Clear(); + for (int i = 0; i < maxProcesses; i++) + { + var thread = new Thread(RunTask); + threads.Add(thread); + + thread.Start(Context.CurrentContext); // Pass the current context as task context + } + + foreach (var thread in threads) + { + thread.Join(); + } + } + catch (ThreadAbortException) + { + Abort(); + } + } + + if (errorOccured) + { + throw new Exception("Error occured in one of the parallel runs."); + } + //DateTime end = DateTime.Now; + //TimeSpan period = end - start; + + //if (period.TotalMilliseconds > 0) + //{ + // string msg = (maxProcesses == 1 ? "Duration of tasks: " : "Parallel duration: "); + // Console.WriteLine(msg + period.TotalMilliseconds + " ms"); + //} + } + + /// + /// Kills all running and queued tasks + /// + public static void Abort() + { + stopPressed = true; + + foreach (var process in processes.ToArray()) + { + if (!process.HasExited) + { + process.Kill(); + } + } + + foreach (var thread in threads) + { + switch (thread.ThreadState) + { + case ThreadState.Running: + try + { + thread.Abort(); + } + catch (ThreadAbortException) + { + // ignore + } + break; + case ThreadState.WaitSleepJoin: + thread.Interrupt(); + break; + } + } + + threads.Clear(); + processes.Clear(); + } + + /// + /// Registers a process which should be killed too when the method is called + /// + /// The process + public static void KillOnAbort(Process process) + { + processes.Add(process); + } + + private static void RunSequential(IList list, TaskDelegate parallelTask, ProgressDelegate progressDelegate) + { + for (int i = 0; i < list.Count; i++) + { + parallelTask(list[i]); + + if (progressDelegate != null) + { + progressDelegate(Convert.ToDouble(i + 1)/Convert.ToDouble(total)); + } + } + } + + private static void RunTask(object context) + { + object argument = null; + + // Set the context of the task thread + Context.CurrentContext = context as IContext; + + while (true) + { + lock (queue) + { + if (!stopPressed && queue.Count > 0) + { + argument = queue.Dequeue(); + } + else + { + return; + } + } + + try + { + if (!stopPressed) + { + task(argument); + } + } + catch (ThreadAbortException) + { + stopPressed = true; + } + catch (Exception e) + { + // most errors already reported to logfile + while (e != null) // Extra instrumentation to trace errors occurring during parallel executions + { +// LogManager.Add(new LogMessage(LogMessageType.Trace, task, "Exception occurred in parallel run: " + e.Message + Environment.NewLine + +// "Stacktrace: " + Environment.NewLine +// + e.StackTrace)); ##BKA: replace with some other mechanism!? + e = e.InnerException; + } + errorOccured = true; + return; + } + finally + { + if (progress != null && !stopPressed) + { + lock (queue) + { + progress(Convert.ToDouble(++executed)/Convert.ToDouble(total)); + } + } + } + } + } + + /// + /// Indicates whether the number of parallel processes is limited to the number of available cores + /// + public static bool LimitToAvailableProcessors + { + get + { + return limitToAvailableProcessors; + } + set + { + limitToAvailableProcessors = value; + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/EvaluationJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/EvaluationJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/EvaluationJob.cs (revision 334) @@ -0,0 +1,154 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class EvaluationJob + { + private string dikeName = ""; + private List locations = new List(); + private List failedEvaluatedLocations = new List(); + private List results = new List(); + private List schematizationFactorResults = new List(); + + public string DikeName + { + get { return dikeName; } + set { dikeName = value; } + } + + public List Locations + { + get { return locations; } + set { locations = value; } + } + + public List Results + { + get { return results; } + set { results = value; } + } + + public List SchematizationFactorResults + { + get { return schematizationFactorResults; } + set { schematizationFactorResults = value; } + } + + [XmlIgnore] +// public string XML +// { +// get +// { +// XmlSerializer serializer = new XmlSerializer(); +// return serializer.SerializeToString(this); +// } +// set +// { +// XmlDeserializer deserializer = new XmlDeserializer(); +// EvaluationJob job = (EvaluationJob)deserializer.XmlDeserializeFromString(value, typeof(EvaluationJob)); +// +// this.DikeName = job.DikeName; +// +// this.Locations.Clear(); +// this.Locations.AddRange(job.Locations); +// +// this.Results.Clear(); +// this.Results.AddRange(job.Results); +// this.schematizationFactorResults.Clear(); +// this.schematizationFactorResults.AddRange(job.schematizationFactorResults); +// } +// } + + public List FailedEvaluatedLocations + { + get { return failedEvaluatedLocations; } + set { failedEvaluatedLocations = value; } + } + + public void AttachResults(IEnumerable locationJobs) + { + foreach (LocationJob locationJob in locationJobs) + { + foreach (Location location in this.locations) + { + if (locationJob.Location.Name.Equals(location.Name)) + { + if (locationJob.LocationResult == null) + { + locationJob.LocationResult = new LocationResult(); + } + + if ((this.locations.IndexOf(location) < 0) || (this.locations.IndexOf(location) >= this.results.Count)) + { + var failedRes = new RWScenariosResult(); + failedRes.CalculationResult = CalculationResult.UnexpectedError; + locationJob.LocationResult.RWScenariosResult = failedRes; + } + else + { + locationJob.LocationResult.RWScenariosResult = this.results[this.locations.IndexOf(location)]; + } + + + foreach (RWScenarioResult scenarioResult in locationJob.LocationResult.RWScenariosResult.RWScenarioResults) + { + foreach (RWScenarioProfileResult scenarioProfileResult in scenarioResult.RWScenarioProfileResults) + { + scenarioProfileResult.Location = locationJob.Location; + } + } + + + if ((this.locations.IndexOf(location) < 0) || (this.locations.IndexOf(location) >= this.results.Count)) + { + // var failedRes = new RWSchematizationFactorsResult(); + // failedRes.SchematizationFactorResults. = CalculationResult.UnexpectedError; + // locationJob.LocationResult.RWScenariosResult = failedRes; + } + else + { + if (schematizationFactorResults.Count > this.locations.IndexOf(location)) + { + locationJob.LocationResult.SchematizationFactorsResult = + schematizationFactorResults[this.locations.IndexOf(location)]; + } + } + + if (locationJob.LocationResult.SchematizationFactorsResult != null) + { + foreach (var schematizationFactorResult in locationJob.LocationResult.SchematizationFactorsResult.SchematizationFactorResults) + { + schematizationFactorResult.Location = locationJob.Location; + } + } + } + } + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Group.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Group.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Group.cs (revision 334) @@ -0,0 +1,235 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + public class Group + { + /// + /// Holds a reference to the set of selected sensors + /// + private readonly HashSet sensors; + private List pickSensors; + private int id; + + /// + /// Holds a reference to a set of relative loctions along the profile + /// + private readonly IDictionary relativeLocationAlongProfileDictionary; + + public Group() + { + sensors = new HashSet(); + relativeLocationAlongProfileDictionary = new Dictionary(); + ID = -1; + } + + /// + /// Gets or sets the ID. + /// + /// + /// The ID value should be unique. + /// + public int ID + { + get { return id; } + set + { + id = value; + } + } + + /// + /// Gets the selected sensors. + /// + [XmlIgnore] + public IEnumerable Selection + { + get { return sensors; } + } + + /// + /// Gets or sets the selection as list for UI (table) purposes. + /// + /// + /// The selection as list. + /// + [XmlIgnore] + public string SelectionAsString + { + get + { + string res = ""; + foreach (var sensor in sensors) + { + res = res + sensor.ID + "; "; + } + return res; + } + set + { + ClearSelection(); + var locSensors = ParseStringToSensorIDs(value); + if (pickSensors != null) + { + foreach (var sensorID in locSensors) + { + var sensor = PickSensors.Find(x => x.ID == sensorID); + if (sensor != null) + { + Add(sensor); + } + } + } + } + } + + private List ParseStringToSensorIDs(string value) + { + value = value.Trim(); + var ids = new List(); + var idsarr = value.Split(new Char [] {';'}, StringSplitOptions.RemoveEmptyEntries); + foreach (var s in idsarr) + { + try + { + var val = Int32.Parse(s); + ids.Add(val); + } + catch (Exception) + { + // surpress errors, just do not use value + } + } + return ids; + } + + /// + /// Persistable sensor array. Only for internal use + /// + public Sensor[] SensorArray + { + get { return sensors.ToArray(); } + set { + ClearSelection(); + foreach (var sensor in value) + { + Add(sensor); + } + } + } + + /// + /// Gets the sensor count. + /// + public int SensorCount + { + get { return sensors.Count; } + } + + [XmlIgnore] + public IEnumerable> SensorRelativeLocations + { + get { return relativeLocationAlongProfileDictionary; } + } + + [XmlIgnore] + public List PickSensors + { + get { return pickSensors; } + set { pickSensors = value; } + } + + /// + /// Determines whether this instance is valid. + /// + /// +// public bool IsValid() +// { +// IEnumerable validationResults = Validator.Validate(this); +// return !validationResults.Any(); +// } + + /// + /// Determines whether this instance is transient (associated with an invalid ID). + /// + /// + /// true if this instance is transient; otherwise, false. + /// + public bool IsTransient() + { + return ID <= 0; + } + + /// + /// Sets the relative location. + /// + /// The sensor. + /// The value. + public void SetRelativeLocation(Sensor sensor, double value) + { + relativeLocationAlongProfileDictionary[sensor] = value; + } + + /// + /// Adds the specified sensor to the selected sensor list for this group. + /// + /// The sensor to add. + public void Add(Sensor sensor) + { + sensors.Add(sensor); + if (!relativeLocationAlongProfileDictionary.ContainsKey(sensor)) + relativeLocationAlongProfileDictionary.Add(sensor, 0); + + } + + /// + /// Removes the specified sensor from the selected sensor list from this group. + /// + /// The sensor to remove. + public void Remove(Sensor sensor) + { + sensors.Remove(sensor); + if (relativeLocationAlongProfileDictionary.ContainsKey(sensor)) + relativeLocationAlongProfileDictionary.Remove(sensor); + } + + /// + /// Clears the sensor selection + /// + public void ClearSelection() + { + sensors.Clear(); + relativeLocationAlongProfileDictionary.Clear(); + } + + public override string ToString() + { + return ID.ToString(); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/RWSchematizationFactorsResult.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/RWSchematizationFactorsResult.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/RWSchematizationFactorsResult.cs (revision 334) @@ -0,0 +1,116 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Data.General.Results +{ + public class RWSchematizationFactorsResult + { + private List schematizationFactorResults = new List(); + + public List SchematizationFactorResults + { + get { return schematizationFactorResults; } + set { schematizationFactorResults = value; } + } + } + + public class RWSchematizationFactorResult + { + private Location location; + private SchematizationType schematizationType; + private string soilProfileName; + private double schematizationFactor; + private double summedProfileProbability; + private CalculationResult calculationResult; + private ScenarioType decisiveScenarioName; + private string originalDecisiveSoilProfileName; + private double detrimentFactor; + private double safetyFactor; + + public virtual Location Location + { + get { return location; } + set { location = value; } + } + + public string LocationName + { + get { return this.Location != null ? this.Location.Name : ""; } + } + + public SchematizationType SchematizationType + { + get { return schematizationType; } + set { schematizationType = value; } + } + + public string SoilProfileName + { + get { return soilProfileName; } + set { soilProfileName = value; } + } + + public string OriginalDecisiveSoilProfileName + { + get { return originalDecisiveSoilProfileName; } + set { originalDecisiveSoilProfileName = value; } + } + + public double SchematizationFactor + { + get { return schematizationFactor; } + set { schematizationFactor = value; } + } + + public double SummedProfileProbability + { + get { return summedProfileProbability; } + set { summedProfileProbability = value; } + } + + public ScenarioType DecisiveScenarioName + { + get { return decisiveScenarioName; } + set { decisiveScenarioName = value; } + } + + public double DetrimentFactor + { + get { return detrimentFactor; } + set { detrimentFactor = value; } + } + + public double SafetyFactor + { + get { return safetyFactor; } + set { safetyFactor = value; } + } + + public CalculationResult CalculationResult + { + get { return calculationResult; } + set { calculationResult = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Line.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Line.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Line.cs (revision 334) @@ -0,0 +1,204 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// Geometry Line, connecting begin point to end point with a straight line. + /// + public class Line + { + private readonly Line line = new Line(); + + /// + /// Initializes a new instance of the class. + /// + public Line() : this(null, null) {} + + /// + /// Initializes a new instance of the class. + /// + /// The begin point. + /// The end point. + public Line(Point2D beginPoint, Point2D endPoint) + { + BeginPoint = beginPoint; + EndPoint = endPoint; + } + + /// + /// Gets or sets the begin point. + /// + /// + /// The begin point. + /// + public Point2D BeginPoint + { + get + { + return line.Start; + } + set + { + line.Start = value; + } + } + + /// + /// Gets or sets the end point. + /// + /// + /// The end point. + /// + public Point2D EndPoint + { + get + { + return line.End; + } + set + { + line.End = value; + } + } + + /// + /// Creates the horizontal z line. + /// + /// The x1. + /// The x2. + /// The z. + public void CreateHorizontalZLine(double x1, double x2, double z) + { + SetBeginAndEndPoints(new Point2D{ X = x1, Z = z}, new Point2D{ X = x2, Z = z}); + } + + /// + /// Sets the begin and end points. + /// + /// The begin point. + /// The end point. + public void SetBeginAndEndPoints(Point2D beginPoint, Point2D endPoint) + { + BeginPoint = beginPoint; + EndPoint = endPoint; + } + + /// + /// Calculate intersection with another projected to the XZ plane. + /// + /// The other line segment. + /// An intersection point in the XZ-plane, or null in case no intersection. + public Point2D GetIntersectPointXz(Line other) + { + Point2D intersectionPoint; + var isIntersecting = line.IntersectsZ(other.line, out intersectionPoint); + + return isIntersecting ? intersectionPoint : null; + } + } + + /// + /// + /// + /// + public class Line where T : Point2D, new() + { + /// + /// Initializes a new instance of the class. + /// + public Line() : this(null, null) {} + + /// + /// Initializes a new instance of the class. + /// + /// The start. + /// The end. + public Line(T start, T end) + { + Start = start; + End = end; + } + + /// + /// Gets or sets the start. + /// + /// + /// The start. + /// + public T Start { get; set; } + + /// + /// Gets or sets the end. + /// + /// + /// The end. + /// + public T End { get; set; } + + /// + /// Intersectses the z. + /// + /// The line. + /// The intersection point. + /// + public bool IntersectsZ(Line line, out T intersectionPoint) + { + return Intersects(line, out intersectionPoint); + } + + private bool Intersects(Line line, out T intersectionPoint) + { + intersectionPoint = null; + + var dx1 = End.X - Start.X; + var dx2 = line.End.X - line.Start.X; + + var dyz1 = End.Z - Start.Z; + var dyz2 = line.End.Z - line.Start.Z; + var yz = Start.Z; + var yzLine = line.Start.Z; + + var noem = dx1*dyz2 - dyz1*dx2; + if (Math.Abs(noem) > 0.0) + { + var u = (dx2*(yz - yzLine) - dyz2*(Start.X - line.Start.X))/noem; + if ((u >= 0.0) && (u <= 1.0)) + { + var v = (dx1*(yz - yzLine) - dyz1*(Start.X - line.Start.X))/noem; + + if ((v >= 0.0) && (v <= 1.0)) + { + intersectionPoint = new T + { + X = Start.X + u * dx1, + Z = yz + u * dyz1 + }; + return true; + } + } + } + return false; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeStep.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeStep.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeStep.cs (revision 334) @@ -0,0 +1,58 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General.TimeSeries +{ + public class TimeStep + { + public TimeStep() + { + DividerSpecified = false; + } + + public TimeStepUnit Unit { get; set; } + + private uint divider; + public uint Divider + { + get { return divider; } + set + { + divider = value; + DividerSpecified = true; + } + } + + public bool DividerSpecified { get; set; } + public bool MultiplierSpecified { get; set; } + + private uint multiplier; + public uint Multiplier + { + get { return multiplier; } + set + { + multiplier = value; + MultiplierSpecified = true; + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerie.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerie.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerie.cs (revision 334) @@ -0,0 +1,239 @@ +// Copyright (C) Stichting Deltares 2017. 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; + +namespace Deltares.DamEngine.Data.General.TimeSeries +{ + public class TimeSerie + { + /// + /// List of parameter identifiers used in Fews timeseries + /// + public const string WaterLevelParameterId = "Waterlevel"; + public const string WaterLevelMeanParameterId = "WaterlevelMean"; + public const string WaterLevelStdParameterId = "WaterlevelStdev"; + public const string WaterLevelDistParameterId = "WaterlevelDistribution"; + public const string WaterPressureParameterId = "Waterpressure"; + public const string PiezoMetricHeadId = "PiezoMetricHead"; + + private readonly TimeStep timeStep; + //Bka: read only not possible to serialize to DB private readonly List entries; + private IList entries; + + public const double DefaultMissingValue = -999.0; + + public TimeSerie() + { + timeStep = new TimeStep(); + entries = new List(); + ForecastDateTime = DateTime.MinValue; + } + + public string Type { get; set; } + public string LocationId { get; set; } + public string ParameterId { get; set; } + public TimeStep TimeStep { get { return timeStep; } } + public DateTime StartDateTime { get; set; } + public DateTime EndDateTime { get; set; } + public DateTime ForecastDateTime { get; set; } + public double MissVal { get; set; } + public string LongName { get; set; } + public string StationName { get; set; } + public string Units { get; set; } + public string SourceOrganisation { get; set; } + public string SourceSystem { get; set; } + public string FileDescription { get; set; } + public DateTime? CreationDateTime { get; set; } + public string Region { get; set; } + + public virtual IList Entries + { + get { return entries; } + set { entries = value; } + } + + public string Comment { get; set; } + + /// + /// Creates a shallow copy of the current time serie and applies the map function to each of its entries + /// + /// The time serie entry function which maps uses the current value as input + /// Time serie (clone) with new calculated entries + public TimeSerie Map(Func function) + { + return Map(ParameterId, function); + } + + /// + /// Creates a shallow copy of the current time serie and applies the map function to each of its entries + /// + /// The (new) id of the parameter in the cloned time serie + /// The (new) location id of the cloned time serie + /// The time serie entry function which maps uses the current value as input + /// Time serie (clone) with new calculated entries + public TimeSerie Map(string parameterId, string locationId, Func function) + { + return Map(this, parameterId, locationId, function); + } + + /// + /// Creates a shallow copy of the current time serie and applies the map function to each of its entries + /// + /// The (new) id of the parameter in the cloned time serie + /// The time serie entry function which maps uses the current value as input + /// Time serie (clone) with new calculated entries + public TimeSerie Map(string parameterId, Func function) + { + return Map(this, parameterId, function); + } + + /// + /// Creates a shallow copy of the current time serie and applies the map function to each of its entries + /// + /// The time serie to map from + /// The (new) id of the parameter in the cloned time serie + /// The time serie entry function which maps uses the current value as input + /// Time serie (clone) with new calculated entries + public static TimeSerie Map(TimeSerie timeSerie, string parameterId, Func function) + { + return Map(timeSerie, parameterId, null, function); + } + + /// + /// Creates a shallow copy of the current time serie and applies the map function to each of its entries + /// + /// The time serie to map from + /// The (new) id of the parameter in the cloned time serie + /// The (new) location id of the cloned time serie + /// The time serie entry function which maps uses the current value as input + /// Time serie (clone) with new calculated entries + public static TimeSerie Map(TimeSerie timeSerie, string parameterId, string locationId, Func function) + { + var result = CreateTimeSerie(timeSerie, parameterId); + if (!(string.IsNullOrEmpty(locationId) || locationId.Trim() == "")) + result.LocationId = locationId; + + foreach (var entry in timeSerie.Entries) + result.Entries.Add(function(entry)); + return result; + } + + /// + /// Gets a shallow copy of the time serie without the time serie entries + /// + /// A copy of this time serie + public TimeSerie GetShallowCopy() + { + var serie = new TimeSerie + { + Type = Type, + ParameterId = ParameterId, + LocationId = LocationId, + StartDateTime = StartDateTime, + EndDateTime = EndDateTime, + ForecastDateTime = ForecastDateTime, + MissVal = MissVal, + LongName = LongName, + StationName = StationName, + SourceOrganisation = SourceOrganisation, + SourceSystem = SourceSystem, + FileDescription = FileDescription, + CreationDateTime = CreationDateTime, + Region = Region, + Units = Units, + TimeStep = + { + Multiplier = TimeStep.Multiplier, + Divider = TimeStep.Divider, + Unit = TimeStep.Unit + } + }; + + serie.Entries.Clear(); + return serie; + } + + public static TimeSerie CreateTimeSerie(string locationId) + { + var timeSerie = new TimeSerie + { + MissVal = DefaultMissingValue, + ParameterId = WaterLevelParameterId, + LocationId = locationId, + StationName = locationId, + Type = "instantaneous", + Units = "m", + Comment = "" + }; + + return timeSerie; + } + + + /// + /// Creates a time serie by copying data from the source time serie without + /// time serie entries (shallow copy) + /// + /// The source time serie used to copy from + /// The new parameter ID + /// A time serie copy without time entries + public static TimeSerie CreateTimeSerie(TimeSerie source, string parameterId) + { + var serie = source.GetShallowCopy(); + serie.ParameterId = parameterId; + serie.Units = "-"; + serie.Comment = ""; + return serie; + } + + public double GetValue(DateTime dateTime) + { + foreach (TimeSerieEntry entry in Entries) + { + if (entry.DateTime >= dateTime) + { + return entry.Value; + } + } + + return -1; + } + + public string GetNearestBasisFileName(DateTime dateTime) + { + string res = ""; + double mindiff = 1e99; + double diff; + foreach (TimeSerieEntry entry in Entries) + { + diff = Math.Abs(entry.DateTime.ToFileTimeUtc() - dateTime.ToFileTimeUtc()); + if (diff < mindiff) + { + res = entry.BasisFileName; + mindiff = diff; + } + } + return res; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (revision 334) @@ -0,0 +1,496 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// + /// A SoilSurfaceProfile constructs a SoilProfile2D object by merging an existing SoilProfile1D with a SurfaceLine + /// + /// Note that actual contruction of 2D based on surface line and 1D happens on setting the properties using dirty flags. + /// + public class SoilSurfaceProfile : SoilProfile2D + { + private Soil dikeEmbankmentMaterial; + private bool dirty; + private bool initial = true; + private SoilProfile1D soilProfile; + private SoilProfile1D orgSoilProfile; + private GeometryPointString surfaceLine; + private SurfaceLine2 surfaceLine2; + private bool createSettlementZones; + + /// + /// Initializes a new instance of the class. + /// + public SoilSurfaceProfile() + { + Name = "Soil Surface Profile"; + } + + /// + /// Gets or sets the surface line. + /// + /// + /// The surface line. + /// + [Validate] + public GeometryPointString SurfaceLine + { + get + { + return surfaceLine; + } + set + { + surfaceLine = value; + dirty = true; + } + } + + /// + /// Gets or sets the surface line2. + /// + [Validate] + public SurfaceLine2 SurfaceLine2 + { + get + { + return surfaceLine2; + } + set + { + surfaceLine2 = value; + if (surfaceLine2 != null) + { + SurfaceLine = surfaceLine2.Geometry; + } + else + { + SurfaceLine = null; + } + dirty = true; + } + } + + /// + /// Gets or sets the soil profile. + /// + /// + /// The soil profile. + /// + [Validate] + public SoilProfile1D SoilProfile + { + get + { + return orgSoilProfile; + } + set + { + orgSoilProfile = value; + dirty = true; + } + } + + /// + /// Gets or sets the dike material. + /// + /// + /// The dike material. + /// + public Soil DikeEmbankmentMaterial + { + get + { + return dikeEmbankmentMaterial; + } + set + { + dikeEmbankmentMaterial = value; + dirty = true; + } + } + + /// + /// List of preconsolidation stresses + /// + [XmlIgnore] + public override List PreconsolidationStresses + { + get + { + if (orgSoilProfile != null) + { + return orgSoilProfile.PreconsolidationStresses; + } + return null; + } + } + + /// + /// Gets the surfaces. + /// + /// + /// The surfaces. + /// + [XmlIgnore] + [Validate] + public override IList Surfaces + { + get + { + if (initial || dirty) + { + UpdateLayers(); + } + return base.Surfaces; + } + } + + /// + /// Gets or sets a value indicating whether to [create settlement zones]. + /// + /// + /// true if [create settlement zones]; otherwise, false. + /// + public bool CreateSettlementZones + { + get + { + return createSettlementZones; + } + set + { + createSettlementZones = value; + } + } + + /// + /// Generates a 1D profile at a given x + /// + /// + /// Generated 1D soil profile + public override SoilProfile1D GetSoilProfile1D(double x) + { + if (initial || dirty) + { + initial = false; + + UpdateLayers(); + } + + // Try to obtain a cached soil profile (performance optimization) + var soilProfile1D = GetCachedSoilProfile1D(x); + if (soilProfile1D != null) + { + return soilProfile1D; + } + + // Otherwise, create and configure a new soil profile + soilProfile1D = new SoilProfile1D(); + + double top = SurfaceLine.GetZatX(x); + soilProfile1D.BottomLevel = soilProfile.BottomLevel; + + if (top > soilProfile.TopLevel) + { + var emptyTopLayer = new SoilLayer1D(null, top) + { + SoilProfile = soilProfile1D + }; + soilProfile1D.Layers.Add(emptyTopLayer); + } + + for (int i = 0; i < soilProfile.Layers.Count; i++) + { + SoilLayer1D layer = soilProfile.Layers[i]; + if (layer.BottomLevel < top) + { + // Perform without publishing events because otherwise the soil profile cache would get lost + var newLayer = new SoilLayer1D(layer.Soil, Math.Min(layer.TopLevel, top)) + { + IsAquifer = layer.IsAquifer, + WaterpressureInterpolationModel = layer.WaterpressureInterpolationModel, + SoilProfile = soilProfile1D + }; + soilProfile1D.Layers.Add(newLayer); + } + } + + // Add the newly created soil profile to the cache + cachedSoilProfiles1D[x] = soilProfile1D; + + return soilProfile1D; + } + + /// + /// Returns a that represents this instance (either Name or SoilProfile). + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + if (!string.IsNullOrEmpty(Name)) + { + return Name; + } + if (orgSoilProfile != null) + { + return orgSoilProfile.ToString(); + } + return "Soil Surface Profile with null Soil Profile"; + } + + /// + /// Converts to soil profile2D. + /// + /// + public SoilProfile2D ConvertToSoilProfile2D() + { + var soilProfile2D = new SoilProfile2D + { + Geometry = Geometry + }; + soilProfile2D.Surfaces.AddRange(Surfaces); + soilProfile2D.Name = Name; + return soilProfile2D; + + } + + /// + /// Updates the dike material. + /// + private void UpdateDikeMaterial() + { + if (soilProfile != null && SurfaceLine != null) + { + double topSurfaceLine = SurfaceLine.GetMaxZ(); + if (!double.IsNaN(topSurfaceLine) && (soilProfile.Layers.Count == 0 || soilProfile.TopLevel < topSurfaceLine)) + { + double newTopLevel = topSurfaceLine + 0.5; + + if (soilProfile.Layers.Count > 0 && soilProfile.Layers[0].Soil == DikeEmbankmentMaterial) + { + SoilLayer1D dikeMaterialLayer = soilProfile.Layers[0]; + dikeMaterialLayer.TopLevel = newTopLevel; + } + else + { + // Add toplayer of dikematerial + var newLayer = new SoilLayer1D + { + TopLevel = newTopLevel, + Soil = DikeEmbankmentMaterial, + }; + + // special handling for dummy soil profiles + if (soilProfile.Layers.Count == 0 && DikeEmbankmentMaterial == null) + { + soilProfile.BottomLevel = SurfaceLine.GetMinZ() - 1; + } + + soilProfile.Layers.Insert(0, newLayer); + soilProfile.EnsureLastLayerHasHeight(); + } + } + } + } + + /// + /// Adds the layer geometry. + /// + /// The data. + /// The layer. + /// The minimum x. + /// The maximum x. + private static void AddLayerGeometry(GeometryData data, SoilLayer1D layer, double minX, double maxX) + { + var top = layer.TopLevel; + var bottom = layer.BottomLevel; + + if (Math.Abs(layer.BottomLevel - layer.SoilProfile.BottomLevel) < GeometryConstants.Accuracy) + { + bottom = data.Bottom; + } + + var bottomLeft = new Point2D(minX, bottom); + var bottomRight = new Point2D(maxX,bottom); + var topLeft = new Point2D(minX, top); + var topRight = new Point2D(maxX, top); + + data.Points.Add(bottomLeft); + data.Points.Add(bottomRight); + data.Points.Add(topLeft); + data.Points.Add(topRight); + + data.Curves.Add(new GeometryCurve(bottomLeft, bottomRight)); + data.Curves.Add(new GeometryCurve(bottomRight, topRight)); + data.Curves.Add(new GeometryCurve(topRight, topLeft)); + data.Curves.Add(new GeometryCurve(topLeft, bottomLeft)); + } + + private void AddSurfaceLineGeometry(GeometryData data) + { + var current = new Point2D(surfaceLine.Points[0].X, surfaceLine.Points[0].Z); + data.Points.Add(current); + for (int i = 1; i < surfaceLine.Points.Count; ++i) + { + var previous = current; + current = new Point2D(surfaceLine.Points[i].X, surfaceLine.Points[i].Z); + + data.Points.Add(current); + data.Curves.Add(new GeometryCurve(previous, current)); + } + } + + private void AddSettlementZones(GeometryData locGeometry) + { + + if (surfaceLine2 != null && surfaceLine2.HasDike()) + { + var xToeRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; + AddVerticalAt(locGeometry, xToeRiver); + var xTopRiver = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; + var xRiver = xToeRiver + (xTopRiver - xToeRiver) / 3.0; + AddVerticalAt(locGeometry, xRiver); + + var xToePolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; + var xTopPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; + var xPolder = xTopPolder + 2 * (xToePolder - xTopPolder) / 3.0; + AddVerticalAt(locGeometry, xPolder); + AddVerticalAt(locGeometry, xToePolder); + } + } + + private void AddVerticalAt(GeometryData aGeometry, double x) + { + const double zMax = 100000.0; + var topX = new Point2D(x, zMax); + var bottomX = new Point2D(x, -zMax); + aGeometry.Points.Add(topX); + aGeometry.Points.Add(bottomX); + aGeometry.Curves.Add(new GeometryCurve(topX, bottomX)); + //aGeometry.NewlyEffectedCurves.Add(aGeometry.Curves.Last());##Bka + } + + private void BuildGeometryModel() + { + if (surfaceLine == null + || soilProfile == null + || soilProfile.Layers.Count == 0 + || surfaceLine.GetMaxZ() < soilProfile.BottomLevel + || surfaceLine.Points.Count < 2) + { + return; + } + + var bounds = SurfaceLine.GetGeometryBounds(); + double minX = bounds.Left; + double maxX = bounds.Right; + + Geometry.Clear(); + Geometry.Left = minX; + Geometry.Right = maxX; + Geometry.Bottom = Math.Min(soilProfile.BottomLevel, surfaceLine.GetMinZ() - 1); + + // add profile geometry + soilProfile.Layers.Sort(); + foreach (var layer in soilProfile.Layers) + { + AddLayerGeometry(Geometry, layer, minX, maxX); + } + + // add surface line geometry + AddSurfaceLineGeometry(Geometry); + + // add the extra lines to create the settlementzones if required + if (createSettlementZones) + { + AddSettlementZones(Geometry); + } +// Geometry.NewlyEffectedPoints.AddRange(Geometry.Points); +// Geometry.NewlyEffectedCurves.AddRange(Geometry.Curves); +// Geometry.RegenerateGeometry(); +// Geometry.DeleteLooseCurves();##Bka + } + + private void RebuildSurfaces(GeometryData locGeometry) + { +// Surfaces.Clear(); +// if (locGeometry == null || surfaceLine == null) +// { +// return; +// } +// var gu = new GeotechnicsUtilities(); +// gu.RemoveGeometryDataAboveSurfaceLine(ref locGeometry, surfaceLine); +// foreach (var geometrySurface in locGeometry.Surfaces) +// { +// var bounds = geometrySurface.GetGeometryBounds(); +// var z = (bounds.Top + bounds.Bottom) * 0.5; +// +// var soilLayer = soilProfile.GetLayerAt(z); +// +// if (soilLayer != null) +// { +// Surfaces.Add(new SoilLayer2D +// { +// GeometrySurface = geometrySurface, +// IsAquifer = soilLayer.IsAquifer, +// WaterpressureInterpolationModel = soilLayer.WaterpressureInterpolationModel, +// Soil = soilLayer.Soil, +// SoilProfile = this +// }); +// } +// } ##Bka + } + + /// + /// Updates the layers. + /// + private void UpdateLayers() + { +// dirty = false; +// initial = false; +// +// // Clear all cached soil profiles +// cachedSoilProfiles1D.Clear(); +// +// if (orgSoilProfile != null) +// { +// soilProfile = (SoilProfile1D)orgSoilProfile.Clone(); +// +// UpdateDikeMaterial(); +// BuildGeometryModel(); +// RebuildSurfaces(Geometry); +// } ##Bka + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/NWO/NonWaterRetainingObject.cs (revision 334) @@ -0,0 +1,158 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.General.NWO +{ + + public class NonWaterRetainingObjectException : ApplicationException + { + public NonWaterRetainingObjectException(string message) + : base(message) + { + } + } + + public class NonWaterRetainingObject + { + public virtual string NwoId { get; set; } + public virtual NonWaterRetainingObjectCategory Category { get; set; } + public virtual NonWaterRetainingObjectType Type { get; set; } + public virtual PhreaticAdaptionType PhreaticAdaption { get; set; } + public virtual double H1 { get; set; } + public virtual double H2 { get; set; } + public virtual double N1 { get; set; } + public virtual double N2 { get; set; } + public virtual double B { get; set; } + public virtual double StepSizeX { get; set; } + public virtual double MaxDistanceFromToe { get; set; } + + public double Btotal () + { + double bTotal = (H1 * N1) + (Math.Sqrt((B*B - (Math.Pow(H2-H1, 2))))) + (H2 * N2); + return bTotal; + } + + public GeometryPoint Point1 { get; set; } + public GeometryPoint Point2 { get; set; } + public GeometryPoint Point3 { get; set; } + public GeometryPoint Point4 { get; set; } + + /// + /// + /// + /// + public void GetDefaultValuesPerTreeType(NonWaterRetainingObjectType type) + { + + switch (type) + { + case NonWaterRetainingObjectType.Oak: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.Alder: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.Poplar: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + default: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + } + } + + /// + /// + /// + /// + public void GetDefaultValuesPerMainType(NonWaterRetainingObjectType type) + { + + switch (type) + { + case NonWaterRetainingObjectType.GasMain: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + case NonWaterRetainingObjectType.WaterMain: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + default: + H1 = 2; + H2 = 2; + N1 = 2; + N2 = 2; + B = 2; + break; + } + } + + /// + /// + /// + /// + /// + public void GetDefaultValuesPerCategoryAndType(NonWaterRetainingObjectCategory category, NonWaterRetainingObjectType type) + { + switch (category) + { + case NonWaterRetainingObjectCategory.Tree: GetDefaultValuesPerTreeType(type); + break; + case NonWaterRetainingObjectCategory.Main: GetDefaultValuesPerMainType(type); + break; + } + } + + public void Validate() + { + if (Btotal() <= 0) + throw new NonWaterRetainingObjectException("NonWaterReatiningObject is invalid. Its total width is smaller than or equal to 0."); + if (MaxDistanceFromToe <= Btotal()) + throw new NonWaterRetainingObjectException("NonWaterReatiningObject is invalid. The required maximum distance from toe is smaller than or equal to the total width."); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWScenariosResult.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWScenariosResult.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWScenariosResult.cs (revision 334) @@ -0,0 +1,278 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using System.ComponentModel; +using System.IO; +using Deltares.DamEngine.Data.General; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class RWScenariosResult : RWResult + { + private IList rwScenarioResults = new List(); + + public RWScenariosResult() + { + } + + public IList RWScenarioResults + { + get { return rwScenarioResults; } + private set { rwScenarioResults = value; } + } + + public RWScenarioResult GetScenarioResult(ScenarioType scenarioType) + { + foreach (RWScenarioResult scenarioResult in this.RWScenarioResults) + { + if (scenarioResult.ScenarioType == scenarioType) + { + return scenarioResult; + } + } + + return null; + } + } + + public class RWScenarioResult : RWResult + { + private LoadSituation loadSituation = LoadSituation.Wet; + private DikeDrySensitivity _dikeDrySensitivity = DikeDrySensitivity.None; + private HydraulicShortcutType hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + private UpliftType upliftType = UpliftType.NoUplift; + private MStabModelType modelOption; + + private ScenarioType scenarioType = ScenarioType.Scenario01; + + private IList rwScenarioProfileResults = new List(); + + public RWScenarioResult() + { + } + + public IList RWScenarioProfileResults + { + get { return rwScenarioProfileResults; } + private set { rwScenarioProfileResults = value; } + } + + public LoadSituation LoadSituation + { + get { return loadSituation; } + set { loadSituation = value; } + } + + public DikeDrySensitivity DikeDrySensitivity + { + get { return _dikeDrySensitivity; } + set { _dikeDrySensitivity = value; } + } + + public HydraulicShortcutType HydraulicShortcutType + { + get { return hydraulicShortcutType; } + set { hydraulicShortcutType = value; } + } + + public UpliftType UpliftType + { + get { return upliftType; } + set { upliftType = value; } + } + + public MStabModelType ModelOption + { + get { return modelOption; } + set { modelOption = value; } + } + + public ScenarioType ScenarioType + { + get { return scenarioType; } + set { scenarioType = value; } + } + } + + public class RWScenarioProfileResult : RWResult + { + private FailureMechanismSystemType failureMechanismType = FailureMechanismSystemType.StabilityInside; + private DikeDrySensitivity _dikeDrySensitivity = DikeDrySensitivity.None; + private HydraulicShortcutType hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + private UpliftType upliftType = UpliftType.NoUplift; + private LoadSituation loadSituation = LoadSituation.Wet; + private MStabModelType mstabModelOption; + private PipingModelType pipingModelOption; + + private SoilGeometryProbability soilGeometryProbability = null; + private Location location = null; + + private ScenarioType scenarioType = ScenarioType.Scenario01; + private string baseFileName = ""; + + public const string CalculationCategory = "Calculation"; + + public RWScenarioProfileResult() + { + } + + public virtual Location Location + { + get { return location; } + set { location = value; } + } + + public string LocationName + { + get { return this.Location.Name; } + } + + public double DetrimentFactor + { + get + { + // For Piping, ignore the given detriment factor and use the required safety for Piping + if (scenarioType == ScenarioType.Scenario10 || scenarioType == ScenarioType.Scenario11) + return DamGlobalConstants.RequiredSafetyPipingForAssessment; + return this.Location.DetrimentFactor; + } + } + + public string SoilProfileName + { + get + { + var res = ""; + if (SoilGeometryProbability != null) + res = SoilGeometryProbability.SoilProfile.Name; + return res; + } + } + + public double SoilProfileProbability + { + get + { + var res = 0.0; + if (SoilGeometryProbability != null) + res = SoilGeometryProbability.Probability; + return res; + } + } + + public LoadSituation LoadSituation + { + get { return loadSituation; } + set { loadSituation = value; } + } + + public DikeDrySensitivity DikeDrySensitivity + { + get { return _dikeDrySensitivity; } + set { _dikeDrySensitivity = value; } + } + + public HydraulicShortcutType HydraulicShortcutType + { + get { return hydraulicShortcutType; } + set { hydraulicShortcutType = value; } + } + + public UpliftType UpliftType + { + get { return upliftType; } + set { upliftType = value; } + } + + public MStabModelType MstabModelOption + { + get { return mstabModelOption; } + set { mstabModelOption = value; } + } + + public PipingModelType PipingModelOption + { + get { return pipingModelOption; } + set { pipingModelOption = value; } + } + + public MStabParameters MStabParameters { get; set; } + + public ScenarioType ScenarioType + { + get { return scenarioType; } + set { scenarioType = value; } + } + + public string BaseFileName + { + get { return baseFileName; } + set { baseFileName = value; } + } + + public string InputFile + { + get { return DamProjectData.ProjectWorkingPath + Path.DirectorySeparatorChar + baseFileName + ".sti"; } + } + + public string ResultFile + { + get + { + const string wmfExtension = ".wmf"; + string fullBaseFilename = DamProjectData.ProjectWorkingPath + Path.DirectorySeparatorChar + baseFileName; + string fullFilename = fullBaseFilename + wmfExtension; + if (!File.Exists(fullFilename)) + { + fullFilename = fullBaseFilename + "z1" + wmfExtension; + } + if (!File.Exists(fullFilename)) + { + fullFilename = fullBaseFilename + "z2" + wmfExtension; + } + return fullFilename; + } + } + + public string PipingResultFile + { + get + { + return "leeg"; + } + // Note Bka: Path of piping is not based on the working dir but on assembly (Assembly.GetExecutingAssembly().Location) + // get { return baseFileName + PipingCalculator.PipingFilenameExtension; } ##Bka: most probably unwanted, replace with other mechanism. Or delete when NOT USED + } + + public FailureMechanismSystemType FailureMechanismType + { + get { return failureMechanismType; } + set { failureMechanismType = value; } + } + + public SoilGeometryProbability SoilGeometryProbability + { + get { return soilGeometryProbability; } + set { soilGeometryProbability = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWResult.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWResult.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWResult.cs (revision 334) @@ -0,0 +1,86 @@ +// Copyright (C) Stichting Deltares 2017. 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.ComponentModel; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class RWResult + { + private RWResultType _rwResultType = RWResultType.ProbabilityOfFailure; + private double safetyFactor = -1; + private double probabilityOfFailure = -1; + private CalculationResult calculationResult = CalculationResult.NoRun; + private ResultEvaluation resultEvaluation = ResultEvaluation.NotEvaluated; + private string notes = ""; + + public const string ResultCategory = "Results"; + + public RWResult() + { + } + + public virtual RWResultType RwResultType + { + get { return _rwResultType; } + set { _rwResultType = value; } + } + + public virtual double SafetyFactor + { + get { return safetyFactor; } + set { safetyFactor = value; } + } + + public virtual double ProbabilityOfFailure + { + get { return probabilityOfFailure; } + set { probabilityOfFailure = value; } + } + + public virtual CalculationResult CalculationResult + { + get { return calculationResult; } + set { calculationResult = value; } + } + + public ResultEvaluation ResultEvaluation + { + get { return resultEvaluation; } + set + { + resultEvaluation = value; + } + } + + [Description("Use this area to explain the valuation and for any further remarks")] + public string Notes + { + get { return notes; } + set + { + notes = value; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile.cs (revision 334) @@ -0,0 +1,77 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Soil Profile Object holding name, location and other common properties, base class for SoilProfile1D and SoilProfile2D + /// + public class SoilProfile : IName + { + private string name = "Soil Profile"; + private readonly List preconsolidationStresses = new List(); + + /// + /// The name of the profile + /// + public virtual string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + /// + /// List of Preconsolidation stresses related to a soil profile + /// + [Validate] + public virtual List PreconsolidationStresses + { + get + { + return preconsolidationStresses; + } + } + + /// + /// Assigns the specified soil profile. + /// + /// The soil profile. + public void Assign(SoilProfile soilProfile) + { + Name = soilProfile.Name; + foreach (var preconsolidationStress in soilProfile.PreconsolidationStresses) + { + var newPs = (PreConsolidationStress)preconsolidationStress.Clone(); + preconsolidationStresses.Add(newPs); + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/JobResultInterpreter.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/JobResultInterpreter.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/JobResultInterpreter.cs (revision 334) @@ -0,0 +1,60 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General.Results +{ + public class JobResultInterpreter + { + public static JobResult GetJobResult(double result, double demand, bool smaller) + { + if (result >= DamGlobalConstants.NoRunValue) + { + return JobResult.NoRun; + } + else if (result < 0 || double.IsNaN(result)) + { + return JobResult.Failed; + } + else if (smaller) + { + if (result < demand) + { + return JobResult.Bad; + } + else + { + return JobResult.Good; + } + } + else + { + if (result > demand) + { + return JobResult.Bad; + } + else + { + return JobResult.Good; + } + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerieEntry.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerieEntry.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/TimeSeries/TimeSerieEntry.cs (revision 334) @@ -0,0 +1,85 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.TimeSeries +{ + public class TimeSerieEntry + { + public TimeSerieEntry() + { + } + + public TimeSerieEntry(DateTime dateTime, double value) + { + this.DateTime = dateTime; + this.Value = value; + } + + public virtual DateTime DateTime { get; set; } + public virtual double Value { get; set; } + public virtual string BasisFileName { get; set; } + public string RelativeCalculationPathName { get; set; } + + //public Stochast StochastValue { get; set; } #Bka: for now just disable. + public int Flag { get; set; } + + public TimeSerieEntry GetShallowCopy() + { + return new TimeSerieEntry + { + DateTime = DateTime, + Flag = Flag, + }; + } + + public TimeSerieEntry Map(Func function) + { + return Map(0, function); + } + + public TimeSerieEntry Map(double missingValue, Func function) + { + var entry = this.GetShallowCopy(); + try + { + entry.Value = !this.Value.AlmostEquals(missingValue) ? function(this) : missingValue; + } + catch + { + entry.Value = missingValue; + } + return entry; + } + + public void Assign(TimeSerieEntry entry) + { + this.DateTime = entry.DateTime; + this.Value = entry.Value; + this.BasisFileName = entry.BasisFileName; + //this.StochastValue = entry.StochastValue; #Bka: for now just disable + this.Flag = entry.Flag; + } + + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/GaugePLLine.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/GaugePLLine.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/GaugePLLine.cs (revision 334) @@ -0,0 +1,74 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.General.Gauges +{ + public class GaugePLLinePoint : GeometryPoint + { + public GaugePLLinePoint() : this(null, null, null, null) { } + + public GaugePLLinePoint(double? localX, double? localZ, string gaugeX, string gaugeZ) + { + this.X = localX; + this.Z = localZ; + this.GaugeIDX = gaugeX; + this.GaugeIDZ = gaugeZ; + } + + public new double? X { get; set; } + public new double? Z { get; set; } + public string GaugeIDX { get; set; } + public string GaugeIDZ { get; set; } + + public override string ToString() + { + return String.Format("({0}, {1}, '{2}', '{3}')", this.X.HasValue ? this.X.ToString() : "?", this.Z.HasValue ? this.Z.ToString() : "?", this.GaugeIDX, this.GaugeIDZ); + } + } + + public class GaugePLLine : PolyLine + { + private GaugePLLine() + : base() + { + } + + public GaugePLLine(PLLineType plLineType) + : this() + { + this.PLLineType = plLineType; + } + + public PLLineType PLLineType { get; set; } + + public override string ToString() + { + string result = String.Format("{0} | ", this.PLLineType.ToString()); + foreach (GaugePLLinePoint point in this.Points) + result += point.ToString() + ", "; + + return result; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/IContext.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/IContext.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/IContext.cs (revision 334) @@ -0,0 +1,108 @@ +// Copyright (C) Stichting Deltares 2017. 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; + +namespace Deltares.DamEngine.Calculators.General +{ + /// + /// Application context class, which governs application wide overrides for visibility, + /// enabledness or domain data collections. + /// + public interface IContext + { + /// + /// Method indicating a visibility override value for a given instance object. + /// + /// Object being evaluated. + /// Name of the member which is part of . + /// True if visible; False if hidden; Null if no override. + bool? IsVisible(object source, string member); + + /// + /// Method indicating if the enabled override value for a given instance object. + /// + /// Object being evaluated. + /// Name of the member which is part of . + /// True if enabled; False if disabled; Null if no override. + bool? IsEnabled(object source, string member); + + /// + /// Method returning a collection of domain object for list or enum type members; + /// + /// Object being evaluated. + /// Name of the member which is part of . + /// A collection of domain object; Null if no override. + ICollection GetDomain(object source, string member); + + /// + /// Indicates to whether to perform the validation on the property or the method + /// + /// Object being evaluated. + /// Name of the member which is part of . + /// True or false if validation should be (or not be) performed; Null if no preference is given, but left over to the caller. + bool? ShouldValidate(object source, string member); + + /// + /// Gets the minimum value for a member. + /// + /// The source. + /// The member. + /// + double? GetMinimum(object source, string member); + + /// + /// Gets the maximum value for a member. + /// + /// The source. + /// The member. + /// + double? GetMaximum(object source, string member); + + /// + /// Gets the format string for a member. + /// + /// The type. + /// The source. + /// The member. + /// + string GetFormat(Type type, object source, string member); + + /// + /// Gets the default value for a memner. + /// + /// The type. + /// The member. + /// + object GetDefault(Type type, string member); + // waar is dit het handigst te implementeren (qua gebruik van)? + + /// + /// Gets the property order for UI display purposes. + /// + /// The type. + /// The member. + /// + int[] GetPropertyOrder(Type type, string member); + // is dit handig? Zo ja, dan ook een idee voor de andere attr? + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DamJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DamJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DamJob.cs (revision 334) @@ -0,0 +1,60 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General +{ + public class DamJob + { + private bool? run = false; + private object subject = null; + private string name; + + public DamJob() + { + } + + public DamJob(object subject) : this() + { + this.subject = subject; + } + + public virtual string Name + { + get { return this.subject != null ? this.subject.ToString() : ""; } + set { name = value; } + } + + public virtual bool? Run + { + get { return run; } + set + { + run = value; + } + } + + public virtual object Subject + { + get { return subject; } + set { subject = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryBounds.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryBounds.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryBounds.cs (revision 334) @@ -0,0 +1,119 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// Class holding the boundaries of a geometry object + /// + public class GeometryBounds + { + /// + /// Initializes a new instance of the class. + /// + public GeometryBounds() : this(0, 0, 0, 0) { } + + /// + /// Initializes a new instance of the class. + /// + /// The left. + /// The right. + /// The bottom. + /// The top. + public GeometryBounds(double left, double right, double bottom, double top) + { + Left = left; + Right = right; + Bottom = bottom; + Top = top; + } + + /// + /// Gets or sets the left. + /// + /// + /// The left. + /// + public double Left { get; set; } + + /// + /// Gets or sets the top. + /// + /// + /// The top. + /// + public double Top { get; set; } + + /// + /// Gets or sets the right. + /// + /// + /// The right. + /// + public double Right { get; set; } + + /// + /// Gets or sets the bottom. + /// + /// + /// The bottom. + /// + public double Bottom { get; set; } + + /// + /// Determines whether the boundary contains the specified point. + /// + /// The x. + /// The y. + /// + public bool ContainsPoint(double x, double y) + { + return x >= Left && x <= Right && y >= Bottom && y <= Top; + } + + /// + /// Implements the operator +. + /// + /// The bounds1. + /// The bounds2. + /// + /// The result of the operator. + /// + public static GeometryBounds operator +(GeometryBounds bounds1, GeometryBounds bounds2) + { + if (bounds2 == null) + { + return bounds1; + } + if (bounds1 == null) + { + return bounds2; + } + + return new GeometryBounds(Math.Min(bounds1.Left, bounds2.Left), + Math.Max(bounds1.Right, bounds2.Right), + Math.Min(bounds1.Bottom, bounds2.Bottom), + Math.Max(bounds1.Top, bounds2.Top)); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoard.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoard.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoard.cs (revision 334) @@ -0,0 +1,181 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.General +{ + public class WaterBoard + { + private string description = ""; + private IList dikes; + private List locations = null; + private IList segments; + private IList soilgeometry2DNames; + private string waterLevelTimeSeriesFileName; + private Dike selectedDike; + + public WaterBoard() + { + this.dikes = new List(); + this.segments = new List(); + this.soilgeometry2DNames = new List(); + } + + public virtual IList Segments + { + get { return this.segments; } + set { this.segments = value; } + } + + public virtual IList SoilGeometry2DNames + { + get { return this.soilgeometry2DNames; } + set { this.soilgeometry2DNames = value; } + } + + public void FillGeometry2DNamesFromSegments() + { + // Add soilgeometry2D names into list + foreach (Segment segment in Segments) + { + foreach (SoilGeometryProbability soilGeometryProbability in segment.SoilProfileProbabilities) + { + if (soilGeometryProbability.SoilGeometry2DName != null && !SoilGeometry2DNamesContains(soilGeometryProbability.SoilGeometry2DName)) + { + SoilGeometry2DName soilGeometry2DName = new SoilGeometry2DName(); + soilGeometry2DName.Geometry2DName = soilGeometryProbability.SoilGeometry2DName; + SoilGeometry2DNames.Add(soilGeometry2DName); + } + } + } + } + + /// + /// Updates the locations for scenarios. + /// + public void UpdateLocationsForScenarios() + { + foreach (Dike dike in this.Dikes) + { + dike.UpdateLocationsForScenarios(); + } + } + + /// + /// Gets the selected dike. + /// Is a helper property to be able to show the soil table. When more Dikes than one are allowed, + /// this has to become a "real" property set by the onselectionchanged event. + /// + /// + /// The selected dike. + /// + public Dike SelectedDike + { + get + { + if (selectedDike != null) + { + return selectedDike; + } + return dikes.Count > 0 ? dikes[0] : null; + } + set + { + selectedDike = value; + } + } + + private bool SoilGeometry2DNamesContains(string Name) + { + foreach (var soilGeometry2DName in SoilGeometry2DNames) + { + if (soilGeometry2DName.Geometry2DName == Name) + return true; + } + return false; + } + + public virtual IList Dikes + { + get { return this.dikes; } + set { this.dikes = value; } + } + + [XmlIgnore] + public List Locations + { + get + { + if (locations == null) + { + locations = new List(); + foreach (Dike dike in this.Dikes) + { + locations.AddRange(dike.Locations); + } + } + + return locations; + } + } + + public virtual string NumberOfDikes + { + get { return this.dikes.Count.ToString(); } + } + + public virtual string Name + { + get { return String.Format(LocalizationManager.GetTranslatedText(this, "WaterBoard")); } + } + + public virtual string Description + { + get { return description; } + set { description = value; } + } + + public override string ToString() + { + return Name; + } + + public string WaterLevelTimeSeriesFileName + { + get { return waterLevelTimeSeriesFileName; } + set + { + waterLevelTimeSeriesFileName = value; + } + } + + public Segment GetSegmentByName(string segmentId) + { + Segment segment = this.segments.Where(x => ((x.Name == segmentId))).FirstOrDefault(); + return segment; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Properties/AssemblyInfo.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Properties/AssemblyInfo.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Properties/AssemblyInfo.cs (revision 334) @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Deltares.DamEngine.Data")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Deltares")] +[assembly: AssemblyProduct("Deltares.DamEngine.Data")] +[assembly: AssemblyCopyright("Copyright © Deltares 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c984b656-9ece-4aef-ae46-6a1bb8023cfe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("17.1.0.0")] +[assembly: AssemblyFileVersion("17.1.0.0")] Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/HydraulicShortcutRWEvaluator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/HydraulicShortcutRWEvaluator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/HydraulicShortcutRWEvaluator.cs (revision 334) @@ -0,0 +1,285 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using Deltares.DamEngine.Data.General.PlLines; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class HydraulicShortcutRWEvaluator : RWEvaluator + { + private const double cMinUpliftFactor = 1.2; + private const double cMinAquitardThickness = 2.0; // meter + private const double cMinHeadGradient = 1.0; // meter + private const double cMinAquitardThicknessIfDrySensitive = 5.0; // meter + private const double cMinClayThickness = 2.0; // meter + private DikeDrySensitivity dikeDrySensitivity = DikeDrySensitivity.None; + private LoadSituation loadSituation = LoadSituation.Wet; + + public HydraulicShortcutRWEvaluator() + { + } + + public override Enum Evaluate(Location location, SoilGeometry soilGeometry, params Enum[] previousChoices) + { + base.Evaluate(location, soilGeometry, previousChoices); + HydraulicShortcutType hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + + // Determine dikeDrySensitivity and loadsituation + Dictionary choices = new Dictionary(); + foreach (Enum enumValue in previousChoices) + { + if (enumValue != null) + { + choices[enumValue.GetType()] = enumValue; + } + } + dikeDrySensitivity = (DikeDrySensitivity)choices[typeof(DikeDrySensitivity)]; + loadSituation = (LoadSituation)choices[typeof(LoadSituation)]; + System.Diagnostics.Debug.Print(String.Format("==== Hydraulic shortcut evaluation of '{0}'", location.Name)); + // determine hydraulic shortcut + + // evaluate boezempeil (step 1) + if (EvaluateBoezemLevelBelowHeadAquifer()) + { + hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + } + else + { + // Evaluate thickness of aquitard (step 2) + if (!EvaluateAquitardHasEnoughThickness()) + { + hydraulicShortcutType = HydraulicShortcutType.HydraulicShortcut; + } + else + { + // Evaluate drysensitive dike (step 3) + if (!EvaluateDikeIsDrySensitive()) + { + hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + } + else + { + // Evaluate thickness clay in aquitard and sheetpile (step 4) + if (EvaluateClayInAquitardTooThin()) + { + if (loadSituation == LoadSituation.Dry) + { + hydraulicShortcutType = HydraulicShortcutType.HydraulicShortcut; + } + else + { + hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + } + } + else + { + hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + } + } + } + } + + System.Diagnostics.Debug.Print(String.Format("==== End of Hydraulic shortcut evalution of '{0}'", location.Name)); + return hydraulicShortcutType; + } + + /// + /// Condition: Dikte waterremmende laag minstens 2 meter + /// + /// + private bool EvaluateAquitardHasEnoughThickness() + { + var aquitardEvaluator = new AquitardEvaluator(soilGeometry.SoilProfile); + double aquitardTichkness = aquitardEvaluator.DetermineAquitardThicknessWithMinimalWeight(location.DredgingDepth, this.location.GetDikeEmbankmentSoil()); // Note: do not evaluate sheetpile here + bool aquitardHasEnoughThickness = (aquitardTichkness >= cMinAquitardThickness); + System.Diagnostics.Debug.Print(String.Format("Aquitard thickness ({0}) sufficient is {1}; it should be more than {2} meter", + aquitardTichkness, aquitardHasEnoughThickness , cMinAquitardThickness)); + return aquitardHasEnoughThickness; + } + + /// + /// Condition: Droogtegevoeilige kade + /// + /// + private bool EvaluateDikeIsDrySensitive() + { + // Evaluate dry sensivity of dike + // with uplift calculation the pl-lines will be created different when dikematerial is of type peat + bool isDrySensitive = (dikeDrySensitivity == DikeDrySensitivity.Dry); + System.Diagnostics.Debug.Print(String.Format("Is dry sensitive dike is {0} (check on material)", isDrySensitive)); + if (isDrySensitive) + { + double gradient = (GetBoezemLevel() - location.PolderLevelLow); + isDrySensitive = gradient > cMinHeadGradient; + System.Diagnostics.Debug.Print(String.Format("Is dry sensitive dike is {0} because Gradient in dike ({1}) more than {2} meter", isDrySensitive, gradient, cMinHeadGradient)); + } + if (isDrySensitive) + { + double? upliftFactor = 0.0; + + // upliftFactor = GetLowestUpliftFactor(); ## Bka + if (upliftFactor != null) + { + isDrySensitive = (upliftFactor.Value < cMinUpliftFactor); + System.Diagnostics.Debug.Print(String.Format("Is dry sensitive dike is {0} because upliftfactor ({1}) more than {2}", isDrySensitive, upliftFactor.Value, cMinUpliftFactor)); + } + else + { + isDrySensitive = false; + } + } + return isDrySensitive; + } + + /// + /// Condition: Dikte kleilaag in waterremmende laag kleiner 2 meter of dikte waterremmende kleiner 5 meter + /// + /// + private bool EvaluateClayInAquitardTooThin() + { + var aquitardEvaluator = new AquitardEvaluator(soilGeometry.SoilProfile); + double aquitardThicknessWithoutMinimalWeight = aquitardEvaluator.DetermineAquitardThicknessWithoutMinimalWeight(GetBoezemBottomOrSheetPileBottom(), this.location.GetDikeEmbankmentSoil()); + double claythickness = aquitardEvaluator.DetermineAquitardClayThickness(GetBoezemBottomOrSheetPileBottom()); + + bool clayInAquitardTooThin = (aquitardThicknessWithoutMinimalWeight < cMinAquitardThicknessIfDrySensitive); + clayInAquitardTooThin = clayInAquitardTooThin || (claythickness < cMinClayThickness); + + System.Diagnostics.Debug.Print(String.Format("For dry sensitive dike aquitard thickness ({0} < {1}) or clay thickness ({2} < {3}) evaluate to {4}", + aquitardThicknessWithoutMinimalWeight, cMinAquitardThicknessIfDrySensitive, claythickness, cMinClayThickness, clayInAquitardTooThin)); + return clayInAquitardTooThin; + } + + /// + /// Condition: Boezempeil kleiner of gelijk aan stijghoogte eerste WVP + /// + /// + private bool EvaluateBoezemLevelBelowHeadAquifer() + { + double boezemLevel = GetBoezemLevel(); + bool boezemLevelBelowHeadAquifer = boezemLevel <= location.HeadPl3; + System.Diagnostics.Debug.Print(String.Format("Storage basin level ({0}) below head Aquifer WVP ({1}) is {2}", boezemLevel, location.HeadPl3, boezemLevelBelowHeadAquifer)); + return boezemLevelBelowHeadAquifer; + } + + private double GetBoezemBottomOrSheetPileBottom() + { + double boezemBottom = location.DredgingDepth; + if (location.SheetPileLength > 0) + { + double rwBankProtectionBottomLevel = location.RwBankProtectionBottomLevel; + boezemBottom = Math.Min(boezemBottom, rwBankProtectionBottomLevel); + //// sheetpile is available + //if (location.LocalXZSheetPilePoint.X < location.LocalXZSurfaceLine.CharacteristicPoints[CharacteristicPointType.DikeTopAtRiver].X) + //{ + // double sheetpilePointLevel = location.LocalXZSheetPilePoint.Z - location.SheetPileLength; + // boezemBottom = Math.Min(boezemBottom, sheetpilePointLevel); + //} + //else + //{ + // System.Diagnostics.Debug.Print(String.Format("Ignored sheetpile because X sheetpile ({0}) is larger than X dike crest at river ({1})", + // location.LocalXZSheetPilePoint.X, location.LocalXZSurfaceLine.CharacteristicPoints[CharacteristicPointType.DikeTopAtRiver].X)); + //} + } + return boezemBottom; + } + + /// + /// Determine boezemlevel according to loadsituation + /// + /// + private double GetBoezemLevel() + { + double boezemLevel = 0.0; + switch (loadSituation) + { + case LoadSituation.Wet: + boezemLevel = location.BoezemLevelTp; + break; + case LoadSituation.Dry: + boezemLevel = location.BoezemLevelHbp; + break; + } + return boezemLevel; + } + + /// + /// Create PL-lines + /// + /// +// private PLLines CreatePLLines() +// { +// PLLinesCreator plLinesCreator = new PLLinesCreator(); +// plLinesCreator.WaterLevelRiverHigh = GetBoezemLevel(); +// plLinesCreator.HeadInPLLine2 = location.HeadPL2; +// plLinesCreator.HeadInPLLine3 = location.HeadPl3; +// plLinesCreator.HeadInPLLine4 = location.HeadPl4; +// +// plLinesCreator.SurfaceLine = location.LocalXZSurfaceLine2; +// plLinesCreator.WaterLevelPolder = location.PolderLevel; +// plLinesCreator.ModelParametersForPLLines = location.CreateModelParametersForPLLines(); +// plLinesCreator.SoilProfile = soilGeometry.SoilProfile; +// plLinesCreator.SoilGeometry2DName = null; +// plLinesCreator.SoilGeometryType = SoilGeometryType.SoilGeometry1D; +// plLinesCreator.GaugePLLines = null; +// plLinesCreator.Gauges = null; +// plLinesCreator.GaugeMissVal = 0.0; +// plLinesCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; // for stability this must set to true +// plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; +// plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; +// plLinesCreator.SoilBaseDB = null; // soilbase; +// plLinesCreator.DikeEmbankmentMaterial = null; // soilbase.GetSoil(location.DikeEmbankmentMaterial); +// plLinesCreator.IsUseOvenDryUnitWeight = (dikeDrySensitivity == DikeDrySensitivity.Dry); +// plLinesCreator.IsHydraulicShortcut = false; // in this evaluation obviously no hydraulic shortcut +// plLinesCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; +// +// PLLines plLines = plLinesCreator.CreateAllPLLines(location); +// return plLines; +// } + + /// + /// Determine where lowest uplift factor occurs and the value of that factor + /// + /// +// private double? GetLowestUpliftFactor() +// { +// +// UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator() +// { +// SurfaceLine = location.SurfaceLine2, +// SoilProfile = soilGeometry.SoilProfile, +// SoilGeometry2DName = null, +// SoilBaseDB = null, //soilbase, +// DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), +// PLLines = CreatePLLines(), +// IsUseOvenDryUnitWeight = (dikeDrySensitivity == DikeDrySensitivity.Dry), +// XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin +// }; +// UpliftLocationAndResult upliftLocationAndResult = upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); +// if (upliftLocationAndResult != null) +// return upliftLocationAndResult.UpliftFactor; +// else +// return null; +// } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryLoop.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryLoop.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryLoop.cs (revision 334) @@ -0,0 +1,157 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using System.Xml.Serialization; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Dataclass for the geometryloop. + /// + /// + public class GeometryLoop : GeometryPointString + { + private readonly List curveList = new List(); + + /// + /// Gets the List of all Curves. + /// + public List CurveList + { + get + { + return curveList; + } + } + + /// + /// List of points that describe the physical surface line or surface. + /// + /// This property is not serialized. If you want to add point definitions, + /// do so by adding/inserting a new element to . + [XmlIgnore] + public override List CalcPoints + { + get + { + // explicit use of protected field to prevent stack overflow due to recursive call + if (calcPoints.Count == 0) + { + PopulateLoopPointList(); + SyncPoints(); + } + + return calcPoints; + } + } + + /// + /// Determines whether this instance is loop. + /// + /// + public bool IsLoop() + { + if (CurveList.Count <= 2) + { + return false; + } + + GeometryCurve beginCurve = curveList[0]; + GeometryCurve endCurve = curveList[curveList.Count - 1]; + + if (beginCurve.HeadPoint == endCurve.HeadPoint || + beginCurve.HeadPoint == endCurve.EndPoint || + beginCurve.EndPoint == endCurve.HeadPoint || + beginCurve.EndPoint == endCurve.EndPoint) + { + return true; + } + + return false; + } + + /// + /// See if a point lies in a closed surface + /// + /// + /// + public bool IsPointInLoopArea(Point2D aPoint) + { + return Routines2D.CheckIfPointIsInPolygon(this, aPoint.X, aPoint.Z) != PointInPolygon.OutsidePolygon; + } + + /// + /// Populates the loop's GeometryPoint list. + /// + private void PopulateLoopPointList() + { + // explicit use of protected field to prevent stack overflow due to recursive call + if (calcPoints.Count > 0) + { + return; + } + for (int index = 0; index < curveList.Count; index++) + { + if (index == 0) + { + calcPoints.Add(curveList[index].HeadPoint); + calcPoints.Add(curveList[index].EndPoint); + } + else + { + // TODO why not compare by value instead of reference + if (curveList[index].HeadPoint == calcPoints[calcPoints.Count - 1]) + { + calcPoints.Add(curveList[index].EndPoint); + } + else if (curveList[index].EndPoint == calcPoints[calcPoints.Count - 1]) + { + calcPoints.Add(curveList[index].HeadPoint); + } + else + { + if (calcPoints.Count == 2) + { + calcPoints.Reverse(); + } + if (curveList[index].HeadPoint == calcPoints[calcPoints.Count - 1]) + { + calcPoints.Add(curveList[index].EndPoint); + } + else if (curveList[index].EndPoint == calcPoints[calcPoints.Count - 1]) + { + calcPoints.Add(curveList[index].HeadPoint); + } + } + } + } + + if (calcPoints.Count > 0) + { + if (calcPoints[0] == calcPoints[calcPoints.Count - 1]) + { + calcPoints.RemoveAt(calcPoints.Count - 1); + } + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPoint.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPoint.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryPoint.cs (revision 334) @@ -0,0 +1,189 @@ +// Copyright (C) Stichting Deltares 2017. 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.ComponentModel; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class to manage a geometry point. + /// + [Serializable] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class GeometryPoint : GeometryObject, ICloneable, IComparable + { + /// + /// The precision + /// + public const double Precision = GeometryConstants.Accuracy; + + private object owner; + + /// + /// Initializes a new instance of the class. + /// + public GeometryPoint() : this(0.0, 0.0) {} + + /// + /// Initializes a new instance of the class. + /// + /// A point. + public GeometryPoint(GeometryPoint aPoint) : this(aPoint.X, aPoint.Z) {} + + /// + /// Initializes a new instance of the class. + /// + /// A x. + /// A z. + public GeometryPoint(double aX, double aZ) + { + X = aX; + Z = aZ; + } + + /// + /// Gets or sets the X coordinate of GeometryPoint + /// + public virtual double X { get; set; } + + /// + /// Gets or sets the Y coordinate of GeometryPoint + /// + public virtual double Y { get; set; } + + /// + /// Gets or sets the Z coordinate of GeometryPoint + /// + public virtual double Z { get; set; } + + /// + /// Identifies the object which owns this point. + /// + /// + /// Usually set by a delegated list, such as in . + /// + [XmlIgnore] + public object Owner + { + get + { + return owner; + } + set + { + owner = value; + } + } + + /// + /// Determines whether the location of the given point and this one are the same. + /// + /// The other. + /// + public bool LocationEquals(GeometryPoint other) + { + return LocationEquals(other, Precision); + } + + /// + /// Determines whether the difference between the location of the given point and + /// this one are within the given precision. + /// + /// The other. + /// The precision. + /// + public bool LocationEquals(GeometryPoint other, double precision) + { + if (ReferenceEquals(other, null)) + { + return false; + } + if (ReferenceEquals(other, this)) + { + return true; + } + + return X.AlmostEquals(other.X, precision) && + Z.AlmostEquals(other.Z, precision); + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + return new GeometryBounds(X, X, Z, Z); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return "(" + X.ToString("F3") + ";" + Z.ToString("F3") + ")"; + } + + + + #region ICloneable Members + + /// + /// Clones this instance. + /// + /// Only copies and . + public virtual object Clone() + { + return new GeometryPoint(this); + } + + #endregion + + #region IComparable Members + + /// + /// Compares the current instance with another object of the same type + /// Eventhough this method does not seem to be used it is! (via GPstring which is a delegated list, using a Sort which needs this). + /// So do NOT delete this as long as GPS stays a delegated list. + /// + /// An object to compare with this instance. + /// + /// Result of comparing the X values + /// + public int CompareTo(object obj) + { + var point = obj as GeometryPoint; + if (point != null) + { + return X.CompareTo(point.X); + } + return ToString().CompareTo(obj.ToString()); + } + + #endregion + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorFactory.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorFactory.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorFactory.cs (revision 334) @@ -0,0 +1,63 @@ +// Copyright (C) Stichting Deltares 2017. 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.Standard; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + public class SensorFactory + { + /// + /// Creates a sensor location. + /// + /// The location. + /// + internal SensorLocation CreateSensorLocation(Location location) + { + return CreateSensorLocation(location, new Group()); + } + + /// + /// Creates a sensor location. + /// + /// The location. + /// The group to associate the location with + /// Should return a valid instance + internal SensorLocation CreateSensorLocation(Location location, Group group) + { + return new SensorLocation + { + Group = group, + Location = location, + PL1WaterLevelAtRiver = DataSourceTypeSensors.LocationData, + PL1PLLineOffsetBelowDikeToeAtPolder = DataSourceTypeSensors.LocationData, + PL1PLLineOffsetBelowDikeTopAtPolder = DataSourceTypeSensors.LocationData, + PL1PLLineOffsetBelowDikeTopAtRiver = DataSourceTypeSensors.LocationData, + PL1PLLineOffsetBelowShoulderBaseInside = DataSourceTypeSensors.LocationData, + PL1WaterLevelAtPolder = DataSourceTypeSensors.LocationData, + PL3 = DataSourceTypeSensors.LocationData, + PL4 = DataSourceTypeSensors.LocationData + }; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry.cs (revision 334) @@ -0,0 +1,91 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Data.General +{ + /// + /// Exception class for SoilGeometry + /// + public class SoilGeometryException : ApplicationException + { + public SoilGeometryException(string message) : base(message) + { + } + } + + public class SoilGeometryBase + { + public virtual SoilGeometryType SoilGeometryType { get; set; } + public virtual string SoilGeometryName { get; set; } + } + + /// + /// Super class to contain 1D and 2D soil geometry + /// + public class SoilGeometry : SoilGeometryBase + { + private SoilProfile1D soilProfile; + private string soilGeometry2DName; + + /// + /// Constructor + /// + public SoilGeometry(SoilProfile1D soilProfile, string soilGeometry2DName) + { + this.SoilProfile = soilProfile; + this.SoilGeometry2DName = soilGeometry2DName; + } + + #region PublicPropteries + public override SoilGeometryType SoilGeometryType + { + get + { + SoilGeometryType soilGeometryType = SoilGeometryType.SoilGeometry2D; + if (soilProfile != null) + { + soilGeometryType = SoilGeometryType.SoilGeometry1D; + } + if ((SoilProfile == null) && ((SoilGeometry2DName == null) || SoilGeometry2DName == "")) + { + throw new SoilGeometryException("No geometry assigned"); + } + return soilGeometryType; + } + } + + public SoilProfile1D SoilProfile + { + get { return soilProfile; } + set { soilProfile = value; } + } + + public string SoilGeometry2DName + { + get { return soilGeometry2DName; } + set { soilGeometry2DName = value; } + } + #endregion PublicPropteries + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DAMEnumerations.cs (revision 334) @@ -0,0 +1,396 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General +{ + public enum DamLicenseType + { + None = 0, + Dongle = 1, + FlexNet = 2, + FlexLm = 3, + LicFile = 4, + LFM = 5 + } + + public enum DamType + { + Primary, + Regional + } + + public enum FullAnalysisType + { + Normal, + WV21 + }; + + public enum DamProjectType + { + Calamity, + Assessment, + Design, + DamLiveConfiguration + } + + public enum ProgramType + { + MStab, + SlopeW + }; + + public enum StabilityKernelType + { + // The Classic models all use DGMStabDam.dll to generate a sti file from the input (so also pl-lines only) + // DAM classic uses the Delphi version of DGS (as exe) to solve the calculation + DamClassic, + + // DAM classic .Net uses the .Net version of DGS which is based on the old Delphi code to solve the calculation + DamClassicDotNet, + + // DAM classic WTI uses the .Net version of DGS which is based on the new C# code to solve the calculation + DamClassicWti, + + // The advanced models use the geotechnics and DGS classes to generate the required data from input, + // using the waternet only. This requires the -rto option for starting + // Advanced .Net uses the .Net version of DGS which is based on the old Delphi code to solve the calculation + AdvancedDotNet, + + // Advanced WTI uses the .Net version of DGS which is based on the new C# code to solve the calculation + AdvancedWti + }; + + public enum AnalysisType + { + NoAdaption, + AdaptGeometry, + AdaptNWO + }; + + public enum ProbabilisticType + { + Deterministic, + Probabilistic, + ProbabilisticFragility + }; + + public enum FailureMechanismSystemType + { + StabilityInside, + StabilityOutside, + Piping, + HorizontalBalance, + FlowSlide + } + + public enum MStabModelType + { + Bishop, + Spencer, + Fellenius, + UpliftVan, + UpliftSpencer, + BishopRandomField, + HorizontalBalance, + BishopUpliftVan, + SpencerHigh, // #Bka added SpencerHigh/SpencerLow as quick fix. Should be replaced with options for Spencer later! These enums should be removed. + SpencerLow + } + + public enum PipingModelType + { + Bligh, + Sellmeijer, + Sellmeijer2Forces, + Sellmeijer4Forces, + Wti2017 + }; + + public enum FlowSlideModelType + { + All, + }; + + public enum PLLineAssignment + { + NoPLLines, + ExpertKnowledge, + DikeFlow, + OrginalPLLines + } + + public enum SoilGeometryType + { + SoilGeometry1D, + SoilGeometry2D + } + + + + public enum MStabShearStrength + { + CPhi, + StressTables, + CuCalculated, + CuMeasured, + CuGradient, + Default + } + + public enum MStabSearchMethod + { + Grid, + GeneticAlgorithm + } + + public enum MStabGridPosition + { + Left, + Right + } + + public enum MStabZonesType + { + NoZones = 0, + ZoneAreas = 1, + ForbiddenZone = 2 + } + + public enum NonWaterRetainingObjectCategory + { + Tree, + Main + }; + + public enum NonWaterRetainingObjectType + { + Oak, + Alder, + Poplar, + GasMain, + WaterMain + }; + + public enum StabilityDesignMethod //Design + { + OptimizedSlopeAndShoulderAdaption, + SlopeAdaptionBeforeShoulderAdaption + } + + public enum PhreaticAdaptionType //NWO + { + None, + MakeEmpty, + Fill // Note: Fill not yet implemented! + } ; + + public enum PLLineType + { + PL1, + PL2, + PL3, + PL4 + } + + public enum PLLinePointPositionXzType + { + OnPLLine, + AbovePLLine, + BelowPLLine, + BeyondPLLine // indicates that point is outside the scope of the pl line. + }; + + public enum DikeDrySensitivity //RWScenarios + { + None, + Dry + } + + public enum HydraulicShortcutType //RWScenarios + { + HydraulicShortcut, + NoHydraulicShortcut + } + + public enum RWResultType //RWScenarios + { + ProbabilityOfFailure, + SafetyFactor + } + + public enum ResultEvaluation //RWScenarios + { + Accepted, + Rejected, + NotEvaluated + } + + public enum LoadSituation //RWScenarios + { + Dry, + Wet + } + + public enum ScenarioType //RWScenarios + { + Scenario01 = 1, + Scenario02 = 2, + Scenario03 = 3, + Scenario04 = 4, + Scenario05 = 5, + Scenario06 = 6, + Scenario07 = 7, + Scenario08 = 8, + Scenario09 = 9, + Scenario10 = 10, + Scenario11 = 11 + } + + public enum SchematizationType //Schematizationfactor + { + MacroStabiltyInnerSideWet, + MacroStabiltyInnerSideDry, + PipingWet, + PipingDry, + HorzontalBalanceDry + } + + public enum DataSourceTypeSensors //Sensors + { + Ignore, + LocationData, + Sensor + } + + public enum SensorType //Sensors + { + PiezometricHead, + WaterLevel, + PolderLevel + } + + /// + /// Type of output series + /// + public enum TimeSerieParameters + { + [Obsolete("Use StabilityInsideFactor instead")] + SafetyFactor, // <- Is same as StabilityInsideFactor, kept for legacy code + PipingFactorWti, + PipingFactorBligh, + PipingFactorSellmeijer, + ProbabilityOfFailurePipingSellmeijer, + OvertoppingErosion, + StabilityInsideFactor, + StabilityOutsideFactor + } + + public enum UpliftType + { + Uplift, + NoUplift + } + + public enum PLLineCreationMethod + { + ExpertKnowledgeRRD, + ExpertKnowledgeLinearInDike, + GaugesWithFallbackToExpertKnowledgeRRD, + DupuitStatic, + DupuitDynamic, + Sensors, + None + } + + public enum ProjectPathLocation + { + // Other future possibilties: InProjectMap, InWindowsTemp + InApplicationMap, + InUserMap, + InProjectMap + } + + public enum StabMethodDupuit + { + None = 0, + Fellenius = 1, + Bishop = 2 + } + + public enum DataSourceType + { + CsvFiles, + Iris, + DataShapeFiles, + BackgroundShapeFiles, + MSoilBase, + MGeobase + } + + public enum LayerType + { + Top, + Dike, + Cover, + Aquifer1, + Aquifer2, + Aquitard + } + + public enum JobResult + { + NoRun, + Failed, + Good, + Bad, + Mixed + } + + public enum TimeStepUnit + { + Second, + Minute, + Hour, + Day, + Week, + Month, + Year, + Nonequidistant + } + + public enum ConfigurationStatus + { + Available, // Option is implemented and available + NotAvailable, // Option is implemented and available (can be used when combination is in development, so it will be hidden) + NotImplemented // Option is not implemented (so also no available) + } + + public enum IntrusionVerticalWaterPressureType + { + Standard, + Linear, + FullHydroStatic, + HydroStatic, + SemiTimeDependent + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/RequiredEntityNotExistException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/RequiredEntityNotExistException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/RequiredEntityNotExistException.cs (revision 334) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2017. 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.General +{ + [Serializable] + public class RequiredEntityNotExistException : Exception + { + public RequiredEntityNotExistException(string messageFormat, Type type, object idValue) + : base(string.Format(messageFormat, type.Name, idValue), null) + { + } + + public RequiredEntityNotExistException(string messageFormat, Type type, object idValue, Exception inner) + : base(string.Format(messageFormat, type.Name, idValue), inner) + { + } + + protected RequiredEntityNotExistException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Sensor.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Sensor.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/Sensor.cs (revision 334) @@ -0,0 +1,324 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + /// + /// This class represents a sensor or monitoring point used in dikes. + /// This entity is created for Dam Live + /// + public class Sensor : IName + { + #region Business Rules + + /// + /// Specication to test if the value of the candidate is valid + /// +// internal class ContiansAtLeastOneItem : PredicateSpecification> +// { +// public ContiansAtLeastOneItem() +// : base(x => x.Any()) +// { +// Description = "The sensor should contain at least one PL Line mapping."; +// } +// } + + #endregion + + //private readonly IGeometry geometry; + private double relativeLocation; + private readonly HashSet plLineTypes; + private int id; + private double xRd; + private double yRd; + private double zRd; + + public Sensor() + { + plLineTypes = new HashSet(); + ID = -1; + //geometry = new Point(0,0,0); + } + +// public Sensor(Point point) : this() +// { +// if (point == null) throw new ArgumentNullException("point"); +// //this.geometry = point; +// +// } + + public Sensor(double x, double y, double z) //: this(new Point(x, y, z)) + { + xRd = x; + yRd = y; + zRd = z; + } + + /// + /// Gets or sets the ID. + /// + /// + /// The ID should be unique. + /// + public int ID + { + get { return id; } + set + { + id = value; + } + } + + /// + /// Gets or sets the name of this sensor. + /// + /// + /// The name string value should not be empty and unique. + /// + // [Specification(typeof(NotEmptySpecification))] + public string Name { get; set; } + + /// + /// Gets or sets the depth. + /// + /// + /// The depth. + /// + public double Depth + { + get { return ZRd; } + set + { + ZRd = value; + } + } + + /// + /// Gets or sets the relative location along the profile. + /// + /// + /// The relative location in meter. + /// + public double RelativeLocation + { + get { return relativeLocation; } + set + { + relativeLocation = value; + RelativeLocationSpecified = true; + } + } + + /// + /// Gets or sets the X rd. + /// + /// + /// The X rd. + /// + public double XRd + { + get { return xRd; } + set { xRd = value; } + } + + /// + /// Gets or sets the Y rd. + /// + /// + /// The Y rd. + /// + public double YRd + { + get { return yRd; } + set { yRd = value; } + } + + /// + /// Gets or sets the Z rd. Same as Depth?? + /// + /// + /// The Z rd. + /// + public double ZRd + { + get { return zRd; } + set { zRd = value; } + } + + /// + /// Gets a value indicating whether the relative location is specified. + /// + /// + /// true if the relative location is specified; otherwise, false. + /// + public bool RelativeLocationSpecified { get; private set; } + + private SensorType type; + + /// + /// Gets or sets the type of this sensor. + /// + /// + /// The type. Default value is PiezoMetricHead. + /// + public SensorType Type + { + get { return type; } + set { type = value; } + } + + /// + /// Gets or sets the PL line array. Used for serialization only. + /// + /// + /// The PL line array. + /// + // [Specification(typeof(NotNullSpecification))] + // [Specification(typeof(ContiansAtLeastOneItem))] + public PLLineType[] PLLineMappings + { + get { return plLineTypes.ToArray(); } + set + { + ClearPLLines(); + foreach (var lineType in value) + { + Add(lineType); + } + } + } + + public string PLLineMappingsAsString + { + get + { + string res = ""; + foreach (var plLineType in plLineTypes) + { + switch (plLineType) + { + case PLLineType.PL1: res = res + "1; "; break; + case PLLineType.PL2: res = res + "2; "; break; + case PLLineType.PL3: res = res + "3; "; break; + case PLLineType.PL4: res = res + "4; "; break; + } + } + return res; + } + set + { + ClearPLLines(); + var locPlLineTypes = ParseStringToPlLineTypes(value); + foreach (var plLineType in locPlLineTypes) + { + switch (plLineType) + { + case 1: plLineTypes.Add(PLLineType.PL1); break; + case 2: plLineTypes.Add(PLLineType.PL2); break; + case 3: plLineTypes.Add(PLLineType.PL3); break; + case 4: plLineTypes.Add(PLLineType.PL4); break; + } + } + } + } + + private List ParseStringToPlLineTypes(string value) + { + value = value.Trim(); + var ids = new List(); + var idsarr = value.Split(new Char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var s in idsarr) + { + try + { + var val = Int32.Parse(s); + ids.Add(val); + } + catch (Exception) + { + // surpress errors, just do not use value + } + } + return ids; + } + + /// + /// Adds the specified PL line. + /// + /// The PL line. + public void Add(PLLineType plLine) + { + plLineTypes.Add(plLine); + } + + /// + /// Removes the specified PL line. + /// + /// The PL line. + public void Remove(PLLineType plLine) + { + plLineTypes.Remove(plLine); + } + + /// + /// Clears the PL lines list. + /// + public void ClearPLLines() + { + plLineTypes.Clear(); + } + + /// + /// Determines whether this instance is valid. + /// + /// + /// true if this instance is valid; otherwise, false. + /// +// public bool IsValid() +// { +// return !Validator.Validate(this).Any(); +// } + + /// + /// Determines whether this instance is transient (associated with a correct ID in the context of the repository). + /// + /// + /// true if this instance is transient; otherwise, false. + /// + public bool IsTransient() + { + return ID < 0; + } + + public override string ToString() + { + var name = string.IsNullOrWhiteSpace(Name) ? "name_not_set" : Name; + + return string.Format("[ID: {0}, Name: {1}, Depth: {2}, Type: {3}, RelativeLocation: {4}]", + ID, name, Depth, Type, RelativeLocation); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgent.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgent.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgent.cs (revision 334) @@ -0,0 +1,585 @@ +// Copyright (C) Stichting Deltares 2017. 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.IO; +using System.Text; +using System.Threading; +using Deltares.DamEngine.Calculators.General; +using Deltares.DamEngine.Calculators.Interfaces; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Calculators.Stability +{ + /// + /// Defines the service agent which is responsible for delegating calls + /// to the MStab calculation kernel or services + /// + public class StabilityServiceAgent : IDisposable + { + private DGSMStabDAMInterface mstabDamDll; + private DGSDAMSlopeWInterface slopeWDamDll; + + public StabilityServiceAgent() + { + mstabDamDll = new DGSMStabDAMInterface(); + slopeWDamDll = new DGSDAMSlopeWInterface(); + MStabExePath = DamProjectData.MStabExePath; + SlopeWExePath = DamProjectData.SlopeWExePath; + } + + #region Native Members + + /// + /// Constant to the dll file can only be a constant! + /// + + #endregion + + #region Wrapper Methods + + public string MStabExePath { get; set; } + public string SlopeWExePath { get; set; } + public ProgramType ProgramType { get; set; } + + /// + /// Get DLL version + /// + /// + public string GetDllVersion() + { + if (ProgramType == ProgramType.SlopeW) + { + return slopeWDamDll.GetDllVersion(); + } + else + { + return mstabDamDll.GetDllVersion(); + } + } + + /// + /// Create MStab project file + /// + /// + public void CreateProjectFile(string inputXmlString) + { + lock (typeof (StabilityServiceAgent)) + { + var result = 0; + if (ProgramType == ProgramType.SlopeW) + { + result = slopeWDamDll.CreateProjectFile(inputXmlString); + if (result > 0) + { + string errorMessage = slopeWDamDll.ErrorMessage(); + throw new StabilityServiceAgentException(errorMessage); + } + } + else + { + result = mstabDamDll.CreateProjectFile(inputXmlString); + if (result > 0) + { + string errorMessage = mstabDamDll.ErrorMessage(); + throw new StabilityServiceAgentException(errorMessage); + } + } + } + } + + /// + /// Create Soilprofile for location X in geometry-2d + /// + /// + /// + public void ConvertGeometry2DTo1D(string inputXML, ref StringBuilder outputXML) + { + const int defaultBufferSize = 10000; + int bufferSize = defaultBufferSize; + outputXML = new StringBuilder(bufferSize); + int returnCode = mstabDamDll.Geometry2DTo1DConversion(inputXML, outputXML, ref bufferSize); + if (returnCode == DgsStandardDllInterface.DllErrorOutputBufferTooSmall) + { + outputXML = new StringBuilder(bufferSize); + returnCode = mstabDamDll.Geometry2DTo1DConversion(inputXML, outputXML, ref bufferSize); + } + if (returnCode != DgsStandardDllInterface.DllErrorNone) + throw new StabilityServiceAgentException(mstabDamDll.ErrorMessage()); + } + + /// + /// Create Geometry2DData object from geometry2D file + /// + /// + /// + public void CreateGeometry2DDataFromGeometry2D(string inputXML, ref StringBuilder outputXML) + { + const int defaultBufferSize = 10000; + int bufferSize = defaultBufferSize; + outputXML = new StringBuilder(bufferSize); + int returnCode = mstabDamDll.CreateGeometry2DDataFromGeometry2D(inputXML, outputXML, ref bufferSize); + if (returnCode == DgsStandardDllInterface.DllErrorOutputBufferTooSmall) + { + outputXML = new StringBuilder(bufferSize); + returnCode = mstabDamDll.CreateGeometry2DDataFromGeometry2D(inputXML, outputXML, ref bufferSize); + } + if (returnCode != DgsStandardDllInterface.DllErrorNone) + throw new StabilityServiceAgentException(mstabDamDll.ErrorMessage()); + } + + /// + /// Calculate piping length + /// + /// + /// + public double CalculatePipingLength(PolyLine headLine) + { + int pointCount = headLine.Points.Count; + var headLinePoints = new DGSMStabDAMInterface.LegacyCoordinate[pointCount]; + double[] pointCoordinates = new double[pointCount * 2]; + for (int pointIndex = 0; pointIndex < pointCount; pointIndex++) + { + headLinePoints[pointIndex].x = headLine.Points[pointIndex].X; + headLinePoints[pointIndex].z = headLine.Points[pointIndex].Z; + pointCoordinates[pointIndex * 2] = headLine.Points[pointIndex].X; + pointCoordinates[pointIndex * 2 + 1] = headLine.Points[pointIndex].Z; + } + return mstabDamDll.PipingLengthCalculation(pointCount, ref headLinePoints); + } + + /// + /// Calculate MStab projects in specified directory + /// + /// + public void CalculateMStabDirectory(string directoryPath) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(directoryPath, StringResourceNames.ProjectFileNameNullOrEmpty); + ThrowHelper.ThrowIfDirectoryNotExist(directoryPath, StringResourceNames.ProjectFileNotExist); + ThrowHelper.ThrowIfFileNotExist(MStabExePath, StringResourceNames.MStabExecutableFileNameNotFound); + + try + { + // Compute the project files + ProcessInputfFile(directoryPath); + } + catch (ArgumentNullException argumentNullException) + { + throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); + } + catch (FileNotFoundException outputFileNotFoundException) + { + throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); + } + } + + /// + /// Calculate MStab project + /// + /// + public void CalculateMStabProject(string projectFilePath) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFilePath, StringResourceNames.ProjectFileNameNullOrEmpty); + ThrowHelper.ThrowIfFileNotExist(projectFilePath, StringResourceNames.ProjectFileNotExist); + ThrowHelper.ThrowIfFileNotExist(MStabExePath, StringResourceNames.MStabExecutableFileNameNotFound); + + try + { + // Compute the project files + ProcessInputfFile(projectFilePath); + } + catch (ArgumentNullException argumentNullException) + { + throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); + } + catch (FileNotFoundException outputFileNotFoundException) + { + throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); + } + } + + /// + /// Calculate SlopeW project + /// + /// + public void CalculateSlopeWProject(string projectFilePath) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFilePath, StringResourceNames.ProjectFileNameNullOrEmpty); + ThrowHelper.ThrowIfFileNotExist(projectFilePath, StringResourceNames.ProjectFileNotExist); + ThrowHelper.ThrowIfFileNotExist(SlopeWExePath, StringResourceNames.SlopeWExecutableFileNameNotFound); + + try + { + // Compute the project files + ProcessInputfFile(projectFilePath); + } + catch (ArgumentNullException argumentNullException) + { + throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); + } + catch (FileNotFoundException outputFileNotFoundException) + { + throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); + } + } + + /// + /// Extracts the relevant calculation results from the outputfile of MStab + /// + /// The project file to process + /// The MStab calculation results + public MStabResults ExtractStabilityResults(string projectFileName) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFileName, StringResourceNames.ProjectFileNameNullOrEmpty); + ThrowHelper.ThrowIfFileNotExist(projectFileName, StringResourceNames.ProjectFileNotExist); + + try + { + if (ProgramType == ProgramType.SlopeW) + { + string outputFile = GetSlopeWOutputFileName(projectFileName); + return ParseSlopeWResultsFromOutputFile(outputFile); + } + else + { + string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); + return ParseMStabResultsFromOutputFile(outputFile); + } + } + catch (ArgumentNullException argumentNullException) + { + string message = LocalizationManager.GetTranslatedText(this.GetType(), "CouldNotExtractSafetyFactor"); + throw new StabilityServiceAgentException(message, argumentNullException); + } + catch (FileNotFoundException outputFileNotFoundException) + { + string message = LocalizationManager.GetTranslatedText(this.GetType(), "CouldNotExtractSafetyFactor"); + + string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); + string[] errorMessages = ParseMStabErrorFile(outputFile); + if (errorMessages.Length > 0) + { + message = errorMessages[0]; + } + + throw new StabilityServiceAgentException(message, outputFileNotFoundException); + } + } + + /// + /// Extract the beta-value from dumpfile of MStab + /// + /// + /// + public double ExtractBeta(string projectFileName) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFileName, StringResourceNames.ProjectFileNameNullOrEmpty); + ThrowHelper.ThrowIfFileNotExist(projectFileName, StringResourceNames.ProjectFileNotExist); + + string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); + + try + { + return ParseBetaFromOutputFile(outputFile); + } + catch (ArgumentNullException argumentNullException) + { + throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); + } + catch (FileNotFoundException outputFileNotFoundException) + { + throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); + } + } + + #endregion + + #region Helper Methods + + private string CreateMStabIniFile(string inputFileName) + { + string filename = Path.GetTempFileName(); + filename = Path.ChangeExtension(filename, "ini"); + string defaultIniFilename = Path.Combine(Path.GetDirectoryName(MStabExePath), "DGeoStability.ini"); + string newIniContent = "[D-Geo Stability batch processing]"; + var isDirectoryBatchCalculation = Directory.Exists(inputFileName); + if (isDirectoryBatchCalculation) + { + newIniContent += System.Environment.NewLine + "Path=" + inputFileName; + newIniContent += System.Environment.NewLine + "Filespec=*.sti"; + } + else + { + newIniContent += System.Environment.NewLine + "InputFileName=" + inputFileName; + } + newIniContent += System.Environment.NewLine + "Plot Critical Circle=1"; + newIniContent += System.Environment.NewLine + "PlotWMF=1"; + newIniContent += System.Environment.NewLine + "PlotJPeg=1"; + if (File.Exists(defaultIniFilename)) + { + string iniContent = File.ReadAllText(defaultIniFilename); + newIniContent += System.Environment.NewLine + System.Environment.NewLine + iniContent; + }; + File.WriteAllText(filename, newIniContent); + return filename; + + } + + /// + /// Processes the input file using the working folder + /// + /// The folder or file name; for MStab: if a filename is specified then the file will be calculated; if a foldername is specified, all the stability files in the folder will be calculated. For SlopeW only filename is allowed + private void ProcessInputfFile(string folderOrFileName) + { + const string quote = "\""; + var argument = ""; + var programpath = ""; + string mStabIniFilename = ""; + if (ProgramType == ProgramType.SlopeW) + { + programpath = SlopeWExePath; + argument = " /s /x " + quote + folderOrFileName + quote + " " + quote + Path.GetFileNameWithoutExtension(folderOrFileName) + quote; + } + else + { + programpath = MStabExePath; + mStabIniFilename = CreateMStabIniFile(folderOrFileName); + argument = string.Format("/b \"{0}\"", mStabIniFilename); + + // For debugging and calling with commandline options i.s.o. inifile + //string filename = Path.GetTempFileName(); + //File.WriteAllText(filename, programpath); + //File.WriteAllText(filename, argument); + //File.AppendAllText(filename, mStabIniFilename); + //argument = string.Format("/B /PlotJPeg /Plot \"{0}\"", folderOrFileName); // note: use the folder name only for running MStab in batch mode + //File.AppendAllText(filename, argument); + } + + var process = new Process + { + StartInfo = + { + FileName = programpath, + Arguments = argument, + UseShellExecute = false + } + + }; + + General.Parallel.KillOnAbort(process); + + process.Start(); + + try + { + process.WaitForExit(); + } + catch (ThreadInterruptedException) + { + // thread was killed by user action to stop calculation + } + finally + { + if (File.Exists(mStabIniFilename)) + { + File.Delete(mStabIniFilename); + } + } + } + + + /// + /// Creates a random working folder by using a GUID + /// + /// The generated folder name + private static string CreateTempDirName() + { + return string.Format("{0}\\{1}", Path.GetTempPath(), Guid.NewGuid().ToString().Replace('-', '0')); + } + + /// + /// Gets the stripped file name with the correct extension extracted from the input file name + /// + /// The file name with path + /// The project file name without path and correct extension + private static string GetOutputFileName(string projectFileName) + { + return GetStrippedFileNameWithoutExtension(projectFileName) + ".std"; + } + + /// + /// Gets the filename with the correct extension and the proper path for the outputfile for SlopeW + /// + /// The file name with path + /// The project file name with extended path and correct extension + private static string GetSlopeWOutputFileName(string projectFileName) + { + string outputFile = Path.GetDirectoryName(projectFileName); + outputFile = Path.Combine(outputFile, Path.GetFileNameWithoutExtension(projectFileName)); + outputFile = Path.Combine(outputFile, "001"); + outputFile = Path.Combine(outputFile, Path.GetFileNameWithoutExtension(projectFileName)); + string outputFileTest = outputFile + ".optfrc"; + if (!File.Exists(outputFileTest)) + { + outputFileTest = outputFile + ".frc01"; + } + if (!File.Exists(outputFileTest)) + { + outputFileTest = ""; + } + return outputFileTest; + } + + /// + /// Gets the stripped file name without a path + /// + /// The file name + /// The project file name without path and correct extension + private static string GetInputFileName(string projectFileName) + { + return GetStrippedFileNameWithoutExtension(projectFileName) + ".sti"; + } + + /// + /// Gets the stripped file name without path and extension + /// + /// The file name to strip + /// The file name + private static string GetStrippedFileNameWithoutExtension(string fileName) + { + return fileName.Substring(fileName.LastIndexOf("\\") + 1).Split('.')[0]; + } + + /// + /// Gets the constructed file name with folder + /// + /// The name of the file + /// The name of the folder + /// The full file path + private static string GetFileName(string fileName, string folderName) + { + return string.Format("{0}\\{1}", folderName, fileName); + } + + /// + /// Parses the safety factor from the output file + /// + /// The file to parse + /// The safety factor + private static MStabResults ParseMStabResultsFromOutputFile(string outputFile) + { + if (!File.Exists(outputFile)) + throw new FileNotFoundException("No valid calculation performed"); + + var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); + return StabilityServiceFileParser.GetMStabResults(fileContent); + } + + /// + /// Parses the error messages from the error file + /// + /// The file to parse + /// The error messages + private string[] ParseMStabErrorFile(string outputFile) + { + string errorFile = outputFile.Replace(".std", ".err"); + + if (File.Exists(errorFile)) + { + List messages = new List(); + bool content = false; + foreach (string line in File.ReadAllLines(outputFile)) + { + if (line.StartsWith("**********")) + { + content = !content; + } + else if (content) + { + messages.Add(line); + } + } + + return messages.ToArray(); + } + else + { + return new string[0]; + } + } + + /// + /// Parses the safety factor from the output file + /// + /// The file to parse + /// The safety factor + private static MStabResults ParseSlopeWResultsFromOutputFile(string outputFile) + { + if (!File.Exists(outputFile)) + throw new FileNotFoundException("No valid calculation performed"); + + var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); + return StabilityServiceFileParser.GetSlopeWResults(fileContent); + } + + private static double ParseBetaFromOutputFile(string outputFile) + { + if (!File.Exists(outputFile)) + throw new FileNotFoundException("No valid calculation performed"); + + var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); + return StabilityServiceFileParser.GetBeta(fileContent); + } + + #endregion + + #region IDispose Members + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // No need to call the finalizer since we've now cleaned + // up the unmanaged memory + GC.SuppressFinalize(this); + } + } + + // This finalizer is called when Garbage collection occurs, but only if + // the IDisposable.Dispose method wasn't already called. + ~StabilityServiceAgent() + { + Dispose(false); + } + + #endregion + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWEvaluator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWEvaluator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/RWEvaluator.cs (revision 334) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.General; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class RWEvaluator + { + protected Location location = null; + protected SoilGeometry soilGeometry = null; + private Enum[] previousChoices = null; + + public RWEvaluator() + { + } + + public virtual Enum Evaluate(Location location, SoilGeometry soilGeometry, params Enum[] previousChoices) + { + this.location = location; + this.soilGeometry = soilGeometry; + this.previousChoices = previousChoices; + + return null; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs (revision 334) @@ -0,0 +1,69 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// Class holding all geometry related constants + /// + public static class GeometryConstants + { + /// + /// The default left limit of the geometry + /// + public const double DefaultLeftLimitGeometry = 0.0; + + /// + /// The default right limit of the geometry + /// + public const double DefaultRightLimitGeometry = 50.0; + + /// + /// The default bottom limit of the geometry + /// + public const double DefaultBottomLimitGeometry = -10.0; + + /// + /// The accuracy as used for the geometry objects + /// + public const double Accuracy = 0.001; + + /// + /// The volumic weight of water + /// + public const double VolumicWeightOfWater = 9.81; + } + + /// + /// Pointtype as used by intersection methods and other helper methods to determine for which plane the method has to work. + /// +// public enum PointType +// { +// /// +// /// The xy plane +// /// +// XY, +// /// +// /// The xz plane +// /// +// XZ +// } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer.cs (revision 334) @@ -0,0 +1,74 @@ +// Copyright (C) Stichting Deltares 2017. 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.Geometry; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Soil Layer object + /// + public class SoilLayer : GeometryObject + { + /// + /// Gets or sets the soil object + /// + /// soil value + public virtual Soil Soil { get; set; } + + /// + /// Defines whether the layer acts as aquifer (true) or aquitard (false). + /// + public virtual bool IsAquifer { get; set; } + + + + /// + /// Gets or sets the waterpressure interpolation model. + /// + /// + /// The waterpressure interpolation model. + /// + public virtual WaterpressureInterpolationModel WaterpressureInterpolationModel { get; set; } + + + /// + /// Validates the layer. + /// + /// + [Validate] + public ValidationResult[] ValidateLayer() + { + var results = new List(); + { + if (Soil == null) + { + results.Add(new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText(GetType(), "NoSoilAssigned"), this)); + } + } + return results.ToArray(); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointSet.cs (revision 334) @@ -0,0 +1,571 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Represents a meta-data set of instances that describe + /// special point-locations of a geometric surfaceline. + /// + public class CharacteristicPointSet : IList, IList + { + private readonly List annotations; + private readonly object syncRoot = new object(); + private readonly Dictionary typeCache; + private GeometryPointString geometry; + private bool geometryMustContainPoint; + + /// + /// Creates a characteristic point set whose points act as meta data for a geometric + /// description ( false) of a surfaceline. + /// + public CharacteristicPointSet() + { + typeCache = new Dictionary(); + annotations = new List(); + geometryMustContainPoint = false; + } + + /// + /// The observed localized geometry point string, describing the dike surfaceline + /// shape. + /// + /// References by aggregation. + public GeometryPointString Geometry + { + get + { + return geometry; + } + set + { + geometry = value; + + FullSyncWithGeometry(); + } + } + + /// + /// When true, requires all instances part of + /// this set to be contained in and cannot have instances + /// not part of . + /// When false, all instances are required NOT + /// to be part of . Their height will then be determined by + /// the height profile defined by . + /// + public bool GeometryMustContainPoint + { + get + { + return geometryMustContainPoint; + } + set + { + geometryMustContainPoint = value; + + FullSyncWithGeometry(); + } + } + + /// + /// Retrieves the annotated with the given type. + /// + /// Annotation to look for. + /// The instances annotated with the given type; + /// Null if no definition can be found. + /// This method relies on this class observing changes to its + /// to work correctly. + public GeometryPoint GetGeometryPoint(CharacteristicPointType characteristicPointType) + { + return typeCache.ContainsKey(characteristicPointType) + ? typeCache[characteristicPointType] + : null; + } + + /// + /// Sorts this characteristic point set items on + /// ascending. If is true, + /// shall also be sorted. + /// + public void Sort() + { + if (GeometryMustContainPoint && Geometry != null) + { + Geometry.SortPointsByXAscending(); + } + annotations.Sort(); + } + + /// + /// Annotates the characteristic point at the specified index. + /// + /// The index. + /// The new type of the characteristic point. + /// When is + /// less then 0 or greater or equal to . + /// will be returning the correct points. + public void Annotate(int index, CharacteristicPointType characteristicPointType) + { + annotations[index].CharacteristicPointType = characteristicPointType; + UpdateTypeCache(annotations[index]); + } + + #region Implementation: IList, IList + + /// + /// Gets an object that can be used to synchronize access to the . + /// + public object SyncRoot + { + get + { + return syncRoot; + } + } + + /// + /// Gets a value indicating whether access to the is synchronized (thread safe). + /// + public bool IsSynchronized + { + get + { + return false; + } + } + + /// + /// Gets a value indicating whether the has a fixed size. + /// + public bool IsFixedSize + { + get + { + return false; + } + } + + /// + /// Gets or sets the element at the specified index. + /// + /// The index. + /// + object IList.this[int index] + { + get + { + return this[index]; + } + set + { + this[index] = (CharacteristicPoint) value; + } + } + + /// + /// Gets the number of elements contained in the . + /// + public int Count + { + get + { + return annotations.Count; + } + } + + /// + /// Gets a value indicating whether the is read-only. + /// + public bool IsReadOnly + { + get + { + return false; + } + } + + /// + /// Gets or sets the element at the specified index. + /// + /// The index. + /// + public CharacteristicPoint this[int index] + { + get + { + return annotations[index]; + } + set + { + RemoveAt(index); + Insert(index, value); + } + } + + /// + /// Adds an item to the . + /// + /// The object to add to the . + /// + /// The position into which the new element was inserted, or -1 to indicate that the item was not inserted into the collection, + /// + public int Add(object value) + { + Add((CharacteristicPoint) value); + return Count - 1; + } + + /// + /// Determines whether the contains a specific value. + /// + /// The object to locate in the . + /// + /// true if the is found in the ; otherwise, false. + /// + public bool Contains(object value) + { + var cp = value as CharacteristicPoint; + if (cp == null) + { + return false; + } + + return Contains(cp); + } + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in at which copying begins. + public void CopyTo(Array array, int index) + { + CopyTo((CharacteristicPoint[]) array, index); + } + + /// + /// Determines the index of a specific item in the . + /// + /// The object to locate in the . + /// + /// The index of if found in the list; otherwise, -1. + /// + public int IndexOf(object value) + { + return IndexOf((CharacteristicPoint) value); + } + + /// + /// Inserts an item to the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The object to insert into the . + public void Insert(int index, object value) + { + Insert(index, (CharacteristicPoint) value); + } + + /// + /// Removes the first occurrence of a specific object from the . + /// + /// The object to remove from the . + public void Remove(object value) + { + Remove((CharacteristicPoint) value); + } + + /// + /// Removes the first occurrence of a specific object from the . + /// + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . + /// + public bool Remove(CharacteristicPoint item) + { + var removed = PerformCollectionRemoveWithEvents(annotations, item); + + if (removed) + { + typeCache.Remove(item.CharacteristicPointType); + + var removeGeometryPoint = GeometryMustContainPoint && Geometry != null && + Geometry.Points.Contains(item.GeometryPoint) && + !annotations.Any(cp => ReferenceEquals(cp.GeometryPoint, item.GeometryPoint)); + + if (removeGeometryPoint) + { + PerformCollectionRemoveWithEvents(Geometry.Points, item.GeometryPoint); + } + } + + return removed; + } + + /// + /// Adds an item to the . + /// + /// The object to add to the . + public void Add(CharacteristicPoint item) + { + Insert(Count, item); + } + + /// + /// Removes all items from the . + /// + public void Clear() + { + ClearCharacteristicPointSet(); + + if (GeometryMustContainPoint && Geometry != null) + { + Geometry.Points.Clear(); + Geometry.CalcPoints.Clear(); + } + } + + /// + /// Determines whether the contains a specific value. + /// + /// The object to locate in the . + /// + /// true if is found in the ; otherwise, false. + /// + public bool Contains(CharacteristicPoint item) + { + return annotations.Contains(item); + } + + /// + /// Copies to. + /// + /// The array. + /// Index of the array. + public void CopyTo(CharacteristicPoint[] array, int arrayIndex) + { + annotations.CopyTo(array, arrayIndex); + } + + /// + /// Determines the index of a specific item in the . + /// + /// The object to locate in the . + /// + /// The index of if found in the list; otherwise, -1. + /// + public int IndexOf(CharacteristicPoint item) + { + return annotations.IndexOf(item); + } + + /// + /// Inserts an item to the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The object to insert into the . + public void Insert(int index, CharacteristicPoint item) + { + if (!ReferenceEquals(item.PointSet, this)) + { + item.PointSet = this; + } + var itemAtIndex = index < annotations.Count ? annotations[index].GeometryPoint : null; + PerformListInsertWithEvents(annotations, item, index); + if (GeometryMustContainPoint && Geometry != null && !Geometry.Points.Contains(item.GeometryPoint)) + { + var geometryIndex = Geometry.Points.Count; + if (null != itemAtIndex) + { + for (int i = 0; i < Geometry.Points.Count; i++) + { + if (ReferenceEquals(Geometry.Points[i], itemAtIndex)) + { + geometryIndex = i; + break; + } + } + } + PerformListInsertWithEvents(Geometry.Points, item.GeometryPoint, geometryIndex); + } + + UpdateCharacteristicPointHeight(item); + UpdateTypeCache(item); + } + + /// + /// Removes the item at the specified index. + /// + /// The zero-based index of the item to remove. + public void RemoveAt(int index) + { + Remove(annotations[index]); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return annotations.GetEnumerator(); + } + + #endregion + + #region Events + + /// + /// + /// Type of the list elements. + /// The list where the item is inserted into. + /// The item inserted into the list. + /// Index where the item is inserted. + private static void PerformListInsertWithEvents(IList list, T item, int index) + { + list.Insert(index, item); + } + + private static bool PerformCollectionRemoveWithEvents(ICollection list, T item) + { + var removed = list.Remove(item); + + return removed; + } + + #endregion + + /// + /// Snaps the characteristic point height to if it's not part + /// of it, or set it to in case no + /// is available. + /// + /// The characteristic point whose height is to be updated. + private void UpdateCharacteristicPointHeight(CharacteristicPoint characteristicPoint) + { + if (geometry == null) + { + characteristicPoint.Z = double.NaN; + } + else if (!geometry.Points.Contains(characteristicPoint.GeometryPoint)) + { + if (double.IsNaN(characteristicPoint.X)) + { + characteristicPoint.Z = double.NaN; + } + else + { + // Note: Cannot use GeometryPointString.GetZAtX due to its requirement + // that Geometry.Points is sorted on X. + characteristicPoint.Z = geometry.GetZAtUnsortedX(characteristicPoint.X); + } + } + // Else: Keep Z the same as in Geometry + } + + private void FullSyncWithGeometry() + { + if (GeometryMustContainPoint) + { + // Resync with geometry; Do not keep previous data: + ClearCharacteristicPointSet(); + + if (geometry == null) + { + return; + } + + foreach (var geometryPoint in geometry.Points) + { + Add(new CharacteristicPoint + { + GeometryPoint = geometryPoint, + CharacteristicPointType = CharacteristicPointType.None + }); + } + } + else + { + // Remove all characteristic points whose GeometryPoint are part of Geometry + // as per required by the value of GeometryMustContainPoint. All other + // characteristic points should have their height updated: + foreach (var characteristicPoint in annotations.ToArray()) + { + if (geometry != null && geometry.Points.Contains(characteristicPoint.GeometryPoint)) + { + Remove(characteristicPoint); + } + else + { + UpdateCharacteristicPointHeight(characteristicPoint); + } + } + } + } + + private void ClearCharacteristicPointSet() + { + ClearAnnotations(); + typeCache.Clear(); + } + + private void ClearAnnotations() + { + annotations.Clear(); + } + + private void UpdateTypeCache(CharacteristicPoint item) + { + if (item.CharacteristicPointType != CharacteristicPointType.None) + { + // Prevent duplication: + var alreadyDefined = annotations.FirstOrDefault(cp => cp.CharacteristicPointType == item.CharacteristicPointType && + !ReferenceEquals(cp.GeometryPoint, item.GeometryPoint)); + if (alreadyDefined != null) + { + alreadyDefined.CharacteristicPointType = CharacteristicPointType.None; + } + + // Set new annotation definition: + typeCache[item.CharacteristicPointType] = item.GeometryPoint; + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/CoordinateSystemConverter.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/CoordinateSystemConverter.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/CoordinateSystemConverter.cs (revision 334) @@ -0,0 +1,295 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// Exception class for . + /// + public class CoordinateSystemConverterException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public CoordinateSystemConverterException(string message) + : base(message) {} + } + + /// + /// class for converting object coordinates from global to local system and back. + /// + /// Converter assumes all points of the given line are in the same vertical + /// 2D plane. + public class CoordinateSystemConverter + { + private double cosAlpha = 0; + private double endX; + private double endY; + private bool isGlobalXYZDefined = false; + + private double length; + private double sinAlpha = 0; + private double startX = 0.0; + private double startY = 0.0; + + /// + /// cos(alpha) of x-axis of local XYZ system + /// + public double CosAlpha + { + get + { + ThrowIfGlobalXYZNotDefined(); + return cosAlpha; + } + } + + /// + /// sin(alpha) of x-axis of local XYZ system + /// + public double SinAlpha + { + get + { + ThrowIfGlobalXYZNotDefined(); + return sinAlpha; + } + } + + /// + /// x-coordinate of origin of local XYZ system + /// + public double XStart + { + get + { + ThrowIfGlobalXYZNotDefined(); + return startX; + } + } + + /// + /// y-coordinate of origin start point of local XYZ system + /// + public double YStart + { + get + { + ThrowIfGlobalXYZNotDefined(); + return startY; + } + } + + /// + /// x-coordinate of origin last point + /// + public double XEnd + { + get + { + ThrowIfGlobalXYZNotDefined(); + return endX; + } + } + + /// + /// y-coordinate of origin end point + /// + public double YEnd + { + get + { + ThrowIfGlobalXYZNotDefined(); + return endY; + } + } + + /// + /// Gets the length. + /// + /// + /// The length. + /// + public double Length + { + get + { + ThrowIfGlobalXYZNotDefined(); + return length; + } + } + + /// + /// Gets a value indicating whether [converted to local]. + /// + /// + /// true if [converted to local]; otherwise, false. + /// + public bool ConvertedToLocal { get; private set; } + + /// + /// Define parameters to parameterize the global reference system. + /// + /// Line defined in global coordinates. + public void DefineGlobalXYZBasedOnLine(GeometryPointString globalLine) + { + GeometryPoint firstPoint = globalLine.Points[0]; + GeometryPoint lastPoint = globalLine.Points[globalLine.Points.Count - 1]; + + double dX = lastPoint.X - firstPoint.X; + double dY = lastPoint.Y - firstPoint.Y; + + length = Math.Sqrt(dX*dX + dY*dY); + + cosAlpha = dX/length; + sinAlpha = dY/length; + + startX = firstPoint.X; + startY = firstPoint.Y; + + endX = lastPoint.X; + endY = lastPoint.Y; + + isGlobalXYZDefined = true; + } + + /// + /// Define parameters to define global reference system + /// + [Obsolete] + public void DefineLocalXZBasedOnSavedProperties(double originalX, double originalY, double angle) + { + cosAlpha = Math.Cos(angle); + sinAlpha = Math.Sin(angle); + startX = originalX; + startY = originalY; + isGlobalXYZDefined = true; + } + + /// + /// Projects a global coordinate to a local XZ reference system. + /// + /// Global coordinate. + /// + /// When global parameters haven't + /// been defined yet with . + public void ConvertGlobalXYZToLocalXZ(GeometryPoint globalPoint) + { + ThrowIfGlobalXYZNotDefined(); + + globalPoint.X = GetLocalXForGlobalPoint(globalPoint); + globalPoint.Y = 0.0; + } + + /// + /// Projects a line of global coordinates to a local XZ reference system. + /// + /// Th line in global coordinates. + /// + public void ConvertGlobalXYZToLocalXZ(GeometryPointString globalLine) + { + if (!isGlobalXYZDefined) + { + DefineGlobalXYZBasedOnLine(globalLine); + } + ThrowIfGlobalXYZNotDefined(); + + foreach (var point in globalLine.Points) + { + ConvertGlobalXYZToLocalXZ(point); + } + ConvertedToLocal = true; + } + + /// + /// Projects a local coordinate back to the parameterized global XYZ reference system. + /// + /// Local coordinate. + /// + /// When global parameters haven't + /// been defined yet with . + public void ConvertLocalXZToGlobalXYZ(GeometryPoint localPoint) + { + ThrowIfGlobalXYZNotDefined(); + + double localX = localPoint.X*cosAlpha + startX; + double localY = localPoint.X*sinAlpha + startY; + localPoint.X = localX; + localPoint.Y = localY; + } + + /// + /// Projects a XZ-line local coordinates back to the parameterized global XYZ reference system. + /// + /// Line in local coordinates. + /// + /// When global parameters haven't + /// been defined yet with . + public void ConvertLocalXZToGlobalXYZ(GeometryPointString localLine) + { + ThrowIfGlobalXYZNotDefined(); + + foreach (var point in localLine.Points) + { + ConvertLocalXZToGlobalXYZ(point); + } + } + + private double GetLocalXForGlobalPoint(GeometryPoint globalPoint) + { + const double cSinCosThreshold = 0.4; + + double dX = globalPoint.X - startX; + double dY = globalPoint.Y - startY; + + double localXfromGlobalX = dX/cosAlpha; + if (Math.Abs(sinAlpha) < cSinCosThreshold) + { + // if line tends to be horizontal use local x calculated based on dX + return localXfromGlobalX; + } + + double localXfromGlobalY = dY/sinAlpha; + if (Math.Abs(cosAlpha) < cSinCosThreshold) + { + // if line tends to be vertical use local x calculated based on dY + return localXfromGlobalY; + } + + // if angle around 45 degrees then use the mean between the 2 values + return (localXfromGlobalX + localXfromGlobalY)/2; + } + + /// + /// Raise exception if Global XYZ reference system is not defined + /// + private void ThrowIfGlobalXYZNotDefined() + { + if (!isGlobalXYZDefined) + { + throw new CoordinateSystemConverterException("Global reference coordinate system is not defined"); + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/DamEngine.sln =================================================================== diff -u -r304 -r334 --- dam engine/trunk/src/DamEngine.sln (.../DamEngine.sln) (revision 304) +++ dam engine/trunk/src/DamEngine.sln (.../DamEngine.sln) (revision 334) @@ -7,6 +7,10 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deltares.DamEngine.Interface.Tests", "Deltares.DamEngine.Interface.Tests\Deltares.DamEngine.Interface.Tests.csproj", "{968516F9-1B92-4ADB-AE4A-CFF54EE43126}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deltares.DamEngine.Calculators", "Deltares.DamEngine.Calculators\Deltares.DamEngine.Calculators.csproj", "{E943B1D5-FAFA-4AFE-9071-F8B22CF612EA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deltares.DamEngine.Data", "Deltares.DamEngine.Data\Deltares.DamEngine.Data.csproj", "{B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -21,6 +25,14 @@ {968516F9-1B92-4ADB-AE4A-CFF54EE43126}.Debug|x86.Build.0 = Debug|x86 {968516F9-1B92-4ADB-AE4A-CFF54EE43126}.Release|x86.ActiveCfg = Release|x86 {968516F9-1B92-4ADB-AE4A-CFF54EE43126}.Release|x86.Build.0 = Release|x86 + {E943B1D5-FAFA-4AFE-9071-F8B22CF612EA}.Debug|x86.ActiveCfg = Debug|x86 + {E943B1D5-FAFA-4AFE-9071-F8B22CF612EA}.Debug|x86.Build.0 = Debug|x86 + {E943B1D5-FAFA-4AFE-9071-F8B22CF612EA}.Release|x86.ActiveCfg = Release|x86 + {E943B1D5-FAFA-4AFE-9071-F8B22CF612EA}.Release|x86.Build.0 = Release|x86 + {B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E}.Debug|x86.ActiveCfg = Debug|x86 + {B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E}.Debug|x86.Build.0 = Debug|x86 + {B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E}.Release|x86.ActiveCfg = Release|x86 + {B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Point2D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Point2D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Point2D.cs (revision 334) @@ -0,0 +1,111 @@ +// Copyright (C) Stichting Deltares 2017. 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.ComponentModel; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class for pure X,Z coors, to be used in calculation + /// + [TypeConverter(typeof(ExpandableObjectConverter))] + public class Point2D : IComparable + { + /// + /// Initializes a new instance of the class. + /// + public Point2D() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The x. + /// The z. + public Point2D(double x, double z) + { + X = x; + Z = z; + } + + /// + /// The x + /// + public double X; + + /// + /// The z + /// + public double Z; + + /// + /// Determines whether the location of the given point and this one are the same. + /// + /// The other. + /// + public bool LocationEquals(Point2D other) + { + return LocationEquals(other, GeometryConstants.Accuracy); + } + + /// + /// Determines whether the difference between the location of the given point and + /// this one are within the given precision. + /// + /// The other. + /// The precision. + /// + public bool LocationEquals(Point2D other, double precision) + { + if (ReferenceEquals(other, null)) + { + return false; + } + if (ReferenceEquals(other, this)) + { + return true; + } + + return X.AlmostEquals(other.X, precision) && + Z.AlmostEquals(other.Z, precision); + } + + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// + /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the sort order as . Greater than zero This instance follows in the sort order. + /// + public int CompareTo(object obj) + { + var point = obj as Point2D; + if (point != null) + { + return X.CompareTo(point.X); + } + return String.Compare(ToString(), obj.ToString(), StringComparison.Ordinal); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs (revision 334) @@ -0,0 +1,546 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// All extension-methods for . + /// + public static class SurfaceLine2Extensions + { + /// + /// Returns all that require to be sorted on X + /// ascending. + /// + /// The evaluated surfaceline. + /// Collection of characteristic points, ordered by type from the point + /// expecting the lowest X coordinate in the set through to the one expecting the + /// highest X coordinate. + public static IEnumerable GetCharacteristicPointsRequiringAscendingX(this SurfaceLine2 line) + { + return line.CharacteristicPoints.Where(p => + !double.IsNaN(p.X) && // Note: This probably shall no longer apply to SurfaceLine2 + p.CharacteristicPointType != CharacteristicPointType.None && + p.CharacteristicPointType != CharacteristicPointType.TrafficLoadInside && + p.CharacteristicPointType != CharacteristicPointType.TrafficLoadOutside). + OrderBy(p => p.CharacteristicPointType); + } + + /// + /// Checks whether the specified line has the given annotation. + /// + /// The surface line to be checked. + /// The type. + /// + /// + public static bool HasAnnotation(this SurfaceLine2 line, CharacteristicPointType type) + { + return line.CharacteristicPoints.GetGeometryPoint(type) != null; + } + + /// + /// Determines whether the specified characteristic point type is defined (has + /// the given annotation and its X coordinate is not ). + /// + /// The evaluated surfaceline. + /// Type of the characteristic point. + /// true if input parameter is defined + /// + public static bool IsDefined(this SurfaceLine2 line, CharacteristicPointType characteristicPointType) + { + // TODO: GRASP: Information Expert -> CharacteristicPoint class should be responsible for this logic. + return line.HasAnnotation(characteristicPointType) && + !Double.IsNaN(line.CharacteristicPoints.GetGeometryPoint(characteristicPointType).X); + } + + /// + /// Gets the absolute height ([m]) of the dike. + /// + /// Height of dike, or null if + /// is not defined for the surface line. + public static double? GetDikeHeight(this SurfaceLine2 line) + { + var dikeTopAtRiver = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + if (dikeTopAtRiver != null) + { + return dikeTopAtRiver.Z; + } + return null; + } + + /// + /// If shoulder is present then the toe of the shoulder () + /// is returned, else the toe of the dike () + /// is returned. + /// + /// Toe of the dike, or null if none of the required characteristic + /// annotations can be found. + public static GeometryPoint GetDikeToeInward(this SurfaceLine2 line) + { + return line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside) ?? + line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + } + + /// + /// Gets the length of the dike. + /// + /// dike length or null in case toe points are null + public static double? GetDikeLength(this SurfaceLine2 line) + { + var dikeToeAtRiver = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver); + var dikeToeAtPolder = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + + if (dikeToeAtRiver != null && dikeToeAtPolder != null) + { + return Math.Abs(dikeToeAtRiver.X - dikeToeAtPolder.X); + } + return null; + } + + /// + /// Checks if a surfaceline has all characteristic point types required to describe + /// a dike. + /// + /// Surfaceline to be checked. + /// True if there are characteristic points defined that describe a dike; + /// False otherwise. + public static bool HasDike(this SurfaceLine2 line) + { + return IsDefined(line, CharacteristicPointType.DikeToeAtRiver) && + IsDefined(line, CharacteristicPointType.DikeTopAtRiver) && + IsDefined(line, CharacteristicPointType.DikeTopAtPolder) && + IsDefined(line, CharacteristicPointType.DikeToeAtPolder); + } + + /// + /// Add 2D characteristic point without a type + /// + /// The surfaceline to be modified. + /// The x. + /// The z. + public static void EnsurePoint(this SurfaceLine2 line, double x, double z) + { + line.EnsurePointOfType(x, z, null); + } + + /// + /// Add characteristic point in X-Z plane + /// + /// The surfaceline to be modified. + /// The x. + /// The z. + /// The type. + public static void EnsurePointOfType(this SurfaceLine2 line, double x, double z, CharacteristicPointType? type) + { + if (!line.CharacteristicPoints.GeometryMustContainPoint) + { + throw new NotImplementedException("SurfaceLine specific method, not implemented for 'Ringtoets'-mode."); + } + + bool movedPointToMatch = false; + bool addPoint = false; + Point2D point = null; + var newPoint = new Point2D() + { + X = x, + Z = z + }; + GeometryPoint gp = null; + if (type.HasValue) + { + // Get point of this type.. + gp = line.CharacteristicPoints.GetGeometryPoint(type.Value); + if (gp != null) + { + point = new Point2D(gp.X, gp.Z); + // Characteristic point annotation set, check location... + if (point.LocationEquals(newPoint)) + { + // Annotated point is at given location; We're done here! :) + return; + } + else + { + bool isAssignedToOtherCharacteristicPoints = + line.GetCharacteristicPoints(gp).Count(cpt => cpt != CharacteristicPointType.None) > 1; + if (isAssignedToOtherCharacteristicPoints) + { + // Other characteristic points exist with the same coordinates so add as new point + point = line.Geometry.GetPointAt(newPoint.X, newPoint.Z); // Get point at specified coords + if (point == null) + { + point = newPoint; + addPoint = true; + } + } + else + { + // Point is unique as characteristic point so set its coords to specified coords + point.X = x; + point.Z = z; + movedPointToMatch = true; + } + gp.X = point.X; + gp.Z = point.Z; + } + } + } + if (point == null) + { + point = line.Geometry.GetPointAt(x, z); // Get point at specified coords + } + if (point == null) + { + point = new Point2D() + { + X = x, + Z = z + }; + addPoint = true; + } + if (addPoint) + { + var newgp = new GeometryPoint(point.X, point.Z); + line.Geometry.Points.Add(newgp); + line.AddCharacteristicPoint(newgp, type ?? CharacteristicPointType.None); + } + else if (type.HasValue && !movedPointToMatch) + { + if (line.CharacteristicPoints.Any(cp => ReferenceEquals(cp.GeometryPoint, gp) && + cp.CharacteristicPointType != CharacteristicPointType.None)) + { + line.AddCharacteristicPoint(gp, type.Value); + } + else + { + int index = -1; + for (int i = 0; i < line.CharacteristicPoints.Count; i++) + { + if (ReferenceEquals(line.CharacteristicPoints[i].GeometryPoint, gp)) + { + index = i; + break; + } + } + line.CharacteristicPoints.Annotate(index, type.Value); + } + } + } + + /// + /// Removes the points between the two x values. The start and end points will + /// not be removed. + /// + /// Surfaceline being modified. + /// The non-inclusive starting X-coordinate. + /// The non-inclusive ending X-coordinate. + /// + public static void RemoveSegmentBetween(this SurfaceLine2 line, double startX, double endX) + { + RemoveGeometryPointsInRange(line, startX, endX, false); + } + + /// + /// Removes the points between the two x values. + /// + /// Surfaceline being modified. + /// The inclusive starting X-Coordinate. + /// The inclusive ending X-Coordinate. + /// + public static void RemoveSegmentIncluding(this SurfaceLine2 line, double startX, double endX) + { + RemoveGeometryPointsInRange(line, startX, endX, true); + } + + /// + /// Removes the points between the two x values. + /// + /// Surfaceline being modified. + /// The starting X-Coordinate. + /// The ending X-Coordinate. + /// Indicates if and + /// are inclusive bounds or not. + private static void RemoveGeometryPointsInRange(SurfaceLine2 line, double startX, double endX, bool isInclusiveRange) + { + foreach (var geometryPoint in GetGeometryPointsWithinRange(line, startX, endX, isInclusiveRange).ToArray()) + { + var characteristicPoints = line.CharacteristicPoints.Where(cp => ReferenceEquals(cp.GeometryPoint, geometryPoint)).ToArray(); + if (characteristicPoints.Length > 0) + { + // CharacteristicPointSet will manage both collections of CharacteristicPoint instances and Geometry + foreach (var characteristicPoint in characteristicPoints) + { + line.CharacteristicPoints.Remove(characteristicPoint); + } + } + else + { + // Notify change such that CharacteristicPointSet instances observing this + // geometry can update if required. + line.Geometry.Points.Remove(geometryPoint); + } + } + } + + /// + /// Retrieve all instances of a surfaceline that + /// fall with the range. + /// + /// Surfaceline being evaluated. + /// Starting X-coordinate. + /// Ending X-coordinate. + /// Indicates if and + /// are inclusive bounds or not. + /// Collection of characteristic points within the given range. + private static IEnumerable GetGeometryPointsWithinRange(SurfaceLine2 line, + double startX, double endX, bool isInclusiveRange) + { + if (isInclusiveRange) + { + return line.Geometry.Points.Where(cp => (cp.X >= startX || cp.X.AlmostEquals(startX, GeometryPoint.Precision)) && + (cp.X <= endX || cp.X.AlmostEquals(endX, GeometryPoint.Precision))); + } + return line.Geometry.Points.Where(cp => cp.X > startX && cp.X < endX); + } + + /// + /// Checks if a surfaceline has all characteristic point types required to describe + /// an inside shoulder. + /// + /// Surfaceline to be checked. + /// True if there are characteristic points defined that described the + /// inside shoulder; False otherwise. + public static bool HasShoulderInside(this SurfaceLine2 line) + { + return IsDefined(line, CharacteristicPointType.ShoulderTopInside) && + IsDefined(line, CharacteristicPointType.ShoulderBaseInside); + } + + /// + /// Checks if a surfaceline has all characteristic point types required to describe + /// a ditch. + /// + /// Surfaceline to be checked. + /// True if there are characteristic points defined that described the + /// ditch; False otherwise. + public static bool HasDitch(this SurfaceLine2 line) + { + return IsDefined(line, CharacteristicPointType.DitchDikeSide) && + IsDefined(line, CharacteristicPointType.DitchPolderSide); + } + + /// + /// Determines whether ditch is correct. + /// + /// true if ditch is correct, otherwise false + /// This methods checks if the following points have their X cooridnates + /// properly defined: + /// + /// + /// + /// + /// + /// + /// + public static bool IsDitchCorrect(this SurfaceLine2 line) + { + // No ditch then always ok + bool res = !line.HasDitch(); + if (!res) + { + // check the unchecked points + var bottomDitchDikeSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide); + var bottomDitchPolderSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide); + res = (bottomDitchDikeSide != null && bottomDitchPolderSide != null); + + // check the ditch points describe following shape: + // 0 0 + // \ / + // 0---0 + var ditchPolderSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); + var ditchDikeSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); + if (res) + { + res = ditchPolderSide.X >= bottomDitchPolderSide.X && + bottomDitchPolderSide.X >= bottomDitchDikeSide.X && + bottomDitchDikeSide.X >= ditchDikeSide.X && + bottomDitchDikeSide.Z <= ditchDikeSide.Z && + bottomDitchPolderSide.Z <= ditchPolderSide.Z; + } + } + return res; + } + + /// + /// Gets the starting point of the surface line. + /// + /// Starting point, or null if none of the considered points can be found. + /// + /// Method looks for the following characteristic points (in this order) and returns + /// the corresponding geometry point if present: + /// + /// + /// + /// + /// + /// + public static GeometryPoint GetStartingPoint(this SurfaceLine2 line) + { + return line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseOutside) ?? + line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopOutside) ?? + line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver); + } + + /// + /// Gets the default height of the dike table. + /// + /// null or height of table + public static double? GetDefaultDikeTableHeight(this SurfaceLine2 line) + { + // Consulted Erik Vastenburg about this: Use buitenkruinlijn as default DTH + GeometryPoint point = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + return point == null ? null : (double?)point.Z; + } + + /// + /// Make sure river level is above the bottom of the river. + /// + /// The evaluated surfaceline. + /// The current river level. + /// Bottom of the river if bottomlevel is above riverLevel, else + /// is required to have the characteristic point + /// when + /// is not null. + /// + public static double? EnsureWaterLevelIsAboveRiverBottom(this SurfaceLine2 line, double? riverLevel) + { + // Waterlevel is supposed to be at level of SurfaceLevelOutside when waterlevel + // is below SurfaceLevelOutside (is the bottom of the river) + if (riverLevel.HasValue) + { + double z = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).Z; + riverLevel = Math.Max(z, riverLevel.Value); + } + return riverLevel; + } + + /// + /// Determines the intersection of a horizontal line with the surfaceline, starting + /// from to . + /// + /// The surfaceline being evaluated. + /// The height of the horizontal line. + /// The GeometryPoint at the intersection, or null if no intersection can + /// be found. + /// + /// Requires that the following characteristic points are defined: + /// + /// + /// + /// + /// + /// This method draws the horizontal line starting from the smallest X available + /// in the geometry to . + /// + /// When greater than + /// the height of the characteristic point . + /// + public static GeometryPoint DetermineIntersectionWithLevel(this SurfaceLine2 line, double level) + { + double startXCoordinate = line.Geometry.GetMinX(); + var waterlevelLine = GetWaterlevelLineStartingFrom(line, level, startXCoordinate); + + return DetermineIntersectionWithHorizontalLevel(line, waterlevelLine); + } + + /// + /// Create a horizontal line from a given starting X coordinate and ending at the + /// X coordinate of defined + /// in the surfaceline. + /// + /// The referenced surfaceline. + /// The height level of the horizontal line. + /// The starting coordinate. + /// The line segment. + private static Line GetWaterlevelLineStartingFrom(SurfaceLine2 line, double level, double startXCoordinate) + { + GeometryPoint pointEndOfprofile = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside); + var waterlevelLine = new Line(); + waterlevelLine.CreateHorizontalZLine(startXCoordinate, pointEndOfprofile.X, level); + + return waterlevelLine; + } + + /// + /// Finds the intersection point of a given horizontal line and the river side talud. + /// + /// The evaluated surfaceline. + /// The horizontal line. + /// The intersection point, or null in case no intersection was found. + /// When height of the horizontal line is + /// greater than the height of the characteristic point . + private static GeometryPoint DetermineIntersectionWithHorizontalLevel(SurfaceLine2 line, Line waterlevelLine) + { + ThrowWhenLevelAboveDike(line, waterlevelLine.BeginPoint.Z); + + var list = line.Geometry.Points.Where(point => + point.X >= line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).X && + point.X <= line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X).ToList(); + + for (int i = 1; i < list.Count; i++) + { + var surfaceLineSegment = new Line(); + surfaceLineSegment.SetBeginAndEndPoints( + new Point2D(list[i - 1].X, list[i - 1].Z), + new Point2D(list[i].X, list[i].Z)); + + var intersectPoint = surfaceLineSegment.GetIntersectPointXz(waterlevelLine); + if (intersectPoint != null) + { + return new GeometryPoint(intersectPoint.X, intersectPoint.Z); + } + } + + return null; + } + + /// + /// Throw an in case the given height level is + /// higher than the characteristic point . + /// + private static void ThrowWhenLevelAboveDike(SurfaceLine2 line, double Level) + { + var dikeTopAtRiver = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + if (Level > dikeTopAtRiver.Z) + { + throw new SurfaceLineException(String.Format( + "Level ({0:F2} m) should NOT be higher than surface line ({1:F2}))", + Level, dikeTopAtRiver.Z)); + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilList.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilList.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilList.cs (revision 334) @@ -0,0 +1,138 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Holds the soils and provides some handy methods for them + /// + public class SoilList + { + private Dictionary aquiferDictionary = new Dictionary(); + private List soils; + + public SoilList() + { + soils = new List(); + } + + /// + /// Gets or sets the soils. + /// + /// + /// The soils. + /// + [Validate] + public virtual List Soils + { + get + { + return soils; + } + set + { + soils = value; + } + } + + /// + /// Gets or sets the aquifer dictionary. + /// This dictionary is used for the backward compatibility issue when aquifers still were part of + /// soil instead of the layer as it is now. + /// + /// + /// The aquifer dictionary. + /// + public Dictionary AquiferDictionary + { + get + { + return aquiferDictionary; + } + set + { + aquiferDictionary = value; + } + } + + /// + /// Gets the index of the soil by its name. + /// + /// Name of the soil. + /// The index when found else -1 + public virtual int GetSoilIndexByName(string soilName) + { + var soil = soils.FirstOrDefault(s => s.Name.Equals( + soilName, StringComparison.InvariantCultureIgnoreCase)); + + return soil == null ? -1 : soils.IndexOf(soil); + } + + /// + /// Gets the soil by its name. + /// + /// Name of the soil. + /// Soil when found else null + public virtual Soil GetSoilByName(string soilName) + { + var soil = soils.FirstOrDefault(s => s.Name.Equals( + soilName, StringComparison.InvariantCultureIgnoreCase)); + + return soil; + } + + /// + /// Adds the specified soil. + /// + /// The soil. + public void Add(Soil soil) + { + Soils.Add(soil); + } + + /// + /// Removes the specified soil. + /// + /// The soil. + public void Remove(Soil soil) + { + Soils.Remove(soil); + if (aquiferDictionary.ContainsKey(soil)) + { + aquiferDictionary.Remove(soil); + } + } + + /// + /// Clears this instance (soils and AquiferDictionary). + /// + public void Clear() + { + Soils.Clear(); + aquiferDictionary.Clear(); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/MStabParameters.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/MStabParameters.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/MStabParameters.cs (revision 334) @@ -0,0 +1,621 @@ +// Copyright (C) Stichting Deltares 2017. 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.ComponentModel; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + public enum TangentLinesDefinition + { + OnBoundaryLines = 0, + Specified = 1 + } + + public enum GridSizeDetermination + { + Automatic = 0, + Specified = 1 + } + + public class SheetPiling : IAssignable, ICloneable + { + public double XCoordinate { get; set; } + public double YCoordinate { get; set; } + public double ZCoordinate { get; set; } + public double Length { get; set; } + + public void Assign(SheetPiling sheetPiling) + { + this.XCoordinate = sheetPiling.XCoordinate; + this.YCoordinate = sheetPiling.YCoordinate; + this.ZCoordinate = sheetPiling.ZCoordinate; + this.Length = sheetPiling.Length; + } + + public SheetPiling Clone() + { + var sheetPiling = new SheetPiling(); + sheetPiling.Assign(this); + return sheetPiling; + } + } + + public class HorizontalBalanceArea : IAssignable, ICloneable + { + public double XLeft { get; set; } + public double XRight { get; set; } + public double YTop { get; set; } + public double YBottom { get; set; } + public int PlaneCount { get; set; } + public void Assign(HorizontalBalanceArea horizontalBalanceArea) + { + this.XLeft = horizontalBalanceArea.XLeft; + this.XRight = horizontalBalanceArea.XRight; + this.YTop = horizontalBalanceArea.YTop; + this.YBottom = horizontalBalanceArea.YBottom; + this.PlaneCount = horizontalBalanceArea.PlaneCount; + } + + public HorizontalBalanceArea Clone() + { + var horizontalBalanceArea = new HorizontalBalanceArea(); + horizontalBalanceArea.Assign(this); + return horizontalBalanceArea; + } + } + + public class SlipCircleDefinition : IAssignable, ICloneable + { + private double xCoordinateLastUpliftPoint; + private int upliftVanLeftGridVerticalPointCount; + private double upliftVanTangentLinesDistance; + private double bishopTangentLinesDistance; + private double upliftVanLeftGridVerticalPointDistance; + private int upliftVanLeftGridHorizontalPointCount; + private double upliftVanLeftGridHorizontalPointDistance; + private int upliftVanRightGridVerticalPointCount; + private double upliftVanRightGridVerticalPointDistance; + private int upliftVanRightGridHorizontalPointCount; + private double upliftVanRightGridHorizontalPointDistance; + private int bishopGridHorizontalPointCount; + private double bishopGridHorizontalPointDistance; + private int bishopGridVerticalPointCount; + private double bishopGridVerticalPointDistance; + + public double XCoordinateLastUpliftPoint + { + get + { + return xCoordinateLastUpliftPoint; + } + set + { + xCoordinateLastUpliftPoint = value; + } + } + public TangentLinesDefinition UpliftVanTangentLinesDefinition { get; set; } + + public double UpliftVanTangentLinesDistance + { + get + { + return upliftVanTangentLinesDistance; + } + set + { + upliftVanTangentLinesDistance = value; + } + } + public TangentLinesDefinition BishopTangentLinesDefinition { get; set; } + + public double BishopTangentLinesDistance + { + get + { + return bishopTangentLinesDistance; + } + set + { + bishopTangentLinesDistance = value; + } + } + public GridSizeDetermination GridSizeDetermination { get; set; } + + public int UpliftVanLeftGridVerticalPointCount + { + get + { + return upliftVanLeftGridVerticalPointCount; + } + set + { + upliftVanLeftGridVerticalPointCount = value; + } + } + + public double UpliftVanLeftGridVerticalPointDistance + { + get + { + return upliftVanLeftGridVerticalPointDistance; + } + set + { + upliftVanLeftGridVerticalPointDistance = value; + } + } + + public int UpliftVanLeftGridHorizontalPointCount + { + get + { + return upliftVanLeftGridHorizontalPointCount; + } + set + { + upliftVanLeftGridHorizontalPointCount = value; + } + } + + public double UpliftVanLeftGridHorizontalPointDistance + { + get + { + return upliftVanLeftGridHorizontalPointDistance; + } + set + { + upliftVanLeftGridHorizontalPointDistance = value; + } + } + + public int UpliftVanRightGridVerticalPointCount + { + get + { + return upliftVanRightGridVerticalPointCount; + } + set + { + upliftVanRightGridVerticalPointCount = value; + } + } + + public double UpliftVanRightGridVerticalPointDistance + { + get + { + return upliftVanRightGridVerticalPointDistance; + } + set + { + upliftVanRightGridVerticalPointDistance = value; + } + } + + public int UpliftVanRightGridHorizontalPointCount + { + get + { + return upliftVanRightGridHorizontalPointCount; + } + set + { + upliftVanRightGridHorizontalPointCount = value; + } + } + + public double UpliftVanRightGridHorizontalPointDistance + { + get + { + return upliftVanRightGridHorizontalPointDistance; + } + set + { + upliftVanRightGridHorizontalPointDistance = value; + } + } + + public int BishopGridVerticalPointCount + { + get + { + return bishopGridVerticalPointCount; + } + set + { + bishopGridVerticalPointCount = value; + } + } + + public double BishopGridVerticalPointDistance + { + get + { + return bishopGridVerticalPointDistance; + } + set + { + bishopGridVerticalPointDistance = value; + } + } + + public int BishopGridHorizontalPointCount + { + get + { + return bishopGridHorizontalPointCount; + } + set + { + bishopGridHorizontalPointCount = value; + } + } + + public double BishopGridHorizontalPointDistance + { + get + { + return bishopGridHorizontalPointDistance; + } + set + { + bishopGridHorizontalPointDistance = value; + } + } + + public DamFailureMechanismeCalculationSpecification Specification { get; set; } + + public void Assign(SlipCircleDefinition slipCircleDefinition) + { + this.XCoordinateLastUpliftPoint = slipCircleDefinition.XCoordinateLastUpliftPoint; + this.UpliftVanTangentLinesDefinition = slipCircleDefinition.UpliftVanTangentLinesDefinition; + this.UpliftVanTangentLinesDistance = slipCircleDefinition.UpliftVanTangentLinesDistance; + this.BishopTangentLinesDefinition = slipCircleDefinition.BishopTangentLinesDefinition; + this.BishopTangentLinesDistance = slipCircleDefinition.BishopTangentLinesDistance; + this.GridSizeDetermination = slipCircleDefinition.GridSizeDetermination; + this.UpliftVanLeftGridVerticalPointCount = slipCircleDefinition.UpliftVanLeftGridVerticalPointCount; + this.UpliftVanLeftGridVerticalPointDistance = slipCircleDefinition.UpliftVanLeftGridVerticalPointDistance; + this.UpliftVanLeftGridHorizontalPointCount = slipCircleDefinition.UpliftVanLeftGridHorizontalPointCount; + this.UpliftVanLeftGridHorizontalPointDistance = slipCircleDefinition.UpliftVanLeftGridHorizontalPointDistance; + this.UpliftVanRightGridVerticalPointCount = slipCircleDefinition.UpliftVanRightGridVerticalPointCount; + this.UpliftVanRightGridVerticalPointDistance = slipCircleDefinition.UpliftVanRightGridVerticalPointDistance; + this.UpliftVanRightGridHorizontalPointCount = slipCircleDefinition.UpliftVanRightGridHorizontalPointCount; + this.UpliftVanRightGridHorizontalPointDistance = slipCircleDefinition.UpliftVanRightGridHorizontalPointDistance; + this.BishopGridVerticalPointCount = slipCircleDefinition.BishopGridVerticalPointCount; + this.BishopGridVerticalPointDistance = slipCircleDefinition.BishopGridVerticalPointDistance; + this.BishopGridHorizontalPointCount = slipCircleDefinition.BishopGridHorizontalPointCount; + this.BishopGridHorizontalPointDistance = slipCircleDefinition.BishopGridHorizontalPointDistance; + } + + public SlipCircleDefinition Clone() + { + var slipCircleDefinition = new SlipCircleDefinition(); + slipCircleDefinition.Assign(this); + return slipCircleDefinition; + } + } + + public class MStabZoneAreas : IAssignable, ICloneable + { + public double DikeTableHeight { get; set; } + public double DikeTableWidth { get; set; } + public double XCoordinateDikeTopAtRiver { get; set; } + public double XCoordinateDikeTopAtPolder { get; set; } + public double XCoordinateStartRestProfile { get; set; } + public double SafetyFactorZone1A { get; set; } + public double SafetyFactorZone1B { get; set; } + public void Assign(MStabZoneAreas mstabZoneAreas) + { + this.DikeTableHeight = mstabZoneAreas.DikeTableHeight; + this.DikeTableWidth = mstabZoneAreas.DikeTableWidth; + this.XCoordinateDikeTopAtRiver = mstabZoneAreas.XCoordinateDikeTopAtRiver; + this.XCoordinateDikeTopAtPolder = mstabZoneAreas.XCoordinateDikeTopAtPolder; + this.XCoordinateStartRestProfile = mstabZoneAreas.XCoordinateStartRestProfile; + this.SafetyFactorZone1A = mstabZoneAreas.SafetyFactorZone1A; + this.SafetyFactorZone1B = mstabZoneAreas.SafetyFactorZone1B; + } + + public MStabZoneAreas Clone() + { + var mstabZoneAreas = new MStabZoneAreas(); + mstabZoneAreas.Assign(this); + return mstabZoneAreas; + } + } + + public class MStabForbiddenZone : IAssignable, ICloneable + { + public bool IsXEntryMinUsed { get; set; } + public bool IsXEntryMaxUsed { get; set; } + public double XEntryMin { get; set; } + public double XEntryMax { get; set; } + public void Assign(MStabForbiddenZone mstabForbiddenZone) + { + this.IsXEntryMinUsed = mstabForbiddenZone.IsXEntryMinUsed; + this.IsXEntryMaxUsed = mstabForbiddenZone.IsXEntryMaxUsed; + this.XEntryMin = mstabForbiddenZone.XEntryMin; + this.XEntryMax = mstabForbiddenZone.XEntryMax; + } + + public MStabForbiddenZone Clone() + { + var mstabForbiddenZone = new MStabForbiddenZone(); + mstabForbiddenZone.Assign(this); + return mstabForbiddenZone; + } + } + + public class MStabDesignEmbankment : IAssignable, ICloneable + { + public string EmbankmentMaterialname { get; set; } + public string PreviousGeometry2DFilename { get; set; } + public void Assign(MStabDesignEmbankment mstabDesignEmbankment) + { + this.EmbankmentMaterialname = mstabDesignEmbankment.EmbankmentMaterialname; + this.PreviousGeometry2DFilename = mstabDesignEmbankment.PreviousGeometry2DFilename; + } + + public MStabDesignEmbankment Clone() + { + var mstabDesignEmbankment = new MStabDesignEmbankment(); + mstabDesignEmbankment.Assign(this); + return mstabDesignEmbankment; + } + } + + public class MStabGeometryCreationOptions : IAssignable, ICloneable + { + public MStabGeometryCreationOptions() + { + SoilGeometryType = SoilGeometryType.SoilGeometry1D; + SoilGeometry2DFilename = ""; + XOffsetSoilGeometry2DOrigin = 0.0; + MaterialForDike = ""; + MaterialForShoulder = ""; + IsUseOriginalPLLineAssignments = false; + IsUseOriginalCalculationOptions = false; + IsDrySituation = false; + PLLineAssignment = PLLineAssignment.ExpertKnowledge; + IntrusionVerticalWaterPressureType = IntrusionVerticalWaterPressureType.Standard; + PenetrationLength = 0.0; + IsDesign = false; + } + public SoilGeometryType SoilGeometryType { get; set; } + public string SoilGeometry2DFilename { get; set; } + public double XOffsetSoilGeometry2DOrigin { get; set; } + public string MaterialForDike { get; set; } + public string MaterialForShoulder { get; set; } + public bool IsUseOriginalPLLineAssignments { get; set; } + public bool IsUseOriginalCalculationOptions { get; set; } + public bool IsDrySituation { get; set; } + public PLLineAssignment PLLineAssignment { get; set; } + public IntrusionVerticalWaterPressureType IntrusionVerticalWaterPressureType { get; set; } + public double PenetrationLength { get; set; } + public bool IsDesign { get; set; } + + public void Assign(MStabGeometryCreationOptions mstabGeometryCreationOptions) + { + this.SoilGeometryType = mstabGeometryCreationOptions.SoilGeometryType; + this.SoilGeometry2DFilename = mstabGeometryCreationOptions.SoilGeometry2DFilename; + this.XOffsetSoilGeometry2DOrigin = mstabGeometryCreationOptions.XOffsetSoilGeometry2DOrigin; + this.MaterialForDike = mstabGeometryCreationOptions.MaterialForDike; + this.MaterialForShoulder = mstabGeometryCreationOptions.MaterialForShoulder; + this.IsUseOriginalPLLineAssignments = mstabGeometryCreationOptions.IsUseOriginalPLLineAssignments; + this.IsUseOriginalCalculationOptions = mstabGeometryCreationOptions.IsUseOriginalCalculationOptions; + this.IsDrySituation = mstabGeometryCreationOptions.IsDrySituation; + this.PLLineAssignment = mstabGeometryCreationOptions.PLLineAssignment; + this.IntrusionVerticalWaterPressureType = mstabGeometryCreationOptions.IntrusionVerticalWaterPressureType; + this.PenetrationLength = mstabGeometryCreationOptions.PenetrationLength; + this.IsDesign = mstabGeometryCreationOptions.IsDesign; + } + + public MStabGeometryCreationOptions Clone() + { + var mstabGeometryCreationOptions = new MStabGeometryCreationOptions(); + mstabGeometryCreationOptions.Assign(this); + return mstabGeometryCreationOptions; + } + } + + public class MStabCalculationOptions : IAssignable, ICloneable + { + public double MinimalCircleDepth { get; set; } + + public MStabZonesType ZonesType { get; set; } + + public void Assign(MStabCalculationOptions mstabCalculationOptions) + { + this.MinimalCircleDepth = mstabCalculationOptions.MinimalCircleDepth; + this.ZonesType = mstabCalculationOptions.ZonesType; + } + + public MStabCalculationOptions Clone() + { + var mstabCalculationOptions = new MStabCalculationOptions(); + mstabCalculationOptions.Assign(this); + return mstabCalculationOptions; + } + } + + public class MStabParameters : ICloneable + { + private MStabGridPosition gridPosition; + + public MStabParameters() + { + this.IsCalculateAllStabilityProjectsAtOnce = true; + this.IsOverrulePLLineCreationMethod = false; + this.PLLineCreationMethod = PLLineCreationMethod.ExpertKnowledgeRRD; + this.Model = MStabModelType.Bishop; + this.SearchMethod = MStabSearchMethod.Grid; + this.ZoneAreas = null; + this.gridPosition = MStabGridPosition.Right; + this.CalculationOptions = new MStabCalculationOptions(); + this.GeometryCreationOptions = new MStabGeometryCreationOptions(); + this.SheetPiling = null; + this.HorizontalBalanceArea = new HorizontalBalanceArea(); + this.SlipCircleDefinition = new SlipCircleDefinition(); + } + + public bool IsCombinedBishopUpliftVanCalculation { get { return (Model == MStabModelType.BishopUpliftVan); } } + // IsCombinedBishopUpliftVanCalculation (formerly IsAutoSelectCalculation) is the same as Model == MStabModel.BishopUpliftVan + // This property was first implemented for FewsDam and later MStabModel.BishopUpliftVan was implemented for normal DAM operation + // Now we will use Model == MStabModel.BishopUpliftVan for both FewsDam and DAM + // This readonly property is implemented for backward compatibiity + + public bool IsCalculateAllStabilityProjectsAtOnce { get; set; } + // Normally PLLine creation is specified per location. + // If IsOverrulePLLineCreationMethod is set to true the settings in the locations will be + // overruled with the value in PLLineCreationMethod + public bool IsOverrulePLLineCreationMethod { get; set; } + public PLLineCreationMethod PLLineCreationMethod { get; set; } + + public MStabModelType Model { get; set; } + + public MStabShearStrength ShearStrength { get; set; } + + public MStabSearchMethod SearchMethod { get; set; } + public bool IsProbabilistic { get; set; } + public string ProjectFileName { get; set; } + public string SoilDatabaseName { get; set; } + public MStabZoneAreas ZoneAreas { get; set; } + public MStabForbiddenZone ForbiddenZone { get; set; } + public MStabGeometryCreationOptions GeometryCreationOptions { get; set; } + public SheetPiling SheetPiling { get; set; } + public HorizontalBalanceArea HorizontalBalanceArea { get; set; } + + [Validate] + public SlipCircleDefinition SlipCircleDefinition { get; set; } + public MStabCalculationOptions CalculationOptions { get; set; } + + public MStabGridPosition GridPosition + { + get { return gridPosition; } + set + { + gridPosition = value; + } + } + + public void Assign(MStabParameters mstabParameters) + { + this.Model = mstabParameters.Model; + this.ShearStrength = mstabParameters.ShearStrength; + this.SearchMethod = mstabParameters.SearchMethod; + this.IsProbabilistic = mstabParameters.IsProbabilistic; + this.GridPosition = mstabParameters.GridPosition; + this.ProjectFileName = mstabParameters.ProjectFileName; + this.SoilDatabaseName = mstabParameters.SoilDatabaseName; + if (this.ZoneAreas != null) + { + this.ZoneAreas.Assign(mstabParameters.ZoneAreas); + } + else + { + this.ZoneAreas = null; + } + if (this.ForbiddenZone != null) + { + this.ForbiddenZone.Assign(mstabParameters.ForbiddenZone); + } + else + { + this.ForbiddenZone = null; + } + if (this.CalculationOptions != null) + { + this.CalculationOptions.Assign(mstabParameters.CalculationOptions); + } + else + { + this.CalculationOptions = null; + } + if (this.GeometryCreationOptions != null) + { + this.GeometryCreationOptions.Assign(mstabParameters.GeometryCreationOptions); + } + else + { + this.GeometryCreationOptions = null; + } + if (this.SheetPiling != null) + { + this.SheetPiling.Assign(mstabParameters.SheetPiling); + } + else + { + this.SheetPiling = null; + } + if (this.HorizontalBalanceArea != null) + { + this.HorizontalBalanceArea.Assign(mstabParameters.HorizontalBalanceArea); + } + else + { + this.HorizontalBalanceArea = null; + } + this.SoilDatabaseName = mstabParameters.SoilDatabaseName; + if (this.SlipCircleDefinition != null) + { + this.SlipCircleDefinition.Assign(mstabParameters.SlipCircleDefinition); + } + else + { + this.SlipCircleDefinition = null; + } + } + + [XmlIgnore] + public MStabZonesType ZonesType + { + get { return this.CalculationOptions.ZonesType; } + set { this.CalculationOptions.ZonesType = value; } + } + + public MStabParameters Clone() + { + var mstabParameters = new MStabParameters(); + if (this.ZoneAreas != null) + mstabParameters.ZoneAreas = this.ZoneAreas.Clone(); + if (this.ForbiddenZone != null) + mstabParameters.ForbiddenZone = this.ForbiddenZone.Clone(); + if (this.GeometryCreationOptions != null) + mstabParameters.GeometryCreationOptions = this.GeometryCreationOptions.Clone(); + if (this.SheetPiling != null) + mstabParameters.SheetPiling = this.SheetPiling.Clone(); + if (this.HorizontalBalanceArea != null) + mstabParameters.HorizontalBalanceArea = this.HorizontalBalanceArea.Clone(); + if (this.SlipCircleDefinition != null) + mstabParameters.SlipCircleDefinition = this.SlipCircleDefinition.Clone(); + if (this.CalculationOptions != null) + mstabParameters.CalculationOptions = this.CalculationOptions.Clone(); + + mstabParameters.Assign(this); + + return mstabParameters; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Routines2D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Routines2D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/Routines2D.cs (revision 334) @@ -0,0 +1,623 @@ +// Copyright (C) Stichting Deltares 2017. 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; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Type of intersection + /// + public enum LineIntersection + { + /// + /// The no intersection + /// + NoIntersection = 0, + /// + /// The intersects + /// + Intersects = 1, + /// + /// The parallel + /// + Parallel = 2 + } + + /// + /// Position of point towards polygon + /// + public enum PointInPolygon + { + /// + /// The inside polygon + /// + InsidePolygon = 0, + /// + /// The on polygon edge + /// + OnPolygonEdge = 1, + /// + /// The outside polygon + /// + OutsidePolygon = 2 + } + + /// + /// Static class Routines2D + /// + public static class Routines2D + { + public struct LineConstant + { + public double X; + public double Y; + public double Z; + } + + private const double cEpsilon = 1.0e-4; + + /// + /// Checks if the 2D Lines strictly intersect. Strictly means that the intersection point must be part of both lines so + /// extrapolated points do not count. + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// The point3 x. + /// The point3 z. + /// The point4 x. + /// The point4 z. + /// The intersection point. + /// + /// Intersection status as well as the intersection point (when found, else null) + /// + /// + /// For connected paralllel lines, the connection point will be returned as valid intersection point. + /// + public static LineIntersection DetermineIf2DLinesIntersectStrickly(double point1X, double point1Z, double point2X, double point2Z, + double point3X, double point3Z, double point4X, double point4Z, out Point2D intersectionPoint) + { + return DetermineIf2DLinesIntersectStrickly(point1X, point1Z, point2X, point2Z, point3X, point3Z, point4X, point4Z, + out intersectionPoint, cEpsilon); + } + + + /// + /// Doeses the point exist in line. + /// + /// The line point1 x. + /// The line point1 z. + /// The line point2 x. + /// The line point2 z. + /// The point x. + /// The point z. + /// The tolerance. + /// + public static bool DoesPointExistInLine(double linePoint1X, double linePoint1Z, double linePoint2X, double linePoint2Z, + double pointX, double pointZ, double tolerance) + { + // Function to find if lies on or close to a line (within a given tolerance) + // Input - a line defined by lTwo points, a third point to test and tolerance aValue + // Output - TRUE or FALSE + + // first check whether the points are identical + if (Math.Abs(linePoint1X - linePoint2X) < tolerance && Math.Abs(linePoint1Z - linePoint2Z) < tolerance) + { + return Compute2DDistance(pointX, pointZ, linePoint1X, linePoint1Z) < tolerance; + } + + // then check if point is within the bounding rectangle formed by 2 line points + var maxX = Math.Max(linePoint1X, linePoint2X); + var minX = Math.Min(linePoint1X, linePoint2X); + var maxY = Math.Max(linePoint1Z, linePoint2Z); + var minY = Math.Min(linePoint1Z, linePoint2Z); + + minX -= tolerance; + minY -= tolerance; + maxX += tolerance; + maxY += tolerance; + + var x3 = pointX; + var y3 = pointZ; + + if (!(x3 > minX && x3 < maxX && y3 > minY && y3 < maxY)) + { + return false; + } + + // check if perpendicular distance between point and line is within tolerance + var a = linePoint1Z - linePoint2Z; + var b = linePoint2X - linePoint1X; + var c = -((a * linePoint1X) + (b * linePoint1Z)); + var distance = ((a * x3) + (b * y3) + c) / Compute2DDistance(linePoint1X, linePoint1Z, linePoint2X, linePoint2Z); + + return Math.Abs(distance) < tolerance; + } + + private static void UndoAddIfNeeded(GeometryLoop polygon, bool needed) + { + if (needed) + { + polygon.CalcPoints.Remove(polygon.CalcPoints[polygon.CalcPoints.Count - 1]); + } + } + + /// + /// Find if points Ax,ay are between a boundary polygon. + /// + /// The polygon. + /// The x. + /// The z. + /// + public static PointInPolygon CheckIfPointIsInPolygon(GeometryLoop polygon, double x, double z) + { + // This is done by calculating and adding the angles from the point to all points + // of the polygon (using the ArcTan2 function). If the sum of these angles is + // aproximate zero the point lies outside the polygon. + // If the sum in aproximate + or - 2Pi the point lies in the polygon; + // Performance tests have proven that this algorithm performs better than the + // polynomial winding number algorithm described at: + // http://geomalgorithms.com/a03-_inclusion.html + + const double epsilon = 1e-10; + var result = PointInPolygon.OutsidePolygon; + + // add the last point at the end, cos the polygon must be closed, so the last node equals the first + var pointAdded = false; + if (polygon.CalcPoints.Count > 0) + { + if (!polygon.CalcPoints[0].LocationEquals(polygon.CalcPoints[polygon.CalcPoints.Count - 1])) + { + polygon.CalcPoints.Add(polygon.CalcPoints[0]); + pointAdded = true; + } + } + + var polygonPoints = polygon.CalcPoints.Count; + if (polygonPoints > 2) + { + var deltaX = polygon[0].X - x; + var deltaZ = polygon[0].Z - z; + var absX = Math.Abs(deltaX); + var absZ = Math.Abs(deltaZ); + if ((absX < epsilon) && (absZ < epsilon)) + { + UndoAddIfNeeded(polygon, pointAdded); + return PointInPolygon.OnPolygonEdge; + } + + var al1 = Math.Atan2(deltaZ, deltaX); + double som = 0; + var index = 1; + + while (index < polygonPoints) + { + deltaX = polygon[index].X - x; + deltaZ = polygon[index].Z - z; + absX = Math.Abs(deltaX); + absZ = Math.Abs(deltaZ); + if ((absX < epsilon) && (absZ < epsilon)) + { + UndoAddIfNeeded(polygon, pointAdded); + return PointInPolygon.OnPolygonEdge; + } + var al2 = Math.Atan2(deltaZ, deltaX); + var al3 = al2 - al1; + + if (al3 < -Math.PI) + { + al3 = al3 + (2.0*Math.PI); + } + if (al3 > Math.PI) + { + al3 = al3 - (2.0*Math.PI); + } + if (((Math.PI - al3) < epsilon) || ((Math.PI + al3) < epsilon)) + { + UndoAddIfNeeded(polygon, pointAdded); + return PointInPolygon.OnPolygonEdge; + } + som = som + al3; + al1 = al2; + index++; + } + + if ((som > (1.9*Math.PI)) || (som < (-1.9*Math.PI))) + { + result = PointInPolygon.InsidePolygon; + } + else + { + result = PointInPolygon.OutsidePolygon; + } + } + UndoAddIfNeeded(polygon, pointAdded); + return result; + } + + /// + /// Intersection of Circle and line + /// + /// + /// + /// + /// + /// + /// + /// + public static List IntersectCircleline(double aX, double aY, double aR, double aX1, double aX2, double aY1, double aY2) + { + // Solve by filling in parametric equation of line : + // X = x1 + u*(x2 - x1) + // Y = y1 + u*(y2 - y1) + // Compare it to that of a cricle: + // (X - xm)^2 + (Y - ym)^2 = r^2 + // And check solve for parameter u in a quadratic equation. + // - no solutions => no intersections + // - one or two solutions => intersection when -eps <= u <= 1+eps. + // If (x1,y1) close to circle edge, return (x1,y1). + + const double lAbcEps = 1E-8; + var lX1 = aX2 - aX1; + var lX2 = aX1 - aX; + var lY1 = aY2 - aY1; + var lY2 = aY1 - aY; + var result = new List(); + if ((Math.Abs(lX1) > lAbcEps) || (Math.Abs(lY1) > lAbcEps)) + { + var lA = lX1*lX1 + lY1*lY1; + var lB = 2*(lX1*lX2 + lY1*lY2); + var lC = lX2*lX2 + lY2*lY2 - aR*aR; + var lD = lB*lB - 4*lA*lC; + + if (lD > lAbcEps) + { + var lU = (-lB + Math.Sqrt(lD))/(2*lA); + if ((lU >= -lAbcEps) && (lU <= (1.0 + lAbcEps))) + { + result.Add(new Point2D{ X= aX1 + lU*lX1, Z = aY1 + lU*lY1}); + } + lU = (-lB - Math.Sqrt(lD))/(2*lA); + + if ((lU >= -lAbcEps) && (lU <= (1.0 + lAbcEps))) + { + result.Add(new Point2D{ X = aX1 + lU*lX1, Z = aY1 + lU*lY1}); + } + } + else if (Math.Abs(lD) <= lAbcEps) + { + var lU = (-lB)/(2*lA); + if ((lU >= -lAbcEps) && (lU <= 1.0 + lAbcEps)) + { + result.Add(new Point2D { X = aX1 + lU*lX1, Z = aY1 + lU*lY1}); + } + } + } + else if (Math.Abs(Math.Pow(lX2, 2) + Math.Pow(lY2, 2) - Math.Pow(aR, 2)) < lAbcEps) + { + result.Add(new Point2D() {X = aX1, Z = aY1}); + } + return result; + } + + + /// + /// Checks if values are equal + /// + /// + /// + /// + /// + public static bool AreEqual(double x1, double x2, double tolerance) + { + return (Math.Abs(x1 - x2) < tolerance); + } + + /// + /// Takes the cross product of two vectors + /// + /// X-coordinate of the first point + /// Y-coordinate of the first point + /// X-coordinate of the second point + /// Y-coordinate of the second point + /// + private static double CrossProduct(double pointAx, double pointAy, double pointBx, double pointBy) + { + return pointAx*pointBy - pointBx*pointAy; + } + + /// + /// Description: Finds the Normal. FPoint1 and FPoint2 are the line coordinates + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// + private static LineConstant CalculateNormalLineConstants(double point1X, double point1Z, double point2X, double point2Z) + { + var lLineConstant = new LineConstant + { + X = point2Z - point1Z, + Y = -(point2X - point1X), + Z = (point2Z - point1Z) * point1X - (point2X - point1X) * point1Z + }; + + return lLineConstant; + } + + /// + /// Checks if lTwo lines are parallel. The Normal Line Constants are required. + /// + /// a line1 constant x. + /// a line1 constant y. + /// a line2 constant x. + /// a line2 constant y. + /// The tolerance. + /// + private static bool AreLinesParallel(double aLine1ConstantX, double aLine1ConstantY, double aLine2ConstantX, double aLine2ConstantY, double tolerance) + { + return Math.Abs(CrossProduct(aLine1ConstantX, aLine2ConstantX, aLine1ConstantY, aLine2ConstantY)) < tolerance; + } + + + public static LineIntersection DetermineIf2DLinesIntersectWithExtrapolation(Point2D aPoint1, Point2D aPoint2, Point2D aPoint3, Point2D aPoint4, ref Point2D aIntersectionPoint) + { + var lLineConstant1 = CalculateNormalLineConstants(aPoint1.X, aPoint1.Z, aPoint2.X, aPoint2.Z); + var lLineConstant2 = CalculateNormalLineConstants(aPoint3.X, aPoint3.Z, aPoint4.X, aPoint4.Z); + + var lResult = DetermineIf2DLinesIntersectWithExtrapolation(lLineConstant1, lLineConstant2, out aIntersectionPoint); + + return lResult; + } + + /// + /// Finds the Intersection Points for two given 2D Lines. + /// The intersection point does not need to be on either given line, extrapolation is used to find it beyond the length of the given lines. + /// Note that parallel lines never return an intersection point, not even when there two parallel lines are neatly connected. + /// + /// + /// + /// + /// + public static LineIntersection DetermineIf2DLinesIntersectWithExtrapolation(LineConstant aLine1Constant, LineConstant aLine2Constant, out Point2D aIntersectionPoint) + { + aIntersectionPoint = new Point2D(0.0, 0.0); + + var lA1 = aLine1Constant.X; + var lB1 = aLine1Constant.Y; + var lC1 = aLine1Constant.Z; + var lA2 = aLine2Constant.X; + var lB2 = aLine2Constant.Y; + var lC2 = aLine2Constant.Z; + + if (AreLinesParallel(lA1, lA2, lB1, lB2, cEpsilon)) + { + aIntersectionPoint = null; + return LineIntersection.Parallel; + } + + var lX = (lB2*lC1 - lB1*lC2)/(lA1*lB2 - lA2*lB1); + var lY = (lC1*lA2 - lC2*lA1)/(lA2*lB1 - lA1*lB2); + + aIntersectionPoint.X = lX; + aIntersectionPoint.Z = lY; + + return LineIntersection.Intersects; + } + + /// + /// Calculates the Euclidean distance between two points on a 2-dimensional plane + /// + /// X-coordinate of the first point + /// Y-coordinate of the first point + /// X-coordinate of the second point + /// Y-coordinate of the second point + /// The distance between the given points. + private static double Compute2DDistance(double aX1, double aY1, double aX2, double aY2) + { + var lX = aX1 - aX2; + var lY = aY1 - aY2; + + return Math.Sqrt(lX * lX + lY * lY); + } + + /// + /// Checks if the 2D Lines strictly intersect. Strictly means that the intersection point must be part of both lines so + /// extrapolated points do not count. + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// The point3 x. + /// The point3 zx. + /// The point4 x. + /// The point4 z. + /// The intersection point. + /// Non-inclusive maximum allowed distance between two possibly intersecting endpoints of the lines + /// + /// Intersection status as well as the intersection point (when found, else null) + /// + /// + /// For connected paralllel lines, the connection point will be returned as valid intersection point. + /// + private static LineIntersection DetermineIf2DLinesIntersectStrickly(double point1X, double point1Z, double point2X, double point2Z, + double point3X, double point3Z, double point4X, double point4Z, out Point2D intersectionPoint, double tolerance) + { + var lineConstant1 = CalculateNormalLineConstants(point1X, point1Z, point2X, point2Z); + var lineConstant2 = CalculateNormalLineConstants(point3X, point3Z, point4X, point4Z); + + var result = DetermineIf2DLinesIntersectWithExtrapolation(lineConstant1, lineConstant2, out intersectionPoint); + + if (result == LineIntersection.Intersects) + { + //check if lies on the line and is not somewhere outside ! + if ((DoesPointExistInLine(point1X, point1Z, point2X, point2Z, intersectionPoint.X, intersectionPoint.Z, tolerance) && + DoesPointExistInLine(point3X, point3Z, point4X, point4Z, intersectionPoint.X, intersectionPoint.Z, tolerance)) == false) + { + intersectionPoint = null; + result = LineIntersection.NoIntersection; + } + } + else + { + if (result == LineIntersection.Parallel && !DoLinesAtLeastPartialyOverlap(point1X, point1Z, point2X, point2Z, point3X, point3Z, + point4X, point4Z, tolerance)) + { + if (DetermineIfPointsCoincide(point1X, point1Z, point3X, point3Z, tolerance) || + DetermineIfPointsCoincide(point1X, point1Z, point4X, point4Z, tolerance)) + { + intersectionPoint = new Point2D(point1X, point1Z); + result = LineIntersection.Intersects; + } + if (DetermineIfPointsCoincide(point2X, point2Z, point3X, point3Z, tolerance) || + DetermineIfPointsCoincide(point2X, point2Z, point4X, point4Z, tolerance)) + { + intersectionPoint = new Point2D(point2X, point2Z); + result = LineIntersection.Intersects; + } + } + } + return result; + } + + /// + /// Determines whether the given lines at least partialy overlap. + /// Note that purely connected parallel lines are NOT considered to be overlapping. + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// The point3 x. + /// The point3 z. + /// The point4 x. + /// The point4 z. + /// The tolerance. + /// + private static bool DoLinesAtLeastPartialyOverlap(double point1X, double point1Z, double point2X, double point2Z, + double point3X, double point3Z, double point4X, double point4Z, double tolerance) + { + var result = AreLinesParallel(point1X, point1Z, point2X, point2Z, point3X, point3Z, point4X, point4Z, tolerance); + + // lines not parallel so can not overlap + if (!result) + { + return false; + } + + if (Math.Abs(point1X - point2X) < double.Epsilon) + { + // lines are vertical so check Y values + var max12 = Math.Max(point1Z, point2Z); + var min12 = Math.Min(point1Z, point2Z); + var max34 = Math.Max(point3Z, point4Z); + var min34 = Math.Min(point3Z, point4Z); + // When max of point1/point2 does not exceed min of point3/point4 lines do not overlap + // When max of point3/point4 does not exceed min of point1/point2 lines do not overlap + if (max12 <= min34 || min12 >= max34) + { + result = false; + } + } + else + { + // lines are not vertical so check X values + var max12 = Math.Max(point1X, point2X); + var min12 = Math.Min(point1X, point2X); + var max34 = Math.Max(point3X, point4X); + var min34 = Math.Min(point3X, point4X); + if (max12 <= min34 || min12 >= max34) + { + result = false; + } + } + return result; + } + + /// + /// Description: Checks if two lines are parallel within the given tolerance + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// The point3 x. + /// The point3 z. + /// The point4 x. + /// The point4 z. + /// The tolerance. + /// + /// True when parallel + /// + private static bool AreLinesParallel(double point1X, double point1Z, double point2X, double point2Z, + double point3X, double point3Z, double point4X, double point4Z, double tolerance) + { + + double aX = point2X - point1X; + double aY = point2Z - point1Z; + + double bX = point4X - point3X; + double bY = point4Z - point3Z; + + Normalize(ref aX, ref aY); + Normalize(ref bX, ref bY); + return AreLinesParallel(aX, aY, bX, bY, tolerance); + } + + /// + /// Normalizes this instance. + /// + private static void Normalize(ref double pointX, ref double pointY) + { + double q = Math.Sqrt(pointX * pointX + pointY * pointY); + + if (q != 0) + { + pointX = pointX / q; + pointY = pointY / q; + } + } + + /// + /// Checks if the points coincide + /// + /// The point1 x. + /// The point1 z. + /// The point2 x. + /// The point2 z. + /// The tolerance. + /// + private static bool DetermineIfPointsCoincide(double point1X, double point1Z, double point2X, double point2Z, double tolerance) + { + if ((Math.Abs(point1X - point2X)) < tolerance && Math.Abs(point1Z - point2Z) < tolerance) + { + return true; + } + + return false; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/LocationResult.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/LocationResult.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/LocationResult.cs (revision 334) @@ -0,0 +1,74 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.General.TimeSeries; +using Deltares.DamEngine.Data.RWScenarios; + +namespace Deltares.DamEngine.Data.General.Results +{ + public class LocationResult + { + private TimeSerie stabilityTimeSerie = new TimeSerie(); + private TimeSerie pipingTimeSerie = new TimeSerie(); + private RWScenariosResult rwScenariosResult = null; + private RWSchematizationFactorsResult schematizationFactorsResult = null; + + public LocationResult() + { + } + + public virtual TimeSerie StabilityTimeSerie + { + get { return stabilityTimeSerie; } + set + { + stabilityTimeSerie = value; + } + } + + public TimeSerie PipingTimeSerie + { + get { return pipingTimeSerie; } + set + { + pipingTimeSerie = value; + } + } + + public virtual RWScenariosResult RWScenariosResult + { + get { return rwScenariosResult; } + set + { + rwScenariosResult = value; + } + } + + public RWSchematizationFactorsResult SchematizationFactorsResult + { + get { return schematizationFactorsResult; } + set + { + schematizationFactorsResult = value; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorData.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorData.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorData.cs (revision 334) @@ -0,0 +1,111 @@ +// Copyright (C) Stichting Deltares 2017. 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; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + /// + /// Class to hold the collected sensor data + /// + public class SensorData + { + private List sensors = new List(); + private List sensorGroups = new List(); + private List sensorLocations = new List(); + + /// + /// Updates the pick sensors for groups. + /// + public void UpdatePickSensorsForGroups() + { + foreach (var sensorGroup in sensorGroups) + { + sensorGroup.PickSensors = sensors; + } + } + + /// + /// Gets or sets the sensors. + /// + /// + /// The sensors. + /// + public List Sensors + { + get { return sensors; } + set { sensors = value; } + } + + /// + /// Gets or sets the sensor groups. + /// + /// + /// The sensor groups. + /// + public List SensorGroups + { + get { return sensorGroups; } + set { sensorGroups = value; } + } + + /// + /// Gets or sets the sensor locations. + /// + /// + /// The sensor locations. + /// + public List SensorLocations + { + get { return sensorLocations; } + } + + public Sensor GetSensorById(int id) + { + return sensors.FirstOrDefault(sensor => sensor.ID == id); + } + + public Group GetGroupById(int id) + { + return sensorGroups.FirstOrDefault(sensorGroup => sensorGroup.ID == id); + } + + public SensorLocation GetSensorLocationByLocationName(string name) + { + return sensorLocations.FirstOrDefault(sensorLocation => sensorLocation.LocationName == name); + } + + /// + /// Gets the groups for use in selection lists in de UI. + /// + /// The sensoLocation. + /// + public IEnumerable GetGroups(SensorLocation sensorLocation) + { + var list = new List(); + list.AddRange(sensorGroups); + return list; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Design/CsvExportData.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Design/CsvExportData.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Design/CsvExportData.cs (revision 334) @@ -0,0 +1,1907 @@ +// Copyright (C) Stichting Deltares 2017. 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.Diagnostics; +using System.IO; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Data.Design +{ + /// + ///1:"Id":invoer + ///2:"Dijkringnaam":invoer + ///3:"RDX":invoer + ///4:"RDY":invoer + ///5:"Scenarionummer (waterhoogtenummer, hoeveelste \"entry\" uit tabel; 1, 2, 3, 4 of 5)":invoer + ///6:"Waterhoogtewaarde":invoer + ///7:"Dijkhoogte bestaand":invoer + ///8:"Huidige locatie teen":invoer + ///9:"Dijktafelhoogte":invoer + ///10:"1Dprofiel":invoer + ///11:"Mechanisme":invoer + ///12:"1Dprofiel kans":invoer + ///13:"Berekende lokatie teen":uitvoer + ///14:"Bermhoogte":uitvoer + ///15:"Dijkbasis bestaand":invoer + ///16:"Dijkbasis nieuw":uitvoer + /// + public class CsvExportData : ICloneable + { + private string id; + private string baseFileName; + private string calculationSubDir; + private Dike dike; + private AnalysisType analysisType; + private ProbabilisticType probabilisticType; + private DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification; + private Scenario scenario; + private SoilProfile1D soilProfile; + private string soilGeometry2DName; + private double? safetyFactorFlowSlide; + private double? failureProbabilityPiping; + private double? localPipingExitPointX; + private SurfaceLine2 redesignedSurfaceLinePiping; + private double? safetyFactorStability; + private double? failureProbabilityStability; + private double? zone1SafetyFactorStability; + private double? localZone1EntryPointX; + private double? localZone1ExitPointX; + private double? zone2SafetyFactorStability; + private double? localZone2EntryPointX; + private double? localZone2ExitPointX; + private double? upliftFactor; + private double? heaveFactor; + private double? blighPipingFactor; + private double? blighHCritical; + private double? sellmeijer2ForcesPipingFactor; + private double? sellmeijer2ForcesHCritical; + private double? sellmeijer4ForcesPipingFactor; + private double? sellmeijer4ForcesHCritical; + private double? sellmeijerPipingFactor; + private double? sellmeijerHCritical; + private double? wti2017PipingFactor; + private double? wti2017HCritical; + private bool? isUplift; + private double? pl3MinUplift; + private double? pl3HeadAdjusted; + private double? pl3LocalLocationXMinUplift; + private double? pl4MinUplift; + private double? pl4HeadAdjusted; + private double? pl4LocalLocationXMinUplift; + private readonly string nwoId; + private readonly int nwoResultIndex; + private double? locationXrdStart; + private double? locationYrdStart; + private readonly double? locationZrdStart; + private double? locationXrdEnd; + private double? locationYrdEnd; + private readonly double? locationZrdEnd; + private CalculationResult calculationResult = CalculationResult.NoRun; + private string resultMessage = ""; + private int numberOfIterations; + private ResultEvaluation resultEvaluation = ResultEvaluation.NotEvaluated; + private string notes = ""; + private bool dirty = true; + private List points = new List(); + private StabilityKernelType selectedStabilityKernelType = StabilityKernelType.DamClassic; + private SurfaceLine2 redesignedSurfaceLineStability; + + public CsvExportData() + { + } + + public CsvExportData(string id, Dike dike, DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification, Scenario scenario, SoilProfile1D soilProfile, + string soilGeometry2DName, AnalysisType analysisType, int nwoResultIndex, ProbabilisticType probabilisticType) + { + this.id = id; + this.BaseFileName = ""; + this.CalculationSubDir = ""; + this.dike = dike; + this.damFailureMechanismeCalculationSpecification = damFailureMechanismeCalculationSpecification; + this.scenario = scenario; + this.soilProfile = soilProfile; + this.SoilGeometry2DName = soilGeometry2DName; + this.analysisType = analysisType; + this.failureProbabilityPiping = null; + this.redesignedSurfaceLinePiping = null; + this.safetyFactorStability = null; + this.failureProbabilityStability = null; + this.redesignedSurfaceLineStability = null; + this.zone1SafetyFactorStability = null; + this.LocalZone1EntryPointX = null; + this.LocalZone1ExitPointX = null; + this.zone2SafetyFactorStability = null; + this.LocalZone2EntryPointX = null; + this.LocalZone2ExitPointX = null; + this.blighPipingFactor = null; + this.blighHCritical = null; + this.sellmeijer2ForcesPipingFactor = null; + this.sellmeijer2ForcesHCritical = null; + this.sellmeijer4ForcesPipingFactor = null; + this.sellmeijer4ForcesHCritical = null; + this.sellmeijerPipingFactor = null; + this.sellmeijerHCritical = null; + this.wti2017PipingFactor = null; + this.wti2017HCritical = null; + this.isUplift = null; + this.pl3MinUplift = null; + this.pl3HeadAdjusted = null; + this.pl3LocalLocationXMinUplift = null; + this.pl4MinUplift = null; + this.pl4HeadAdjusted = null; + this.pl4LocalLocationXMinUplift = null; + this.nwoId = ""; + this.nwoResultIndex = nwoResultIndex; + this.locationXrdStart = null; + this.locationXrdEnd = null; + this.locationYrdStart = null; + this.locationYrdEnd = null; + this.locationZrdStart = null; + this.locationZrdEnd = null; + this.dirty = true; + + if (damFailureMechanismeCalculationSpecification != null) + { + this.probabilisticType = probabilisticType; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + case FailureMechanismSystemType.StabilityOutside: + + if (analysisType == AnalysisType.AdaptNWO) + { + // an index of 0 can also indicate an error message. That has no futher data so check if there actualy is any. + if (scenario.NwoResults.Count > 0) + { + this.nwoId = scenario.NwoResults[nwoResultIndex].NwoId; + this.locationXrdStart = scenario.NwoResults[nwoResultIndex].LocationXrdStart; + this.locationYrdStart = scenario.NwoResults[nwoResultIndex].LocationYrdStart; + this.locationZrdStart = scenario.NwoResults[nwoResultIndex].LocationZrdStart; + this.locationXrdEnd = scenario.NwoResults[nwoResultIndex].LocationXrdEnd; + this.locationYrdEnd = scenario.NwoResults[nwoResultIndex].LocationYrdEnd; + this.locationZrdEnd = scenario.NwoResults[nwoResultIndex].LocationZrdEnd; + this.dirty = true; + this.BaseFileName = scenario.NwoResults[nwoResultIndex].MStabResults.CalculationName; + this.CalculationSubDir = + scenario.NwoResults[nwoResultIndex].MStabResults.CalculationSubDir; + this.numberOfIterations = + scenario.NwoResults[nwoResultIndex].MStabResults.IterationNumber; + this.safetyFactorStability = scenario.NwoResults[nwoResultIndex].MStabResults.zone1.safetyFactor; + this.zone1SafetyFactorStability = scenario.NwoResults[nwoResultIndex].MStabResults.zone1.safetyFactor; + this.LocalZone1EntryPointX = scenario.NwoResults[nwoResultIndex].MStabResults.zone1.entryPointXCoordinate; + this.LocalZone1ExitPointX = scenario.NwoResults[nwoResultIndex].MStabResults.zone1.exitPointXCoordinate; + if (scenario.NwoResults[nwoResultIndex].MStabResults.zone2 != null) + { + this.zone2SafetyFactorStability = scenario.NwoResults[nwoResultIndex].MStabResults.zone2.Value.safetyFactor; + this.LocalZone2EntryPointX = scenario.NwoResults[nwoResultIndex].MStabResults.zone2.Value.entryPointXCoordinate; + this.LocalZone2ExitPointX = scenario.NwoResults[nwoResultIndex].MStabResults.zone2.Value.exitPointXCoordinate; + } + } + } + else + { + MStabResults? mstabResults = scenario.GetMStabResults(this.SoilProfile, this.SoilGeometry2DName); + this.resultMessage = scenario.GetResultMessage(this.SoilProfile, this.SoilGeometry2DName); + calculationResult = DetermineStabilityCalculationResult(this.resultMessage, mstabResults); + if (mstabResults != null) + { + + BaseFileName = mstabResults.Value.CalculationName; + CalculationSubDir = mstabResults.Value.CalculationSubDir; + numberOfIterations = mstabResults.Value.IterationNumber; + this.safetyFactorStability = mstabResults.Value.zone1.safetyFactor; + this.zone1SafetyFactorStability = mstabResults.Value.zone1.safetyFactor; + this.LocalZone1EntryPointX = mstabResults.Value.zone1.entryPointXCoordinate; + this.LocalZone1ExitPointX = mstabResults.Value.zone1.exitPointXCoordinate; + if (mstabResults.Value.zone2 != null) + { + this.zone2SafetyFactorStability = mstabResults.Value.zone2.Value.safetyFactor; + this.LocalZone2EntryPointX = mstabResults.Value.zone2.Value.entryPointXCoordinate; + this.LocalZone2ExitPointX = mstabResults.Value.zone2.Value.exitPointXCoordinate; + } + } + } + this.failureProbabilityStability = scenario.GetFailureProbabilityStability(this.SoilProfile, this.SoilGeometry2DName); + this.redesignedSurfaceLineStability = scenario.GetRedesignedSurfaceLine(this.SoilProfile, this.SoilGeometry2DName); + + UpliftSituation? upliftSituation = scenario.GetStabilityUpliftSituation(this.SoilProfile, this.SoilGeometry2DName); + if (upliftSituation != null) + { + SetUpliftSituationResults(upliftSituation.Value); + } + + break; + + case FailureMechanismSystemType.Piping: + + this.failureProbabilityPiping = scenario.GetFailureProbabilityPiping(this.SoilProfile, this.SoilGeometry2DName); + this.resultMessage = scenario.GetResultMessage(this.SoilProfile, this.SoilGeometry2DName); + this.redesignedSurfaceLinePiping = scenario.GetRedesignedSurfaceLine(this.SoilProfile, this.SoilGeometry2DName); + UpliftSituation? upliftSituationPiping = scenario.GetStabilityUpliftSituation(this.SoilProfile, this.SoilGeometry2DName); + if (upliftSituationPiping != null) + { + SetUpliftSituationResults(upliftSituationPiping.Value); + } + PipingResults? pipingResults = scenario.GetPipingResults(this.SoilProfile, this.SoilGeometry2DName); + if (pipingResults != null) + { + BaseFileName = pipingResults.Value.CalculationName; + CalculationSubDir = pipingResults.Value.CalculationSubDir; + this.blighPipingFactor = pipingResults.Value.BlighPipingFactor; + this.blighHCritical = pipingResults.Value.BlighHCritical; + this.sellmeijer2ForcesPipingFactor = pipingResults.Value.Sellmeijer2ForcesPipingFactor; + this.sellmeijer2ForcesHCritical = pipingResults.Value.Sellmeijer2ForcesHCritical; + this.sellmeijer4ForcesPipingFactor = pipingResults.Value.Sellmeijer4ForcesPipingFactor; + this.sellmeijer4ForcesHCritical = pipingResults.Value.Sellmeijer4ForcesHCritical; + this.sellmeijerPipingFactor = pipingResults.Value.SellmeijerPipingFactor; + this.sellmeijerHCritical = pipingResults.Value.SellmeijerHCritical; + this.wti2017PipingFactor = pipingResults.Value.Wti2017PipingFactor; + this.wti2017HCritical = pipingResults.Value.Wti2017HCritical; + this.localPipingExitPointX = pipingResults.Value.PipingExitPointX; + this.HeaveFactor = pipingResults.Value.HeaveFactor; + this.UpliftFactor = pipingResults.Value.UpliftFactor; + } + this.calculationResult = (this.PipingFactor == null && this.PipingFailureProbability == null) ? CalculationResult.RunFailed : CalculationResult.Succeeded; + break; + case FailureMechanismSystemType.FlowSlide: + this.safetyFactorFlowSlide = scenario.GetSafetyFactorFlowSlide(this.SoilProfile, this.SoilGeometry2DName); + break; + } + } + } + + /// + /// Determines the global point coordinates based on global surface line. + /// + /// The local point. + /// The global surface line. + /// + private GeometryPoint DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine(GeometryPoint localPoint, SurfaceLine2 globalSurfaceLine) + { + CoordinateSystemConverter coordinateSystemConverter = new CoordinateSystemConverter(); + coordinateSystemConverter.DefineGlobalXYZBasedOnLine(globalSurfaceLine.Geometry); + + coordinateSystemConverter.ConvertLocalXZToGlobalXYZ(localPoint); + return localPoint; + } + + /// + /// Determines the stability calculation run result. + /// + /// The result message. + /// The mstab results. + /// + private CalculationResult DetermineStabilityCalculationResult(string message, MStabResults? mstabResults) + { + CalculationResult result; + if ((message != null) && this.resultMessage.Contains("FAIL")) + { + result = CalculationResult.UnexpectedError; + } + else + { + // If no failure and no results, then no run has been made + result = mstabResults != null ? CalculationResult.Succeeded : CalculationResult.NoRun; + } + return result; + } + + /// + /// Sets the uplift situation results. + /// + /// The uplift situation. + private void SetUpliftSituationResults(UpliftSituation upliftSituation) + { + this.isUplift = upliftSituation.IsUplift; + if (upliftSituation.Pl3MinUplift < double.MaxValue) + { + this.pl3MinUplift = upliftSituation.Pl3MinUplift; + } + if (upliftSituation.Pl3HeadAdjusted < double.MaxValue) + { + this.pl3HeadAdjusted = upliftSituation.Pl3HeadAdjusted; + } + if (upliftSituation.Pl3LocationXMinUplift < double.MaxValue) + { + this.pl3LocalLocationXMinUplift = upliftSituation.Pl3LocationXMinUplift; + } + if (upliftSituation.Pl4MinUplift < double.MaxValue) + { + this.pl4MinUplift = upliftSituation.Pl4MinUplift; + } + if (upliftSituation.Pl4HeadAdjusted < double.MaxValue) + { + this.pl4HeadAdjusted = upliftSituation.Pl4HeadAdjusted; + } + if (upliftSituation.Pl4LocationXMinUplift < double.MaxValue) + { + this.pl4LocalLocationXMinUplift = upliftSituation.Pl4LocationXMinUplift; + } + } + + public StabilityKernelType SelectedStabilityKernelType + { + get { return selectedStabilityKernelType; } + set { selectedStabilityKernelType = value; } + } + + public int NumberOfIterations + { + get { return numberOfIterations; } + set { numberOfIterations = value; } + } + + public string ResultFile + { + get + { + if (!String.IsNullOrEmpty(BaseFileName)) + { + const string wmfExtension = ".wmf"; + string fullBaseFilename = DamProjectData.ProjectWorkingPath; + if (CalculationSubDir != "") + { + fullBaseFilename = Path.Combine(fullBaseFilename, CalculationSubDir); + } + fullBaseFilename = fullBaseFilename + Path.DirectorySeparatorChar + BaseFileName; + string fullFilename = fullBaseFilename + wmfExtension; + if (!File.Exists(fullFilename)) + { + fullFilename = fullBaseFilename + "z1" + wmfExtension; + } + if (!File.Exists(fullFilename)) + { + fullFilename = fullBaseFilename + "z2" + wmfExtension; + } + return fullFilename; + } + return ""; + } + } + + public string InputFile + { + get + { + if (!String.IsNullOrEmpty(BaseFileName)) + { + string fileExtension = ".sti"; + if (selectedStabilityKernelType != StabilityKernelType.DamClassic) + { + fileExtension = ".dsx"; + } + string fullBaseFilename = DamProjectData.ProjectWorkingPath; + if (CalculationSubDir != "") + { + fullBaseFilename = Path.Combine(fullBaseFilename, CalculationSubDir); + } + fullBaseFilename = fullBaseFilename + Path.DirectorySeparatorChar + BaseFileName; + string fullFilename = fullBaseFilename + fileExtension; + return fullFilename; + } + return ""; + } + } + + public string PipingResultFile + { + // Path of piping is not based on the working dir but on assembly (Assembly.GetExecutingAssembly().Location) + get + { + if (!String.IsNullOrEmpty(BaseFileName)) + { + const string txtExtension = ".txt"; + string fullBaseFilename = DamProjectData.ProjectWorkingPath; + if (CalculationSubDir != "") + { + fullBaseFilename = Path.Combine(fullBaseFilename, CalculationSubDir); + } + fullBaseFilename = fullBaseFilename + Path.DirectorySeparatorChar + BaseFileName; + string fullFilename = fullBaseFilename + txtExtension; + return fullFilename; + } + return ""; + } + } + + public AnalysisType AnalysisType + { + get { return analysisType; } + set { analysisType = value; } + } + + public ProbabilisticType ProbabilisticType + { + get { return probabilisticType; } + set { probabilisticType = value; } + } + + [Browsable(false)] + public DamFailureMechanismeCalculationSpecification DamFailureMechanismeCalculation + { + get { return damFailureMechanismeCalculationSpecification; } + set { damFailureMechanismeCalculationSpecification = value; } + } + + public string ID + { + get { return this.id; } + } + + public string DikeName + { + get { return dike.Name; } + } + + public string Calculation + { + get { return this.damFailureMechanismeCalculationSpecification != null ? this.damFailureMechanismeCalculationSpecification.ToString() : ""; } + } + + public string ScenarioName + { + get { return this.Scenario.LocationScenarioID; } + } + + public string LocationName + { + get { return this.Scenario.Location.Name; } + } + + public int LocationScenarioCount + { + get { return this.Scenario.Location.Scenarios.Count; } + } + + public string ScenarioDefinitionName + { + get { return this.Scenario.LocationScenarioID + " of " + this.LocationScenarioCount.ToString(); } + } + + public CalculationResult CalculationResult + { + get + { + return calculationResult; + } + set + { + calculationResult = value; + } + } + + public string ResultMessage + { + get { return resultMessage; } + set { resultMessage = value; } + } + + [XmlIgnore] + public double X + { + get + { + return (this.Scenario != null) ? this.Scenario.Location.XRd : 0.0; + } + set + { + if (this.Scenario != null) + { + this.Scenario.Location.XRd = value; + } + } + } + + [XmlIgnore] + public double Y + { + get + { + return (this.Scenario != null) ? this.Scenario.Location.YRd : 0.0; + } + set + { + if (this.Scenario != null) + { + this.Scenario.Location.YRd = value; + } + } + } + + public string LocationScenarioId + { + get { return this.Scenario.LocationScenarioID; } + } + + public double? RiverLevel + { + get { return this.Scenario.RiverLevel; } + } + + public double? RiverLevelLow + { + get { return this.Scenario.RiverLevelLow; } + } + + public double? DikeTableHeight + { + get { return this.Scenario.DikeTableHeight; } + } + + public double? SlopeDampingPiezometricHeightPolderSide + { + get { return this.Scenario.Location.SlopeDampingPiezometricHeightPolderSide; } + } + + public double? CurrentDikeHeight + { + get { return this.Scenario.Location.SurfaceLine2.GetDikeHeight(); } + } + + public double? CurrentDikeToeAtPolderX + { + get + { + double? x = null; + GeometryPoint point = this.Scenario.Location.SurfaceLine2.GetDikeToeInward(); + if (point != null) + x = point.X; + return x; + } + } + + public double? CurrentDikeToeAtPolderZ + { + get + { + double? z = null; + GeometryPoint point = this.Scenario.Location.SurfaceLine2.GetDikeToeInward(); + if (point != null) + z = point.Z; + return z; + } + } + + private string GetSoilProfileName(FailureMechanismSystemType failureMechanismType) + { + string soilprofilename = ""; + if (this.SoilProfile != null) + { + soilprofilename = this.SoilProfile.Name; + } + else + { + if (this.SoilGeometry2DName != null) + { + soilprofilename = this.SoilGeometry2DName; + } + } + return failureMechanismType == this.damFailureMechanismeCalculationSpecification.FailureMechanismSystemType ? soilprofilename : ""; + } + + private double? GetSoilProfileProbability(FailureMechanismSystemType? failureMechanismType) + { + return this.Scenario.Location.GetSoilProfileProbability(this.SoilProfile, failureMechanismType); + } + + public string StabilityProfileName + { + get { return GetSoilProfileName(FailureMechanismSystemType.StabilityInside); } + } + + public double? StabilityProfileProbability + { + get { return GetSoilProfileProbability(FailureMechanismSystemType.StabilityInside); } + } + + public string PipingProfileName + { + get { return GetSoilProfileName(FailureMechanismSystemType.Piping); } + } + + public double? PipingProfileProbability + { + get { return GetSoilProfileProbability(FailureMechanismSystemType.Piping); } + } + + public double? CurrentDikeLength + { + get { return this.Scenario.Location.SurfaceLine2.GetDikeLength(); } + } + + public double? StabilityToeAtPolderX + { + get + { + if (this.redesignedSurfaceLineStability == null) + return null; + + GeometryPoint point = this.redesignedSurfaceLineStability.GetDikeToeInward(); + if (point != null) + return point.X; + else + return null; + } + } + + public double? StabilityToeAtPolderZ + { + get + { + if (this.redesignedSurfaceLineStability == null) + return null; + + GeometryPoint point = this.redesignedSurfaceLineStability.GetDikeToeInward(); + if (point != null) + return point.Z; + else + return null; + } + } + + public double? StabilityShoulderHeight + { + get + { + if (this.redesignedSurfaceLineStability == null) + return null; + + GeometryPoint point = this.redesignedSurfaceLineStability.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + if (point != null) + return point.Z; + else + return null; + } + } + + public double? StabilitySafetyFactor + { + get { return this.safetyFactorStability; } + set { this.safetyFactorStability = value; } + } + + public double? StabilityFailureProbability + { + get { return this.failureProbabilityStability; } + set { this.failureProbabilityStability = value; } + } + + public double? RequiredSafetyFactorStabilityInnerSlope + { + get { return this.Scenario.RequiredSafetyFactorStabilityInnerSlope;} + } + + public double? RequiredSafetyFactorStabilityOuterSlope + { + get { return this.Scenario.RequiredSafetyFactorStabilityOuterSlope; } + } + + public double? RequiredSafetyFactorPiping + { + get { return this.Scenario.RequiredSafetyFactorPiping; } + } + + public double? PipingToeAtPolderX + { + get + { + if (this.redesignedSurfaceLinePiping == null) + return null; + + GeometryPoint point = this.redesignedSurfaceLinePiping.GetDikeToeInward(); + if (point != null) + return point.X; + else + return null; + } + } + + public double? PipingToeAtPolderZ + { + get + { + if (this.redesignedSurfaceLinePiping == null) + return null; + + GeometryPoint point = this.redesignedSurfaceLinePiping.GetDikeToeInward(); + if (point != null) + return point.Z; + else + return null; + } + } + + public double? PipingShoulderHeight + { + get + { + if (this.redesignedSurfaceLinePiping == null) + return null; + + GeometryPoint point = redesignedSurfaceLinePiping.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + if (point != null) + return point.Z; + else + return null; + } + } + + public double? PipingFailureProbability + { + get { return this.failureProbabilityPiping; } + set { this.failureProbabilityPiping = value; } + } + + public double? RequiredFailureProbabilityPiping + { + get { return this.Scenario.RequiredProbabilityOfFailurePiping; } + } + + public double? DikeLength + { + get + { + double? maxDikeLength = null; + List dikeLengths = new List(); + SurfaceLine2 surfaceLine = this.Scenario.Location.SurfaceLine2; + if (surfaceLine != null) + dikeLengths.Add(surfaceLine.GetDikeLength()); + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + if (redesignedSurfaceLineStability != null) + dikeLengths.Add(redesignedSurfaceLineStability.GetDikeLength()); + break; + case FailureMechanismSystemType.Piping: + if (redesignedSurfaceLinePiping != null) + dikeLengths.Add(redesignedSurfaceLinePiping.GetDikeLength()); + break; + } + + foreach (double? dikeLength in dikeLengths) + { + if (dikeLength.HasValue && (!maxDikeLength.HasValue || maxDikeLength < dikeLength)) + maxDikeLength = dikeLength; + } + return maxDikeLength; + } + } + + public double? Zone1SafetyFactorStability + { + get { return this.zone1SafetyFactorStability; } + set { this.zone1SafetyFactorStability = value; } + } + + public double? LocalZone1EntryPointX + { + get { return localZone1EntryPointX; } + set { localZone1EntryPointX = value; } + } + + [XmlIgnore] + public double? Zone1EntryPointX + { + get + { + if (this.LocalZone1EntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone1EntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + [XmlIgnore] + public double? Zone1EntryPointY + { + get + { + if (this.LocalZone1EntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone1EntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + [XmlIgnore] + public double? Zone1EntryPointZ + { + get + { + if (this.LocalZone1EntryPointX == null) + return null; + if (redesignedSurfaceLineStability == null) + return null; + return this.redesignedSurfaceLineStability.Geometry.GetZatX(this.LocalZone1EntryPointX.Value); + } + } + + public double? LocalZone1ExitPointX + { + get { return localZone1ExitPointX; } + set { localZone1ExitPointX = value; } + } + + public double? Zone1ExitPointX + { + get + { + if (this.LocalZone1ExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone1ExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + public double? Zone1ExitPointY + { + get + { + if (this.LocalZone1ExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone1ExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? Zone1ExitPointZ + { + get + { + if (this.LocalZone1ExitPointX == null) + return null; + if (redesignedSurfaceLineStability == null) + return null; + return this.redesignedSurfaceLineStability.Geometry.GetZatX(this.LocalZone1ExitPointX.Value); + } + } + + public double? Zone2SafetyFactorStability + { + get { return this.zone2SafetyFactorStability; } + set { this.zone2SafetyFactorStability = value; } + } + + public double? LocalZone2EntryPointX + { + get { return localZone2EntryPointX; } + set { localZone2EntryPointX = value; } + } + + public double? Zone2EntryPointX + { + get + { + if (this.LocalZone2EntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone2EntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + + } + } + + public double? Zone2EntryPointY + { + get + { + if (this.LocalZone2EntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone2EntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + + } + } + + public double? Zone2EntryPointZ + { + get + { + if (this.LocalZone2EntryPointX == null) + return null; + if (redesignedSurfaceLineStability == null) + return null; + return this.redesignedSurfaceLineStability.Geometry.GetZatX(this.LocalZone2EntryPointX.Value); + } + } + + public double? LocalZone2ExitPointX + { + get { return localZone2ExitPointX; } + set { localZone2ExitPointX = value; } + } + + public double? Zone2ExitPointX + { + get + { + if (this.LocalZone2ExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone2ExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + public double? Zone2ExitPointY + { + get + { + if (this.LocalZone2ExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalZone2ExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? Zone2ExitPointZ + { + get + { + if (this.LocalZone2ExitPointX == null) + return null; + if (redesignedSurfaceLineStability == null) + return null; + return this.redesignedSurfaceLineStability.Geometry.GetZatX(this.LocalZone2ExitPointX.Value); + } + } + + public bool? IsUplift + { + get { return this.isUplift; } + set { this.isUplift = value; } + } + + public double? Pl3MinUplift + { + get { return this.pl3MinUplift; } + set { this.pl3MinUplift = value; } + } + + public double? Pl3HeadAdjusted + { + get { return this.pl3HeadAdjusted; } + set { this.pl3HeadAdjusted = value; } + } + + public double? Pl3LocalLocationXMinUplift + { + get { return this.pl3LocalLocationXMinUplift; } + set { this.pl3LocalLocationXMinUplift = value; } + } + + [XmlIgnore] + public double? Pl3LocationXMinUplift + { + get + { + if (this.pl3LocalLocationXMinUplift == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.pl3LocalLocationXMinUplift.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + [XmlIgnore] + public double? Pl3LocationYMinUplift + { + get + { + if (this.pl3LocalLocationXMinUplift == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.pl3LocalLocationXMinUplift.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? Pl4MinUplift + { + get { return this.pl4MinUplift; } + set { this.pl4MinUplift = value; } + } + + public double? Pl4HeadAdjusted + { + get { return this.pl4HeadAdjusted; } + set { this.pl4HeadAdjusted = value; } + } + + public double? Pl4LocalLocationXMinUplift + { + get { return this.pl4LocalLocationXMinUplift; } + set { this.pl4LocalLocationXMinUplift = value; } + } + + [XmlIgnore] + public double? Pl4LocationXMinUplift + { + get + { + if (this.pl4LocalLocationXMinUplift == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.pl4LocalLocationXMinUplift.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + [XmlIgnore] + public double? Pl4LocationYMinUplift + { + get + { + if (this.pl4LocalLocationXMinUplift == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.pl4LocalLocationXMinUplift.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? UpliftFactor + { + get { return this.upliftFactor; } + set { this.upliftFactor = value; } + } + + public double? HeaveFactor + { + get { return this.heaveFactor; } + set { this.heaveFactor = value; } + } + + public double? BlighPipingFactor + { + get { return this.blighPipingFactor; } + set { this.blighPipingFactor = value; } + } + + public double? BlighHCritical + { + get { return this.blighHCritical; } + set { this.blighHCritical = value; } + } + + public double? Sellmeijer2ForcesPipingFactor + { + get { return this.sellmeijer2ForcesPipingFactor; } + set { this.sellmeijer2ForcesPipingFactor = value; } + } + + public double? Sellmeijer2ForcesHCritical + { + get { return this.sellmeijer2ForcesHCritical; } + set { this.sellmeijer2ForcesHCritical = value; } + } + + public double? Sellmeijer4ForcesPipingFactor + { + get { return this.sellmeijer4ForcesPipingFactor; } + set { this.sellmeijer4ForcesPipingFactor = value; } + } + + public double? Sellmeijer4ForcesHCritical + { + get { return this.sellmeijer4ForcesHCritical; } + set { this.sellmeijer4ForcesHCritical = value; } + } + + public double? SellmeijerPipingFactor + { + get { return this.sellmeijerPipingFactor; } + set { this.sellmeijerPipingFactor = value; } + } + + public double? SellmeijerHCritical + { + get { return this.sellmeijerHCritical; } + set { this.sellmeijerHCritical = value; } + } + + /// + /// Gets or sets the wti2017 piping factor. + /// + /// + /// The wti2017 piping factor. + /// + public double? Wti2017PipingFactor + { + get { return wti2017PipingFactor; } + set { wti2017PipingFactor = value; } + } + + /// + /// Gets or sets the wti2017 h critical. + /// + /// + /// The wti2017 h critical. + /// + public double? Wti2017HCritical + { + get { return wti2017HCritical; } + set { wti2017HCritical = value; } + } + + public string NwoId { get { return this.nwoId; } } + + public int NwoResultIndex + { + get { return this.nwoResultIndex; } + } + + public double? NWOLocationXrdStart + { + get { return this.locationXrdStart; } + } + + public double? NWOLocationYrdStart + { + get { return this.locationYrdStart; } + } + + public double? NWOLocationZrdStart + { + get { return this.locationZrdStart; } + } + + public double? NWOLocationXrdEnd + { + get { return this.locationXrdEnd; } + } + + public double? NWOLocationYrdEnd + { + get { return this.locationYrdEnd; } + } + + public double? NWOLocationZrdEnd { get { return this.locationZrdEnd; } } + //Note: using SurfaceLine instead of LocalXzSurfaceLine must give the proper RD coors. If this is not the case, error is somewhere else. Do not convert here! + + public double? DikeToeAtRiverXrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; } + } + + public double? DikeToeAtRiverYrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).Y; } + } + + public double? DikeToeAtRiverZrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).Z; } + } + + public double? DikeTopAtRiverXrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; } + } + + public double? DikeTopAtRiverYrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).Y; } + } + + public double? DikeTopAtRiverZrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).Z; } + } + + public double? DikeTopAtPolderXrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; } + } + + public double? DikeTopAtPolderYrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Y; } + } + + public double? DikeTopAtPolderZrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z; } + } + + public double? DikeToeAtPolderXrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; } + } + + public double? DikeToeAtPolderYrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Y; } + } + + public double? DikeToeAtPolderZrd + { + get { return this.Scenario.Location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z; } + } + + public double? FlowSlideSafetyFactor + { + get { return this.safetyFactorFlowSlide; } + set { this.safetyFactorFlowSlide = value; } + } + + public Scenario Scenario + { + get { return scenario; } + set { scenario = value; } + } + + public SoilProfile1D SoilProfile + { + get { return soilProfile; } + set { soilProfile = value; } + } + + public string SoilGeometry2DName + { + get { return soilGeometry2DName; } + set { soilGeometry2DName = value; } + } + + /// + /// Creates a new instance based on + /// with global coordinates instead of local coordinates. + /// + public SurfaceLine2 CreateRedesignedSurfaceLineStabilityGlobal() + { + if (this.RedesignedSurfaceLine2Stability == null) + return null; + + SurfaceLine2 originalSurfaceLine = this.Scenario.Location.SurfaceLine2; + var coordinateSystemConverter = new CoordinateSystemConverter(); + coordinateSystemConverter.DefineGlobalXYZBasedOnLine(originalSurfaceLine.Geometry); + + var redesignedSurfaceLineStabilityGlobal = new SurfaceLine2 + { + CharacteristicPoints = { GeometryMustContainPoint = true }, + Geometry = new GeometryPointString() + }; + redesignedSurfaceLineStabilityGlobal.Assign(this.RedesignedSurfaceLine2Stability); + coordinateSystemConverter.ConvertLocalXZToGlobalXYZ(redesignedSurfaceLineStabilityGlobal.Geometry); + + return redesignedSurfaceLineStabilityGlobal; + } + + public SurfaceLine2 RedesignedSurfaceLine2Stability + { + get { return redesignedSurfaceLineStability; } + set { redesignedSurfaceLineStability = value; } + } + + /// + /// Creates a new instance based on + /// with global coordinates instead of local coordinates. + /// + public SurfaceLine2 CreateRedesignedSurfaceLinePipingGlobal() + { + if (this.RedesignedSurfaceLine2Piping == null) + return null; + + SurfaceLine2 originalSurfaceLine = this.Scenario.Location.SurfaceLine2; + var coordinateSystemConverter = new CoordinateSystemConverter(); + coordinateSystemConverter.DefineGlobalXYZBasedOnLine(originalSurfaceLine.Geometry); + + var redesignedSurfaceLinePipingGlobal = new SurfaceLine2 + { + CharacteristicPoints = { GeometryMustContainPoint = true }, + Geometry = new GeometryPointString() + }; + redesignedSurfaceLinePipingGlobal.Assign(this.RedesignedSurfaceLine2Piping); + coordinateSystemConverter.ConvertLocalXZToGlobalXYZ(redesignedSurfaceLinePipingGlobal.Geometry); + + return redesignedSurfaceLinePipingGlobal; + } + + public SurfaceLine2 RedesignedSurfaceLine2Piping + { + get { return redesignedSurfaceLinePiping; } + set { redesignedSurfaceLinePiping = value; } + } + + [XmlIgnore] + public string ProfileName + { + get + { + var res = ""; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.HorizontalBalance: + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.StabilityInside: + res = StabilityProfileName; + break; + case FailureMechanismSystemType.Piping: + res = PipingProfileName; + break; + } + return res; + } + } + + [XmlIgnore] + public double? ProfileProbability + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.HorizontalBalance: + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.StabilityInside: + res = StabilityProfileProbability; + break; + case FailureMechanismSystemType.Piping: + res = PipingProfileProbability; + break; + } + return res; + } + } + + [XmlIgnore] + public MStabModelType? StabilityModel + { + get + { + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.StabilityInside: + return damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.Model; + default: + return null; + } + } + } + + [XmlIgnore] + public double? SafetyFactor + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.HorizontalBalance: + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.StabilityInside: + res = StabilitySafetyFactor; + break; + case FailureMechanismSystemType.Piping: + res = PipingFactor; + break; + case FailureMechanismSystemType.FlowSlide: + res = FlowSlideSafetyFactor; + break; + } + return res; + } + } + + [XmlIgnore] + public double? FailureProbability + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.HorizontalBalance: + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.StabilityInside: + res = StabilityFailureProbability; + break; + case FailureMechanismSystemType.Piping: + res = PipingFailureProbability; + break; + } + return res; + } + } + + [XmlIgnore] + public double? RequiredFailureProbability + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.Piping: + res = RequiredFailureProbabilityPiping; + break; + } + return res; + } + } + + [XmlIgnore] + public double? RequiredSafetyFactor + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityOutside: + res = RequiredSafetyFactorStabilityOuterSlope; + break; + case FailureMechanismSystemType.StabilityInside: + res = RequiredSafetyFactorStabilityInnerSlope; + break; + case FailureMechanismSystemType.Piping: + res = RequiredSafetyFactorPiping; + break; + } + return res; + } + } + + [XmlIgnore] + public double? ShoulderHeight + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + res = StabilityShoulderHeight; + break; + case FailureMechanismSystemType.Piping: + res = PipingShoulderHeight; + break; + } + return res; + } + } + + [XmlIgnore] + public double? ToeAtPolderX + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + res = StabilityToeAtPolderX; + break; + case FailureMechanismSystemType.Piping: + res = PipingToeAtPolderX; + break; + } + return res; + } + } + + [XmlIgnore] + public double? ToeAtPolderZ + { + get + { + double? res = null; + switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + res = StabilityToeAtPolderZ; + break; + case FailureMechanismSystemType.Piping: + res = PipingToeAtPolderZ; + break; + } + return res; + } + } + + [XmlIgnore] + public PipingModelType? PipingModel + { + get + { + if (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.Piping) + { + return damFailureMechanismeCalculationSpecification.PipingModelType; + } + return null; + } + } + + [XmlIgnore] + public double? PipingFactor + { + get + { + double? res = null; + if (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.Piping) + { + switch (damFailureMechanismeCalculationSpecification.PipingModelType) + { + case PipingModelType.Bligh: + res = BlighPipingFactor; + break; + case PipingModelType.Sellmeijer: + res = SellmeijerPipingFactor; + break; + case PipingModelType.Sellmeijer2Forces: + res = Sellmeijer2ForcesPipingFactor; + break; + case PipingModelType.Sellmeijer4Forces: + res = Sellmeijer4ForcesPipingFactor; + break; + case PipingModelType.Wti2017: + res = Wti2017PipingFactor; + break; + } + } + return res; + } + } + + [XmlIgnore] + public double? LocalPipingEntryPointX + { + get + { + GeometryPoint point = null; + if (this.RedesignedSurfaceLine2Piping != null) + { + point = this.RedesignedSurfaceLine2Piping.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver); + } + else + { + point = this.scenario.Location.LocalXZSurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver); + } + if (point != null) + return point.X; + else + return null; + } + } + + [XmlIgnore] + public double? PipingEntryPointX + { + get + { + if (this.LocalPipingEntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalPipingEntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + [XmlIgnore] + public double? PipingEntryPointY + { + get + { + if (this.LocalPipingEntryPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalPipingEntryPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? LocalPipingExitPointX + { + get { return localPipingExitPointX; } + set { localPipingExitPointX = value; } + } + + [XmlIgnore] + public double? PipingExitPointX + { + get + { + if (this.LocalPipingExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalPipingExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.X; + } + } + + [XmlIgnore] + public double? PipingExitPointY + { + get + { + if (this.LocalPipingExitPointX == null) + return null; + + GeometryPoint point = DetermineGlobalPointCoordinatesBasedOnGlobalSurfaceLine( + new GeometryPoint(this.LocalPipingExitPointX.Value, 0.0), this.Scenario.Location.SurfaceLine2); + + return point.Y; + } + } + + public double? SeepageLength + { + get { return LocalPipingExitPointX - LocalPipingEntryPointX; } + } + + [XmlIgnore] + public double? HCritical + { + get + { + double? res = null; + if (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.Piping) + { + switch (damFailureMechanismeCalculationSpecification.PipingModelType) + { + case PipingModelType.Bligh: + res = BlighHCritical; + break; + case PipingModelType.Sellmeijer: + res = SellmeijerHCritical; + break; + case PipingModelType.Sellmeijer2Forces: + res = Sellmeijer2ForcesHCritical; + break; + case PipingModelType.Sellmeijer4Forces: + res = Sellmeijer4ForcesHCritical; + break; + case PipingModelType.Wti2017: + res = Wti2017HCritical; + break; + } + } + return res; + } + } + + public string BaseFileName + { + get { return baseFileName; } + set { baseFileName = value; } + } + + public string CalculationSubDir + { + get { return calculationSubDir; } + set { calculationSubDir = value; } + } + + public ResultEvaluation ResultEvaluation + { + get { return resultEvaluation; } + set + { + resultEvaluation = value; + } + } + + public string Notes + { + get { return notes; } + set + { + notes = value; + } + } + + /// + /// Returns the begin point and end point as a list + /// + [XmlIgnore] + public List Points + { + get + { + if (dirty) + { + dirty = false; + points.Clear(); + if (this.locationXrdStart.HasValue && this.locationYrdStart.HasValue) + { + points.Add(new GeometryPoint(this.locationXrdStart.Value, this.locationYrdStart.Value)); + } + if (this.locationXrdEnd.HasValue && this.locationYrdEnd.HasValue) + { + points.Add(new GeometryPoint(this.locationXrdEnd.Value, this.locationYrdEnd.Value)); + } + } + + return points; + } + } + + /// + /// Copy data + /// + /// + public void Assign(CsvExportData csvExportData) + { + this.id = csvExportData.id; + this.BaseFileName = csvExportData.BaseFileName; + this.CalculationSubDir = csvExportData.CalculationSubDir; + this.NumberOfIterations = csvExportData.NumberOfIterations; + this.dike = csvExportData.dike; + this.damFailureMechanismeCalculationSpecification = csvExportData.damFailureMechanismeCalculationSpecification; + this.Scenario = csvExportData.Scenario; + this.SoilProfile = csvExportData.SoilProfile; + this.SoilGeometry2DName = csvExportData.SoilGeometry2DName; + this.probabilisticType = csvExportData.ProbabilisticType; + + this.failureProbabilityPiping = csvExportData.failureProbabilityPiping; + this.redesignedSurfaceLinePiping = csvExportData.redesignedSurfaceLinePiping; + this.safetyFactorStability = csvExportData.safetyFactorStability; + this.failureProbabilityStability = csvExportData.failureProbabilityStability; + this.zone1SafetyFactorStability = csvExportData.zone1SafetyFactorStability; + this.LocalZone1EntryPointX = csvExportData.LocalZone1EntryPointX; + this.LocalZone1ExitPointX = csvExportData.LocalZone1ExitPointX; + this.zone2SafetyFactorStability = csvExportData.zone2SafetyFactorStability; + this.LocalZone2EntryPointX = csvExportData.LocalZone2EntryPointX; + this.LocalZone2ExitPointX = csvExportData.LocalZone2ExitPointX; + this.blighPipingFactor = csvExportData.blighPipingFactor; + this.blighHCritical = csvExportData.blighHCritical; + this.sellmeijer2ForcesPipingFactor = csvExportData.sellmeijer2ForcesPipingFactor; + this.sellmeijer2ForcesHCritical = csvExportData.sellmeijer2ForcesHCritical; + this.sellmeijer4ForcesPipingFactor = csvExportData.sellmeijer4ForcesPipingFactor; + this.sellmeijer4ForcesHCritical = csvExportData.sellmeijer4ForcesHCritical; + this.sellmeijerPipingFactor = csvExportData.sellmeijerPipingFactor; + this.sellmeijerHCritical = csvExportData.sellmeijerHCritical; + this.wti2017PipingFactor = csvExportData.wti2017PipingFactor; + this.wti2017HCritical = csvExportData.wti2017HCritical; + this.redesignedSurfaceLineStability = csvExportData.redesignedSurfaceLineStability; + this.calculationResult = csvExportData.calculationResult; + } + + /// + /// Copies the result file. + /// + /// The extension. + private void CopyResultFile(string extension) + { + string copyResFile = Path.GetDirectoryName(InputFile) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(InputFile) + " (copy)" + extension; + var resFile = Path.ChangeExtension(InputFile, extension); + File.Copy(resFile, copyResFile, true); + } + + private string GetCurrentExeForOpenCalculationFile() + { + var exeName = DamProjectData.MStabExePath; + if (SelectedStabilityKernelType != StabilityKernelType.DamClassic) + { + exeName = Path.GetDirectoryName(exeName) + "\\MStab.exe"; + } + return exeName; + } + + /// + /// Opens the calculation file. + /// + public void OpenCalculationFile() + { + if (File.Exists(InputFile)) + { + string copyFile = Path.GetDirectoryName(InputFile) + Path.DirectorySeparatorChar + + Path.GetFileNameWithoutExtension(InputFile) + " (copy)" + Path.GetExtension(InputFile); + File.Copy(InputFile, copyFile, true); + var exeName = GetCurrentExeForOpenCalculationFile(); + if (SelectedStabilityKernelType == StabilityKernelType.DamClassic) + { + const string stdExtension = ".std"; + CopyResultFile(stdExtension); + + const string stoExtension = ".sto"; + CopyResultFile(stoExtension); + } + Process process = new Process(); + process.StartInfo.RedirectStandardOutput = false; + process.StartInfo.FileName = exeName; + if (SelectedStabilityKernelType == StabilityKernelType.DamClassicWti || + SelectedStabilityKernelType == StabilityKernelType.AdvancedWti) + { + process.StartInfo.Arguments = " -rto " + " \"" + copyFile + "\""; + } + else + { + process.StartInfo.Arguments = " \"" + copyFile + "\""; + } + process.StartInfo.UseShellExecute = false; + process.StartInfo.WindowStyle = ProcessWindowStyle.Normal; + process.Start(); + } + else + { + if (File.Exists(PipingResultFile)) + { + string copyFile = Path.GetTempPath() + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(PipingResultFile) + " (copy)" + + Path.GetExtension(PipingResultFile); + + File.Copy(PipingResultFile, copyFile, true); + System.Diagnostics.Process.Start(copyFile); + } + } + } + + /// + /// Make a clone of object + /// + /// + public object Clone() + { + CsvExportData csvExportData = new CsvExportData(this.id, this.dike, this.damFailureMechanismeCalculationSpecification, this.Scenario, + this.SoilProfile, this.SoilGeometry2DName, this.analysisType, this.nwoResultIndex, this.probabilisticType); + + csvExportData.Assign(this); + + return csvExportData; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry2DName.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry2DName.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/SoilGeometry2DName.cs (revision 334) @@ -0,0 +1,34 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General +{ + public class SoilGeometry2DName + { + private string geometry2DName; + + public virtual string Geometry2DName + { + get { return geometry2DName; } + set { geometry2DName = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/DilatancyType.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/DilatancyType.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/DilatancyType.cs (revision 334) @@ -0,0 +1,44 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// Dilatancy (shear thickening) type enumerator + /// + public enum DilatancyType + { + /// + /// The phi + /// + Phi = 1, + + /// + /// The zero + /// + Zero = 2, + + /// + /// The minus phi + /// + MinusPhi = 3 + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/SchematizationFactor/SchematizationFactorCalculation.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/SchematizationFactor/SchematizationFactorCalculation.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/SchematizationFactor/SchematizationFactorCalculation.cs (revision 334) @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.General.SchematizationFactor; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.RWScenarios; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Calculators.SchematizationFactor +{ + public class SchematizationFactorIntermediate + { + private SoilProfile1D soilProfile; + private double safetyFactor; + private double probPercentage; + private double summedProbPercentage; + + public SoilProfile1D SoilProfile + { + get { return soilProfile; } + set { soilProfile = value; } + } + + public double SafetyFactor + { + get { return safetyFactor; } + set { safetyFactor = value; } + } + + public double ProbPercentage + { + get { return probPercentage; } + set { probPercentage = value; } + } + + public double SummedProbPercentage + { + get { return summedProbPercentage; } + set { summedProbPercentage = value; } + } + } + + public class SchematizationFactorIntermediateList + { + private List schematizationFactorIntermediates = new List(); + + public List SchematizationFactorIntermediates + { + get { return schematizationFactorIntermediates; } + set { schematizationFactorIntermediates = value; } + } + + public void SortBySafetyFactor() + { + // First sort on prob + var sorted1 = schematizationFactorIntermediates.OrderByDescending(item => item.ProbPercentage); + List res1 = new List(); + foreach (var schematizationFactorIntermediate in sorted1) + { + res1.Add(schematizationFactorIntermediate); + } + schematizationFactorIntermediates.Clear(); + schematizationFactorIntermediates = res1; + + // then sort on sf. + var sorted = schematizationFactorIntermediates.OrderByDescending(item => item.SafetyFactor); + List res = new List(); + + foreach (var schematizationFactorIntermediate in sorted) + { + res.Add(schematizationFactorIntermediate); + } + schematizationFactorIntermediates.Clear(); + schematizationFactorIntermediates = res; + } + + public void SumSoilProfileProbabilities() + { + for (int i = 0; i < schematizationFactorIntermediates.Count; i++) + { + if (i == 0) + { + schematizationFactorIntermediates[i].SummedProbPercentage = + schematizationFactorIntermediates[i].ProbPercentage; + } + else + { + schematizationFactorIntermediates[i].SummedProbPercentage = + schematizationFactorIntermediates[i - 1].SummedProbPercentage + + schematizationFactorIntermediates[i].ProbPercentage; + } + } + } + + public int GetBasicSchematization(double requiredProbability) + { + var result = schematizationFactorIntermediates.Count - 1; + for (int i = 0; i < schematizationFactorIntermediates.Count; i++) + { + if (schematizationFactorIntermediates[i].SummedProbPercentage >= requiredProbability) + { + result = i; + break; + } + } + return result; + } + } + + public class SchematizationFactorCalculation + { + private RWScenariosResult scenariosResult; // input: scenariosResult are the results of all scenarios for one location. + private double detrimentFactor = 0; + private SchematizationFactorData schematizationFactorData; + private Location location; + + public RWScenariosResult ScenariosResult + { + get { return scenariosResult; } + set { scenariosResult = value; } + } + + public double DetrimentFactor + { + get { return detrimentFactor; } + set { detrimentFactor = value; } + } + + public SchematizationFactorData SchematizationFactorData + { + get { return schematizationFactorData; } + set { schematizationFactorData = value; } + } + + public Location Location + { + get { return location; } + set { location = value; } + } + + public RWSchematizationFactorsResult CalculateSchematizationFactorResults() + { + CheckData(); + + var results = new RWSchematizationFactorsResult(); + var macroStabilityInnerSideWetResult = + CalculateSchematizationFactorResultForType(SchematizationType.MacroStabiltyInnerSideWet); + results.SchematizationFactorResults.Add(macroStabilityInnerSideWetResult); + + var macroStabiltyInnerSideDryResult = + CalculateSchematizationFactorResultForType(SchematizationType.MacroStabiltyInnerSideDry); + results.SchematizationFactorResults.Add(macroStabiltyInnerSideDryResult); + + return results; + } + + public RWSchematizationFactorResult CalculateSchematizationFactorResultForType(SchematizationType schematizationType) + { + CheckData(); + + var result = GetSchematizationFactorResult(schematizationType); + + return result; + } + + private void CheckData() + { + if (scenariosResult == null) + { + throw new ApplicationException("Scenario results must be available to calculate the Schematization Factor."); + } + + if (detrimentFactor <= 0.0001) + { + throw new ApplicationException("Detriment factor must be specified to calculate the Schematization Factor."); + } + + if (schematizationFactorData == null) + { + throw new ApplicationException("Schematization Factor Data must be available to calculate the Schematization Factor."); + } + + if (this.Location == null) + { + throw new ApplicationException("Location name must be available to calculate the Schematization Factor."); + } + } + + private RWSchematizationFactorResult GetSchematizationFactorResult(SchematizationType schematizationType) + { + var schematizationFactorResult = new RWSchematizationFactorResult(); + schematizationFactorResult.SchematizationType = schematizationType; + schematizationFactorResult.SchematizationFactor = schematizationFactorData.SchematizationFactorMin; + schematizationFactorResult.Location = this.Location; + schematizationFactorResult.DetrimentFactor = DetrimentFactor; + + var decisiveScenarioResults = GetDecisiveResultsPerSchematizationType(schematizationType); + if (decisiveScenarioResults != null) + { + var mswIntermediates = SortResultsSchematizationType(decisiveScenarioResults); + var basicSchematization = + mswIntermediates.GetBasicSchematization(schematizationFactorData.RequiredProbability); + var schematizationFactor = schematizationFactorData.SchematizationFactorMin; + var allowedProbability = DetermineAllowedProbabilty(); + if ((basicSchematization >= 0) && (CheckOnB6(mswIntermediates, allowedProbability))) + { +//#Bka hier de SummedProbPercentage initialiseren op 1e laag basisprofiel zodat het % niet op nul blijft staan als je direct aan B7 voldoet!!!! Nagaan bij Erik of dat klopt of dat + // hij toch liever 0 of 100% ziet. + schematizationFactorResult.SummedProfileProbability = + mswIntermediates.SchematizationFactorIntermediates[basicSchematization].SummedProbPercentage; + schematizationFactorResult.OriginalDecisiveSoilProfileName = mswIntermediates.SchematizationFactorIntermediates[basicSchematization].SoilProfile.Name; + while (!CheckOnB7(mswIntermediates, basicSchematization, allowedProbability, schematizationFactor)) + { + //increase Pallowed + schematizationFactor = schematizationFactor + schematizationFactorData.SchematizationFactorDelta; + if (schematizationFactor > schematizationFactorData.SchematizationFactorMax) + { + // reset the factor, go to the next schematization when possible + schematizationFactor = schematizationFactorData.SchematizationFactorMin; + if (basicSchematization < mswIntermediates.SchematizationFactorIntermediates.Count - 1) + { + basicSchematization++; + } + else + { + schematizationFactorResult.CalculationResult = CalculationResult.RunFailed; + break; + } + } + } + schematizationFactorResult.SchematizationFactor = schematizationFactor; + schematizationFactorResult.SummedProfileProbability = + mswIntermediates.SchematizationFactorIntermediates[basicSchematization].SummedProbPercentage; + schematizationFactorResult.SoilProfileName = + mswIntermediates.SchematizationFactorIntermediates[basicSchematization].SoilProfile.Name; + schematizationFactorResult.DecisiveScenarioName = decisiveScenarioResults.ScenarioType; + schematizationFactorResult.SafetyFactor = + mswIntermediates.SchematizationFactorIntermediates[basicSchematization].SafetyFactor; + } + else + { + schematizationFactorResult.CalculationResult = CalculationResult.RunFailed; + } + } + else + { + schematizationFactorResult.CalculationResult = CalculationResult.RunFailed; + } + + if (schematizationFactorResult.CalculationResult != CalculationResult.Succeeded) + { + schematizationFactorResult.SchematizationFactor = 0; + } + return schematizationFactorResult; + } + + private double DetermineProbabilty(double factor) + { +// var beta = 4 + ((factor - 1)/0.13); +// var prob = Probabilistic.Probabilistic.NormalDistribution(beta * -1); +// return prob;##Bka + return double.MaxValue; + } + + internal double DetermineAllowedProbabilty() + { + return DetermineProbabilty(detrimentFactor); + } + + private double DetermineProbabiltyForSchematization(double safetyFactor) + { + return DetermineProbabilty(safetyFactor); + } + + private SchematizationFactorIntermediateList SortResultsSchematizationType(RWScenarioResult result) + { + var intermediateResults = new SchematizationFactorIntermediateList(); + foreach (var rwScenarioProfileResult in result.RWScenarioProfileResults) + { + var inter = new SchematizationFactorIntermediate(); + inter.SafetyFactor = rwScenarioProfileResult.SafetyFactor; + inter.SoilProfile = rwScenarioProfileResult.SoilGeometryProbability.SoilProfile; + inter.ProbPercentage = rwScenarioProfileResult.SoilGeometryProbability.Probability; + intermediateResults.SchematizationFactorIntermediates.Add(inter); + } + intermediateResults.SortBySafetyFactor(); + intermediateResults.SumSoilProfileProbabilities(); + return intermediateResults; + } + + private RWScenarioResult GetDecisiveResultsPerSchematizationType(SchematizationType schematizationType) + { + RWScenarioResult result = null; + double minSafetyFactor = Double.MaxValue; + switch (schematizationType) + { + case SchematizationType.MacroStabiltyInnerSideWet: + { + // scenarios 3, 4, 7 and 8 are relevant. + foreach (RWScenarioResult scenarioResult in scenariosResult.RWScenarioResults) + { + //#bka: nagaan bij Erik/Tom of dit de bedoeling is! + // nog groter mogelijk probleem : ik krijg niet alle resultaten door. Van de 37 profiles krijg ik er hier maar + // 27 door omdat de rest gefaald is en daarmee geen deel zijn van de scenarioResults! + if (scenarioResult.CalculationResult == CalculationResult.Succeeded) + { + if ((scenarioResult.ScenarioType == ScenarioType.Scenario03) || (scenarioResult.ScenarioType == ScenarioType.Scenario04) || + (scenarioResult.ScenarioType == ScenarioType.Scenario07) || (scenarioResult.ScenarioType == ScenarioType.Scenario08)) + { + if (scenarioResult.SafetyFactor < minSafetyFactor) + { + minSafetyFactor = scenarioResult.SafetyFactor; + result = scenarioResult; + } + } + } + } + break; + } + case SchematizationType.MacroStabiltyInnerSideDry: + { + // scenarios 1, 2, 5 and 6 are relevant. + foreach (RWScenarioResult scenarioResult in scenariosResult.RWScenarioResults) + { + //#bka: nagaan bij Erik/Tom of dit de bedoeling is! Non Succceeded heeft sf = -1 dus komt goed bij bepaling B06. + if (scenarioResult.CalculationResult == CalculationResult.Succeeded) + { + if ((scenarioResult.ScenarioType == ScenarioType.Scenario01) || (scenarioResult.ScenarioType == ScenarioType.Scenario02) || + (scenarioResult.ScenarioType == ScenarioType.Scenario05) || (scenarioResult.ScenarioType == ScenarioType.Scenario06)) + { + if (scenarioResult.SafetyFactor < minSafetyFactor) + { + minSafetyFactor = scenarioResult.SafetyFactor; + result = scenarioResult; + } + } + } + } + break; + } + default: + { + throw new ApplicationException("Schematization Factor not yet implemented for other things than macro stability."); + } + + } + return result; + } + + /// + /// Checks condition B.6: sum of all ( P(D|Si) * P(Si) ) smaller than or equal to Pallowed + /// P(D|Si) is the probability of failure for the schematization i + /// P(Si) is the probability of occurence for the schematization i + /// + /// + /// + /// + private bool CheckOnB6(SchematizationFactorIntermediateList intermediates, double allowedProbability) + { + double summedProbability = 0; + foreach (var intermediate in intermediates.SchematizationFactorIntermediates) + { + summedProbability = summedProbability + (DetermineProbabiltyForSchematization(intermediate.SafetyFactor) * + (intermediate.ProbPercentage / 100)); + } + var result = (summedProbability <= allowedProbability); + return result; + } + + /// + /// Checks condition B.7: (1 - sum of P(Si)) * P(D|Sk) + sum of ( P(D|Si) * P(Si) ) smaller than or equal to Pallowed + /// Note that the summing starts at i = k+1 with k being the number of the basic schematization + /// P(D|Sk) is the probability of failure for the schematization k + /// P(D|Si) is the probability of failure for the schematization i + /// P(Si) is the probability of occurence for the schematization i + /// + /// + /// + /// + /// + /// + private bool CheckOnB7(SchematizationFactorIntermediateList intermediates, int basicScenario, double allowedProbability, double schematizationFactor) + { + var result = false; + if (basicScenario >= 0) + { + var summedProbability = (DetermineProbabiltyForSchematization(intermediates.SchematizationFactorIntermediates[basicScenario].SafetyFactor * + schematizationFactor) * (intermediates.SchematizationFactorIntermediates[basicScenario].SummedProbPercentage / 100.0)); ; + + for (int i = basicScenario + 1; i < intermediates.SchematizationFactorIntermediates.Count; i++) + { + var prob = DetermineProbabiltyForSchematization(intermediates.SchematizationFactorIntermediates[i].SafetyFactor*schematizationFactor)* + (intermediates.SchematizationFactorIntermediates[i].ProbPercentage/100.0); + summedProbability = summedProbability + prob; + } + result = (summedProbability <= allowedProbability); + } + return result; + + } + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilTypes.cs (revision 334) @@ -0,0 +1,35 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// Enumerator for commonly used major soil types (Sand, Peat, Loam, Clay, Gravel) + /// + public enum SoilType + { + Sand, + Peat, + Loam, + Clay, + Gravel + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityFileParseException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityFileParseException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityFileParseException.cs (revision 334) @@ -0,0 +1,49 @@ +// Copyright (C) Stichting Deltares 2017. 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.Stability +{ + [Serializable] + public class StabilityFileParseException : Exception + { + + public StabilityFileParseException() + { + } + + public StabilityFileParseException(string message) : base(message) + { + } + + public StabilityFileParseException(string message, Exception inner) : base(message, inner) + { + } + + protected StabilityFileParseException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceFileParser.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceFileParser.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceFileParser.cs (revision 334) @@ -0,0 +1,438 @@ +// Copyright (C) Stichting Deltares 2017. 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.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Deltares.DamEngine.Calculators.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Calculators.Stability +{ + /// + /// Parses the stability factor from the file contents of the stability output file + /// + /// + /// The parser looks for the [Dump] identifier and if found the [Data] id. + /// When found the next line contains several numbers. We need the first one which is the stability factor + /// + public class StabilityServiceFileParser + { + enum StabilityZone { stabilityZone1a = 1, stabilityZone1b = 2, stabilityZone2a = 3, stabilityZone2b = 4, stabilityZone3a = 5, stabilityZone3b = 6 }; + + /// + /// Gets the file content (text) from a file + /// + /// The name of the file + /// The content string + public static string GetFileContents(string fileName) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(fileName, StringResourceNames.OutputFileNameNotValid); + + ThrowHelper.ThrowIfFileNotExist(fileName, StringResourceNames.OutputFileNotExist); + + string fileContents; + using (var sr = new StreamReader(fileName)) + { + fileContents = sr.ReadToEnd(); + } + return fileContents; + } + + /// + /// Parses the content to get the safety factory + /// + /// The text to parse + /// The safety factor + private static double GetColumnValueNoZones(string fileContent, string columnName) + { + fileContent = ReadContentAfterIdentifier(fileContent, "[Dumps]"); + fileContent = ReadContentAfterIdentifier(fileContent, "[Dump]"); + fileContent = ReadContentAfterIdentifier(fileContent, "[Dump Header]"); + fileContent = ReadContentAfterIdentifier(fileContent, "[Column Indication]"); + + int columnIndex = GetDataColumnIndex(fileContent, columnName, "[End of Column Indication]"); + + fileContent = ReadContentAfterIdentifier(fileContent, "[Data]"); + + double columnValue = GetNumberFromLine(fileContent, columnIndex); + + return columnValue; + } + + private static bool IsUpliftResults(string fileContent) + { + fileContent = ReadContentAfterIdentifier(fileContent, "[MODEL]"); + if (fileContent.Contains(" 4 : Uplift Van")) + { + return true; + } + else + { + return false; + } + } + + private static MStabResultsSingleZone GetMStabResultsNoZones(string fileContent) + { + MStabResultsSingleZone mStabResultsStruct = new MStabResultsSingleZone(); + mStabResultsStruct.safetyFactor = GetColumnValueNoZones(fileContent, "Stability factor"); + if (IsUpliftResults(fileContent)) + mStabResultsStruct.safetyFactor = mStabResultsStruct.safetyFactor / 1.05; + mStabResultsStruct.circleSurfacePointLeftXCoordinate = GetColumnValueNoZones(fileContent, "X coordinate left surface"); + mStabResultsStruct.circleSurfacePointRightXCoordinate = GetColumnValueNoZones(fileContent, "X coordinate right surface"); + return mStabResultsStruct; + + } + + public static double GetBetaNoZones(string fileContent) + { + return GetColumnValueNoZones(fileContent, "Beta"); + } + + public static double GetBetaWithZones(string fileContent) + { + MStabResults mStabResults = new MStabResults(); + MStabResultsSingleZone? zoneResults1 = GetMStabResultsSingleZoneFrom(fileContent, StabilityZone.stabilityZone1a, StabilityZone.stabilityZone1b); + if (zoneResults1 != null) + { + mStabResults.zone1 = zoneResults1.Value; + } + else + { + throw new StabilityFileParseException("Stabilityzone 1a or 1b should exist"); + } + //mStabResults.zone2 = GetMStabResultsSingleZoneFrom(fileContent, StabilityZone.stabilityZone2a, StabilityZone.stabilityZone2b); + return mStabResults.zone1.beta; + } + + /// + /// Get the results from a zone (A or if not exists then B) + /// + /// + /// + private static MStabResultsSingleZone? GetMStabResultsSingleZoneFrom(string fileContent, StabilityZone zoneA, StabilityZone zoneB) + { + MStabResultsSingleZone? mStabResultsSingleZone = null; + MStabResultsSingleZone? zoneAResults = ParseZoneResults(fileContent, (int)zoneA); + MStabResultsSingleZone? zoneBResults = null; + if (zoneAResults != null) + { + mStabResultsSingleZone = zoneAResults.Value; + } + + else + { + zoneBResults = ParseZoneResults(fileContent, (int)zoneB); + if (zoneBResults != null) + { + mStabResultsSingleZone = zoneBResults.Value; + } + } + return mStabResultsSingleZone; + } + + /// + /// Read all relevant MStab results from file + /// + /// + /// + public static MStabResults GetMStabResults(string fileContent) + { + MStabResults mStabResults = new MStabResults(); + + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(fileContent, StringResourceNames.OutputFileHasNoContent); + if (ParseHasZonePlotEnabled(fileContent)) + { + MStabResultsSingleZone? zoneResults1 = GetMStabResultsSingleZoneFrom(fileContent, StabilityZone.stabilityZone1a, StabilityZone.stabilityZone1b); + if (zoneResults1 != null) + { + mStabResults.zone1 = zoneResults1.Value; + } + else + { + throw new StabilityFileParseException("Stabilityzone 1a or 1b should exist"); + } + mStabResults.zone2 = GetMStabResultsSingleZoneFrom(fileContent, StabilityZone.stabilityZone2a, StabilityZone.stabilityZone2b); + } + else + { + MStabResultsSingleZone? noZoneResults = GetMStabResultsNoZones(fileContent); + mStabResults.zone1 = noZoneResults.Value; + } + return mStabResults; + } + + /// + /// Read all relevant SlopeW results from file + /// + /// + /// + public static MStabResults GetSlopeWResults(string fileContent) + { + MStabResults mStabResults = new MStabResults(); + + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(fileContent, StringResourceNames.OutputFileHasNoContent); + fileContent = ReadContentAfterIdentifier(fileContent, "Bishop_Method_Fm="); + var indexEnd = fileContent.IndexOf("Applied_Lambda"); + fileContent = fileContent.Substring(17, indexEnd - 18); + fileContent.Trim(); + mStabResults.zone1.safetyFactor = Convert.ToDouble(fileContent); + + return mStabResults; + } + + public static double GetBeta(string fileContent) + { + ThrowHelper.ThrowIfStringArgumentNullOrEmpty(fileContent, StringResourceNames.OutputFileHasNoContent); + if (ParseHasZonePlotEnabled(fileContent)) + { + return GetBetaWithZones(fileContent); + } + else + { + return GetBetaNoZones(fileContent); + } + + } + + public static bool ParseHasZonePlotEnabled(string fileContent) + { + StringReader stringReader = new StringReader(fileContent); + string line = ""; + + while ((line = stringReader.ReadLine()) != null) + { + if (line.EndsWith(": Zone plot on")) + { + return int.Parse(line.Substring(0, 3)).Equals(1) ? true : false; + } + } + return false; + } + + private static bool ReadParameterColumnIndices(StringReader stringReader, ref int stabilityFactorIndex, + ref int xCoordinateLeftSurfaceIndex, ref int xCoordinateRightSurfaceIndex, ref int zoneNumberIndex, ref int betaIndex) + { + string line = ""; + const string startCondition = "[Column Indication]"; + const string endCondition = "[End of Column Indication]"; + const string headerSafetyFactor = "Stability factor"; + const string headerXCoordinateLeftSurface = "X coordinate left surface"; + const string headerXCoordinateRightSurface = "X coordinate right surface"; + const string headerZoneNumber = "Zone number"; + const string headerBeta = "Beta"; + + bool isEndCondition = false; + stabilityFactorIndex = -1; + xCoordinateLeftSurfaceIndex = -1; + xCoordinateRightSurfaceIndex = -1; + zoneNumberIndex = -1; + while ((line = stringReader.ReadLine()) != null) + { + if (line.Equals(startCondition)) + { + int columnIndex = 0; + while ((line = stringReader.ReadLine()) != null) + { + if (line.Equals(headerSafetyFactor)) + stabilityFactorIndex = columnIndex; + + if (line.Equals(headerXCoordinateLeftSurface)) + xCoordinateLeftSurfaceIndex = columnIndex; + + if (line.Equals(headerXCoordinateRightSurface)) + xCoordinateRightSurfaceIndex = columnIndex; + + if (line.Equals(headerZoneNumber)) + zoneNumberIndex = columnIndex; + + if (line.Equals(headerBeta)) + betaIndex = columnIndex; + + columnIndex++; + if (line.Equals(endCondition)) + { + isEndCondition = true; + break; + } + } + } + if (isEndCondition) + break; + } + + return ((stabilityFactorIndex >= 0) && (zoneNumberIndex >= 0) && (xCoordinateLeftSurfaceIndex >= 0) && (xCoordinateRightSurfaceIndex >= 0)) ? true : false; + } + + private static MStabResultsSingleZone? ParseZoneResults(string fileContent, int stabilityZone) + { + StringReader stringReader = new StringReader(fileContent); + string line = ""; + string zoneStabilityResults = null; + + int stabilityFactorIndex = -1; + int xCoordinateLeftSurfaceIndex = -1; + int xCoordinateRightSurfaceIndex = -1; + int zoneNumberIndex = -1; + int betaIndex = -1; + + MStabResultsSingleZone mStabResultsStruct = new MStabResultsSingleZone(); + while ((line = stringReader.ReadLine()) != null) + { + if (line.Equals("[Dump]")) + { + if (!ReadParameterColumnIndices(stringReader, ref stabilityFactorIndex, + ref xCoordinateLeftSurfaceIndex, ref xCoordinateRightSurfaceIndex, ref zoneNumberIndex, ref betaIndex)) + throw new StabilityFileParseException("Could not read Column Indication"); + + while ((line = stringReader.ReadLine()) != null) + { + if (line.Equals("[Data]")) + { + zoneStabilityResults = stringReader.ReadLine(); + + var zoneStabilityResultsElements = zoneStabilityResults.Split(' ').ToList().Where(x => x.Length > 0).ToArray(); + + if (zoneStabilityResultsElements != null) + { + if ((zoneStabilityResultsElements.Count() > stabilityFactorIndex) && (zoneStabilityResultsElements.Count() > zoneNumberIndex)) + { + try + { + if (int.Parse(zoneStabilityResultsElements[zoneNumberIndex]).Equals(stabilityZone)) + { + mStabResultsStruct.safetyFactor = zoneStabilityResultsElements[stabilityFactorIndex].ToType(); + if (IsUpliftResults(fileContent)) + mStabResultsStruct.safetyFactor = mStabResultsStruct.safetyFactor/1.05; + mStabResultsStruct.circleSurfacePointLeftXCoordinate = zoneStabilityResultsElements[xCoordinateLeftSurfaceIndex].ToType(); + mStabResultsStruct.circleSurfacePointRightXCoordinate = zoneStabilityResultsElements[xCoordinateRightSurfaceIndex].ToType(); + if (betaIndex > -1) + { + mStabResultsStruct.beta = zoneStabilityResultsElements[betaIndex].ToType(); + } + return mStabResultsStruct; + } + } + catch (Exception e) + { + throw new StabilityFileParseException("Could not parse Stabilityzone : " + e.ToString()); + } + } + else + throw new StabilityFileParseException("stabilityZone or stabilityFactorIndex not found"); + } + break; + } + } + } + } + return null; + } + + public static MStabResultsSingleZone? GetZoneStability1a(string fileContent) + { + return ParseZoneResults(fileContent, (int)StabilityZone.stabilityZone1a); + } + + public static MStabResultsSingleZone? GetZoneStability1b(string fileContent) + { + return ParseZoneResults(fileContent, (int)StabilityZone.stabilityZone1b); + } + + /// + /// + /// + /// + /// + /// + private static string ReadContentAfterIdentifier(string fileContent, string identifier) + { + if (!fileContent.Contains(identifier)) + throw new StabilityFileParseException("Stability file doesn't contain identifier " + identifier); + fileContent = fileContent.Substring(fileContent.IndexOf(identifier)); + return fileContent.Replace(identifier + Environment.NewLine, ""); + } + + /// + /// + /// + /// + /// Returns -1 if identifier is not found + /// + /// The content to search in + /// The identifier to look for + /// The index of the column + private static int GetDataColumnIndex(string fileContent, string identifier, string endTag) + { + if (!fileContent.Contains(identifier)) + throw new StabilityFileParseException(); + + var items = fileContent + .Substring(0, fileContent.IndexOf(endTag) - Environment.NewLine.Length) + .Replace(Environment.NewLine, ";") + .Split(';'); + + var foundMatch = false; + var i = -1; + if (items.Length == 1 && StringsAreEqual(items[0], identifier)) + i = 0; + else if (items.Length > 1) + { + foreach (var word in items) + { + ++i; + if (StringsAreEqual(word, identifier)) + { + foundMatch = true; + break; + } + } + } + + if (i == -1 || !foundMatch) + throw new StabilityFileParseException(); + + return i; + } + + private static bool StringsAreEqual(string left, string right) + { + return ((!string.IsNullOrEmpty(left) || left.Trim() == "") && + left.Equals(right, StringComparison.InvariantCulture)); + } + + /// + /// + /// + /// + /// + private static double GetNumberFromLine(string fileContent, int idPos) + { + var doublesPattern = new Regex(@"-?\d+(?:\.\d+)?"); + var matches = doublesPattern.Matches(fileContent); + return double.Parse(matches[idPos].Value, NumberStyles.Any, CultureInfo.InvariantCulture); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenariosCalculation.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenariosCalculation.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenariosCalculation.cs (revision 334) @@ -0,0 +1,627 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text.RegularExpressions; +using Deltares.DamEngine.Calculators.SchematizationFactor; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.General.SchematizationFactor; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.RWScenarios; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Logging; + +namespace Deltares.DamEngine.Calculators.Dikes_Assessment_Regional +{ + /// + /// Exception for RWScenariosCalculation class + /// + public class RWScenariosCalculationException : ApplicationException + { + public RWScenariosCalculationException() { } + public RWScenariosCalculationException(string message) : base(message) { } + } + + public class RWScenariosCalculation : ICalculation + { + private EvaluationJob evaluationJob = null; + private GetValuesDelegate getValuesDelegate = null; + private ProgressDelegate progressDelegate = null; + private SendMessageDelegate sendMessageDelegate = null; + private string mstabExePath = @".\DGeoStability.exe"; + private int maxCalculationCores = 255; + + private Dictionary runningJobs = new Dictionary(); + private bool isSkipStabilityCalculation = false; + private SchematizationFactorData schematizationFactorData; + + public PipingModelType PipingModelType { get; set; } + public MStabParameters MStabParameters { get; set; } + + public RWScenariosCalculation() + { + } + + #region ICalculation Members + + public CalculationResult GetResults(ref string results) + { + // try + // { + // XmlSerializer serializer = new XmlSerializer(); + // results = serializer.SerializeToString(this.evaluationJob); + // return CalculationResult.Succeeded; + // } + // catch + // { + // return CalculationResult.UnexpectedError; + // }##Bka + return CalculationResult.UnexpectedError; + } + + public CalculationResult Load(string input) + { + // try + // { + // XmlDeserializer deserializer = new XmlDeserializer(); + // this.evaluationJob = (EvaluationJob)deserializer.XmlDeserializeFromString(input, typeof(EvaluationJob), new DefaultClassFactory()); + // return CalculationResult.Succeeded; + // } + // catch + // { + // return CalculationResult.UnexpectedError; + // }##Bka + return CalculationResult.UnexpectedError; + } + + public CalculationResult RegisterGetValues(GetValuesDelegate getValuesDelegate) + { + this.getValuesDelegate = getValuesDelegate; + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterProgress(ProgressDelegate progressDelegate) + { + this.progressDelegate = progressDelegate; + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterSendDebugInfo(SendDebugInfodelegate sendDebugInfoDelegate) + { + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterSendMessage(SendMessageDelegate sendMessageDelegate) + { + this.sendMessageDelegate = sendMessageDelegate; + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterSetValues(SetValuesDelegate setValuesDelegate) + { + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterUserAbort(UserAbortDelegate userAbortDelegate) + { + return CalculationResult.Succeeded; + } + + public CalculationResult Run() + { + try + { + + List tasks = this.FillQueue(); + + General.Parallel.Run(tasks, this.RunTask, this.progressDelegate, this.MaxCalculationCores); + this.FillResults(tasks); + + return CalculationResult.Succeeded; + } + catch(Exception exception) + { + sendMessageDelegate(new LogMessage(LogMessageType.Warning, null, "Unexpected error:" + exception.Message)); + throw exception; + } + } + + public CalculationResult Validate() + { + return CalculationResult.Succeeded; + } + + #endregion + + public string Version + { + get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } + } + + public string MStabExePath + { + get { return mstabExePath; } + set { mstabExePath = value; } + } + + public bool IsSkipStabilityCalculation + { + get { return isSkipStabilityCalculation; } + set { isSkipStabilityCalculation = value; } + } + + public int MaxCalculationCores + { + get { return maxCalculationCores; } + set { maxCalculationCores = value; } + } + + public SchematizationFactorData SchematizationFactorData + { + get { return schematizationFactorData; } + set { schematizationFactorData = value; } + } + + private List FillQueue() + { + List tasks = new List(); + + this.evaluationJob.FailedEvaluatedLocations = new List(); + foreach (Location location in this.evaluationJob.Locations) + { + if (location.Segment == null) + { + // Add this location to the failed locations + if (this.evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) + { + this.evaluationJob.FailedEvaluatedLocations.Add(location); + var locationHasNoSegment = LocalizationManager.GetTranslatedText(this.GetType(), "LocationHasNoSegment"); + sendMessageDelegate(new LogMessage(LogMessageType.Error, location, locationHasNoSegment)); + } + } + else + { + // TODO: Ask Erik Vastenburg how to handle piping and stability soilprofiles when determining RWScenarios + // For now we only use the stability profiles. + var soilGeometryProbabilities = + location.Segment.SoilProfileProbabilities.Where(s => (s.SegmentFailureMechanismType == null) || + (s.SegmentFailureMechanismType.Value == + FailureMechanismSystemType.StabilityInside)).ToList(); + if (soilGeometryProbabilities.Count == 0) + { + this.evaluationJob.FailedEvaluatedLocations.Add(location); + sendMessageDelegate( + new LogMessage(LogMessageType.Warning, location, String.Format("Location has no soilprofiles: ") + + String.Format("Segment: {0}", location.Segment.Name))); + + } + else + { + foreach (SoilGeometryProbability soilGeometryProbability in soilGeometryProbabilities) + { + if (soilGeometryProbability.SoilGeometryType == SoilGeometryType.SoilGeometry2D) + { + this.evaluationJob.FailedEvaluatedLocations.Add(location); + sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, LocalizationManager.GetTranslatedText(this, "Geometry2DNotSupportedInRegionalAssessment") + + String.Format("Segment: {0}", location.Segment.Name))); + } + else + { + + SoilProfile soilProfile = soilGeometryProbability.SoilProfile; + IList rwScenarios = null; + try + { + rwScenarios = this.GetRWScenarios(location, soilGeometryProbability); + } + catch (Exception e) + { + rwScenarios = null; + // Add this location to the failed locations + if (this.evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) + { + this.evaluationJob.FailedEvaluatedLocations.Add(location); + sendMessageDelegate( + new LogMessage(LogMessageType.Warning, location, String.Format("Cannot generate scenarios: {0}", e.Message) + + String.Format("Soilprofile: {0}", soilProfile.Name))); + } + } + if (rwScenarios != null) + { + foreach (RWScenarioProfileResult job in rwScenarios) + { + tasks.Add(job); + } + } + } + } + } + } + } + + return tasks; + } + + private IList GetRWScenarios(Location location, SoilGeometryProbability soilGeometryProbability) + { + RWScenarioSelector selector = new RWScenarioSelector(); + selector.PipingModelType = PipingModelType; + selector.MStabParameters = MStabParameters; + return selector.GetScenarios(location, soilGeometryProbability); + } + + private void RunTask(object task) + { + RWScenarioProfileResult job = (RWScenarioProfileResult)task; + + try + { + if (!IsSkipStabilityCalculation) + { + ProcessJob(job); + } + else + { + job.CalculationResult = CalculationResult.NoRun; + } + } + catch (Exception e) + { + job.CalculationResult = CalculationResult.UnexpectedError; + sendMessageDelegate(new LogMessage(LogMessageType.Warning, job.Location, String.Format("Error: {0}", e.Message))); + } + } + + /// + /// Select which job processor to use, depending on failuremechanism + /// + /// + private void ProcessJob(RWScenarioProfileResult job) + { + Debug.WriteLine(String.Format("Job {0}, location {1}, Scenario {2}", job.FailureMechanismType.ToString(), job.LocationName, job.ScenarioType.ToString())); + switch (job.FailureMechanismType) + { + case FailureMechanismSystemType.StabilityInside: + ProcessJobStability(job); + break; + case FailureMechanismSystemType.Piping: + ProcessJobPiping(job); + break; + default: + throw new RWScenariosCalculationException(String.Format("Failuremechanism {0} not yet implemented for scenario calculation", job.FailureMechanismType)); + } + } + + /// + /// Process a job for failuremechanism Piping + /// + /// + private void ProcessJobPiping(RWScenarioProfileResult job) + { +// if (job.Location.ModelFactors.UpliftCriterionPiping.HasValue) +// { +// var modelParametersForPLLines = new ModelParametersForPLLines(); +// var calculator = GetCalculatorForPipingModel(job, modelParametersForPLLines); +// double waterLevel; +// switch (job.LoadSituation) +// { +// case LoadSituation.Dry: +// waterLevel = job.Location.BoezemLevelLbp; +// break; +// default: // LoadSituation.Wet +// waterLevel = job.Location.BoezemLevelTp; +// break; +// } +// job.SoilGeometryProbability.SoilProfile.EnsureUniqueLayerIds(); +// var calculationName = GetCalculationNameForPipingCalculator(job); +// calculator.FilenameCalculation = Path.Combine(Path.Combine(DamProject.ProjectWorkingPath, job.FailureMechanismType.ToString()), calculationName); +// calculator.IsHydraulicShortcut = (job.HydraulicShortcutType == HydraulicShortcutType.HydraulicShortcut); +// double? pipingFactor = calculator.CalculatePipingFactor(job.Location, job.Location.LocalXZSurfaceLine2, job.SoilGeometryProbability.SoilProfile, waterLevel); +// job.BaseFileName = calculator.FilenameCalculation; +// +// job.RwResultType = RWResultType.SafetyFactor; +// if (pipingFactor.HasValue) +// { +// job.SafetyFactor = pipingFactor.Value; +// job.CalculationResult = CalculationResult.Succeeded; +// job.ProbabilityOfFailure = double.NaN; +// job.RwResultType = RWResultType.SafetyFactor; +// } +// +// else +// { +// job.SafetyFactor = double.NaN; +// job.CalculationResult = CalculationResult.RunFailed; +// } +// } +// else +// { +// throw new RWScenariosCalculationException(String.Format("Uplift criterion not defined for location {0}", job.Location.Name)); +// } ##Bka + + } + + private string GetCalculationNameForPipingCalculator(RWScenarioProfileResult job) + { + string calculationName; + switch (job.PipingModelOption) + { + case PipingModelType.Sellmeijer : calculationName = String.Format("Calc(Sellmeijer)_Loc({0})_Pro({1}))", + job.Location.Name, job.SoilGeometryProbability.SoilProfile.Name); + break; + case PipingModelType.Sellmeijer2Forces: calculationName = String.Format("Calc(Sellmeijer2Forces)_Loc({0})_Pro({1}))", + job.Location.Name, job.SoilGeometryProbability.SoilProfile.Name); + break; + case PipingModelType.Sellmeijer4Forces: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))", + job.Location.Name, job.SoilGeometryProbability.SoilProfile.Name); + break; + // Set Sellmeijer4Forces as default. + default: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))", + job.Location.Name, job.SoilGeometryProbability.SoilProfile.Name); + break; + } + calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); + return calculationName; + } + + /// + /// Determines the proper calculator for pipng + /// + /// + /// + /// proper piping calculator +// private PipingCalculator GetCalculatorForPipingModel(RWScenarioProfileResult job, ModelParametersForPLLines modelParametersForPLLines) +// { +// PipingCalculator calculator; +// switch (job.PipingModelOption) +// { +// case PipingModelType.Sellmeijer: calculator = new PipingCalculatorSellmeijer(modelParametersForPLLines, +// 1.0, null, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); +// break; +// case PipingModelType.Sellmeijer2Forces: calculator = new PipingCalculatorSellmeijer2Forces(modelParametersForPLLines, +// 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); +// break; +// case PipingModelType.Sellmeijer4Forces: calculator = new PipingCalculatorSellmeijer4Forces(modelParametersForPLLines, +// 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); +// break; +// case PipingModelType.Bligh: calculator = new PipingCalculatorBligh(modelParametersForPLLines, +// 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); +// break; +// default: +// throw new RWScenariosCalculationException(String.Format("Piping model {0} not yet implemented for scenario calculation", job.PipingModelOption)); +// } +// return calculator; +// } + + /// + /// Process a job for failuremechanism Stability + /// + /// + private void ProcessJobStability(RWScenarioProfileResult job) + { +// StabilityCalculation calculator = new StabilityCalculation(); +// +// lock (runningJobs) +// { +// runningJobs[calculator] = job; +// } +// +// calculator.MStabExePath = this.MStabExePath; +// calculator.RegisterSendMessage(this.SendStabilityMessage); +// +// string soilDatabaseName = job.Location.SoildatabaseName; +// DamFailureMechanismeCalculationSpecification damCalculation = +// calculator.GetSpecification(this.evaluationJob.DikeName, soilDatabaseName, job.Location, new SoilGeometry(job.SoilGeometryProbability.SoilProfile, null), +// (MStabModelType)job.MstabModelOption, job.LoadSituation, job.DikeDrySensitivity, job.HydraulicShortcutType, MStabParameters); +// +// calculator.SaveToFile(damCalculation.FailureMechanismeParamatersMStab); +// +// string inputFile = damCalculation.FailureMechanismeParamatersMStab.MStabParameters.ProjectFileName; +// +// job.BaseFileName = inputFile.Replace(DamProject.ProjectWorkingPath, @"").Replace(".sti", ""); +// +// calculator.Load(inputFile); +// job.CalculationResult = calculator.Run(); +// +// if (job.CalculationResult == CalculationResult.Succeeded) +// { +// string results = ""; +// +// job.CalculationResult = calculator.GetResults(ref results); +// XmlDeserializer deserializer = new XmlDeserializer(); +// RWResult result = (RWResult)deserializer.XmlDeserializeFromString(results, typeof(RWResult)); +// +// job.SafetyFactor = result.SafetyFactor; +// job.ProbabilityOfFailure = result.ProbabilityOfFailure; +// job.RwResultType = result.RwResultType; +// job.CalculationResult = result.CalculationResult; +// } +// else +// { +// job.RwResultType = (damCalculation.FailureMechanismeParamatersMStab.MStabParameters.IsProbabilistic ? RWResultType.ProbabilityOfFailure : RWResultType.SafetyFactor); +// job.SafetyFactor = double.NaN; +// job.ProbabilityOfFailure = double.NaN; +// } +// +// lock (runningJobs) +// { +// runningJobs.Remove(calculator); +// } ##Bka + } + + /// + /// Log messages + /// + /// + private void SendStabilityMessage(LogMessage logMessage) + { + lock (runningJobs) + { + if (logMessage.Subject != null) + { + RWScenarioProfileResult job = (RWScenarioProfileResult)runningJobs[(ICalculation)logMessage.Subject]; + logMessage.Subject = job.Location; + // logMessage.Detail = job.SoilGeometryProbability.SoilProfile.Name; + } + } + + this.sendMessageDelegate(logMessage); + } + + /// + /// Fill the results for the scenarios + /// + private void FillResults(List tasks) + { + // Fill scenariosResult structure with jobs just run + + foreach (Location location in this.evaluationJob.Locations) + { + try + { + RWScenariosResult scenariosResult = new RWScenariosResult(); + + if (this.evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) + { + // scenarios were succesfully created, so results are available + foreach (RWScenarioProfileResult job in tasks) + { + if (job.Location.Name.Equals(location.Name)) + { + RWScenarioResult scenarioResult = null; + foreach (RWScenarioResult existingScenarioResult in scenariosResult.RWScenarioResults) + { + if (existingScenarioResult.ScenarioType == job.ScenarioType) + { + scenarioResult = existingScenarioResult; + } + } + + if (scenarioResult == null) + { + scenarioResult = new RWScenarioResult(); + scenarioResult.ScenarioType = job.ScenarioType; + + scenariosResult.RWScenarioResults.Add(scenarioResult); + } + + scenarioResult.RWScenarioProfileResults.Add(job); + } + } + + // Combine results + + foreach (RWScenarioResult scenarioResult in scenariosResult.RWScenarioResults) + { + this.CombineProfiles(scenarioResult); + } + this.CombineScenarios(scenariosResult); + + } + else + { + // scenarios were not succesfully created, so results are not available + // no succesful calculations found + scenariosResult.CalculationResult = CalculationResult.RunFailed; + scenariosResult.SafetyFactor = double.NaN; + } + + if (schematizationFactorData != null) + { + var results = AddSchematizationFactors(location, scenariosResult); + evaluationJob.SchematizationFactorResults.Add(results); + } + // scenariosResult are the results of all scenarios for one location. + this.evaluationJob.Results.Add(scenariosResult); + + } + catch (Exception e) + { + RWScenariosResult scenariosResult = new RWScenariosResult + { + CalculationResult = CalculationResult.RunFailed, + SafetyFactor = double.NaN + }; + sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, String.Format("Error in location {0}: {1}", location.Name, e.Message))); + } + } + + } + + private RWSchematizationFactorsResult AddSchematizationFactors(Location location, RWScenariosResult scenariosResult) + { + var schematizationFactorCalculation = new SchematizationFactorCalculation(); + schematizationFactorCalculation.ScenariosResult = scenariosResult; + schematizationFactorCalculation.Location = location; + schematizationFactorCalculation.SchematizationFactorData = SchematizationFactorData; + schematizationFactorCalculation.DetrimentFactor = location.DetrimentFactor; + var results = schematizationFactorCalculation.CalculateSchematizationFactorResults(); + return results; + } + + private void CombineProfiles(RWScenarioResult scenarioResult) + { + // combine results of profiles + + scenarioResult.SafetyFactor = Double.MaxValue; + foreach (RWScenarioProfileResult profileResult in scenarioResult.RWScenarioProfileResults) + { + if (profileResult.CalculationResult == CalculationResult.Succeeded) + { + if (profileResult.SafetyFactor < scenarioResult.SafetyFactor) + { + scenarioResult.SafetyFactor = profileResult.SafetyFactor; + } + + scenarioResult.CalculationResult = CalculationResult.Succeeded; + } + } + if (scenarioResult.CalculationResult != CalculationResult.Succeeded) + { + // no succesful calculations found + scenarioResult.CalculationResult = scenarioResult.RWScenarioProfileResults[0].CalculationResult; + scenarioResult.SafetyFactor = scenarioResult.RWScenarioProfileResults[0].SafetyFactor; + } + } + + private void CombineScenarios(RWScenariosResult scenariosResult) + { + // combine results of scenarios + scenariosResult.SafetyFactor = Double.MaxValue; + foreach (RWScenarioResult scenarioResult in scenariosResult.RWScenarioResults) + { + if (scenarioResult.CalculationResult == CalculationResult.Succeeded) + { + if (scenarioResult.SafetyFactor < scenariosResult.SafetyFactor) + { + scenariosResult.SafetyFactor = scenarioResult.SafetyFactor; + } + scenariosResult.CalculationResult = CalculationResult.Succeeded; + } + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DamFailureMechanismeCalculationSpecification.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DamFailureMechanismeCalculationSpecification.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DamFailureMechanismeCalculationSpecification.cs (revision 334) @@ -0,0 +1,233 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + /// + /// + /// + public class DamFailureMechanismeCalculationSpecification + { + private FailureMechanismSystemType failureMechanismSystemType; + private PipingModelType pipingModelType = PipingModelType.Sellmeijer4Forces; + private Enum calculationModel; + private FailureMechanismeParamatersMStab failureMechanismeParamatersMStab; + private static ProbabilisticType probabilisticType; + private static DamProjectType damProjectType; + private StabilityKernelType stabilityKernelType = StabilityKernelType.DamClassic; + + public DamFailureMechanismeCalculationSpecification() + { + //Todo interface + failureMechanismSystemType = FailureMechanismSystemType.StabilityInside; + failureMechanismeParamatersMStab = new FailureMechanismeParamatersMStab(); + CalculationModel = failureMechanismeParamatersMStab.MStabParameters.Model; + FailureMechanismeParamatersMStab.MStabParameters.GridPosition = MStabGridPosition.Right; + ReadUserSettingsSlipCircleDefinition(); + } + + [Validate] + public FailureMechanismeParamatersMStab FailureMechanismeParamatersMStab + { + get { return failureMechanismeParamatersMStab; } + set { failureMechanismeParamatersMStab = value; } + } + + public FailureMechanismSystemType FailureMechanismSystemType + { + get { return failureMechanismSystemType; } + set + { + if (failureMechanismSystemType != value) + { + failureMechanismSystemType = value; + // To solve MWDAM-592, remember the current pipingmodeltype as this gets reset by setting the + // calculationmodel. Only switch it back when needed. + var oldPipingModelType = pipingModelType; +// foreach (Enum possibleModel in this.GetDomain("CalculationModel")) +// { +// this.CalculationModel = possibleModel; +// break; +// } #Bka: I think this is only needed for the UI. + switch (failureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + failureMechanismeParamatersMStab.MStabParameters.GridPosition = MStabGridPosition.Right; + break; + case FailureMechanismSystemType.StabilityOutside: + failureMechanismeParamatersMStab.MStabParameters.GridPosition = MStabGridPosition.Left; + break; + case FailureMechanismSystemType.Piping: + PipingModelType = oldPipingModelType; + break; + } + } + } + } + + + public PipingModelType PipingModelType + { + get { return pipingModelType; } + set + { + pipingModelType = value; + if (failureMechanismSystemType == FailureMechanismSystemType.Piping) + { + CalculationModel = pipingModelType; + } + } + } + + public static DamProjectType DamProjectType + { + get { return damProjectType; } + set { damProjectType = value; } + } + + public static ProbabilisticType ProbabilisticType + { + get { return probabilisticType; } + set { probabilisticType = value; } + } + + /// + /// The calculationmodel is only needed to support the selection of the modeltype in the UI. The dropdownlist + /// in the UI depends on this. This set can be filled with any proper types (for piping, stabilty etc) for any + /// mechanisme instead of the fixed types per mechanisme. + /// + [XmlIgnore] + public Enum CalculationModel + { + get { return calculationModel; } + set + { + calculationModel = value; + if (value is PipingModelType) + { + pipingModelType = (PipingModelType) value; + } + else + { + failureMechanismeParamatersMStab.MStabParameters.Model = (MStabModelType)value; + } + } + } + + public MStabModelType StabilityModelType + { + get { return failureMechanismeParamatersMStab.MStabParameters.Model; } + set + { + failureMechanismeParamatersMStab.MStabParameters.Model = value; + if (failureMechanismSystemType != FailureMechanismSystemType.Piping) + { + CalculationModel = value; + } + } + } + + public StabilityKernelType StabilityKernelType + { + get { return stabilityKernelType; } + set { stabilityKernelType = value; } + } + + public void Assign(DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculation) + { + this.FailureMechanismSystemType = damFailureMechanismeCalculation.failureMechanismSystemType; + this.FailureMechanismeParamatersMStab.Assign(damFailureMechanismeCalculation.FailureMechanismeParamatersMStab); + //assign interface + } + + public DamFailureMechanismeCalculationSpecification Clone() + { + DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculation = new DamFailureMechanismeCalculationSpecification(); + + damFailureMechanismeCalculation.Assign(this); + + return damFailureMechanismeCalculation; + } + + public override string ToString() + { + string description = ""; + description += String.Format("{0}", StabilityKernelType); + description += String.Format("{0}", this.FailureMechanismSystemType); + if ((this.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) || + (this.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside)) + { + //interface? + description += String.Format(" ({0})", this.FailureMechanismeParamatersMStab.MStabParameters.Model); + } + + return description; + } + + /// + /// Determines whether slip circle definition is undefined. + /// + /// + /// true if [is slip circle definition undefined]; otherwise, false. + /// + public bool IsSlipCircleDefinitionUndefined() + { + bool isSlipCircleDefinitionUndefined = (failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition == null); + if (!isSlipCircleDefinitionUndefined) + { + isSlipCircleDefinitionUndefined = (failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanLeftGridHorizontalPointCount == 0); + } + return isSlipCircleDefinitionUndefined; + } + + /// + /// Reads the user settings. + /// + public void ReadUserSettingsSlipCircleDefinition() + { +// if (failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition == null) +// { +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition = new SlipCircleDefinition(); +// } +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanTangentLinesDefinition = Properties.Settings.Default.SlipCircleUpliftVanTangentLinesDefinition; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanTangentLinesDistance = Properties.Settings.Default.SlipCircleUpliftVanTangentLinesDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopTangentLinesDefinition = Properties.Settings.Default.SlipCircleBishopTangentLinesDefinition; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopTangentLinesDistance = Properties.Settings.Default.SlipCircleBishopTangentLinesDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.GridSizeDetermination = Properties.Settings.Default.SlipCircleGridSizeDetermination; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanLeftGridVerticalPointCount = Properties.Settings.Default.SlipCircleUpliftVanLeftGridVerticalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanLeftGridVerticalPointDistance = Properties.Settings.Default.SlipCircleUpliftVanLeftGridVerticalPointDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanLeftGridHorizontalPointCount = Properties.Settings.Default.SlipCircleUpliftVanLeftGridHorizontalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanLeftGridHorizontalPointDistance = Properties.Settings.Default.SlipCircleUpliftVanLeftGridHorizontalPointDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanRightGridVerticalPointCount = Properties.Settings.Default.SlipCircleUpliftVanRightGridVerticalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanRightGridVerticalPointDistance = Properties.Settings.Default.SlipCircleUpliftVanRightGridVerticalPointDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanRightGridHorizontalPointCount = Properties.Settings.Default.SlipCircleUpliftVanRightGridHorizontalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.UpliftVanRightGridHorizontalPointDistance = Properties.Settings.Default.SlipCircleUpliftVanRightGridHorizontalPointDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopGridVerticalPointCount = Properties.Settings.Default.SlipCircleBishopGridVerticalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopGridVerticalPointDistance = Properties.Settings.Default.SlipCircleBishopGridVerticalPointDistance; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopGridHorizontalPointCount = Properties.Settings.Default.SlipCircleBishopGridHorizontalPointCount; +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.BishopGridHorizontalPointDistance = Properties.Settings.Default.SlipCircleBishopGridHorizontalPointDistance; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelFactors.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelFactors.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelFactors.cs (revision 334) @@ -0,0 +1,56 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; + +namespace Deltares.DamEngine.Data.General +{ + public class ModelFactors + { + public virtual double? RequiredSafetyFactorStabilityInnerSlope { get; set; } + public virtual double? RequiredSafetyFactorStabilityOuterSlope { get; set; } + public virtual double? RequiredSafetyFactorPiping { get; set; } + public virtual double? RequiredProbabilityOfFailureStabilityInnerslope { get; set; } + public virtual double? RequiredProbabilityOfFailureStabilityOuterslope { get; set; } + public virtual double? RequiredProbabilityOfFailurePiping { get; set; } + public virtual double? UpliftCriterionPiping { get; set; } + public virtual double? UpliftCriterionStability { get; set; } + + [XmlIgnore] + public double?[] AllValues + { + get + { + return new [] + { + RequiredSafetyFactorStabilityInnerSlope, + RequiredSafetyFactorStabilityOuterSlope, + RequiredSafetyFactorPiping, + RequiredProbabilityOfFailureStabilityInnerslope, + RequiredProbabilityOfFailureStabilityOuterslope, + RequiredProbabilityOfFailurePiping, + UpliftCriterionPiping, + UpliftCriterionStability + }; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile2D.cs (revision 334) @@ -0,0 +1,188 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// 2D Soil Profile Object + /// + public class SoilProfile2D : SoilProfile + { + protected readonly Dictionary cachedSoilProfiles1D = new Dictionary(); + protected GeometryData geometry = new GeometryData(); + protected readonly List surfaces = new List(); + + /// + /// Initializes a new instance of the class. + /// + public SoilProfile2D() + { + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilProfile2D"); + } + + /// + /// Gets the surfaces. + /// + /// + /// The surfaces. + /// + [Validate] + public virtual IList Surfaces + { + get + { + return surfaces; + } + } + + /// + /// Gets or sets the geometry. + /// + /// + /// The geometry. + /// + public GeometryData Geometry + { + get + { + return geometry; + } + set + { + geometry = value; + } + } + + /// + /// Gets the soil profile 1D at the given X. + /// + /// The x. + /// Soil Profile 1D + public virtual SoilProfile1D GetSoilProfile1D(double x) + { + const double diff = 0.001; + SoilProfile1D soilProfile = GetCachedSoilProfile1D(x); + + if (soilProfile != null) + { + return soilProfile; + } + + soilProfile = new SoilProfile1D + { + Name = "Generated at x = " + x + " from " + Name + }; + var detector = new LayerDetector(Surfaces); + if (x > Geometry.Right) + { + x = Geometry.Right - diff; + } + if (x < Geometry.Left) + { + x = Geometry.Left + diff; + } + + detector.DetermineMaterials(x); + + if (detector.LayerList.Count > 0) + { + soilProfile.BottomLevel = detector.LayerList[detector.LayerList.Count - 1].EndPoint.Z; + for (int i = 0; i < detector.LayerList.Count; i++) + { + var layer = new SoilLayer1D(detector.LayerList[i].Soil, detector.LayerList[i].StartPoint.Z) + { + IsAquifer = detector.LayerList[i].IsAquifer + }; + soilProfile.Layers.Add(layer); + } + } + + + cachedSoilProfiles1D[x] = soilProfile; + + return soilProfile; + } + + /// + /// Get the surface from the point + /// + /// The point which is supposed to be within the soil layer + /// Surface + public SoilLayer2D GetSoilLayer(Point2D point) + { + for (int i = 0; i < Surfaces.Count; i++) + { + SoilLayer2D surface = Surfaces[i]; + GeometryLoop surfaceLine = surface.GeometrySurface.OuterLoop; + if (surfaceLine.IsPointInLoopArea(point)) + { + bool found = true; + + // if point lies in an innerloop it belongs to another area + foreach (var innerloop in surface.GeometrySurface.InnerLoops) + { + if (innerloop.IsPointInLoopArea(point)) + { + found = false; + } + } + + if (found) + { + return surface; + } + } + } + + return null; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + /// + /// Gets the cached soil profile1 d. + /// + /// The x. + /// + protected SoilProfile1D GetCachedSoilProfile1D(double x) + { + if (cachedSoilProfiles1D.ContainsKey(x)) + { + return cachedSoilProfiles1D[x]; + } + return null; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculator.cs (revision 334) @@ -0,0 +1,2019 @@ +// Copyright (C) Stichting Deltares 2017. 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.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Calculators.Dikes_Design; +using Deltares.DamEngine.Calculators.General; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.NWO; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Probabilistic; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Logging; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Calculators +{ + public class MaximumRedesignIterationsReachedException : Exception + { + public MaximumRedesignIterationsReachedException() : base("Maximum number of iterations in redesign reached.") + { + } + } + + /// + /// + /// + public class DamFailureMechanismeCalculator + { + private const int PipingRedesingMaxIterations = 400; + private const double defaultMaxFractionOfDikeHeightForShoulderHeight = 0.67; + private const double CMinimumShoulderElevation = 0.5; + private const double CMinimumShoulderExtraElevation = 0.05; + private const double CMinimumShoulderWidth = 2; + private const double CMinimumShoulderExtraWidth = 1; + private const double CToleranceShoulderChanges = 0.001; + + private readonly DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification; + private readonly string mstabProgramPath; + private readonly ProgramType programType; + private readonly string slopeWProgramPath; + private AnalysisType analysisType; + private List errorMessages = new List(); + private int progressSofar; + + public DamFailureMechanismeCalculator(ProgramType programType, DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification, + string mstabProgramPath, string slopeWProgramPath, string mapForSoilGeometries2D, ProbabilisticType probabilisticType) + { + this.programType = programType; + this.damFailureMechanismeCalculationSpecification = damFailureMechanismeCalculationSpecification; + this.mstabProgramPath = mstabProgramPath; + this.slopeWProgramPath = slopeWProgramPath; + MapForSoilGeometries2D = mapForSoilGeometries2D; + ProbabilisticType = probabilisticType; + } + + public string CalculationBaseDirectory { get; set; } + public string MapForSoilGeometries2D { get; set; } + public ProbabilisticType ProbabilisticType { get; set; } + public NonWaterRetainingObject NonWaterRetainingObject { get; set; } + + public List ErrorMessages + { + get + { + return errorMessages; + } + set + { + errorMessages = value; + } + } + + /// + /// Main calculation call + /// + /// + /// + public void Calculate(AnalysisType analysisTypeGiven, Scenario scenario) + { + Debug.WriteLine("Location '{0}', scenario '{1}' DamFailureMechanismeCalculator.Calculation", scenario.Location.Name, scenario.LocationScenarioID); + analysisType = analysisTypeGiven; + + switch (analysisType) + { + case AnalysisType.NoAdaption: + CalculateForScenario(scenario); + break; + + case AnalysisType.AdaptGeometry: + RedesignSurfaceLinesForAllScenarios(scenario); + break; + case AnalysisType.AdaptNWO: + ImplementNWOInSurfaceLinesForAllScenarios(scenario); + break; + } + } + + /// + /// Selects the probabilities for specific failure mechanism. + /// + /// Type of the failure mechanism system. + /// The soil profile probabilities. + /// + public static List SelectProbabilitiesForFailureMechanism(FailureMechanismSystemType failureMechanismSystemType, IList soilProfileProbabilities) + { + switch (failureMechanismSystemType) + { + case FailureMechanismSystemType.StabilityInside: + case FailureMechanismSystemType.StabilityOutside: + case FailureMechanismSystemType.HorizontalBalance: + return SelectStabilityProbabilities(soilProfileProbabilities); + case FailureMechanismSystemType.Piping: + return SelectPipingProbabilities(soilProfileProbabilities); + case FailureMechanismSystemType.FlowSlide: + return SelectFlowSlideProbabilities(soilProfileProbabilities); + } + return null; + } + + /// + /// Redesigns the height of the surface line. + /// + /// Type of the failure mechanism system. + /// The scenario. + /// The surface line. + /// + public static SurfaceLine2 RedesignSurfaceLineHeight(FailureMechanismSystemType failureMechanismSystemType, Scenario scenario, SurfaceLine2 surfaceLine) + { + double? dikeHeight = surfaceLine.GetDikeHeight(); + if (dikeHeight.HasValue) + { + if (scenario.DikeTableHeight > dikeHeight.Value) + { + var surfaceLineHeightAdapter = new SurfaceLineHeightAdapter(surfaceLine, scenario.Location); + SurfaceLine2 adaptedSurfaceLine = surfaceLineHeightAdapter.ConstructNewSurfaceLine(scenario.DikeTableHeight ?? surfaceLine.GetDefaultDikeTableHeight() ?? 0); + + if (adaptedSurfaceLine != null) + { + var validationError = adaptedSurfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); + if (validationError != null) + { + throw new SurfaceLineException(validationError.Text); + } + + surfaceLine = adaptedSurfaceLine; + foreach (var soilProfileProbability in scenario.Location.Segment.SoilProfileProbabilities) + { + if (soilProfileProbability.SegmentFailureMechanismType == failureMechanismSystemType || soilProfileProbability.SegmentFailureMechanismType == null) + { + scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, surfaceLine); + } + } + } + } + } + return surfaceLine; + } + + /// + /// Cleanup directory where the piping project files are created + /// + public static void ClearPipingCalculationBaseDirectory() + { + string pipingBaseDirectory = GetPipingCalculationBaseDirectory(); + if (Directory.Exists(pipingBaseDirectory)) + { + Directory.Delete(pipingBaseDirectory, true); + } + } + + private void CalculateForScenario(Scenario scenario) + { +// switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) +// { +// case FailureMechanismSystemType.StabilityInside: +// case FailureMechanismSystemType.StabilityOutside: +// CalculateStabilityForScenario(scenario, 0); +// break; +// case FailureMechanismSystemType.Piping: +// CalculatePipingForScenario(scenario); +// break; +// case FailureMechanismSystemType.FlowSlide: +// CalculateFlowSlideForScenario(scenario); +// break; +// } + } + + /// + /// Checks the and adapt betas water levels when needed. + /// + /// The betas. + /// The water levels. + /// The scenario. + /// The new surface line. + /// The piping calculator. + /// The soil profile probability. + /// +// private bool CheckAndAdaptBetasWaterLevelsWhenNeeded(double[] betas, double[] waterLevels, Scenario scenario, SurfaceLine2 newSurfaceLine, PipingCalculator pipingCalculator, SoilGeometryProbability soilProfileProbability) +// { +// int nrValidItems = 0; +// for (int i = 0; i < 3; i++) +// { +// // If beta >= 10, then in fact no uplift occured and probability of failure is in fact 0. Such a value would be invalid for the design point calculation. +// if (betas[i] < 10) +// { +// nrValidItems++; +// } +// } +// if ((nrValidItems == 0) || (nrValidItems == 3)) +// { +// return (nrValidItems == 3); +// } +// else +// { +// if (nrValidItems == 1) +// { +// // extra calculation(s) needed to determine a second valid beta (<10) to be able to perform a design point calculation. Search between toplevel +// // (beta[0]) and middle level a waterlevel at which a beta is valid and use that one (adapt the levels too of course). +// double? betaloc = null; +// bool lReady = false; +// double locLevel = (waterLevels[0] + waterLevels[1])*0.5; +// var waterLevelProbabilistic = new ProbabilisticStruct(0.0, 0.01, (int) DistributionType.LogNormal, false); +// waterLevelProbabilistic.Distribution = (int) DistributionType.LogNormal; +// waterLevelProbabilistic.StandardDeviation = 0.01; +// waterLevelProbabilistic.IsUsed = false; +// while (!lReady) +// { +// waterLevelProbabilistic.Mean = locLevel; +// betaloc = CalculatePipingReliabilityIndexForSurface(scenario, newSurfaceLine, pipingCalculator, soilProfileProbability, +// waterLevelProbabilistic); +// lReady = betaloc.Value < 10; +// if (lReady) +// { +// betas[1] = betaloc.Value; +// waterLevels[1] = locLevel; +// } +// else +// { +// locLevel = locLevel + (waterLevels[0] + locLevel)*0.5; +// lReady = Math.Abs(locLevel - waterLevels[0]) < 0.0001; +// } +// } +// +// // now set nrValidItems to 2 to get the required third valid beta by axtrapolation +// nrValidItems = 2; +// } +// if (nrValidItems == 2) +// { +// // use the 2 valid betas to extrapolate a valid third beta value. +// betas[2] = Routines2D.LinInpolY(waterLevels[0], betas[0], waterLevels[1], betas[1], waterLevels[2]); +// } +// return true; +// } +// } + +// private double? CalculatePipingFailureProbabilityAdvanced(PipingCalculator pipingCalculator, Scenario scenario, +// SoilGeometryProbability soilProfileProbability, SurfaceLine2 newSurfaceLine) +// { +// double[] waterLevels = scenario.DetermineProperWaterlevelsForProbabilisticAdvanced(); +// var betas = new double[3]; +// var waterLevelProbabilistic = new ProbabilisticStruct(0.0, 0.01, (int) DistributionType.LogNormal, false); +// for (int i = 0; i < 3; i++) +// { +// betas[i] = 1; +// waterLevelProbabilistic.Mean = waterLevels[i]; +// string calculationName = String.Format("Prob{0}_Loc({1})_Sce({2})_Pro({3})_wl({4})", +// PipingModelType.Sellmeijer.ToString(), scenario.Location.Name, scenario.LocationScenarioID, soilProfileProbability.SoilGeometryName, i); +// calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); +// pipingCalculator.FilenameCalculation = pipingCalculator.PipingCalculationDirectory + calculationName; +// +// double? betaloc = CalculatePipingReliabilityIndexForSurface(scenario, newSurfaceLine, pipingCalculator, soilProfileProbability, waterLevelProbabilistic); +// if (betaloc != null) +// { +// betas[i] = betaloc.Value; +// } +// } + + // Note Bka: For now, set MHW to original max water level (= river level + WaterHeightDecimeringsHoogte) and set + // Decimate to the original WaterHeightDecimeringsHoogte. Han Best has to approve this! + // After consulting Best, the next decision is made. MHW should be the riverlevel. And if the maxwaterlevel is smaller than MHW,then a designpoint + // calculation is not longer required as the safety is determined by the maxwaterlevel. So just return the Beta[0] (= beta at maxwaterlevel) in + // that case. +// if (scenario.RiverLevel > scenario.MaxWaterLevel) +// { +// return Probabilistic.Probabilistic.NormalDistribution(-betas[0]); +// } +// else +// { +// if (CheckAndAdaptBetasWaterLevelsWhenNeeded(betas, waterLevels, scenario, newSurfaceLine, pipingCalculator, soilProfileProbability)) +// { +// var designPointWater = new DesignPointCalculation(); +// designPointWater.Betas = betas; +// designPointWater.Waterlevels = waterLevels; +// designPointWater.MHW = (double) (scenario.RiverLevel); +// designPointWater.Decimate = (double) scenario.WaterHeightDecimeringsHoogte; +// designPointWater.Exceed = DesignPointCalculation.ExceedingSet.twoThousend; +// designPointWater.IsMaxLevelUsed = false; +// designPointWater.MaxLevel = 0; +// if (designPointWater.CalculateTheWaterDesignpoint()) +// { +// return Probabilistic.Probabilistic.NormalDistribution(-designPointWater.Beta); +// } +// else +// { +// // result could not be determined. +// throw new DamFailureMechanismeCalculatorException("Water design point calculation failed"); +// } +// } +// else +// { +// // total situation is safe, so return 0. +// return 0; +// } +// } +// } + + /// + /// + /// + /// + /// + /// + /// + /// + /// +// private double? CalculatePipingReliabilityIndexForSurface(Scenario scenario, SurfaceLine2 newSurfaceLine, PipingCalculator pipingCalculator, SoilGeometryProbability soilProfileProbability, +// ProbabilisticStruct waterLevel) +// { +// double? betaloc; +// if (newSurfaceLine != null) +// { +// betaloc = pipingCalculator.CalculateReliabilityIndex(scenario.Location, newSurfaceLine, soilProfileProbability.SoilProfile, waterLevel); +// } +// else +// { +// betaloc = pipingCalculator.CalculateReliabilityIndex(scenario.Location, scenario.GetMostRecentSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName), soilProfileProbability.SoilProfile, waterLevel); +// } +// return betaloc; +// } + + /// + /// + /// + /// + /// + /// +// private void CalculatePipingForScenario(Scenario scenario) +// { +// var waterLevelProbabilistic = new ProbabilisticStruct(0.0, 0.01, (int) DistributionType.LogNormal, false); +// string pipingCalculationDirectory = GetPipingCalculationBaseDirectory(); +// try +// { +// var validSoilProfileProbabilities = SelectPipingProbabilities(scenario.Location.Segment.SoilProfileProbabilities); +// if (validSoilProfileProbabilities.Count == 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("No piping profiles to calcutate for location {0}", scenario.Location.Name)); +// } +// foreach (var soilProfileProbability in validSoilProfileProbabilities) +// { +// try +// { +// var pipingResults = new PipingResults(); +// foreach (PipingModelType pipingCalculationType in Enum.GetValues(typeof(PipingModelType))) +// { +// var pipingProbabilisticParameters = new PipingProbabilisticParameters(scenario.Location.LayerHeightDistribution, scenario.Location.LayerHeightDeviation); +// PipingCalculator pipingCalculator = pipingCalculatorFactory(scenario.Location, scenario.Location.CreateModelParametersForPLLines(), +// pipingCalculationType, +// scenario.GetUpliftCriterionPiping(scenario.Location.ModelFactors.UpliftCriterionPiping), +// scenario.GetRequiredSafetyFactorPiping(scenario.Location.ModelFactors.RequiredSafetyFactorPiping), +// pipingProbabilisticParameters); +// pipingCalculator.PipingCalculationDirectory = pipingCalculationDirectory; +// double? safetyFactor = null; +// double? failureProbability = null; +// double? failureProbabilityAdvanced = null; +// double? pipingExitPointX = null; +// double? upliftFactor = null; +// double? heaveFactor = null; +// try +// { +// switch (ProbabilisticType) +// { +// case ProbabilisticType.Deterministic: +// safetyFactor = pipingCalculator.CalculatePipingFactor( +// scenario.Location, +// scenario.GetMostRecentSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName), +// soilProfileProbability.SoilProfile, +// scenario.RiverLevel); +// if (pipingCalculator.UpliftLocationAndResult != null) +// { +// pipingExitPointX = pipingCalculator.UpliftLocationAndResult.X; +// upliftFactor = pipingCalculator.UpliftLocationAndResult.UpliftFactor; +// heaveFactor = pipingCalculator.HeaveFactor; +// } +// break; +// case ProbabilisticType.Probabilistic: +// waterLevelProbabilistic.Mean = scenario.RiverLevel; +// +// string calculationName = String.Format("Prob{0}_Loc({1})_Sce({2})_Pro({3})", +// pipingCalculationType.ToString(), scenario.Location.Name, scenario.LocationScenarioID, soilProfileProbability.SoilGeometryName); +// calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); +// pipingCalculator.FilenameCalculation = pipingCalculator.PipingCalculationDirectory + calculationName; +// +// failureProbability = +// pipingCalculator.CalculatePipingFailureProbability( +// scenario.Location, +// scenario.GetMostRecentSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName), +// soilProfileProbability.SoilProfile, +// waterLevelProbabilistic); +// break; +// case ProbabilisticType.ProbabilisticFragility: +// failureProbabilityAdvanced = CalculatePipingFailureProbabilityAdvanced(pipingCalculator, scenario, soilProfileProbability, null); +// break; +// } +// } +// catch (Exception exception) +// { +// throw new DamFailureMechanismeCalculatorException(exception.Message); +// } +// +// if (pipingCalculationType == PipingModelType.Sellmeijer) +// { +// scenario.SetSafetyFactorPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, safetyFactor); +// if (ProbabilisticType == ProbabilisticType.ProbabilisticFragility) +// { +// scenario.SetFailureProbabilityPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// failureProbabilityAdvanced); +// } +// else +// { +// scenario.SetFailureProbabilityPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// failureProbability); +// } +// } +// pipingResults.CalculationName = pipingCalculator.FilenameCalculation; +// pipingResults.CalculationSubDir = @"PipingCalculation\\"; +// pipingResults.PipingExitPointX = pipingExitPointX; +// pipingResults.UpliftFactor = upliftFactor; +// pipingResults.HeaveFactor = heaveFactor; +// switch (pipingCalculationType) +// { +// case PipingModelType.Bligh: +// pipingResults.BlighHCritical = pipingCalculator.HCritical; +// pipingResults.BlighPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer: +// pipingResults.SellmeijerHCritical = pipingCalculator.HCritical; +// pipingResults.SellmeijerPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer2Forces: +// pipingResults.Sellmeijer2ForcesHCritical = pipingCalculator.HCritical; +// pipingResults.Sellmeijer2ForcesPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer4Forces: +// pipingResults.Sellmeijer4ForcesHCritical = pipingCalculator.HCritical; +// pipingResults.Sellmeijer4ForcesPipingFactor = safetyFactor; +// break; +// case PipingModelType.Wti2017: +// pipingResults.Wti2017HCritical = pipingCalculator.HCritical; +// pipingResults.Wti2017PipingFactor = safetyFactor; +// break; +// } +// } +// scenario.SetPipingResults(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, pipingResults); +// } +// catch (DamFailureMechanismeCalculatorException calculatorException) +// { +// string errorMessage = "FAIL: " + calculatorException.Message; +// Exception innerException = calculatorException.InnerException; +// while (innerException != null) +// { +// errorMessage = errorMessage + ";" + innerException.Message; +// innerException = innerException.InnerException; +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, errorMessage); +// +// calculatorException.Scenario = scenario; +// throw calculatorException; +// } +// } +// } +// catch (Exception exception) +// { +// scenario.Errors.Add(exception.Message); +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// scenario.Errors.Add(innerException.Message); +// innerException = innerException.InnerException; +// } +// } +// } + + /// + /// Calculates failuremechanism flowslide for scenario. + /// + /// The scenario. +// private void CalculateFlowSlideForScenario(Scenario scenario) +// { +// try +// { +// var validSoilProfileProbabilities = SelectFlowSlideProbabilities(scenario.Location.Segment.SoilProfileProbabilities); +// if (validSoilProfileProbabilities.Count == 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("No profiles to calcutate for location {0}", scenario.Location.Name)); +// } +// foreach (var soilProfileProbability in validSoilProfileProbabilities) +// { +// try +// { +// if (soilProfileProbability.SoilProfile == null) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("Soilprofile is not 1D for location {0}", +// scenario.Location.Name)); +// } +// var flowSlideCalculations = new FlowSlideCalculations(); +// using (var flowSlideProject = CreateFlowSlideProject(scenario, soilProfileProbability)) +// { +// string calculationName = StabilityCalculator.DetermineCalculationFilename(scenario.Location.Name, scenario.LocationScenarioID, +// soilProfileProbability.SoilGeometryName, 0); +// WriteFlowSlideProjectToFile(flowSlideProject, calculationName); +// +// flowSlideCalculations.RunCalculation(flowSlideProject); +// double safetyFactor = flowSlideProject.ResultOverallFactor; +// scenario.SetSafetyFactorFlowSlide(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, safetyFactor); +// } +// } +// catch (DamFailureMechanismeCalculatorException calculatorException) +// { +// string errorMessage = "FAIL: " + calculatorException.Message; +// Exception innerException = calculatorException.InnerException; +// while (innerException != null) +// { +// errorMessage = errorMessage + ";" + innerException.Message; +// innerException = innerException.InnerException; +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, errorMessage); +// +// calculatorException.Scenario = scenario; +// throw calculatorException; +// } +// } +// } +// catch (Exception exception) +// { +// scenario.Errors.Add(exception.Message); +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// scenario.Errors.Add(innerException.Message); +// innerException = innerException.InnerException; +// } +// } +// } + + /// + /// Creates the flowslide project. + /// + /// The scenario. + /// The soil profile probability. + /// +// private static FlowSlideProject CreateFlowSlideProject(Scenario scenario, SoilGeometryProbability soilProfileProbability) +// { +// var flowSlideProject = new FlowSlideProject(); +// flowSlideProject.FlowSlideCalculationParameters.UseFlowSlideCalculation = UseFlowSlideCalculation.Global; +// flowSlideProject.SurfaceLine2 = scenario.Location.LocalXZSurfaceLine2; +// flowSlideProject.SoilProfile = soilProfileProbability.SoilProfile; +// flowSlideProject.Soils.Clear(); +// var projectSoils = new List(); +// foreach (var layer in soilProfileProbability.SoilProfile.Layers) +// { +// if (!projectSoils.Exists(T => layer.Soil.Name.Equals(T.Name))) +// { +// projectSoils.Add(layer.Soil); +// flowSlideProject.Soils.Add(layer.Soil); +// } +// } +// flowSlideProject.FlowSlideCalculationParameters.CalculationParametersGeneral.Waterlevel = scenario.RiverLevel; +// return flowSlideProject; +// } + + /// + /// Writes the flowslide project to file. + /// + /// The flow slide project. + /// Name of the calculation. +// private void WriteFlowSlideProjectToFile(FlowSlideProject flowSlideProject, string calculationName) +// { +// string flowslideCalculationDirectory = Path.Combine(CalculationBaseDirectory, @"Flowslide\"); +// if (!Directory.Exists(flowslideCalculationDirectory)) +// { +// Directory.CreateDirectory(flowslideCalculationDirectory); +// } +// string filenameExtension = ".fsx"; +// string fileName = calculationName + filenameExtension; +// string flowslideProjectFilename = Path.Combine(flowslideCalculationDirectory, fileName); +// var xmlSerializer = new XmlSerializer(); +// xmlSerializer.Serialize(flowSlideProject, flowslideProjectFilename); +// } + + /// + /// Selects the soilProfileProbabilities for piping. + /// + /// The soil profile probabilities. + /// + private static List SelectPipingProbabilities(IList soilProfileProbabilities) + { + var validSoilProfileProbabilities = + new List(soilProfileProbabilities.Where( + p => ((p.SegmentFailureMechanismType == FailureMechanismSystemType.Piping) || + (p.SegmentFailureMechanismType == null)))); + return validSoilProfileProbabilities; + } + + /// + /// Selects the soilProfileProbabilities for stability. + /// + /// The soil profile probabilities. + /// + private static List SelectStabilityProbabilities(IList soilProfileProbabilities) + { + var validSoilProfileProbabilities = new List(soilProfileProbabilities.Where( + p => ((p.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityInside) || + (p.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityOutside) || + (p.SegmentFailureMechanismType == null)))); + return validSoilProfileProbabilities; + } + + /// + /// Selects the flowslide probabilities. + /// + /// The soil profile probabilities. + /// + private static List SelectFlowSlideProbabilities(IList soilProfileProbabilities) + { + // For now use the stability probabilities + return SelectStabilityProbabilities(soilProfileProbabilities); + } + + /// + /// Consistency check to be performed before stability calculation + /// + /// + private void ConsistencyCheckStability(Scenario scenario) + { + ConsistencyCheckStabilityPerScenario(scenario); + } + + private void ConsistencyCheckStabilityPerScenario(Scenario scenario) + { + // If outward stability calculation then low waterlevel is required + if (damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.GridPosition == MStabGridPosition.Left) + { + if (!scenario.RiverLevelLow.HasValue) + { + throw new DamFailureMechanismeCalculatorException(String.Format( + "Location {0} scenario {1} has no low waterlevel defined, which is required for outward stability calculation (grid at left).", + scenario.Location.Name, scenario.LocationScenarioID)); + } + } + } + + /// + /// Stability calculation + /// + /// +// private void CalculateStabilityForScenario(Scenario scenario, int iter) +// { +// try +// { +// ConsistencyCheckStability(scenario); +// Location location = scenario.Location; +// var modelParametersForPLLines = new ModelParametersForPLLines +// { +// PenetrationLength = location.PenetrationLength, +// DampingFactorPL3 = location.DampingFactorPL3, +// DampingFactorPL4 = location.DampingFactorPL4, +// PLLineCreationMethod = location.PLLineCreationMethod +// }; +// var requiredSafetyFactorStabilityInnerSlope = scenario.RequiredSafetyFactorStabilityInnerSlope ?? +// location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope; +// using (var stabilityCalculator = +// new StabilityCalculator( +// damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab, +// programType, +// modelParametersForPLLines, +// location.TrafficLoad, +// location.MinimalCircleDepth, +// requiredSafetyFactorStabilityInnerSlope.Value, +// mstabProgramPath, slopeWProgramPath, +// location.GaugePLLines, +// location.Gauges, +// location.SoilbaseDB, +// location.SoilList, +// ProbabilisticType) +// { +// SelectedStabilityKernelType = damFailureMechanismeCalculationSpecification.StabilityKernelType +// }) +// { +// //stabilityCalculator.CalculationBaseDirectory = this.CalculationBaseDirectory; +// var validSoilProfileProbabilities = SelectStabilityProbabilities(scenario.Location.Segment.SoilProfileProbabilities); +// if (validSoilProfileProbabilities.Count == 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("No stability profiles to calcutate for location {0}", scenario.Location.Name)); +// } +// int errorCount = 0; +// var scenarioErrorMessages = new List(); +// foreach (var soilProfileProbability in validSoilProfileProbabilities) +// { +// try +// { +// UpliftSituation? upliftSituation = scenario.GetStabilityUpliftSituation(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); +// // The calculation for UpliftVan will only will done if there is Uplift +// if (IsCalculationRequired(upliftSituation)) +// { +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), iter); +// MStabResults? mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); +// if ((mStabResults != null) && (AnalysisType.AdaptNWO == analysisType)) +// { +// // Store the NWO results +// stabilityCalculator.NWOPhreaticAdaption = NonWaterRetainingObject.PhreaticAdaption; +// var results = new NonWaterRetainingObjectResults(); +// results.NwoId = NonWaterRetainingObject.NwoId; +// var coordinateSystemConverter = new CoordinateSystemConverter(); +// coordinateSystemConverter.DefineGlobalXYZBasedOnLine(scenario.Location.SurfaceLine2.Geometry); +// results.AdaptedSurfaceLine = scenario.Location.LocalXZSurfaceLine2.FullDeepClone(); +// coordinateSystemConverter.ConvertLocalXZToGlobalXYZ(results.AdaptedSurfaceLine.Geometry); +// results.LocationXrdStart = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1).X; +// results.LocationYrdStart = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1).Y; +// results.LocationZrdStart = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1).Z; +// results.LocationXrdEnd = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4).X; +// results.LocationYrdEnd = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4).Y; +// results.LocationZrdEnd = results.AdaptedSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4).Z; +// +// results.MStabResults = mStabResults.Value; +// results.SoilProfileProbability = soilProfileProbability; +// scenario.NwoResults.Add(results); +// } +// } +// // assign original surfaceline to redesigned surfaceline (not for NWODesign as that would provide wrong surface line) +// if (analysisType != AnalysisType.AdaptNWO) +// { +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, +// scenario.Location.SurfaceLine2); +// } +// } +// catch (DamFailureMechanismeCalculatorException calculatorException) +// { +// string errorMessage = "FAIL: " + calculatorException.Message; +// Exception innerException = calculatorException.InnerException; +// while (innerException != null) +// { +// errorMessage = errorMessage + ";" + innerException.Message; +// innerException = innerException.InnerException; +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, errorMessage); +// +// calculatorException.Scenario = scenario; +// errorCount++; +// scenarioErrorMessages.Add(errorMessage); +// } +// } +// if (errorCount > 0) +// { +// string errorMessage = String.Format("{0} calculation error(s) in location {1} scenario {2}", +// errorCount, location.Name, scenario.LocationScenarioID); +// foreach (var scenarioErrorMessage in scenarioErrorMessages) +// { +// errorMessage = String.Format("{0}; {1}", errorMessage, scenarioErrorMessage); +// } +// var calculatorException = new DamFailureMechanismeCalculatorException(errorMessage) +// { +// Scenario = scenario +// }; +// throw calculatorException; +// } +// } +// } +// catch (Exception exception) +// { +// scenario.Errors.Add(exception.Message); +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// scenario.Errors.Add(innerException.Message); +// innerException = innerException.InnerException; +// } +// throw; +// } +// } + + /// + /// Check if calculation should be done + /// (In case of UpliftVan and no uplift this is not the case) + /// + /// The uplift situation. + /// + /// true if [is calculation required] ; otherwise, false. + /// + private bool IsCalculationRequired(UpliftSituation? upliftSituation) + { + bool isUplift = upliftSituation.HasValue && upliftSituation.Value.IsUplift; + bool isSkipCalculation = (!isUplift && + damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.IsStabilityCheckOnUplift && + (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && + (damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.UpliftVan)); + return !isSkipCalculation; + } + + /// + /// + /// + /// + private void ImplementNWOInSurfaceLinesForAllScenarios(Scenario scenario) + { +// try +// { +// ImplementNWOInSurfaceLine(scenario); +// } +// catch (Exception exception) +// { +// scenario.Errors.Add(exception.Message); +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// scenario.Errors.Add(innerException.Message); +// innerException = innerException.InnerException; +// } +// } + } + +// private void CalculateScenario(Scenario scenario, int iter) +// { +// switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) +// { +// case FailureMechanismSystemType.StabilityInside: +// case FailureMechanismSystemType.StabilityOutside: +// ConsistencyCheckStabilityPerScenario(scenario); +// CalculateStabilityForScenario(scenario, iter); +// break; +// +// case FailureMechanismSystemType.Piping: +// CalculatePipingForScenario(scenario); +// break; +// } +// } + + /// + /// + /// + /// + /// +// private double? ImplementNWOInSurfaceLine(Scenario scenario) +// { +// double? safetyFactor = null; +// +// if (scenario.Location != null) +// { +// SurfaceLine2 originalLocalXzSurfaceLine = scenario.Location.LocalXZSurfaceLine2.FullDeepClone(); +// try +// { +// // fit the non water retaining object in the current surfaceline. If it does (no longer) fit, surfaceline is returned as null and +// // the calculation is finished. The phreaticline may have to be adapted to the new surfaceline. +// +// var nwoInSurfacleLine = new NonWaterRetainingObjectInSurfaceLine(); +// nwoInSurfacleLine.NonWaterRetainingObject = NonWaterRetainingObject; +// nwoInSurfacleLine.SurfaceLine = scenario.Location.LocalXZSurfaceLine2; +// nwoInSurfacleLine.GridPosition = damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.GridPosition; +// nwoInSurfacleLine.StepSizeX = NonWaterRetainingObject.StepSizeX; +// double fitPositionX = nwoInSurfacleLine.DetermineStartLocationForNonWaterRetainingObject(true); +// if (nwoInSurfacleLine.DoesPositionXFitInSurfaceLine(fitPositionX)) +// { +// var iter = 0; +// bool doneFittingNWO = false; +// while (!doneFittingNWO) +// { +// // try to fit NWO in surfaceline. If successfull, calculate it, else this is finished. +// SurfaceLine2 localXzSurfaceLine = nwoInSurfacleLine.FitNonWaterRetainingObjectInSurfaceLine(fitPositionX); +// if (localXzSurfaceLine != null) +// { +// var validationError = localXzSurfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// localXzSurfaceLine.Dispose(); +// throw new SurfaceLineException(validationError.Text); +// } +// +// scenario.Location.LocalXZSurfaceLine2.Dispose(); +// scenario.Location.LocalXZSurfaceLine2 = localXzSurfaceLine; +// // calculate with this surfaceline and store the results. +// CalculateScenario(scenario, iter); +// // Get new fitPositionX (based on stepsize X and gridposition) +// fitPositionX = nwoInSurfacleLine.DetermineNewFitPostionX(fitPositionX, true); +// iter++; +// } +// else +// { +// doneFittingNWO = true; +// } +// } +// +// if (iter > 0) +// { +// // restore the original surface line +// // Note: 'originalLocalXzSurfaceLine' is only used if now exception have occurred and +// scenario.Location.LocalXZSurfaceLine2 = originalLocalXzSurfaceLine; +// } +// else +// { +// throw new DamFailureMechanismeCalculatorException( +// "NonWaterRetainingObject does not fit within Surfaceline."); +// } +// } +// else +// { +// throw new DamFailureMechanismeCalculatorException( +// "NonWaterRetainingObject does not fit within Surfaceline."); +// } +// } +// catch (Exception e) +// { +// originalLocalXzSurfaceLine.Dispose(); // Clone has become an orphan, so dispose and discard +// +// // Add scenario if having a failure mechanism calculation exception: +// var calculatorException = e as DamFailureMechanismeCalculatorException; +// if (calculatorException != null) +// { +// calculatorException.Scenario = scenario; +// } +// throw; +// } +// } +// +// return safetyFactor; +// } + + /// + /// + /// + /// + private void RedesignSurfaceLinesForAllScenarios(Scenario scenario) + { +// try +// { +// RedesignSurfaceLine(scenario); +// } +// catch (Exception exception) +// { +// scenario.Errors.Add(exception.Message); +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// scenario.Errors.Add(innerException.Message); +// innerException = innerException.InnerException; +// } +// } + } + + /// + /// + /// + /// + /// +// private void RedesignSurfaceLine(Scenario scenario) +// { +// try +// { +// if (scenario.Location != null) +// { +// SurfaceLine2 surfaceLine = scenario.Location.LocalXZSurfaceLine2.FullDeepClone(); //TODO: I really have no clue this object should be in a using clause or not... :( +// if (scenario.Location.RedesignDikeHeight) +// { +// // Dike height adaptation +// +// var redesignedSurfaceLine = RedesignSurfaceLineHeight(damFailureMechanismeCalculationSpecification.FailureMechanismSystemType, +// scenario, surfaceLine); +// var validationError = redesignedSurfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// redesignedSurfaceLine.Dispose(); +// throw new SurfaceLineException(validationError.Text); +// } +// +// // No error, so replace clone with redesigned surfaceline +// surfaceLine.Dispose(); +// surfaceLine = redesignedSurfaceLine; +// } +// +// if (scenario.Location.RedesignDikeShoulder) +// { +// // Shoulder and slope adaption +// double? safetyFactor = null; +// switch (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) +// { +// case FailureMechanismSystemType.StabilityInside: +// case FailureMechanismSystemType.StabilityOutside: +// safetyFactor = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope; +// RedesignSurfaceLineStabilityInside(scenario, safetyFactor); +// break; +// +// case FailureMechanismSystemType.Piping: +// safetyFactor = scenario.ModelFactors.RequiredSafetyFactorPiping; +// RedesignSurfaceLinePipingShoulder(damFailureMechanismeCalculationSpecification.PipingModelType, +// scenario, ref safetyFactor, ref surfaceLine); +// break; +// case FailureMechanismSystemType.FlowSlide: +// RedesignSurfaceLineFlowSlide(scenario, safetyFactor, ref surfaceLine); +// break; +// } +// } +// } +// } +// catch (DamFailureMechanismeCalculatorException calculatorException) +// { +// calculatorException.Scenario = scenario; +// throw; +// } +// } + + /// + /// + /// + /// + /// + /// + /// +// private void RedesignSurfaceLinePipingShoulder(PipingModelType pipingModelType, Scenario scenario, ref double? safetyFactor, ref SurfaceLine2 surfaceLine) +// { +// var modelParametersForPLLines = new ModelParametersForPLLines +// { +// PenetrationLength = scenario.Location.PenetrationLength, +// DampingFactorPL3 = scenario.Location.DampingFactorPL3, +// DampingFactorPL4 = scenario.Location.DampingFactorPL4, +// PLLineCreationMethod = scenario.Location.PLLineCreationMethod +// }; +// +// var pipingProbabilisticParameters = new PipingProbabilisticParameters(scenario.Location.LayerHeightDistribution, +// scenario.Location.LayerHeightDeviation); +// var pipingUpliftCriterion = scenario.GetUpliftCriterionPiping(scenario.Location.ModelFactors.UpliftCriterionPiping); +// if (pipingUpliftCriterion <= 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("Invalid piping uplift criterion {0} for location {1} scenario {2}", +// pipingUpliftCriterion, scenario.Location.Name, scenario.LocationScenarioID)); +// } +// +// var requiredSafetyFactorPiping = 0.0; +// if (scenario.RequiredSafetyFactorPiping != null) +// { +// requiredSafetyFactorPiping = scenario.RequiredSafetyFactorPiping.Value; +// } +// if (safetyFactor != null) +// { +// requiredSafetyFactorPiping = safetyFactor.Value; +// } +// if (requiredSafetyFactorPiping <= 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("Invalid required safetyfactor piping {0} for location {1} scenario {2}", +// requiredSafetyFactorPiping, scenario.Location.Name, scenario.LocationScenarioID)); +// } +// PipingCalculator pipingCalculator = pipingCalculatorFactory(scenario.Location, modelParametersForPLLines, pipingModelType, +// pipingUpliftCriterion, +// requiredSafetyFactorPiping, +// pipingProbabilisticParameters); +// +// var validSoilProfileProbabilities = SelectPipingProbabilities(scenario.Location.Segment.SoilProfileProbabilities); +// if (validSoilProfileProbabilities.Count == 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("No piping profiles to calcutate for location {0}", scenario.Location.Name)); +// } +// foreach (var soilProfileProbability in validSoilProfileProbabilities) +// { +// try +// { +// SurfaceLine2 newSurfaceLine = surfaceLine.FullDeepClone(); +// switch (ProbabilisticType) +// { +// case ProbabilisticType.Deterministic: +// { +// var newCandidate = DetermineNewSafeSurfaceLinePipingDeterministic(scenario, soilProfileProbability, pipingCalculator, newSurfaceLine, ref safetyFactor); +// if (!ReferenceEquals(newSurfaceLine, newCandidate)) +// { +// newSurfaceLine.Dispose(); +// newSurfaceLine = newCandidate; +// } +// +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, newSurfaceLine); +// scenario.SetSafetyFactorPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, safetyFactor); +// PipingResults pipingResults = GetPipingResults(safetyFactor, pipingModelType, pipingCalculator); +// scenario.SetPipingResults(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, pipingResults); +// break; +// } +// +// case ProbabilisticType.Probabilistic: +// case ProbabilisticType.ProbabilisticFragility: +// { +// //Todo Adapt the determination of the piping design to the way it should be (See Detrministic and functional design) +// double[] waterLevels = scenario.DetermineProperWaterlevelsForProbabilisticAdvanced(); +// double waterLevel = scenario.RiverLevel; +// +// // for test of deterministic as initialisation for probabilistic, use next line. +// // newSurfaceLine = GetNewSafeSurfaceLine(scenario, soilProfileProbability, pipingCalculator, newSurfaceLine, ref requiredSafetyFactor); +// +// bool upLiftOccured = false; +// if (ProbabilisticType == ProbabilisticType.ProbabilisticFragility) +// { +// waterLevel = waterLevels[1]; +// } +// // start by checking the uplift first (if so, a newShoulderHeight can be determined). If uplift is not an issue then +// // probability of failure = 0. If uplift is an issue, add a berm until uplift is no longer an issue. +// double? newShoulderHeight = pipingCalculator.CalculateDesignShoulderHeight(scenario.Location, newSurfaceLine, +// soilProfileProbability.SoilProfile, waterLevel); +// +// double currentShoulderHeight = 0; +// double currentShoulderWidth = 0; +// double newShoulderWidth = 0; +// double slopeFactor = 0; +// if (newShoulderHeight != null) +// { +// // Debug.Write(String.Format("New Shoulder Height {0:0.000}\n", newShoulderHeight)); +// +// // if a new shoulderheight could be found, uplift is an issue. The new found shoulderheight might however not be the correct one +// // as with this height we insert or adjust a berm. This new/adjusted berm has to be checked until uplift is no longer an issue. +// upLiftOccured = true; +// +// // Start by adding the new shoulder. Note that there might be an existing shoulder. +// var shoulderTopInside = newSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); +// var dikeToeAtPolder = newSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); +// if (newSurfaceLine.HasShoulderInside()) +// { +// // there was a shoulder which now has to be extended. +// currentShoulderWidth = shoulderTopInside.X - +// newSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside).X; +// currentShoulderHeight = shoulderTopInside.Z - dikeToeAtPolder.Z; +// // shoulder must grow in length, it should be passed the uplift location +// newShoulderWidth = currentShoulderWidth + pipingCalculator.UpliftLocationAndResult.X - shoulderTopInside.X; +// // in height it should grow with the calculated amount. +// newShoulderHeight = newShoulderHeight.Value + currentShoulderHeight; +// } +// else +// { +// // there was no shoulder, so create one +// var dikeTopAtPolder = newSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); +// slopeFactor = (dikeToeAtPolder.X - dikeTopAtPolder.X)/(dikeTopAtPolder.Z - dikeToeAtPolder.Z); +// newShoulderWidth = 0.5 + newShoulderHeight.Value*slopeFactor; +// } +// // Make sure new berm is not too small +// newShoulderHeight = Math.Max(newShoulderHeight.Value, CMinimumShoulderElevation); +// newShoulderWidth = Math.Max(newShoulderWidth, CMinimumShoulderWidth); +// currentShoulderWidth = newShoulderWidth; +// currentShoulderHeight = newShoulderHeight.Value; +// +// bool finished = false; +// double maxShoulderLevel = CalculateMaximumShoulderLevel(newSurfaceLine, 1.0); // no limit to height of shoulder +// while ((newShoulderHeight != null) && (!finished)) +// { +// var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(newSurfaceLine, scenario.Location); +// surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; +// newSurfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(newShoulderWidth, newShoulderHeight.Value, true); +// newShoulderHeight = pipingCalculator.CalculateDesignShoulderHeight(scenario.Location, newSurfaceLine, +// soilProfileProbability.SoilProfile, waterLevel); +// finished = (pipingCalculator.UpliftLocationAndResult.X > shoulderTopInside.X); +// if (newShoulderHeight != null && (!finished)) +// { +// // make sure new height is at least cMinimumShoulderExtraElevation higher +// if (newShoulderHeight.Value < CMinimumShoulderExtraElevation) +// { +// newShoulderHeight = currentShoulderHeight + CMinimumShoulderExtraElevation; +// } +// else +// { +// newShoulderHeight = currentShoulderHeight + newShoulderHeight.Value; +// } +// // shoulder must grow in length, it should be passed the uplift location and at least the minimum grow value +// newShoulderWidth = currentShoulderWidth + CMinimumShoulderExtraWidth; +// currentShoulderWidth = currentShoulderWidth + pipingCalculator.UpliftLocationAndResult.X - +// shoulderTopInside.X; +// newShoulderWidth = Math.Max(currentShoulderWidth, newShoulderWidth); +// +// currentShoulderWidth = newShoulderWidth; +// currentShoulderHeight = newShoulderHeight.Value; +// } +// } +// } +// +// // if no shoulder needed (i.e. when no uplift occurs) then failure probability is always cDefaultMinReturnValue = 0.0 +// double? failureProbability = PipingCalculator.cDefaultMinReturnValue; +// if (upLiftOccured) +// { +// // Uplift occured, so calculate failureProbability +// if (ProbabilisticType == ProbabilisticType.Probabilistic) +// { +// var waterLevelProbabilistic = new ProbabilisticStruct(0.0, 0.01, (int) DistributionType.LogNormal, false); +// waterLevelProbabilistic.Mean = scenario.RiverLevel; +// failureProbability = pipingCalculator.CalculatePipingFailureProbability(scenario.Location, newSurfaceLine, +// soilProfileProbability.SoilProfile, waterLevelProbabilistic); +// } +// else +// { +// failureProbability = CalculatePipingFailureProbabilityAdvanced(pipingCalculator, scenario, soilProfileProbability, +// newSurfaceLine); +// } +// +// if (failureProbability != null) +// { +// int iterationIndex = 1; +// bool isRedesignRequired = (failureProbability.Value > scenario.ModelFactors.RequiredProbabilityOfFailurePiping); +// +// double maxShoulderLevel = CalculateMaximumShoulderLevel(newSurfaceLine, 1.0); // no limit to height of shoulder +// while (isRedesignRequired && newSurfaceLine != null) +// { +// // Debug.Write(String.Format("Iteration {0} failureProbability {1:0.0000000000}, currentShoulderWidth {2:0.000}, currentShoulderHeight {3:0.000}\n", iterationIndex, failureProbability, currentShoulderWidth, currentShoulderHeight)); +// iterationIndex++; +// currentShoulderWidth = currentShoulderWidth + 1; +// // Due to different calculation types, raise the shoulder too next to making it wider. +// currentShoulderHeight = currentShoulderHeight + CMinimumShoulderExtraElevation; +// var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(newSurfaceLine, scenario.Location); +// surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; +// newSurfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(currentShoulderWidth, currentShoulderHeight, true); +// if (ProbabilisticType == ProbabilisticType.Probabilistic) +// { +// var waterLevelProbabilistic = new ProbabilisticStruct(0.0, 0.01, (int) DistributionType.LogNormal, false); +// waterLevelProbabilistic.Mean = scenario.RiverLevel; +// failureProbability = pipingCalculator.CalculatePipingFailureProbability( +// scenario.Location, newSurfaceLine, +// soilProfileProbability.SoilProfile, waterLevelProbabilistic); +// } +// else +// { +// failureProbability = CalculatePipingFailureProbabilityAdvanced(pipingCalculator, scenario, +// soilProfileProbability, newSurfaceLine); +// } +// +// if (failureProbability != null) +// { +// isRedesignRequired = (failureProbability.Value > scenario.ModelFactors.RequiredProbabilityOfFailurePiping); +// } +// else +// { +// isRedesignRequired = true; +// } +// if (iterationIndex >= PipingRedesingMaxIterations) +// { +// // #BKA: vraag voor Ray set the results in case of failure too to provide feedback. (of niet Tom???) Voorlopig even niet. Ray was net naar huis dus nog navragen. +// // scenario.SetFailureProbabilityPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// // failureProbability); +// // scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// // newSurfaceLine); +// throw new MaximumRedesignIterationsReachedException(); +// } +// } +// } +// } +// if (failureProbability != null) +// { +// scenario.SetFailureProbabilityPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// failureProbability); +// } +// else +// { +// scenario.SetFailureProbabilityPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, +// 999); +// } +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, newSurfaceLine); +// break; +// } +// } +// +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, "Succes"); +// } +// catch (Exception exception) +// { +// string errorMessage = String.Format("Location '{0}', Soilprofile '{1}': {2}", +// scenario.Location.Name, soilProfileProbability.SoilGeometryName, exception.Message); +// PipingResults pipingResults = GetPipingResults(-1, pipingModelType, pipingCalculator); +// scenario.SetPipingResults(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, pipingResults); +// scenario.SetSafetyFactorPiping(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, -1); +// scenario.Errors.Add("FAIL: " + errorMessage); +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, "FAIL: " + errorMessage); +// } +// } +// } + +// private PipingResults GetPipingResults(double? safetyFactor, PipingModelType pipingModelType, PipingCalculator pipingCalculator) +// { +// var pipingResults = new PipingResults(); +// switch (pipingModelType) +// { +// case PipingModelType.Bligh: +// pipingResults.BlighHCritical = pipingCalculator.HCritical; +// pipingResults.BlighPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer: +// pipingResults.SellmeijerHCritical = pipingCalculator.HCritical; +// pipingResults.SellmeijerPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer2Forces: +// pipingResults.Sellmeijer2ForcesHCritical = pipingCalculator.HCritical; +// pipingResults.Sellmeijer2ForcesPipingFactor = safetyFactor; +// break; +// case PipingModelType.Sellmeijer4Forces: +// pipingResults.Sellmeijer4ForcesHCritical = pipingCalculator.HCritical; +// pipingResults.Sellmeijer4ForcesPipingFactor = safetyFactor; +// break; +// case PipingModelType.Wti2017: +// pipingResults.Wti2017HCritical = pipingCalculator.HCritical; +// pipingResults.Wti2017PipingFactor = safetyFactor; +// break; +// } +// return pipingResults; +// } + + /// + /// Ensures that the points on the surface line are never more than cDiff (0.5) apart. + /// + /// + /// + private IEnumerable GetCheckedSurfaceLine(IEnumerable originalLine) + { + const double cDiff = 0.5; + var newLine = new List(); + double X = originalLine.First().X; + foreach (var point in originalLine) + { + while (point.X > X + cDiff) + { + var newPoint = new GeometryPoint(point) + { + X = X + cDiff + }; + if (newPoint.X > newLine.Last().X) + { + newPoint.Z = newLine.Last().Z + ((newPoint.X - newLine.Last().X)/(point.X - newLine.Last().X))* + (point.Z - newLine.Last().Z); + newLine.Add(newPoint); + } + X = newPoint.X; + } + newLine.Add(point); + } + return newLine; + } + +// private SurfaceLine2 DetermineNewSafeSurfaceLinePipingDeterministic(Scenario scenario, SoilGeometryProbability soilProfileProbability, PipingCalculator pipingCalculator, SurfaceLine2 surfaceLine, ref double? safetyFactor) +// { +// double orgShoulderLength = surfaceLine.DetermineShoulderWidth(); +// double orgShoulderHeight = surfaceLine.DetermineShoulderHeight(); +// double desiredShoulderLength = orgShoulderLength; +// double desiredShoulderHeight = orgShoulderHeight; +// double oldDesiredShoulderLength = orgShoulderLength; +// double oldDesiredShoulderHeight = orgShoulderHeight; +// +// GeometryPoint startSurfacePoint = surfaceLine.GetDikeToeInward(); +// +// IEnumerable relevantSurfacePointsList = from GeometryPoint point in surfaceLine.Geometry.Points +// where point.X >= startSurfacePoint.X +// orderby point.X ascending +// select point; +// relevantSurfacePointsList = GetCheckedSurfaceLine(relevantSurfacePointsList); +// int pointCount = 0; +// foreach (var point in relevantSurfacePointsList) +// { +// pointCount++; +// // Determine calculation filename to output piping calculation file +// //pipingCalculator.PipingCalculationDirectory = GetPipingCalculationBaseDirectory(); +// //string fileNameCalculation =String.Format("Calc({0})_Loc({1})_Pro({2})_Pnt({3}))", +// // pipingCalculator.CalculationModelIdentifier, scenario.Location.Name, soilProfileProbability.SoilProfile.Name, pointCount.ToString("d4")); ; +// //pipingCalculator.FilenameCalculation = Path.Combine(pipingCalculator.PipingCalculationDirectory, fileNameCalculation); +// +// // Calculate the piping design at the given point. This returns the required adaption (berm length and height) if any. +// var pipingDesign = pipingCalculator.CalculateDesignAtPoint(scenario.Location, surfaceLine, +// soilProfileProbability.SoilProfile, +// scenario.RiverLevel, point); +// if (pipingDesign != null) +// { +// // Piping is an issue so adapt the surfaceline for it +// desiredShoulderLength = pipingDesign.PipingLengthFromToe; +// desiredShoulderLength = Math.Max(desiredShoulderLength, oldDesiredShoulderLength); +// oldDesiredShoulderLength = desiredShoulderLength; +// // shoulder height is height above surfacelevel!! +// desiredShoulderHeight = pipingDesign.ShoulderHeightFromToe; +// desiredShoulderHeight = Math.Max(desiredShoulderHeight, oldDesiredShoulderHeight); +// oldDesiredShoulderHeight = desiredShoulderHeight; +// } +// } +// if (desiredShoulderLength > 0) +// { +// desiredShoulderLength = Math.Max(desiredShoulderLength, CMinimumShoulderWidth); +// } +// if (desiredShoulderLength > 0) +// { +// desiredShoulderHeight = Math.Max(desiredShoulderHeight, CMinimumShoulderElevation); +// } +// bool isNewShoulderSameAsOriginal = ((Math.Abs(desiredShoulderLength - orgShoulderLength) < CToleranceShoulderChanges) && +// (Math.Abs(desiredShoulderHeight - orgShoulderHeight) < CToleranceShoulderChanges)); +// if (isNewShoulderSameAsOriginal) +// { +// return surfaceLine; +// } +// else +// { +// // Adapt the surfaceline for the finally required shoulder dimensions. +// double maxShoulderLevel = CalculateMaximumShoulderLevel(surfaceLine, 1.0); // no limit to height of shoulder +// var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(surfaceLine, scenario.Location); +// surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; +// SurfaceLine2 newSurfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(desiredShoulderLength, desiredShoulderHeight, true); +// +// safetyFactor = pipingCalculator.CalculatePipingFactor(scenario.Location, newSurfaceLine, soilProfileProbability.SoilProfile, scenario.RiverLevel); +// if (safetyFactor < scenario.RequiredSafetyFactorPiping) +// { +// throw new DamFailureMechanismeCalculatorException("Deterministic Design: Piping is not safe yet."); +// } +// return newSurfaceLine; +// } +// } + + /// + /// Create the initial geometry to be used to determine layers for embankment for design + /// + /// + /// + /// + /// + /// + /// +// private void CreateInitialGeometry(Scenario scenario, StabilityCalculator stabilityCalculator, SoilGeometryProbability soilProfileProbability, SurfaceLine2 surfaceLine, out String initialgeometryFile) +// { +// const int IterationIndex = -1; +// +// initialgeometryFile = StabilityCalculator.DetermineCalculationFilename(scenario.Location.Name, scenario.LocationScenarioID, soilProfileProbability.SoilGeometryName, IterationIndex); +// initialgeometryFile = initialgeometryFile + stabilityCalculator.GetFilenameExtension(); +// initialgeometryFile = Path.Combine(stabilityCalculator.GetStabilityCalculationDirectory(), initialgeometryFile); +// double riverLevel = 0.5*(surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).Z + +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).Z); +// string soilgeometry2DFilename = null; +// if (soilProfileProbability.SoilGeometry2DName != null) +// { +// soilgeometry2DFilename = +// Path.GetFullPath(Path.Combine(DamProject.ProjectMap, Path.Combine(scenario.Location.MapForSoilGeometries2D, soilProfileProbability.SoilGeometry2DName))); +// } +// XDocument mstabXML = stabilityCalculator.CreateMStabXmlDoc(initialgeometryFile, scenario, soilProfileProbability.SoilProfile, +// soilgeometry2DFilename, riverLevel, null, surfaceLine); +// mstabXML.Save(initialgeometryFile + ".xml"); +// var stabilityServiceAgent = new StabilityServiceAgent(); +// stabilityServiceAgent.CreateProjectFile(mstabXML.ToString()); +// if (!File.Exists(initialgeometryFile)) +// { +// throw new DamFailureMechanismeCalculatorException("Initial geometry file (sti) is not created."); +// } +// } + + /// + /// Redesigns the surface line for mechanism stability inside. + /// + /// The scenario. + /// The safety factor. +// private void RedesignSurfaceLineStabilityInside(Scenario scenario, double? requiredSafetyFactor) +// { +// Location location = scenario.Location; +// var modelParametersForPLLines = new ModelParametersForPLLines +// { +// PenetrationLength = location.PenetrationLength, +// DampingFactorPL3 = location.DampingFactorPL3, +// DampingFactorPL4 = location.DampingFactorPL4, +// PLLineCreationMethod = location.PLLineCreationMethod +// }; +// using (var stabilityCalculator = +// new StabilityCalculator(damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab, +// programType, +// modelParametersForPLLines, +// location.TrafficLoad, +// location.MinimalCircleDepth, +// requiredSafetyFactor.Value, +// mstabProgramPath, +// slopeWProgramPath, +// location.GaugePLLines, +// location.Gauges, +// location.SoilbaseDB, +// location.SoilList, +// ProbabilisticType) +// { +// SelectedStabilityKernelType = damFailureMechanismeCalculationSpecification.StabilityKernelType +// }) +// { +// var validSoilProfileProbabilities = SelectStabilityProbabilities(scenario.Location.Segment.SoilProfileProbabilities); +// if (validSoilProfileProbabilities.Count == 0) +// { +// throw new DamFailureMechanismeCalculatorException(String.Format("No stability profiles to calcutate for location {0}", scenario.Location.Name)); +// } +// foreach (var soilProfileProbability in validSoilProfileProbabilities) +// { +// // The calculation for UpliftVan will only will done if there is Uplift +// UpliftSituation? upliftSituation = scenario.GetStabilityUpliftSituation(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); +// if (IsCalculationRequired(upliftSituation)) +// { +// switch (scenario.Location.StabilityDesignMethod) +// { +// // Bij WTIkernel is het soilprofile2D nog null in de soilProfileProbability en daarom gat Adapt Geometry fout. +//// nagaan bij classic Delphi of dat daar ook leeg is. Daarnaast is het probleem groter. Je moet denk ik de geometrie geheel regenereren NADAT de surfaceline +//// is aangepast. Dan moet de soilprofile2D goed gezet worden (en ook de sti + naam sti!?!?!?! uitzoeken!) op de nieuwe 2Dgeom. En die moet goed in de kernel terecht komen. +//// Dus dat kan nog niet hier want de nieuwe surfaceline is nog niet bekend. Gebruik maken van de surf2dprof combiner!! +// case StabilityDesignMethod.OptimizedSlopeAndShoulderAdaption: +// { +// RedesignCombinedSlopeAdaptionAndShoulderAdaption(scenario, stabilityCalculator, soilProfileProbability); +// break; +// } +// case StabilityDesignMethod.SlopeAdaptionBeforeShoulderAdaption: +// { +// RedesignFirstSlopeAdaptionThenShoulderAdaption(scenario, stabilityCalculator, soilProfileProbability); +// break; +// } +// } +// } +// } +// } +// } + + /// + /// Redesign for Stability: + /// Dependent on the exit point of the stability circle. + /// If the exit point is in the slope, the slope will be adapted. + /// If the exit point is not in the slope, a shoulder will be made, + /// or if the shoulder exists, the shoulder will be enlarged. + /// + /// + /// + /// + /// +// private void RedesignCombinedSlopeAdaptionAndShoulderAdaption(Scenario scenario, StabilityCalculator stabilityCalculator, +// SoilGeometryProbability soilProfileProbability) +// { +// Location location = scenario.Location; +// double requiredSafetyFactor = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? +// scenario.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value; +// double betaRequired = scenario.ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope ?? +// scenario.Location.ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.Value; +// const int maxRedesignIterations = 200; +// int iterationIndex = 1; +// string previousFilename; +// SurfaceLine2 orgSurfaceLine = scenario.Location.LocalXZSurfaceLine2; +// +// // Create the file with the initial geometry to be used to determine which layers have to be defined as dike embankment material +// CreateInitialGeometry(scenario, stabilityCalculator, soilProfileProbability, orgSurfaceLine, out previousFilename); +// SurfaceLine2 surfaceLine = scenario.GetMostRecentSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName).FullDeepClone(); +// +// var mstabDesignEmbankment = new MStabDesignEmbankment +// { +// EmbankmentMaterialname = location.DikeEmbankmentMaterial, +// PreviousGeometry2DFilename = previousFilename +// }; +// +// try +// { +// double? beta; +// bool isRedesignRequired; +// double? exitPointXCoordinate; +// scenario.Location.AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(surfaceLine); +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, +// GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), +// iterationIndex, mstabDesignEmbankment); +// mstabDesignEmbankment.PreviousGeometry2DFilename = stabilityCalculator.StabilityProjectFilename; +// mstabDesignEmbankment.EmbankmentMaterialname = location.ShoulderEmbankmentMaterial; +// MStabResults? mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// double? safetyFactor = mStabResults.Value.zone1.safetyFactor; +// beta = scenario.GetFailureProbabilityStability(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// isRedesignRequired = IsRedesignRequired(safetyFactor, requiredSafetyFactor, betaRequired, beta); +// exitPointXCoordinate = mStabResults.Value.zone1.circleSurfacePointRightXCoordinate; +// +// if (!isRedesignRequired && surfaceLine != null) +// { +// // Set redesigned surfaceline to original, so in case no redesign is needed, the original surfaceline will be returned +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, surfaceLine); +// } +// else +// { +// double maxFractionOfDikeHeightForShoulderHeight = scenario.Location.UseNewMaxHeightShoulderAsFraction ? +// scenario.Location.NewMaxHeightShoulderAsFraction : defaultMaxFractionOfDikeHeightForShoulderHeight; +// double maxShoulderLevel = CalculateMaximumShoulderLevel(surfaceLine, maxFractionOfDikeHeightForShoulderHeight); +// while (isRedesignRequired && surfaceLine != null) +// { +// iterationIndex++; +// if (iterationIndex >= maxRedesignIterations) +// { +// throw new MaximumRedesignIterationsReachedException(); +// } +// +// GeometryPoint limitPointForShoulderDesign = surfaceLine.GetLimitPointForShoulderDesign(); +// if (exitPointXCoordinate > limitPointForShoulderDesign.X) +// { +// // If exit point of circle is after the limitPointForShoulderDesign then enlarge the shoulder +// +// // Determine new width and height for shoulder +// double shoulderHeight; +// double shoulderWidth; +// DetermineNewShoulderWidthAndHeight(scenario.Location.StabilityShoulderGrowDeltaX, +// scenario.Location.StabilityShoulderGrowSlope, surfaceLine, limitPointForShoulderDesign, out shoulderHeight, out shoulderWidth); +// +// // Create new shoulder +// var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(surfaceLine, scenario.Location); +// surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; +// surfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(shoulderWidth, shoulderHeight, false); +// +// var validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// throw new SurfaceLineException(validationError.Text); +// } +// +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, surfaceLine); +// } +// else +// { +// // If exit point of circle is in the slope (inward) of the dike or the top of the shoulder then adapt slope +// var surfaceLineSlopeAdapter = new SurfaceLineSlopeAdapter(surfaceLine, scenario.Location); +// surfaceLine = surfaceLineSlopeAdapter.ConstructNewSurfaceLine(scenario.Location.StabilitySlopeAdaptionDeltaX); +// +// var validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// throw new SurfaceLineException(validationError.Text); +// } +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, surfaceLine); +// } +// +// scenario.Location.AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(surfaceLine); +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, +// GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), +// iterationIndex, mstabDesignEmbankment); +// +// mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// safetyFactor = mStabResults.Value.zone1.safetyFactor; +// beta = scenario.GetFailureProbabilityStability(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// isRedesignRequired = IsRedesignRequired(safetyFactor, requiredSafetyFactor, betaRequired, beta); +// exitPointXCoordinate = mStabResults.Value.zone1.circleSurfacePointRightXCoordinate; +// } +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, "Succes"); +// } +// catch (Exception exception) +// { +// string errorMessage = "FAIL: " + exception.Message; +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// errorMessage = errorMessage + ";" + innerException.Message; +// innerException = innerException.InnerException; +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, errorMessage); +// // Add message to log too for output tab. +// errorMessage = scenario.Location.Name + ", scenario " + scenario.LocationScenarioID + ", " + soilProfileProbability.SoilGeometryName + " " + errorMessage; +// stabilityCalculator.ErrorMessages.Add(new LogMessage(LogMessageType.Error, this, errorMessage)); +// scenario.CalculationResult = CalculationResult.RunFailed; +// // Redesign not succesful, so no redesigned surfaceline will be returned +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, null); +// } +// foreach (var errorMessage in stabilityCalculator.ErrorMessages) +// { +// errorMessages.Add(errorMessage); +// } +// } + + /// + /// Determines the new height and width of the shoulder width + /// + /// The shoulder grow delta X. + /// The shoulder grow slope. + /// The surface line. + /// The limit point for shoulder design. + /// New height of the shoulder. + /// New width of the shoulder. +// private static void DetermineNewShoulderWidthAndHeight(double shoulderGrowDeltaX, double shoulderGrowSlope, +// SurfaceLine2 surfaceLine, GeometryPoint limitPointForShoulderDesign, out double shoulderHeight, out double shoulderWidth) +// { +// // Determine new shoulderpoint +// var newShoulderPoint = new GeometryPoint() +// { +// X = limitPointForShoulderDesign.X + shoulderGrowDeltaX, +// Z = limitPointForShoulderDesign.Z + shoulderGrowDeltaX*shoulderGrowSlope +// }; +// +// // Determine new shoulder width and height +// shoulderWidth = surfaceLine.DetermineShoulderLengthForGivenShoulderTopInside(newShoulderPoint); +// shoulderHeight = newShoulderPoint.Z - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z; +// } + + /// + /// Redesign for Stability: + /// - first do slope adaption (until required safety is reached) + /// * slope adaption is done in a range between startCoTangent and endCoTangent in steps of stepCoTangent + /// * and while the exit point of the slipcircle is in the slope (so currentCoTangent could be larger than endCoTangent + /// - than (if required safety is not reached) do shoulder adaption + /// Note: Use same slope for shoulder as for dike. + /// + /// + /// + /// + /// +// private void RedesignFirstSlopeAdaptionThenShoulderAdaption(Scenario scenario, StabilityCalculator stabilityCalculator, +// SoilGeometryProbability soilProfileProbability) +// { +// Location location = scenario.Location; +// double requiredSafetyFactor = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? +// scenario.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value; +// double betaRequired = scenario.ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope ?? +// scenario.Location.ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.Value; +// const int maxRedesignIterations = 200; +// int iterationIndex = 1; +// string previousFilename; +// SurfaceLine2 orgSurfaceLine = scenario.Location.LocalXZSurfaceLine2; +// +// // Create the file with the initial geometry to be used to determine which layers have to be defined as dike embankment material +// CreateInitialGeometry(scenario, stabilityCalculator, soilProfileProbability, orgSurfaceLine, out previousFilename); +// SurfaceLine2 surfaceLine = scenario.GetMostRecentSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName).FullDeepClone(); +// +// var mstabDesignEmbankment = new MStabDesignEmbankment +// { +// EmbankmentMaterialname = location.DikeEmbankmentMaterial, +// PreviousGeometry2DFilename = previousFilename +// }; +// +// try +// { +// double? beta; +// bool isRedesignRequired; +// double? exitPointXCoordinate; +// scenario.Location.AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(surfaceLine); +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, +// GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), +// iterationIndex, mstabDesignEmbankment); +// mstabDesignEmbankment.PreviousGeometry2DFilename = stabilityCalculator.StabilityProjectFilename; +// mstabDesignEmbankment.EmbankmentMaterialname = location.ShoulderEmbankmentMaterial; +// MStabResults? mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// double? safetyFactor = mStabResults.Value.zone1.safetyFactor; +// beta = scenario.GetFailureProbabilityStability(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// isRedesignRequired = IsRedesignRequired(safetyFactor, requiredSafetyFactor, betaRequired, beta); +// exitPointXCoordinate = mStabResults.Value.zone1.circleSurfacePointRightXCoordinate; +// +// if (!isRedesignRequired && surfaceLine != null) +// { +// // Set redesigned surfaceline to original, so in case no redesign is needed, the original surfaceline will be returned +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, surfaceLine); +// } +// else +// { +// double maxFractionOfDikeHeightForShoulderHeight = scenario.Location.UseNewMaxHeightShoulderAsFraction ? +// scenario.Location.NewMaxHeightShoulderAsFraction : defaultMaxFractionOfDikeHeightForShoulderHeight; +// double maxShoulderLevel = CalculateMaximumShoulderLevel(surfaceLine, maxFractionOfDikeHeightForShoulderHeight); +// while (isRedesignRequired && surfaceLine != null) +// { +// // First slope adaption +// double startCoTangent = location.SlopeAdaptionStartCotangent; +// double endCoTangent = location.SlopeAdaptionEndCotangent; +// double stepCoTangent = location.SlopeAdaptionStepCotangent; +// var orgCotangent = surfaceLine.GetCotangentOfInnerSlope(); +// double coTangent = startCoTangent; +// double currentCoTangent = orgCotangent; +// +// // Find out for which cotangent we want to start designing +// while (coTangent <= orgCotangent) +// { +// coTangent += stepCoTangent; +// } +// +// // Design for slope adaption +// GeometryPoint limitPointForShoulderDesign = surfaceLine.GetLimitPointForShoulderDesign(); +// while (isRedesignRequired && (coTangent < endCoTangent)) +// { +// iterationIndex++; +// if (iterationIndex >= maxRedesignIterations) +// { +// throw new MaximumRedesignIterationsReachedException(); +// } +// var surfaceLineSlopeAdapter = new SurfaceLineSlopeAdapter(surfaceLine, scenario.Location); +// // The parameter for ConstructNewSurfaceLineBySlope is the tangent of the slope, so use reciproce value +// surfaceLine = surfaceLineSlopeAdapter.ConstructNewSurfaceLineBySlope(1/coTangent); +// currentCoTangent = coTangent; +// +// var validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// throw new SurfaceLineException(validationError.Text); +// } +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName, surfaceLine); +// +// // Recalculate new surfaceline +// scenario.Location.AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(surfaceLine); +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, +// GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), +// iterationIndex, mstabDesignEmbankment); +// mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// safetyFactor = mStabResults.Value.zone1.safetyFactor; +// exitPointXCoordinate = mStabResults.Value.zone1.circleSurfacePointRightXCoordinate; +// beta = scenario.GetFailureProbabilityStability(soilProfileProbability.SoilProfile, +// soilProfileProbability.SoilGeometry2DName); +// isRedesignRequired = IsRedesignRequired(safetyFactor, requiredSafetyFactor, betaRequired, beta); +// limitPointForShoulderDesign = surfaceLine.GetLimitPointForShoulderDesign(); +// +// coTangent += stepCoTangent; +// } +// +// // Then shoulder adaption +// while (isRedesignRequired && surfaceLine != null) +// { +// iterationIndex++; +// if (iterationIndex >= maxRedesignIterations) +// { +// throw new MaximumRedesignIterationsReachedException(); +// } +// +// // Determine new width and height for shoulder +// double shoulderHeight; +// double shoulderWidth; +// DetermineNewShoulderWidthAndHeight(scenario.Location.StabilityShoulderGrowDeltaX, +// scenario.Location.StabilityShoulderGrowSlope, surfaceLine, limitPointForShoulderDesign, out shoulderHeight, out shoulderWidth); +// +// // Create new shoulder +// var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(surfaceLine, scenario.Location); +// surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; +// surfaceLineShoulderAdapter.SlopeOfNewShoulder = currentCoTangent; +// surfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(shoulderWidth, shoulderHeight, false); +// +// var validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); +// if (validationError != null) +// { +// throw new SurfaceLineException(validationError.Text); +// } +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, surfaceLine); +// +// // Recalculate new surfaceline +// scenario.Location.AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(surfaceLine); +// stabilityCalculator.Calculate(scenario, soilProfileProbability.SoilProfile, +// GetFullSoilGeometry2DName(soilProfileProbability.SoilGeometry2DName), +// iterationIndex, mstabDesignEmbankment); +// mStabResults = scenario.GetMStabResults(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); +// safetyFactor = mStabResults.Value.zone1.safetyFactor; +// beta = scenario.GetFailureProbabilityStability(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); +// isRedesignRequired = IsRedesignRequired(safetyFactor, requiredSafetyFactor, betaRequired, beta); +// limitPointForShoulderDesign = surfaceLine.GetLimitPointForShoulderDesign(); +// } +// } +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, "Succes"); +// } +// catch (Exception exception) +// { +// string errorMessage = "FAIL: " + exception.Message; +// Exception innerException = exception.InnerException; +// while (innerException != null) +// { +// errorMessage = errorMessage + ";" + innerException.Message; +// innerException = innerException.InnerException; +// } +// scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, errorMessage); +// scenario.CalculationResult = CalculationResult.RunFailed; +// // Redesign not succesful, so no redesigned surfaceline will be returned +// scenario.SetRedesignedSurfaceLine(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, null); +// } +// foreach (var errorMessage in stabilityCalculator.ErrorMessages) +// { +// errorMessages.Add(errorMessage); +// } +// } + + /// + /// Redesigns the surface line flow slide. + /// + /// The scenario. + /// The safety factor. + /// The surface line. + private void RedesignSurfaceLineFlowSlide(Scenario scenario, double? safetyFactor, ref SurfaceLine2 surfaceLine) + { + throw new DamFailureMechanismeCalculatorException("Geometry adaption not supported for Flowslide"); + } + + /// + /// Check if a stability redesign is required + /// + /// + /// + /// + /// + /// + private bool IsRedesignRequired(double? safetyFactor, double requiredSafetyFactor, double betaRequired, double? beta) + { + bool isRedesignRequired; + if (ProbabilisticType == ProbabilisticType.ProbabilisticFragility) + { + isRedesignRequired = beta > betaRequired; + } + else + { + isRedesignRequired = safetyFactor < requiredSafetyFactor; + } + return isRedesignRequired; + } + + /// + /// + /// + /// + /// +// private PipingCalculator pipingCalculatorFactory(Location location, ModelParametersForPLLines modelParametersForPLLines, PipingModelType pipingModelType, double upliftCriterion, double requiredSafetyFactorPiping, PipingProbabilisticParameters? pipingProbabilisticParameters) +// { +// switch (pipingModelType) +// { +// case PipingModelType.Bligh: +// return new PipingCalculatorBligh(modelParametersForPLLines, +// requiredSafetyFactorPiping, location.GaugePLLines, location.Gauges, upliftCriterion); +// case PipingModelType.Sellmeijer: +// PipingProbabilisticParameters? actualPipingProbabilisticParameters = null; +// if ((ProbabilisticType == ProbabilisticType.Probabilistic) || (ProbabilisticType == ProbabilisticType.ProbabilisticFragility)) +// { +// actualPipingProbabilisticParameters = pipingProbabilisticParameters; +// } +// return new PipingCalculatorSellmeijer(modelParametersForPLLines, +// requiredSafetyFactorPiping, location.GaugePLLines, location.Gauges, actualPipingProbabilisticParameters, upliftCriterion); +// case PipingModelType.Sellmeijer2Forces: +// return new PipingCalculatorSellmeijer2Forces(modelParametersForPLLines, +// requiredSafetyFactorPiping, location.GaugePLLines, location.Gauges, upliftCriterion); +// case PipingModelType.Sellmeijer4Forces: +// return new PipingCalculatorSellmeijer4Forces(modelParametersForPLLines, +// requiredSafetyFactorPiping, location.GaugePLLines, location.Gauges, upliftCriterion); +// case PipingModelType.Wti2017: +// return new PipingCalculatorWti2017(modelParametersForPLLines, +// requiredSafetyFactorPiping, location.GaugePLLines, location.Gauges, upliftCriterion); +// } +// return null; +// } + + /// + /// + /// + /// + /// +// private string GetFullSoilGeometry2DName(string soilGeometry2DName) +// { +// if (soilGeometry2DName == null) +// { +// return null; +// } +// else +// { +// string fullSoilGeometry2DName = Path.Combine(DamProjectData.ProjectMap, Path.Combine(MapForSoilGeometries2D, soilGeometry2DName)); +// return fullSoilGeometry2DName; +// } +// } + + /// + /// Get the directory where to create the piping project files + /// + /// + private static string GetPipingCalculationBaseDirectory() + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "PipingCalculation\\"); + } + + /// + /// Calculates the maximum level for the shoulder. + /// + /// The surface line. + /// The fraction of dike height to determine maximimum shoulder height. + /// + private double CalculateMaximumShoulderLevel(SurfaceLine2 surfaceLine, double maxFractionOfDikeHeightForShoulderHeight) + { + var top = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z; + var bottom = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z; + if (top - bottom <= 0) + { + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(this, "SurfaceLineShoulderAdapterMaxShoulderHeightError")); + } + double maxHeight = Math.Abs((top - bottom)*maxFractionOfDikeHeightForShoulderHeight); + return bottom + maxHeight; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointType.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointType.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPointType.cs (revision 334) @@ -0,0 +1,120 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// All types of characteristic points for a surface line. + /// + /// + public enum CharacteristicPointType + { + /// + /// The none + /// + None, + + /// + /// The surface level outside + /// + SurfaceLevelOutside = 1, // Maaiveld buitenwaarts + + /// + /// The dike toe at river + /// + DikeToeAtRiver = 5, // Teen dijk buitenwaarts + + /// + /// The shoulder top outside + /// + ShoulderTopOutside = 6, // Kruin buitenberm + + /// + /// The shoulder base outside + /// + ShoulderBaseOutside = 7, // Insteek buitenberm + + /// + /// The dike top at river + /// + DikeTopAtRiver = 8, // Kruin buitentalud + + /// + /// The dike line + /// + DikeLine = 9, // referentielijn + + /// + /// The traffic load outside + /// + TrafficLoadOutside = 10, // Verkeersbelasting kant buitenwaarts + + /// + /// The traffic load inside + /// + TrafficLoadInside = 11, // Verkeersbelasting kant binnenwaarts + + /// + /// The dike top at polder + /// + DikeTopAtPolder = 12, // Kruin binnentalud + + /// + /// The shoulder base inside + /// + ShoulderBaseInside = 13, // Insteek binnenberm + + /// + /// The shoulder top inside + /// + ShoulderTopInside = 14, // Kruin binnenberm + + /// + /// The dike toe at polder + /// + DikeToeAtPolder = 15, // Teen dijk binnenwaarts + + /// + /// The ditch dike side + /// + DitchDikeSide = 16, // Insteek sloot dijkzijde + + /// + /// The bottom ditch dike side + /// + BottomDitchDikeSide = 17, // Slootbodem dijkzijde + + /// + /// The bottom ditch polder side + /// + BottomDitchPolderSide = 18, // Slootbodem polderzijde + + /// + /// The ditch polder side + /// + DitchPolderSide = 19, // Insteek sloot polderzijde + + /// + /// The surface level inside + /// + SurfaceLevelInside = 25, // Maaiveld binnenwaarts + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2.cs (revision 334) @@ -0,0 +1,322 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Representation of a surface line with characteristic point annotations. + /// + /// Extension methods can be found in . + public class SurfaceLine2 : GeometryObject + { + private CharacteristicPointSet characteristicPoints; + private GeometryPointString geometry; + + /// + /// Create a new empty surface line. + /// + public SurfaceLine2() + { + geometry = new GeometryPointString(); + characteristicPoints = new CharacteristicPointSet + { + GeometryMustContainPoint = true + }; + LandwardDirection = LandwardDirection.PositiveX; + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSurfaceLine2"); + } + + /// + /// The geometrical description of the surface line. + /// + /// Aggregation relationship. + public GeometryPointString Geometry + { + get + { + return geometry; + } + set + { + geometry = value; + CharacteristicPoints.Geometry = geometry; + } + } + + /// + /// The characteristic point annotations for . + /// + /// Cannot be null. + public CharacteristicPointSet CharacteristicPoints + { + get + { + return characteristicPoints; + } + set + { + characteristicPoints = value; + characteristicPoints.Geometry = geometry; + } + } + + /// + /// Determines toward which direction land is expected. Value is used as reference. + /// + public LandwardDirection LandwardDirection { get; set; } + + /// + /// Define a new characteristic point on the surface line with the given characteristic + /// point annotation. + /// + /// The point to be added. Cannot be null. + /// The annotations for . + public void AddCharacteristicPoint(GeometryPoint geometryPoint, params CharacteristicPointType[] annotations) + { + if (annotations == null || annotations.Length == 0) + { + CharacteristicPoints.Add(new CharacteristicPoint + { + GeometryPoint = geometryPoint, + CharacteristicPointType = CharacteristicPointType.None + }); + } + else + { + foreach (var type in annotations) + { + + CharacteristicPoints.Add(new CharacteristicPoint + { + GeometryPoint = geometryPoint, + CharacteristicPointType = type + }); + } + } + } + + /// + /// Define a new characteristic point on the surface line with the given characteristic + /// point annotation. + /// + /// The x. + /// The y. + /// The annotations for geometryPoint with x, z/>. + public void AddCharacteristicPoint(double x, double z, params CharacteristicPointType[] annotations) + { + GeometryPoint geometryPoint = new GeometryPoint(x, z); + AddCharacteristicPoint(geometryPoint, annotations); + } + + /// + /// Find all characteristic point annotations corresponding with the given location. + /// + /// + /// + public IEnumerable GetCharacteristicPoints(GeometryPoint geometryPoint) + { + return CharacteristicPoints.Where(cp => ReferenceEquals(cp.GeometryPoint, geometryPoint)) + .Select(cp => cp.CharacteristicPointType); + } + + /// + /// Sort all points on X in a ascending manner. + /// + public void SortPoints() + { + CharacteristicPoints.Sort(); + } + + /// + /// Validates this surfaceline. + /// + /// All validation messages. + [Validate] + public ValidationResult[] Validate() + { + return new SurfaceLine2Validator().Validate(this).ToArray(); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + /// + /// Gets the geometry bounds (i.e. the extents for drawing) + /// + /// + public override GeometryBounds GetGeometryBounds() + { + if (CharacteristicPoints.Geometry != null) + { + return CharacteristicPoints.Geometry.GetGeometryBounds(); + } + return null; + } + + /// + /// Copy all characteristic point related data from another . + /// + /// Data source + public void Assign(SurfaceLine2 source) + { + SetValuesFromOtherSurfaceLine(source); + } + + /// + /// Sets the values from another surface line. + /// + /// The source. + /// If set to true, the of + /// will be deep cloned, otherwise the reference is shared. + private void SetValuesFromOtherSurfaceLine(SurfaceLine2 source, bool cloneGeometry = false) + { + CharacteristicPoints.Clear(); // clears the whole characteristic points state. + + Name = source.Name; + Geometry.Name = Name; + LandwardDirection = source.LandwardDirection; + + CharacteristicPoints.GeometryMustContainPoint = source.CharacteristicPoints.GeometryMustContainPoint; + Geometry = cloneGeometry ? source.Geometry.Clone() : source.Geometry; + + var geometryAnnotations = GetCharacteristicAnnotationsInSource(source, cloneGeometry); + + // Reconstruct annotation state from dictionary: + if (CharacteristicPoints.GeometryMustContainPoint) + { + foreach (var annotation in geometryAnnotations) + { + for (int i = 0; i < annotation.Value.Length; i++) + { + var index = -1; + for (int j = 0; j < CharacteristicPoints.Count; j++) + { + if (ReferenceEquals(CharacteristicPoints[j].GeometryPoint, annotation.Key)) + { + index = j; + break; + } + } + + if (i == 0) + { + // Reassign annotation of already created CharacteristicPoint: + CharacteristicPoints.Annotate(index, annotation.Value[i]); + } + else + { + // Add new CharacteristicPoint instance for all subsequent annotations and ensuring to keep the defined order: + CharacteristicPoints.Insert(index + i, new CharacteristicPoint(CharacteristicPoints, annotation.Key) + { + CharacteristicPointType = annotation.Value[i] + }); + } + } + } + } + else + { + foreach (var annotation in geometryAnnotations) + { + AddCharacteristicPoint((GeometryPoint)annotation.Key.Clone(), annotation.Value); + } + } + } + + /// + /// Collapses all characteristic point annotations in the given surfaceline into + /// a dictionary keyed on instances in that surfaceline + /// and their annotations. + /// + /// The referenced surfaceline. + /// True if should be a clone from + /// .; false if it should + /// take the same instance instead. + /// Dictionary keyed on instances in the surfaceline + /// that have annotations. + private Dictionary GetCharacteristicAnnotationsInSource(SurfaceLine2 source, bool cloneGeometry) + { + return CharacteristicPoints.GeometryMustContainPoint + ? GetCharacteristicAnnotationsInSource_GeometryMustContainPoints(source, cloneGeometry) + : GetCharacteristicAnnotationsInSource_GeometryMustNotContainPoints(source); + } + + /// + /// Handlers return value in case + /// is true. + /// + /// The referenced surfaceline. + /// True if should be a clone from + /// .; false if it should + /// take the same instance instead. + /// Dictionary keyed on instances in the surfaceline + /// that have annotations. + private Dictionary GetCharacteristicAnnotationsInSource_GeometryMustContainPoints(SurfaceLine2 source, bool cloneGeometry) + { + var geometryAnnotations = new Dictionary(); + for (int i = 0; i < source.Geometry.Count; i++) + { + var annotationsForPoint = source.GetCharacteristicPoints(source.Geometry.Points[i]).Where(cpt => cpt != CharacteristicPointType.None).ToArray(); + if (annotationsForPoint.Length > 0) + { + geometryAnnotations[Geometry.Points[i]] = annotationsForPoint; + } + } + return geometryAnnotations; + } + + /// + /// Handles return value in case + /// is false. + /// + /// The referenced surfaceline. + /// Dictionary keyed on instances in the surfaceline + /// that have annotations. + private static Dictionary GetCharacteristicAnnotationsInSource_GeometryMustNotContainPoints(SurfaceLine2 source) + { + var geometryAnnotations = new Dictionary(); + foreach (var characteristicPoint in source.CharacteristicPoints) + { + if (!geometryAnnotations.ContainsKey(characteristicPoint.GeometryPoint)) + { + geometryAnnotations[characteristicPoint.GeometryPoint] = + source.GetCharacteristicPoints(characteristicPoint.GeometryPoint).ToArray(); + } + } + return geometryAnnotations; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/IGeometryObject.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/IGeometryObject.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/IGeometryObject.cs (revision 334) @@ -0,0 +1,37 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// interface IGeometryObject + /// + public interface IGeometryObject + { + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + string Name { set; get; } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculator.cs (revision 334) @@ -0,0 +1,1230 @@ +// Copyright (C) Stichting Deltares 2017. 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.Reflection; +using System.Security.Policy; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Calculators.Uplift; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Gauges; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Logging; + +namespace Deltares.DamEngine.Calculators.Stability +{ + + public class StabilityCalculator : IDisposable + { + protected ModelParametersForPLLines modelParametersForPLLines; + private ProgramType programType; + private double trafficLoad; + private double minimalCircleDepth; + private double requiredSafetyFactor; + private string mstabProgramPath; + private string slopeWProgramPath; + private FailureMechanismeParamatersMStab failureMechanismeParamatersMStab; + private IList gaugePLLines; + private IList gauges; + private string stabilityProjectFilename = ""; + private List errorMessages = new List(); + + public const string StabilitySubDir = @"Stability\"; + + public StabilityCalculator(FailureMechanismeParamatersMStab failureMechanismeParamatersMStab, + ProgramType programType, + ModelParametersForPLLines modelParametersForPLLines, double trafficLoad, double minimalCircleDepth, + double requiredSafetyFactor, string mstabProgramPath, string slopeWProgramPath, + IList gaugePLLines, + IList gauges, SoilList soilList, ProbabilisticType probabilisticType) + { + this.programType = programType; + this.modelParametersForPLLines = modelParametersForPLLines; + this.trafficLoad = trafficLoad; + this.minimalCircleDepth = minimalCircleDepth; + this.requiredSafetyFactor = requiredSafetyFactor; + this.mstabProgramPath = mstabProgramPath; + this.slopeWProgramPath = slopeWProgramPath; + // need to have own instance of failureMechanismeParamatersMStab because the calculation + // makes changes to this object (e.g. failureMechanismeParamatersMStab.PLLines) + // This will not function correctly when the calculations are performed + // multi threaded (MWDAM-568) + this.failureMechanismeParamatersMStab = failureMechanismeParamatersMStab.Clone(); + this.gaugePLLines = gaugePLLines; + this.gauges = gauges; + this.SoilList = soilList; + ProbabilisticType = probabilisticType; + CalculationBaseDirectory = ""; + } + + public string CalculationBaseDirectory { get; set; } + public SoilList SoilList { get; set; } + public ProbabilisticType ProbabilisticType { get; set; } + public static string ModelSubDirectory = ""; + private MStabProject dotNetMstabProjectResults; + public PhreaticAdaptionType? NWOPhreaticAdaption { get; set; } + + /// + /// Create PLLines with selected model + /// + /// The location. + /// The surface line. + /// The soil profile. + /// Name of the soil geometry2 d. + /// The waterlevel. + /// The waterlevel low. + /// + private PLLines CreateAllPLLines(Location location, SurfaceLine2 surfaceLine, SoilProfile soilProfile, + string soilGeometry2DName, double waterlevel, double? waterlevelLow) + { + // switch (location.PLLineCreationMethod) + // { + // case PLLineCreationMethod.ExpertKnowledgeLinearInDike: + // case PLLineCreationMethod.ExpertKnowledgeRRD: + // case PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD: + // return CreateAllPLLinesExpertKnowledge(location, surfaceLine, soilProfile, soilGeometry2DName, waterlevel, waterlevelLow); + // case PLLineCreationMethod.DupuitStatic: + // return CreateAllPLLinesDupuit(); + // case PLLineCreationMethod.DupuitDynamic: + // throw new StabilityCalculationException("PL-Line creation with DupuitDynamic not yet implemented"); + // default: + // return null; + // } + return null; + } + + /// + /// Create PLLines with Dupuit model + /// + /// + private PLLines CreateAllPLLinesDupuit() + { + return null; + } + + /// + /// Create PLLines with expert knowledge + /// + /// The location. + /// The surface line. + /// The soil profile. + /// Name of the soil geometry2 d. + /// The waterlevel. + /// The waterlevel low. + /// +// private PLLines CreateAllPLLinesExpertKnowledge(Location location, SurfaceLine2 surfaceLine, SoilProfile soilProfile, +// string soilGeometry2DName, double waterlevel, double? waterlevelLow) +// { +// PLLines plLines = null; +// +// if (surfaceLine != null && surfaceLine.HasDike()) +// { +// PLLinesCreator plLineCreator = new PLLinesCreator(); +// plLineCreator.SurfaceLine = surfaceLine; +// plLineCreator.WaterLevelRiverHigh = waterlevel; +// plLineCreator.WaterLevelRiverLow = waterlevelLow; +// plLineCreator.IsUseLowWaterLevel = (failureMechanismeParamatersMStab.MStabParameters.GridPosition == MStabGridPosition.Left); +// plLineCreator.WaterLevelPolder = location.PolderLevel; +// plLineCreator.HeadInPLLine2 = location.HeadPL2; +// plLineCreator.HeadInPLLine3 = location.HeadPl3; +// plLineCreator.HeadInPLLine4 = location.HeadPl4; +// plLineCreator.ModelParametersForPLLines = this.modelParametersForPLLines; +// SoilProfile1D profile1D = soilProfile as SoilProfile1D; +// if (profile1D != null) +// { +// plLineCreator.SoilProfile = profile1D; +// plLineCreator.SoilGeometryType = SoilGeometryType.SoilGeometry1D; +// } +// else +// { +// plLineCreator.SoilGeometryType = SoilGeometryType.SoilGeometry2D; +// string mapForSoilGeometries2D = location.MapForSoilGeometries2D; +// soilGeometry2DName = Path.Combine(Path.Combine(DamProject.ProjectMap, mapForSoilGeometries2D), soilGeometry2DName); +// plLineCreator.SoilGeometry2DName = soilGeometry2DName; +// plLineCreator.SoilList = this.SoilList; +// plLineCreator.DikeEmbankmentMaterial = +// this.SoilList.GetSoilByName(location.DikeEmbankmentMaterial); +// } +// plLineCreator.GaugePLLines = this.gaugePLLines; +// plLineCreator.Gauges = this.gauges; +// plLineCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; +// // for stability this must be set to true +// plLineCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; +// plLineCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; +// plLineCreator.PlLineOffsetBelowShoulderBaseInside = location.PlLineOffsetBelowShoulderBaseInside; +// plLineCreator.PlLineOffsetBelowDikeToeAtPolder = location.PlLineOffsetBelowDikeToeAtPolder; +// plLineCreator.PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle; +// plLineCreator.PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest; +// plLineCreator.UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle; +// plLineCreator.UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest; +// plLineCreator.NWOPhreaticAdaption = NWOPhreaticAdaption; +// plLineCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; +// +// plLines = plLineCreator.CreateAllPLLines(location); +// } +// +// return plLines; +// } + + public string GetStabilityCalculationDirectory() + { + string stabilityDirectory = GetStabilityCalculationBaseDirectory(); + if (StabilityCalculator.ModelSubDirectory != "") + stabilityDirectory = Path.Combine(stabilityDirectory, StabilityCalculator.ModelSubDirectory); + if (!Directory.Exists(stabilityDirectory)) + Directory.CreateDirectory(stabilityDirectory); + return stabilityDirectory; + } + + /// + /// Get the directory where to create the MStab project files + /// + /// + private string GetStabilityCalculationBaseDirectory() + { + if (CalculationBaseDirectory == "") + { + CalculationBaseDirectory = DamProjectData.ProjectWorkingPath; + } + return Path.Combine(CalculationBaseDirectory, StabilitySubDir); + } + + /// + /// + /// + /// + /// + /// + public void ConsistencyCheck(Scenario scenario, SoilProfile1D soilProfile, string soilGeometry2DName) + { + if (soilProfile != null) + { + if (soilProfile.BottomAquiferLayer == null) + { + throw new DamFailureMechanismeCalculatorException( + String.Format("Soilprofile '{0}' does not contain aquifer layers.", soilProfile.Name)); + } + } + } + +// private void AddForbiddenZoneToMstabProject(MStabProject mStabProject, Scenario scenario, SurfaceLine2 surfaceLine) +// { +// if (failureMechanismeParamatersMStab.MStabParameters.CalculationOptions.ZonesType.Equals( +// MStabZonesType.ForbiddenZone)) +// { +// CreateForbiddenZone(scenario, surfaceLine); +// AddMissingSlipPlaneConstraintInfo(mStabProject.Stability.SlipPlaneConstraints); +// } +// } + +// private void CalculateType(string stabilityProjectFilename, Scenario scenario, SoilProfile1D soilProfile, +// string soilGeometry2DName, +// StabilityServiceAgent stabilityServiceAgent, double riverLevel, MStabDesignEmbankment mstabDesignEmbankment) +// { +// +// // +// // Here start of implementation of DesignPoint Probabilistic Calculation +// // Perform DesignPoint Probabilistic Calculation when this.ProbabilisticType == ProbabilisticType.ProbabilisticAdvanced +// // +// if (dotNetMstabProjectResults != null) +// { +// dotNetMstabProjectResults.Dispose(); +// dotNetMstabProjectResults = null; +// } +// failureMechanismeParamatersMStab.MStabParameters.CalculationOptions = new MStabCalculationOptions +// { +// MinimalCircleDepth = this.minimalCircleDepth, +// ZonesType = scenario.Location.StabilityZoneType +// }; +// SoilProfile profile; +// var surfaceLine = scenario.GetMostRecentSurfaceLine(soilProfile, +// Path.GetFileName(soilGeometry2DName)); +// //create mstabproj using .NET, without using delphi dll and xml files +// if (SelectedStabilityKernelType == StabilityKernelType.AdvancedWti) +// { +// profile = GetSoilProfileByType(soilProfile, scenario.Location.MapForSoilGeometries2D, soilGeometry2DName); +// UpdateProfileSoilsToProjectSoils(profile); +// +// var parameterValues = GetStabilityProjectParameterValues(); +// var stabilityProjectObjectCreator = new StabilityProjectObjectCreator(); +// MStabProject mStabProject = stabilityProjectObjectCreator.CreateMacroStabilityProject(scenario, profile, failureMechanismeParamatersMStab, riverLevel, parameterValues); +// AddForbiddenZoneToMstabProject(mStabProject, scenario, surfaceLine); +// RunStabilityCalculationWtiKernel(mStabProject); +// return; +// } +// //use mstab stability kernel, create mstabproj using .NET +// if (SelectedStabilityKernelType == StabilityKernelType.AdvancedDotNet) +// { +// profile = GetSoilProfileByType(soilProfile, scenario.Location.MapForSoilGeometries2D, soilGeometry2DName); +// UpdateProfileSoilsToProjectSoils(profile); +// +// var parameterValues = GetStabilityProjectParameterValues(); +// var stabilityProjectObjectCreator = new StabilityProjectObjectCreator(); +// MStabProject mStabProject = stabilityProjectObjectCreator.CreateMacroStabilityProject(scenario, +// profile, failureMechanismeParamatersMStab, riverLevel, parameterValues); +// AddForbiddenZoneToMstabProject(mStabProject, scenario, surfaceLine); +// var projectString = SaveStabilityProjectFileToString(mStabProject); +// +// RunMstabStabilityCalculation(projectString); +// return; +// } +// +// XDocument mstabXML = CreateMStabXmlDoc(stabilityProjectFilename, scenario, soilProfile, soilGeometry2DName, +// riverLevel, mstabDesignEmbankment, surfaceLine); +// mstabXML.Save(stabilityProjectFilename + ".xml"); +// +// stabilityServiceAgent.CreateProjectFile(mstabXML.ToString()); +// // use the current stability kernel +// if (SelectedStabilityKernelType == StabilityKernelType.DamClassic) +// { +// if (programType == ProgramType.SlopeW) +// { +// stabilityServiceAgent.CalculateSlopeWProject(stabilityProjectFilename); +// } +// else +// { +// stabilityServiceAgent.CalculateMStabProject(stabilityProjectFilename); +// } +// } +// // use the converted .NET stability kernel +// else if (SelectedStabilityKernelType == StabilityKernelType.DamClassicDotNet) +// { +// RunMstabStabilityCalculation(stabilityProjectFilename); +// } +// +// // use the WTI Stability Kernel, create mstabproj using delphi +// else if (SelectedStabilityKernelType == StabilityKernelType.DamClassicWti) +// { +// MStabProject mStabProject = ReadStabilityModel(stabilityProjectFilename); +// mStabProject.Stability.Location.WaterLevelRiver = riverLevel; +// AddMissingSlipPlaneConstraintInfo(mStabProject.Stability.SlipPlaneConstraints); +// mStabProject.Stability.SurfaceLine2 = surfaceLine; +// RunStabilityCalculationWtiKernel(mStabProject); +// } +// } + + /// + /// Updates the profile soils to project soils. + /// + /// The profile. + /// + private void UpdateProfileSoilsToProjectSoils(SoilProfile profile) + { + // Assign the soils from the soillist to the soils in the profile + var soilProfile2D = profile as SoilProfile2D; + if (soilProfile2D != null) + { + foreach (var surface in soilProfile2D.Surfaces) + { + var soil = SoilList.GetSoilByName(surface.Soil.Name); + if (soil == null) + { + throw new StabilityCalculationException(String.Format("No matching soil found for {0}", surface.Soil.Name)); + } + surface.Soil = soil; + } + } + else + { + var soilProfile1D = profile as SoilProfile1D; + if (soilProfile1D != null) + { + foreach (var layer in soilProfile1D.Layers) + { + var soil = SoilList.GetSoilByName(layer.Soil.Name); + if (soil == null) + { + throw new StabilityCalculationException(String.Format("No matching soil found for {0}", layer.Soil.Name)); + } + layer.Soil = soil; + } + } + else + { + throw new StabilityCalculationException(String.Format("Profile '{0}' has unexpected soilprofile type ", profile.Name)); + } + } + } + +// private void AddMissingSlipPlaneConstraintInfo(SlipplaneConstraints slipPlaneConstraints) +// { +// slipPlaneConstraints.CreateZones = +// failureMechanismeParamatersMStab.MStabParameters.ZonesType == MStabZonesType.ForbiddenZone; +// if (slipPlaneConstraints.CreateZones) +// { +// slipPlaneConstraints.SlipPlaneMinDepth = minimalCircleDepth; +// +// if (failureMechanismeParamatersMStab.MStabParameters.ForbiddenZone.IsXEntryMaxUsed) +// { +// slipPlaneConstraints.XEntryMax = failureMechanismeParamatersMStab.MStabParameters.ForbiddenZone.XEntryMax; +// } +// else +// { +// slipPlaneConstraints.XEntryMax = double.NaN; +// } +// +// if (failureMechanismeParamatersMStab.MStabParameters.ForbiddenZone.IsXEntryMinUsed) +// { +// slipPlaneConstraints.XEntryMin = failureMechanismeParamatersMStab.MStabParameters.ForbiddenZone.XEntryMin; +// } +// else +// { +// slipPlaneConstraints.XEntryMin = double.NaN; +// } +// } +// } + +// private static SoilProfile GetSoilProfileByType(SoilProfile1D soilProfile, string mapForSoilGeometries2D, string soilGeometry2DName) +// { +// SoilProfile profile = null; +// if (soilProfile != null) +// { +// profile = soilProfile; +// } +// else +// { +// var projDir = Path.GetDirectoryName(DamProjectData.ProjectWorkingPath); +// var fullPath = Path.Combine(projDir, mapForSoilGeometries2D, Path.GetFileName(soilGeometry2DName)); +// // Bka: for now, see if there is a dsx version too and if so prefer that. +// var dsxPath = Path.ChangeExtension(fullPath, ".dsx"); +// MStabProject mStab = null; +// //if (soilGeometry2DName.EndsWith(".dsx", StringComparison.OrdinalIgnoreCase)) +// if (File.Exists(dsxPath)) +// { +// try +// { +// var xmlDeserializer = new XmlDeserializer(); +// mStab = (MStabProject) xmlDeserializer.XmlDeserialize(dsxPath, typeof (MStabProject)); +// } +// catch (Exception ex) +// { +// LogManager.Add(new LogMessage(LogMessageType.Error, typeof (Converter), ex.Message)); +// } +// if (mStab != null) +// { +// profile = mStab.Stability.SoilProfile; +// mStab.Dispose(); +// } +// } +// else +// { +// var converter = new Converter(); +// mStab = new MStabProject(); +// mStab.Stability = converter.ConvertClassicMStab(fullPath); +// if (mStab.Stability.SoilProfile.Surfaces != null && mStab.Stability.SoilProfile.Surfaces.Count > 0) +// { +// // Ensure that the bottom layer of the geometry is seen as Aquifer. +// // There is no other way to get aquifer information as Delphi DGS does not work with aquifers and also not +// // with soiltypes so you can not derive anything from that too. +// mStab.Stability.SoilProfile.Surfaces[0].IsAquifer = true; +// } +// profile = mStab.Stability.SoilProfile; +// mStab.Dispose(); +// } +// } +// return profile; +// } + + /// + /// get stability project input parameters from DAM input + /// + /// +// private StabilityProjectParameterValues GetStabilityProjectParameterValues() +// { +// StabilityProjectParameterValues parameterValues = new StabilityProjectParameterValues(); +// parameterValues.MinimalCircleDepth = minimalCircleDepth; +// parameterValues.TrafficLoad = trafficLoad; +// parameterValues.PhreaticAdaptionType = NWOPhreaticAdaption != null +// ? (PhreaticAdaptionType)NWOPhreaticAdaption +// : PhreaticAdaptionType.None; +// parameterValues.PLlineCreationMethod = modelParametersForPLLines.PLLineCreationMethod; +// return parameterValues; +// } + + /// + /// run stability calculation using WTI stability kernel + /// + /// +// private void RunStabilityCalculationWtiKernel(MStabProject mStabProject) +// { +// StabilityModel stabilityModel = mStabProject.Stability; +// stabilityModel.CalculationModel = CalculationModel.RTO; +// var calculation = new Stability.Calculation2.StabilityCalculation(); +// calculation.RunCalculation(stabilityModel); +// // Todo mstabproject still to be filled with the results from the stabilityModel calculation. +// if (stabilityModel.MinimumSafetyCurve != null) +// { +// mStabProject.Result = CalculationResult.Succeeded; +// mStabProject.SlidingData = new SlidingModel() { CurrentZone = new Zone() { MinimumSafetyCurve = stabilityModel.MinimumSafetyCurve } }; +// +// } +// dotNetMstabProjectResults = mStabProject; +// } + + /// + /// run stability calculation using classic .NET kernel + /// + /// +// private void RunMstabStabilityCalculation(string projectString) +// { +// using (var calculation = new Stability.Calculation.StabilityCalculation()) +// { +// CalculationResult loadResult = calculation.Load(projectString); +// MStabProject loadedMStabProject = calculation.ClaimLoadedMStabProject(); +// if (loadResult == CalculationResult.Succeeded) +// { +// StabilityModel stabilityModel = loadedMStabProject.Stability; +// stabilityModel.CalculationModel = CalculationModel.DSerie; +// CalculationResult runResult = calculation.Run(); +// if (runResult == CalculationResult.Succeeded) +// { +// string results = null; +// CalculationResult calculationResult = calculation.GetResults(ref results); +// if (calculationResult == CalculationResult.Succeeded) +// { +// loadedMStabProject.ProcessResults(results); +// dotNetMstabProjectResults = loadedMStabProject; +// } +// else +// { +// loadedMStabProject.Dispose(); +// throw new DamFailureMechanismeCalculatorException(calculation.Messages[0].Message); +// } +// } +// } +// } +// } + + public MStabProject GetDotNetStabilityKernelResults() + { + return dotNetMstabProjectResults; + } + +// private MStabProject ReadStabilityModel(string fileName) +// { +// MStabProject project = null; +// DataEventPublisher.InvokeWithoutPublishingEvents(() => +// { +// if (!fileName.EndsWith(".dsx")) +// { +// var converter = new Converter(); +// project = new MStabProject(); +// project.Stability = converter.ConvertClassicMStab(fileName); +// } +// else +// { +// XmlDeserializer deserializer = new XmlDeserializer(); +// project = (MStabProject)deserializer.XmlDeserialize(fileName, typeof(MStabProject)); +// } +// }); +// +// return project; +// } + + /// + /// Determine a filename based on the different inout parameters + /// + /// + /// + /// + /// + /// + public static string DetermineCalculationFilename(string locationName, string scenarioName, + string soilGeometryName, int iterationIndex) + { + string calculationName; + if (iterationIndex < 0) + { + calculationName = String.Format("Loc({0})_Sce({1})_Pro({2})", locationName, scenarioName, + soilGeometryName); + } + else + { + calculationName = String.Format("Loc({0})_Sce({1})_Pro({2})_Ite({3})", locationName, scenarioName, + soilGeometryName, iterationIndex); + } + return Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); + } + + /// + /// + /// + /// + /// + /// + /// +// public void Calculate(Scenario scenario, SoilProfile1D soilProfile, string soilGeometry2DName, +// int iterationIndex) +// { +// Calculate(scenario, soilProfile, soilGeometry2DName, iterationIndex, null); +// } + + /// + /// Calculate 1 scenario + /// + /// + /// + /// + /// +// public void Calculate(Scenario scenario, SoilProfile1D soilProfile, string soilGeometry2DName, +// int iterationIndex, MStabDesignEmbankment mstabDesignEmbankment) +// { +// failureMechanismeParamatersMStab.MStabParameters.IsProbabilistic = ((this.ProbabilisticType == +// ProbabilisticType.Probabilistic) || +// (this.ProbabilisticType == +// ProbabilisticType +// .ProbabilisticFragility)); +// string soilGeometryName; +// if (!string.IsNullOrEmpty(soilGeometry2DName)) +// { +// soilGeometryName = Path.GetFileName(soilGeometry2DName); +// } +// else +// { +// soilGeometryName = soilProfile.Name; +// } +// +// string calculationName = DetermineCalculationFilename(scenario.Location.Name, scenario.LocationScenarioID, +// soilGeometryName, iterationIndex); +// +// try +// { +// StabilityServiceAgent stabilityServiceAgent = new StabilityServiceAgent(); +// stabilityServiceAgent.ProgramType = this.programType; +// stabilityServiceAgent.SlopeWExePath = this.slopeWProgramPath; +// stabilityServiceAgent.MStabExePath = this.mstabProgramPath; +// string stabilityDirectory = GetStabilityCalculationDirectory(); +// string filenameExtension = GetFilenameExtension(); +// string fileName = calculationName + filenameExtension; +// stabilityProjectFilename = Path.Combine(stabilityDirectory, fileName); +// +// MStabResults mStabResults = new MStabResults(); +// mStabResults.Init(); +// switch (ProbabilisticType) +// { +// case ProbabilisticType.Deterministic: +// { +// CalculateType(stabilityProjectFilename, scenario, soilProfile, soilGeometry2DName, +// stabilityServiceAgent, scenario.RiverLevel, mstabDesignEmbankment); +// scenario.SetFailureProbabilityStability(soilProfile, Path.GetFileName(soilGeometry2DName), null); +// break; +// } +// case ProbabilisticType.Probabilistic: +// { +// CalculateType(stabilityProjectFilename, scenario, soilProfile, soilGeometry2DName, +// stabilityServiceAgent, scenario.RiverLevel, mstabDesignEmbankment); +// double beta = 0; +// beta = stabilityServiceAgent.ExtractBeta(stabilityProjectFilename); +// scenario.SetFailureProbabilityStability(soilProfile, soilGeometry2DName, +// Probabilistic.Probabilistic.NormalDistribution(-beta)); +// break; +// } +// case ProbabilisticType.ProbabilisticFragility: +// { +// double[] waterLevels = scenario.DetermineProperWaterlevelsForProbabilisticAdvanced(); +// double[] betas = new double[3]; +// for (int i = 0; i < 3; i++) +// { +// string fileNameAdvanced = calculationName + "_WL" + i + ".sti"; +// stabilityProjectFilename = Path.Combine(stabilityDirectory, fileNameAdvanced); +// CalculateType(stabilityProjectFilename, scenario, soilProfile, soilGeometry2DName, +// stabilityServiceAgent, waterLevels[i], mstabDesignEmbankment); +// betas[i] = stabilityServiceAgent.ExtractBeta(stabilityProjectFilename); +// } +// var designPointWater = new DesignPointCalculation(); +// designPointWater.Waterlevels = waterLevels; +// designPointWater.Betas = betas; +// // Note Bka: For now, set MHW to original max water level (= river level + WaterHeightDecimeringsHoogte) and set +// // Decimate to the original WaterHeightDecimeringsHoogte. Han Best has to approve this! +// designPointWater.MHW = (double)(scenario.RiverLevel + scenario.WaterHeightDecimeringsHoogte); +// designPointWater.Decimate = (double)scenario.WaterHeightDecimeringsHoogte; +// designPointWater.Exceed = DesignPointCalculation.ExceedingSet.twoThousend; +// designPointWater.IsMaxLevelUsed = false; +// designPointWater.MaxLevel = 0; +// +// if (designPointWater.CalculateTheWaterDesignpoint()) +// { +// scenario.SetFailureProbabilityStability(soilProfile, soilGeometry2DName, +// Probabilistic.Probabilistic.NormalDistribution(-designPointWater.Beta)); +// } +// break; +// } +// } +// if (SelectedStabilityKernelType == StabilityKernelType.DamClassic) +// { +// mStabResults = stabilityServiceAgent.ExtractStabilityResults(stabilityProjectFilename); +// mStabResults = SetMStabAdministrationResults(mStabResults, iterationIndex, calculationName); +// DetermineMStabResultsEntryPoint(ref mStabResults, +// failureMechanismeParamatersMStab.MStabParameters.GridPosition); +// DetermineMStabResultsExitPoint(ref mStabResults, +// failureMechanismeParamatersMStab.MStabParameters.GridPosition); +// scenario.SetMStabResults(soilProfile, Path.GetFileName(soilGeometry2DName), mStabResults); +// } +// else +// { +// if (dotNetMstabProjectResults != null) +// { +// string stabilityResultsFileName = stabilityProjectFilename.Replace("sti", "dsx"); +// if (File.Exists(stabilityResultsFileName)) +// { +// File.Delete(stabilityResultsFileName); +// } +// var filledGeometry = dotNetMstabProjectResults.Geometry; +// // Todo het juist vullen van het Mstab project met alle waarden op de benodige plek (iom Rob) dus ook de results +// SaveStabilityProjectToDsxFile(stabilityResultsFileName, dotNetMstabProjectResults); +// mStabResults = ExtractDotNetStabilityKernelResults(); +// mStabResults = SetMStabAdministrationResults(mStabResults, iterationIndex, calculationName); +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve == null && +// !IsSlidingDataMinimumSafetyCurveAvailable()) +// { +// return; +// } +// var cn = Path.GetFileNameWithoutExtension(stabilityResultsFileName); +// mStabResults.CalculationName = cn; +// DetermineDotNetStabilityKernelResultsEntryPoint(mStabResults); +// // TODO: Exit point is not read correctly +// DetermineDotNetStabilityKernelResultsExitPoint(mStabResults); +// scenario.SetMStabResults(soilProfile, Path.GetFileName(soilGeometry2DName), mStabResults); +// } +// } +// } +// +// catch (Exception e) +// { +// throw new DamFailureMechanismeCalculatorException( +// String.Format("Error calculating stability factor for '{0}'", calculationName), e); +// } +// } + + private static MStabResults SetMStabAdministrationResults(MStabResults mStabResults, int iterationIndex, + string calculationName) + { + mStabResults.CalculationName = calculationName; + mStabResults.CalculationSubDir = StabilitySubDir; + mStabResults.IterationNumber = iterationIndex; + if (StabilityCalculator.ModelSubDirectory != "") + { + mStabResults.CalculationSubDir = Path.Combine(mStabResults.CalculationSubDir, + StabilityCalculator.ModelSubDirectory); + } + return mStabResults; + } + + +// private bool IsSlidingDataMinimumSafetyCurveAvailable() +// { +// var notAvailable = dotNetMstabProjectResults.SlidingData == null || +// dotNetMstabProjectResults.SlidingData.CurrentZone == null || +// dotNetMstabProjectResults.SlidingData.CurrentZone.MinimumSafetyCurve == null; +// return !notAvailable; +// } + +// private MStabResults ExtractDotNetStabilityKernelResults() +// { +// MStabResults mStabResults = new MStabResults(); +// if (dotNetMstabProjectResults.Stability.HasZonePlot) +// { +// throw new NotImplementedException("Zoning features are not implementen yet in the Wti Stability kernel"); +// } +// else +// { +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve == null) +// { +// if (!IsSlidingDataMinimumSafetyCurveAvailable()) +// { +// return mStabResults; +// } +// else +// { +// dotNetMstabProjectResults.Stability.MinimumSafetyCurve = +// dotNetMstabProjectResults.SlidingData.CurrentZone.MinimumSafetyCurve; +// } +// } +// double safetyFactor = dotNetMstabProjectResults.Stability.MinimumSafetyCurve.SafetyFactor; +// mStabResults.zone1.safetyFactor = safetyFactor; +// mStabResults.zone1.circleSurfacePointLeftXCoordinate = dotNetMstabProjectResults.Stability.MinimumSafetyCurve.LeftPoint.X; +// mStabResults.zone1.circleSurfacePointRightXCoordinate = dotNetMstabProjectResults.Stability.MinimumSafetyCurve.RightPoint.X; +// if (dotNetMstabProjectResults.Stability.ModelOption == ModelOptions.UpliftVan || +// dotNetMstabProjectResults.Stability.ModelOption == ModelOptions.UpliftSpencer) +// { +// mStabResults.zone1.safetyFactor = safetyFactor / 1.05; +// } +// } +// return mStabResults; +// } + +// private void DetermineDotNetStabilityKernelResultsExitPoint(MStabResults results) +// { +// if (dotNetMstabProjectResults.Stability.GridOrientation == GridOrientation.Outwards) +// { +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve.LeftPoint != null) +// { +// // Outward stability +// results.zone1.exitPointXCoordinate = dotNetMstabProjectResults.Stability.MinimumSafetyCurve.LeftPoint.X; +// if (results.zone2.HasValue) +// { +// } +// } +// } +// else +// { +// // Inward stability +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve.RightPoint != null) +// { +// results.zone1.exitPointXCoordinate = dotNetMstabProjectResults.Stability.MinimumSafetyCurve.RightPoint.X; +// if (results.zone2.HasValue) +// { +// } +// } +// } +// } + +// private void DetermineDotNetStabilityKernelResultsEntryPoint(MStabResults mStabResults) +// { +// if (dotNetMstabProjectResults.Stability.GridOrientation == GridOrientation.Outwards) +// { +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve.RightPoint != null) +// { +// mStabResults.zone1.entryPointXCoordinate = +// dotNetMstabProjectResults.Stability.MinimumSafetyCurve.RightPoint.X; +// if (mStabResults.zone2.HasValue) +// { +// /*MStabResultsSingleZone zone = mstabResults.zone2.Value; +// zone.entryPointXCoordinate = zone.circleSurfacePointRightXCoordinate; +// mstabResults.zone2 = zone;*/ +// } +// } +// } +// else +// { +// if (dotNetMstabProjectResults.Stability.MinimumSafetyCurve.LeftPoint != null) +// { +// // Inward stability +// mStabResults.zone1.entryPointXCoordinate = +// dotNetMstabProjectResults.Stability.MinimumSafetyCurve.LeftPoint.X; +// if (mStabResults.zone2.HasValue) +// { +// /*MStabResultsSingleZone zone = mstabResults.zone2.Value; +// zone.entryPointXCoordinate = zone.circleSurfacePointLeftXCoordinate; +// mstabResults.zone2 = zone;*/ +// } +// } +// } +// } + + /// + /// Determine filename extension according to which failuremechanism is used + /// + /// + public string GetFilenameExtension() + { + string filenameExtension; + if (programType == ProgramType.SlopeW) + { + filenameExtension = ".xml"; + } + else + { + filenameExtension = ".sti"; + } + return filenameExtension; + } + + /// + /// Depending on outward/inward stability (position of grid) the entrypoint of the slipcricle is determined + /// + /// + /// + private void DetermineMStabResultsEntryPoint(ref MStabResults mstabResults, MStabGridPosition mstabGridPosition) + { + if (mstabGridPosition == MStabGridPosition.Left) + { + // Outward stability + mstabResults.zone1.entryPointXCoordinate = mstabResults.zone1.circleSurfacePointRightXCoordinate; + if (mstabResults.zone2.HasValue) + { + MStabResultsSingleZone zone = mstabResults.zone2.Value; + zone.entryPointXCoordinate = zone.circleSurfacePointRightXCoordinate; + mstabResults.zone2 = zone; + } + } + else + { + // Inward stability + mstabResults.zone1.entryPointXCoordinate = mstabResults.zone1.circleSurfacePointLeftXCoordinate; + if (mstabResults.zone2.HasValue) + { + MStabResultsSingleZone zone = mstabResults.zone2.Value; + zone.entryPointXCoordinate = zone.circleSurfacePointLeftXCoordinate; + mstabResults.zone2 = zone; + } + } + } + + + /// + /// Depending on outward/inward stability (position of grid) the exitpoint of the slipcricle is determined + /// + /// + /// + private void DetermineMStabResultsExitPoint(ref MStabResults mstabResults, MStabGridPosition mstabGridPosition) + { + if (mstabGridPosition == MStabGridPosition.Left) + { + // Outward stability + mstabResults.zone1.exitPointXCoordinate = mstabResults.zone1.circleSurfacePointLeftXCoordinate; + if (mstabResults.zone2.HasValue) + { + MStabResultsSingleZone zone = mstabResults.zone2.Value; + zone.exitPointXCoordinate = zone.circleSurfacePointLeftXCoordinate; + mstabResults.zone2 = zone; + } + } + else + { + // Inward stability + mstabResults.zone1.exitPointXCoordinate = mstabResults.zone1.circleSurfacePointRightXCoordinate; + if (mstabResults.zone2.HasValue) + { + MStabResultsSingleZone zone = mstabResults.zone2.Value; + zone.exitPointXCoordinate = zone.circleSurfacePointRightXCoordinate; + mstabResults.zone2 = zone; + } + } + } + + private void CreateForbiddenZone(Scenario scenario, SurfaceLine2 surfaceLine) + { + var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + // Zonestype is ForbiddenZone; TODO: Combine with code in StabilityCalculator? + double maxZoneX = dikeTopAtPolder.X + + scenario.Location.ForbiddenZoneFactor * (surfaceLine.GetDikeToeInward().X - dikeTopAtPolder.X); + failureMechanismeParamatersMStab.MStabParameters.ForbiddenZone = new MStabForbiddenZone + { + IsXEntryMinUsed = false, + XEntryMin = 0.0, + IsXEntryMaxUsed = true, + XEntryMax = maxZoneX + }; + } + + /// + /// Create XML definition for Stability calculation + /// + /// + /// + /// + /// + /// + /// + /// + /// +// public XDocument CreateMStabXmlDoc(string mstabProjectFilename, Scenario scenario, SoilProfile soilProfile, +// string soilGeometry2DName, double riverLevel, +// MStabDesignEmbankment mstabDesignEmbankment, SurfaceLine2 surfaceLine) +// { +// SoilProfile1D profile1D = soilProfile as SoilProfile1D; +// SoilProfile2D profile2D = soilProfile as SoilProfile2D; +// ConsistencyCheck(scenario, profile1D, soilGeometry2DName); +// failureMechanismeParamatersMStab.Location = scenario.Location; +// if (profile1D != null) +// { +// failureMechanismeParamatersMStab.SoilProfile = profile1D; +// // 1d-geometry +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.SoilGeometryType = +// SoilGeometryType.SoilGeometry1D; +// } +// else +// { +// // 2d-geometry +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.SoilGeometryType = +// SoilGeometryType.SoilGeometry2D; +// } +// // Geometry Creation Options +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.SoilGeometry2DFilename = +// soilGeometry2DName; +// +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.MaterialForDike = +// scenario.Location.DikeEmbankmentMaterial; +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.MaterialForShoulder = +// scenario.Location.ShoulderEmbankmentMaterial; +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.IsUseOriginalPLLineAssignments = +// scenario.Location.IsUseOriginalPLLineAssignments; +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.IsDesign = +// (mstabDesignEmbankment != null); +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.XOffsetSoilGeometry2DOrigin = +// -scenario.Location.XSoilGeometry2DOrigin; +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.PLLineAssignment = +// CalculationHelper.PLLineCreationMethod2PLLineAssignment(scenario.Location.PLLineCreationMethod); +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = +// scenario.Location.IntrusionVerticalWaterPressure.Value; +// failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.PenetrationLength = +// scenario.Location.PenetrationLength; +// // End of Geometry Creation Options +// // Design options +// failureMechanismeParamatersMStab.Design = mstabDesignEmbankment; +// +// failureMechanismeParamatersMStab.SurfaceLine = surfaceLine; +// failureMechanismeParamatersMStab.RiverLevel = riverLevel; // scenario.RiverLevel; +// failureMechanismeParamatersMStab.DikeTableHeight = +// scenario.DikeTableHeight ?? surfaceLine.GetDefaultDikeTableHeight() ?? 0; +// failureMechanismeParamatersMStab.TrafficLoad = this.trafficLoad; +// +// // Horizontal balance; TODO: Combine with code in StabilityCalculation +// if (failureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.HorizontalBalance) +// { +// if (profile1D == null) +// { +// throw new DamFailureMechanismeCalculatorException( +// "Model horizontal balance does not support 2d-geometries"); +// } +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea = new HorizontalBalanceArea(); +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.XLeft = +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.XRight = +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.YTop = riverLevel; +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.YBottom = +// profile1D.InBetweenAquiferLayer != null +// ? profile1D.InBetweenAquiferLayer.TopLevel +// : profile1D.BottomAquiferLayer.TopLevel; +// int planeCount = +// (int)(Math.Round((failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.YTop - +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.YBottom) / 0.25)); +// failureMechanismeParamatersMStab.MStabParameters.HorizontalBalanceArea.PlaneCount = Math.Min(planeCount, 50); +// +// } +// +// // Zonestype is ZoneAreas; TODO: Combine with code in StabilityCalculation +// var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); +// if ( +// failureMechanismeParamatersMStab.MStabParameters.CalculationOptions.ZonesType.Equals( +// MStabZonesType.ZoneAreas)) +// { +// double? dikeTableHeight = scenario.DikeTableHeight ?? surfaceLine.GetDefaultDikeTableHeight() ?? null; +// if (!dikeTableHeight.HasValue) +// throw new DamFailureMechanismeCalculatorException("Surface line has no dike table height."); +// failureMechanismeParamatersMStab.MStabParameters.ZoneAreas = new MStabZoneAreas +// { +// DikeTableHeight = dikeTableHeight.Value, +// DikeTableWidth = scenario.Location.ZoneAreaRestSlopeCrestWidth, +// SafetyFactorZone1A = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? this.requiredSafetyFactor, +// SafetyFactorZone1B = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? this.requiredSafetyFactor, +// XCoordinateDikeTopAtPolder = dikeTopAtPolder.X, +// XCoordinateDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X, +// XCoordinateStartRestProfile = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X +// }; +// } +// +// if (failureMechanismeParamatersMStab.MStabParameters.CalculationOptions.ZonesType.Equals( +// MStabZonesType.ForbiddenZone)) +// { +// CreateForbiddenZone(scenario, surfaceLine); +// } +// +// // Make sure riverlevel is correct with respect to surfaceline +// double riverLevelLow = double.NaN; +// if (failureMechanismeParamatersMStab.MStabParameters.GridPosition == MStabGridPosition.Left && scenario.RiverLevelLow.HasValue) +// { +// riverLevelLow = scenario.RiverLevelLow.Value; +// } +// double? riverLevelHigh = riverLevel; +// var surfaceLevelOutside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); +// if (riverLevelHigh < surfaceLevelOutside.Z) +// { +// var riverLevelHighIsBelowSurfaceLevelOutside = Path.GetFileName(mstabProjectFilename) + ": " + +// LocalizationManager.GetTranslatedText(this.GetType(), +// "riverLevelHighIsBelowSurfaceLevelOutside"); +// LogMessage logMessage = new LogMessage(LogMessageType.Warning, null, +// String.Format(riverLevelHighIsBelowSurfaceLevelOutside, riverLevelHigh, +// surfaceLevelOutside.Z)); +// errorMessages.Add(logMessage); +// } +// +// var currentSurfaceLine = scenario.GetMostRecentSurfaceLine(soilProfile, Path.GetFileName(soilGeometry2DName)); +// if (currentSurfaceLine == null) +// { +// currentSurfaceLine = surfaceLine; +// } +// if (SelectedStabilityKernelType == StabilityKernelType.AdvancedWti || +// SelectedStabilityKernelType == StabilityKernelType.AdvancedDotNet) +// { +// var lphreaticAdaptionType = NWOPhreaticAdaption != null +// ? (PhreaticAdaptionType)NWOPhreaticAdaption +// : PhreaticAdaptionType.None; +// var stabilityProjectObjectCreator = new StabilityProjectObjectCreator(); +// failureMechanismeParamatersMStab.PLLines = stabilityProjectObjectCreator.CreateAllPlLinesUsingWaternetCreator(scenario.Location, +// currentSurfaceLine, soilProfile, lphreaticAdaptionType, modelParametersForPLLines.PenetrationLength, riverLevelHigh.Value, modelParametersForPLLines.PLLineCreationMethod, riverLevelLow); +// } +// else +// { +// failureMechanismeParamatersMStab.PLLines = CreateAllPLLines(scenario.Location, currentSurfaceLine, +// soilProfile, soilGeometry2DName, riverLevelHigh.Value, riverLevelLow); +// } +// // Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculation +// if (this.failureMechanismeParamatersMStab.MStabParameters.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 +// var upliftLocationAndResult = this.GetLocationWithLowestUpliftFactor(currentSurfaceLine, soilProfile, +// soilGeometry2DName, +// failureMechanismeParamatersMStab.PLLines, +// scenario.Location); +// double upliftCriterion = +// scenario.GetUpliftCriterionStability(scenario.Location.ModelFactors.UpliftCriterionStability); +// bool isUplift = !(upliftLocationAndResult == null) && +// (upliftLocationAndResult.UpliftFactor < upliftCriterion); +// double xCoordinateLastUpliftPoint = isUplift +// ? upliftLocationAndResult.X +// : currentSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; +// var nonWaterRetaining2 = currentSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2); +// if (nonWaterRetaining2 != +// null) +// { +// xCoordinateLastUpliftPoint = +// nonWaterRetaining2.X; +// } +// failureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition.XCoordinateLastUpliftPoint = +// xCoordinateLastUpliftPoint; +// } +// +// failureMechanismeParamatersMStab.MStabParameters.ProjectFileName = mstabProjectFilename; +// failureMechanismeParamatersMStab.MStabParameters.SoilDatabaseName = scenario.Location.SoildatabaseName; +// +// if (!failureMechanismeParamatersMStab.IsComplete) +// { +// throw new Exception("Not all required data is available"); +// } +// DamMStabAssembler assembler = new DamMStabAssembler(); +// XDocument mstabXML = assembler.CreateDataTransferObject(failureMechanismeParamatersMStab); +// return mstabXML; +// } + + /// + /// Determines which MStabResults of 2, contains the smallest safety factor + /// + /// + /// + /// MStab results with the minimum safety factor + public static MStabResults MinMStabResults(MStabResults mStabResults1, MStabResults mStabResults2) + { + if (mStabResults2.zone1.safetyFactor < mStabResults1.zone1.safetyFactor) + { + return mStabResults2; + } + else + { + return mStabResults1; + } + } + + /// + /// This is the place where we determine where the DGeoStability executable is located + /// + public static string MStabExePath + { + get + { + return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + @"DGeoStability.exe"); + } + } + + public string StabilityProjectFilename + { + get { return stabilityProjectFilename; } + } + + public List ErrorMessages + { + get { return errorMessages; } + set { errorMessages = value; } + } + + // option of various computation kernel types + public StabilityKernelType SelectedStabilityKernelType { get; set; } + + /// + /// save stability project to dsx file + /// + /// + /// +// public void SaveStabilityProjectToDsxFile(string fileName, MStabProject project) +// { +// DataEventPublisher.InvokeWithoutPublishingEvents(() => +// { +// var xmlSerializer = new XmlSerializer(); +// xmlSerializer.Serialize(project, fileName, AppDomain.CurrentDomain.BaseDirectory + "Mstab.xsl"); +// }); +// } + +// private string SaveStabilityProjectFileToString(object stabilityProject) +// { +// var xmlSerializer = new XmlSerializer(); +// return xmlSerializer.SerializeToString(stabilityProject); +// } + + /// + /// Gets the location with lowest uplift factor. + /// + /// The surface line. + /// The soil profile. + /// Name of the soil geometry2 D. + /// The pl lines. + /// The location. + /// + public UpliftLocationAndResult GetLocationWithLowestUpliftFactor(SurfaceLine2 surfaceLine, + SoilProfile soilProfile, string soilGeometry2DName, PLLines plLines, Location location) + { + var profile1D = soilProfile as SoilProfile1D; + var profile2D = soilProfile as SoilProfile2D; + UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator() + { + SurfaceLine = surfaceLine, + SoilProfile = profile1D, + SoilProfile2D = profile2D, + SoilGeometry2DName = soilGeometry2DName, + SoilList = location.SoilList, + DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), + PLLines = plLines, + XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin + }; + return upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); + } + + public void Dispose() + { + if (dotNetMstabProjectResults != null) + { + dotNetMstabProjectResults.Dispose(); + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/UpliftRWEvaluator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/UpliftRWEvaluator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/UpliftRWEvaluator.cs (revision 334) @@ -0,0 +1,150 @@ +// Copyright (C) Stichting Deltares 2017. 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.Calculators.PlLinesCreator; +using Deltares.DamEngine.Calculators.Uplift; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.RWScenarios; + +namespace Deltares.DamEngine.Calculators.Dikes_Assessment_Regional +{ + public class UpliftRWEvaluator : RWEvaluator + { + private DikeDrySensitivity dikeDrySensitivity = DikeDrySensitivity.None; + private LoadSituation loadSituation = LoadSituation.Wet; + private HydraulicShortcutType hydraulicShortcutType = HydraulicShortcutType.NoHydraulicShortcut; + + public UpliftRWEvaluator() + { + } + + public override Enum Evaluate(Location location, SoilGeometry soilGeometry, params Enum[] previousChoices) + { + base.Evaluate(location, soilGeometry, previousChoices); + + Dictionary choices = new Dictionary(); + foreach (Enum enumValue in previousChoices) + { + if (enumValue != null) + { + choices[enumValue.GetType()] = enumValue; + } + } + dikeDrySensitivity = (DikeDrySensitivity)choices[typeof(DikeDrySensitivity)]; + loadSituation = (LoadSituation)choices[typeof(LoadSituation)]; + hydraulicShortcutType = (HydraulicShortcutType) choices[typeof (HydraulicShortcutType)]; + // determine uplift here + + double? upliftFactor = GetLowestUpliftFactor(); + UpliftType upliftType = UpliftType.NoUplift; + if (upliftFactor != null) + { + if (upliftFactor.Value < location.ModelFactors.UpliftCriterionStability) + { + return UpliftType.Uplift; + } + } + return upliftType; + } + + /// + /// Create PL-lines + /// + /// + private PLLines CreatePLLines() + { + PLLinesCreator plLinesCreator = new PLLinesCreator(); + double waterLevel = GetBoezemLevel(); + + plLinesCreator.WaterLevelRiverHigh = waterLevel; + plLinesCreator.HeadInPLLine2 = location.HeadPL2; + plLinesCreator.HeadInPLLine3 = location.HeadPl3; + plLinesCreator.HeadInPLLine4 = location.HeadPl4; + + plLinesCreator.SurfaceLine = location.LocalXZSurfaceLine2; + plLinesCreator.WaterLevelPolder = location.PolderLevel; + plLinesCreator.ModelParametersForPLLines = location.CreateModelParametersForPLLines(); + plLinesCreator.SoilProfile = soilGeometry.SoilProfile; + plLinesCreator.SoilGeometry2DName = null; + plLinesCreator.SoilGeometryType = SoilGeometryType.SoilGeometry1D; + plLinesCreator.GaugePLLines = null; + plLinesCreator.Gauges = null; + plLinesCreator.GaugeMissVal = 0.0; + plLinesCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; // for stability this must set to true + plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; + plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; + plLinesCreator.DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(); + plLinesCreator.IsUseOvenDryUnitWeight = (dikeDrySensitivity == DikeDrySensitivity.Dry); + plLinesCreator.IsHydraulicShortcut = (hydraulicShortcutType == HydraulicShortcutType.HydraulicShortcut); + plLinesCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; + +// PLLines plLines = plLinesCreator.CreateAllPLLines(location); +// return plLines; ##Bka + return null; + } + + /// + /// Determine boezemlevel according to loadsituation + /// + /// + private double GetBoezemLevel() + { + double boezemLevel = 0.0; + switch (loadSituation) + { + case LoadSituation.Wet: + boezemLevel = location.BoezemLevelTp; + break; + case LoadSituation.Dry: + boezemLevel = location.BoezemLevelHbp; + break; + } + return boezemLevel; + } + + /// + /// Determine where lowest uplift factor occurs and the value of that factor + /// + /// + private double? GetLowestUpliftFactor() + { + + UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator() + { + SurfaceLine = location.LocalXZSurfaceLine2, + SoilProfile = soilGeometry.SoilProfile, + SoilGeometry2DName = null, + DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), + PLLines = CreatePLLines(), + IsUseOvenDryUnitWeight = (dikeDrySensitivity == DikeDrySensitivity.Dry), + XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin + }; + UpliftLocationAndResult upliftLocationAndResult = upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); + if (upliftLocationAndResult != null) + return upliftLocationAndResult.UpliftFactor; + else + return null; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/LineHelper.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/LineHelper.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/LineHelper.cs (revision 334) @@ -0,0 +1,165 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Helper class for Line objects + /// + public static class LineHelper + { + /// + /// Calculate intersection between two lines (strict interpolation) + /// + /// + /// + /// + /// + public static bool GetStrictIntersectionPoint(Line line1, Line line2, ref GeometryPoint intersectPoint) + { + var point1 = new Point2D(line1.BeginPoint.X, line1.BeginPoint.Z); + var point2 = new Point2D(line1.EndPoint.X, line1.EndPoint.Z); + var point3 = new Point2D(line2.BeginPoint.X, line2.BeginPoint.Z); + var point4 = new Point2D(line2.EndPoint.X, line2.EndPoint.Z); + + Point2D ip; + var res = Routines2D.DetermineIf2DLinesIntersectStrickly(point1.X, point1.Z, point2.X, point2.Z, + point3.X, point3.Z, point4.X, point4.Z, out ip); + if (ip != null) + { + intersectPoint.X = ip.X; + intersectPoint.Z = ip.Z; + } + return res == LineIntersection.Intersects; + } + + /// + /// This method uses constant extrapolation from the start point to the negative X direction and + /// from the end point to the positive X direction. Then the method tries to find intersection + /// points with the circle on that line. + /// + /// Circle's middle point X value + /// Circle's middle point Z value + /// Circle's radius + /// Point collection which defines a line. Extrapolation is performed at the start and end points. + /// Intersections of this line extrapolated to the negative and positive X with the circle. + public static List ExtendedSurfaceIntersectionPointsWithCircle(double xMid, double zMid, double radius, IList pointss) + { + var points = pointss.Where(p => !double.IsNaN(p.X)).ToList(); + if (points.Count >= 2) + { + var requiredMinSurfacePointX = xMid - radius; + var requiredMaxSurfacePointX = xMid + radius; + if (requiredMinSurfacePointX < points[0].X) + { + points.Insert(0, new Point2D{ X = requiredMinSurfacePointX, Z = points[0].Z}); + } + if (requiredMaxSurfacePointX > points[points.Count - 1].X) + { + points.Insert(points.Count, new Point2D{ X = requiredMaxSurfacePointX, Z = points[points.Count - 1].Z}); + } + } + return IntersectionPointsWithCircle(xMid, zMid, radius, points); + } + + /// + /// Intersections the points with circle. + /// + /// The x mid. + /// The z mid. + /// The radius. + /// The points. + /// + public static List IntersectionPointsWithCircle(double xMid, double zMid, double radius, IList points) + { + var result = new List(); + if (points.Count >= 2) + { + for (int pointIndex = 0; pointIndex < points.Count - 1; pointIndex++) + { + var start = points[pointIndex]; + var end = points[pointIndex + 1]; + var outOfReach = ((Math.Max(start.X, end.X) < xMid - radius) || + (Math.Min(start.X, end.X) > xMid + radius) || + (Math.Max(start.Z, end.Z) < zMid - radius) || + (Math.Min(start.Z, end.Z) > zMid + radius)); + if (!outOfReach) + { + var line = new Line + { + BeginPoint = start, EndPoint = end + }; + result.AddRange(Intersect_Circle_line(xMid, zMid, radius, line)); + } + } + } + return result; + } + + /// + /// Intersects the circle line. + /// + /// The xm. + /// The ym. + /// The r. + /// The line. + /// + private static List Intersect_Circle_line(double xm, double ym, double r, Line line) + { + return Routines2D.IntersectCircleline(xm, ym, r, line.BeginPoint.X, line.EndPoint.X, line.BeginPoint.Z, line.EndPoint.Z); + } + + public static GeometryPoint GetIntersectionPointWithExtrapolation(GeometryPoint p1, GeometryPoint p2, GeometryPoint p3, GeometryPoint p4) + { + return IntersectionPointWithExtrapolation(p1, p2, p3, p4); + } + + /// + /// Determines the intersection point of two lines, allowing the intersection point being extrapolated. + /// + /// + /// + /// + /// + /// Intersection point or null (parallel lines) + private static GeometryPoint IntersectionPointWithExtrapolation(GeometryPoint p1, GeometryPoint p2, GeometryPoint p3, GeometryPoint p4) + { + GeometryPoint intersectPoint = null; + + var point1 = new Point2D(p1.X, p1.Z); + var point2 = new Point2D(p2.X, p2.Z); + var point3 = new Point2D(p3.X, p3.Z); + var point4 = new Point2D(p4.X, p4.Z); + + var ip = new Point2D(); + var res = Routines2D.DetermineIf2DLinesIntersectWithExtrapolation(point1, point2, point3, point4, ref ip); + if (ip != null) + { + intersectPoint = new GeometryPoint(ip.X, ip.Z); + } + return intersectPoint; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectCalculationSpecification.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectCalculationSpecification.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectCalculationSpecification.cs (revision 334) @@ -0,0 +1,153 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + /// + /// Represents the calculation specifications at project level for DAM. + /// These are the main choices that specify the calculation + /// + public class DamProjectCalculationSpecification + { + private readonly List damCalculationSpecifications; + + private static AnalysisType selectedAnalysisType = AnalysisType.AdaptGeometry; + private ProbabilisticType selectedProbabilisticType; + private DamFailureMechanismeCalculationSpecification currentSpecification; + private StabilityKernelType selectedStabilityKernelType; + + public DamProjectCalculationSpecification() + { + damCalculationSpecifications = new List(); + //waterLevelTimeSeriesFileName = @"d:\src\delftgeosystems\trunk\data\Dam\RRD\Groot Salland\DAM UI Testdata\inputshortstart_dam.xml"; + } + + [Validate] + public List DamCalculationSpecifications + { + get + { + + if (currentSpecification != null && currentSpecification.FailureMechanismSystemType != FailureMechanismSystemType.Piping) + { + selectedProbabilisticType = ProbabilisticType.Deterministic; + } + return damCalculationSpecifications; + } + } + + /// + /// Gets or sets the analysis type for serialization purpose only. + /// This "dummy" property is and must be only used for serialization/deserialization purposes as the real static property + /// SelectedAnalysisType is NOT serialized. This is way its name is deliberately strange. + /// + /// + /// The analysis type for serialization purpose only. + /// + public AnalysisType AnalysisTypeForSerializationPurposeOnly + { + get + { + return selectedAnalysisType; + } + set + { + selectedAnalysisType = value; + } + + } + + /// + /// Gets or sets the type of the selected analysis. + /// + /// + /// The type of the selected analysis. + /// + public static AnalysisType SelectedAnalysisType + { + get { return selectedAnalysisType; } + set + { + selectedAnalysisType = value; + } + } + + public ProbabilisticType SelectedProbabilisticType + { + get { return selectedProbabilisticType; } + set + { + selectedProbabilisticType = value; + DamFailureMechanismeCalculationSpecification.ProbabilisticType = selectedProbabilisticType; + } + } + + [XmlIgnore] + public DamFailureMechanismeCalculationSpecification CurrentSpecification + { + get + { + if (currentSpecification == null && damCalculationSpecifications.Count > 0) + { + currentSpecification = damCalculationSpecifications[0]; + } + + return currentSpecification; + } + set + { + currentSpecification = value; + } + } + + public StabilityKernelType SelectedStabilityKernelType + { + get { return selectedStabilityKernelType; } + set + { + selectedStabilityKernelType = value; + if (currentSpecification != null) + { + currentSpecification.StabilityKernelType = selectedStabilityKernelType; + } + } + } + + [Validate] + public ValidationResult[] Validate() + { + if (damCalculationSpecifications.Count > 1) + { + return new[]{ new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText(this, "MaxOneCalculationSpecification"), + this)}; + } + else + { + return new ValidationResult[0]; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/PipingResults.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/PipingResults.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Results/PipingResults.cs (revision 334) @@ -0,0 +1,42 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General.Results +{ + public struct PipingResults + { + public string CalculationName { get; set; } + public string CalculationSubDir { get; set; } + public double? BlighPipingFactor { get; set; } + public double? BlighHCritical { get; set; } + public double? Sellmeijer2ForcesPipingFactor { get; set; } + public double? Sellmeijer2ForcesHCritical { get; set; } + public double? Sellmeijer4ForcesPipingFactor { get; set; } + public double? Sellmeijer4ForcesHCritical { get; set; } + public double? SellmeijerPipingFactor { get; set; } + public double? SellmeijerHCritical { get; set; } + public double? Wti2017PipingFactor { get; set; } + public double? Wti2017HCritical { get; set; } + public double? PipingExitPointX { get; set; } + public double? UpliftFactor { get; set; } + public double? HeaveFactor { get; set; } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Probabilistic/Enumerations.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Probabilistic/Enumerations.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Probabilistic/Enumerations.cs (revision 334) @@ -0,0 +1,86 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Probabilistic +{ + public enum ProbabilisticMethod + { + FORM, + MonteCarlo, // Crude MonteCarlo + DirectionalSampling, + NumericalIntegration, + ImportanceSampling, // MonteCarlo Importance sampling + FOSM + } + + public enum DistributionType + { + Deterministic = 0, + Uniform = 1, + Triangular = 11, + Normal = 2, + LogNormal = 3, // will convert to log normal II in HydraRing + + //[Label("Log normal II")] + //LogNormalII = 31, + + Exponential = 4, + Gamma = 5, + Beta = 6, + Frechet = 7, + Weibull = 8, + Gumbel = 9, + Rayleigh =10, + Pareto = 16, + TruncatedNormal = 12, + Table = 13, + StudentT = 14 + } + + public enum StartMethodType + { + StartZero = 1, + StartOne = 2, + StartGivenVector = 3, + StartRaySearch = 4, + StartSphereSearch = 5 + } + + public enum ProbabilisticOutputType + { + Model, + DesignPoint, + BandWidth + } + + public enum QualitativeValue + { + Low, + Medium, + High + } + + public enum SourceLocationType + { + Internal, + External + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryObject.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryObject.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryObject.cs (revision 334) @@ -0,0 +1,86 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Base class for all Geometry objects + /// + [Serializable] + public abstract class GeometryObject : IGeometryObject, IName + { + private string name = ""; + + /// + /// Sets the name. + /// + /// The new name. + public virtual void SetName(string newName) + { + name = newName; // TODO: Name is virtual. Is this really expected behavior? + } + + /// + /// Gets the geometry bounds. + /// + /// + public virtual GeometryBounds GetGeometryBounds() + { + return null; + } + + #region IGeometryObject Members + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public virtual string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + #endregion + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Design/Scenario.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Design/Scenario.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Design/Scenario.cs (revision 334) @@ -0,0 +1,1400 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Specialized; +using System.ComponentModel; +using System.Globalization; +using System.Linq.Expressions; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Design +{ + + /// + /// Does uplift occur or not + /// + public struct UpliftSituation + { + public bool IsUplift; + public double Pl3MinUplift; + public double Pl3HeadAdjusted; + public double Pl3LocationXMinUplift; + public double Pl4MinUplift; + public double Pl4HeadAdjusted; + public double Pl4LocationXMinUplift; + } + + [Serializable] + public class ScenarioException : Exception + { + public ScenarioException(string message) : base(message) + { + } + } + + /// + /// Calculation scenario class + /// + public class Scenario + { + #region Performance optimization: Extract expression so it only has to be generated once. + + private static readonly Expression> ExpressionLocationScenarioId = x => x.LocationScenarioID; + private static readonly Expression> ExpressionRiverLevel = x => x.RiverLevel; + private static readonly Expression> ExpressionRiverLevelLow = x => x.RiverLevelLow; + private static readonly Expression> ExpressionDikeTableHeight = x => x.DikeTableHeight; + private static readonly Expression> ExpressionRequiredSafetyFactorStabilityInnerSlope = x => x.RequiredSafetyFactorStabilityInnerSlope; + private static readonly Expression> ExpressionRequiredSafetyFactorStabilityOuterSlope = x => x.RequiredSafetyFactorStabilityOuterSlope; + private static readonly Expression> ExpressionRequiredSafetyFactorPiping = x => x.RequiredSafetyFactorPiping; + private static readonly Expression> ExpressionRequiredProbabilityOfFailurePiping = x => x.RequiredProbabilityOfFailurePiping; + private static readonly Expression> ExpressionUpliftCriterionPiping = x => x.UpliftCriterionPiping; + private static readonly Expression> ExpressionUpliftCriterionStability = x => x.UpliftCriterionStability; + private static readonly Expression> ExpressionPlLineOffsetBelowDikeTopAtRiver = x => x.PlLineOffsetBelowDikeTopAtRiver; + private static readonly Expression> ExpressionPlLineOffsetBelowDikeTopAtPolder = x => x.PlLineOffsetBelowDikeTopAtPolder; + private static readonly Expression> ExpressionPlLineOffsetBelowShoulderBaseInside = x => x.PlLineOffsetBelowShoulderBaseInside; + private static readonly Expression> ExpressionPlLineOffsetBelowDikeToeAtPolder = x => x.PlLineOffsetBelowDikeToeAtPolder; + private static readonly Expression> ExpressionUsePlLineOffsetBelowDikeCrestMiddle = x => x.UsePlLineOffsetBelowDikeCrestMiddle; + private static readonly Expression> ExpressionPlLineOffsetBelowDikeCrestMiddle = x => x.PlLineOffsetBelowDikeCrestMiddle; + private static readonly Expression> ExpressionUsePlLineOffsetFactorBelowShoulderCrest = x => x.UsePlLineOffsetFactorBelowShoulderCrest; + private static readonly Expression> ExpressionPlLineOffsetFactorBelowShoulderCrest = x => x.PlLineOffsetFactorBelowShoulderCrest; + private static readonly Expression> ExpressionHeadPl3 = x => x.HeadPl3; + private static readonly Expression> ExpressionHeadPl4 = x => x.HeadPl4; + private static readonly Expression> ExpressionWaterHeightDecimeringsHoogte = x => x.WaterHeightDecimeringsHoogte; + private static readonly Expression> ExpressionMaxWaterLevel = x => x.MaxWaterLevel; + + #endregion + + private CalculationResult calculationResult = CalculationResult.NoRun; + private Location location = null; + private readonly List calculationResults = new List(); + + private Dictionary stabilityUpliftSituations; + private Dictionary pipingResults; + private Dictionary mStabResults; + private Dictionary failureProbabilitiesStability; + private Dictionary safetyFactorsPiping; + private Dictionary failureProbabilitiesPiping; + private Dictionary redesignedSurfaceLines; + private Dictionary resultMessages; + private Dictionary safetyFactorsFlowSlide; + + private string locationScenarioId; + private double riverLevel; + private double? riverLevelLow; + private double? dikeTableHeight; + private double? plLineOffsetBelowDikeTopAtRiver; + private double? plLineOffsetBelowDikeTopAtPolder; + private double? plLineOffsetBelowShoulderBaseInside; + private double? plLineOffsetBelowDikeToeAtPolder; + private bool? usePlLineOffsetBelowDikeCrestMiddle; + private double? plLineOffsetBelowDikeCrestMiddle; + private bool? usePlLineOffsetFactorBelowShoulderCrest; + private double? plLineOffsetFactorBelowShoulderCrest; + private double? headPl3; + private double? headPl4; + private double? waterHeightDecimeringsHoogte; + private double? maxWaterLevel; + + public CalculationResult CalculationResult + { + get { return calculationResult; } + set { calculationResult = value; } + } + + [XmlIgnore] + public IList NwoResults { get; set; } + + public List CalculationResults + { + get { return calculationResults; } + } + + /// + /// Constructor + /// + public Scenario() + { + ClearResults(); + ClearErrors(); + ClearstabilityUpliftSituations(); + ModelFactors = new ModelFactors(); + } + + /// + /// Clears the results + /// + public void ClearstabilityUpliftSituations() + { + stabilityUpliftSituations = new Dictionary(); + } + + /// + /// Clears the errors. + /// + public void ClearErrors() + { + Errors = new StringCollection(); + } + + /// + /// Clears the results + /// + public void ClearResults() + { + calculationResult = CalculationResult.NoRun; + pipingResults = new Dictionary(); + mStabResults = new Dictionary(); + safetyFactorsPiping = new Dictionary(); + safetyFactorsFlowSlide = new Dictionary(); + resultMessages = new Dictionary(); + failureProbabilitiesStability = new Dictionary(); + failureProbabilitiesPiping = new Dictionary(); + redesignedSurfaceLines = new Dictionary(); + NwoResults = new List(); + calculationResults.Clear(); + } + + /// + /// Gets or sets the location scenario identifier. + /// + /// + /// The location scenario identifier. + /// + public string LocationScenarioID + { + get + { + return locationScenarioId; + } + set + { + locationScenarioId = value; + } + } + + [Browsable(false)] + public StringCollection Errors { get; private set; } + + /// + /// Gets or sets the river level. + /// + /// + /// The river level. + /// + [Description("River level")] + public double RiverLevel + { + get + { + return riverLevel; + } + set + { + riverLevel = value; + } + } + + /// + /// Gets or sets the river level low. + /// + /// + /// The river level low. + /// + [Description("River level low")] + public double? RiverLevelLow + { + get + { + return riverLevelLow; + } + set + { + riverLevelLow = value; + } + } + + /// + /// Gets or sets the height of the dike table. + /// + /// + /// The height of the dike table. + /// + [Description("Dike table height")] + public double? DikeTableHeight + { + get + { + return dikeTableHeight; + } + set + { + dikeTableHeight = value; + } + } + + /// + /// Gets or sets the required safety factor stability inner slope. + /// + /// + /// The required safety factor stability inner slope. + /// + [Description("Required safety factor stability inner slope")] + public double? RequiredSafetyFactorStabilityInnerSlope + { + get { return ModelFactors.RequiredSafetyFactorStabilityInnerSlope; } + set + { + ModelFactors.RequiredSafetyFactorStabilityInnerSlope = value; + } + } + + /// + /// Gets or sets the required safety factor stability outer slope. + /// + /// + /// The required safety factor stability outer slope. + /// + [Description("Required safety factor stability outer slope")] + public double? RequiredSafetyFactorStabilityOuterSlope + { + get { return ModelFactors.RequiredSafetyFactorStabilityOuterSlope; } + set + { + ModelFactors.RequiredSafetyFactorStabilityOuterSlope = value; + } + } + + /// + /// Gets or sets the required safety factor piping. + /// + /// + /// The required safety factor piping. + /// + [Description("Required safety factor piping")] + public double? RequiredSafetyFactorPiping + { + get { return ModelFactors.RequiredSafetyFactorPiping; } + set + { + ModelFactors.RequiredSafetyFactorPiping = value; + } + } + + /// + /// Gets or sets the required probability of failure piping. + /// + /// + /// The required probability of failure piping. + /// + [Description("Required probability of failure piping")] + public double? RequiredProbabilityOfFailurePiping + { + get { return ModelFactors.RequiredProbabilityOfFailurePiping; } + set + { + ModelFactors.RequiredProbabilityOfFailurePiping = value; + } + } + + /// + /// Gets or sets the uplift criterion piping. + /// + /// + /// The uplift criterion piping. + /// + [Description("Uplift criterion piping")] + public double? UpliftCriterionPiping + { + get { return ModelFactors.UpliftCriterionPiping; } + set + { + ModelFactors.UpliftCriterionPiping = value; + } + } + + /// + /// Gets or sets the uplift criterion stability. + /// + /// + /// The uplift criterion stability. + /// + [Description("Uplift criterion stability")] + public double? UpliftCriterionStability + { + get { return ModelFactors.UpliftCriterionStability; } + set + { + ModelFactors.UpliftCriterionStability = value; + } + } + + public double? PlLineOffsetBelowDikeTopAtRiver + { + get + { + return plLineOffsetBelowDikeTopAtRiver; + } + set + { + plLineOffsetBelowDikeTopAtRiver = value; + } + } + + /// + /// Gets or sets the pl line offset below dike top at polder. + /// + /// + /// The pl line offset below dike top at polder. + /// + public double? PlLineOffsetBelowDikeTopAtPolder + { + get + { + return plLineOffsetBelowDikeTopAtPolder; + } + set + { + plLineOffsetBelowDikeTopAtPolder = value; + } + } + + /// + /// Gets or sets the pl line offset below shoulder base inside. + /// + /// + /// The pl line offset below shoulder base inside. + /// + public double? PlLineOffsetBelowShoulderBaseInside + { + get + { + return plLineOffsetBelowShoulderBaseInside; + } + set + { + plLineOffsetBelowShoulderBaseInside = value; + } + } + + /// + /// Gets or sets the pl line offset below dike toe at polder. + /// + /// + /// The pl line offset below dike toe at polder. + /// + public double? PlLineOffsetBelowDikeToeAtPolder + { + get + { + return plLineOffsetBelowDikeToeAtPolder; + } + set + { + plLineOffsetBelowDikeToeAtPolder = value; + } + } + + /// + /// Gets or sets the use pl line offset below dike crest middle. + /// + /// + /// The use pl line offset below dike crest middle. + /// + public bool? UsePlLineOffsetBelowDikeCrestMiddle + { + get + { + return usePlLineOffsetBelowDikeCrestMiddle; + } + set + { + usePlLineOffsetBelowDikeCrestMiddle = value; + } + } + + /// + /// Gets or sets the pl line offset below dike crest middle. + /// + /// + /// The pl line offset below dike crest middle. + /// + public double? PlLineOffsetBelowDikeCrestMiddle + { + get { return plLineOffsetBelowDikeCrestMiddle; } + set + { + plLineOffsetBelowDikeCrestMiddle = value; + } + } + + /// + /// Gets or sets the use pl line offset factor below shoulder crest. + /// + /// + /// The use pl line offset factor below shoulder crest. + /// + public bool? UsePlLineOffsetFactorBelowShoulderCrest + { + get + { + return usePlLineOffsetFactorBelowShoulderCrest; + } + set + { + usePlLineOffsetFactorBelowShoulderCrest = value; + } + } + + /// + /// Gets or sets the pl line offset factor below shoulder crest. + /// + /// + /// The pl line offset factor below shoulder crest. + /// + public double? PlLineOffsetFactorBelowShoulderCrest + { + get { return plLineOffsetFactorBelowShoulderCrest; } + set + { + plLineOffsetFactorBelowShoulderCrest = value; + } + } + + /// + /// Gets or sets the head PL3. + /// + /// + /// The head PL3. + /// + public double? HeadPl3 + { + get + { + return headPl3; + } + set + { + headPl3 = value; + } + } + + /// + /// Gets or sets the head PL4. + /// + /// + /// The head PL4. + /// + public double? HeadPl4 + { + get + { + return headPl4; + } + set + { + headPl4 = value; + } + } + + /// + /// Gets or sets the water height decimerings hoogte. + /// + /// + /// The water height decimerings hoogte. + /// + public double? WaterHeightDecimeringsHoogte + { + get + { + return waterHeightDecimeringsHoogte; + } + set + { + waterHeightDecimeringsHoogte = value; + } + } + + /// + /// Gets or sets the maximum water level. + /// + /// + /// The maximum water level. + /// + public double? MaxWaterLevel + { + get + { + return maxWaterLevel; + } + set + { + maxWaterLevel = value; + } + } + + /// + /// Gets or sets the model factors. + /// + /// + /// The model factors. + /// + public ModelFactors ModelFactors { get; set; } + + /// Aggregation relationship. + public Location Location + { + get { return location; } + set { location = value; } + } + + /// + /// Get uplift criterion for this scenario; return default value if not available + /// + /// default value if not available + /// uplift criterion for this scenario + public double GetUpliftCriterionStability(double? defaultUpliftCriterionStability) + { + if ((defaultUpliftCriterionStability == null) && (ModelFactors.UpliftCriterionStability == null)) + { + throw new ScenarioException(String.Format(LocalizationManager.GetTranslatedText(this, "NoUpliftCriterionForStability"), Location.Name, ToString())); + + } + return (ModelFactors.UpliftCriterionStability == null ? defaultUpliftCriterionStability.Value + : ModelFactors.UpliftCriterionStability.Value); + } + + /// + /// Get uplift criterion for this scenario; return default value if not available + /// + /// default value if not available + /// uplift criterion for this scenario + public double GetUpliftCriterionPiping(double? defaultUpliftCriterionPiping) + { + if ((defaultUpliftCriterionPiping == null) && (ModelFactors.UpliftCriterionPiping == null)) + { + throw new ScenarioException(String.Format(LocalizationManager.GetTranslatedText(this, "NoUpliftCriterionForPiping"), Location.Name, ToString())); + } + return (ModelFactors.UpliftCriterionPiping == null ? defaultUpliftCriterionPiping.Value : ModelFactors.UpliftCriterionPiping.Value); + } + + /// + /// Get required safety factor for this scenario; return default value if not available + /// + /// default value if not available + /// uplift criterion for this scenario + public double GetRequiredSafetyFactorPiping(double? defaultRequiredSafetyFactorPiping) + { + if ((defaultRequiredSafetyFactorPiping == null) && (ModelFactors.RequiredSafetyFactorPiping == null)) + { + throw new ScenarioException(String.Format(LocalizationManager.GetTranslatedText(this, "NoRequiredSafetyFactorPiping"), Location.Name, ToString())); + } + return (ModelFactors.RequiredSafetyFactorPiping == null ? defaultRequiredSafetyFactorPiping.Value : ModelFactors.RequiredSafetyFactorPiping.Value); + } + + /// + /// Determines whether [is pl line offset factor below shoulder crest valid]. + /// + /// + [Validate] + public ValidationResult[] IsPlLineOffsetFactorBelowShoulderCrestValid() + { + if (UsePlLineOffsetFactorBelowShoulderCrest.HasValue && UsePlLineOffsetFactorBelowShoulderCrest.Value && + PlLineOffsetFactorBelowShoulderCrest.HasValue) + { + if (PlLineOffsetFactorBelowShoulderCrest.Value < DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMinValue) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "PlLineOffsetFactorBelowShoulderCrestTooSmall"), + this) + }; + } + if (PlLineOffsetFactorBelowShoulderCrest.Value > DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMaxValue) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "PlLineOffsetFactorBelowShoulderCrestTooLarge"), + this) + }; + } + } + return new ValidationResult[0]; + } + + /// + /// Get stability uplift situation + /// + /// + /// + private UpliftSituation? GetStabilityUpliftSituation(Object objectAsKey) + { + return objectAsKey != null && stabilityUpliftSituations.ContainsKey(objectAsKey) ? stabilityUpliftSituations[objectAsKey] : null; + } + + /// + /// Get stability uplift situation + /// + /// + /// + /// + public UpliftSituation? GetStabilityUpliftSituation(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetStabilityUpliftSituation(objectAsKey); + } + + /// + /// Set stability uplift situation + /// + /// + /// + private void SetStabilityUpliftSituation(Object objectAsKey, UpliftSituation upliftSituation) + { + stabilityUpliftSituations[objectAsKey] = upliftSituation; + } + + /// + /// Set stability uplift situation + /// + /// + /// + /// + public void SetStabilityUpliftSituation(SoilProfile1D soilProfile, string soilGeometry2DName, UpliftSituation upliftSituation) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetStabilityUpliftSituation(objectAsKey, upliftSituation); + } + + /// + /// Get PipingResults + /// + /// + /// + private PipingResults? GetPipingResults(Object objectAsKey) + { + if (objectAsKey != null) + { + return pipingResults.ContainsKey(objectAsKey) ? pipingResults[objectAsKey] : null; + } + return null; + } + + /// + /// Get PipingResults + /// + /// + /// + /// + public PipingResults? GetPipingResults(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetPipingResults(objectAsKey); + } + + /// + /// Set PipingResults + /// + /// + /// + private void SetPipingResults(Object objectAsKey, PipingResults? pipingResults) + { + this.pipingResults[objectAsKey] = pipingResults; + } + + /// + /// Set PipingResults + /// + /// + /// + /// + public void SetPipingResults(SoilProfile1D soilProfile, string soilGeometry2DName, PipingResults? pipingResults) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetPipingResults(objectAsKey, pipingResults); + } + + /// + /// Get MStabResults + /// + /// + /// + private MStabResults? GetMStabResults(Object objectAsKey) + { + if (objectAsKey != null) + { + return mStabResults.ContainsKey(objectAsKey) ? mStabResults[objectAsKey] : null; + } + return null; + } + + /// + /// Get MStabResults + /// + /// + /// + /// + public MStabResults? GetMStabResults(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetMStabResults(objectAsKey); + } + + /// + /// Set MStabResults + /// + /// + /// + private void SetMStabResults(Object objectAsKey, MStabResults? mStabResults) + { + this.mStabResults[objectAsKey] = mStabResults; + } + + /// + /// Set MStabResults + /// + /// + /// + /// + public void SetMStabResults(SoilProfile1D soilProfile, string soilGeometry2DName, MStabResults? mStabResults) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetMStabResults(objectAsKey, mStabResults); + } + + /// + /// Get Safety Factor Piping + /// + /// + /// + private double? GetSafetyFactorPiping(Object objectAsKey) + { + if (objectAsKey != null) + { + return safetyFactorsPiping.ContainsKey(objectAsKey) ? safetyFactorsPiping[objectAsKey] : null; + } + return null; + } + + /// + /// Get Safety Factor Piping + /// + /// + /// + /// + public double? GetSafetyFactorPiping(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetSafetyFactorPiping(objectAsKey); + } + + /// + /// Set Safety Factor Piping + /// + /// + /// + private void SetSafetyFactorPiping(Object objectAsKey, double? safetyFactor) + { + safetyFactorsPiping[objectAsKey] = safetyFactor; + } + + /// + /// Set Safety Factor Piping + /// + /// + /// + /// + public void SetSafetyFactorPiping(SoilProfile1D soilProfile, string soilGeometry2DName, double? safetyFactor) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetSafetyFactorPiping(objectAsKey, safetyFactor); + } + + /// + /// Get Failure Probability piping + /// + /// + /// + private double? GetFailureProbabilityPiping(Object objectAsKey) + { + if (objectAsKey != null) + { + return failureProbabilitiesPiping.ContainsKey(objectAsKey) ? failureProbabilitiesPiping[objectAsKey] : null; + } + return null; + } + + /// + /// Get Failure Probability piping + /// + /// + /// + /// + public double? GetFailureProbabilityPiping(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetFailureProbabilityPiping(objectAsKey); + } + + /// + /// Set Failure Probability piping + /// + /// + /// + /// + public void SetFailureProbabilityPiping(SoilProfile1D soilProfile, string soilGeometry2DName, double? failureProbability) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetFailureProbabilityPiping(objectAsKey, failureProbability); + } + + /// + /// Set Failure Probability piping + /// + /// + /// + private void SetFailureProbabilityPiping(Object objectAsKey, double? failureProbability) + { + failureProbabilitiesPiping[objectAsKey] = failureProbability; + } + + /// + /// Get Safety Factor Piping + /// + /// + /// + /// + public double? GetSafetyFactorFlowSlide(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetSafetyFactorFlowSlide(objectAsKey); + } + + /// + /// Get Safety Factor FlowSlide + /// + /// + /// + private double? GetSafetyFactorFlowSlide(Object objectAsKey) + { + if (objectAsKey != null) + { + return safetyFactorsFlowSlide.ContainsKey(objectAsKey) ? safetyFactorsFlowSlide[objectAsKey] : null; + } + return null; + } + + /// + /// Set Safety Factor FlowSlide + /// + /// + /// + private void SetSafetyFactorFlowSlide(Object objectAsKey, double? safetyFactor) + { + safetyFactorsFlowSlide[objectAsKey] = safetyFactor; + } + + /// + /// Set Safety Factor FlowSlide + /// + /// + /// + /// + public void SetSafetyFactorFlowSlide(SoilProfile1D soilProfile, string soilGeometry2DName, double? safetyFactor) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetSafetyFactorFlowSlide(objectAsKey, safetyFactor); + } + + /// + /// Get Result Message + /// + /// + /// + private string GetResultMessage(Object objectAsKey) + { + if (objectAsKey != null) + { + return resultMessages.ContainsKey(objectAsKey) ? resultMessages[objectAsKey] : null; + } + return null; + } + + /// + /// Get Result Message + /// + /// + /// + /// + public string GetResultMessage(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetResultMessage(objectAsKey); + } + + /// + /// Set Result Message + /// + /// + /// + private void SetResultMessage(Object objectAsKey, string resultMessage) + { + resultMessages[objectAsKey] = resultMessage; + } + + /// + /// Set Result Message + /// + /// + /// + /// + public void SetResultMessage(SoilProfile1D soilProfile, string soilGeometry2DName, string resultMessage) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetResultMessage(objectAsKey, resultMessage); + } + + /// + /// Return the safety factor for calculation type of most probable soil profile + /// + /// + /// + public double? GetMostProbableSafetyFactor(FailureMechanismSystemType? failureMechanismType) + { + SoilProfile1D soilProfile = Location.Segment.GetMostProbableProfile(failureMechanismType); + string soilGeometry2DName = Location.Segment.GetMostProbableGeometry2DName(failureMechanismType); + switch (failureMechanismType) + { + case FailureMechanismSystemType.Piping: + return GetSafetyFactorPiping(soilProfile, soilGeometry2DName); + case FailureMechanismSystemType.StabilityInside: + case FailureMechanismSystemType.StabilityOutside: + MStabResults? mstabResults = GetMStabResults(soilProfile, soilGeometry2DName); + double? safetyFactor = null; + if (mstabResults != null) + { + safetyFactor = mstabResults.Value.zone1.safetyFactor; + } + return safetyFactor; + } + return null; + } + + /// + /// Return probability stability + /// + /// + /// + private double? GetFailureProbabilityStability(Object objectAsKey) + { + if (objectAsKey != null) + { + return failureProbabilitiesStability.ContainsKey(objectAsKey) ? failureProbabilitiesStability[objectAsKey] : null; + } + return null; + } + + /// + /// Return probability stability + /// + /// + /// + /// + public double? GetFailureProbabilityStability(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetFailureProbabilityStability(objectAsKey); + } + + /// + /// Set probability stability + /// + /// + /// + private void SetFailureProbabilityStability(Object objectAsKey, double? failureProbability) + { + failureProbabilitiesStability[objectAsKey] = failureProbability; + } + + /// + /// Set probability stability + /// + /// + /// + /// + public void SetFailureProbabilityStability(SoilProfile1D soilProfile, string soilGeometry2DName, double? failureProbability) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetFailureProbabilityStability(objectAsKey, failureProbability); + } + + /// + /// Get Redesigned surfaceline + /// + /// + /// + private SurfaceLine2 GetRedesignedSurfaceLine(Object objectAsKey) + { + if (objectAsKey != null) + { + return redesignedSurfaceLines.ContainsKey(objectAsKey) ? redesignedSurfaceLines[objectAsKey] : null; + } + return null; + } + + /// + /// Get Redesigned surfaceline + /// + /// + /// + /// + public SurfaceLine2 GetRedesignedSurfaceLine(SoilProfile1D soilProfile, string soilGeometry2DName) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + return GetRedesignedSurfaceLine(objectAsKey); + } + + /// + /// Set Redesigned surfaceline + /// + /// + /// + private void SetRedesignedSurfaceLine(Object objectAsKey, SurfaceLine2 surfaceLine) + { + redesignedSurfaceLines[objectAsKey] = surfaceLine; + } + + /// + /// Set Redesigned surfaceline + /// + /// + /// + /// + public void SetRedesignedSurfaceLine(SoilProfile1D soilProfile, string soilGeometry2DName, SurfaceLine2 surfaceLine) + { + Object objectAsKey = GetObjectAsKey(soilProfile, soilGeometry2DName); + SetRedesignedSurfaceLine(objectAsKey, surfaceLine); + } + + /// + /// Get Most recent surfaceline + /// + /// + /// + private SurfaceLine2 GetMostRecentSurfaceLine(Object objectAsKey) + { + if (objectAsKey != null) + { + return redesignedSurfaceLines.ContainsKey(objectAsKey) ? redesignedSurfaceLines[objectAsKey] ?? Location.LocalXZSurfaceLine2 : Location.LocalXZSurfaceLine2; + } + return null; + } + + /// + /// Get Most recent surfaceline + /// + /// + /// + /// + public SurfaceLine2 GetMostRecentSurfaceLine(SoilProfile soilProfile, string soilGeometry2DName) + { + var profile1D = soilProfile as SoilProfile1D; + Object objectAsKey = GetObjectAsKey(profile1D, soilGeometry2DName); + return GetMostRecentSurfaceLine(objectAsKey); + } + + /// + /// Determine object key based on either 1d-soilprofile or 2d-geometry + /// + /// + /// + /// + /// + private Object GetObjectAsKey(SoilProfile1D soilProfile, string soilGeometry2DName) + { + if (soilProfile != null) + { + return soilProfile; + } + return soilGeometry2DName; + } + + /// + /// Implementation of ToString + /// + /// + public override string ToString() + { + return String.Format("Location={0}, ID={1} RiverLevel={2} RiverLevelLow={3} DikeTableHeight={4} SafetyFactorStabilityInnerSlope={5} RequiredSafetyFactorStabilityOuterSlope={6} WaterHeightDecimeringsHoogte= {7} MaxWaterheight={8} ProbabilityOfFailureStabilityInnerslope={9} ProbabilityOfFailurePiping={10} PlLineOffsetBelowDikeTopAtRiver={11} PlLineOffsetBelowDikeToeAtPolder={12} PlLineOffsetBelowDikeTopAtPolder={13} PlLineOffsetBelowShoulderBaseInside={14} UsePlLineOffsetBelowDikeCrestMiddle {15} PlLineOffsetBelowDikeCrestMiddle {16} UsePlLineOffsetFactorBelowShoulderCrest {17} PlLineOffsetFactorBelowShoulderCrest {18} HeadPl3={19} HeadPl4={20}", + Location.Name, LocationScenarioID, RiverLevel, + RiverLevelLow.HasValue ? RiverLevelLow.ToString() : "?", + DikeTableHeight.HasValue ? DikeTableHeight.ToString() : "?", + ModelFactors.RequiredSafetyFactorStabilityInnerSlope.HasValue ? ModelFactors.RequiredSafetyFactorStabilityInnerSlope.ToString() : "?", + ModelFactors.RequiredSafetyFactorStabilityOuterSlope.HasValue ? ModelFactors.RequiredSafetyFactorStabilityOuterSlope.ToString() : "?", + WaterHeightDecimeringsHoogte.HasValue ? WaterHeightDecimeringsHoogte.ToString() : "?", + MaxWaterLevel.HasValue ? MaxWaterLevel.ToString() : "?", + ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.HasValue ? ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.ToString() : "?", + ModelFactors.RequiredProbabilityOfFailurePiping.HasValue ? ModelFactors.RequiredProbabilityOfFailurePiping.ToString() : "?", + PlLineOffsetBelowDikeTopAtRiver.HasValue ? PlLineOffsetBelowDikeToeAtPolder.ToString() : "?", + PlLineOffsetBelowDikeToeAtPolder.HasValue ? MaxWaterLevel.ToString() : "?", + PlLineOffsetBelowDikeTopAtPolder.HasValue ? PlLineOffsetBelowDikeTopAtPolder.ToString() : "?", + PlLineOffsetBelowShoulderBaseInside.HasValue ? PlLineOffsetBelowShoulderBaseInside.ToString() : "?", + UsePlLineOffsetBelowDikeCrestMiddle.HasValue ? UsePlLineOffsetBelowDikeCrestMiddle.ToString() : "?", + PlLineOffsetBelowDikeCrestMiddle.HasValue ? PlLineOffsetBelowDikeCrestMiddle.ToString() : "?", + UsePlLineOffsetFactorBelowShoulderCrest.HasValue ? UsePlLineOffsetFactorBelowShoulderCrest.ToString() : "?", + PlLineOffsetFactorBelowShoulderCrest.HasValue ? PlLineOffsetFactorBelowShoulderCrest.ToString() : "?", + HeadPl3.HasValue ? HeadPl3.ToString() : "?", + HeadPl4.HasValue ? HeadPl4.ToString() : "?"); + } + + /// + /// Determine waterlevels based on waterlevel, max waterlevel and decimeringshoogte + /// + /// + public double[] DetermineProperWaterlevelsForProbabilisticAdvanced() + { + double[] waterLevels = new double[3]; + + waterLevels[0] = (double)MaxWaterLevel; + waterLevels[1] = (double)MaxWaterLevel; + waterLevels[2] = (double)MaxWaterLevel; + + if (MaxWaterLevel > RiverLevel + WaterHeightDecimeringsHoogte) + { + waterLevels[0] = (double)(RiverLevel + WaterHeightDecimeringsHoogte); + waterLevels[1] = (double)RiverLevel; + waterLevels[2] = (double)(RiverLevel - WaterHeightDecimeringsHoogte); + } + else + { + if (MaxWaterLevel > RiverLevel) + { + waterLevels[0] = (double)MaxWaterLevel; + waterLevels[1] = (double)RiverLevel; + waterLevels[2] = (double)(RiverLevel - WaterHeightDecimeringsHoogte); + } + else + { + if (MaxWaterLevel > RiverLevel - WaterHeightDecimeringsHoogte) + { + waterLevels[0] = (double)MaxWaterLevel; + waterLevels[1] = (double)MaxWaterLevel; + waterLevels[2] = (double)(RiverLevel - WaterHeightDecimeringsHoogte); + } + } + } + return waterLevels; + } + + public Dictionary GetParametersAsNameValuePairs() + { + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + var nameValuePairs = new Dictionary(); + nameValuePairs.Add(ScenarioParameterNames.LocationScenarioId, LocationScenarioID); + nameValuePairs.Add(ScenarioParameterNames.RiverLevel, RiverLevel.ToString(numberFormatInfo)); + if (RiverLevelLow != null) + { + nameValuePairs.Add(ScenarioParameterNames.RiverLevelLow, RiverLevelLow.Value.ToString(numberFormatInfo)); + } + if (DikeTableHeight != null) + { + nameValuePairs.Add(ScenarioParameterNames.DikeTableHeight, DikeTableHeight.Value.ToString(numberFormatInfo)); + } + if (WaterHeightDecimeringsHoogte != null) + { + nameValuePairs.Add(ScenarioParameterNames.WaterHeightDecimeringsHoogte, WaterHeightDecimeringsHoogte.Value.ToString(numberFormatInfo)); + } + if (MaxWaterLevel != null) + { + nameValuePairs.Add(ScenarioParameterNames.MaxWaterLevel, MaxWaterLevel.Value.ToString(numberFormatInfo)); + } + if (ModelFactors != null) + { + if (ModelFactors.RequiredSafetyFactorStabilityInnerSlope != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredSafetyFactorStabilityInnerSlope, ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredSafetyFactorStabilityOuterSlope != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredSafetyFactorStabilityOuterSlope, ModelFactors.RequiredSafetyFactorStabilityOuterSlope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredSafetyFactorPiping != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredSafetyFactorPiping, ModelFactors.RequiredSafetyFactorPiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredProbabilityOfFailureStabilityInnerslope, ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredProbabilityOfFailureStabilityOuterslope, ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailurePiping != null) + { + nameValuePairs.Add(ScenarioParameterNames.RequiredProbabilityOfFailurePiping, ModelFactors.RequiredProbabilityOfFailurePiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.UpliftCriterionPiping != null) + { + nameValuePairs.Add(ScenarioParameterNames.UpliftCriterionPiping, ModelFactors.UpliftCriterionPiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.UpliftCriterionStability != null) + { + nameValuePairs.Add(ScenarioParameterNames.UpliftCriterionStability, ModelFactors.UpliftCriterionStability.Value.ToString(numberFormatInfo)); + } + } + if (PlLineOffsetBelowDikeTopAtRiver != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetBelowDikeTopAtRiver, PlLineOffsetBelowDikeTopAtRiver.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetBelowDikeTopAtPolder != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetBelowDikeTopAtPolder, PlLineOffsetBelowDikeTopAtPolder.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetBelowShoulderBaseInside != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetBelowShoulderBaseInside, PlLineOffsetBelowShoulderBaseInside.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetBelowDikeToeAtPolder != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetBelowDikeToeAtPolder, PlLineOffsetBelowDikeToeAtPolder.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetBelowDikeCrestMiddle != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetBelowDikeCrestMiddle, PlLineOffsetBelowDikeCrestMiddle.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetFactorBelowShoulderCrest != null) + { + nameValuePairs.Add(ScenarioParameterNames.PlLineOffsetFactorBelowShoulderCrest, PlLineOffsetFactorBelowShoulderCrest.Value.ToString(numberFormatInfo)); + } + if (UsePlLineOffsetBelowDikeCrestMiddle != null) + { + nameValuePairs.Add(ScenarioParameterNames.UsePlLineOffsetBelowDikeCrestMiddle, UsePlLineOffsetBelowDikeCrestMiddle.Value.ToString()); + } + if (UsePlLineOffsetFactorBelowShoulderCrest != null) + { + nameValuePairs.Add(ScenarioParameterNames.UsePlLineOffsetFactorBelowShoulderCrest, UsePlLineOffsetFactorBelowShoulderCrest.Value.ToString()); + } + if (HeadPl3 != null) + { + nameValuePairs.Add(ScenarioParameterNames.HeadPl3, HeadPl3.Value.ToString(numberFormatInfo)); + } + if (HeadPl4 != null) + { + nameValuePairs.Add(ScenarioParameterNames.HeadPl4, HeadPl4.Value.ToString(numberFormatInfo)); + } + return nameValuePairs; + } + + public void SetParameterFromNameValuePair(string parameterName, string parameterValue) + { + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + if (parameterName.Equals(ScenarioParameterNames.LocationScenarioId)) + LocationScenarioID = parameterValue; + if (parameterName.Equals(ScenarioParameterNames.RiverLevel)) + RiverLevel = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RiverLevelLow)) + RiverLevelLow = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.DikeTableHeight)) + DikeTableHeight = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.WaterHeightDecimeringsHoogte)) + WaterHeightDecimeringsHoogte = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.MaxWaterLevel)) + MaxWaterLevel = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredSafetyFactorStabilityInnerSlope)) + ModelFactors.RequiredSafetyFactorStabilityInnerSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredSafetyFactorStabilityOuterSlope)) + ModelFactors.RequiredSafetyFactorStabilityOuterSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredSafetyFactorPiping)) + ModelFactors.RequiredSafetyFactorPiping = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredProbabilityOfFailureStabilityInnerslope)) + ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredProbabilityOfFailureStabilityOuterslope)) + ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.RequiredProbabilityOfFailurePiping)) + ModelFactors.RequiredProbabilityOfFailurePiping = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.UpliftCriterionPiping)) + ModelFactors.UpliftCriterionPiping = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.UpliftCriterionStability)) + ModelFactors.UpliftCriterionStability = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetBelowDikeTopAtRiver)) + PlLineOffsetBelowDikeTopAtRiver = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetBelowDikeTopAtPolder)) + PlLineOffsetBelowDikeTopAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetBelowShoulderBaseInside)) + PlLineOffsetBelowShoulderBaseInside = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetBelowDikeToeAtPolder)) + PlLineOffsetBelowDikeToeAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetBelowDikeCrestMiddle)) + PlLineOffsetBelowDikeCrestMiddle = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.PlLineOffsetFactorBelowShoulderCrest)) + PlLineOffsetFactorBelowShoulderCrest = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.UsePlLineOffsetBelowDikeCrestMiddle)) + UsePlLineOffsetBelowDikeCrestMiddle = Convert.ToBoolean(parameterValue); + if (parameterName.Equals(ScenarioParameterNames.UsePlLineOffsetFactorBelowShoulderCrest)) + UsePlLineOffsetFactorBelowShoulderCrest = Convert.ToBoolean(parameterValue); + if (parameterName.Equals(ScenarioParameterNames.HeadPl3)) + HeadPl3 = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(ScenarioParameterNames.HeadPl4)) + HeadPl4 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + } + + public static class ScenarioParameterNames + { + public const string LocationScenarioId = "LocationScenarioId"; + public const string RiverLevel = "RiverLevel"; + public const string RiverLevelLow = "RiverLevelLow"; + public const string DikeTableHeight = "DikeTableHeight"; + public const string WaterHeightDecimeringsHoogte = "WaterHeightDecimeringsHoogte"; + public const string MaxWaterLevel = "MaxWaterLevel"; + + public const string RequiredSafetyFactorStabilityInnerSlope = "RequiredSafetyFactorStabilityInnerSlope"; + public const string RequiredSafetyFactorStabilityOuterSlope = "RequiredSafetyFactorStabilityOuterSlope"; + public const string RequiredSafetyFactorPiping = "RequiredSafetyFactorPiping"; + public const string RequiredProbabilityOfFailureStabilityInnerslope = "RequiredProbabilityOfFailureStabilityInnerslope"; + public const string RequiredProbabilityOfFailureStabilityOuterslope = "RequiredProbabilityOfFailureStabilityOuterslope"; + public const string RequiredProbabilityOfFailurePiping = "RequiredProbabilityOfFailurePiping"; + public const string UpliftCriterionPiping = "UpliftCriterionPiping"; + public const string UpliftCriterionStability = "UpliftCriterionStability"; + public const string PlLineOffsetBelowDikeTopAtRiver = "PLLineOffsetBelowDikeTopAtRiver"; + public const string PlLineOffsetBelowDikeTopAtPolder = "PLLineOffsetBelowDikeTopAtPolder"; + public const string PlLineOffsetBelowShoulderBaseInside = "PLLineOffsetBelowShoulderBaseInside"; + public const string PlLineOffsetBelowDikeToeAtPolder = "PLLineOffsetBelowDikeToeAtPolder"; + public const string PlLineOffsetBelowDikeCrestMiddle = "PlLineOffsetBelowDikeCrestMiddle"; + public const string PlLineOffsetFactorBelowShoulderCrest = "PlLineOffsetFactorBelowShoulderCrest"; + public const string UsePlLineOffsetBelowDikeCrestMiddle = "UsePlLineOffsetBelowDikeCrestMiddle"; + public const string UsePlLineOffsetFactorBelowShoulderCrest = "UsePlLineOffsetFactorBelowShoulderCrest"; + public const string HeadPl3 = "HeadPL3"; + public const string HeadPl4 = "HeadPL4"; + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Segment.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Segment.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Segment.cs (revision 334) @@ -0,0 +1,247 @@ +// Copyright (C) Stichting Deltares 2017. 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.Linq; +using System.Text; +using Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Data.General +{ + public class SoilGeometryProbability : IComparable + { + public virtual SoilProfile1D SoilProfile { get; set; } + public virtual string SoilGeometry2DName { get; set; } + public virtual SoilProfile2D SoilProfile2D { get; set; } + public virtual FailureMechanismSystemType? SegmentFailureMechanismType { get; set; } + public virtual double Probability { get; set; } // Probability of occurance; number between 0.0 and 100.0 + + /// + /// Assigns the specified soil geometry probability. + /// + /// The soil geometry probability. + public void Assign(SoilGeometryProbability soilGeometryProbability) + { + if (soilGeometryProbability.SoilProfile != null) + { + SoilProfile = new SoilProfile1D(); + SoilProfile.Assign(soilGeometryProbability.SoilProfile); + } + SegmentFailureMechanismType = soilGeometryProbability.SegmentFailureMechanismType; + Probability = soilGeometryProbability.Probability; + SoilGeometry2DName = soilGeometryProbability.SoilGeometry2DName; + } + + public SoilGeometryType SoilGeometryType + { + get + { + if (SoilProfile != null) + { + return SoilGeometryType.SoilGeometry1D; + } + else + { + if (SoilGeometry2DName == null) + { + throw new Exception("No soilprofile assigned"); + } + return SoilGeometryType.SoilGeometry2D; + } + } + } + + /// + /// Returns either the 1D-geometry or the 2D-geometry name + /// + public virtual string SoilGeometryName + { + get + { + string soilGeometryName = ""; + if (this.SoilProfile != null) + { + soilGeometryName = this.SoilProfile.Name; + } + else + { + soilGeometryName = this.SoilGeometry2DName; + } return soilGeometryName; + } + } + + public int CompareTo(SoilGeometryProbability other) + { + return - this.Probability.CompareTo(other.Probability); + } + } + + public class Segment + { + private List soilGeometryProbabilities = new List(); + + public virtual string Name { get; set; } + + /// + /// Gets the soil probalilities for this segment + /// + public virtual List SoilProfileProbabilities + { + get { return this.soilGeometryProbabilities; } + } + + public SoilProfile1D GetMostProbableProfile(FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable spps = from SoilGeometryProbability spp in this.soilGeometryProbabilities + where !spp.SegmentFailureMechanismType.HasValue || !segmentFailureMechanismType.HasValue || spp.SegmentFailureMechanismType == segmentFailureMechanismType + orderby spp.Probability descending + select spp; + if (spps.Count() > 0) + return spps.First().SoilProfile; + else + return null; + } + + public string GetMostProbableGeometry2DName(FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable spps = from SoilGeometryProbability spp in this.soilGeometryProbabilities + where !spp.SegmentFailureMechanismType.HasValue || !segmentFailureMechanismType.HasValue || spp.SegmentFailureMechanismType == segmentFailureMechanismType + orderby spp.Probability descending + select spp; + if (spps.Count() > 0) + return spps.First().SoilGeometry2DName; + else + return null; + } + + public void AddSoilProfileProbability(SoilProfile1D soilProfile, double probability, FailureMechanismSystemType? segmentFailureMechanismType) + { + if (this.soilGeometryProbabilities.Where(x => x.SoilProfile == soilProfile && x.SegmentFailureMechanismType == segmentFailureMechanismType).Count() == 0) + this.soilGeometryProbabilities.Add(new SoilGeometryProbability() { SoilProfile = soilProfile, Probability = probability, SegmentFailureMechanismType = segmentFailureMechanismType, SoilGeometry2DName = null }); + } + + public double? GetSoilProfileProbability(SoilProfile1D soilProfile, FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable probs = this.soilGeometryProbabilities.Where( + x => (x.SoilProfile == soilProfile) && + (segmentFailureMechanismType == null || x.SegmentFailureMechanismType == segmentFailureMechanismType || x.SegmentFailureMechanismType == null)); + + if (probs.Count() > 0) + return probs.Select(x => x.Probability).Average(); + else + return null; + } + + public void AddSoilGeometry2DProbability(string soilGeometry2DName, double probability, FailureMechanismSystemType? segmentFailureMechanismType) + { + if (this.soilGeometryProbabilities.Where(x => x.SoilGeometry2DName == soilGeometry2DName && x.SegmentFailureMechanismType == segmentFailureMechanismType).Count() == 0) + this.soilGeometryProbabilities.Add(new SoilGeometryProbability() { SoilProfile = null, Probability = probability, SegmentFailureMechanismType = segmentFailureMechanismType, SoilGeometry2DName = soilGeometry2DName }); + } + + public double? GetSoilGeometry2DProbability(string soilGeometry2DName, FailureMechanismSystemType? segmentFailureMechanismType) + { + IEnumerable probs = this.soilGeometryProbabilities.Where( + x => (x.SoilGeometry2DName == soilGeometry2DName) && + (segmentFailureMechanismType == null || x.SegmentFailureMechanismType == segmentFailureMechanismType || x.SegmentFailureMechanismType == null)); + + if (probs.Count() > 0) + return probs.Select(x => x.Probability).Average(); + else + return null; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append(this.Name); + sb.Append(": "); + foreach (FailureMechanismSystemType type in Enum.GetValues(typeof(FailureMechanismSystemType))) + { + sb.Append(type.ToString()); + sb.Append(": "); + foreach (SoilGeometryProbability spp in this.SoilProfileProbabilities.Where(x => x.SegmentFailureMechanismType == null || x.SegmentFailureMechanismType == type)) + { + if (spp.SoilProfile != null) + { + sb.Append(String.Format("(1D) {0} ({1}%) ", spp.SoilProfile.Name, spp.Probability)); + } + else + { + sb.Append(String.Format("(2D) {0} ({1}%) ", spp.SoilGeometry2DName, spp.Probability)); + } + } + } + + return sb.ToString(); + } + + /// + /// Assemble a list of key/value pairs with the relevant parameters for the specified 1d-profile + /// + /// + public Dictionary GetParametersForSoilProfile1DAsNameValuePairs(string soilProfile1DId, FailureMechanismSystemType failureMechanismSystemType) + { + SoilGeometryProbability soilProfileProbability = this.SoilProfileProbabilities.FirstOrDefault(x => (x.SoilProfile != null && + x.SoilProfile.Name.Equals(soilProfile1DId) && + x.SegmentFailureMechanismType == failureMechanismSystemType + )); + if (soilProfileProbability != null) + { + var nameValuePairs = new Dictionary(); + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + nameValuePairs.Add("Probability", soilProfileProbability.Probability.ToString(numberFormatInfo)); + nameValuePairs.Add("FailureMechanismType", soilProfileProbability.SegmentFailureMechanismType.ToString()); + return nameValuePairs; + } + else + { + return null; + } + } + + /// + /// Assemble a list of key/value pairs with the relevant parameters for the specified 2d-profile + /// + /// + public Dictionary GetParametersForSoilProfile2DAsNameValuePairs(string soilProfile2DId, FailureMechanismSystemType failureMechanismSystemType) + { + SoilGeometryProbability soilProfileProbability = this.SoilProfileProbabilities.FirstOrDefault(x => x.SoilGeometry2DName.Equals(soilProfile2DId) && + x.SegmentFailureMechanismType == failureMechanismSystemType); + if (soilProfileProbability != null) + { + var nameValuePairs = new Dictionary(); + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + nameValuePairs.Add("Probability", soilProfileProbability.Probability.ToString(numberFormatInfo)); + nameValuePairs.Add("FailureMechanismType", soilProfileProbability.SegmentFailureMechanismType.ToString()); + return nameValuePairs; + } + else + { + return null; + } + } + } + +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPoint.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPoint.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/CharacteristicPoint.cs (revision 334) @@ -0,0 +1,154 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Represents a point on a surface line of a particular . + /// + /// + public class CharacteristicPoint : GeometryPoint + { + private CharacteristicPointType characteristicPointType = CharacteristicPointType.None; + private GeometryPoint geometryPoint; + + // Aggregation relationship + + /// + /// Initializes a new instance of the class. + /// + /// + public CharacteristicPoint() + { + //geometryPoint = new GeometryPoint(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The containing characteristic point set. + /// The geometry point. + public CharacteristicPoint(CharacteristicPointSet set, GeometryPoint point) + : this() + { + PointSet = set; + SetGeometryPoint(point); + } + + /// + /// Gets or sets the characteristic type 'marker' of a geometry point on a surfaceline.. + /// + public CharacteristicPointType CharacteristicPointType + { + get + { + return characteristicPointType; + } + set + { + characteristicPointType = value; + } + } + + /// + /// Gets or sets the geometry point. + /// + /// + /// The geometry point. + /// + public GeometryPoint GeometryPoint + { + get + { + return geometryPoint; + } + set + { + SetGeometryPoint(value); + } + } + + /// + /// Gets or sets the characteristic point set associated containing this point. + /// + [XmlIgnore] // Ignore to prevent cyclic reference build up in XML. Field is set by CharacteristicPointSet on Add + public CharacteristicPointSet PointSet { get; set; } + + /// + /// Gets or sets the X coordinate of GeometryPoint + /// + [Translation("L")] + [XmlIgnore] + public override double X + { + get + { + return GeometryPoint.X; + } + set + { + if (GeometryPoint != null) + { + GeometryPoint.X = value; + } + } + } + + /// + /// Gets or sets the Z coordinate of GeometryPoint + /// + [XmlIgnore] + public override double Z + { + get + { + return GeometryPoint.Z; + } + set + { + if (GeometryPoint != null) + { + GeometryPoint.Z = value; + } + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return LocalizationManager.GetTranslatedText(GetType(), CharacteristicPointType.ToString()); + } + + private void SetGeometryPoint(GeometryPoint point) + { + geometryPoint = point; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgentException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgentException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityServiceAgentException.cs (revision 334) @@ -0,0 +1,36 @@ +// Copyright (C) Stichting Deltares 2017. 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.Stability +{ + public class StabilityServiceAgentException : Exception + { + public StabilityServiceAgentException() : this("There was an error") { } + public StabilityServiceAgentException(string message) : base(message) { } + public StabilityServiceAgentException(string message, Exception inner) : base(message, inner) { } + protected StabilityServiceAgentException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) + : base(info, context) { } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/MStabProject.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/MStabProject.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/MStabProject.cs (revision 334) @@ -0,0 +1,448 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Net.Mime; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Logging; +using Deltares.DamEngine.Data.Standard.Validation; +//using XmlSerializer = Deltares.Standard.IO.Xml.XmlSerializer; + +namespace Deltares.DamEngine.Calculators.Stability +{ + public class MStabProject : ICloneable, IDisposable + { + public MStabProject Clone() + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + } + +// public class MStabProject : Project, ICloneable, IDisposable +// { +// public bool IsApplicationCreated; +// private List messages = new List(); +// +// private string originalStiFileName; +// private CalculationResult result = CalculationResult.NoRun; +// private StabilityModel stabilityModel; //Object of DefinitionModel +// +// public Func GetGeometryImage; +// +// //public MStabProject(ICoordinateSystem coordinateSystem) +// public MStabProject() +// { +// originalStiFileName = ""; +// +// Stability = new StabilityModel(); +// +// DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange; +// } +// +// +// [Label("GeometryPicture")] +// [Description("GeometryPicture")] +// public MediaTypeNames.Image GeometryPicture +// { +// get +// { +// return GetGeometryImage(); +// } +// } +// +// [XmlCategory("Identification")] +// public string OriginalStiFileName +// { +// get +// { +// return originalStiFileName; +// } +// set +// { +// originalStiFileName = value; +// } +// } +// +// /// +// /// //Object of SoilModel +// /// +// [XmlCategory("Input")] +// [XmlElement("Soils")] +// [Validate] +// public SoilModel SoilModel +// { +// get +// { +// return stabilityModel.SoilModel; +// } +// } +// +// /// +// /// Object of GeometryData +// /// +// [XmlCategory("Input")] +// public GeometryData Geometry +// { +// get +// { +// return stabilityModel != null && stabilityModel.SoilProfile != null ? stabilityModel.SoilProfile.Geometry : null; +// } +// } +// +// /// +// /// Object of WaternetData +// /// +// [XmlCategory("Input")] +// [XmlElement("WaternetData")] +// public GeotechnicsModel Geotechnics +// { +// get +// { +// return stabilityModel.GeotechnicsData; +// } +// } +// +// /// +// /// Object of DefinitionModel +// /// +// [XmlCategory("Input")] +// [XmlElement("Definitions")] +// [Validate] +// public StabilityModel Stability +// { +// get +// { +// return stabilityModel; +// } +// set +// { +// if (stabilityModel != null && !ReferenceEquals(stabilityModel, value) && +// value != null) // Hack: StabilityCalculation sets this property to null so it can claim owner ship of StabilityModel +// { +// Stability.Dispose(); +// } +// stabilityModel = value; +// +// Soil.SoilPropertyManager = stabilityModel; +// } +// } +// +// public void SetStabilityModel(StabilityModel newStabilityModel) +// { +// stabilityModel = newStabilityModel; +// +// Soil.SoilPropertyManager = stabilityModel; +// } +// +// /// +// /// Units manager object +// /// +// [XmlCategory("Input")] +// public UnitsManager Units +// { +// get +// { +// return UnitsManager.Units; +// } +// } +// +// [XmlCategory("Output")] +// public CalculationResult Result +// { +// get +// { +// return result; +// } +// set +// { +// if (result != value) +// { +// DataEventPublisher.BeforeChange(this, "Result"); +// result = value; +// DataEventPublisher.AfterChange(this, "Result"); +// } +// } +// } +// +// [XmlCategory("Output")] +// [Impact(Impact.Descriptive)] +// [XmlIgnore] +// public SlidingModel SlidingData +// { +// get +// { +// return stabilityModel != null ? stabilityModel.SlidingModel : null; +// } +// set +// { +// if (stabilityModel != null) +// { +// if (value != stabilityModel.SlidingModel) +// { +// DataEventPublisher.BeforeChange(this, "SlidingData"); +// +// stabilityModel.SlidingModel = value; +// +// if (stabilityModel.SlidingModel == null) +// { +// Result = CalculationResult.NoRun; +// } +// +// DataEventPublisher.AfterChange(this, "SlidingCurve"); // to force update in UI +// DataEventPublisher.AfterChange(this, "SlidingData"); +// DataEventPublisher.AfterChange(this, "RestProfile"); +// DataEventPublisher.AfterChange(this, "SafeProfile"); +// } +// } +// } +// } +// +// [XmlIgnore] +// [Browsable(false)] +// [Impact(Impact.None)] +// public SlidingCurve SlidingCurve +// { +// get +// { +// return SlidingData != null ? MinimumSafetyCurve : null; +// } +// } +// +// [Impact(Impact.None)] +// public RestProfile RestProfile +// { +// get +// { +// return SlidingData != null ? SlidingData.RestProfile : null; +// } +// } +// +// [Impact(Impact.None)] +// public SafeProfile SafeProfile +// { +// get +// { +// return SlidingData != null ? SlidingData.SafeProfile : null; +// } +// } +// +// [XmlIgnore] +// [ReadOnly(true)] +// [Translation("Slices")] +// public IList MinimumSafetySlices +// { +// get +// { +// if (SlidingData != null && SlidingData.CurrentZone != null && MinimumSafetyCurve != null) +// { +// return MinimumSafetyCurve.Slices; +// } +// else +// { +// return new List(); +// } +// } +// } +// +// [Validate] +// public IGeometryModel GeometryDataModel +// { +// get +// { +// return Geometry; +// } +// } +// +// [Validate] +// public IGeometryModel WaternetDataModel +// { +// get +// { +// return stabilityModel.GeotechnicsData; +// } +// } +// +// public List Messages +// { +// get +// { +// return messages; +// } +// } +// +// public List GetMStabModels() +// { +// var models = new List() +// { +// this, Geometry, SoilModel, WaternetDataModel, +// stabilityModel, stabilityModel.ConsolidationMatrix, SlidingData +// }; +// +// return models; +// } +// +// public void ProcessResults(string inputString) +// { +// var deserializer = new XmlDeserializer(); +// try +// { +// MStabProject newProject = null; +// DataEventPublisher.InvokeWithoutPublishingEvents(() => { newProject = (MStabProject)deserializer.XmlDeserializeFromString(inputString, typeof(MStabProject)); }); +// +// SlidingData = newProject.SlidingData; +// newProject.Dispose(); +// } +// catch { } +// } +// +// public IEnumerable[] GetModelComponents() +// { +// var lists = new List(); +// lists.Add(Geometry.Points); +// lists.Add(Geometry.Curves); +// lists.AddRange(stabilityModel.GetModelLists()); +// +// return lists.ToArray(); +// } +// +// /// +// /// Update object counters +// /// +// public void UpdateCounters() +// { +// Geometry.UpdateCounters(); +// stabilityModel.UpdateCounters(); +// stabilityModel.GeotechnicsData.UpdateCounters(); +// SoilModel.UpdateCounters(); +// } +// +// /// +// /// Create Default Library Data +// /// +// public void CreateDefaultLibraryData() +// { +// SoilModel.CreateDefaultSoilLibrary(); +// } +// +// /// +// /// Renumbers the geometry items +// /// +// public void RenumberGeometryObjects() +// { +// UndoRedoManager.Instance.BeginAction(); +// // Renumbers all Geometry Points as well +// GeometryDataModel.RenumberGeometryObjects(); +// stabilityModel.RenumberGeometryObjects(); +// DataEventPublisher.Changed(this, "Renumbering"); +// DataEventPublisher.DoRefreshView(null); +// UndoRedoManager.Instance.EndAction(); +// } +// +// #region IVisibleEnabled Members +// +// public override bool IsVisible(string property) +// { +// switch (property) +// { +// case "RestProfile": +// case "SafeProfile": +// case "SlidingCurve": +// return SlidingData != null; +// case "MinimumSafetySlices": +// return SlidingData != null && SlidingData.CurrentZone != null && MinimumSafetyCurve != null; +// default: +// return base.IsVisible(property); +// } +// } +// +// #endregion +// +// public MStabProject Clone() +// { +// MStabProject clone = default(MStabProject); +// DataEventPublisher.InvokeWithoutPublishingEvents(() => +// { +// string xml = new XmlSerializer().SerializeToString(this); +// clone = new XmlDeserializer().XmlDeserializeFromString(xml); +// }); +// return clone; +// } +// +// public void Dispose() +// { +// DataEventPublisher.OnAfterChange -= DataEventPublisher_OnAfterChange; +// +// if (Stability != null) +// { +// Stability.Dispose(); +// //Stability = null; +// } +// } +// +// private SlidingCurve MinimumSafetyCurve +// { +// get +// { +// return SlidingData.CurrentZone.MinimumSafetyCurve; +// } +// } +// +// private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e) +// { +// if (HasComputationImpact(sender, e.Property)) +// { +// if (!UndoRedoManager.Instance.IsUndoingRedoing) +// { +// SlidingData = null; +// } +// } +// +// if (string.IsNullOrWhiteSpace(e.Property)) +// { +// return; +// } +// +// var slidingData = sender as SlidingModel; +// if (slidingData != null && e.Property == "CurrentZone") +// { +// DataEventPublisher.AfterChange(this, x => x.SlidingCurve); +// } +// } +// +// private static bool HasComputationImpact(object sender, string property) +// { +// return property != null && PropertyInfoSupport.GetPropertyInfo(sender.GetType(), property).GetImpact(sender) == Impact.Computation; +// } +// } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometrySurface.cs (revision 334) @@ -0,0 +1,185 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class for geometry surfaces. + /// + /// + [Serializable] + public class GeometrySurface : GeometryObject + { + private readonly List innerLoops = new List(); + private GeometryLoop outerLoop = new GeometryLoop(); + + /// + /// Empty constructor + /// + public GeometrySurface() { } + + /// + /// Initializes a new instance of the class. + /// + /// The loop. + public GeometrySurface(GeometryLoop loop) + { + outerLoop = loop; + } + + /// + /// The circumference of the surface. + /// + public GeometryLoop OuterLoop + { + get + { + return outerLoop; + } + set + { + outerLoop = value; + } + } + + /// + /// All internal loops encompassed by . + /// + public List InnerLoops + { + get + { + return innerLoops; + } + } + + /// + /// determine top of geometry surface outerloop as GeometryPointString + /// + /// + public GeometryPointString DetermineTopGeometrySurface() + { + return DetermineTopCurves(); + } + + /// + /// determine bottom of geometry surface outerloop as GeometryPointString + /// + /// + public GeometryPointString DetermineBottomGeometrySurface() + { + return DetermineBottomCurves(); + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + return OuterLoop.GetGeometryBounds(); + } + + /// + /// Determine points at the top side of the geometry surface + /// + /// + private GeometryPointString DetermineTopCurves() + { + //TODO: Lot of similar code to DetermineBottomCurves; Refactoring recommended. + var minXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMinX()); + var maxXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMaxX()); + + //verticals at start are omitted + Point2D startTopPoint = minXPoints.OrderByDescending(p => p.Z).First(); + + //verticals at end are omitted + Point2D endTopPoint = maxXPoints.OrderByDescending(p => p.Z).First(); + + var topPoints = new GeometryPointString(); + + int currentIndex = OuterLoop.CalcPoints.IndexOf(startTopPoint); + + while (!topPoints.CalcPoints.Contains(endTopPoint)) + { + topPoints.CalcPoints.Add(OuterLoop.CalcPoints[currentIndex++]); + if (currentIndex >= OuterLoop.CalcPoints.Count) + { + currentIndex = 0; + } + } + + // Replace the points by clones + for (int i = 0; i < topPoints.CalcPoints.Count; i++) + { + topPoints.CalcPoints[i] = new Point2D(topPoints.CalcPoints[i].X, topPoints.CalcPoints[i].Z); + } + + return topPoints; + } + + /// + /// determine curves at the bottom side of the geometry surface + /// + /// + private GeometryPointString DetermineBottomCurves() + { + //TODO: Lot of similar code to DetermineTopCurves; Refactoring recommended. + //create copy, leave original + var minXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMinX()); + var maxXPoints = OuterLoop.GetPointsAtX(OuterLoop.GetMaxX()); + + //verticals at start are omitted + var startBottomPoint = minXPoints.OrderBy(p => p.Z).First(); + + //verticals at end are omitted + var endBottomPoint = maxXPoints.OrderBy(p => p.Z).First(); + + var bottomPoints = new GeometryPointString(); + + int currentIndex = OuterLoop.CalcPoints.IndexOf(endBottomPoint); + + while (!bottomPoints.CalcPoints.Contains(startBottomPoint)) + { + bottomPoints.CalcPoints.Add(OuterLoop.CalcPoints[currentIndex++]); + if (currentIndex >= OuterLoop.CalcPoints.Count) + { + currentIndex = 0; + } + } + + // Replace the points by clones + for (int i = 0; i < bottomPoints.CalcPoints.Count; i++) + { + bottomPoints.CalcPoints[i] = new Point2D(bottomPoints.CalcPoints[i].X, bottomPoints.CalcPoints[i].Z); + } + + // As the curves are sorted clockwise, the bottomcurves are always orientated from right to left + // while this result of this method must be from left to right so reverse the curves + bottomPoints.CalcPoints.Reverse(); + return bottomPoints; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/IAssignable.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/IAssignable.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/IAssignable.cs (revision 334) @@ -0,0 +1,31 @@ +// Copyright (C) Stichting Deltares 2017. 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.Runtime.InteropServices; + +namespace Deltares.DamEngine.Data.General +{ + [ComVisible(true)] + public interface IAssignable + { + void Assign(T t); + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamCalculation.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamCalculation.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamCalculation.cs (revision 334) @@ -0,0 +1,326 @@ +// Copyright (C) Stichting Deltares 2017. 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.Threading.Tasks; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.Standard.Calculation; + +namespace Deltares.DamEngine.Calculators +{ + + [Serializable] + public class DamCalculationException : ApplicationException + { + public DamCalculationException(string message) + : base(message) + { + } + } + + //Todo handling of the actual messages instead of just CalculationResult has to be added. + /// + /// class DamFailureMechanismeCalculation + /// + public class DamCalculation : ICalculation + { + private string projectWorkingDirectory = ""; + private string projectDataDirectory = ""; + private DamProjectData damProjectData; + private DamProjectCalculator damProjectCalculator; + private string mstabExePath = @".\DGeoStability.exe"; + private int failureMechanismIndex = 0; + private ProgressDelegate progressDelegate = null; + private int maxCalculationCores = 255; + private SendMessageDelegate sendMessageDelegate = null; + + /// + /// Constructor + /// + public DamCalculation() + { + damProjectData = new DamProjectData(); + damProjectCalculator = new DamProjectCalculator(damProjectData); + } + + public int MaxCalculationCores + { + get { return maxCalculationCores; } + set { maxCalculationCores = value; } + } + + public string Version + { + get + { + return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string ProjectWorkingDirectory + { + get { return projectWorkingDirectory; } + set { projectWorkingDirectory = value; } + } + + public string ProjectDataDirectory + { + get { return projectDataDirectory; } + set { projectDataDirectory = value; } + } + + public string MStabExePath + { + get { return mstabExePath; } + set { mstabExePath = value; } + } + + #region ICalculation Members + + public CalculationResult RegisterUserAbort(UserAbortDelegate userAbortDelegate) + { + if (this.damProjectCalculator == null) + return CalculationResult.UnexpectedError; + else + { + //var lp = (TUserAbortDelegate)Delegate.CreateDelegate(typeof(TUserAbortDelegate), userAbortDelegate.Target, userAbortDelegate.Method.Name); + //this.damProjectCalculator.SetUserAbortDelegate(lp); + return CalculationResult.Succeeded; + } + } + + public CalculationResult RegisterProgress(ProgressDelegate progressDelegate) + { + if (damProjectCalculator == null) + { + return CalculationResult.UnexpectedError; + } + this.progressDelegate = progressDelegate; + this.damProjectCalculator.Progress = progressDelegate; + return CalculationResult.Succeeded; + } + + public CalculationResult RegisterSendMessage(SendMessageDelegate sendMessageDelegate) + { + this.sendMessageDelegate = sendMessageDelegate; + + if (this.damProjectCalculator == null) + return CalculationResult.UnexpectedError; + else + { + //var lp = (TSendMessageDelegate) Delegate.CreateDelegate(typeof (TSendMessageDelegate), sendMessageDelegate.Target, sendMessageDelegate.Method.Name); + //this.damProjectCalculator.SetSendMessageDelegate(lp); + return CalculationResult.Succeeded; + } + } + + public CalculationResult RegisterSendDebugInfo(SendDebugInfodelegate sendDebugInfoDelegate) + { + if (this.damProjectCalculator == null) + return CalculationResult.UnexpectedError; + else + { + //var d = (Delegate)sendDebugInfoDelegate; + //this.damProjectCalculator.SetSendDebugInfoDelegate((TSendDebugInfoDelegate)d); + return CalculationResult.Succeeded; + } + } + + public CalculationResult RegisterGetValues(GetValuesDelegate getValuesDelegate) + { + if (this.damProjectCalculator == null) + return CalculationResult.UnexpectedError; + else + { + //var lp = (TGetValuesDelegate)Delegate.CreateDelegate(typeof(TGetValuesDelegate), getValuesDelegate.Target, getValuesDelegate.Method.Name); + //this.damProjectCalculator.SetGetValuesDelegate(lp); + return CalculationResult.Succeeded; + } + } + + public CalculationResult RegisterSetValues(SetValuesDelegate setValuesDelegate) + { + if (this.damProjectCalculator == null) + return CalculationResult.UnexpectedError; + else + { + //var lp = (TSetValuesDelegate)Delegate.CreateDelegate(typeof(TSetValuesDelegate), setValuesDelegate.Target, setValuesDelegate.Method.Name); + //this.damProjectCalculator.SetSetValuesDelegate(lp); + return CalculationResult.Succeeded; + } + } + + public CalculationResult Validate() + { + if (this.damProjectData == null) + { + return CalculationResult.UnexpectedError; + } + else + { + try + { + // first check project data + CalculationResult res = this.damProjectData.Validate(); + if (res == CalculationResult.Succeeded) + { + try + { + // then check general calculator data + this.damProjectCalculator.ValidateGeneral(); + } + catch (Exception) + { + + res = CalculationResult.InvalidInputData; + } + + } + return res; + + } + catch + { + return CalculationResult.InvalidInputData; + } + } + } + + public CalculationResult GetResults(ref string results) + { + results = "No results available."; + return CalculationResult.Succeeded; + } + + #endregion + + /// + /// Calculate failure mechanism + /// + /// + /// +// private void CalculateFailureMechanismStabilityInsideMStab( +// DamFailureMechanismeCalculationSpecification failureMechanismeCalculationSpecification, +// string failureMechanismWorkingDirectory) +// { +// if (string.IsNullOrWhiteSpace(failureMechanismWorkingDirectory)) +// throw new ArgumentException("Invalid working directory. The supplied string is empty or null.", "failureMechanismWorkingDirectory"); +// +// string stabilityWorkingPath = Path.GetFullPath(failureMechanismWorkingDirectory); +// +// var timeSerieStabilityCalculator = new TimeSerieStabilityCalculator +// { +// StabilityWorkingPath = stabilityWorkingPath, +// IsMStabCalculationOff = false, +// MStabExePath = this.mstabExePath, +// SendMessageDelegate = sendMessageDelegate +// }; +// +// if (!Directory.Exists(timeSerieStabilityCalculator.StabilityWorkingPath)) +// { +// Directory.CreateDirectory(timeSerieStabilityCalculator.StabilityWorkingPath); +// } +// int locationCounter = 0; +// var safetyFactorsTimeSerieCollection = new TimeSerieCollection(); +// foreach (DamJob damJob in (damProjectData.WaterBoardJob as WaterBoardJob).Jobs) +// { +// DikeJob dikeJob = damJob as DikeJob; +// foreach (LocationJob locationJob in dikeJob.Jobs) +// { +// if (locationJob.Run.Value && locationJob.WaterLevelTimeSerie != null) +// { +// TimeSerie safefactorsTimeSerie = timeSerieStabilityCalculator.CreateStabilityInsideSafetyFactorTimeSerie( +// locationJob.WaterLevelTimeSerie, +// dikeJob.Dike, +// locationJob.Location, +// locationCounter, +// ProjectDataDirectory, +// failureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters, +// null); +// locationJob.LocationResult.StabilityTimeSerie = safefactorsTimeSerie; +// safefactorsTimeSerie.LocationId = locationJob.Location.Name; +// safetyFactorsTimeSerieCollection.Series.Add(safefactorsTimeSerie); +// locationCounter++; +// } +// } +// timeSerieStabilityCalculator.IsCalculateAllStabilityProjectsAtOnce = true; +// timeSerieStabilityCalculator.CalculateSafetyFactorFromTimeSeries(TimeSerieParameters.StabilityInsideFactor.ToString(), +// dikeJob.Dike, safetyFactorsTimeSerieCollection); +// } +// ThrowHelper.ThrowWhenConditionIsTrue("No locations specified.",() => locationCounter == 0); +// } + + public void CalculateDamProject(DamProjectData damProject, string defaultProjectWorkingPath) + { +// damProjectData = damProject; ##Bka +// +// // Set default working directory +// if (ProjectWorkingDirectory.Equals("")) +// { +// ProjectWorkingDirectory = defaultProjectWorkingPath; +// } +// +// this.failureMechanismIndex = -1; +// ThrowHelper.ThrowWhenConditionIsTrue("No actual calculation specified.", +// () => damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications.Count == 0); +// +// Parallel.Run(damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications, this.RunFailureMechanism, this.progressDelegate, this.MaxCalculationCores); + } + + private int GetFailureMechanismIndex() + { + lock (this) + { + failureMechanismIndex++; + return failureMechanismIndex; + } + } + +// private void RunFailureMechanism(object task) +// { +// DamFailureMechanismeCalculationSpecification failureMechanismCalculationSpecification = (DamFailureMechanismeCalculationSpecification)task; +// string failureMechanismWorkingDirectory = String.Format(@"{0}\FM{1}\", ProjectWorkingDirectory, GetFailureMechanismIndex()); +// DeleteDirectoryWithFiles(failureMechanismWorkingDirectory); +// if (failureMechanismCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) +// { +// CalculateFailureMechanismStabilityInsideMStab(failureMechanismCalculationSpecification, failureMechanismWorkingDirectory); +// } +// } + + /// + /// Delete all files in directory and all files in it + /// + /// + private void DeleteDirectoryWithFiles(string directory) + { + if (Directory.Exists(directory)) + { + string[] fileNames = Directory.GetFiles(directory); + foreach (string filename in fileNames) + { + File.Delete(filename); + } + Directory.Delete(directory); + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LandwardDirection.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LandwardDirection.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LandwardDirection.cs (revision 334) @@ -0,0 +1,39 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// The direction where land lies in the XZ-plane for a surface line. + /// + public enum LandwardDirection + { + /// + /// Land lies towards the positive X axis. + /// + PositiveX, + + /// + /// Land lies towards the negative X axis. + /// + NegativeX + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryCurve.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryCurve.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryCurve.cs (revision 334) @@ -0,0 +1,207 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geometry +{ + /// + /// Represents the possible directions of the curve + /// + public enum CurveDirection + { + /// + /// Unknown as direction + /// + Unknown = -1, + /// + /// Forward as direction + /// + Forward = 0, + /// + /// Reverse as direction + /// + Reverse = 1 + } + + /// + /// Contains the collection of all the curves data. + /// + public class GeometryCurve : GeometryObject + { + private Point2D endPoint; + private Point2D headPoint; + + /// + /// Initializes a new instance of the class. + /// + public GeometryCurve() {} + + /// + /// Initializes a new instance of the class. + /// + /// The head point. + /// The end point. + public GeometryCurve(Point2D headPoint, Point2D endPoint) + { + this.headPoint = headPoint; + this.endPoint = endPoint; + } + + /// + /// Gets or sets the head point of the curve. + /// + public virtual Point2D HeadPoint + { + get + { + return headPoint; + } + set + { + headPoint = value; + } + } + + /// + /// Gets or sets the end point of the curve. + /// + public virtual Point2D EndPoint + { + get + { + return endPoint; + } + set + { + endPoint = value; + } + } + + /// + /// The unique name of the object. + /// + public override string Name + { + get + { + if (!string.IsNullOrEmpty(base.Name)) + { + return base.Name; + } + + string text = ""; + if (HeadPoint != null) + { + text += HeadPoint.ToString().Trim(); + } + text += "-"; + if (EndPoint != null) + { + text += EndPoint.ToString().Trim(); + } + return text; + } + set + { + base.Name = value; + } + } + + /// + /// Swaps and . + /// + public void Reverse() + { + var point = HeadPoint; + HeadPoint = EndPoint; + EndPoint = point; + } + + /// + /// Returns the head point in given direction + /// + /// Direction is either Forward or Reverse or Unknown + /// Returns the head point in the given direction + public Point2D GetHeadPoint(CurveDirection aDirection) + { + if (aDirection == CurveDirection.Forward) + { + return headPoint; + } + + return endPoint; + } + + /// + /// Gets the end point in the given direction + /// + /// Direction is either Forward or Reverse or Unknown + /// Returns the end point in the given direction + public Point2D GetEndPoint(CurveDirection aDirection) + { + if (aDirection == CurveDirection.Forward) + { + return endPoint; + } + + return headPoint; + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + if (HeadPoint != null && EndPoint != null) + { + var head = new GeometryBounds(HeadPoint.X, HeadPoint.X, HeadPoint.Z, HeadPoint.Z); + var end = new GeometryBounds(EndPoint.X, EndPoint.X, EndPoint.Z, EndPoint.Z); + return head + end; + } + + return null; + } + + /// + /// Determines whether the curve contains the specified point within the given tolerance. + /// + /// The point. + /// The tolerance. + /// + public bool ContainsPoint(Point2D point, double tolerance) + { + return HeadPoint != null && EndPoint != null && + Routines2D.DoesPointExistInLine(HeadPoint.X, HeadPoint.Z, EndPoint.X, EndPoint.Z, point.X, point.Z, tolerance); + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + /// 2 + public override string ToString() + { + return string.Empty; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapterException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapterException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapterException.cs (revision 334) @@ -0,0 +1,51 @@ +// Copyright (C) Stichting Deltares 2017. 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.Dikes_Design +{ + [Serializable] + public class SurfaceLineAdapterException : Exception + { + public SurfaceLineAdapterException() + { + } + + public SurfaceLineAdapterException(string message) + : base(message) + { + } + + public SurfaceLineAdapterException(string message, Exception inner) + : base(message, inner) + { + } + + protected SurfaceLineAdapterException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Layer.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Layer.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Layer.cs (revision 334) @@ -0,0 +1,93 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// publisherEventArgs helper struct, to aid in Layer Intersection + /// TODO: Comment + /// + public struct LayerIntersectionPoint + { + private readonly Point2D intersectionPoint; + private readonly SoilLayer2D surfaceRefKey; + + internal LayerIntersectionPoint(Point2D aIntersectionPoint, SoilLayer2D aSurfaceRefKey) + { + intersectionPoint = aIntersectionPoint; + surfaceRefKey = aSurfaceRefKey; + } + + internal Point2D IntersectionPoint + { + get + { + return intersectionPoint; + } + } + + internal SoilLayer2D SurfaceRefKey + { + get + { + return surfaceRefKey; + } + } + } + + /// + /// publisherEventArgs helper struct, to aid in Layer Intersection + /// TODO: Comment + /// + public class Layer : SoilLayer1D + { + /// + /// Initializes a new instance of the class. + /// + /// A start point. + /// An end point. + /// A stability soil properties ID. + public Layer(Point2D aStartPoint, Point2D aEndPoint, Soil aStabilitySoilPropertiesId) + { + StartPoint = aStartPoint; + EndPoint = aEndPoint; + Soil = aStabilitySoilPropertiesId; + } + + /// + /// Gets or sets the start point. + /// + /// + /// The start point. + /// + public Point2D StartPoint { get; set; } + + /// + /// Gets or sets the end point. + /// + /// + /// The end point. + /// + public Point2D EndPoint { get; set; } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/AquitardEvaluator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/AquitardEvaluator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/AquitardEvaluator.cs (revision 334) @@ -0,0 +1,155 @@ +// Copyright (C) Stichting Deltares 2017. 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.Geotechnics; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class AquitardEvaluatorException : Exception + { + public AquitardEvaluatorException(string message) + : base(message) + { + } + } + + public class AquitardEvaluator + { + private SoilProfile1D soilProfile; + const double CMinimimalUnitWeightAquitard = 12.0; // kN/m2 + public AquitardEvaluator(SoilProfile1D soilProfile) + { + this.soilProfile = soilProfile; + } + + /// + /// Sum all aquitards between boezembottom and aquifer with a minimum weight of CMinimimalUnitWeightAquitard + /// + /// + /// + public double DetermineAquitardThicknessWithMinimalWeight(double surfaceLevel, Soil embankmentMaterial) + { + return DetermineAquitardThickness(surfaceLevel, true, embankmentMaterial); + } + + /// + /// Sum all aquitards between boezembottom and aquifer without check on minimum weight + /// + /// + /// + public double DetermineAquitardThicknessWithoutMinimalWeight(double surfaceLevel, Soil embankmentMaterial) + { + return DetermineAquitardThickness(surfaceLevel, false, embankmentMaterial); + } + + /// + /// Sum all aquitards between boezembottom and aquifer + /// + /// + /// + /// + private double DetermineAquitardThickness(double surfaceLevel, bool checkOnMinimalWeight, Soil embankmentMaterial) + { + ThrowExceptionWhenSurfaceLevelOutsideProfile(surfaceLevel, embankmentMaterial); + + double aquitardBottomLevel = this.soilProfile.GetTopLevelOfHighestAquifer(); + double thickness = 0.0; + + List layers = new List(this.soilProfile.Layers); + if (surfaceLevel > soilProfile.TopLevel) + { + SoilLayer1D embankmentLayer = new SoilLayer1D(embankmentMaterial, surfaceLevel); + layers.Insert(0, embankmentLayer); + } + + foreach (SoilLayer1D layer in layers) + { + bool includeLayer = true; + + // Only include layer if soil has minimal weight + if (checkOnMinimalWeight) + { + includeLayer = layer.Soil.BelowPhreaticLevel >= CMinimimalUnitWeightAquitard; + } + + // Only include layer if soil is waterremmend (clay or peat) + includeLayer = includeLayer && (layer.Soil.SoilType == SoilType.Clay || layer.Soil.SoilType == SoilType.Peat); + if (includeLayer) + { + double levelTop = Math.Min(surfaceLevel, layer.TopLevel); + double levelBottom = soilProfile.TopLevel; + if (soilProfile.Layers.Contains(layer)) + { + levelBottom = Math.Max(aquitardBottomLevel, layer.TopLevel - soilProfile.GetLayerHeight(layer)); + } + + if (levelTop > levelBottom) + { + thickness += (levelTop - levelBottom); + } + } + } + + return thickness; + } + + public double DetermineAquitardClayThickness(double surfaceLevel) + { + ThrowExceptionWhenSurfaceLevelOutsideProfile(surfaceLevel, null); + //ThrowExceptionWhenMoreThan2Aquifers(); + double aquitardBottomLevel = this.soilProfile.GetTopLevelOfHighestAquifer(); + double thickness = 0.0; + foreach (SoilLayer1D layer in soilProfile.Layers) + { + if (layer.Soil.SoilType == SoilType.Clay) + { + double levelTop = Math.Min(surfaceLevel, layer.TopLevel); + double levelBottom = Math.Max(aquitardBottomLevel, layer.TopLevel - soilProfile.GetLayerHeight(layer)); + if (levelTop > levelBottom) + { + thickness += (levelTop - levelBottom); + } + } + } + return thickness; + } + + private void ThrowExceptionWhenSurfaceLevelOutsideProfile(double surfaceLevel, Soil embankmentMaterial) + { + if (surfaceLevel < soilProfile.BottomLevel || (surfaceLevel > soilProfile.TopLevel && embankmentMaterial == null)) + { + throw new AquitardEvaluatorException(String.Format( + "Specified z-level {0} in AquitardEvaluator outside soilprofile '{1}' (should be between {2} and {3}", + surfaceLevel, soilProfile.Name, soilProfile.BottomLevel, soilProfile.TopLevel)); + } + } + + private void ThrowExceptionWhenMoreThan2Aquifers() + { + if (soilProfile.GetAquiferLayers().Count > 2) + { + throw new AquitardEvaluatorException("Soilprofile has more than 2 aquifers"); + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamRunner.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamRunner.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamRunner.cs (revision 334) @@ -0,0 +1,264 @@ +// Copyright (C) Stichting Deltares 2017. 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 System.Reflection; +using System.Text; +using Deltares.DamEngine.Calculators.Dikes_Assessment_Regional; +using Deltares.DamEngine.Calculators.Stability; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.RWScenarios; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Logging; + +namespace Deltares.DamEngine.Calculators +{ + public class DamRunner + { + private readonly DamProjectData damProjectData; + private readonly string directory = ""; + private int maxCalculationCores = 255; + private DateTime startTimeCalculation; + + public DamRunner(DamProjectData damProjectData, string projectFileName) + { + this.damProjectData = damProjectData; + directory = Path.GetDirectoryName(projectFileName); + } + + private delegate void ProcessResultDelegate(DamProjectData damProject, CalculationResult result, string output); + + private void ProcessResultLocal(DamProjectData damProject, CalculationResult result, string output) + { + damProjectData.UpdateCalculations(); + damProjectData.UpdateSchematizationFactors(); + + TimeSpan elapsedTime = DateTime.Now - startTimeCalculation; + string timeMessage = String.Format(LocalizationManager.GetTranslatedText(this, "CalculationTime"), elapsedTime.ToString(@"dd\.hh\:mm\:ss")); + string paragraphSepatator = Environment.NewLine + Environment.NewLine; + if (output.StartsWith("Thread was being aborted")) + { + // LocalizedMessageBox.Show(this, "CalculationAborted"); ##Bka: most probably unwanted, replace with other mechanism + } + else if (result == CalculationResult.Succeeded) + { + string openingMessage = LocalizationManager.GetTranslatedText(this, "CalculationFinished"); + // LocalizedMessageBox.ShowTranslatedText(openingMessage + paragraphSepatator + timeMessage + paragraphSepatator + output); ##Bka: most probably unwanted, replace with other mechanism + } + else if ((result == CalculationResult.RunFailed) || (result == CalculationResult.UnexpectedError)) + { + string openingMessage = LocalizationManager.GetTranslatedText(this, "CalculationFailed"); + //LocalizedMessageBox.ShowTranslatedText(openingMessage + paragraphSepatator + output); ##Bka: most probably unwanted, replace with other mechanism + } + } + + private void ProcessResult(DamProjectData damProject, CalculationResult result, string output) + { + // if (BindSupport.InvokeControl.InvokeRequired) + // { + // var d = new ProcessResultDelegate(ProcessResultLocal); + // BindSupport.InvokeControl.Invoke(d, new object[] { damProject, result, output }); + // } + // else ##Bka: most probably unwanted, replace with other mechanism + { + ProcessResultLocal(damProject, result, output); + } + } + + public void PerformCalculation(ProgressDelegate progressDelegate) + { + startTimeCalculation = DateTime.Now; + try + { + switch (damProjectData.DamProjectType) + { + case DamProjectType.Calamity: + { + var damCalculation = new DamCalculation(); + + damCalculation.RegisterProgress(progressDelegate); + damCalculation.RegisterSendMessage(HandleCalculationSendMessage); + damCalculation.ProjectWorkingDirectory = ""; // Force default location for working directory + damCalculation.ProjectDataDirectory = directory + Path.DirectorySeparatorChar; + damCalculation.MStabExePath = StabilityCalculator.MStabExePath; + damCalculation.MaxCalculationCores = MaxCalculationCores; + damCalculation.CalculateDamProject(damProjectData, DamProjectData.ProjectWorkingPath); //##Bka!? or damCalculation.ProjectDataDirectory + var output = FillOutputForMessage(damProjectData.LocationJobs); + ProcessResult(damProjectData, CalculationResult.Succeeded, output); + break; + } + case DamProjectType.Assessment: + { + var rwScenariosCalculation = new RWScenariosCalculation + { + SchematizationFactorData = damProjectData.SchematizationFactorData, + MaxCalculationCores = MaxCalculationCores + }; + + rwScenariosCalculation.RegisterProgress(progressDelegate); + rwScenariosCalculation.RegisterSendMessage(HandleCalculationSendMessage); + rwScenariosCalculation.MStabExePath = StabilityCalculator.MStabExePath; + rwScenariosCalculation.PipingModelType = damProjectData.DamProjectCalculationSpecification.CurrentSpecification.PipingModelType; + rwScenariosCalculation.MStabParameters = + damProjectData.DamProjectCalculationSpecification.CurrentSpecification + .FailureMechanismeParamatersMStab.MStabParameters; + EvaluationJob evaluationJob = damProjectData.GetEvaluationJob(); + + RemoveLogMessages(evaluationJob); + CalculationResult calculationResult; + try + { + //rwScenariosCalculation.Load(evaluationJob.XML); ##Bka + calculationResult = rwScenariosCalculation.Run(); + //DataEventPublisher.DataListModified(LogManager.Messages); + } + catch (Exception) + { + calculationResult = CalculationResult.UnexpectedError; + } + + string results = ""; + rwScenariosCalculation.GetResults(ref results); + + //evaluationJob.XML = results; ##Bka + evaluationJob.AttachResults(damProjectData.LocationJobs); + var output = FillOutputForMessage(damProjectData.LocationJobs); + ProcessResult(damProjectData, calculationResult, output); + break; + } + case DamProjectType.Design: + { + if (damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications.Count > 0) + { + List scenarios = CreateScenarioListForCalculation(); + var damProjectCalculator = new DamProjectCalculator(damProjectData) + { + MaxCalculationCores = MaxCalculationCores, + MStabProgramPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "DGeoStability.exe"), + SlopeWProgramPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Slope2.exe"), + ProjectDataDirectory = directory + Path.DirectorySeparatorChar, + Progress = progressDelegate, + CalculationBaseDirectory = DamProjectData.ProjectWorkingPath + @"\CalculationFiles\" + }; + + damProjectCalculator.Calculate(damProjectData, scenarios); + var output = FillOutputForMessage(damProjectData.LocationJobs); + ProcessResult(damProjectData, CalculationResult.Succeeded, output); + } + } + break; + } + } + catch (Exception exception) + { + var sb = new StringBuilder(exception.Message); + for (Exception innerException = exception.InnerException; innerException != null; innerException = innerException.InnerException) + { + sb.Append('\n'); + sb.Append(innerException.Message); + } + + ProcessResult(damProjectData, CalculationResult.RunFailed, sb.ToString()); + } + } + + + private string FillOutputForMessage(IEnumerable locationJobs) + { + var res = ""; + foreach (var locationJob in locationJobs) + { + if (locationJob.Result == JobResult.Failed) + { + var failedLocationCalculation = LocalizationManager.GetTranslatedText(GetType(), "failedLocationCalculationId"); + res = res + String.Format(failedLocationCalculation, locationJob.Location.Name) + Environment.NewLine; + } + else + { + if (locationJob.Result != JobResult.NoRun && !locationJob.HasLocationResults + && !locationJob.HasRWScenarioResults && !locationJob.HasScenarioResults) + { + var noResultsForLocation = LocalizationManager.GetTranslatedText(GetType(), "noResultsForLocationId"); + res = res + String.Format(noResultsForLocation, locationJob.Location.Name) + Environment.NewLine; + } + } + } + return res; + } + + + /// + /// Create a list of scenarios to be calculated + /// + /// List of the generated scenarios + private List CreateScenarioListForCalculation() + { + var scenarios = new List(); + + // The locations of the scenarios can get out of sync after a calculation, so make sure they are in sync + damProjectData.WaterBoard.UpdateLocationsForScenarios(); + + List selectedLocations = damProjectData.SelectedLocationJobs.Select(x => x.Location).ToList(); + foreach (var location in selectedLocations) + { + scenarios.AddRange(location.Scenarios); + } + + return scenarios; + } + + private void RemoveLogMessages(EvaluationJob evaluationJob) + { +// foreach (LogMessage logMessage in LogManager.Messages.ToArray()) +// { +// foreach (var location in evaluationJob.Locations) +// { +// if (logMessage.SubjectName.Equals(location.ToString())) +// { +// LogManager.Messages.Remove(logMessage); +// } +// } +// } +// +// DataEventPublisher.DataListModified(LogManager.Messages); + } + + private void HandleCalculationSendMessage(LogMessage logMessage) + { +// lock (LogManager.Messages) +// { +// LogManager.Messages.Add(logMessage); +// DataEventPublisher.DataListModified(LogManager.Messages); +// } + } + + public int MaxCalculationCores + { + get { return maxCalculationCores; } + set { maxCalculationCores = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (revision 334) @@ -0,0 +1,98 @@ + + + + + Debug + AnyCPU + {E943B1D5-FAFA-4AFE-9071-F8B22CF612EA} + Library + Properties + Deltares.DamEngine.Calculators + Deltares.DamEngine.Calculators + v4.5 + 512 + + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b7a49c1a-1c91-4d72-aba9-9fbac2509d8e} + Deltares.DamEngine.Data + + + + + + + + + + \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/Gauge.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/Gauge.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Gauges/Gauge.cs (revision 334) @@ -0,0 +1,39 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General.Gauges +{ + public class Gauge + { + public virtual string Name { get; set; } + public virtual Location Location{ get; set; } + public virtual double LocalX { get; set; } + + public double? Value { get; set; } + + public override string ToString() + { + return String.Format("{0} @ Location {1} | Local X={2}", this.Name, this.Location != null ? this.Location.Name : "?", this.LocalX); + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SurfaceLineException.cs (revision 334) @@ -0,0 +1,35 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// Surface Line Exception + /// + public class SurfaceLineException : System.Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public SurfaceLineException(string message) : base(message) {} + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/DikeMaterialRWEvaluator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/DikeMaterialRWEvaluator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/RWScenarios/DikeMaterialRWEvaluator.cs (revision 334) @@ -0,0 +1,48 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Data.RWScenarios +{ + public class DikeMaterialRWEvaluator : RWEvaluator + { + public DikeMaterialRWEvaluator() + { + } + + public override Enum Evaluate(Location location, SoilGeometry soilGeometry, params Enum[] previousChoices) + { + base.Evaluate(location, soilGeometry, previousChoices); + + if (location.DikeMaterialType == SoilType.Peat) + { + return DikeDrySensitivity.Dry; + } + else + { + return DikeDrySensitivity.None; + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Sensors/SensorLocation.cs (revision 334) @@ -0,0 +1,472 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.General.Sensors +{ + /// + /// Association class for sensor data and a location + /// + public class SensorLocation + { + #region Business Rules + + /// + /// Specication to test if the value of the candidate is valid + /// +// internal class IgnoreOrLocationData : PredicateSpecification +// { +// public IgnoreOrLocationData() +// : base(x => x == DataSourceTypeSensors.Ignore || x == DataSourceTypeSensors.LocationData) +// { +// Description = "Only Ignore or LocationData value allowed for this property."; +// } +// } + + /// + /// Specication to test if the value of the candidate is valid + /// +// internal class SensorOrLocationData : PredicateSpecification +// { +// public SensorOrLocationData() +// : base(x => x == DataSourceTypeSensors.Sensor || x == DataSourceTypeSensors.LocationData) +// { +// Description = "Only Sensor or LocationData value allowed for this property."; +// } +// } + + #endregion + + /// + /// Constructor is needed for XML deserialization + /// + + public SensorLocation() + { + PL1WaterLevelAtRiver = DataSourceTypeSensors.LocationData; + PL1WaterLevelAtPolder = DataSourceTypeSensors.LocationData; + } + + private Group sensorGroup; + + /// + /// Gets the PL line offset below dike top at river. + /// + public double PLLineOffsetBelowDikeTopAtRiver + { + get { return Location.PlLineOffsetBelowDikeTopAtRiver; } + } + + /// + /// Gets the PL line offset below dike top at polder. + /// + public double PLLineOffsetBelowDikeTopAtPolder + { + get { return Location.PLLineOffsetDryBelowDikeTopAtPolder; } + } + + /// + /// Gets the PL line offset below dike toe at polder. + /// + public double PLLineOffsetBelowDikeToeAtPolder + { + get { return Location.PlLineOffsetBelowDikeToeAtPolder; } + } + + /// + /// Gets the PL line offset dry below shoulder base inside. + /// + public double PLLineOffsetDryBelowShoulderBaseInside + { + get { return Location.PlLineOffsetBelowShoulderBaseInside; } + } + + /// + /// Gets or sets the DAM location. + /// + /// + /// The location. + /// + [XmlIgnore] + // [Specification(typeof(NotNullSpecification))] + public Location Location { get; set; } + + /// + /// Gets the location Name. + /// + /// + /// If the Name is empty it could indicate that there is no reference + /// to a valid location + /// + [XmlIgnore] + public string LocationName + { + get { return (Location != null) ? Location.Name : string.Empty; } + } + + /// + /// Gets or sets the sensor group. + /// + /// + /// The group. + /// + // [Specification(typeof(NotNullSpecification))] + public Group Group + { + get { return sensorGroup; } + set + { + sensorGroup = value; + } + } + + public void ResetGroupID(int id) + { + sensorGroup.ID = id; + } + + /// + /// Gets the group ID. + /// + /// + /// If the ID has value -1 then the there is no valid reference (null) + /// or the group is transient. + /// + [XmlIgnore] + public int GroupID + { + get + { + if (sensorGroup == null) + return -1; + + return sensorGroup.ID; + } + } + + /// + /// Gets the sensor selection. + /// + [XmlIgnore] + public IEnumerable Sensors + { + get + { + if (sensorGroup == null) + return new Sensor[0]; + + return sensorGroup.Selection; + } + } + + /// + /// Gets or sets the PL3 data source type. + /// + /// + /// The PL3. + /// + // [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL3 { get; set; } + + /// + /// Gets or sets the PL4 data source type. + /// + /// + /// The PL4. + /// + // [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL4 { get; set; } + + + /// + /// Gets or sets the outer water level data source type. + /// + /// + /// The outer water level. + /// + // [Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL1WaterLevelAtRiver { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike top at river data source type. + /// + /// + /// Data source type for PL1 PLLine offset below dike top at river. + /// + // [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtRiver { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike top at polder data source type + /// + /// + /// The PL1 PL line offset below dike top at polder. + /// + // [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtPolder { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below shoulder base inside data source type + /// + /// + /// The PL1 PL line offset below shoulder base inside. + /// + // [Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowShoulderBaseInside { get; set; } + + /// + /// Gets or sets the PL1 PL line offset below dike toe at polder data source type. + /// + /// + /// The PL1 PL line offset below dike toe at polder. + /// + //[Specification(typeof(IgnoreOrLocationData))] + public DataSourceTypeSensors PL1PLLineOffsetBelowDikeToeAtPolder { get; set; } + + /// + /// Gets or sets the PL1 polder level data source type. + /// + /// + /// The PL1 polder level. + /// + //[Specification(typeof(SensorOrLocationData))] + public DataSourceTypeSensors PL1WaterLevelAtPolder { get; set; } + + /// + /// Gets the sensor count. + /// + public int SensorCount + { + get + { + return sensorGroup == null ? 0 : Group.SensorCount; + } + } + + public SurfaceLine2 SurfaceLine + { + get { return Location.SurfaceLine2; } + } + + public double RiverLevel + { + get { return Location.RiverLevel; } + } + + public double PolderLevel + { + get { return Location.PolderLevel; } + } + + public double? HeadPl3 + { + get { return Location.HeadPl3; } + } + + public double? HeadPl4 + { + get { return Location.HeadPl4; } + } + + public string Alias { get; set; } // ToDo Tom/Kin Sun Waarvoor nodig? Wordt nergens gebruikt. Kan gewoon weg!? + + public string Profile + { + get; //{ return SoilProfile2D } ; + set; + } + + public string MStabFile + { + get; //{ return SoilProfile2D } ; + set; + } + + /// + /// Gets the PiezometricHead type sensors sorted by relative location along profile. + /// + /// Type of the pl line. + /// +// internal SortedDictionary GetSensorsSortedByRelativeLocationAlongProfile(PLLineType plLineType) +// { +// var calculatedRelativeLocations = BuildRelativeLocationTable(); +// +// var table = new SortedDictionary(); +// +// // leave out the water level and polder level sensors +// var candidateSensors = +// Sensors.GetBySpecification(new PiezometricHeadSensorSpecification()); +// +// foreach (var sensor in candidateSensors) +// { +// if (sensor.PLLineMappings.Contains(plLineType)) +// { +// double relativeLocation = sensor.RelativeLocationSpecified ? +// sensor.RelativeLocation : calculatedRelativeLocations[sensor]; +// +// if (table.ContainsKey(relativeLocation)) +// { +// throw new InvalidOperationException( +// "Error creating lookup table with sensors sorted by relative location along profile. The x-location " + relativeLocation + " already exists. Sensor " + sensor); +// } +// +// table.Add(relativeLocation, sensor); +// } +// } +// return table; +// } ##Bka + + /// + /// Builds the relative location table. + /// + /// + internal IDictionary BuildRelativeLocationTable() + { + var surfaceLevelOutside = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); + if (surfaceLevelOutside == null) + throw new InvalidOperationException("No SurfaceLevelOutside point on surface line defined"); + + double startPoint = surfaceLevelOutside.X; + + var dict = new Dictionary(); + foreach (Sensor sensor in Sensors) + { + double relativeLocation = startPoint + (Location.XRdDikeLine - sensor.XRd); + dict.Add(sensor, relativeLocation); + } + return dict; + } + + internal static class MemberNames + { + internal static readonly string OffsetBelowDikeToeAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeToeAtPolder); + internal static readonly string OffsetBelowDikeTopAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtPolder); + internal static readonly string OffsetBelowDikeTopAtRiver = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtRiver); + internal static readonly string OffsetBelowShoulderBaseInside = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowShoulderBaseInside); + internal static readonly string WaterLevelAtRiver = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtRiver); + internal static readonly string PolderLevel = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtPolder); + internal static readonly string PL3 = StaticReflection.GetMemberName(x => x.PL3); + internal static readonly string PL4 = StaticReflection.GetMemberName(x => x.PL4); + } + + public double? GetValue(Expression> expression, IDictionary sensorValues, Sensor sensor) + { + if (sensorValues == null) throw new ArgumentNullException("sensorValues"); + if (sensor == null) throw new ArgumentNullException("sensor"); + + if (!sensorValues.ContainsKey(sensor)) + throw new ArgumentException("The given sensor is not an item/key in the table of sensor values"); + + var memberName = StaticReflection.GetMemberName(expression); + + if (memberName == MemberNames.OffsetBelowDikeToeAtPolder) + { + if (PL1PLLineOffsetBelowDikeToeAtPolder == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeToeAtPolder; + } + + if (memberName == MemberNames.OffsetBelowDikeTopAtPolder) + { + if (PL1PLLineOffsetBelowDikeTopAtPolder == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeTopAtPolder; + } + + if (memberName == MemberNames.OffsetBelowDikeTopAtRiver) + { + if (PL1PLLineOffsetBelowDikeTopAtRiver == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowDikeTopAtRiver; + } + + if (memberName == MemberNames.OffsetBelowShoulderBaseInside) + { + if (PL1PLLineOffsetBelowShoulderBaseInside == DataSourceTypeSensors.LocationData) + return Location.PlLineOffsetBelowShoulderBaseInside; + } + + if (memberName == MemberNames.WaterLevelAtRiver) + { + if (PL1WaterLevelAtRiver == DataSourceTypeSensors.LocationData) + return Location.RiverLevel; + + if (PL1WaterLevelAtRiver == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PolderLevel) + { + if (PL1WaterLevelAtPolder == DataSourceTypeSensors.LocationData) + return Location.PolderLevel; + + if (PL1WaterLevelAtPolder == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PL3) + { + if (PL3 == DataSourceTypeSensors.LocationData) + return Location.HeadPl3; + + if (PL3 == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + if (memberName == MemberNames.PL4) + { + if (PL4 == DataSourceTypeSensors.LocationData) + return Location.HeadPl4; + + if (PL4 == DataSourceTypeSensors.Sensor) + return sensorValues[sensor]; + } + + + return null; + } + + /// + /// Determines whether this instance is valid. + /// + /// + /// true if this instance is valid; otherwise, false. + /// +// public bool IsValid() +// { +// return !Validator.Validate(this).Any(); +// } + + /// + /// Gets or sets the GetGroups function (injectable list, for UI purposes). + /// + /// + /// The list of available Groups. + /// + [XmlIgnore] + public static Func> GetGroups { get; set; } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DikeJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DikeJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DikeJob.cs (revision 334) @@ -0,0 +1,62 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; + +namespace Deltares.DamEngine.Data.General +{ + public class DikeJob : CompositeJob + { + public DikeJob() + { + } + + public DikeJob(object subject) : base(subject) + { + } + + [XmlIgnore] + public Dike Dike + { + get + { + return this.Subject as Dike; + } + set + { + this.Subject = value; + } + } + + public bool AreAllLocationWaterLevelTimeSeriesAssigned() + { + bool areAssigned = true; + foreach (DamJob damJob in Jobs) + { + if (damJob.GetType() == typeof(LocationJob)) + { + areAssigned = areAssigned && (((LocationJob)damJob).WaterLevelTimeSerie != null); + } + } + return areAssigned; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/PolyLine.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/PolyLine.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/PolyLine.cs (revision 334) @@ -0,0 +1,288 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.General +{ + public class PolyLineException : Exception + { + public PolyLineException(string message) + : base(message) + { + } + } + + public class PolyLine where T : GeometryPoint, new() + { + protected IList points; + + public PolyLine() + { + this.points = new List(); + } + + public virtual int Id { get; private set; } + + public virtual string Name { get; set; } + + public virtual IList Points { get { return this.points; } private set { this.points = value; } } + + /// + /// Check if lines are equal + /// + /// + /// + public virtual bool Equals(PolyLine other) + { + bool isEqual = (other.Points.Count == this.Points.Count); + if (isEqual) + { + for (int pointIndex = 0; pointIndex < this.Points.Count; pointIndex++) + { + isEqual = isEqual && (this.Points[pointIndex].LocationEquals(other.Points[pointIndex])); + } + } + return isEqual; + } + + /// + /// Check if line has a minimum of two points + /// + /// + public bool Exists() + { + return (this.Points.Count > 1); + } + + /// + /// Check if all the points are in strict ascending X order + /// + /// + public bool IsXStrictAscending() + { + bool isStrictAscending = true; + for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++) + { + if (this.Points[pointIndex + 1].X <= this.Points[pointIndex].X) + { + isStrictAscending = false; + break; + } + } + return isStrictAscending; + } + + /// + /// Check if all the points are in ascending X order + /// + /// + public bool IsXAscending() + { + bool isAscending = true; + for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++) + { + if (this.Points[pointIndex + 1].X < this.Points[pointIndex].X) + { + isAscending = false; + break; + } + } + return isAscending; + } + + /// + /// Gets point at X if present within tolerance or null if not present. + /// + /// + public T GetPointAtX(double X, double tolerance) + { + return (from T point in this.points + where Math.Abs(point.X - X) < tolerance + select point).FirstOrDefault(); + } + + private T InsertPointAtX(double X) + { + T newPoint = new T(); + newPoint.X = X; + try + { + T pointAfter = (from T point in this.points + where point.X > X + select point).First(); + + this.points.Insert(this.points.IndexOf(pointAfter), newPoint); + } + catch + { + this.points.Add(newPoint); + } + return newPoint; + } + + /// + /// Gets point at X if present within tolerance; creates one there if not present. + /// + /// + public T EnsurePointAtX(double X, double tolerance) + { + T point = GetPointAtX(X, tolerance); + if (point == null) + { + point = InsertPointAtX(X); + } + return point; + } + + public double ZFromX(double X) + { + if (!this.IsXAscending()) + { + throw new PolyLineException("Interpolation only possible with ascending polyline"); + } + + double valueZ = 0.0; + + // Less then first X + if (X <= this.Points[0].X) + { + valueZ = this.Points[0].Z; + } + // More then last X + else if (X >= this.Points[this.Points.Count - 1].X) + { + valueZ = this.Points[this.Points.Count - 1].Z; + } + else + { + // X is inside boundaries + for (int pointIndex = 0; pointIndex < this.Points.Count - 1; pointIndex++) + { + if ((X > this.Points[pointIndex].X) && (X <= this.Points[pointIndex + 1].X)) + { + // interpolate in this section + double fractionX = (X - this.Points[pointIndex].X) / (this.Points[pointIndex + 1].X - this.Points[pointIndex].X); + valueZ = this.Points[pointIndex].Z + fractionX * (this.Points[pointIndex + 1].Z - this.Points[pointIndex].Z); + break; + } + } + } + return valueZ; + } + + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.Append(this.Name); + stringBuilder.Append(" ["); + foreach (T point in this.points) + { + if (this.points.IndexOf(point) > 0) + stringBuilder.Append(", "); + stringBuilder.Append(point.ToString()); + } + stringBuilder.Append("]"); + + return stringBuilder.ToString(); + } + + public virtual void CopyPoints(PolyLine polyLine) + { + foreach (T point in polyLine.Points) + { + points.Add(point); + } + } + + /// + /// Deletes the coinsiding points. + /// + /// The tolerance. + public virtual void DeleteCoinsidingPoints(double tolerance) + { + // First build a list of indices of points that have to be removed (from end of list to start) + var indicesToDelete = new List(); + for (int pointIndex = Points.Count - 1; pointIndex > 0; pointIndex--) + { + for (int i = pointIndex - 1; i >= 0; i--) + { + if (Points[pointIndex].LocationEquals(Points[i], tolerance)) + { + indicesToDelete.Add(i); + } + } + } + + // Remove duplicate points beginning from the end + for (int index = 0; index < indicesToDelete.Count; index++) + { + Points.RemoveAt(indicesToDelete[index]); + } + + } + + public virtual void DeleteCoinsidingPoints() + { + const double defaultTolerance = 0.001; + DeleteCoinsidingPoints(defaultTolerance); + } + + public virtual double MinZ() + { + if (this.Points.Count > 1) + { + double minZ = this.points.First().Z; + foreach (T point in this.points) + { + minZ = Math.Min(minZ, point.Z); + } + return minZ; + } + else + { + return 0.0; + } + } + + public virtual double MaxZ() + { + if (this.Points.Count > 1) + { + double maxZ = this.points.First().Z; + foreach (T point in this.points) + { + maxZ = Math.Max(maxZ, point.Z); + } + return maxZ; + } + else + { + return 0.0; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Location.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Location.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Location.cs (revision 334) @@ -0,0 +1,3000 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General.Gauges; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.General.Sensors; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Probabilistic; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + internal static class LocationParameterNames + { + public const string DamType = "DamType"; + public const string DikeRingId = "DikeRingId"; + public const string Description = "Description"; + public const string XRd = "XRd"; + public const string YRd = "YRd"; + public const string SegmentId = "SegmentId"; + public const string SurfaceLineId = "SurfaceLineId"; + public const string PL1LineId = "PL1LineId"; + public const string DredgingDepth = "DredgingDepth"; + public const string PolderLevel = "PolderLevel"; + public const string PolderLevelLow = "PolderLevelLow"; + public const string HeadPL2 = "HeadPL2"; + public const string HeadPL3 = "HeadPL3"; + public const string HeadPL4 = "HeadPL4"; + public const string GrassQuality = "GrassQuality"; + public const string Direction = "Direction"; + public const string XSoilGeometry2DOrigin = "XSoilGeometry2DOrigin"; + public const string DikeMaterialType = "DikeMaterialType"; + public const string DikeEmbankmentMaterial = "DikeEmbankmentMaterial"; + public const string ShoulderEmbankmentMaterial = "ShoulderEmbankmentMaterial"; + public const string DampingFactorPL3 = "DampingFactorPL3"; + public const string DampingFactorPL4 = "DampingFactorPL4"; + public const string SheetPilePointX = "SheetPilePointX"; + public const string SheetPilePointY = "SheetPilePointY"; + public const string SheetPilePointZ = "SheetPilePointZ"; + public const string SheetPileLength = "SheetPileLength"; + public const string RwBankProtectionBottomLevel = "RwBankProtectionBottomLevel"; + public const string IsUseOriginalPLLineAssignments = "IsUseOriginalPLLineAssignments"; + public const string PenetrationLength = "PenetrationLength"; + public const string TrafficLoad = "TrafficLoad"; + public const string PLLineCreationMethod = "PLLineCreationMethod"; + public const string PLLineOffsetBelowDikeTopAtRiver = "PLLineOffsetBelowDikeTopAtRiver"; + public const string PLLineOffsetBelowDikeTopAtPolder = "PLLineOffsetBelowDikeTopAtPolder"; + public const string PLLineOffsetBelowShoulderBaseInside = "PLLineOffsetBelowShoulderBaseInside"; + public const string PLLineOffsetBelowDikeToeAtPolder = "PLLineOffsetBelowDikeToeAtPolder"; + public const string PLLineOffsetDryBelowDikeTopAtRiver = "PLLineOffsetDryBelowDikeTopAtRiver"; + public const string PLLineOffsetDryBelowDikeTopAtPolder = "PLLineOffsetDryBelowDikeTopAtPolder"; + public const string PLLineOffsetDryBelowShoulderBaseInside = "PLLineOffsetDryBelowShoulderBaseInside"; + public const string PLLineOffsetDryBelowDikeToeAtPolder = "PLLineOffsetDryBelowDikeToeAtPolder"; + public const string PlLineOffsetBelowDikeCrestMiddle = "PlLineOffsetBelowDikeCrestMiddle"; + public const string PlLineOffsetFactorBelowShoulderCrest = "PlLineOffsetFactorBelowShoulderCrest"; + public const string PlLineOffsetDryBelowDikeCrestMiddle = "PlLineOffsetDryBelowDikeCrestMiddle"; + public const string PlLineOffsetDryFactorBelowShoulderCrest = "PlLineOffsetDryFactorBelowShoulderCrest"; + public const string UsePlLineOffsetBelowDikeCrestMiddle = "UsePlLineOffsetBelowDikeCrestMiddle"; + public const string UsePlLineOffsetFactorBelowShoulderCrest = "UsePlLineOffsetFactorBelowShoulderCrest"; + public const string UsePlLineOffsetDryBelowDikeCrestMiddle = "UsePlLineOffsetDryBelowDikeCrestMiddle"; + public const string UsePlLineOffsetDryFactorBelowShoulderCrest = "UsePlLineOffsetDryFactorBelowShoulderCrest"; + public const string StabilityShoulderGrowSlope = "StabilityShoulderGrowSlope"; + public const string StabilityShoulderGrowDeltaX = "StabilityShoulderGrowDeltaX"; + public const string StabilitySlopeAdaptionDeltaX = "StabilitySlopeAdaptionDeltaX"; + public const string BoezemLevelTp = "BoezemLevelTp"; + public const string BoezemlevelHbp = "BoezemLevelHbp"; + public const string BoezemLevelLbp = "BoezemLevelLbp"; + public const string MinimalCircleDepth = "MinimalCircleDepth"; + public const string LevelReductionInside = "LevelReductionInside"; + public const string LevelReductionOutside = "LevelReductionOutside"; + public const string LayerHeightDistribution = "LayerHeightDistribution"; + public const string LayerHeightDeviation = "LayerHeightDeviation"; + public const string DistanceToEntryPoint = "DistanceToEntryPoint"; + public const string RequiredSafetyFactorStabilityInnerSlope = "RequiredSafetyFactorStabilityInnerSlope"; + public const string RequiredSafetyFactorStabilityOuterSlope = "RequiredSafetyFactorStabilityOuterSlope"; + public const string RequiredSafetyFactorPiping = "RequiredSafetyFactorPiping"; + public const string RequiredProbabilityOfFailureStabilityInnerslope = "RequiredProbabilityOfFailureStabilityInnerslope"; + public const string RequiredProbabilityOfFailureStabilityOuterslope = "RequiredProbabilityOfFailureStabilityOuterslope"; + public const string RequiredProbabilityOfFailurePiping = "RequiredProbabilityOfFailurePiping"; + public const string UpliftCriterionPiping = "UpliftCriterionPiping"; + public const string UpliftCriterionStability = "UpliftCriterionStability"; + public const string DetrimentFactor = "DetrimentFactor"; + public const string StabilityZoneType = "StabilityZoneType"; + public const string ForbiddenZoneFactor = "ForbiddenZoneFactor"; + public const string ZoneAreaRestSlopeCrestWidth = "ZoneAreaRestSlopeCrestWidth"; + public const string DikeTableHeight = "DikeTableHeight"; + public const string StabilityDesignMethod = "StabilityDesignMethod"; + public const string SlopeAdaptionStartCotangent = "SlopeAdaptionStartCotangent"; + public const string SlopeAdaptionEndCotangent = "SlopeAdaptionEndCotangent"; + public const string SlopeAdaptionStepCotangent = "SlopeAdaptionStepCotangent"; + public const string SlopeDampingPiezometricHeightPolderSide = "SlopeDampingPiezometricHeightPolderSide"; + public const string NewDepthDitch = "NewDepthDitch"; + public const string NewDikeSlopeInside = "NewDikeSlopeInside"; + public const string NewDikeSlopeOutside = "NewDikeSlopeOutside"; + public const string NewDikeTopWidth = "NewDikeTopWidth"; + public const string NewMaxHeightShoulderAsFraction = "NewMaxHeightShoulderAsFraction"; + public const string NewMinDistanceDikeToeStartDitch = "NewMinDistanceDikeToeStartDitch"; + public const string NewShoulderBaseSlope = "NewShoulderBaseSlope"; + public const string NewShoulderTopSlope = "NewShoulderTopSlope"; + public const string NewSlopeAngleDitch = "NewSlopeAngleDitch"; + public const string NewWidthDitchBottom = "NewWidthDitchBottom"; + public const string UseNewDikeSlopeInside = "UseNewDikeSlopeInside"; + public const string UseNewDikeSlopeOutside = "UseNewDikeSlopeOutside"; + public const string UseNewDikeTopWidth = "UseNewDikeTopWidth"; + public const string UseNewDitchDefinition = "UseNewDitchDefinition"; + public const string UseNewMaxHeightShoulderAsFraction = "UseNewMaxHeightShoulderAsFraction"; + public const string UseNewMinDistanceDikeToeStartDitch = "UseNewMinDistanceDikeToeStartDitch"; + public const string UseNewShoulderBaseSlope = "UseNewShoulderBaseSlope"; + public const string UseNewShoulderTopSlope = "UseNewShoulderTopSlope"; + public const string IntrusionVerticalWaterPressure = "IntrusionVerticalWaterPressure"; + } + + public class Location + { + // Added initial value as these properties must be tested for real values on import + public const string AllCategory = "MainItems"; + public const string DikeCategory = "Dike"; + public const string WaterCategory = "Water levels"; + public const string DesignCategory = "Design"; + private const double BoezemLevelNotSetValue = -987654321.0; + private const double newDikeTopWidthMinValue = 0.1; + private const double newDikeSlopeInsideMinValue = 0.01; + private const double newDikeSlopeOutsideMinValue = 0.01; + private const double penetrationLenghtMinValue = 0.00; + private static DamProjectType damProjectType = DamProjectType.Calamity; + private readonly List scenarios = new List(); + private bool areLocalXZObjectsCreated = false; + private double boezemLevelHbp = BoezemLevelNotSetValue; + private double boezemLevelLbp = BoezemLevelNotSetValue; + private double boezemLevelTp = BoezemLevelNotSetValue; + + // ATTENTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // + // When adding properties below do not forget to add these properties to SetParameterFromNameValuePair and GetParametersAsNameValuePairs + // + // ATTENTION !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + private DamType damType = DamType.Primary; + private double dampingFactorPL3 = 0; + private double dampingFactorPL4 = 0; + private string description = ""; + private double detrimentFactor = 0.95; + private string dikeEmbankmentMaterial = ""; + private SoilType dikeMaterialType = SoilType.Clay; + private string dikeRingId = ""; + private double dikeTableHeight = 0.0; + private double direction = 0; + private double distanceToEntryPoint = 0; + private double dredgingDepth = 0; + private double forbiddenZoneFactor = 1.0; + private IList gaugePLLines = new List(); + private IList gauges = new List(); + private double grassQuality = 0; + private double? headPL2 = null; + private double? headPL3 = null; + private double? headPL4 = null; + private bool isUseOriginalPLLineAssignments = false; + private double layerHeightDeviation = 0; + private DistributionType layerHeightDistribution = 0; + // Start of parameters that are also defined in modelparameters + private double levelReductionInside = 0; + private double levelReductionOutside = 0; + private PL1Line localXZPL1Line; + private GeometryPoint localXZSheetPilePoint; + private SurfaceLine2 localXzSurfaceLine; + private string mapForSoilGeometries2D = ""; + private double minimalCircleDepth = 0; + private ModelFactors modelFactors = new ModelFactors(); + private string name = ""; + private double newDepthDitch = 1.0; + private double newDikeSlopeInside = 1.0/3.0; // as tangent + private double newDikeSlopeOutside = 1.0/3.0; // as tangent + private double newDikeTopWidth = 5.0; + private double newMaxHeightShoulderAsFraction = 2.0/3.0; // as tangent + private double newMinDistanceDikeToeStartDitch = 5.0; + private double newShoulderBaseSlope = 1.0/3.0; // as tangent + private double newShoulderTopSlope = 1.0/20.0; // as tangent + private double newSlopeAngleDitch = 1.0/0.5; // as tangent + private double newWidthDitchBottom = 1.0; + private PL1Line pL1Line; + private PLLineCreationMethod pLLineCreationMethod = PLLineCreationMethod.ExpertKnowledgeRRD; + private double pLLineOffsetBelowDikeToeAtPolder = 0.1; + private double pLLineOffsetBelowDikeTopAtPolder = 1.5; + private double pLLineOffsetBelowDikeTopAtRiver = 0.5; + private double pLLineOffsetBelowShoulderBaseInside = 0.1; + private double pLLineOffsetDryBelowDikeToeAtPolder = 0.1; + private double pLLineOffsetDryBelowDikeTopAtPolder = 1.5; + private double pLLineOffsetDryBelowDikeTopAtRiver = 0.5; + private double pLLineOffsetDryBelowShoulderBaseInside = 0.1; + private double penetrationLength = 0; + private double polderLevel = 0; + private double polderLevelLow = 0; + private bool redesignDikeHeight = true; + private bool redesignDikeShoulder = true; + private double rwBankProtectionBottomLevel = 0; + private double scenarioRiverLevel = 0; + private Segment segment; + private SensorLocation sensorData; + private double sheetPileLength = 0; + private GeometryPoint sheetPilePoint = new GeometryPoint(); + private string shoulderEmbankmentMaterial = ""; + private double slopeAdaptionEndCotangent = 6.0; + private double slopeAdaptionStartCotangent = 3.0; + private double slopeAdaptionStepCotangent = 0.5; + private double slopeDampingPiezometricHeightPolderSide = 0.0; + private SoilSurfaceProfile soilSurfaceProfile = null; + private string soildatabaseName = ""; + private StabilityDesignMethod stabilityDesignMethod = StabilityDesignMethod.OptimizedSlopeAndShoulderAdaption; + private double stabilityShoulderGrowDeltaX = 2.0; + private double stabilityShoulderGrowSlope = 1.0/3; + private double stabilitySlopeAdaptionDeltaX = 2.0; + private MStabZonesType stabilityZoneType = MStabZonesType.NoZones; + + private SurfaceLine2 surfaceLine2; + private string surfaceLineId = ""; + private double trafficLoad = 0; + private bool useNewDikeSlopeInside; + private bool useNewDikeSlopeOutside; + private bool useNewDikeTopWidth; + private bool useNewDitchDefinition; + private bool useNewMaxHeightShoulderAsFraction; + private bool useNewMinDistanceDikeToeStartDitch; + private bool useNewShoulderBaseSlope; + private bool useNewShoulderTopSlope; + private double xRdDikeLine; + private double xSoilGeometry2DOrigin = 0; + private double xrd = 0; + private double yrd = 0; + private double zoneAreaRestSlopeCrestWidth = 3.0; + + private double? plLineOffsetFactorBelowShoulderCrest; + private double? plLineOffsetBelowDikeCrestMiddle; + private double? plLineOffsetDryFactorBelowShoulderCrest; + private double? plLineOffsetDryBelowDikeCrestMiddle; + + private IntrusionVerticalWaterPressureType? intrusionVerticalWaterPressure = IntrusionVerticalWaterPressureType.Standard; + + + public Location() + { + SoilList = null; + } + + /// + /// Initializes a new instance of the class. + /// + /// The name. + public Location(string name) : this() + { + this.name = name; + } + + public bool HasSensorData + { + get + { + return sensorData != null; + } + } + + public virtual SensorLocation SensorData + { + get + { + return sensorData; + } + set + { + sensorData = value; + sensorData.Location = this; + } + } + + public virtual bool AreLocalXZObjectsCreated + { + get + { + return areLocalXZObjectsCreated; + } + set + { + areLocalXZObjectsCreated = value; + } + } + + public virtual string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + public virtual string Description + { + get + { + return description; + } + set + { + description = value; + } + } + + public virtual double XRd + { + get + { + return xrd; + } + set + { + xrd = value; + } + } + + public virtual double YRd + { + get + { + return yrd; + } + set + { + yrd = value; + } + } + + public virtual double XRdDikeLine + { + get + { + return xRdDikeLine; + } + set + { + xRdDikeLine = value; + } + } + + public virtual double GrassQuality + { + get + { + return grassQuality; + } + set + { + grassQuality = value; + } + } + + public virtual double Direction + { + get + { + return direction; + } + set + { + direction = value; + } + } + + public virtual double XSoilGeometry2DOrigin + { + get + { + return xSoilGeometry2DOrigin; + } + set + { + xSoilGeometry2DOrigin = value; + } + } + + public virtual double TrafficLoad + { + get + { + return trafficLoad; + } + set + { + trafficLoad = value; + } + } + + public virtual double DredgingDepth + { + get + { + return dredgingDepth; + } + set + { + dredgingDepth = value; + } + } + + public virtual SoilType DikeMaterialType + { + get + { + return dikeMaterialType; + } + set + { + dikeMaterialType = value; + } + } + + public virtual GeometryPoint SheetPilePoint + { + get + { + return sheetPilePoint; + } + set + { + sheetPilePoint = value; + } + } + + public virtual double SheetPilePointX + { + get + { + return SheetPilePoint.X; + } + set + { + SheetPilePoint.X = value; + } + } + + public virtual double SheetPilePointY + { + get + { + return SheetPilePoint.Y; + } + set + { + SheetPilePoint.Y = value; + } + } + + [Browsable(false)]public virtual double SheetPilePointZ + { + get + { + return SheetPilePoint.Z; + } + set + { + SheetPilePoint.Z = value; + } + } + + public virtual double SheetPileLength + { + get + { + return sheetPileLength; + } + set + { + sheetPileLength = value; + } + } + + public virtual double RwBankProtectionBottomLevel + { + get + { + return rwBankProtectionBottomLevel; + } + set + { + rwBankProtectionBottomLevel = value; + } + } + + public virtual bool IsUseOriginalPLLineAssignments + { + get + { + return isUseOriginalPLLineAssignments; + } + set + { + isUseOriginalPLLineAssignments = value; + } + } + + public virtual PL1Line PL1Line + { + get + { + return pL1Line; + } + set + { + pL1Line = value; + } + } + + public virtual PL1Line LocalXZPL1Line + { + get + { + return localXZPL1Line; + } + set + { + localXZPL1Line = value; + } + } + + /// + /// TODO + /// + /// Composite relationship. + [Validate] + public virtual SurfaceLine2 LocalXZSurfaceLine2 + { + get + { + return localXzSurfaceLine; + } + set + { + localXzSurfaceLine = value; + } + } + + public virtual GeometryPoint LocalXZSheetPilePoint + { + get + { + return localXZSheetPilePoint; + } + set + { + localXZSheetPilePoint = value; + } + } + + /// + /// Gets or sets the Segment + /// + public virtual string SegmentId { get; set; } + + /// + /// Gets or sets the Segment + /// + public virtual Segment Segment + { + get + { + return segment; + } + set + { + segment = value; + } + } + + /// + /// Gets or sets the surface line + /// + public virtual SurfaceLine2 SurfaceLine2 + { + get + { + return surfaceLine2; + } + set + { + surfaceLine2 = value; + } + } + + /// + /// + /// + public virtual double MinimalCircleDepth + { + get + { + return minimalCircleDepth; + } + set + { + minimalCircleDepth = value; + } + } + + public virtual double LevelReductionInside + { + get + { + return levelReductionInside; + } + set + { + levelReductionInside = value; + } + } + + public virtual double LevelReductionOutside + { + get + { + return levelReductionOutside; + } + set + { + levelReductionOutside = value; + } + } + + public virtual ModelFactors ModelFactors + { + get + { + return modelFactors; + } + set + { + modelFactors = value; + } + } + + [XmlIgnore] + public virtual double? UpliftCriterionStability + { + get + { + return ModelFactors.UpliftCriterionStability; + } + set + { + ModelFactors.UpliftCriterionStability = value; + } + } + + [XmlIgnore] + public virtual double? UpliftCriterionPiping + { + get + { + return ModelFactors.UpliftCriterionPiping; + } + set + { + ModelFactors.UpliftCriterionPiping = value; + } + } + + public virtual DistributionType LayerHeightDistribution + { + get + { + return layerHeightDistribution; + } + set + { + layerHeightDistribution = value; + } + } + + public virtual double LayerHeightDeviation + { + get + { + return layerHeightDeviation; + } + set + { + layerHeightDeviation = value; + } + } + + public virtual double DistanceToEntryPoint + { + get + { + return distanceToEntryPoint; + } + set + { + distanceToEntryPoint = value; + } + } + + public virtual double DetrimentFactor + { + get + { + return detrimentFactor; + } + set + { + detrimentFactor = value; + } + } + + public virtual double SlopeDampingPiezometricHeightPolderSide + { + get + { + return slopeDampingPiezometricHeightPolderSide; + } + set + { + slopeDampingPiezometricHeightPolderSide = value; + } + } + + public virtual double DikeTableHeight + { + get + { + return dikeTableHeight; + } + set + { + dikeTableHeight = value; + } + } + + public DamType DamType + { + get + { + return damType; + } + set + { + damType = value; + } + } + + public string DikeRingId + { + get + { + return dikeRingId; + } + set + { + dikeRingId = value; + } + } + + public string SurfaceLineId + { + get + { + return surfaceLineId; + } + set + { + surfaceLineId = value; + } + } + + public string SoildatabaseName + { + get + { + return soildatabaseName; + } + set + { + soildatabaseName = value; + } + } + + public SoilList SoilList { get; set; } + + + public string MapForSoilGeometries2D + { + get + { + return mapForSoilGeometries2D; + } + set + { + mapForSoilGeometries2D = value; + } + } + + public virtual IList Gauges + { + get + { + return gauges; + } + set + { + gauges = value; + } + } + + public virtual IList GaugePLLines + { + get + { + return gaugePLLines; + } + set + { + gaugePLLines = value; + } + } + + public bool UsesGauges + { + get + { + return GaugePLLines != null && GaugePLLines.Count > 0 && Gauges != null; + } + } + + public double GaugeMissVal { get; set; } + + public bool RedesignDikeHeight + { + get + { + return redesignDikeHeight; + } + set + { + redesignDikeHeight = value; + } + } + + public bool RedesignDikeShoulder + { + get + { + return redesignDikeShoulder; + } + set + { + redesignDikeShoulder = value; + } + } + + public StabilityDesignMethod StabilityDesignMethod + { + get + { + return stabilityDesignMethod; + } + set + { + stabilityDesignMethod = value; + } + } + + public double SlopeAdaptionStartCotangent + { + get + { + return slopeAdaptionStartCotangent; + } + set + { + slopeAdaptionStartCotangent = value; + } + } + + public double SlopeAdaptionEndCotangent + { + get + { + return slopeAdaptionEndCotangent; + } + set + { + slopeAdaptionEndCotangent = value; + } + } + + public double SlopeAdaptionStepCotangent + { + get + { + return slopeAdaptionStepCotangent; + } + set + { + slopeAdaptionStepCotangent = value; + } + } + + public bool UseNewDikeTopWidth + { + get + { + return useNewDikeTopWidth; + } + set + { + useNewDikeTopWidth = value; + } + } + + public double NewDikeTopWidth + { + get + { + return newDikeTopWidth; + } + set + { + newDikeTopWidth = value; + } + } + + public bool UseNewDikeSlopeInside + { + get + { + return useNewDikeSlopeInside; + } + set + { + useNewDikeSlopeInside = value; + } + } + + public double NewDikeSlopeInside + { + get + { + return newDikeSlopeInside; + } + set + { + newDikeSlopeInside = value; + } + } + + public bool UseNewDikeSlopeOutside + { + get + { + return useNewDikeSlopeOutside; + } + set + { + useNewDikeSlopeOutside = value; + } + } + + public double NewDikeSlopeOutside + { + get + { + return newDikeSlopeOutside; + } + set + { + newDikeSlopeOutside = value; + } + } + + public bool UseNewShoulderTopSlope + { + get + { + return useNewShoulderTopSlope; + } + set + { + useNewShoulderTopSlope = value; + } + } + + public double NewShoulderTopSlope + { + get + { + return newShoulderTopSlope; + } + set + { + newShoulderTopSlope = value; + } + } + + public bool UseNewShoulderBaseSlope + { + get + { + return useNewShoulderBaseSlope; + } + set + { + useNewShoulderBaseSlope = value; + } + } + + public double NewShoulderBaseSlope + { + get + { + return newShoulderBaseSlope; + } + set + { + newShoulderBaseSlope = value; + } + } + + public bool UseNewMaxHeightShoulderAsFraction + { + get + { + return useNewMaxHeightShoulderAsFraction; + } + set + { + useNewMaxHeightShoulderAsFraction = value; + } + } + + public double NewMaxHeightShoulderAsFraction + { + get + { + return newMaxHeightShoulderAsFraction; + } + set + { + newMaxHeightShoulderAsFraction = value; + } + } + + public bool UseNewMinDistanceDikeToeStartDitch + { + get + { + return useNewMinDistanceDikeToeStartDitch; + } + set + { + useNewMinDistanceDikeToeStartDitch = value; + } + } + + public double NewMinDistanceDikeToeStartDitch + { + get + { + return newMinDistanceDikeToeStartDitch; + } + set + { + newMinDistanceDikeToeStartDitch = value; + } + } + + public bool UseNewDitchDefinition + { + get + { + return useNewDitchDefinition; + } + set + { + useNewDitchDefinition = value; + } + } + + public double NewWidthDitchBottom + { + get + { + return newWidthDitchBottom; + } + set + { + newWidthDitchBottom = value; + } + } + + public double NewSlopeAngleDitch + { + get + { + return newSlopeAngleDitch; + } + set + { + newSlopeAngleDitch = value; + + } + } + + public double NewDepthDitch + { + get + { + return newDepthDitch; + } + set + { + newDepthDitch = value; + } + } + + [Validate] + public List Scenarios + { + get + { + return scenarios; + } + } + + [XmlIgnore] + public static DamProjectType DamProjectType + { + get + { + return damProjectType; + } + set + { + damProjectType = value; + } + } + + #region IGeographic Members + + public MStabZonesType StabilityZoneType + { + get + { + return stabilityZoneType; + } + set + { + stabilityZoneType = value; + } + } + + public double ForbiddenZoneFactor + { + get + { + return forbiddenZoneFactor; + } + set + { + forbiddenZoneFactor = value; + } + } + + public double ZoneAreaRestSlopeCrestWidth + { + get + { + return zoneAreaRestSlopeCrestWidth; + } + set + { + zoneAreaRestSlopeCrestWidth = value; + } + } + + [XmlIgnore] + public double X + { + get + { + return XRd; + } + set + { + XRd = value; + } + } + + [XmlIgnore] + public double Y + { + get + { + return YRd; + } + set + { + YRd = value; + } + } + + /// + /// Ensure proper Safety Factors for zone type areas by always using the detriment factor. + /// + public void EnsureProperZoneSafetyFactors() + { + if (modelFactors != null) + { + // For regional assessment, automatically fill with the detriment factor instead of error message and repairer (MWDAM-748) + if (DamType == DamType.Regional && DamProjectType == DamProjectType.Assessment) + { + modelFactors.RequiredSafetyFactorStabilityInnerSlope = detrimentFactor; + } + } + } + + /// + /// Checks whether the required safety (stability inner slope) is given as that is needed to work with zone areas. + /// + /// + [Validate] + public ValidationResult[] IsRequiredSafetySetForZoneTypeArea() + { + if (stabilityZoneType == MStabZonesType.ZoneAreas) + { + // For design projects, the safetey must be defined per scenario, not per location + if (DamProjectType == DamProjectType.Design && scenarios != null && scenarios.Count > 0) + { + foreach (var scenario in scenarios) + { + if (scenario.ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope == null) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText( + this, "NoRequiredSafetyForZonesScenario"), scenario) + }; + } + } + } + else + { + if (modelFactors.RequiredSafetyFactorStabilityInnerSlope == null) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText( + this, "NoRequiredSafetyForZones"), this) + }; + } + } + } + return new ValidationResult[0]; + } + + [Validate] + public ValidationResult[] ValidateDikeEmbankmentMaterial() + { + if (DamProjectType == DamProjectType.Design && !HasValidDikeEmbankmentMaterial()) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText( + this, "NoDikeEmbankmentMaterial"), this) + }; + } + else + { + return new ValidationResult[0]; + } + } + + [Validate] + public ValidationResult[] ValidateLocationNewDikeTopWidth() + { + if (DamProjectType == DamProjectType.Design) + { + if ((UseNewDikeTopWidth) && (NewDikeTopWidth < newDikeTopWidthMinValue)) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, String.Format( + LocalizationManager.GetTranslatedText(this, "NewDikeTopWidthRangeError"), + newDikeTopWidthMinValue), this) + }; + } + } + return new ValidationResult[0]; + } + + [Validate] + public ValidationResult[] ValidateLocationNewDikeSlopeInside() + { + if (DamProjectType == DamProjectType.Design) + { + if ((UseNewDikeSlopeInside) && (NewDikeSlopeInside < newDikeSlopeInsideMinValue)) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, String.Format( + LocalizationManager.GetTranslatedText(this, "NewDikeSlopeInsideRangeError"), + newDikeSlopeInsideMinValue), this) + }; + } + } + return new ValidationResult[0]; + } + + + [Validate] + public ValidationResult[] ValidateLocationNewDikeSlopeOutside() + { + if (DamProjectType == DamProjectType.Design) + { + if ((UseNewDikeSlopeOutside) && (NewDikeSlopeOutside < newDikeSlopeOutsideMinValue)) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, String.Format(LocalizationManager. + GetTranslatedText(this, "NewDikeSlopeOutsideRangeError"), + newDikeSlopeOutsideMinValue), this) + }; + } + } + return new ValidationResult[0]; + } + + /// + /// Validates the use of the penetration length. + /// + /// Validation result + [Validate] + public ValidationResult[] ValidateLocationUseOfPenetrationLength() + { + if (PenetrationLength > 0) + { + // It may be used on 1D geometries + if (!String.IsNullOrEmpty(this.Segment.GetMostProbableGeometry2DName(FailureMechanismSystemType.StabilityInside))) + { + // It may be used on 2D geometries only if condition below is true + if (this.IntrusionVerticalWaterPressure != IntrusionVerticalWaterPressureType.SemiTimeDependent) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, String.Format( + LocalizationManager.GetTranslatedText(this, "UseOfPenetrationLengthError"), + penetrationLenghtMinValue), this) + }; + } + } + } + return new ValidationResult[0]; + } + + [Validate] + public ValidationResult[] ValidateShoulderEmbankmentMaterial() + { + if (DamProjectType == DamProjectType.Design && !HasValidShoulderEmbankmentMaterial()) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText( + this, "NewDikeTopWidth"), this) + }; + } + else + { + return new ValidationResult[0]; + } + } + + /// + /// Validates the location has segment. + /// + /// + [Validate] + public ValidationResult[] ValidateLocationHasSegment() + { + if (Segment == null) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "LocationHasNoSegment"), + this) + }; + } + else + { + return new ValidationResult[0]; + } + } + + /// + /// Validates the location has valid essential assessment values. + /// + /// + [Validate] + public ValidationResult[] ValidateLocationHasValidEssentialAssessmentValues() + { + if (DamProjectType == DamProjectType.Assessment) + { + if (Math.Abs(BoezemLevelTp - BoezemLevelNotSetValue) < Double.Epsilon) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "LocationInvalidBoezemLevelTp"), + this) + }; + } + if (Math.Abs(boezemLevelHbp - BoezemLevelNotSetValue) < Double.Epsilon) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "LocationInvalidBoezemLevelHbp"), + this) + }; + } + if (Math.Abs(boezemLevelLbp - BoezemLevelNotSetValue) < Double.Epsilon) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "LocationInvalidBoezemLevelLbp"), + this) + }; + } + } + return new ValidationResult[0]; + } + + [Validate] + public ValidationResult[] ValidateDikeEmbankmentMaterialDefinedIfSurfacelineAboveSoilProfile() + { + if (IsSurfaceLineAboveSoilProfile() && !HasValidDikeEmbankmentMaterial()) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "NoDikeEmbankmentMaterialAndNeeded"), + this) + }; + } + else + { + return new ValidationResult[0]; + } + } + + /// + /// Determines whether [is pl line offset factor below shoulder crest valid]. + /// + /// + [Validate] + public ValidationResult[] IsPlLineOffsetFactorBelowShoulderCrestValid() + { + if (!IsDesign() && ArePlLineCreationExpertKnowledgeParametersNeeded() && UsePlLineOffsetFactorBelowShoulderCrest.HasValue && UsePlLineOffsetFactorBelowShoulderCrest.Value && + PlLineOffsetFactorBelowShoulderCrest.HasValue) + { + if (PlLineOffsetFactorBelowShoulderCrest.Value < DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMinValue) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "PlLineOffsetFactorBelowShoulderCrestTooSmall"), + this) + }; + } + if (PlLineOffsetFactorBelowShoulderCrest.Value > DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMaxValue) + { + return new[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "PlLineOffsetFactorBelowShoulderCrestTooLarge"), + this) + }; + } + } + return new ValidationResult[0]; + } + /// + /// Check if DikeEmbankmentMaterial is defined and is available as soil + /// + /// + private bool HasValidDikeEmbankmentMaterial() + { + return !String.IsNullOrEmpty(DikeEmbankmentMaterial) && GetDikeEmbankmentSoil() != null; + } + + /// + /// Check if ShoulderEmbankmentMaterial is defined and is available as soil + /// + /// + private bool HasValidShoulderEmbankmentMaterial() + { + return !String.IsNullOrEmpty(ShoulderEmbankmentMaterial) && GetShoulderEmbankmentSoil() != null; + } + + /// + /// Determine if surfaceline is higher than any of the 1D soilprofiles + /// + /// + private bool IsSurfaceLineAboveSoilProfile() + { + bool isSurfaceLineAboveSoilProfile = false; + if (Segment != null) + { + foreach (var soilGeometryProbability in Segment.SoilProfileProbabilities) + { + SoilProfile1D soilProfile = soilGeometryProbability.SoilProfile; + if (soilProfile != null) + { + isSurfaceLineAboveSoilProfile = isSurfaceLineAboveSoilProfile || (LocalXZSurfaceLine2.Geometry.GetMaxZ() > soilGeometryProbability.SoilProfile.TopLevel); + } + } + } + return isSurfaceLineAboveSoilProfile; + } + + #endregion + + #region Design parameters + + public virtual string DikeEmbankmentMaterial + { + get + { + return dikeEmbankmentMaterial; + } + set + { + dikeEmbankmentMaterial = value; + } + } + + public virtual string ShoulderEmbankmentMaterial + { + get + { + return shoulderEmbankmentMaterial; + } + set + { + shoulderEmbankmentMaterial = value; + } + } + + public virtual double StabilityShoulderGrowSlope + { + get + { + return stabilityShoulderGrowSlope; + } + set + { + stabilityShoulderGrowSlope = value; + } + } + + public virtual double StabilityShoulderGrowDeltaX + { + get + { + return stabilityShoulderGrowDeltaX; + } + set + { + stabilityShoulderGrowDeltaX = value; + } + } + + public virtual double StabilitySlopeAdaptionDeltaX + { + get + { + return stabilitySlopeAdaptionDeltaX; + } + set + { + stabilitySlopeAdaptionDeltaX = value; + } + } + + #endregion + + #region PLLine creation parameters + + /// + /// Gets or sets the pl line creation method. + /// + /// + /// The pl line creation method. + /// + public virtual PLLineCreationMethod PLLineCreationMethod + { + get + { + return pLLineCreationMethod; + } + set + { + pLLineCreationMethod = value; + } + } + + /// + /// Gets or sets the head pl 2. + /// + /// + /// The head pl 2. + /// + public virtual double? HeadPL2 + { + get + { + return headPL2; + } + set + { + headPL2 = value; + } + } + + /// + /// Gets or sets the head PL3. + /// + /// + /// The head PL3. + /// + public virtual double? HeadPl3 + { + get + { + return headPL3; + } + set + { + headPL3 = value; + } + } + + /// + /// Gets or sets the head PL4. + /// + /// + /// The head PL4. + /// + public virtual double? HeadPl4 + { + get + { + return headPL4; + } + set + { + headPL4 = value; + } + } + + /// + /// Gets or sets the damping factor pl 3. + /// + /// + /// The damping factor pl 3. + /// + public virtual double DampingFactorPL3 + { + get + { + return dampingFactorPL3; + } + set + { + dampingFactorPL3 = value; + } + } + + /// + /// Gets or sets the damping factor pl 4. + /// + /// + /// The damping factor pl 4. + /// + public virtual double DampingFactorPL4 + { + get + { + return dampingFactorPL4; + } + set + { + dampingFactorPL4 = value; + } + } + + /// + /// Gets or sets the length of the penetration. + /// + /// + /// The length of the penetration. + /// + public virtual double PenetrationLength + { + get + { + return penetrationLength; + } + set + { + penetrationLength = value; + } + } + + /// + /// Gets or sets the pl line offset below dike top at river. + /// + /// + /// The pl line offset below dike top at river. + /// + public virtual double PlLineOffsetBelowDikeTopAtRiver + { + get + { + return pLLineOffsetBelowDikeTopAtRiver; + } + set + { + pLLineOffsetBelowDikeTopAtRiver = value; + } + } + + /// + /// Gets or sets the pl line offset below dike top at polder. + /// + /// + /// The pl line offset below dike top at polder. + /// + public virtual double PlLineOffsetBelowDikeTopAtPolder + { + get + { + return pLLineOffsetBelowDikeTopAtPolder; + } + set + { + pLLineOffsetBelowDikeTopAtPolder = value; + } + } + + /// + /// Gets or sets the pl line offset below shoulder base inside. + /// + /// + /// The pl line offset below shoulder base inside. + /// + public virtual double PlLineOffsetBelowShoulderBaseInside + { + get + { + return pLLineOffsetBelowShoulderBaseInside; + } + set + { + pLLineOffsetBelowShoulderBaseInside = value; + } + } + + /// + /// Gets or sets the pl line offset below dike toe at polder. + /// + /// + /// The pl line offset below dike toe at polder. + /// + public virtual double PlLineOffsetBelowDikeToeAtPolder + { + get + { + return pLLineOffsetBelowDikeToeAtPolder; + } + set + { + pLLineOffsetBelowDikeToeAtPolder = value; + } + } + + /// + /// Gets or sets the pl line offset dry below dike top at river. + /// + /// + /// The pl line offset dry below dike top at river. + /// + public virtual double PLLineOffsetDryBelowDikeTopAtRiver + { + get + { + return pLLineOffsetDryBelowDikeTopAtRiver; + } + set + { + pLLineOffsetDryBelowDikeTopAtRiver = value; + } + } + + /// + /// Gets or sets the pl line offset dry below dike top at polder. + /// + /// + /// The pl line offset dry below dike top at polder. + /// + public virtual double PLLineOffsetDryBelowDikeTopAtPolder + { + get + { + return pLLineOffsetDryBelowDikeTopAtPolder; + } + set + { + pLLineOffsetDryBelowDikeTopAtPolder = value; + } + } + + /// + /// Gets or sets the pl line offset dry below shoulder base inside. + /// + /// + /// The pl line offset dry below shoulder base inside. + /// + public virtual double PLLineOffsetDryBelowShoulderBaseInside + { + get + { + return pLLineOffsetDryBelowShoulderBaseInside; + } + set + { + pLLineOffsetDryBelowShoulderBaseInside = value; + } + } + + /// + /// Gets or sets the pl line offset dry below dike toe at polder. + /// + /// + /// The pl line offset dry below dike toe at polder. + /// + public virtual double PLLineOffsetDryBelowDikeToeAtPolder + { + get + { + return pLLineOffsetDryBelowDikeToeAtPolder; + } + set + { + pLLineOffsetDryBelowDikeToeAtPolder = value; + } + } + + /// + /// Gets or sets the use pl line offset below dike crest middle. + /// + /// + /// The use pl line offset below dike crest middle. + /// + public bool? UsePlLineOffsetBelowDikeCrestMiddle { get; set; } + + /// + /// Gets or sets the pl line offset below dike crest middle. + /// + /// + /// The pl line offset below dike crest middle. + /// + public double? PlLineOffsetBelowDikeCrestMiddle + { + get { return plLineOffsetBelowDikeCrestMiddle; } + set + { + plLineOffsetBelowDikeCrestMiddle = value; + } + } + + /// + /// Gets or sets the use pl line offset factor below shoulder crest. + /// + /// + /// The use pl line offset factor below shoulder crest. + /// + public bool? UsePlLineOffsetFactorBelowShoulderCrest { get; set; } + + /// + /// Gets or sets the pl line offset factor below shoulder crest. + /// + /// + /// The pl line offset factor below shoulder crest. + /// + public double? PlLineOffsetFactorBelowShoulderCrest + { + get { return plLineOffsetFactorBelowShoulderCrest; } + set + { + plLineOffsetFactorBelowShoulderCrest = value; + } + } + + /// + /// Gets or sets the use pl line offset dry below dike crest middle. + /// + /// + /// The use pl line offset dry below dike crest middle. + /// + public bool? UsePlLineOffsetDryBelowDikeCrestMiddle { get; set; } + + /// + /// Gets or sets the pl line offset dry below dike crest middle. + /// + /// + /// The pl line offset dry below dike crest middle. + /// + public double? PlLineOffsetDryBelowDikeCrestMiddle + { + get { return plLineOffsetDryBelowDikeCrestMiddle; } + set + { + plLineOffsetDryBelowDikeCrestMiddle = value; + } + } + + /// + /// Gets or sets the use pl line offset dry factor below shoulder crest. + /// + /// + /// The use pl line offset dry factor below shoulder crest. + /// + public bool? UsePlLineOffsetDryFactorBelowShoulderCrest { get; set; } + + /// + /// Gets or sets the pl line offset dry factor below shoulder crest. + /// + /// + /// The pl line offset dry factor below shoulder crest. + /// + public double? PlLineOffsetDryFactorBelowShoulderCrest + { + get { return plLineOffsetDryFactorBelowShoulderCrest; } + set + { + plLineOffsetDryFactorBelowShoulderCrest = value; + } + } + + /// + /// Gets or sets the intrusion vertical water pressure. + /// + /// + /// The intrusion vertical water pressure. + /// + public IntrusionVerticalWaterPressureType? IntrusionVerticalWaterPressure + { + get { return intrusionVerticalWaterPressure; } + set + { + intrusionVerticalWaterPressure = value; + } + } + #endregion + + #region Waterlevels + + public virtual double BoezemLevelTp + { + get + { + return boezemLevelTp; + } + set + { + boezemLevelTp = value; + } + } + + public virtual double BoezemLevelHbp + { + get + { + return boezemLevelHbp; + } + set + { + boezemLevelHbp = value; + } + } + + public virtual double BoezemLevelLbp + { + get + { + return boezemLevelLbp; + } + set + { + boezemLevelLbp = value; + } + } + + public virtual double PolderLevel + { + get + { + return polderLevel; + } + set + { + polderLevel = value; + } + } + + public virtual double PolderLevelLow + { + get + { + return polderLevelLow; + } + set + { + polderLevelLow = value; + } + } + + public virtual double RiverLevel + { + get + { + return scenarioRiverLevel; + } + set + { + scenarioRiverLevel = value; + } + } + + #endregion + + /// + /// Sets the default values; taking into account which DamProjectType and DamType is set + /// + /// Type of the dam. + /// Type of the dam project. + // TODO fix hiding parameter (e.g. use field instead of parameter) + // TODO possibly set this when setting a damType and damProjectType for this location + public void SetDefaultValues(DamType damType, DamProjectType damProjectType) + { + if ((damType == DamType.Regional) && (damProjectType == DamProjectType.Assessment)) + { + zoneAreaRestSlopeCrestWidth = 1.5; + } + else + { + zoneAreaRestSlopeCrestWidth = 3.0; + } + } + + /// + /// Assemble a list of key/value pairs with the relevant parameters for the location + /// + /// + public Dictionary GetParametersAsNameValuePairs() + { + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + var nameValuePairs = new Dictionary(); + nameValuePairs.Add(LocationParameterNames.DamType, DamType.ToString()); + nameValuePairs.Add(LocationParameterNames.DikeRingId, DikeRingId); + nameValuePairs.Add(LocationParameterNames.SurfaceLineId, SurfaceLineId); + nameValuePairs.Add(LocationParameterNames.Description, Description); + nameValuePairs.Add(LocationParameterNames.XRd, XRd.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.YRd, YRd.ToString(numberFormatInfo)); + if (Segment != null) + { + nameValuePairs.Add(LocationParameterNames.SegmentId, Segment.Name); + } + else + { + nameValuePairs.Add(LocationParameterNames.SegmentId, SegmentId); + } + if (SurfaceLine2 != null) + { + nameValuePairs[LocationParameterNames.SurfaceLineId] = SurfaceLine2.Name; + } + if (PL1Line != null) + { + nameValuePairs.Add(LocationParameterNames.PL1LineId, PL1Line.Name); + } + nameValuePairs.Add(LocationParameterNames.DredgingDepth, DredgingDepth.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PolderLevel, PolderLevel.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PolderLevelLow, PolderLevelLow.ToString(numberFormatInfo)); + if (HeadPL2.HasValue) + { + nameValuePairs.Add(LocationParameterNames.HeadPL2, HeadPL2.Value.ToString(numberFormatInfo)); + } + if (HeadPl3.HasValue) + { + nameValuePairs.Add(LocationParameterNames.HeadPL3, HeadPl3.Value.ToString(numberFormatInfo)); + } + if (HeadPl4.HasValue) + { + nameValuePairs.Add(LocationParameterNames.HeadPL4, HeadPl4.Value.ToString(numberFormatInfo)); + } + nameValuePairs.Add(LocationParameterNames.GrassQuality, GrassQuality.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.Direction, Direction.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.XSoilGeometry2DOrigin, XSoilGeometry2DOrigin.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.DikeMaterialType, DikeMaterialType.ToString()); + nameValuePairs.Add(LocationParameterNames.DikeEmbankmentMaterial, DikeEmbankmentMaterial); + nameValuePairs.Add(LocationParameterNames.ShoulderEmbankmentMaterial, ShoulderEmbankmentMaterial); + nameValuePairs.Add(LocationParameterNames.DampingFactorPL3, DampingFactorPL3.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.DampingFactorPL4, DampingFactorPL4.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PenetrationLength, PenetrationLength.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.BoezemLevelTp, BoezemLevelTp.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.BoezemlevelHbp, BoezemLevelHbp.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.BoezemLevelLbp, BoezemLevelLbp.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineCreationMethod, PLLineCreationMethod.ToString()); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetBelowDikeTopAtRiver, PlLineOffsetBelowDikeTopAtRiver.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetBelowDikeTopAtPolder, PlLineOffsetBelowDikeTopAtPolder.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetBelowShoulderBaseInside, PlLineOffsetBelowShoulderBaseInside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetBelowDikeToeAtPolder, PlLineOffsetBelowDikeToeAtPolder.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetDryBelowDikeTopAtRiver, PLLineOffsetDryBelowDikeTopAtRiver.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetDryBelowDikeTopAtPolder, PLLineOffsetDryBelowDikeTopAtPolder.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetDryBelowShoulderBaseInside, PLLineOffsetDryBelowShoulderBaseInside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.PLLineOffsetDryBelowDikeToeAtPolder, PLLineOffsetDryBelowDikeToeAtPolder.ToString(numberFormatInfo)); + if (PlLineOffsetBelowDikeCrestMiddle.HasValue) + { + nameValuePairs.Add(LocationParameterNames.PlLineOffsetBelowDikeCrestMiddle, + PlLineOffsetBelowDikeCrestMiddle.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetFactorBelowShoulderCrest.HasValue) + { + nameValuePairs.Add(LocationParameterNames.PlLineOffsetFactorBelowShoulderCrest, + PlLineOffsetFactorBelowShoulderCrest.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetDryBelowDikeCrestMiddle.HasValue) + { + nameValuePairs.Add(LocationParameterNames.PlLineOffsetDryBelowDikeCrestMiddle, + PlLineOffsetDryBelowDikeCrestMiddle.Value.ToString(numberFormatInfo)); + } + if (PlLineOffsetDryFactorBelowShoulderCrest.HasValue) + { + nameValuePairs.Add(LocationParameterNames.PlLineOffsetDryFactorBelowShoulderCrest, + PlLineOffsetDryFactorBelowShoulderCrest.Value.ToString(numberFormatInfo)); + } + if (UsePlLineOffsetBelowDikeCrestMiddle.HasValue) + { + nameValuePairs.Add(LocationParameterNames.UsePlLineOffsetBelowDikeCrestMiddle, + UsePlLineOffsetBelowDikeCrestMiddle.Value.ToString()); + } + if (UsePlLineOffsetFactorBelowShoulderCrest.HasValue) + { + nameValuePairs.Add(LocationParameterNames.UsePlLineOffsetFactorBelowShoulderCrest, + UsePlLineOffsetFactorBelowShoulderCrest.Value.ToString()); + } + if (UsePlLineOffsetDryBelowDikeCrestMiddle.HasValue) + { + nameValuePairs.Add(LocationParameterNames.UsePlLineOffsetDryBelowDikeCrestMiddle, + UsePlLineOffsetDryBelowDikeCrestMiddle.Value.ToString()); + } + if (UsePlLineOffsetDryFactorBelowShoulderCrest.HasValue) + { + nameValuePairs.Add(LocationParameterNames.UsePlLineOffsetDryFactorBelowShoulderCrest, + UsePlLineOffsetDryFactorBelowShoulderCrest.Value.ToString()); + } + if (IntrusionVerticalWaterPressure.HasValue) + { + nameValuePairs.Add(LocationParameterNames.IntrusionVerticalWaterPressure, + IntrusionVerticalWaterPressure.Value.ToString()); + } + nameValuePairs.Add(LocationParameterNames.StabilityShoulderGrowSlope, StabilityShoulderGrowSlope.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.StabilityShoulderGrowDeltaX, StabilityShoulderGrowDeltaX.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.StabilitySlopeAdaptionDeltaX, StabilitySlopeAdaptionDeltaX.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SheetPilePointX, SheetPilePoint.X.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SheetPilePointY, SheetPilePoint.Y.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SheetPilePointZ, SheetPilePoint.Z.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SheetPileLength, SheetPileLength.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.RwBankProtectionBottomLevel, RwBankProtectionBottomLevel.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.IsUseOriginalPLLineAssignments, IsUseOriginalPLLineAssignments.ToString()); + nameValuePairs.Add(LocationParameterNames.TrafficLoad, TrafficLoad.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.MinimalCircleDepth, MinimalCircleDepth.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.LevelReductionInside, LevelReductionInside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.LevelReductionOutside, LevelReductionOutside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.LayerHeightDistribution, LayerHeightDistribution.ToString()); + nameValuePairs.Add(LocationParameterNames.LayerHeightDeviation, LayerHeightDeviation.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.DistanceToEntryPoint, DistanceToEntryPoint.ToString(numberFormatInfo)); + if (ModelFactors.RequiredSafetyFactorStabilityInnerSlope != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredSafetyFactorStabilityInnerSlope, ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredSafetyFactorStabilityOuterSlope != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredSafetyFactorStabilityOuterSlope, ModelFactors.RequiredSafetyFactorStabilityOuterSlope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredSafetyFactorPiping != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredSafetyFactorPiping, ModelFactors.RequiredSafetyFactorPiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredProbabilityOfFailureStabilityInnerslope, ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredProbabilityOfFailureStabilityOuterslope, ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.RequiredProbabilityOfFailurePiping != null) + { + nameValuePairs.Add(LocationParameterNames.RequiredProbabilityOfFailurePiping, ModelFactors.RequiredProbabilityOfFailurePiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.UpliftCriterionPiping != null) + { + nameValuePairs.Add(LocationParameterNames.UpliftCriterionPiping, ModelFactors.UpliftCriterionPiping.Value.ToString(numberFormatInfo)); + } + if (ModelFactors.UpliftCriterionStability != null) + { + nameValuePairs.Add(LocationParameterNames.UpliftCriterionStability, ModelFactors.UpliftCriterionStability.Value.ToString(numberFormatInfo)); + } + nameValuePairs.Add(LocationParameterNames.DetrimentFactor, DetrimentFactor.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.StabilityZoneType, StabilityZoneType.ToString()); + nameValuePairs.Add(LocationParameterNames.ForbiddenZoneFactor, ForbiddenZoneFactor.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.ZoneAreaRestSlopeCrestWidth, ZoneAreaRestSlopeCrestWidth.ToString(numberFormatInfo)); + + nameValuePairs.Add(LocationParameterNames.DikeTableHeight, DikeTableHeight.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SlopeDampingPiezometricHeightPolderSide, SlopeDampingPiezometricHeightPolderSide.ToString(numberFormatInfo)); + + nameValuePairs.Add(LocationParameterNames.StabilityDesignMethod, StabilityDesignMethod.ToString()); + nameValuePairs.Add(LocationParameterNames.SlopeAdaptionStartCotangent, SlopeAdaptionStartCotangent.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SlopeAdaptionEndCotangent, SlopeAdaptionEndCotangent.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.SlopeAdaptionStepCotangent, SlopeAdaptionStepCotangent.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewDepthDitch, NewDepthDitch.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewDikeSlopeInside, NewDikeSlopeInside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewDikeSlopeOutside, NewDikeSlopeOutside.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewDikeTopWidth, NewDikeTopWidth.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewMaxHeightShoulderAsFraction, NewMaxHeightShoulderAsFraction.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewMinDistanceDikeToeStartDitch, NewMinDistanceDikeToeStartDitch.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewShoulderBaseSlope, NewShoulderBaseSlope.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewShoulderTopSlope, NewShoulderTopSlope.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewSlopeAngleDitch, NewSlopeAngleDitch.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.NewWidthDitchBottom, NewWidthDitchBottom.ToString(numberFormatInfo)); + nameValuePairs.Add(LocationParameterNames.UseNewDikeSlopeInside, UseNewDikeSlopeInside.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewDikeSlopeOutside, UseNewDikeSlopeOutside.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewDikeTopWidth, UseNewDikeTopWidth.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewDitchDefinition, UseNewDitchDefinition.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewMaxHeightShoulderAsFraction, UseNewMaxHeightShoulderAsFraction.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewMinDistanceDikeToeStartDitch, UseNewMinDistanceDikeToeStartDitch.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewShoulderBaseSlope, UseNewShoulderBaseSlope.ToString()); + nameValuePairs.Add(LocationParameterNames.UseNewShoulderTopSlope, UseNewShoulderTopSlope.ToString()); + return nameValuePairs; + } + + public void SetParametersByNameValuepairs(Dictionary nameValuePairs) + { + foreach (var nameValuePair in nameValuePairs) + { + SetParameterFromNameValuePair(nameValuePair.Key, nameValuePair.Value); + } + } + + [Validate] + public ValidationResult[] AscendingLocalXZSurfaceLine() + { + if (LocalXZSurfaceLine2 != null) + { + return new SurfaceLine2Validator().ValidateCharacteristicPointsAreOrdered(LocalXZSurfaceLine2).ToArray(); + } + else + { + return new ValidationResult[0]; + } + } + + /// + /// Gets the dike embankment soil. + /// + /// + public Soil GetDikeEmbankmentSoil() + { + if (String.IsNullOrEmpty(SoildatabaseName) || String.IsNullOrEmpty(DikeEmbankmentMaterial)) + { + return null; + } + else + { + return SoilList.GetSoilByName(DikeEmbankmentMaterial); + } + } + + /// + /// Gets the shoulder embankment soil. + /// + /// + public Soil GetShoulderEmbankmentSoil() + { + if (String.IsNullOrEmpty(SoildatabaseName) || String.IsNullOrEmpty(ShoulderEmbankmentMaterial)) + { + return null; + } + else + { + return SoilList.GetSoilByName(ShoulderEmbankmentMaterial); + } + } + + /// + /// Gets the most probable profile. If there are no elements in the it returns null + /// and leave the handling over to the caller + /// + /// The soil profile + public SoilProfile1D GetMostProbableProfile(FailureMechanismSystemType? segmentFailureMechanismType) + { +// if (Segment == null) +// { +// throw new ArgumentNullException(String.Format(ThrowHelper.GetResourceString(StringResourceNames.LocationHasNoSegment), Name)); +// } + + return Segment.GetMostProbableProfile(segmentFailureMechanismType); + } + + /// + /// Gets the most probable profile. If there are no elements in the it returns null + /// and leave the handling over to the caller + /// + /// The soil profile + public string GetMostProbableGeometry2DName(FailureMechanismSystemType? segmentFailureMechanismType) + { +// if (Segment == null) +// { +// throw new ArgumentNullException(String.Format(ThrowHelper.GetResourceString(StringResourceNames.LocationHasNoSegment), Name)); +// } + + return Segment.GetMostProbableGeometry2DName(segmentFailureMechanismType); + } + + public double? GetSoilProfileProbability(SoilProfile1D soilProfile, FailureMechanismSystemType? segmentFailureMechanismType) + { +// if (Segment == null) +// { +// throw new ArgumentNullException(String.Format(ThrowHelper.GetResourceString(StringResourceNames.LocationHasNoSegment), Name)); +// } + + return Segment.GetSoilProfileProbability(soilProfile, segmentFailureMechanismType); + } + + /// + /// Gets a sorted list of soil geometry probabilities for a certain failure mechanism type + /// + /// The failure mechanism type + /// List of geometry probabilities + public List GetGeometryProbabilities(FailureMechanismSystemType failureMechanismType) + { + var geometryProbabilities = new List(); + if (Segment != null) + { + foreach (var existingGeometryProbability in Segment.SoilProfileProbabilities) + { + if (existingGeometryProbability.SegmentFailureMechanismType.HasValue && existingGeometryProbability.SegmentFailureMechanismType.Value == failureMechanismType) + { + geometryProbabilities.Add(existingGeometryProbability); + } + } + + geometryProbabilities.Sort(); + } + return geometryProbabilities; + } + + /// + /// Gets the combination of the surface line and soil profile for a given failure mechanism and index + /// + /// Failure mechanism type + /// The index indicates the ranking in probability + /// The probability of the soil surface profile + /// The soil surface profile + public SoilSurfaceProfile GetSoilSurfaceProfile(FailureMechanismSystemType failureMechanismType, int index, out double probability) + { + List soilGeometryProbabilities = GetGeometryProbabilities(failureMechanismType); + SoilGeometryProbability soilGeometryProbability = index < soilGeometryProbabilities.Count ? soilGeometryProbabilities[index] : null; + + SoilProfile1D originalProfile = soilGeometryProbability != null ? soilGeometryProbability.SoilProfile : null; + probability = soilGeometryProbability != null ? soilGeometryProbability.Probability : 0; + + if (soilSurfaceProfile == null || soilSurfaceProfile.SoilProfile != originalProfile || soilSurfaceProfile.SurfaceLine2 != LocalXZSurfaceLine2) + { + Soil dikeSoil = SoilList.GetSoilByName(DikeEmbankmentMaterial); + + if (soilSurfaceProfile == null) + { + soilSurfaceProfile = new SoilSurfaceProfile(); + } + // Do not assign the orginal soilprofile, because it will be changed in the class SoilSurfaceProfile + SoilProfile1D soilProfile1D; + if (originalProfile == null) + { + soilProfile1D = new SoilProfile1D(SurfaceLine2.Geometry.GetMaxZ(), -10, dikeSoil); + } + else + { + soilProfile1D = new SoilProfile1D(); + soilProfile1D.Assign(originalProfile); + } + soilSurfaceProfile.SoilProfile = soilProfile1D; + soilSurfaceProfile.SurfaceLine2 = LocalXZSurfaceLine2; + soilSurfaceProfile.DikeEmbankmentMaterial = GetDikeEmbankmentSoil(); + + foreach (SoilLayer2D layer in soilSurfaceProfile.Surfaces) + { + if (layer.Soil == null) + { + layer.Soil = dikeSoil; + } + } + } + + return soilSurfaceProfile; + } + + public void AlignBoundaryPointsOfPL1LineWithAdaptedSurfaceLine(SurfaceLine2 adaptedSurfaceLine) + { + if ((LocalXZPL1Line != null) && (LocalXZPL1Line.Points.Count > 1)) + { + GeometryPoint lastPointPL1Line = LocalXZPL1Line.Points.Last(); + GeometryPoint lastPointSurfaceLine = adaptedSurfaceLine.Geometry.Points.Last(); + lastPointPL1Line.X = lastPointSurfaceLine.X; + GeometryPoint firstPointPL1Line = LocalXZPL1Line.Points.First(); + GeometryPoint firstPointSurfaceLine = adaptedSurfaceLine.Geometry.Points.First(); + firstPointPL1Line.X = firstPointSurfaceLine.X; + } + } + + public void SetParameterFromNameValuePair(string parameterName, string parameterValue) + { + var numberFormatInfo = new NumberFormatInfo(); + numberFormatInfo.NumberDecimalSeparator = "."; + if (parameterName.Equals(LocationParameterNames.DamType)) + { + DamType = (DamType) Enum.Parse(typeof(DamType), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.DikeRingId)) + { + DikeRingId = parameterValue; + } + if (parameterName.Equals(LocationParameterNames.Description)) + { + Description = parameterValue; + } + if (parameterName.Equals(LocationParameterNames.XRd)) + { + XRd = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.YRd)) + { + YRd = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SegmentId)) + { + SegmentId = parameterValue; + } + if (parameterName.Equals(LocationParameterNames.SurfaceLineId)) + { + SurfaceLineId = parameterValue; + } + //if (parameterName.Equals(LocationParameterNames.PL1LineId)) + // this.PL1LineId = Convert.ToDouble(parameterValue, numberFormatInfo); + if (parameterName.Equals(LocationParameterNames.DredgingDepth)) + { + DredgingDepth = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PolderLevel)) + { + PolderLevel = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PolderLevelLow)) + { + PolderLevelLow = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.HeadPL2)) + { + HeadPL2 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.HeadPL3)) + { + HeadPl3 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.HeadPL4)) + { + HeadPl4 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.GrassQuality)) + { + GrassQuality = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.Direction)) + { + Direction = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.XSoilGeometry2DOrigin)) + { + XSoilGeometry2DOrigin = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.DikeMaterialType)) + { + DikeMaterialType = (SoilType) Enum.Parse(typeof(SoilType), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.DikeEmbankmentMaterial)) + { + DikeEmbankmentMaterial = parameterValue; + } + if (parameterName.Equals(LocationParameterNames.ShoulderEmbankmentMaterial)) + { + ShoulderEmbankmentMaterial = parameterValue; + } + if (parameterName.Equals(LocationParameterNames.DampingFactorPL3)) + { + DampingFactorPL3 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.DampingFactorPL4)) + { + DampingFactorPL4 = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PenetrationLength)) + { + PenetrationLength = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.BoezemLevelTp)) + { + BoezemLevelTp = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.BoezemlevelHbp)) + { + BoezemLevelHbp = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.BoezemLevelLbp)) + { + BoezemLevelLbp = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineCreationMethod)) + { + PLLineCreationMethod = (PLLineCreationMethod) Enum.Parse(typeof(PLLineCreationMethod), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetBelowDikeTopAtRiver)) + { + PlLineOffsetBelowDikeTopAtRiver = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetBelowDikeTopAtPolder)) + { + PlLineOffsetBelowDikeTopAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetBelowShoulderBaseInside)) + { + PlLineOffsetBelowShoulderBaseInside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetBelowDikeToeAtPolder)) + { + PlLineOffsetBelowDikeToeAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetDryBelowDikeTopAtRiver)) + { + PLLineOffsetDryBelowDikeTopAtRiver = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetDryBelowDikeTopAtPolder)) + { + PLLineOffsetDryBelowDikeTopAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetDryBelowShoulderBaseInside)) + { + PLLineOffsetDryBelowShoulderBaseInside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PLLineOffsetDryBelowDikeToeAtPolder)) + { + PLLineOffsetDryBelowDikeToeAtPolder = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PlLineOffsetBelowDikeCrestMiddle)) + { + PlLineOffsetBelowDikeCrestMiddle = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PlLineOffsetFactorBelowShoulderCrest)) + { + PlLineOffsetFactorBelowShoulderCrest = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PlLineOffsetDryBelowDikeCrestMiddle)) + { + PlLineOffsetDryBelowDikeCrestMiddle = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.PlLineOffsetDryFactorBelowShoulderCrest)) + { + PlLineOffsetDryFactorBelowShoulderCrest = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UsePlLineOffsetBelowDikeCrestMiddle)) + { + UsePlLineOffsetBelowDikeCrestMiddle = Convert.ToBoolean(parameterValue); + } + if (parameterName.Equals(LocationParameterNames.UsePlLineOffsetFactorBelowShoulderCrest)) + { + UsePlLineOffsetFactorBelowShoulderCrest = Convert.ToBoolean(parameterValue); + } + if (parameterName.Equals(LocationParameterNames.UsePlLineOffsetDryBelowDikeCrestMiddle)) + { + UsePlLineOffsetDryBelowDikeCrestMiddle = Convert.ToBoolean(parameterValue); + } + if (parameterName.Equals(LocationParameterNames.UsePlLineOffsetDryFactorBelowShoulderCrest)) + { + UsePlLineOffsetDryFactorBelowShoulderCrest = Convert.ToBoolean(parameterValue); + } + if (parameterName.Equals(LocationParameterNames.IntrusionVerticalWaterPressure)) + { + IntrusionVerticalWaterPressure = + (IntrusionVerticalWaterPressureType) + Enum.Parse(typeof (IntrusionVerticalWaterPressureType), parameterValue); + + } + if (parameterName.Equals(LocationParameterNames.StabilityShoulderGrowSlope)) + { + StabilityShoulderGrowSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.StabilityShoulderGrowDeltaX)) + { + StabilityShoulderGrowDeltaX = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.StabilitySlopeAdaptionDeltaX)) + { + StabilitySlopeAdaptionDeltaX = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SheetPileLength)) + { + SheetPileLength = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RwBankProtectionBottomLevel)) + { + RwBankProtectionBottomLevel = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SheetPilePointX)) + { + SheetPilePointX = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SheetPilePointY)) + { + SheetPilePointY = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SheetPilePointZ)) + { + SheetPilePointZ = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.IsUseOriginalPLLineAssignments)) + { + IsUseOriginalPLLineAssignments = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.TrafficLoad)) + { + TrafficLoad = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.MinimalCircleDepth)) + { + MinimalCircleDepth = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.LevelReductionInside)) + { + LevelReductionInside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.LevelReductionOutside)) + { + LevelReductionOutside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.LayerHeightDistribution)) + { + LayerHeightDistribution = (DistributionType) Enum.Parse(typeof(DistributionType), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.LayerHeightDeviation)) + { + LayerHeightDeviation = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.DistanceToEntryPoint)) + { + DistanceToEntryPoint = Convert.ToDouble(parameterValue, numberFormatInfo); + } + + if (parameterName.Equals(LocationParameterNames.RequiredSafetyFactorStabilityInnerSlope)) + { + ModelFactors.RequiredSafetyFactorStabilityInnerSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RequiredSafetyFactorStabilityOuterSlope)) + { + ModelFactors.RequiredSafetyFactorStabilityOuterSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RequiredSafetyFactorPiping)) + { + ModelFactors.RequiredSafetyFactorPiping = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RequiredProbabilityOfFailureStabilityInnerslope)) + { + ModelFactors.RequiredProbabilityOfFailureStabilityInnerslope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RequiredProbabilityOfFailureStabilityOuterslope)) + { + ModelFactors.RequiredProbabilityOfFailureStabilityOuterslope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.RequiredProbabilityOfFailurePiping)) + { + ModelFactors.RequiredProbabilityOfFailurePiping = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UpliftCriterionPiping)) + { + ModelFactors.UpliftCriterionPiping = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UpliftCriterionStability)) + { + ModelFactors.UpliftCriterionStability = Convert.ToDouble(parameterValue, numberFormatInfo); + } + + if (parameterName.Equals(LocationParameterNames.DetrimentFactor)) + { + DetrimentFactor = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.StabilityZoneType)) + { + StabilityZoneType = (MStabZonesType) Enum.Parse(typeof(MStabZonesType), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.ForbiddenZoneFactor)) + { + ForbiddenZoneFactor = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.ZoneAreaRestSlopeCrestWidth)) + { + ZoneAreaRestSlopeCrestWidth = Convert.ToDouble(parameterValue, numberFormatInfo); + } + + if (parameterName.Equals(LocationParameterNames.DikeTableHeight)) + { + DikeTableHeight = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SlopeDampingPiezometricHeightPolderSide)) + { + SlopeDampingPiezometricHeightPolderSide = Convert.ToDouble(parameterValue, numberFormatInfo); + } + + if (parameterName.Equals(LocationParameterNames.StabilityDesignMethod)) + { + StabilityDesignMethod = (StabilityDesignMethod) Enum.Parse(typeof(StabilityDesignMethod), parameterValue); + } + if (parameterName.Equals(LocationParameterNames.SlopeAdaptionStartCotangent)) + { + SlopeAdaptionStartCotangent = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SlopeAdaptionEndCotangent)) + { + SlopeAdaptionEndCotangent = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.SlopeAdaptionStepCotangent)) + { + SlopeAdaptionStepCotangent = Convert.ToDouble(parameterValue, numberFormatInfo); + } + + if (parameterName.Equals(LocationParameterNames.NewDepthDitch)) + { + NewDepthDitch = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewDikeSlopeInside)) + { + NewDikeSlopeInside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewDikeSlopeOutside)) + { + NewDikeSlopeOutside = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewDikeTopWidth)) + { + NewDikeTopWidth = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewMaxHeightShoulderAsFraction)) + { + NewMaxHeightShoulderAsFraction = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewMinDistanceDikeToeStartDitch)) + { + NewMinDistanceDikeToeStartDitch = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewShoulderBaseSlope)) + { + NewShoulderBaseSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewShoulderTopSlope)) + { + NewShoulderTopSlope = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewSlopeAngleDitch)) + { + NewSlopeAngleDitch = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.NewWidthDitchBottom)) + { + NewWidthDitchBottom = Convert.ToDouble(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewDikeSlopeInside)) + { + UseNewDikeSlopeInside = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewDikeSlopeOutside)) + { + UseNewDikeSlopeOutside = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewDikeTopWidth)) + { + UseNewDikeTopWidth = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewDitchDefinition)) + { + UseNewDitchDefinition = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewMaxHeightShoulderAsFraction)) + { + UseNewMaxHeightShoulderAsFraction = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewMinDistanceDikeToeStartDitch)) + { + UseNewMinDistanceDikeToeStartDitch = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewShoulderBaseSlope)) + { + UseNewShoulderBaseSlope = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + if (parameterName.Equals(LocationParameterNames.UseNewShoulderTopSlope)) + { + UseNewShoulderTopSlope = Convert.ToBoolean(parameterValue, numberFormatInfo); + } + } + + public ModelParametersForPLLines CreateModelParametersForPLLines() + { + return new ModelParametersForPLLines + { + PenetrationLength = PenetrationLength, + DampingFactorPL3 = DampingFactorPL3, + DampingFactorPL4 = DampingFactorPL4, + PLLineCreationMethod = PLLineCreationMethod + }; + } + + + + private bool IsDesign() + { + bool isDesign = (DamProjectType == DamProjectType.Design); + return isDesign; + } + + private bool ArePlLineCreationExpertKnowledgeParametersNeeded() + { + bool arePlLineCreationExpertKnowledgeParametersNeeded = PLLineCreationMethod == + PLLineCreationMethod.ExpertKnowledgeRRD || + PLLineCreationMethod == + PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD; + return arePlLineCreationExpertKnowledgeParametersNeeded; + } + + + public override string ToString() + { + return Name; + + /* StringBuilder sb = new StringBuilder(); + sb.Append(this.Name); + if (this.Segment != null) + sb.Append(String.Format(" @ Segment {0}", this.Segment.Name)); + if (this.SurfaceLine != null) + sb.Append(String.Format(" with {0})", this.SurfaceLine.Name)); + sb.Append(String.Format(" | X={0}, Y={1}, PolderLevel={2:F2}, HeadPL2={3:F2}, HeadPl3={4:F2}", this.XRd, this.YRd, this.PolderLevel, this.HeadPL2, this.HeadPl3)); + return sb.ToString();*/ + } + + public ICollection GetDomain(string property) + { + switch (property) + { + case "PLLineCreationMethod": // ToDo Moet dit nog afhankelijk van damProjectType (design/calamity etc) o.i.d. ? --->> Erik + if (DamProjectType == DamProjectType.DamLiveConfiguration) + { + return new[] + { + PLLineCreationMethod.ExpertKnowledgeRRD, + PLLineCreationMethod.ExpertKnowledgeLinearInDike, + PLLineCreationMethod.DupuitStatic + }; + } + else + { + return new[] + { + PLLineCreationMethod.ExpertKnowledgeRRD, + PLLineCreationMethod.ExpertKnowledgeLinearInDike, + }; + } + case "IntrusionVerticalWaterPressure": + return new[] + { + this.Translate("Standard"), + this.Translate("Linear"), + this.Translate("FullHydroStatic"), + this.Translate("HydroStatic"), + this.Translate("SemiTimeDependent") + }; + default: + return null; + } + } + + public void Repair(object subject, string property, string id) + { + if (subject is Location) + { + if (id == "ZoneTypeSafety" && property == "StabilityZoneType") + { + modelFactors.RequiredSafetyFactorStabilityInnerSlope = detrimentFactor; + } + if (id == "AssignMinValue" && property == "NewDikeTopWidth") + { + NewDikeTopWidth = newDikeTopWidthMinValue; + } + if (id == "AssignMinValue" && property == "NewDikeSlopeInside") + { + NewDikeSlopeInside = newDikeSlopeInsideMinValue; + } + if (id == "AssignMinValue" && property == "NewDikeSlopeOutside") + { + NewDikeSlopeOutside = newDikeSlopeOutsideMinValue; + } + if (id == "AssignMinValue" && property == "PlLineOffsetFactorBelowShoulderCrest") + { + PlLineOffsetFactorBelowShoulderCrest = DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMinValue; + } + if (id == "AssignMaxValue" && property == "PlLineOffsetFactorBelowShoulderCrest") + { + PlLineOffsetFactorBelowShoulderCrest = DamGlobalConstants.PlLineOffsetFactorBelowShoulderCrestMaxValue; + } + if (id == "AssignMinValue" && property == "PenetrationLength") + { + PenetrationLength = penetrationLenghtMinValue; + } + } + } + + public string GetRepairDescription(object subject, string property, string id) + { + if (id == "ZoneTypeSafety" && property == "StabilityZoneType") + { + return LocalizationManager.GetTranslatedText(this, "NoRequiredSafetyForZonesRepair"); + } + if (id == "AssignMinValue") + { + return LocalizationManager.GetTranslatedText(this, "AssignMinValue"); + } + if (id == "AssignMaxValue") + { + return LocalizationManager.GetTranslatedText(this, "AssignMaxValue"); + } + return ""; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PL1Line.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PL1Line.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/PL1Line.cs (revision 334) @@ -0,0 +1,56 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geometry; + +namespace Deltares.DamEngine.Data.General.PlLines +{ + public class PL1LineException : Exception + { + public PL1LineException(string message) : base(message) + { + } + } + + public class PL1Line : GeometryPointString + { + public void Assign(PL1Line pl1Line) + { + this.Points.Clear(); + + foreach (GeometryPoint point in pl1Line.Points) + { + GeometryPoint newPoint = (GeometryPoint) point.Clone(); + this.Points.Add(newPoint); + } + } + + public new PL1Line Clone() + { + var newPL1Line = new PL1Line(); + + newPL1Line.Assign(this); + + return newPL1Line; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DamGlobalConstants.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DamGlobalConstants.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DamGlobalConstants.cs (revision 334) @@ -0,0 +1,31 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General +{ + public static class DamGlobalConstants + { + public const double NoRunValue = 99; + public const double RequiredSafetyPipingForAssessment = 1.2; + public const double PlLineOffsetFactorBelowShoulderCrestMinValue = 0.0; + public const double PlLineOffsetFactorBelowShoulderCrestMaxValue = 1.0; + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSDAMSlopeWInterface.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSDAMSlopeWInterface.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSDAMSlopeWInterface.cs (revision 334) @@ -0,0 +1,70 @@ +// Copyright (C) Stichting Deltares 2017. 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.Runtime.InteropServices; + +namespace Deltares.DamEngine.Calculators.Interfaces +{ + public class DGSDAMSlopeWInterface : DgsStandardDllInterface + { + private const string DllFileName = @"DGSDAMSlopeW.dll"; + + [DllImport(DllFileName)] + static extern int DllGetVersion(out DllVersionInfoStructure dllVersionInfoStructure); + [DllImport(DllFileName)] + static extern string GetDescription(); + [DllImport(DllFileName)] + static extern string GetErrorMessage(); + [DllImport(DllFileName)] + static extern int CreateSlopeWProject(string inputXmlString); + + /// + /// GetDllVersion + /// + /// version as string + new public string GetDllVersion() + { + DllVersionInfoStructure dllInfo; + var returnValue = DllGetVersion(out dllInfo); + return dllInfo.DwBuildNumber.ToString(); + } + + /// + /// CreateProjectFile + /// + /// Error number + public int CreateProjectFile(string inputXmlString) + { + return (CreateSlopeWProject(inputXmlString)); + } + + /// + /// ErrorMessage + /// + /// Error as string + new public string ErrorMessage() + { + return (GetErrorMessage()); + } + + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ParameterMissingException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ParameterMissingException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ParameterMissingException.cs (revision 334) @@ -0,0 +1,47 @@ +// Copyright (C) Stichting Deltares 2017. 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.General +{ + [Serializable] + public class ParameterMissingException : Exception + { + public ParameterMissingException(string messageFormat) + : base(messageFormat, null) + { + } + + public ParameterMissingException(string messageFormat, Exception inner) + : base(string.Format(messageFormat), inner) + { + } + + protected ParameterMissingException( + SerializationInfo info, + StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSStandardDLLInterface.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSStandardDLLInterface.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSStandardDLLInterface.cs (revision 334) @@ -0,0 +1,131 @@ +// Copyright (C) Stichting Deltares 2017. 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.Runtime.InteropServices; + +namespace Deltares.DamEngine.Calculators.Interfaces +{ + /// + /// Structure for dll information + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct DllVersionInfoStructure + { + /// + /// Size of the structure, in bytes + /// + public uint CbSize; + + /// + /// Major version of the DLL + /// + public uint DwMajorVersion; + + /// + /// Minor version of the DLL + /// + public uint DwMinorVersion; + + /// + /// Build number of the DLL + /// + public uint DwBuildNumber; + + /// + /// Identifies the platform for which the DLL was built + /// + public uint DwPlatformID; + } + + /// + /// The standard DLL interface for DGS. + /// + public class DgsStandardDllInterface + { + /// + /// No Licence error + /// + public const int DllUErrorNoLicense = 1; + + /// + /// User has aborted error + /// + public const int DllErrorUserAborted = 2; + + /// + /// Non compliant xml error + /// + public const int DllErrorNonCompliantXml = 3; + + /// + /// Invalid input data error + /// + public const int DllErrorInvalidInputData = 4; + + /// + /// Handled fatal error + /// + public const int DllErrorHandledFatal = 5; + + /// + /// Unhandled fatal error + /// + public const int DllErrorUnhandledFatal = 6; + + /// + /// Invalid handle for dll error + /// + public const int DllErrorInvalidHandle = 7; + + /// + /// Output buffer too small error + /// + public const int DllErrorOutputBufferTooSmall = 8; + + /// + /// Error constants + /// + public static int DllErrorNone = 0; + + /// + /// Used to hold the last error encountered + /// + public static int DllErrorLastErrorCode = 0; + + /// + /// Example! (remove this wrapper if not needed) + /// + /// + public string GetDllVersion() + { + return "To be implemented"; + } + + /// + /// List of errormessages + /// + /// + public string ErrorMessage() + { + return "To be implemented"; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapter.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapter.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineAdapter.cs (revision 334) @@ -0,0 +1,495 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Calculators.General; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Calculators.Dikes_Design +{ + public struct DitchDefinition + { + public double OriginalX; + public double DistanceFromToe; + public double DistanceToBottomDikeSide; + public double DistanceToBottomPolderSide; + public double DistanceToEndDitch; + public double DepthBottomDikeSide; + public double DepthBottomPolderSide; + } + + public abstract class SurfaceLineAdapter + { + + private struct DitchCoordinates + { + public double XAtDike; + public double ZAtDike; + public double XBottomAtDike; + public double ZBottom; + public double XBottomAtPolder; + public double XAtPolder; + public double ZAtPolder; + } + + protected readonly Location Location; + protected readonly SurfaceLine2 surfaceLine; + protected double trafficLoadOffsetXfromRiverside; + protected double trafficLoadOffsetXfromPolderside; + protected double trafficLoadWidth; + protected bool hasTrafficLoad; + protected bool isTrafficLoadOnCrest = false; + const double offset = 100.0; + + /// + /// Constructor + /// + /// + /// + protected SurfaceLineAdapter(SurfaceLine2 surfaceLine, Location location) + { + ThrowWhenSurfaceLineIsNull(surfaceLine); + ThrowWhenSurfaceLineDoesNotSatisfyToSpecification(surfaceLine); + this.surfaceLine = new SurfaceLine2(); + surfaceLine.CloneProperties(this.surfaceLine);// ##Bka: replaced FullDeepClone(); by this (as todo says, has to be tested)// TODO: Do not do this! Give it the clone instead: GRASP Creator principle + this.Location = location; + RetainTrafficLoad(); + } + + /// + /// Store the parameters with which the traffic load can be restored. + /// The traffic load will be retained relative to the buitenkruinlijn. + /// If the traffic load is completly inside area between buitenkruinlijn and binnenkruinlijn the following will be done: + /// - The traffic load will be retained relative to the binnenkruinlijn. If the leftside of the traffic load passes the buitenkruinlijn, + /// the leftside of the traffic load will be placed on the buitenkruinlijn. It is possible that the rightside of the traffic load + /// passes the buitenkruinlijn. + /// See documentation in Issue [MWDAM-548] + /// + private void RetainTrafficLoad() + { + GeometryPoint pointTrafficLoadInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadInside); + GeometryPoint pointTrafficLoadOutside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadOutside); + GeometryPoint pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + GeometryPoint pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + + hasTrafficLoad = ((pointTrafficLoadInside != null) && (pointTrafficLoadOutside != null)); + if (hasTrafficLoad) + { + trafficLoadOffsetXfromRiverside = pointTrafficLoadOutside.X - pointDikeTopAtRiver.X; + trafficLoadOffsetXfromPolderside = pointDikeTopAtPolder.X - pointTrafficLoadInside.X; + trafficLoadWidth = pointTrafficLoadInside.X - pointTrafficLoadOutside.X; + isTrafficLoadOnCrest = (pointTrafficLoadOutside.X >= pointDikeTopAtRiver.X) && (pointTrafficLoadInside.X <= pointDikeTopAtPolder.X); + } + + } + + /// + /// Create traffic load based on the retained traffic load parameters + /// See documentation in Issue [MWDAM-548] + /// + protected void RestoreTrafficLoad() + { + if (hasTrafficLoad) + { + GeometryPoint pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + GeometryPoint pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + if (isTrafficLoadOnCrest) + { + // The traffic load will be restored relative to the binnenkruinlijn. If the leftside of the traffic load passes the buitenkruinlijn, + // the leftside of the traffic load will be placed on the buitenkruinlijn. It is possible that the rightside of the traffic load + // passes the buitenkruinlijn. + surfaceLine.SortPoints(); // line need to be sorted to use GetZAtX + double xCoordinate = pointDikeTopAtPolder.X - trafficLoadOffsetXfromPolderside - trafficLoadWidth; + if (xCoordinate < pointDikeTopAtRiver.X) + { + xCoordinate = pointDikeTopAtRiver.X; + } + double zCoordinate = surfaceLine.Geometry.GetZatX(xCoordinate); + surfaceLine.EnsurePointOfType(xCoordinate, zCoordinate, CharacteristicPointType.TrafficLoadOutside); + + surfaceLine.SortPoints(); // line need to be sorted to use GetZAtX + xCoordinate += trafficLoadWidth; + zCoordinate = surfaceLine.Geometry.GetZatX(xCoordinate); + surfaceLine.EnsurePointOfType(xCoordinate, zCoordinate, CharacteristicPointType.TrafficLoadInside); + } + else + { + // The traffic load will be restore relative to the buitenkruinlijn. + surfaceLine.SortPoints(); // line need to be sorted to use GetZAtX + double xCoordinate = pointDikeTopAtRiver.X + trafficLoadOffsetXfromRiverside; + double zCoordinate = surfaceLine.Geometry.GetZatX(xCoordinate); + surfaceLine.EnsurePointOfType(xCoordinate, zCoordinate, CharacteristicPointType.TrafficLoadOutside); + + surfaceLine.SortPoints(); // line need to be sorted to use GetZAtX + xCoordinate = pointDikeTopAtRiver.X + trafficLoadOffsetXfromRiverside + trafficLoadWidth; + zCoordinate = surfaceLine.Geometry.GetZatX(xCoordinate); + surfaceLine.EnsurePointOfType(xCoordinate, zCoordinate, CharacteristicPointType.TrafficLoadInside); + } + } + } + + /// + /// Replaces the inside slope by adding the new end point of the slope to the surfaceline. + /// + /// + /// + /// point equal to the ShoulderTopInside when the new slope ends on that point else null + protected GeometryPoint ReplaceBaseInsideForNewSlope(GeometryPoint startPoint, double slopeTangent) + { + GeometryPoint result = null; + var line = new Line + { + BeginPoint = new Point2D(startPoint.X, startPoint.Z), + EndPoint = + new Point2D(startPoint.X + offset, + startPoint.Z - offset * slopeTangent) + }; + // Find the intersectionpoint(s) of the new slope with the surface line + var intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); + Point2D newSlopeEndPoint = null; + if (intersectionpoints.Count > 0) + { + newSlopeEndPoint = intersectionpoints.First(); + // One of the intersection points can be the dike top which should not be replaced + if (newSlopeEndPoint.X == surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X && + newSlopeEndPoint.Z == surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z) + { + newSlopeEndPoint = null; + if (intersectionpoints.Count > 1) + { + newSlopeEndPoint = intersectionpoints[1]; + } + } + } + if (newSlopeEndPoint == null) + { + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(this, "SlopeErrorNoIntersection")); + } + var dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + if (newSlopeEndPoint.X > dikeToeAtPolder.X) + { + // The new point is beyond the old dike toe so adapt that point. + surfaceLine.EnsurePointOfType(newSlopeEndPoint.X, newSlopeEndPoint.Z, CharacteristicPointType.DikeToeAtPolder); + // Remove all points between top and dike toe, + surfaceLine.RemoveSegmentBetween( + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, + newSlopeEndPoint.X); + } + else + { + var shoulderTopInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + var shoulderBaseInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); + if (shoulderBaseInside != null && shoulderTopInside != null) + { + if (newSlopeEndPoint.X > shoulderTopInside.X) + { + // The new point is in the slope part of the shoulder (between ShoulderTopInside and Dike toe). So add a normal point + // at the new location and remove all points between the top and the new point. + //surfaceLine.RemovePoint(CharacteristicPointType.); + surfaceLine.EnsurePoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); + surfaceLine.RemoveSegmentBetween( + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, + newSlopeEndPoint.X); + } + else + { + if (newSlopeEndPoint.X < shoulderTopInside.X) + { + // The new point is in the horizontal part of the shoulder. Remove all points between the current + // shoulderbase inside and its new location, then move the base + surfaceLine.RemoveSegmentBetween(shoulderBaseInside.X, newSlopeEndPoint.X); + surfaceLine.EnsurePointOfType(newSlopeEndPoint.X, newSlopeEndPoint.Z, + CharacteristicPointType.ShoulderBaseInside); + + } + else + { + // The new point is equal to ShoulderTopInside. So remove that, add a normal point at its location + // and remove all points between the top and the new point. + var toBeRemoved = surfaceLine.CharacteristicPoints.FirstOrDefault( + cp => cp.CharacteristicPointType == CharacteristicPointType.ShoulderTopInside); + if (toBeRemoved != null) + { + surfaceLine.CharacteristicPoints.Remove(toBeRemoved); + } + surfaceLine.EnsurePoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); + surfaceLine.RemoveSegmentBetween( + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, + newSlopeEndPoint.X); + result = new GeometryPoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); + } + } + } + else + { + // if the newtoe equals the diketoe, then just skip, nothing has to be changed. Otherwise there is a mistake! + if (!newSlopeEndPoint.LocationEquals(new Point2D(dikeToeAtPolder.X, dikeToeAtPolder.Z))) + { + // There is no shoulder so the slope must be too steep. + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(this, + "SlopeErrorNoIntersection")); + } + } + } + surfaceLine.SortPoints(); + return result; + } + + /// + /// Throws an exception when the surface line does not comply to the specification + /// + /// + /// The specification is that there: + /// - There are should be at least 4 points in the surface line + /// - must be a dike + /// - that the point coords are non zero + /// - There is a surface line when a shoulder exists + /// + /// The candidate to test + private static void ThrowWhenSurfaceLineDoesNotSatisfyToSpecification(SurfaceLine2 surfaceLine) + { + ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(surfaceLine.Geometry.Points); + ThrowWhenSurfaceHasNoDike(surfaceLine); + ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(surfaceLine, + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside)); + + var p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + var p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + + var zeroPoint = new GeometryPoint(); + + if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterDikeHeightError")); + + if (surfaceLine.HasShoulderInside()) + { + p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); + if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterShoulderHeightError")); + } + } + + private static void ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(SurfaceLine2 surfaceLine, GeometryPoint surfaceLevelPoint) + { + if (surfaceLine.HasShoulderInside() && surfaceLevelPoint == null) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterSurfaceLevelError")); + } + + private static void ThrowWhenSurfaceHasNoDike(SurfaceLine2 surfaceLine) + { + if (!surfaceLine.HasDike()) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterInvalidDikeError")); + } + + private static void ThrowWhenSurfaceLineIsNull(SurfaceLine2 surfaceLine) + { + if (surfaceLine == null) + throw new ArgumentNullException("SurfaceLine", LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterNoDikeError")); + } + + private static void ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(ICollection points) + { + if (points == null || points.Count < 4) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterNoDikePointsError")); + } + + protected DitchDefinition? GetDitchDefinition() + { + var ditchDefinition = new DitchDefinition(); + if (surfaceLine.HasDitch() && surfaceLine.IsDitchCorrect()) + { + var ditchDikeSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); + ditchDefinition.DistanceFromToe = ditchDikeSide.X - + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; + if (ditchDefinition.DistanceFromToe >= 0) + { + ditchDefinition.OriginalX = ditchDikeSide.X; + ditchDefinition.DistanceToBottomDikeSide = + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide).X - + ditchDikeSide.X; + ditchDefinition.DistanceToBottomPolderSide = + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide).X - + ditchDikeSide.X; + ditchDefinition.DistanceToEndDitch = + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X - + ditchDikeSide.X; + ditchDefinition.DepthBottomDikeSide = ditchDikeSide.Z - + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide).Z; + ditchDefinition.DepthBottomPolderSide = ditchDikeSide.Z - + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide).Z; + return ditchDefinition; + } + } + else + { + if (surfaceLine.HasDitch()) + { + // Incorrect ditch is an error here, this should have been checked already + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterDikeDitchError")); + } + } + return null; + } + + /// + /// Removes the existing ditch. + /// + /// The ditch definition. + protected void RemoveExistingDitch(DitchDefinition? ditchDefinition) + { + if (ditchDefinition != null) + { + // It is possible that DikeToeAtPolder coinsides with DitchDikeSide or SurfaceLevelInside with DitchPolderSide + // If that is the case, those characteristic points should be restored + // So first save those characteristic points + GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + GeometryPoint surfaceLevelInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside); + // The characteristic points DitchDikeSide and DitchPolderSide should be removed, but the points itself should be restored, + // else the surfaceline will get a new form. So save those points + GeometryPoint ditchDikeSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); + GeometryPoint ditchPolderSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); + surfaceLine.RemoveSegmentIncluding( + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X, + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X); + // Now restore characteristic points DikeToeAtPolder and SurfaceLevelInside if necessary + surfaceLine.EnsurePointOfType(dikeToeAtPolder.X, dikeToeAtPolder.Z, CharacteristicPointType.DikeToeAtPolder); + surfaceLine.EnsurePointOfType(surfaceLevelInside.X, surfaceLevelInside.Z, CharacteristicPointType.SurfaceLevelInside); + // Now restore points ditchDikeSide and ditchPolderSide + surfaceLine.EnsurePoint(ditchDikeSide.X, ditchDikeSide.Z); + surfaceLine.EnsurePoint(ditchPolderSide.X, ditchPolderSide.Z); + surfaceLine.SortPoints(); + } + } + + private DitchCoordinates GetCoordinatesForOldShape(double xDitchDike, DitchDefinition ditchDefinition) + { + var res = new DitchCoordinates(); + res.XAtDike = xDitchDike; + res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); + res.XBottomAtDike = xDitchDike + ditchDefinition.DistanceToBottomDikeSide; + res.ZBottom = res.ZAtDike - ditchDefinition.DepthBottomDikeSide; + res.XBottomAtPolder = xDitchDike + ditchDefinition.DistanceToBottomPolderSide; + res.XAtPolder = xDitchDike + ditchDefinition.DistanceToEndDitch; + res.ZAtPolder = surfaceLine.Geometry.GetZatX(res.XAtPolder); + return res; + } + + private DitchCoordinates GetCoordinatesForNewShape(double xDitchDike) + { + var res = new DitchCoordinates(); + res.XAtDike = xDitchDike; + res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); + // Depth of the ditch is defined towards PolderLevel + res.ZBottom = Location.PolderLevel - Location.NewDepthDitch; + res.XBottomAtDike = xDitchDike + (res.ZAtDike - res.ZBottom)*Location.NewSlopeAngleDitch; + res.XBottomAtPolder = res.XBottomAtDike + Location.NewWidthDitchBottom; + var line = new Line + { + BeginPoint = new Point2D(res.XBottomAtPolder, res.ZBottom), + EndPoint = new Point2D(res.XBottomAtPolder + offset, + res.ZBottom + offset * Location.NewSlopeAngleDitch) + }; + // Find the intersectionpoint(s) of the new ditch slope with the surface line + var intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); + if (intersectionpoints.Count > 0) + { + res.XAtPolder = intersectionpoints[0].X; + res.ZAtPolder = intersectionpoints[0].Z; + } + else + { + //new slope of ditch does not intersect with surface line (most probably because the bottom is too high) + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(typeof(SurfaceLineAdapter), + "SurfaceLineAdapterDitchSlopeError")); + } + return res; + } + + protected void RestoreDitch(DitchDefinition? ditchDefinition) + { + if (ditchDefinition == null) return; + var dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + double distanceToNewToe = ditchDefinition.Value.OriginalX - dikeToeAtPolder.X; + double xDitchDikeSide; + DitchCoordinates coors; + surfaceLine.SortPoints(); + // First determine all coordinates + if (distanceToNewToe < Location.NewMinDistanceDikeToeStartDitch && distanceToNewToe != ditchDefinition.Value.DistanceFromToe) + { + // Ditch needs to be moved as it is less then the minimum required distance from the new toe + xDitchDikeSide = dikeToeAtPolder.X + + Location.NewMinDistanceDikeToeStartDitch; + if (Location.UseNewDitchDefinition) + { + // Use the new definition instead of the old shape + coors = GetCoordinatesForNewShape(xDitchDikeSide); + + } + else + { + // replace the ditch with the same shape. + coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); + } + } + else + { + // replace the ditch with the same shape and same location. + xDitchDikeSide = dikeToeAtPolder.X + + distanceToNewToe; + coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); + } + // check if the new bottom is beneath the surface line. If not, the ditch must not be replaced at all + if (coors.ZBottom >= surfaceLine.Geometry.GetZatX(coors.XBottomAtDike) || + coors.ZBottom >= surfaceLine.Geometry.GetZatX(coors.XBottomAtPolder)) + { + return; + } + double surfaceLevelInsideX = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X; + if (coors.XAtPolder > surfaceLevelInsideX) + { + throw new SurfaceLineAdapterException(LocalizationManager.GetTranslatedText(this, "SurfaceLineHeightAdapterDitchOutsideSurfaceLine")); + } + // Add the outside points of the new ditch + surfaceLine.EnsurePointOfType(coors.XAtDike, coors.ZAtDike, CharacteristicPointType.DitchDikeSide); + surfaceLine.EnsurePointOfType(coors.XAtPolder, coors.ZAtPolder, CharacteristicPointType.DitchPolderSide); + // Delete all existing points in the new ditch + surfaceLine.RemoveSegmentBetween(coors.XAtDike, coors.XAtPolder); + // Add the bottom of the ditch + surfaceLine.EnsurePointOfType(coors.XBottomAtDike, coors.ZBottom, CharacteristicPointType.BottomDitchDikeSide); + surfaceLine.EnsurePointOfType(coors.XBottomAtPolder, coors.ZBottom, CharacteristicPointType.BottomDitchPolderSide); + surfaceLine.SortPoints(); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/PreConsolidationStress.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/PreConsolidationStress.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/PreConsolidationStress.cs (revision 334) @@ -0,0 +1,105 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Pre-consolidation stress used within preproces stability + /// + public class PreConsolidationStress : GeometryPoint + { + /// + /// Initializes a new instance of the class + /// as a XZ point. + /// + public PreConsolidationStress() + { + StressValue = double.NaN; + } + + /// + /// Gets or sets the stress value. + /// + [XmlIgnore] + public double StressValue { get; set; } + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public override string Name { get; set; } + + + /// + /// Gets or sets the X coordinate of publisherEventArgs GeometryPoint + /// + [Translation("XCoordYieldStress")] + public override double X + { + get + { + return base.X; + } + set + { + base.X = value; + } + } + + + /// + /// Gets or sets the Z coordinate of publisherEventArgs GeometryPoint + /// + [Translation("ZCoordYieldStress")] + public override double Z + { + get + { + return base.Z; + } + set + { + base.Z = value; + } + } + + /// + /// Clones this instance. + /// + public override object Clone() + { + var clone = new PreConsolidationStress + { + Name = Name, + StressValue = StressValue, + X = X, + Z = Z + }; + return clone; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectData.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectData.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/DamProjectData.cs (revision 334) @@ -0,0 +1,646 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.General.SchematizationFactor; +using Deltares.DamEngine.Data.General.Sensors; +using Deltares.DamEngine.Data.RWScenarios; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + public class DamProjectData + { + public readonly double MissValStabilitySafetyFactor = -1.0; + private WaterBoard waterBoard; + private DamProjectCalculationSpecification damProjectCalculationSpecification; + private WaterBoardJob waterBoardJob = null; + private DamProjectType damProjectType = DamProjectType.Calamity; + private ProgramType programType = ProgramType.MStab; + private List jobs = new List(); + private SchematizationFactorData schematizationFactorData = new SchematizationFactorData(); + private List calculations = null; // will be created and initialized in property + private List designCalculations = null; + private List schematizationFactors = null; + private SensorData sensorData; + + /// + /// Constructor + /// + public DamProjectData() + { + this.waterBoard = new WaterBoard(); + this.waterBoardJob = null; + this.damProjectCalculationSpecification = new DamProjectCalculationSpecification(); + } + + public static string ProjectWorkingPath + { + get; + set; + } + + public static string MStabExePath + { + get; + set; + } + + public static string SlopeWExePath + { + get; + set; + } + + /// + /// Toplevel object to hold waterboard data + /// + public virtual WaterBoard WaterBoard + { + get { return this.waterBoard; } + set + { + this.waterBoard = value; + if (this.waterBoardJob != null && this.waterBoardJob.Subject != value) + { + this.waterBoardJob = null; + } + } + } + /// + /// calculation specification for the project + /// + /// Composite relationship + [Validate] + public DamProjectCalculationSpecification DamProjectCalculationSpecification + { + get { return damProjectCalculationSpecification; } + set { damProjectCalculationSpecification = value; } + + } + + public virtual DamJob WaterBoardJob + { + get + { + if (waterBoardJob == null) + { + waterBoardJob = new WaterBoardJob(this.waterBoard); + waterBoardJob.Subject = this.waterBoard; + + foreach (Dike dike in waterBoard.Dikes) + { + CompositeJob dikeJob = new DikeJob(dike); + waterBoardJob.Jobs.Add(dikeJob); + + foreach (Location location in dike.Locations) + { + LocationJob locationJob = new LocationJob(location); + dikeJob.Jobs.Add(locationJob); + } + } + } + + return waterBoardJob; + } + set { waterBoardJob = value as WaterBoardJob; } + } + + public virtual DamProjectType DamProjectType + { + get { return damProjectType; } + set + { + bool modified = damProjectType != value; + + damProjectType = value; + Location.DamProjectType = value; + DamFailureMechanismeCalculationSpecification.DamProjectType = value; + + if (modified) + { + LocationJob.DamProjectType = damProjectType; + } + } + } + + [XmlIgnore] + public List Calculations + { + get + { + if (calculations == null) + { + calculations = new List(); + this.UpdateCalculations(); + } + + return calculations; + } + } + + /// + /// Clear all results + /// + public void ClearResults() + { + foreach (LocationJob locationJob in this.LocationJobs) + { + locationJob.LocationResult = new LocationResult(); + foreach (Scenario scenario in locationJob.Location.Scenarios) + { + scenario.CalculationResults.Clear(); + } + } + } + + public void UpdateCalculations() + { + if (calculations != null) + { + calculations.Clear(); + + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.HasRWScenarioResults) + { + foreach (RWScenarioResult locationResult in locationJob.RWScenarioResults) + { + calculations.AddRange(locationResult.RWScenarioProfileResults); + } + } + } + } + } + + private List CreateScenarioListForDeletion() + { + List scenarios = new List(); ; + + List locations = this.LocationJobs.Select(x => x.Location).ToList(); + foreach (Location location in locations) + { + if (location.Scenarios != null) + { + scenarios.AddRange(location.Scenarios); + } + } + + return scenarios; + } + + private List CreateScenarioListForCalculation() + { + List scenarios = new List(); ; + + List locations = this.SelectedLocationJobs.Select(x => x.Location).ToList(); + foreach (Location location in locations) + { + if (location.Scenarios != null) + { + scenarios.AddRange(location.Scenarios); + } + } + + return scenarios; + } + + /// + /// Updates the design calculations. + /// + public void UpdateDesignCalculations() + { + if (designCalculations == null) + { + designCalculations = new List(); + } + else + { + designCalculations.Clear(); + } + var scenarios = CreateScenarioListForCalculation(); + foreach (Scenario scenario in scenarios) + { + if (scenario.CalculationResults != null && scenario.CalculationResults.Count > 0) + { + designCalculations.AddRange(scenario.CalculationResults); + } + } + } + + [XmlIgnore] + public List DesignCalculations + { + get + { + if (designCalculations == null) + { + this.UpdateDesignCalculations(); + } + + return designCalculations; + } + } + + [XmlIgnore] + public List SchematizationFactors + { + get + { + if (schematizationFactors == null) + { + schematizationFactors = new List(); + this.UpdateSchematizationFactors(); + } + + return schematizationFactors; + } + } + + public void UpdateSchematizationFactors() + { + if (schematizationFactors != null) + { + schematizationFactors.Clear(); + + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.HasSchematizationFactorResults) + { + foreach ( + var rwSchematizationFactorResult in + locationJob.LocationResult.SchematizationFactorsResult.SchematizationFactorResults) + { + schematizationFactors.Add(rwSchematizationFactorResult); + } + } + } + } + } + + public SchematizationFactorData SchematizationFactorData + { + get { return schematizationFactorData; } + set + { + schematizationFactorData = value; + } + } + + public CalculationResult Validate() + { + try + { + //Todo validation has to extended, handling the actual messages instead of just CalculationResult too. + foreach (Dike dike in this.WaterBoard.Dikes) + { + dike.Validate(); + } + return CalculationResult.Succeeded; + } + catch + { + return CalculationResult.InvalidInputData; + } + } + + public LocationJob GetLocationJob(Location location) + { + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.Location == location) + { + return locationJob; + } + } + + return null; + } + + [XmlIgnore] + public List LocationJobs + { + get + { + if (jobs.Count == 0) + { + CompositeJob waterboardJob = this.WaterBoardJob as CompositeJob; + foreach (CompositeJob dijkJob in waterboardJob.Jobs) + { + foreach (LocationJob locationJob in dijkJob.Jobs) + { + jobs.Add(locationJob); + } + } + } + + return jobs; + } + } + + public LocationJob GetFirstLocationJobWithDesignResults() + { + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.HasScenarioResults) + { + return locationJob; + } + } + return null; + } + + public LocationJob GetFirstLocationJobWithAssesmentResults() + { + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.HasRWScenarioResults) + { + return locationJob; + } + } + return null; + } + + public LocationJob GetFirstLocationJobWithCalamityResults() + { + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.HasLocationResults) + { + return locationJob; + } + } + return null; + } + + [XmlIgnore] + [Validate] + public List SelectedLocationJobs + { + get + { + List selectedLocationJobs = new List(); + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.Run.HasValue && locationJob.Run.Value) + { + selectedLocationJobs.Add(locationJob); + } + } + + return selectedLocationJobs; + } + } + + [Validate] + public ValidationResult[] ValidateEnoughLocationJobs() + { + if (this.SelectedLocationJobs.Count == 0) + { + return new ValidationResult[] + { + new ValidationResult(ValidationResultType.Error, + LocalizationManager.GetTranslatedText(this, "NoLocationsSelected"), + this) + }; + } + else + { + return new ValidationResult[0]; + } + } + + [XmlIgnore] + public List Locations + { + get { return this.WaterBoard.Locations; } + } + + public ProgramType ProgramType + { + // For now, only MStab (= default value) allowed so ReadOnly. Add setter when needed. + get { return programType; } + } + + /// + /// Gets or sets the sensor data. + /// + /// + /// The sensor data. + /// + public SensorData SensorData + { + get { return sensorData; } + set { sensorData = value; } + } + + public EvaluationJob GetEvaluationJob() + { + EvaluationJob evaluationJob = new EvaluationJob(); + + evaluationJob.DikeName = this.WaterBoard.Dikes[0].Name; + //evaluationJob.MapForSoilGeometries2D = this.WaterBoard.Dikes[0].MapForSoilGeometries2D; + //evaluationJob.SoildatabaseName = this.WaterBoard.Dikes[0].SoilDatabaseName; + + foreach (LocationJob locationJob in this.LocationJobs) + { + if (locationJob.Run != null && locationJob.Run.Value) + { + foreach (Dike dike in this.WaterBoard.Dikes) + { + if (dike.Locations.Contains(locationJob.Location)) + { + dike.UpdateLocation(locationJob.Location); + break; + } + } + + evaluationJob.Locations.Add(locationJob.Location); + } + } + + return evaluationJob; + } + + /// + /// Ensures the proper zone safety factors are available for all locations. + /// + public void EnsureProperZoneSafetyFactors() + { + foreach (var location in Locations) + { + location.EnsureProperZoneSafetyFactors(); + } + } + + public void DeleteResults() + { + if (waterBoardJob != null && waterBoardJob.Jobs != null) + { + waterBoardJob.Jobs.Clear(); + } + waterBoardJob = null; + if (jobs != null) + { + jobs.Clear(); + } + if (calculations != null) + { + calculations.Clear(); + } + if (schematizationFactors != null) + { + schematizationFactors.Clear(); + } + + // Delete calculationresults in scenarios + var scenarios = CreateScenarioListForDeletion(); + foreach (Scenario scenario in scenarios) + { + scenario.ClearResults(); + scenario.ClearErrors(); + } + + if (designCalculations != null) + { + designCalculations.Clear(); + } + } + + private EvaluationJob GetCalculatedEvaluationJob() + { + EvaluationJob evaluationJob = new EvaluationJob(); + + evaluationJob.DikeName = this.WaterBoard.Dikes[0].Name; + + foreach (LocationJob locationJob in this.LocationJobs) + { + if ((locationJob.Result != JobResult.NoRun || (locationJob.HasRWScenarioResults)) && locationJob.Run != null && locationJob.Run.Value) + { + foreach (Dike dike in this.WaterBoard.Dikes) + { + if (dike.Locations.Contains(locationJob.Location)) + { + dike.UpdateLocation(locationJob.Location); + break; + } + } + + evaluationJob.Locations.Add(locationJob.Location); + } + } + + return evaluationJob; + } + + public bool HasResults() + { + bool hasResults = waterBoard.Dikes.Count > 0 && waterBoardJob != null && waterBoardJob.Jobs.Count > 0; + if (hasResults) + { + EvaluationJob evaluationJob = GetCalculatedEvaluationJob(); + hasResults = evaluationJob.Locations != null && evaluationJob.Locations.Count > 0; + } + return hasResults; + } + + /// + /// Check if design with geometry adaption is allowed + /// + /// + private bool IsDesignWithGeometryAdaptionAllowed() + { + bool isAdoption = this.DamProjectType == DamProjectType.Design && DamProjectCalculationSpecification.SelectedAnalysisType != AnalysisType.NoAdaption; + bool isStabilityOutside = this.DamProjectCalculationSpecification.DamCalculationSpecifications.Any(specification => specification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside); + return (!isAdoption || !isStabilityOutside); + } + + /// + /// Validates the geometry adaption setting. + /// + /// + [Validate] + public ValidationResult[] ValidateGeometryAdaptionSetting() + { + if (!IsDesignWithGeometryAdaptionAllowed()) + { + return new[]{ new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText(this, "DesignAndAdaptionNotAllowedForStabilityOutside"), + this)}; + } + else + { + return new ValidationResult[0]; + } + + } + + public override string ToString() + { + return this.WaterBoard != null ? this.WaterBoard.Name : ""; + } + + + public void FillOverallSensorData() + { + if (sensorData != null) + { + sensorData.Sensors.Clear(); + sensorData.SensorGroups.Clear(); + sensorData.SensorLocations.Clear(); + } + else + { + sensorData = new SensorData(); + } + foreach (var location in Locations) + { + var sd = location.SensorData; + + foreach (var sensor in sd.Sensors ) + { + if (sensorData.GetSensorById(sensor.ID) == null) + { + sensorData.Sensors.Add(sensor); + } + } + if (sensorData.GetGroupById(sd.Group.ID) == null && sd.Group.ID >= 0) + { + sd.Group.PickSensors = sensorData.Sensors; + sensorData.SensorGroups.Add(sd.Group); + } + if (sensorData.GetSensorLocationByLocationName(sd.LocationName) == null) + { + sensorData.SensorLocations.Add(sd); + } + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/PLLinesCreator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/PLLinesCreator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/PLLinesCreator.cs (revision 334) @@ -0,0 +1,2187 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using Deltares.DamEngine.Calculators.Uplift; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Gauges; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Calculators.PlLinesCreator +{ + [Serializable] + public class PLLinesCreatorException : Exception + { + public PLLinesCreatorException() + { + } + + public PLLinesCreatorException(string message) + : base(message) + { + } + + public PLLinesCreatorException(string message, Exception inner) + : base(message, inner) + { + } + + protected PLLinesCreatorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + + /// + /// + /// + public class PLLinesCreator + { + private const double cUpliftFactorEquilibrium = 1.0; + private const double cOffsetPhreaticLineBelowSurface = 0.01; + private ModelParametersForPLLines modelParametersForPLLines = new ModelParametersForPLLines(); + public bool IsUseOvenDryUnitWeight { get; set; } + public SoilGeometryType SoilGeometryType { get; set; } + public SoilProfile1D SoilProfile { get; set; } + public string SoilGeometry2DName { get; set; } + public Soil DikeEmbankmentMaterial { get; set; } + //public SoilbaseDB SoilBaseDB { get; set; } + public SoilList SoilList { get; set; } + public double? HeadInPLLine2 { get; set; } + private double? headInPLLine3 { get; set; } + private double? headInPLLine4 { get; set; } + public double XSoilGeometry2DOrigin { get; set; } + private bool isAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; + private bool isHydraulicShortcut = false; + private double waterLevelPolder; + private double waterLevelRiverHigh; + private double? waterLevelRiverLow; + private bool isUseLowWaterLevel; + private SurfaceLine2 surfaceLine; + public bool IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled { get { return isAdjustPL3AndPL4SoNoUpliftWillOccurEnabled; } set { isAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = value; } } + public double WaterLevelRiverHigh { get { return waterLevelRiverHigh; } set { waterLevelRiverHigh = value; } } + public double? WaterLevelRiverLow { get { return waterLevelRiverLow; } set { waterLevelRiverLow = value; } } + public bool IsUseLowWaterLevel { get { return isUseLowWaterLevel; } set { isUseLowWaterLevel = value; } } + public double WaterLevelPolder { get { return waterLevelPolder; } set { waterLevelPolder = value; } } + public double? HeadInPLLine3 { get { return headInPLLine3; } set { headInPLLine3 = value; } } + public double? HeadInPLLine4 { get { return headInPLLine4; } set { headInPLLine4 = value; } } + + /// Aggregation relationship + public SurfaceLine2 SurfaceLine + { + get { return surfaceLine; } + set { surfaceLine = value; } + } + public IList GaugePLLines { get; set; } + public IList Gauges { get; set; } + public double GaugeMissVal { get; set; } + public double PlLineOffsetBelowDikeTopAtRiver { get; set; } + public double PlLineOffsetBelowDikeTopAtPolder { get; set; } + public virtual double PlLineOffsetBelowShoulderBaseInside { get; set; } + public virtual double PlLineOffsetBelowDikeToeAtPolder { get; set; } + public double? PlLineOffsetBelowDikeCrestMiddle { get; set; } + public double? PlLineOffsetFactorBelowShoulderCrest { get; set; } + public bool? UsePlLineOffsetBelowDikeCrestMiddle { get; set; } + public bool? UsePlLineOffsetFactorBelowShoulderCrest { get; set; } + public PhreaticAdaptionType? NWOPhreaticAdaption { get; set; } + + private double WaterLevelToUse() + { + if (isUseLowWaterLevel) + { + return this.waterLevelRiverLow.Value; + + } + else + { + return this.WaterLevelRiverHigh; + } + } + private double HeadPL3TakingInAccountHydraulicShortcut + { + get + { + double waterLevel = WaterLevelToUse(); + // If no value known for headPl3 then use waterlevel for headPL3 + if (HeadInPLLine3 == null) + { + return waterLevel; + } + // If hydraulic shortcut and no inbetween aquifer layer then taka into account hydraulic shortcut + // If hydraulic shortcut then use waterlevel for headPL3 + if (IsHydraulicShortcut) + { + if (SoilGeometryType == SoilGeometryType.SoilGeometry1D) + { + if (SoilProfile.InBetweenAquiferLayer == null) + { + return waterLevel; + } + } + return HeadInPLLine3.Value; + } + else + { + return HeadInPLLine3.Value; + } + } + } + + private double GetHeadPL4TakingInAccountHydraulicShortcut(DamType damType) + { + // If hydraulic shortcut or no value known for headPl4 then use waterlevel for headPL4 + double waterLevel = WaterLevelToUse(); + if (IsHydraulicShortcut) + { + // If hydraulic shortcut then use waterlevel for headPL4 + return waterLevel; + } + else + { + if (HeadInPLLine4 == null) + { + // If no hydraulic shortcut and no value known for headPl4 then use polderlevel for headPL4 + if (damType == DamType.Primary) + { + return waterLevel; + } + else + { + return waterLevelPolder; + } + } + else + { + // If no hydraulic shortcut and value is specified for headPl4 then use this value for headPL4 + return HeadInPLLine4.Value; + } + } + } + + private PLLine currentPL1Line = null; // is needed when calculating uplift reduction for PL3 and Pl4 + + // Output + private double pl3MinUplift; + private double pl3HeadAdjusted; + private double pl3LocationXMinUplift; + public double Pl3MinUplift { get { return pl3MinUplift; } } + public double Pl3HeadAdjusted { get { return pl3HeadAdjusted; } } + public double Pl3LocationXMinUplift { get { return pl3LocationXMinUplift; } } + private double pl4MinUplift; + private double pl4HeadAdjusted; + private double pl4LocationXMinUplift; + + public double Pl4MinUplift { get { return pl4MinUplift; } } + public double Pl4HeadAdjusted { get { return pl4HeadAdjusted; } } + public double Pl4LocationXMinUplift { get { return pl4LocationXMinUplift; } } + + /// + /// Constructor + /// + public PLLinesCreator() + { + SoilGeometryType = SoilGeometryType.SoilGeometry1D; + PlLineOffsetBelowDikeTopAtRiver = 0.5; // Default value + PlLineOffsetBelowDikeTopAtPolder = 1.5; // Default value + PlLineOffsetBelowShoulderBaseInside = 0.1; // Default value + PlLineOffsetBelowDikeToeAtPolder = 0.1; // Default value + IsUseOvenDryUnitWeight = false; + } + + /// + /// + /// + /// + /// + private SoilProfile1D GetSoilProfileBelowPoint(double xCoordinate) + { + switch (SoilGeometryType) + { + case SoilGeometryType.SoilGeometry1D: + var soilProfile = new SoilProfile1D(); + soilProfile.Assign(this.SoilProfile); + return soilProfile; +// case SoilGeometryType.SoilGeometry2D: +// var geometry2DTo1DConverter = new Geometry2DTo1DConverter(this.SoilGeometry2DName, this.SurfaceLine, this.DikeEmbankmentMaterial, this.SoilBaseDB, this.SoilList, -this.XSoilGeometry2DOrigin); +// return geometry2DTo1DConverter.Convert(xCoordinate); ##Bka + default: + return null; + } + } + + public ModelParametersForPLLines ModelParametersForPLLines + { + get { return modelParametersForPLLines; } + set { modelParametersForPLLines = value; } + } + + public bool IsHydraulicShortcut + { + get { return isHydraulicShortcut; } + set { isHydraulicShortcut = value; } + } + + /// + /// Check if enough soil geometry data available + /// + private void ThrowIfInsufficientSoilGeometryData() + { + bool hasNoGeometry1DData = (SoilGeometryType == SoilGeometryType.SoilGeometry1D) && SoilProfile == null; + bool hasNoGeometry2DData = (SoilGeometryType == SoilGeometryType.SoilGeometry2D) && (SoilGeometry2DName == null || DikeEmbankmentMaterial == null); + if (hasNoGeometry1DData && hasNoGeometry2DData) + { + throw new PLLinesCreatorException("PLLinesCreator contains not enough soil geometry information (SoilProfile, SoilGeometry2DName, dikeEmbankmentMaterial or soilBase)"); + } + } + + /// + /// Create PL2 (is pl line for penetration) + /// + /// + private PLLine CreatePLLine2ByExpertKnowledge(double penetrationLength, double? headInPLLine2) + { + PLLine plLine = null; + + if (penetrationLength < 0.0) + { + throw new PLLinesCreatorException("Negative penetration length."); + } + if ((penetrationLength.AlmostEquals(0.0)) || (headInPLLine2 == null)) + { + // No penetration, or no Head Pl2 defined, so empty pl-line will be returned + plLine = new PLLine(); + } + else + { + ThrowIfInsufficientSoilGeometryData(); + ThrowIfNoSurfaceLine(); + ThrowIfSurfaceLineContainsNoPoints(); + + switch (SoilGeometryType) + { + case SoilGeometryType.SoilGeometry1D: + plLine = CreatePlLine2ByExpertKnowledgeFor1DGeometry(penetrationLength, headInPLLine2); + break; + case SoilGeometryType.SoilGeometry2D: + plLine = CreatePlLine2ByExpertKnowledgeFor2DGeometry(penetrationLength, headInPLLine2); + break; + } + } + + return plLine; + } + + /// + /// Create PL2 (is pl line for penetration) for 2d-geometry + /// + /// Length of the penetration. + /// The head in pl line2. + /// + /// Head PL2 not defined + private PLLine CreatePlLine2ByExpertKnowledgeFor2DGeometry(double penetrationLength, double? headInPLLine2) + { + if (headInPLLine2 == null) + { + throw new PLLinesCreatorException("Head PL2 not defined"); + } + PLLine plLine = new PLLine(); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.First().X, headInPLLine2.Value)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, headInPLLine2.Value)); + return plLine; + } + + /// + /// Create PL2 (is pl line for penetration) for 1d-geometry + /// + /// + /// + /// + private PLLine CreatePlLine2ByExpertKnowledgeFor1DGeometry(double penetrationLength, double? headInPLLine2) + { + if (headInPLLine2 == null) + { + throw new PLLinesCreatorException("Head PL2 not defined"); + } + PLLine plLine = new PLLine(); + if (SoilProfile != null) + { + IList aquiferLayers = this.SoilProfile.GetAquiferLayers(); + if (aquiferLayers.Count == 0) + { + throw new PLLinesCreatorException("Soil profile contains no aquifer layers."); + } + + if (penetrationLength > 0 && aquiferLayers.Count > 0) + { + IList infiltrationLayers = (from SoilLayer1D layer in this.SoilProfile.Layers + where (this.SoilProfile.InBetweenAquiferLayer == null || layer.TopLevel < this.SoilProfile.InBetweenAquiferLayer.TopLevel) && + layer.TopLevel > this.SoilProfile.BottomAquiferLayer.TopLevel + select layer).ToList(); + + if (infiltrationLayers.Count > 0) + { + double separationLevel = this.SoilProfile.BottomAquiferLayer.TopLevel + penetrationLength; + + if (separationLevel <= infiltrationLayers.First().TopLevel) + { + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.First().X, headInPLLine2.Value)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, headInPLLine2.Value)); + + SoilLayer1D separationLayer = (from SoilLayer1D layer in infiltrationLayers + where layer.TopLevel >= separationLevel + select layer).Last(); + + if (separationLevel < separationLayer.TopLevel) + { + + // Split layer at separation level + var extraLayer = new SoilLayer1D(); + extraLayer.Assign(separationLayer); + //extraLayer.Id = this.SoilProfile.GetNewUniqueLayerId(); ##Bka + extraLayer.TopLevel = separationLevel; + this.SoilProfile.Layers.Insert(this.SoilProfile.Layers.IndexOf(separationLayer) + 1, extraLayer); + } + } + } + this.SoilProfile.DetermineInfiltrationLayer(penetrationLength); + } + } + return plLine; + } + + /// + /// Check if surfaceline contains points + /// + private void ThrowIfSurfaceLineContainsNoPoints() + { + if (this.surfaceLine.Geometry.Count < 1) + { + throw new PLLinesCreatorException("Surface line contains no points."); + } + } + + /// + /// Check if surfaceline assigned + /// + private void ThrowIfNoSurfaceLine() + { + if (this.surfaceLine == null) + { + throw new PLLinesCreatorException("PLLinesCreator contains no surface line."); + } + } + + /// + /// Create PL3 (is phreatic level) + /// + /// + private PLLine CreatePLLine3ByExpertKnowledge(double headValue, double dampingFactor, double slopeGradient) + { + return CreatePLLine3Or4ByExpertKnowledge(headValue, dampingFactor, PLLineType.PL3, slopeGradient); + } + + /// + /// Create PL4 (is phreatic level) + /// + /// + private PLLine CreatePLLine4ByExpertKnowledge(double headValue, double dampingFactor, double slopeGradient) + { + return CreatePLLine3Or4ByExpertKnowledge(headValue, dampingFactor, PLLineType.PL4, slopeGradient); + } + + private PLLine CreatePLLine3Or4ByExpertKnowledge(double headValue, double dampingFactor, PLLineType plLineType, double slopeGradient) + { + // Offset to solve issue MWDAM-557 + const double offset = 0.01; + + PLLine plLine = new PLLine(); + + ThrowIfInsufficientSoilGeometryData(); + ThrowIfNoSurfaceLine(); + ThrowIfSurfaceLineContainsNoPoints(); + // Soilprofile is used to check if there is really an aquifer below toe of dike at river. + // The assumption is made that if there is an aquifer at the riverside and at the the polderside, + // that there is a connection between these aquifers. + // In the uplift calculation there will also be a check on the existence of an aquifer. + SoilProfile1D actualSoilProfile = GetSoilProfileBelowPoint(this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X + offset); + if (this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver) == null) + { + throw new PLLinesCreatorException("Characteristic point \"dike toe at river\" is not defined."); + } + if (dampingFactor < 0.0) + { + throw new PLLinesCreatorException("Damping factor < 0.0"); + } + + SoilLayer1D relevantAquiferLayer = GetRelevantAquiferLayer(plLineType, actualSoilProfile); + + if (relevantAquiferLayer != null) + { + double referenceLevel = (this.HeadInPLLine2 != null) ? this.HeadInPLLine2.Value : this.waterLevelPolder; + double headAtPolderDikeToe = headValue - Math.Max(0, dampingFactor * (headValue - referenceLevel)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.First().X, headValue)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X, headValue)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X, headAtPolderDikeToe)); + + // Now continue PLline to the end with a slope of slopegradient + AddTailOfPl3OrPl4WithSlopeGradient(slopeGradient, plLine); + + if (isAdjustPL3AndPL4SoNoUpliftWillOccurEnabled) + { + AdjustLineAccordingToTRWUplift(plLine, plLineType, slopeGradient); + } + + EnsureDescendingLine(plLine); + + RemoveRedundantPoints(plLine); + + + } + + return plLine; + } + + /// + /// Continue PLline to the end with a slope of slopegradient + /// If PLLine is lower then polderlevel, continue with polderlevel + /// + /// The slope gradient. + /// The pl line. + private void AddTailOfPl3OrPl4WithSlopeGradient(double slopeGradient, PLLine plLine) + { + if (plLine.Points.Last().Z <= this.WaterLevelPolder) + { + // the PL line is already at WaterLevelPolder, so countinue it horizontally + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, this.WaterLevelPolder)); + } + else + { + double lengthFromLastPlPointToEnd = Math.Abs(this.surfaceLine.Geometry.Points.Last().X - plLine.Points.Last().X); + double headAtLastPlPoint = plLine.Points.Last().Z; + double headAtEnd = plLine.Points.Last().Z - slopeGradient * lengthFromLastPlPointToEnd; + + Line waterLevelPolderLine = + new Line(new Point2D(this.surfaceLine.Geometry.Points.First().X, this.WaterLevelPolder), + new Point2D(this.surfaceLine.Geometry.Points.Last().X, WaterLevelPolder)); + Line slopeLine = + new Line( + new Point2D(this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X, headAtLastPlPoint), + new Point2D(this.surfaceLine.Geometry.Points.Last().X, headAtEnd)); + var intersectionPoint = new Point2D(); + + if (waterLevelPolderLine.IntersectsZ(slopeLine, out intersectionPoint)) + { + plLine.Points.Add(new PLLinePoint(intersectionPoint.X, this.WaterLevelPolder)); + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, this.WaterLevelPolder)); + } + else + { + plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, headAtEnd)); + } + + } + } + + private static SoilLayer1D GetRelevantAquiferLayer(PLLineType type, SoilProfile1D actualSoilProfile) + { + IList aquiferLayers = actualSoilProfile.GetAquiferLayers(); + // Note : if no aquifers at all, always throw a message + if (aquiferLayers.Count == 0) + { + string message = "Soil profile (" + actualSoilProfile.Name + ") contains no aquifer layers at all."; + throw new PLLinesCreatorException(message); + } + SoilLayer1D relevantAquiferLayer = null; + switch (type) + { + case PLLineType.PL3: + relevantAquiferLayer = actualSoilProfile.BottomAquiferLayer; // Pleistocene + break; + case PLLineType.PL4: + relevantAquiferLayer = actualSoilProfile.InBetweenAquiferLayer; // Intermediate sand layer + break; + default: + throw new PLLinesCreatorException(String.Format("Invalid PL line type:{0} for creation of PL Line 3 or 4", type)); + } + + // Note : DAM already handles a missing (null) InBetweenAquiferLayer itself so do not throw for that. + if (relevantAquiferLayer == null && type == PLLineType.PL3) + { + string message = "Soil profile (" + actualSoilProfile.Name + ") contains no relevant aquifer layer."; + throw new PLLinesCreatorException(message); + } + return relevantAquiferLayer; + } + + /// + /// Remove redundant points (i.e. lying on a line between its both neighbours) + /// + /// + /// + private static void RemoveRedundantPoints(PLLine plLine) + { + const double Tolerance = 0.001; + for (int pointIndex = plLine.Points.Count - 2; pointIndex > 0; pointIndex--) + { + PLLinePoint plPointPrev = plLine.Points[pointIndex - 1]; + PLLinePoint plPoint = plLine.Points[pointIndex]; + PLLinePoint plPointNext = plLine.Points[pointIndex + 1]; + if (Math.Abs((plPoint.Z - plPointPrev.Z) / (plPoint.X - plPointPrev.X) - (plPointNext.Z - plPoint.Z) / (plPointNext.X - plPoint.X)) < Tolerance) + { + plLine.Points.Remove(plPoint); + } + } + } + + /// + /// All points should have descending z from dike to polder + /// + /// + private static void EnsureDescendingLine(PLLine plLine) + { + PLLinePoint plPointPrevious = null; + foreach (PLLinePoint plPoint in plLine.Points) + { + if (plPointPrevious != null && plPoint.Z > plPointPrevious.Z) + plPoint.Z = plPointPrevious.Z; + plPointPrevious = plPoint; + } + } + + /// + /// Clear outputvalues for PL3 or PL4 + /// + /// + private void ClearOutputValuesForPl3_4(PLLineType plLineType) + { + switch (plLineType) + { + case PLLineType.PL3: + pl3MinUplift = Double.MaxValue; + pl3HeadAdjusted = Double.MaxValue; + pl3LocationXMinUplift = Double.MaxValue; + break; + case PLLineType.PL4: + pl4MinUplift = Double.MaxValue; + pl4HeadAdjusted = Double.MaxValue; + pl4LocationXMinUplift = Double.MaxValue; + break; + } + } + + /// + /// Determine outputvalues for PL3 or PL4 for minimal upliftfactor + /// + /// Type of the pl line. + /// The x coordinate. + /// The uplift factor. + /// The head value. + private void UpdateOutputValuesForPl3_4(PLLineType plLineType, double xCoordinate, double upliftFactor, double headValue) + { + switch (plLineType) + { + case PLLineType.PL3: + if (upliftFactor < pl3MinUplift) + { + pl3MinUplift = upliftFactor; + pl3HeadAdjusted = headValue; + pl3LocationXMinUplift = xCoordinate; + } + break; + case PLLineType.PL4: + if (upliftFactor < pl4MinUplift) + { + pl4MinUplift = upliftFactor; + pl4HeadAdjusted = headValue; + pl4LocationXMinUplift = xCoordinate; + } + break; + } + + } + + /// + /// Finds the index of point with X coordinate. + /// + /// The pl line. + /// The x coordinate. + /// + private int FindIndexOfPointInPLLineWithXCoordinate(PLLine plLine, double x) + { + for (int pointIndex = plLine.Points.Count - 1; pointIndex > 0; pointIndex--) + { + PLLinePoint plPoint = plLine.Points[pointIndex]; + if (plPoint.X.AlmostEquals(x, GeometryPoint.Precision)) + { + return pointIndex; + } + } + + return -1; + } + + /// + /// Removes the index of all points of pl line after the start index. + /// + /// The pl line. + /// The start index (this point will not be removed). + private void RemoveAllPointsOfPlLineAfterIndex(PLLine plLine, int startIndex) + { + for (int pointIndex = plLine.Points.Count - 1; pointIndex > startIndex; pointIndex--) + { + plLine.Points.RemoveAt(pointIndex); + } + } + + /// + /// Determines whether a x coordinate is in ditch (excluding first and last point of ditch). + /// + /// The x coordinate. + /// + private bool IsXCoordinateInDitch(double xCoordinate) + { + if (this.surfaceLine.HasDitch()) + { + return (xCoordinate > this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X && + xCoordinate < this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X); + } + else + { + // if ditch does not exist the x coordinate is clearly not in the ditch + return false; + } + } + + /// + /// Determines the thickness of aquitard at characteristic point. + /// This is the distance betweeen the surfacelevel and the top of the first aquifer + /// + /// Type of the characteristic point. + /// + private double? DetermineThicknessAquitardAtCharacteristicPoint(CharacteristicPointType characteristicPointType) + { + if (!surfaceLine.HasAnnotation(characteristicPointType)) + { + return null; + } + else + { + var characteristicGeometryPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(characteristicPointType); + SoilProfile1D actualSoilProfile = GetSoilProfileBelowPoint(characteristicGeometryPoint.X); + double bottomLevel = actualSoilProfile.GetTopLevelOfHighestAquifer(); + double topLevel = characteristicGeometryPoint.Z; + return topLevel - bottomLevel; + } + + } + + /// + /// The correction is applied as follows: + /// Check every point from DikeToeAtPolder to SurfaceLevelInside (from left to right) for uplift. + /// If uplift occurs, then correct PL3/PL4 value, so uplift does not occur. + /// All points in PL3 from this point to DikeToeAtRiver should be removed. + /// The PL3 continues from this point on with the specified slopegradient until polderlevel. + /// Make sure PL3 is always descending from left to right. + /// + /// A better implementation (not implemented yet) would be: + /// Correct plline 3 or 4 for uplift according to + /// TRW (Technisch Rapport Waterspanningen bij dijken) par. b1.3.4 "Stijghoogte in het eerste watervoerende pakket" + /// - Adjust PL3/4 for all surface points from end of profile to toe of dike, so no uplift will occur in that surface point + /// - From the point, closest to the dike, (firstAdjustedPLPoint) where this correction has been made the following has to be done + /// * PL3/4 will continue horizontally from firstAdjustedPLPoint over a distance L = 2* d (d is height all layers above the aquifer) + /// * The the PL3/4 will go down in a slope of 1:50 to the PolderLevel + /// PL3/4----- + /// \___________ L = 2 * d + /// \ + /// \__________ + /// + /// + /// + /// + private void AdjustLineAccordingToTRWUplift(PLLine plLine, PLLineType plLineType, double slopeGradient) + { + const double cTolerancePoint = 0.0001; + ClearOutputValuesForPl3_4(plLineType); + + var upliftCalculator = new UpliftCalculator + { + IsUseOvenDryUnitWeight = IsUseOvenDryUnitWeight, + UnitWeightSoilEmbankment = (this.DikeEmbankmentMaterial == null) ? (double?)null : this.DikeEmbankmentMaterial.AbovePhreaticLevel + }; + GeometryPoint startSurfacePoint = this.surfaceLine.GetDikeToeInward(); + + int indexOfFixedPlPoint = FindIndexOfPointInPLLineWithXCoordinate(plLine, this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X); + if (indexOfFixedPlPoint < 0) + { + throw new PLLinesCreatorException("Could not find fixed point for PLLine"); + } + + // Adjust PL3/4 for all surface points from toe of dike to end of profile to, so no uplift will occur in that surface point + IEnumerable relevantSurfacePointsList = from GeometryPoint point in this.surfaceLine.Geometry.Points + where point.X >= startSurfacePoint.X + orderby point.X ascending + select point; + // Adjustment will only be applied if the value to adjust to is smaller than the previous adjusted value (to avoid that the PL3/PL4 will be adjusted to the + // polderside of the ditch i.s.o. the dikeside of the ditch. + // So we remember which was the last adjusted value in lastAdjustedHeadOfPlLine. + double lastAdjustedHeadOfPlLine = Double.MaxValue; + + bool isRemoveAllPlPointsBackToDikeToeAtRiver; + bool isSkipAdjustmentInDitch; + DetermineHowToActDueToDitch(out isSkipAdjustmentInDitch, out isRemoveAllPlPointsBackToDikeToeAtRiver); + + foreach (GeometryPoint surfacePoint in relevantSurfacePointsList) + { + if (IsXCoordinateInDitch(surfacePoint.X) && isSkipAdjustmentInDitch) + { + continue; + } + ConfigureUpliftCalculator(plLineType, upliftCalculator, surfacePoint); + SoilLayer1D relevantSandLayer = GetRelevantAquiferLayer(plLineType, upliftCalculator.SoilProfile); + // When plLineType is PL4 it is possible that no relevant aquifer layer is found, then the adjustment is not necessary + if (relevantSandLayer != null) + { + double aquiferTopLayer = Math.Min(surfacePoint.Z, relevantSandLayer.TopLevel); + upliftCalculator.TopOfLayerToBeEvaluated = aquiferTopLayer; + double headOfPlLine = plLine.ZFromX(surfacePoint.X); + double upliftFactor = upliftCalculator.CalculateUpliftFactor(headOfPlLine); + if (upliftFactor <= cUpliftFactorEquilibrium) + { + // Adjust headOfPLLine so there is equilibrium + bool hasNoCoverLayer = surfacePoint.Z <= aquiferTopLayer; + if (hasNoCoverLayer) + { + headOfPlLine = this.waterLevelPolder; + } + else + { + headOfPlLine = Math.Max(upliftCalculator.CalculateHeadOfPLLine(cUpliftFactorEquilibrium), + this.waterLevelPolder); + } + if (headOfPlLine < lastAdjustedHeadOfPlLine) + { + var plPoint = new PLLinePoint(surfacePoint.X, headOfPlLine); + // Remove all points of PLLine after fixed point + RemoveAllPointsOfPlLineAfterIndex(plLine, indexOfFixedPlPoint); + plLine.Points.Add(plPoint); + if (!isRemoveAllPlPointsBackToDikeToeAtRiver) + { + // To make sure that not all points of the PL-line back to the toe of the dike at riverside are to be removed + indexOfFixedPlPoint = plLine.Points.Count - 1; + } + AddTailOfPl3OrPl4WithSlopeGradient(slopeGradient, plLine); + lastAdjustedHeadOfPlLine = headOfPlLine; + } + } + UpdateOutputValuesForPl3_4(plLineType, surfacePoint.X, upliftFactor, headOfPlLine); + } + } + + // Recheck on Uplift in case points are removed + if (isRemoveAllPlPointsBackToDikeToeAtRiver && this.SurfaceLine.HasDitch()) + { + GeometryPoint startPoint = this.SurfaceLine.GetDikeToeInward(); + GeometryPoint endPoint = this.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); + IEnumerable recheckSurfacePointsList = from GeometryPoint point in this.surfaceLine.Geometry.Points + where point.X >= startPoint.X && point.X <= endPoint.X + orderby point.X ascending + select point; + + foreach (GeometryPoint surfacePoint in recheckSurfacePointsList) + { + ConfigureUpliftCalculator(plLineType, upliftCalculator, surfacePoint); + SoilLayer1D relevantSandLayer = GetRelevantAquiferLayer(plLineType, upliftCalculator.SoilProfile); + // When plLineType is PL4 it is possible that no relevant aquifer layer is found, then the adjustment is not necessary + if (relevantSandLayer != null) + { + double aquiferTopLayer = Math.Min(surfacePoint.Z, relevantSandLayer.TopLevel); + upliftCalculator.TopOfLayerToBeEvaluated = aquiferTopLayer; + double headOfPlLine = plLine.ZFromX(surfacePoint.X); + double upliftFactor = upliftCalculator.CalculateUpliftFactor(headOfPlLine); + if (upliftFactor <= cUpliftFactorEquilibrium) + { + // Adjust headOfPLLine so there is equilibrium + headOfPlLine = Math.Max(upliftCalculator.CalculateHeadOfPLLine(cUpliftFactorEquilibrium), this.waterLevelPolder); + double currentHead = plLine.ZFromX(surfacePoint.X); + if (headOfPlLine < currentHead) + { + PLLinePoint plPoint = plLine.EnsurePointAtX(surfacePoint.X, cTolerancePoint); + plPoint.Z = headOfPlLine; + } + } + UpdateOutputValuesForPl3_4(plLineType, surfacePoint.X, upliftFactor, headOfPlLine); + } + } + } + } + + /// + /// Configures the uplift calculator. + /// + /// Type of the pl line. + /// The uplift calculator. + /// The surface point. + private void ConfigureUpliftCalculator(PLLineType plLineType, UpliftCalculator upliftCalculator, GeometryPoint surfacePoint) + { + // Offset to solve issue MWDAM-764 + const double offset = 0.01; + upliftCalculator.SurfaceLevel = surfacePoint.Z; + if (currentPL1Line != null) + { + upliftCalculator.PhreaticLevel = currentPL1Line.ZFromX(surfacePoint.X); + // set phreatic level to calculate upliftfactor + } + else + { + upliftCalculator.PhreaticLevel = this.WaterLevelPolder; + // if not PL1 created then assume phreatic level is same as waterlevel polder + } + SoilProfile1D actualSoilProfile = GetSoilProfileBelowPoint(surfacePoint.X + offset); + // At the end of a geometry, there are no layers to be found beyond that end. In that case + // get the layers just before the end of the geometry. + if (actualSoilProfile.LayerCount == 0) + { + actualSoilProfile = GetSoilProfileBelowPoint(surfacePoint.X - offset); + } + AdaptSoilProfileForSurfaceLevelAccuracy(actualSoilProfile, upliftCalculator.SurfaceLevel); + upliftCalculator.SoilProfile = actualSoilProfile; + } + + /// + /// Determines how to act due to ditch. + /// + /// if set to true [is skip adjustment in ditch]. + /// if set to true [is remove all pl points back to dike toe at river]. + private void DetermineHowToActDueToDitch(out bool isSkipAdjustmentInDitch, out bool isRemoveAllPlPointsBackToDikeToeAtRiver) + { + if (this.surfaceLine.HasDitch()) + { + double thicknessAquitardAtTopDitch = + DetermineThicknessAquitardAtCharacteristicPoint(CharacteristicPointType.DitchPolderSide).Value; + double thicknessAquitardAtBottomDitch = + DetermineThicknessAquitardAtCharacteristicPoint(CharacteristicPointType.BottomDitchPolderSide).Value; + double widthDitchAtTop = this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X - + this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X; + double widthDitchAtTBottom = + this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide).X - + this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide).X; + if ((thicknessAquitardAtTopDitch > widthDitchAtTop) && + (thicknessAquitardAtBottomDitch > widthDitchAtTBottom)) + { + isRemoveAllPlPointsBackToDikeToeAtRiver = false; + isSkipAdjustmentInDitch = true; + } + else + { + isRemoveAllPlPointsBackToDikeToeAtRiver = true; + isSkipAdjustmentInDitch = false; + } + } + else + { + isRemoveAllPlPointsBackToDikeToeAtRiver = false; + isSkipAdjustmentInDitch = false; + } + } + + /// + /// Due to accuracy surfacelevel could be slightly below toplevel of toplevel soilprofile + /// Adjust toplevel of soilprofile to avoid this + /// + /// + /// + private static void AdaptSoilProfileForSurfaceLevelAccuracy(SoilProfile1D actualSoilProfile, double surfaceLevel) + { + if (surfaceLevel > actualSoilProfile.TopLevel) + { + actualSoilProfile.Layers[0].TopLevel = surfaceLevel; + } + } + + /// + /// + /// + /// + /// + void CopyPointsInPLLine(ref PLLine plLine, GeometryPointString genericLine) + { + plLine.Points.Clear(); + foreach (GeometryPoint point in genericLine.Points) + { + plLine.Points.Add(new PLLinePoint(point.X, point.Z)); + } + } + + /// + /// + /// + /// + /// +// private PLLines CreateAllPLLinesWithExpertKnowledge(Location location) +// { +// PLLines plLines = new PLLines(); +// foreach (PLLineType plLineType in Enum.GetValues(typeof(PLLineType))) +// { +// bool isPL1LineDefinedForLocation = (location != null) && (location.LocalXZPL1Line != null) && (location.LocalXZPL1Line.Points.Count > 1); +// if ((plLineType == PLLineType.PL1) && isPL1LineDefinedForLocation) +// { +// PLLine plLine = plLines.Lines[plLineType]; +// CopyPointsInPLLine(ref plLine, location.LocalXZPL1Line); +// } +// else +// { +// plLines.Lines[plLineType] = CreatePLLineByExpertKnowledge(plLineType, location.DamType, location.SlopeDampingPiezometricHeightPolderSide); +// } +// +// // currentPL1Line is needed when calculating uplift reduction for PL3 and Pl4 +// if (plLineType == PLLineType.PL1) +// { +// // var plLine = plLines.Lines[plLineType]; +// // AdaptPL1ForNonWaterRetainingObject(ref plLine); +// // plLines.Lines[plLineType] = plLine; +// currentPL1Line = plLines.Lines[plLineType]; +// } +// } +// return plLines; +// } + +// private IEnumerable FindAllPlLinePointsAtNWOLocation(PLLine pl1Line) +// { +// IEnumerable results = pl1Line.GetPointSegmentBetween(this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1).X - cOffsetPhreaticLineBelowSurface, +// this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4).X + cOffsetPhreaticLineBelowSurface); +// +// return results; +// } + +// private void AdaptPL1ForNonWaterRetainingObject(ref PLLine pl1Line) +// { +// // check if nwo points are available as CharacteristicPoints +// var nwo1 = this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1); +// var nwo2 = this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2); +// var nwo3 = this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint3); +// var nwo4 = this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4); +// if ((nwo1 != null) && (nwo2 != null) && (nwo3 != null) && (nwo4 != null)) +// { +// +// // Find all points in the Pl line that (might) coincide with the NWO +// IEnumerable plPointsToBeMoved = FindAllPlLinePointsAtNWOLocation(pl1Line); +// +// PLLinePoint nwo1Pl = null; +// PLLinePoint nwo2Pl = null; +// PLLinePoint nwo3Pl = null; +// PLLinePoint nwo4Pl = null; +// +// // For NWO point, determine whether a pl point has to be added +// if (pl1Line.PositionXzOfPointRelatedToPLLine(nwo1) != PLLinePointPositionXzType.AbovePLLine) +// { +// nwo1Pl = new PLLinePoint(nwo1.X, nwo1.Z - cOffsetPhreaticLineBelowSurface); +// } +// if (pl1Line.PositionXzOfPointRelatedToPLLine(nwo2) != PLLinePointPositionXzType.AbovePLLine) +// { +// nwo2Pl = new PLLinePoint(nwo2.X, nwo2.Z - cOffsetPhreaticLineBelowSurface); +// } +// if (pl1Line.PositionXzOfPointRelatedToPLLine(nwo3) != PLLinePointPositionXzType.AbovePLLine) +// { +// nwo3Pl = new PLLinePoint(nwo3.X, nwo3.Z - cOffsetPhreaticLineBelowSurface); +// } +// if (pl1Line.PositionXzOfPointRelatedToPLLine(nwo4) != PLLinePointPositionXzType.AbovePLLine) +// { +// nwo4Pl = new PLLinePoint(nwo4.X, nwo4.Z - cOffsetPhreaticLineBelowSurface); +// } +// +// // Find the intersections of pl line and NWO and handle these +// // Intersection between nwo point1 and nwo point2 only when nwo point1 is above pl line and nwo point2 is below plLine +// PLLinePoint intersection1 = null; +// if ((nwo1Pl == null) && (nwo2Pl != null)) +// { +// var lineNWO = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo1.X, 0, nwo1.Z), EndPoint = new GeometryPoint(nwo2.X, 0, nwo2.Z) }; +// var ips = pl1Line.IntersectionPointsXzWithLineXz(lineNWO); +// if (ips.Count > 0) +// { +// intersection1 = new PLLinePoint(ips.First().X, ips.First().Z); +// } +// } +// // Intersection between nwo point3 and nwo point4 only when nwo point3 is below pl line and nwo point4 is above plLine +// PLLinePoint intersection2 = null; +// if ((nwo3Pl != null) && (nwo4Pl == null)) +// { +// var lineNWO = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z), EndPoint = new GeometryPoint(nwo4.X, 0, nwo4.Z) }; +// var ips = pl1Line.IntersectionPointsXzWithLineXz(lineNWO); +// if (ips.Count > 0) +// { +// intersection2 = new PLLinePoint(ips.Last().X, ips.Last().Z); +// } +// } +// +// // Handle making the NWO empty +// if ((NWOPhreaticAdaption != null) && (NWOPhreaticAdaption == PhreaticAdaptionType.MakeEmpty)) +// { +// // for the polderside, the pl line is always allowed to be adapted. For the riverside, the pl line may only be adapted when the original waterlevel is runs through the nwo. +// RemoveAllWaterFromNonWaterRetainingObject(nwo1, pl1Line, nwo1Pl, nwo2Pl, nwo3Pl, nwo4Pl, intersection1, intersection2, plPointsToBeMoved); +// } +// // Handle making the waterlevel horizontal in the NWO at the Riverside when needed (Polderside is already done when needed, see CreatePhreaticLineSegmentsInShoulderAndPolder. +// if ((NWOPhreaticAdaption != null) && (NWOPhreaticAdaption == PhreaticAdaptionType.None)) +// { +// // For the riverside, the pl line may only be adapted when the original waterlevel is runs through the nwo and is not already level. +// if ((nwo1.X <= this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X) && ((intersection1 != null) || (intersection2 != null))) +// { +// double requiredWaterLevel; +// // Check whether adaption of intersection points is needed +// if (intersection2 == null) +// { +// // only intersection 1 avaialable so add intersection 2 +// // first see if nwo3/4 intersects, if not try nwo2/3. If still no intersection found valid level not possible, raise error +// MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection1(nwo2, nwo3, nwo4, pl1Line, nwo3Pl, nwo4Pl, intersection1); +// requiredWaterLevel = intersection1.Z; +// } +// else +// { +// if (intersection1 == null) +// { +// // only intersection 2 avaialable so add intersection 1 +// // first see if nwo1/2 intersects, if not try nwo2/3. If still no intersection found valid level not possible, raise error +// MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection2(nwo1, nwo2, nwo3, pl1Line, nwo1Pl, nwo2Pl, nwo3Pl, intersection2); +// requiredWaterLevel = intersection2.Z; +// } +// else +// { +// // intersection 1 and intersection 2 available. Only act when levels were different. +// requiredWaterLevel = Math.Min(intersection1.Z, intersection2.Z); +// if ((Math.Abs(intersection1.Z - intersection2.Z) > GeometryPoint.Precision)) +// { +// if (intersection1.Z < intersection2.Z) +// { +// // make level in NWO intersection1.Z +// MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection1And2(nwo2, nwo3, nwo4, pl1Line, nwo3Pl, intersection1, intersection2); +// } +// else +// { +// // make level in NWO intersection2.Z +// MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection2And1(nwo1, nwo2, nwo3, pl1Line, nwo2Pl, intersection1, intersection2); +// } +// +// } +// } +// } +// +// // Move all the points in the pl line itself that need to be moved to the horizontal proper level. +// foreach (var plLinePoint in plPointsToBeMoved) +// { +// plLinePoint.Z = requiredWaterLevel; +// } +// pl1Line.DeleteCoinsidingPoints(GeometryPoint.Precision); +// } +// } +// } +// } + +// private void MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection2And1(GeometryPoint nwo1, GeometryPoint nwo2, GeometryPoint nwo3, PLLine pl1Line, PLLinePoint nwo2Pl, PLLinePoint intersection1, PLLinePoint intersection2) +// { +// var lineNWO = new Line { BeginPoint = new Point2D(nwo1.X, nwo1.Z), EndPoint = new Point2D(nwo2.X, nwo2.Z) }; +// var linePL = new Line { BeginPoint = new Point2D(nwo1.X, intersection2.Z), EndPoint = new Point2D(intersection2.X, intersection2.Z) }; +// var isp = new GeometryPoint(); +// if (LineHelper.GetStrictIntersectionPoint(lineNWO, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection2.X, GeometryPoint.Precision); +// newP1.Z = intersection2.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection2.Z; +// var newP3 = pl1Line.EnsurePointAtX(intersection1.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP3.Z = intersection1.Z; +// } +// else +// { +// var lineNWOb = new Line { BeginPoint = new Point2D(nwo2.X, nwo2.Z), EndPoint = new Point2D(nwo3.X, nwo3.Z) }; +// if (LineHelper.GetStrictIntersectionPoint(lineNWOb, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection2.X, GeometryPoint.Precision); +// newP1.Z = intersection2.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection2.Z; +// var newP3 = pl1Line.EnsurePointAtX(nwo2Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo2Pl.Z; +// if (nwo2Pl.X > intersection1.X) +// { +// var newP4 = pl1Line.EnsurePointAtX(intersection1.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP4.Z = intersection1.Z; +// } +// +// } +// else +// { +// throw new PLLinesCreatorException("Could not create the intersectionsection points between NWO and Phreatic line to create horizontal level."); +// } +// } +// } + +// private void MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection1And2(GeometryPoint nwo2, GeometryPoint nwo3, GeometryPoint nwo4, PLLine pl1Line, PLLinePoint nwo3Pl, PLLinePoint intersection1, PLLinePoint intersection2) +// { +// var lineNWO = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z), EndPoint = new GeometryPoint(nwo4.X, 0, nwo4.Z) }; +// var linePL = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(intersection1.X, 0, intersection1.Z), EndPoint = new GeometryPoint(nwo4.X, 0, intersection1.Z) }; +// var isp = new GeometryPoint(); +// if (LineHelper.GetStrictIntersectionPoint(lineNWO, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection1.X, GeometryPoint.Precision); +// newP1.Z = intersection1.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection1.Z; +// var newP3 = pl1Line.EnsurePointAtX(intersection2.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP3.Z = intersection2.Z; +// } +// else +// { +// var lineNWOb = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo2.X, 0, nwo2.Z), EndPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z) }; +// if (LineHelper.GetStrictIntersectionPoint(lineNWOb, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection1.X, GeometryPoint.Precision); +// newP1.Z = intersection1.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection1.Z; +// var newP3 = pl1Line.EnsurePointAtX(nwo3Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo3Pl.Z; +// if (nwo3Pl.X < intersection2.X) +// { +// var newP4 = pl1Line.EnsurePointAtX(intersection2.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP4.Z = intersection2.Z; +// } +// } +// else +// { +// throw new PLLinesCreatorException("Could not create the intersectionsection points between NWO and Phreatic line to create horizontal level."); +// } +// } +// } + +// private void RemoveAllWaterFromNonWaterRetainingObject(GeometryPoint nwo1, PLLine pl1Line, PLLinePoint nwo1Pl, PLLinePoint nwo2Pl, PLLinePoint nwo3Pl, PLLinePoint nwo4Pl, PLLinePoint intersection1, PLLinePoint intersection2, IEnumerable plPointsToBeMoved) +// { +// if ((nwo1.X >= this.surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X) || +// ((intersection1 != null) && (intersection2 != null))) +// { +// // Move all the points in the pl line itself that need to be moved to below the surfaceline. +// MoveSelectedPLLinePointsBelowSurfaceLine(plPointsToBeMoved); +// +// // now add all extra points to the pl line +// if (nwo1Pl != null) +// { +// var newP = pl1Line.EnsurePointAtX(nwo1Pl.X, GeometryPoint.Precision); +// newP.Z = nwo1Pl.Z; +// } +// if (nwo2Pl != null) +// { +// var newP = pl1Line.EnsurePointAtX(nwo2Pl.X, GeometryPoint.Precision); +// newP.Z = nwo2Pl.Z; +// } +// if (nwo3Pl != null) +// { +// var newP = pl1Line.EnsurePointAtX(nwo3Pl.X, GeometryPoint.Precision); +// newP.Z = nwo3Pl.Z; +// } +// if (nwo4Pl != null) +// { +// var newP = pl1Line.EnsurePointAtX(nwo4Pl.X, GeometryPoint.Precision); +// newP.Z = nwo4Pl.Z; +// } +// // Note: for intersection points, apply offset in X direction not in Z. +// if (intersection1 != null) +// { +// var newP = pl1Line.EnsurePointAtX(intersection1.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP.Z = intersection1.Z; +// } +// if (intersection2 != null) +// { +// var newP = pl1Line.EnsurePointAtX(intersection2.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP.Z = intersection2.Z; +// } +// pl1Line.DeleteCoinsidingPoints(GeometryPoint.Precision); +// } +// } + +// private void MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection2(GeometryPoint nwo1, GeometryPoint nwo2, GeometryPoint nwo3, PLLine pl1Line, PLLinePoint nwo1Pl, PLLinePoint nwo2Pl, PLLinePoint nwo3Pl, PLLinePoint intersection2) +// { +// var lineNWO = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo1.X, 0, nwo1.Z), EndPoint = new GeometryPoint(nwo2.X, 0, nwo2.Z) }; +// var linePL = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo1.X, 0, intersection2.Z), EndPoint = new GeometryPoint(intersection2.X, 0, intersection2.Z) }; +// var isp = new GeometryPoint(); +// if (LineHelper.GetStrictIntersectionPoint(lineNWO, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection2.X, GeometryPoint.Precision); +// newP1.Z = intersection2.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection2.Z; +// if (nwo1Pl != null) +// { +// var newP3 = pl1Line.EnsurePointAtX(nwo1Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo1Pl.Z; +// } +// } +// else +// { +// var lineNWOb = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo2.X, 0, nwo2.Z), EndPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z) }; +// if (LineHelper.GetStrictIntersectionPoint(lineNWOb, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection2.X, GeometryPoint.Precision); +// newP1.Z = intersection2.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X - cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection2.Z; +// if (nwo2Pl != null) +// { +// var newP3 = pl1Line.EnsurePointAtX(nwo2Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo2Pl.Z; +// if ((nwo1Pl != null) && (nwo2Pl.X > nwo1Pl.X)) +// { +// var newP4 = pl1Line.EnsurePointAtX(nwo1Pl.X, GeometryPoint.Precision); +// newP4.Z = nwo1Pl.Z; +// } +// } +// } +// else +// { +// throw new PLLinesCreatorException("Could not create the intersectionsection points between NWO and Phreatic line to create horizontal level."); +// } +// } +// } + +// private void MakeWaterLevelHorizontalInNWOAtRiverSideUsingInterSection1(GeometryPoint nwo2, GeometryPoint nwo3, GeometryPoint nwo4, PLLine pl1Line, PLLinePoint nwo3Pl, PLLinePoint nwo4Pl, PLLinePoint intersection1) +// { +// var lineNWO = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z), EndPoint = new GeometryPoint(nwo4.X, 0, nwo4.Z) }; +// var linePL = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(intersection1.X, 0, intersection1.Z), EndPoint = new GeometryPoint(nwo4.X, 0, intersection1.Z) }; +// var isp = new GeometryPoint(); +// if (LineHelper.GetStrictIntersectionPoint(lineNWO, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection1.X, GeometryPoint.Precision); +// newP1.Z = intersection1.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection1.Z; +// if (nwo4Pl != null) +// { +// var newP3 = pl1Line.EnsurePointAtX(nwo4Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo4Pl.Z; +// } +// } +// else +// { +// var lineNWOb = new Deltares.Geometry.Line { BeginPoint = new GeometryPoint(nwo2.X, 0, nwo2.Z), EndPoint = new GeometryPoint(nwo3.X, 0, nwo3.Z) }; +// if (LineHelper.GetStrictIntersectionPoint(lineNWOb, linePL, ref isp)) +// { +// var newP1 = pl1Line.EnsurePointAtX(intersection1.X, GeometryPoint.Precision); +// newP1.Z = intersection1.Z; +// var newP2 = pl1Line.EnsurePointAtX(isp.X + cOffsetPhreaticLineBelowSurface, GeometryPoint.Precision); +// newP2.Z = intersection1.Z; +// if (nwo3Pl != null) +// { +// var newP3 = pl1Line.EnsurePointAtX(nwo3Pl.X, GeometryPoint.Precision); +// newP3.Z = nwo3Pl.Z; +// if ((nwo4Pl != null) && (nwo4Pl.X > nwo3Pl.X)) +// { +// var newP4 = pl1Line.EnsurePointAtX(nwo4Pl.X, GeometryPoint.Precision); +// newP4.Z = nwo4Pl.Z; +// } +// } +// } +// else +// { +// throw new PLLinesCreatorException("Could not create the intersectionsection points between NWO and Phreatic line to create horizontal level."); +// } +// } +// } + +// private void MoveSelectedPLLinePointsBelowSurfaceLine(IEnumerable plPointsToBeMoved) +// { +// foreach (var plLinePoint in plPointsToBeMoved) +// { +// // Determine which of these points must be moved and move them +// if (this.surfaceLine.Geometry.PositionXzOfPointRelatedToExtrapolatedLine(plLinePoint) != +// RelativeXzPosition.BelowGeometricLine) +// { +// plLinePoint.Z = this.surfaceLine.Geometry.GetZatX(plLinePoint.X) - cOffsetPhreaticLineBelowSurface; +// } +// } +// } + + /// + /// + /// + /// + /// +// private PLLines CreateAllPLLinesWithGaugesWithFallbackToExpertKnowledgeRRD(Location location) +// { +// var plLines = new PLLines(); +// +// foreach (PLLineType plLineType in Enum.GetValues(typeof(PLLineType))) +// { +// GaugePLLine gaugePLLine = (this.GaugePLLines != null) ? (this.GaugePLLines.FirstOrDefault(x => x.PLLineType == plLineType)) : null; +// if (gaugePLLine != null && location != null) +// { +// Boolean isUseWaterLevel = ((plLineType == PLLineType.PL1) || (plLineType == PLLineType.PL2)); +// plLines.Lines[plLineType] = CreatePLLineFromGauges(gaugePLLine, this.Gauges, location, isUseWaterLevel); +// } +// else +// plLines.Lines[plLineType] = CreatePLLineByExpertKnowledge(plLineType, location.DamType, location.SlopeDampingPiezometricHeightPolderSide); +// +// // currentPL1Line is needed when calculating uplift reduction for PL3 and Pl4 +// if (plLineType == PLLineType.PL1) +// { +// currentPL1Line = plLines.Lines[plLineType]; +// } +// } +// return plLines; +// } + + /// + /// Create all PLLines + /// + /// +// public PLLines CreateAllPLLines(Location location) +// { +// +// PLLines plLines = new PLLines(); +// switch (modelParametersForPLLines.PLLineCreationMethod) +// { +// case PLLineCreationMethod.ExpertKnowledgeLinearInDike: +// case PLLineCreationMethod.ExpertKnowledgeRRD: plLines = CreateAllPLLinesWithExpertKnowledge(location); +// break; +// case PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD: plLines = CreateAllPLLinesWithGaugesWithFallbackToExpertKnowledgeRRD(location); +// break; +// } +// +// +// // If PL Line2 does not exists, make it equal to PL line 4 +// if (!plLines.Lines[PLLineType.PL2].Exists()) +// { +// plLines.Lines[PLLineType.PL2] = plLines.Lines[PLLineType.PL4].Clone(); +// } +// +// if (!plLines.Lines[PLLineType.PL1].IsXAscending()) +// { +// throw new PLLinesCreatorException("PLLine 1 not an X-ascending polyline"); +// } +// +// return plLines; +// } + + /// + /// + /// + /// + /// + public PLLine CreatePLLineByExpertKnowledge(PLLineType plLineType, DamType damType, double slopeGradient) + { + PLLine plLine = null; + + switch (plLineType) + { + case PLLineType.PL1: + plLine = this.CreatePLLine1ByExpertKnowledge(); + break; + case PLLineType.PL2: + plLine = this.CreatePLLine2ByExpertKnowledge(this.ModelParametersForPLLines.PenetrationLength, this.HeadInPLLine2); + break; + case PLLineType.PL3: + plLine = this.CreatePLLine3ByExpertKnowledge(HeadPL3TakingInAccountHydraulicShortcut, this.ModelParametersForPLLines.DampingFactorPL3, slopeGradient); + break; + case PLLineType.PL4: + plLine = this.CreatePLLine4ByExpertKnowledge(GetHeadPL4TakingInAccountHydraulicShortcut(damType), this.ModelParametersForPLLines.DampingFactorPL4, slopeGradient); + break; + } + + if (plLine != null) + { + plLine.DeleteCoinsidingPoints(); + } + return plLine; + } + + /* + private PLLine CreatePLLineFromSensorGroup(PLLineType pLLineType, SensorLocation sensorLocation) + { + var creator = SensorPLLineCreator.CreateInstance(sensorLocation); + return creator.CreatePLLine(pLLineType); + } + */ + + /// + /// + /// + /// + /// + /// + /// +// private PLLine CreatePLLineFromGauges(GaugePLLine gaugePLLine, IEnumerable gauges, Location location, Boolean useWaterLevel) +// { +// PLLine plLine = new PLLine(); +// +// double? gaugeWaterLevelRiver = null; +// double? leftMostXAtRiverLevel = null; +// +// int pointIndex = 0; +// foreach (GaugePLLinePoint gaugePLLinePoint in gaugePLLine.Points) +// { +// +// double? localX = gaugePLLinePoint.X; +// double? localZ = gaugePLLinePoint.Z; +// +// if (gauges != null) +// { +// if (gaugePLLinePoint.GaugeIDX != null && gaugePLLinePoint.GaugeIDX != "") +// { +// Gauge gauge = (gauges.Where(x => x.Name == gaugePLLinePoint.GaugeIDX && x.Location == location)).FirstOrDefault(); +// if (gauge != null) +// localX = gauge.LocalX; +// else +// { +// throw new PLLinesCreatorException(String.Format("Gauge PL line {0} refers to an unknown gauge named '{1}' at X coordinate #{2}.", +// gaugePLLine.PLLineType.ToString(), gaugePLLinePoint.GaugeIDX, pointIndex)); +// } +// } +// if (gaugePLLinePoint.GaugeIDZ != null && gaugePLLinePoint.GaugeIDZ != "") +// { +// Gauge gauge = (gauges.Where(x => x.Name == gaugePLLinePoint.GaugeIDZ && x.Location == location)).FirstOrDefault(); +// if (gauge != null) +// { +// if ((!gauge.Value.HasValue) || (gauge.Value == GaugeMissVal)) +// throw new PLLinesCreatorException(String.Format("Value of gauge {0} at location {1} in gauge PL line of type {2} is undefined.", +// gauge.Name, location.Name, gaugePLLine.PLLineType.ToString())); +// localZ = gauge.Value; +// } +// else +// { +// throw new PLLinesCreatorException(String.Format("Gauge PL line {0} refers to an unknown gauge named '{1}' at Z coordinate #{2}.", +// gaugePLLine.PLLineType.ToString(), gaugePLLinePoint.GaugeIDZ, pointIndex)); +// } +// } +// } +// +// if (!localX.HasValue) +// throw new PLLinesCreatorException(String.Format("Gauge PL line {0}'s X coordinate #{1} is undefined.", gaugePLLine.PLLineType.ToString(), pointIndex)); +// else if (!localZ.HasValue) +// throw new PLLinesCreatorException(String.Format("Gauge PL line {0}'s value #{1} is undefined.", gaugePLLine.PLLineType.ToString(), pointIndex)); +// else +// { +// if (!leftMostXAtRiverLevel.HasValue || localX > leftMostXAtRiverLevel) +// { +// plLine.Points.Add(new PLLinePoint(localX.Value, localZ.Value)); +// if (useWaterLevel) +// { +// // Have to account for waterlevel +// if (!gaugeWaterLevelRiver.HasValue) +// { +// // Use first gauge as waterlevel +// gaugeWaterLevelRiver = localZ.Value; +// IList intersectionsAtX = this.surfaceLine.Geometry.IntersectionsXAtZ(gaugeWaterLevelRiver.Value); +// if (intersectionsAtX.Count() > 0) +// { +// // this is where the waterlevel intersects with the dike +// leftMostXAtRiverLevel = intersectionsAtX.First(); +// plLine.Points.Add(new PLLinePoint(leftMostXAtRiverLevel.Value, gaugeWaterLevelRiver.Value)); +// } +// else +// { +// // No intersection with dike; polder is flooded +// leftMostXAtRiverLevel = this.surfaceLine.Geometry.Points.Last().X; +// plLine.Points.Add(new PLLinePoint(this.surfaceLine.Geometry.Points.Last().X, gaugeWaterLevelRiver.Value)); +// } +// } +// } +// else +// { +// // In this case no intersection for this Plline with the dike will be considered +// leftMostXAtRiverLevel = this.surfaceLine.Geometry.Points.First().X; +// } +// } +// } +// +// pointIndex++; +// } +// +// if (plLine.Points.Count() > 0) +// { +// plLine.Points.First().X = this.surfaceLine.Geometry.Points.First().X; +// plLine.Points.Last().X = this.surfaceLine.Geometry.Points.Last().X; +// } +// +// return plLine; +// } + + /// + /// Validate of all required characteristic points exists + /// + private void ValidateRequiredCharacteristicPoints() + { + if (!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeTopAtRiver)) + { + throw new PLLinesCreatorException("Required characteristic point DikeTopAtRiver not found. "); + } + + if (!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeTopAtPolder)) + { + throw new PLLinesCreatorException("Required characteristic point DikeTopAtPolder not found. "); + } + + if (!SurfaceLine.HasAnnotation(CharacteristicPointType.DikeToeAtPolder)) + { + throw new PLLinesCreatorException("Required characteristic point DikeToeAtPolder not found. "); + } + } + + /// + /// + /// + /// + /// + /// + private void CreatePhreaticLineSegmentsInsideDikeForLowRiverLevel(PLLine phreaticLine, double lowWaterLevel, double highWaterLevel) + { + PLLinePoint intersectionLowWaterLevelWithDike = DetermineIntersectionBetweenWaterLevelAndDike(lowWaterLevel); + GeometryPoint pointDikeToeAtRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver); + switch (modelParametersForPLLines.PLLineCreationMethod) + { + case PLLineCreationMethod.ExpertKnowledgeLinearInDike: + const double cPLLineOffsetBelowSurface = 0.1; + PLLinePoint intersectionHighWaterLevelWithDike = DetermineIntersectionBetweenWaterLevelAndDike(highWaterLevel); + if (intersectionLowWaterLevelWithDike == null) + { + // Intersection is supposed to be at toe of dike when no intersection found (i.e. waterlevel below toe of dike) + intersectionLowWaterLevelWithDike = new PLLinePoint(pointDikeToeAtRiver.X, pointDikeToeAtRiver.Z); + } + // At this point both intersectionHighWaterLevelWithDike and intersectionLowWaterLevelWithDike are <> null + // or else an exception would have been thrown + PLLinePoint pointBelowHighLevel = new PLLinePoint(intersectionHighWaterLevelWithDike.X, + intersectionHighWaterLevelWithDike.Z - cPLLineOffsetBelowSurface); + + //Add points below surface of dike talud riverside + foreach (GeometryPoint point in SurfaceLine.Geometry.Points.Where( + point => point.X > intersectionLowWaterLevelWithDike.X && + point.X < intersectionHighWaterLevelWithDike.X)) + { + phreaticLine.Points.Add(new PLLinePoint(point.X, point.Z - cPLLineOffsetBelowSurface)); + } + + // Add last point (below high riverlevel/dike section + phreaticLine.Points.Add(pointBelowHighLevel); + + break; +// case PLLineCreationMethod.ExpertKnowledgeRRD: +// //Add points below surface of dike talud riverside until toe of dike riverside +// foreach (GeometryPoint point in SurfaceLine.Geometry.Points.Where( +// point => point.X > intersectionLowWaterLevelWithDike.X && +// point.X <= pointDikeToeAtRiver.X)) +// { +// if (!surfaceLine.IsNonWaterRetainingObjectPoint(point)) +// { +// phreaticLine.Points.Add(new PLLinePoint(point.X, point.Z - cPLLineOffsetBelowSurface)); +// } +// } +// +// // Add points below crest of dike +// double offsetDikeTopAtRiver = this.waterLevelRiverHigh - PlLineOffsetBelowDikeTopAtRiver; +// double offsetDikeTopAtPolder = this.waterLevelRiverHigh - PlLineOffsetBelowDikeTopAtPolder; +// GeometryPoint pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); +// GeometryPoint pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); +// if (pointDikeTopAtRiver != null) +// phreaticLine.Points.Add(new PLLinePoint(pointDikeTopAtRiver.X, offsetDikeTopAtRiver)); +// +// if (pointDikeTopAtRiver != null && pointDikeTopAtPolder != null) +// { +// CreateOptionalPointAtDikeCrestMiddle(phreaticLine, pointDikeTopAtRiver, pointDikeTopAtPolder); +// } +// +// if (pointDikeTopAtPolder != null) +// phreaticLine.Points.Add(new PLLinePoint(pointDikeTopAtPolder.X, offsetDikeTopAtPolder)); +// break; + } + } + + /// + /// Creates the optional point at dike crest middle. + /// + /// The phreatic line. + /// The point dike top at river. + /// The point dike top at polder. + private void CreateOptionalPointAtDikeCrestMiddle(PLLine phreaticLine, GeometryPoint pointDikeTopAtRiver, + GeometryPoint pointDikeTopAtPolder) + { + if (UsePlLineOffsetBelowDikeCrestMiddle.HasValue && UsePlLineOffsetBelowDikeCrestMiddle.Value && PlLineOffsetBelowDikeCrestMiddle != null) + { + var middleDikeCrestX = (pointDikeTopAtRiver.X + pointDikeTopAtPolder.X)*0.5; + var middleDikeCrestZ = waterLevelRiverHigh - PlLineOffsetBelowDikeCrestMiddle.Value; + // Check whether middleDikeCrestZ is above the surface line. If so, than use the value at the surfaceline instead. + var allZ = surfaceLine.Geometry.GetAllZatXForLine(middleDikeCrestX); + if (allZ.Count > 0) + { + var z = allZ.FirstOrDefault(); + if (middleDikeCrestZ > z) + { + middleDikeCrestZ = z; + } + } + phreaticLine.Points.Add(new PLLinePoint(middleDikeCrestX, middleDikeCrestZ)); + } + } + + /// + /// Create the phreatic line segments inside the dike + /// + /// + private void CreatePhreaticLineSegmentsInsideDikeForHighRiverLevel(PLLine phreaticLine) + { + double offsetDikeTopAtRiver = waterLevelRiverHigh - PlLineOffsetBelowDikeTopAtRiver; + double offsetDikeTopAtPolder = waterLevelRiverHigh - PlLineOffsetBelowDikeTopAtPolder; + + // points created here are in dike + switch (modelParametersForPLLines.PLLineCreationMethod) + { + case PLLineCreationMethod.ExpertKnowledgeLinearInDike: + // No extra points below top of dike at river and top of dike at polder + break; + case PLLineCreationMethod.ExpertKnowledgeRRD: + var pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + if (pointDikeTopAtRiver != null) + phreaticLine.Points.Add(new PLLinePoint(pointDikeTopAtRiver.X, offsetDikeTopAtRiver)); + var pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + if (pointDikeTopAtRiver != null && pointDikeTopAtPolder != null) + { + CreateOptionalPointAtDikeCrestMiddle(phreaticLine, pointDikeTopAtRiver, pointDikeTopAtPolder); + } + if (pointDikeTopAtPolder != null) + phreaticLine.Points.Add(new PLLinePoint(pointDikeTopAtPolder.X, offsetDikeTopAtPolder)); + break; + } + + } + + /// + /// + /// + /// +// private void CreatePhreaticLineSegmentsInShoulderAndPolder(PLLine phreaticLine) +// { +// PLLinePoint intersectionPolderLevelWithDike = DetermineIntersectionBetweenPolderLevelAndDike(this.WaterLevelPolder); +// GeometryPoint dikeToeAtPolderPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); +// +// double maxXCoordinateSurface = surfaceLine.Geometry.Points.Max(x => x.X); +// if (modelParametersForPLLines.PLLineCreationMethod != PLLineCreationMethod.ExpertKnowledgeLinearInDike) +// { +// // Points created below are points starting at shoulder point to the right +// GeometryPoint shoulderBaseInsidePoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); +// if (shoulderBaseInsidePoint != null) +// { +// double zLevel = Math.Min(phreaticLine.Points.Last().Z, +// shoulderBaseInsidePoint.Z - +// Math.Max(cOffsetPhreaticLineBelowSurface, PlLineOffsetBelowShoulderBaseInside)); +// zLevel = Math.Max(zLevel, this.WaterLevelPolder); +// // Add point if it lies left of intersection of polderlevel with dike) +// if ((intersectionPolderLevelWithDike == null) || +// (intersectionPolderLevelWithDike.X > shoulderBaseInsidePoint.X)) +// { +// phreaticLine.Points.Add(new PLLinePoint(shoulderBaseInsidePoint.X, zLevel)); +// } +// +// if (UsePlLineOffsetFactorBelowShoulderCrest.HasValue && UsePlLineOffsetFactorBelowShoulderCrest.Value && +// PlLineOffsetFactorBelowShoulderCrest != null && dikeToeAtPolderPoint != null) +// { +// GeometryPoint shoulderTopInsidePoint = +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); +// if (shoulderTopInsidePoint != null) +// { +// zLevel = dikeToeAtPolderPoint.Z + (PlLineOffsetFactorBelowShoulderCrest.Value* +// (shoulderTopInsidePoint.Z - dikeToeAtPolderPoint.Z)); +// zLevel = Math.Min(zLevel, shoulderTopInsidePoint.Z - cOffsetPhreaticLineBelowSurface); +// zLevel = Math.Min(zLevel, phreaticLine.Points.Last().Z); +// zLevel = Math.Max(zLevel, this.WaterLevelPolder); +// phreaticLine.Points.Add(new PLLinePoint(shoulderTopInsidePoint.X, zLevel)); +// } +// } +// } +// } +// +// GeometryPoint ditchDikeSidePoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); +// if (dikeToeAtPolderPoint != null) +// { +// +// double zLevel = Math.Min(phreaticLine.Points.Last().Z, dikeToeAtPolderPoint.Z - Math.Max(cOffsetPhreaticLineBelowSurface, PlLineOffsetBelowDikeToeAtPolder)); +// if (ditchDikeSidePoint != null) +// { +// if (ditchDikeSidePoint.LocationEquals(dikeToeAtPolderPoint)) +// { +// // If DikeToeAtPolder is same as DitchDikeSide pl1 should always go to polderlevel at this point +// zLevel = this.WaterLevelPolder; +// } +// } +// zLevel = Math.Max(zLevel, this.WaterLevelPolder); +// // Add point if it lies left of intersection of polderlevel with dike +// if ((intersectionPolderLevelWithDike == null) || (intersectionPolderLevelWithDike.X > dikeToeAtPolderPoint.X)) +// { +// phreaticLine.Points.Add(new PLLinePoint(dikeToeAtPolderPoint.X, zLevel)); +// } +// } +// +// if (intersectionPolderLevelWithDike != null) +// { +// phreaticLine.Points.Add(intersectionPolderLevelWithDike); +// } +// +// var isDitchPresent = (ditchDikeSidePoint != null); +// var isNonWaterRetainingOjectPresent = ((NWOPhreaticAdaption != null) && surfaceLine.HasAnnotation(CharacteristicPointType.NonWaterRetainingObjectPoint1)); +// var adjustDitch = false; +// // Handle making the waterlevel horizontal in the NWO at the Polderside when needed (For Riverside see AdaptPL1ForNonWaterRetainingObject). +// var nonWaterRetainingGeometryPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1); +// if (isNonWaterRetainingOjectPresent && (NWOPhreaticAdaption != PhreaticAdaptionType.Fill) && +// (nonWaterRetainingGeometryPoint.X >= surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X)) +// { +// // if there is a ditch and it is to the left of the NWO, then only the ditch needs to be adjusted and the NWO will be correct automatically. +// // if there is a ditch but it is to the right of the NWO, the NWO needs adjusting and the Ditch will be correct automatically. +// // if there is no ditch then the NWO needs adjusting. +// if (isDitchPresent) +// { +// adjustDitch = (nonWaterRetainingGeometryPoint.X >= surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X); +// } +// if (!adjustDitch) +// { +// GeometryPoint nw1 = nonWaterRetainingGeometryPoint; +// int surfacePointIndex = surfaceLine.Geometry.Points.IndexOf(nw1); +// AdjustForDitchAndOrNonWaterRetainingObjectatPolderSide(phreaticLine, surfacePointIndex); +// } +// } +// else +// { +// // No (relevant) NWO so enable handling of ditch. +// // If there is a ditch but there is also a NWO to the right of it at polder side, then do not adjust the ditch. Do in all other cases. +// // First see if there is a NWO. +// adjustDitch = !isNonWaterRetainingOjectPresent; +// if (!adjustDitch) +// { +// // there is a NWO, check the position +// adjustDitch = +// !((isDitchPresent) && +// (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint1).X >= +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X) && +// (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint4).X <= +// surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide).X)); +// } +// } +// // if the NWO is not there or irrelevant and there is a ditch, then adjust it. +// if ((adjustDitch) && (isDitchPresent)) +// { +// int surfacePointIndex = surfaceLine.Geometry.Points.IndexOf(ditchDikeSidePoint); +// AdjustForDitchAndOrNonWaterRetainingObjectatPolderSide(phreaticLine, surfacePointIndex); +// } +// else +// { +// // if no ditch then the PL1 will continue horizontally until the end of the profile +// // another choice could be to let the PL1 go to polderlevel at the end of the profile, but that could be too optimistic for uplift. +// // Discussion about this was done between Vastenburg, Knoeff and The. +// // After a renewed discussion with Vastenburg, Van der Zwan and Bka, it has been decided that the PL1 should follow the +// // surfaceline (with offset) until either end of surface line or polder level. Note: this is only needed when the phreatic level +// // at dike toe is above polder level. +// if ((!isNonWaterRetainingOjectPresent) && (!isDitchPresent)) +// { +// if (phreaticLine.Points[phreaticLine.Points.Count - 1].Z > WaterLevelPolder) +// { +// AddPhreaticLineAlongSurfaceLevel(phreaticLine); +// } +// } +// } +// +// //Validate if endpoint surface has reached +// if (phreaticLine.Points.Last().X != maxXCoordinateSurface) +// { +// PLLinePoint endPoint = new PLLinePoint(maxXCoordinateSurface, phreaticLine.Points.Last().Z); +// phreaticLine.Points.Add(endPoint); +// } +// } + +// private void AddPhreaticLineAlongSurfaceLevel(PLLine phreaticLine) +// { +// // Add phreatic point at offset below every surface line point as long as depth > polder level. Else determine the +// // proper position of the point at polder level (intersection) and stop. +// var surfacePointIndex = surfaceLine.Geometry.Points.IndexOf(surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder)) + 1; +// bool intersected = false; +// for (int i = surfacePointIndex; i < surfaceLine.Geometry.Points.Count; i++) +// { +// double z = Math.Max(waterLevelPolder, surfaceLine.Geometry.Points[i].Z - PlLineOffsetBelowDikeToeAtPolder); +// double x = surfaceLine.Geometry.Points[i].X; +// if (waterLevelPolder > surfaceLine.Geometry.Points[i].Z - PlLineOffsetBelowDikeToeAtPolder) +// { +// // Determine intersection between would be phreatic segment and polderlevel. Add that as next point. +// Line waterLevelPolderLine = new Line(new GeometryPoint(surfaceLine.Geometry.Points.First().X, WaterLevelPolder), +// new GeometryPoint(surfaceLine.Geometry.Points.Last().X, 0, WaterLevelPolder)); +// Line slopeLine = new Line(new GeometryPoint(phreaticLine.Points[phreaticLine.Points.Count - 1].X, phreaticLine.Points[phreaticLine.Points.Count - 1].Z), +// new GeometryPoint(surfaceLine.Geometry.Points[i].X, surfaceLine.Geometry.Points[i].Z - PlLineOffsetBelowDikeToeAtPolder)); +// GeometryPoint intersectionPoint = new GeometryPoint(); +// if (waterLevelPolderLine.IntersectsZ(slopeLine, out intersectionPoint)) +// { +// x = intersectionPoint.X; +// } +// intersected = true; +// } +// PLLinePoint point = new PLLinePoint(x, z); +// phreaticLine.Points.Add(point); +// if (intersected) +// { +// break; +// } +// } +// } + + private void AdjustForDitchAndOrNonWaterRetainingObjectatPolderSide(PLLine phreaticLine, int surfacePointIndex) + { + const double maxDouble = 99999.999; + var phreaticPolderPartialLine = new Line(); + //#bka: hier niet langer ook starten met waterlevel als waterlevel onder bottomditch zit! + phreaticPolderPartialLine.SetBeginAndEndPoints(new Point2D(phreaticLine.Points[0].X, waterLevelPolder), + new Point2D(maxDouble, waterLevelPolder)); + AddIntersectionDitchDikeSegmentPolderLevelToPhreatic(phreaticLine, surfacePointIndex, phreaticPolderPartialLine); + AddIntersectionDitchPolderSegmentPolderLevelToPhreatic(phreaticLine, phreaticPolderPartialLine); + } + + /// + /// Intersection between two line segments: + /// -Ditchpolder Surfaceline segment + /// -Polder waterlevel + /// + /// + /// + private void AddIntersectionDitchPolderSegmentPolderLevelToPhreatic(PLLine phreaticLine, Line phreaticPolderPartialLine) + { + GeometryPoint pointDitchPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide); + if (pointDitchPolder != null) + { + int indexatDitchPolder = surfaceLine.Geometry.Points.IndexOf(pointDitchPolder); + var lineDitchPolderSide = new Line(); + if (indexatDitchPolder > 1) + { + lineDitchPolderSide.SetBeginAndEndPoints(new Point2D(surfaceLine.Geometry.Points[indexatDitchPolder - 1].X, surfaceLine.Geometry.Points[indexatDitchPolder - 1].Z), + new Point2D(surfaceLine.Geometry.Points[indexatDitchPolder].X, surfaceLine.Geometry.Points[indexatDitchPolder].Z)); + + GeometryPoint intersectDitchPolderPhreatic = new GeometryPoint(); + if (LineHelper.GetStrictIntersectionPoint(lineDitchPolderSide, phreaticPolderPartialLine, ref intersectDitchPolderPhreatic)) + { + phreaticLine.Points.Add(new PLLinePoint(intersectDitchPolderPhreatic.X, intersectDitchPolderPhreatic.Z)); + } + else + { + phreaticLine.Points.Add(new PLLinePoint(pointDitchPolder.X, phreaticPolderPartialLine.EndPoint.Z)); + } + } + else + throw new PLLinesCreatorException("DitchPolderSide should be part of a line segment"); + + } + } + + /// + /// Intersection between two line segments: + /// -DitchDike Surfaceline segment + /// -Polder waterlevel + /// + /// + /// + /// + private void AddIntersectionDitchDikeSegmentPolderLevelToPhreatic(PLLine phreaticLine, int surfacePointIndex, Line phreaticPolderPartialLine) + { + if (surfacePointIndex + 1 < surfaceLine.Geometry.Points.Count) + { + var lineDitchDikeSide = new Line(); + lineDitchDikeSide.SetBeginAndEndPoints(new Point2D(surfaceLine.Geometry.Points[surfacePointIndex].X, surfaceLine.Geometry.Points[surfacePointIndex].Z), + new Point2D(surfaceLine.Geometry.Points[surfacePointIndex + 1].X, surfaceLine.Geometry.Points[surfacePointIndex + 1].Z)); + + GeometryPoint intersectDitchDikePhreatic = new GeometryPoint(); + if (LineHelper.GetStrictIntersectionPoint(lineDitchDikeSide, phreaticPolderPartialLine, ref intersectDitchDikePhreatic)) + { + phreaticLine.Points.Add(new PLLinePoint(intersectDitchDikePhreatic.X, intersectDitchDikePhreatic.Z)); + } + else + { + phreaticLine.Points.Add(new PLLinePoint(surfaceLine.Geometry.Points[surfacePointIndex].X, phreaticPolderPartialLine.EndPoint.Z)); + } + + } + else + throw new PLLinesCreatorException("Could not create DikeSementPolderLevel"); + } + + /// + /// Intersection between two line segments: + /// - Horizontal waterlevel + /// - Surface line (until DikeTopAtRiver) + /// + /// + /// + /// + public PLLinePoint DetermineIntersectionBetweenWaterLevelAndDike(double waterLevelRiver) + { + GeometryPoint PointAtLevel = this.surfaceLine.DetermineIntersectionWithLevel(waterLevelRiver); + if (PointAtLevel != null) + { + return new PLLinePoint(PointAtLevel.X, PointAtLevel.Z); + } + else + { + return null; + } + } + + private PLLinePoint DetermineIntersectionBetweenPolderLevelAndDike(double polderLevel) + { + var polderlevelLine = new Line(); + double startXCoordinate = this.surfaceLine.Geometry.Points.OrderBy(p => p.X).First().X; + GeometryPoint pointEndOfprofile = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside); + polderlevelLine.SetBeginAndEndPoints(new Point2D(startXCoordinate, polderLevel), + new Point2D(pointEndOfprofile.X, polderLevel)); + + ThrowWhenWaterLevelAboveDike(polderLevel, SurfaceLine); + + int startPosition = 0; + int endPosition = 0; + startPosition = SurfaceLine.Geometry.Points.IndexOf(SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver)); + endPosition = SurfaceLine.Geometry.Points.IndexOf(SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder)); + for (int surfacePointIndex = startPosition; surfacePointIndex < endPosition; surfacePointIndex++) + { + var surfaceLineSegment = new Line(); + surfaceLineSegment.SetBeginAndEndPoints(new Point2D(SurfaceLine.Geometry.Points[surfacePointIndex].X, SurfaceLine.Geometry.Points[surfacePointIndex].Z), + new Point2D(SurfaceLine.Geometry.Points[surfacePointIndex + 1].X, SurfaceLine.Geometry.Points[surfacePointIndex + 1].Z)); + GeometryPoint intersectPoint = new GeometryPoint(); + if (LineHelper.GetStrictIntersectionPoint(surfaceLineSegment, polderlevelLine, ref intersectPoint)) + { + return new PLLinePoint(intersectPoint.X, intersectPoint.Z); + } + } + return null; + } + + /// + /// Detects whether the phreatic line is above the surface line between DikeTopAtRiver and DikeToeAtPolder + /// If the phreatic line is above the surface, then the phreatic line should follow the surface + /// + /// + /// + private void ValidatePhreaticBelowDike(PLLine phreaticLine) + { + int startIndex = SurfaceLine.Geometry.Points.IndexOf(SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver)); + int stopIndex = SurfaceLine.Geometry.Points.IndexOf(SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder)); + bool StopIteration = false; + // This code can go into an endless loop + // Enter failsave to raise exception when this occurs + int cMaxIterations = Math.Max(100, phreaticLine.Points.Count * SurfaceLine.Geometry.Points.Count); + int iterationCount = 0; + while (StopIteration == false) + { + iterationCount++; + bool foundIntersect = false; + for (int phreaticPointIndex = 0; phreaticPointIndex < phreaticLine.Points.Count - 1; phreaticPointIndex++) + { + var phreaticLineSegment = new Line(); + phreaticLineSegment.SetBeginAndEndPoints( + new Point2D(phreaticLine.Points[phreaticPointIndex].X, phreaticLine.Points[phreaticPointIndex].Z), + new Point2D(phreaticLine.Points[phreaticPointIndex + 1].X, phreaticLine.Points[phreaticPointIndex + 1].Z)); + for (int surfacePointIndex = startIndex; surfacePointIndex < stopIndex; surfacePointIndex++) + { + var surfaceLineSegment = new Line(); + surfaceLineSegment.SetBeginAndEndPoints( + new Point2D(SurfaceLine.Geometry.Points[surfacePointIndex].X, SurfaceLine.Geometry.Points[surfacePointIndex].Z), + new Point2D(SurfaceLine.Geometry.Points[surfacePointIndex + 1].X, SurfaceLine.Geometry.Points[surfacePointIndex + 1].Z)); + var intersectGeoPoint = new GeometryPoint(); + var intersectPoint = new Point2D(); + if (LineHelper.GetStrictIntersectionPoint(phreaticLineSegment, surfaceLineSegment, ref intersectGeoPoint)) + { + intersectPoint.X = intersectGeoPoint.X; + intersectPoint.Z = intersectGeoPoint.Z; + // Prevent any adding when intersectPoint is already on Pl + if (!intersectPoint.LocationEquals(phreaticLineSegment.BeginPoint) && + !intersectPoint.LocationEquals(phreaticLineSegment.EndPoint)) + { + // Only add intersectPoint if it is higher than waterlevelPolder, because the intersection could be caused + // by the fact that the waterlevel is higher than DikeToeAtPolder + if (intersectPoint.Z > waterLevelPolder + cOffsetPhreaticLineBelowSurface) + { + var newPLLinePoint = new PLLinePoint(intersectPoint.X, + intersectPoint.Z - cOffsetPhreaticLineBelowSurface); + // Only add new point if it is more to the right than the first point of the phreatic line segment when + if (newPLLinePoint.X > phreaticLineSegment.BeginPoint.X) + { + phreaticLine.Points.Insert(phreaticPointIndex + 1, newPLLinePoint); + if (SurfaceLine.Geometry.Points[surfacePointIndex + 1].X.IsNearEqual(intersectPoint.X)) + { + // phreatic point and surfaceline point are postioned above each other, so replace the phreatic point with the intersect point + phreaticLine.Points[phreaticPointIndex + 2] = + new PLLinePoint(SurfaceLine.Geometry.Points[surfacePointIndex + 1].X, + SurfaceLine.Geometry.Points[surfacePointIndex + 1].Z - + cOffsetPhreaticLineBelowSurface); + } + else + { + var newNextPLLinePoint = + new PLLinePoint(SurfaceLine.Geometry.Points[surfacePointIndex + 1].X, + SurfaceLine.Geometry.Points[surfacePointIndex + 1].Z - + cOffsetPhreaticLineBelowSurface); + if (newNextPLLinePoint.X <= phreaticLine.Points[phreaticPointIndex + 2].X) + { + if (newNextPLLinePoint.X.IsNearEqual(phreaticLine.Points[phreaticPointIndex + 2].X)) + { + // If phreatic point already exist on this x-coordinate just replace it with the new point + phreaticLine.Points[phreaticPointIndex + 2] = newNextPLLinePoint; + } + else + { + phreaticLine.Points.Insert(phreaticPointIndex + 2, + newNextPLLinePoint); + } + } + } + foundIntersect = true; + } + break; + } + } + } + } + } + if (foundIntersect == false) + StopIteration = true; + if (iterationCount > cMaxIterations) + throw new PLLinesCreatorException("PLLinesCreator.ValidatePhreaticBelowDike() cannot succeed"); + } + } + + /// + /// Create PL1 (is phreatic level) + /// + /// + /// + private PLLine CreatePLLine1ByExpertKnowledge() + { + ValidateSurfaceLine(); + + ValidateRequiredCharacteristicPoints(); + + ThrowWhenWaterLevelPolderAboveDikeTopAtPolder(); + + //Create Phreatic line and add polderwater level + double startXCoordinate = this.surfaceLine.Geometry.Points.OrderBy(p => p.X).First().X; + + PLLine phreaticLine = new PLLine(); + phreaticLine.IsPhreatic = true; + double? waterLevel = WaterLevelToUse(); + // Waterlevel is supposed to be at level of SurfaceLevelOutside when waterlevel is below SurfaceLevelOutside (is the bottom of the river) + waterLevel = this.SurfaceLine.EnsureWaterLevelIsAboveRiverBottom(waterLevel); + phreaticLine.Points.Add(new PLLinePoint(startXCoordinate, waterLevel.Value)); + + PLLinePoint intersectionPhreaticDike = null; + + //Determine intersection Phreaticlevel - Berm (or dike) + intersectionPhreaticDike = DetermineIntersectionBetweenWaterLevelAndDike(waterLevel.Value); + if (intersectionPhreaticDike == null) + { + throw new PLLinesCreatorException("DetermineIntersectionBetweenWaterLevelAndDike failed"); + } + + //Add intersectioncoordinate to phreatic line list if not already in list. + if (!phreaticLine.Points.Contains(intersectionPhreaticDike)) + { + phreaticLine.Points.Add(intersectionPhreaticDike); + } + + //Complete phreatic line + if (this.IsUseLowWaterLevel) + { + // intersectionPhreaticDike.Z is either low riverlevel or ToeAtDike.Z, whichever is higher + // Or in human language: low riverlevel should always be a least at surfacelevel + CreatePhreaticLineSegmentsInsideDikeForLowRiverLevel(phreaticLine, Math.Max(intersectionPhreaticDike.Z, this.waterLevelRiverLow.Value), this.waterLevelRiverHigh); + } + else + { + CreatePhreaticLineSegmentsInsideDikeForHighRiverLevel(phreaticLine); + } + //CreatePhreaticLineSegmentsInShoulderAndPolder(phreaticLine); ##Bka + + //Check if phreatic line is above + ValidatePhreaticAboveWaterLevelPolder(phreaticLine); + //Check if phreatic line is below the surface line + ValidatePhreaticBelowDike(phreaticLine); + + // currentPL1Line is needed when calculating uplift reduction for PL3 and Pl4 + //AdaptPL1ForNonWaterRetainingObject(ref phreaticLine); ##Bka + currentPL1Line = phreaticLine; + return phreaticLine; + } + + /// + /// Check whether a correct surface line has been imported + /// + private void ValidateSurfaceLine() + { + if (SurfaceLine == null) + { + throw new PLLinesCreatorException("Surfaceline should be initialized"); + } + + if (SurfaceLine.Geometry.Points.Count < 2) + { + throw new PLLinesCreatorException("More surfaceline points are required"); + } + } + /// + /// Check if phreatic line is above waterlevel + /// If it is below, correct it + /// + /// + private void ValidatePhreaticAboveWaterLevelPolder(PLLine phreaticLine) + { + foreach (PLLinePoint phreaticPoint in phreaticLine.Points) + { + if (phreaticPoint.Z < waterLevelPolder) + { + phreaticPoint.Z = waterLevelPolder; + } + } + } + + /// + /// + /// + private void ThrowWhenWaterLevelAboveDike(double waterLevelRiver, SurfaceLine2 surfaceLine) + { + var dikeTopAtRiverHeight = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).Z; + if (waterLevelRiver > dikeTopAtRiverHeight) + { + throw new PLLinesCreatorException(String.Format("Phreatic water level should have an intersection with the dike at least once (phreatic line higher ({0:F2} m) than surface line ({1:F2}))", waterLevelRiver, dikeTopAtRiverHeight)); + } + } + + /// + /// + /// + private void ThrowWhenWaterLevelPolderAboveDikeTopAtPolder() + { + if (waterLevelPolder > surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z) + { + throw new PLLinesCreatorException(String.Format("Waterlevel ({0:0.00}) in polder higher than dike top at polder ({1:0.00}) in surfaceline {2}", waterLevelPolder, SurfaceLine.GetDikeToeInward().Z, SurfaceLine.Name)); + } + } + } + +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculator.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculator.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DamProjectCalculator.cs (revision 334) @@ -0,0 +1,975 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Xml.Serialization; +using Deltares.DamEngine.Calculators.Uplift; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.General.TimeSeries; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Logging; +using Deltares.DamEngine.Calculators.General; +using Deltares.DamEngine.Calculators.PlLinesCreator; +using Deltares.DamEngine.Calculators.Stability; +using Parallel = Deltares.DamEngine.Calculators.General.Parallel; + +namespace Deltares.DamEngine.Calculators +{ + public class DamProjectCalculator + { + private readonly DamProjectData damProjectData; + private readonly Object lockObject = new object(); + private int maxCalculationCores = 255; + private string slopeWProgramPath = ""; + private string mStabProgramPath = ""; + private string calculationBaseDirectory = ""; + + /// + /// Constructor + /// + /// + public DamProjectCalculator(DamProjectData damProjectData) + { + this.damProjectData = damProjectData; + } + + /// + /// Base directory where the project is stored + /// Needed to find the 2d geometries + /// + public string ProjectDataDirectory { get; set; } + + public ProgressDelegate Progress { get; set; } + + /// + /// Properties + /// + public string CalculationBaseDirectory + { + get + { + return calculationBaseDirectory; + } + set + { + calculationBaseDirectory = value; + } + } + + public string MStabProgramPath + { + get + { + return mStabProgramPath; + } + set + { + mStabProgramPath = value; + } + } + + public string SlopeWProgramPath + { + get + { + return slopeWProgramPath; + } + set + { + slopeWProgramPath = value; + } + } + + public int MaxCalculationCores + { + get + { + return maxCalculationCores; + } + set + { + maxCalculationCores = value; + } + } + + /// + /// Validate if all parameters are available for calculation of project + /// + public void ValidateGeneral() + { + // ToDo make this intelligent depending on the specification + ThrowHelper.ThrowWhenConditionIsTrue("No actual calculation specified.", + () => damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications.Count == 0); + } + + /// + /// Validate if all parameters are available for calculation of project + /// + public void ValidateSpecification() + { + // ToDo make this intelligent depending on the specification + if (damProjectData.ProgramType == ProgramType.MStab) + { + ThrowHelper.ThrowIfFileNotExist(MStabProgramPath, StringResourceNames.MStabExecutableFileNameNotFound); + } + if (damProjectData.ProgramType == ProgramType.SlopeW) + { + ThrowHelper.ThrowIfFileNotExist(SlopeWProgramPath, StringResourceNames.SlopeWExecutableFileNameNotFound); + } + } + + /// + /// Perform the calculations + /// + public List> Calculate(DamProjectData damProjectData, IList scenarios) + { + foreach (var scenario in scenarios) + { + foreach (var dike in damProjectData.WaterBoard.Dikes) + { + if (dike.Locations.Contains(scenario.Location)) + { + dike.UpdateLocation(scenario.Location); + break; + } + } + } + + ValidateGeneral(); + + Parallel.Run((IList) scenarios, RunScenario, Progress, MaxCalculationCores); + + var allCalculationResults = scenarios.Select(scenario => scenario.CalculationResults).ToList(); + + PostprocessForStabilityUpliftVanBishop(ref allCalculationResults); + + this.damProjectData.UpdateDesignCalculations(); + + return allCalculationResults; + } + + /// + /// Determine where lowest uplift factor occurs and the value of that factor + /// + /// + /// + /// + /// + /// + /// + /// + public double? GetLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PLLines plLines, Location location) + { + 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; + } + + /// + /// Determines whether it is a combined stability bishop and liftvan calculation. + /// + /// The calculation specification. + /// + /// true if it is a stability bishop and liftvan calculation; otherwise, false. + /// + private bool IsStabilityBishopLiftVanCalculation(DamFailureMechanismeCalculationSpecification calculationSpecification) + { + return ((calculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && + ((MStabModelType) calculationSpecification.CalculationModel == MStabModelType.BishopUpliftVan)); + } + + /// + /// Calculate one scenario + /// + /// + private void RunScenario(object scenarioTask) + { + var scenario = (Scenario) scenarioTask; + var scenarioName = scenario.Location.Name; + Debug.WriteLine(String.Format("Start thread for location '{0}'", scenarioName)); + + Location oldLocation = null; + + try + { + oldLocation = scenario.Location; + var scenarioId = scenario.LocationScenarioID; + Debug.WriteLine("Location '{0}', scenario '{1}'", scenarioName, scenarioId); + scenario.ClearResults(); + scenario.ClearErrors(); + + CloneLocationOnScenario(scenario); + + if (scenario.PlLineOffsetBelowDikeToeAtPolder.HasValue) + { + scenario.Location.PlLineOffsetBelowDikeToeAtPolder = scenario.PlLineOffsetBelowDikeToeAtPolder.Value; + } + if (scenario.PlLineOffsetBelowDikeTopAtPolder.HasValue) + { + scenario.Location.PlLineOffsetBelowDikeTopAtPolder = scenario.PlLineOffsetBelowDikeTopAtPolder.Value; + } + if (scenario.PlLineOffsetBelowDikeTopAtRiver.HasValue) + { + scenario.Location.PlLineOffsetBelowDikeTopAtRiver = scenario.PlLineOffsetBelowDikeTopAtRiver.Value; + } + if (scenario.PlLineOffsetBelowShoulderBaseInside.HasValue) + { + scenario.Location.PlLineOffsetBelowShoulderBaseInside = scenario.PlLineOffsetBelowShoulderBaseInside.Value; + } + if (scenario.PlLineOffsetBelowDikeCrestMiddle.HasValue) + { + scenario.Location.PlLineOffsetBelowDikeCrestMiddle = scenario.PlLineOffsetBelowDikeCrestMiddle; + } + if (scenario.PlLineOffsetFactorBelowShoulderCrest.HasValue) + { + scenario.Location.PlLineOffsetFactorBelowShoulderCrest = scenario.PlLineOffsetFactorBelowShoulderCrest; + } + if (scenario.UsePlLineOffsetBelowDikeCrestMiddle.HasValue) + { + scenario.Location.UsePlLineOffsetBelowDikeCrestMiddle = scenario.UsePlLineOffsetBelowDikeCrestMiddle; + } + if (scenario.UsePlLineOffsetFactorBelowShoulderCrest.HasValue) + { + scenario.Location.UsePlLineOffsetFactorBelowShoulderCrest = scenario.UsePlLineOffsetFactorBelowShoulderCrest; + } + if (scenario.HeadPl3.HasValue) + { + scenario.Location.HeadPl3 = scenario.HeadPl3.Value; + } + if (scenario.HeadPl4.HasValue) + { + scenario.Location.HeadPl4 = scenario.HeadPl4.Value; + } + + var selectedKernelType = StabilityKernelType.DamClassic; + var damProjectCalculationSpecification = damProjectData.DamProjectCalculationSpecification; + var spec = damProjectCalculationSpecification.DamCalculationSpecifications.First(); + if (spec != null) + { + selectedKernelType = spec.StabilityKernelType; + } + if (DetermineStabilityUpliftForScenarios(scenario, selectedKernelType)) + { + + // Save the results after each calculation, because these will be deleted in the next calculation + var calculationresults = new List(); + + foreach (var calculationSpecification in damProjectCalculationSpecification.DamCalculationSpecifications) + { + var selectedProbabilisticType = damProjectCalculationSpecification.SelectedProbabilisticType; + var analysisType = DamProjectCalculationSpecification.SelectedAnalysisType; + + Debug.WriteLine("Location '{0}', scenario '{1}' 10", scenarioName, scenarioId); + ValidateSpecification(); + if (IsStabilityBishopLiftVanCalculation(calculationSpecification)) + { + Debug.WriteLine("Location '{0}', scenario '{1}' 11", scenarioName, scenarioId); + CalculateStabilityBishopUpliftvanForScenario(scenario, calculationSpecification, selectedProbabilisticType, analysisType); + } + else + { + Debug.WriteLine("Location '{0}', scenario '{1}' 15", scenarioName, scenarioId); + CalculateOneCalculationTypeForScenario(scenario, calculationSpecification, selectedProbabilisticType, analysisType); + } + Debug.WriteLine("Location '{0}', scenario '{1}' 20", scenarioName, scenarioId); + calculationresults.AddRange(scenario.CalculationResults); + } + // Assign the combined results to the scenario + scenario.CalculationResults.Clear(); + scenario.CalculationResults.AddRange(calculationresults); + } + + } + catch (Exception exception) + { + scenario.Errors.Add(exception.Message); + } + finally + { + if( oldLocation != null) + { + scenario.Location = oldLocation; + } + } + } + + private void CloneLocationOnScenario(Scenario scenario) + { + lock (lockObject) + { +// // TODO missing clone method for Location. This is a dirty way of performing a clone. +// var locationUsedInCalculation = new XmlSerializer().SerializeToString(scenario.Location); +// var location = new XmlDeserializer().XmlDeserializeFromString(locationUsedInCalculation); +// scenario.Location = location; ##Bka replace with object copier. + } + } + + /// + /// Calculates combined stability bishop and upliftvan for scenario. + /// + /// The scenario. + /// The calculation specification. + /// Type of the probabilistic. + /// Type of the analysis. + private void CalculateStabilityBishopUpliftvanForScenario(Scenario scenario, DamFailureMechanismeCalculationSpecification calculationSpecification, ProbabilisticType probabilisticType, AnalysisType analysisType) + { + var bishopCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); + bishopCalculationSpecification.Assign(calculationSpecification); + bishopCalculationSpecification.CalculationModel = MStabModelType.Bishop; + var liftvanCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); + liftvanCalculationSpecification.Assign(calculationSpecification); + liftvanCalculationSpecification.CalculationModel = MStabModelType.UpliftVan; + // Make sure check on uplift is performed before doing UpliftVan calculation + liftvanCalculationSpecification.FailureMechanismeParamatersMStab.IsStabilityCheckOnUplift = true; + + // First perform calculate Bishop + CalculateOneCalculationTypeForScenario(scenario, bishopCalculationSpecification, probabilisticType, analysisType); + // Save the results, because these will be deleted in the next calculation + var calculationresults = new List(); + calculationresults.AddRange(scenario.CalculationResults); + // Now run LiftVan calculation + CalculateOneCalculationTypeForScenario(scenario, liftvanCalculationSpecification, probabilisticType, analysisType); + // Combine Bishop and Liftvan results and assign them to the scenario + calculationresults.AddRange(scenario.CalculationResults); + scenario.CalculationResults.Clear(); + scenario.CalculationResults.AddRange(calculationresults); + } + + /// + /// Calculates one calculation type for scenario. + /// + /// The scenario. + /// The dam failure mechanisme calculation specification. + /// Type of the probabilistic. + /// Type of the analysis. + private void CalculateOneCalculationTypeForScenario( + Scenario scenario, + DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification, + ProbabilisticType probabilisticType, + AnalysisType analysisType) + { + if (damProjectData.WaterBoard.Dikes.Count > 1) + { + throw new Exception("Not possible to calculate with more than one dike"); + } + + var dike = damProjectData.WaterBoard.Dikes[0]; + var damProjectCalculatorLogBuilder = new DamProjectCalculatorCsvExportDataBuilder + ( + dike, + scenario, + damFailureMechanismeCalculationSpecification, + analysisType, + probabilisticType + ); + + scenario.ClearResults(); + scenario.ClearErrors(); + + var damFailureMechanismeCalculator = new DamFailureMechanismeCalculator( + damProjectData.ProgramType, + damFailureMechanismeCalculationSpecification, + MStabProgramPath, + SlopeWProgramPath, + dike.MapForSoilGeometries2D, + probabilisticType); + damFailureMechanismeCalculator.CalculationBaseDirectory = CalculationBaseDirectory; + + if (analysisType == AnalysisType.AdaptNWO) + { + damFailureMechanismeCalculator.NonWaterRetainingObject = dike.NonWaterRetainingObjects[0]; + } + + if (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside || + damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside) + { + StabilityCalculator.ModelSubDirectory = damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.Model.ToString(); + } + + try + { + damFailureMechanismeCalculator.Calculate(analysisType, scenario); + + foreach (var error in scenario.Errors) + { + var logMessage = new LogMessage(LogMessageType.Error, null, error); + damFailureMechanismeCalculator.ErrorMessages.Add(logMessage); + } + foreach (var errorMessage in damFailureMechanismeCalculator.ErrorMessages) + { + //LogManager.Messages.Add(errorMessage);##Bka + } + + var recordIndex = 0; + var firstNwoSoilProfileProbability = true; + var validSoilProfileProbabilities = DamFailureMechanismeCalculator.SelectProbabilitiesForFailureMechanism( + damFailureMechanismeCalculationSpecification.FailureMechanismSystemType, scenario.Location.Segment.SoilProfileProbabilities); + foreach (var soilProfileProbability in validSoilProfileProbabilities) + { + if (analysisType == AnalysisType.AdaptNWO) + { + if (firstNwoSoilProfileProbability) + { + // for NWO, only add results for every first soilProfileProbability as the others are already part of the nwo results. + foreach (var nwoResult in scenario.NwoResults) + { + var resultMessage = scenario.GetResultMessage( + nwoResult.SoilProfileProbability.SoilProfile, + nwoResult.SoilProfileProbability.SoilGeometry2DName); + // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a scv file + damProjectCalculatorLogBuilder.Append( + @"""", + ++recordIndex, + " - ", + resultMessage, + " - ", + nwoResult.NwoId, + " - ", + nwoResult.LocationXrdStart, + " - ", + nwoResult.MStabResults.CalculationName, + @"""" + ); + + scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(nwoResult.SoilProfileProbability, scenario.NwoResults.IndexOf(nwoResult))); + scenario.CalculationResult = CalculationResult.Succeeded; + } + foreach (var error in scenario.Errors) + { + damProjectCalculatorLogBuilder.Append(error); + scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); + scenario.CalculationResult = CalculationResult.Succeeded; + } + firstNwoSoilProfileProbability = false; + } + else + { + if (scenario.CalculationResult != CalculationResult.NoRun) + { + // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a csv file + string resultMessage = scenario.GetResultMessage(soilProfileProbability.SoilProfile, + soilProfileProbability.SoilGeometry2DName); + damProjectCalculatorLogBuilder.Append( + @"""", + ++recordIndex, + " - ", + resultMessage, + @"""" + ); + + scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); + } + scenario.CalculationResult = CalculationResult.Succeeded; + } + } + else + { + // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a scv file + var resultMessage = scenario.GetResultMessage( + soilProfileProbability.SoilProfile, + soilProfileProbability.SoilGeometry2DName); + + damProjectCalculatorLogBuilder.Append( + @"""", + ++recordIndex, + " - ", + resultMessage, + @"""" + ); + + scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability, damFailureMechanismeCalculationSpecification.StabilityKernelType)); + scenario.CalculationResult = CalculationResult.Succeeded; + } + } + } + catch (Exception exception) + { + damProjectCalculatorLogBuilder.Append("Error: ", exception.Message); + + var innerException = exception.InnerException; + while (innerException != null) + { + damProjectCalculatorLogBuilder.Append(": ", innerException.Message); + innerException = innerException.InnerException; + } + + foreach (var error in scenario.Errors) + { + var logMessage = new LogMessage(LogMessageType.Error, null, error); + //LogManager.Messages.Add(logMessage);##Bka + } + foreach (var errorMessage in damFailureMechanismeCalculator.ErrorMessages) + { + // LogManager.Messages.Add(errorMessage);##Bka + } + + foreach (var soilProfileProbability in scenario.Location.Segment.SoilProfileProbabilities) + { + if (soilProfileProbability.SegmentFailureMechanismType == null || + soilProfileProbability.SegmentFailureMechanismType == damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) + { + scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); + scenario.CalculationResult = CalculationResult.UnexpectedError; + } + } + throw; + } + } + + /// + /// Determine for each scenario if uplift occurs + /// + /// + /// + /// + private bool DetermineStabilityUpliftForScenarios(Scenario scenario, StabilityKernelType stabilityKernelType) + { + if (stabilityKernelType == StabilityKernelType.AdvancedWti || + stabilityKernelType == StabilityKernelType.AdvancedDotNet) + { + return true; + } + var res = true; + Dike dike = damProjectData.WaterBoard.Dikes[0]; + double upliftCriterion = scenario.GetUpliftCriterionStability(scenario.Location.ModelFactors.UpliftCriterionStability); + foreach (var soilProfileProbability in scenario.Location.Segment.SoilProfileProbabilities) + { + if (soilProfileProbability.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityInside || + soilProfileProbability.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityOutside || + soilProfileProbability.SegmentFailureMechanismType == null) + { + try + { + SurfaceLine2 surfaceLineWithNewHeight = DamFailureMechanismeCalculator.RedesignSurfaceLineHeight(FailureMechanismSystemType.StabilityInside, scenario, + scenario.Location.LocalXZSurfaceLine2); + // for scenarios the uplift should be calculated with the redesigned height, else a problem may occur with the waterlevel above the dike + var upliftSituation = new UpliftSituation(); + PLLines plLines = CreateAllPLLines(out upliftSituation, scenario.RiverLevel, + scenario.RiverLevelLow, scenario.Location, soilProfileProbability, + surfaceLineWithNewHeight); + + if (plLines != null) + { + string fullSoilGeometry2DName = (soilProfileProbability.SoilGeometry2DName == null) ? null : + Path.Combine(ProjectDataDirectory, Path.Combine(dike.MapForSoilGeometries2D, soilProfileProbability.SoilGeometry2DName)); + double? upliftFactor = GetLowestUpliftFactor(surfaceLineWithNewHeight, + soilProfileProbability.SoilProfile, fullSoilGeometry2DName, plLines, scenario.Location); + upliftSituation.IsUplift = (upliftFactor < upliftCriterion); + } + else + { + upliftSituation.IsUplift = false; + } + scenario.SetStabilityUpliftSituation(soilProfileProbability.SoilProfile, + soilProfileProbability.SoilGeometry2DName, upliftSituation); + } + catch (Exception exception) + { + string errorMessage = String.Format("{0} in location '{1}' scenario '{2}' soilprofile '{3}'", + exception.Message, scenario.Location.Name, + scenario.LocationScenarioID, + soilProfileProbability.SoilGeometryName); + scenario.SetResultMessage(soilProfileProbability.SoilProfile, + soilProfileProbability.SoilGeometry2DName, exception.Message); + var resultRecord = new CsvExportData( + "Error: " + exception.Message, + dike, + damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications[0], + scenario, + soilProfileProbability.SoilProfile, + soilProfileProbability.SoilGeometry2DName, + DamProjectCalculationSpecification.SelectedAnalysisType, + 0, + damProjectData.DamProjectCalculationSpecification.SelectedProbabilisticType); + scenario.CalculationResults.Add(resultRecord); + scenario.Errors.Add(errorMessage); + scenario.CalculationResult = CalculationResult.RunFailed; + res = false; + } + } + } + foreach (var error in scenario.Errors) + { + var logMessage = new LogMessage(LogMessageType.Error, null, error); + //LogManager.Messages.Add(logMessage); ##Bka + } + return res; + } + + /// + /// Determines whether the specified calculation result is Bishop. + /// + /// The calculation result. + /// + /// true if it is Bishop; otherwise, false. + /// + private bool IsBishopResult(CsvExportData calculationResult) + { + return ((calculationResult.DamFailureMechanismeCalculation.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && + (calculationResult.DamFailureMechanismeCalculation.FailureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.Bishop)); + } + + /// + /// Determines whether the specified calculation result is UpliftVan. + /// + /// The calculation result. + /// + /// true if it is UpliftVan; otherwise, false. + /// + private bool IsUpliftVanResult(CsvExportData calculationResult) + { + return ((calculationResult.DamFailureMechanismeCalculation.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && + (calculationResult.DamFailureMechanismeCalculation.FailureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.UpliftVan)); + } + + /// + /// Create new results depending on Uplift + /// + /// + private void PostprocessForStabilityUpliftVanBishop(ref List> allCalculationResults) + { + var normativeCalculationResults = new List(); + var bishopCalculationResults = new List(); + var upliftVanCalculationResults = new List(); + + // First collect all Bishop and Uplift calculations + foreach (var calculationResults in allCalculationResults) + { + if (calculationResults.Count > 0) + { + foreach (var calculationResult in calculationResults) + { + if (IsBishopResult(calculationResult)) + { + bishopCalculationResults.Add(calculationResult); + } + if (IsUpliftVanResult(calculationResult)) + { + upliftVanCalculationResults.Add(calculationResult); + } + } + } + } + if ((bishopCalculationResults.Any()) && (upliftVanCalculationResults.Any())) + { + var bishopLiftvancalculation = bishopCalculationResults[0].DamFailureMechanismeCalculation.Clone(); + bishopLiftvancalculation.FailureMechanismeParamatersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan; + foreach (var bishopCalculationRecord in bishopCalculationResults) + { + CsvExportData liftVanCalculationResult = (from calculationResult in upliftVanCalculationResults + where calculationResult.LocationName.Equals(bishopCalculationRecord.LocationName) && + calculationResult.ScenarioName.Equals(bishopCalculationRecord.ScenarioName) && + calculationResult.StabilityProfileName.Equals(bishopCalculationRecord.StabilityProfileName) + select calculationResult).ToList().FirstOrDefault(); + CsvExportData normativeCalculationResult = SelectStabilityNormativeResult(bishopCalculationRecord, liftVanCalculationResult, + bishopCalculationRecord.AnalysisType, bishopCalculationRecord.ProbabilisticType); + // Clone this result, to make sure the original won't be changed + normativeCalculationResult = (CsvExportData) normativeCalculationResult.Clone(); + normativeCalculationResult.DamFailureMechanismeCalculation = bishopLiftvancalculation; + normativeCalculationResults.Add(normativeCalculationResult); + // Add the normative result also to the scenario + normativeCalculationResult.Scenario.CalculationResults.Add(normativeCalculationResult); + } + allCalculationResults.Add(normativeCalculationResults); + } + } + + /// + /// Select which result is the norm for stability Bishop/UpliftVan calculation + /// + /// + /// + /// + private CsvExportData SelectStabilityNormativeResult(CsvExportData bishopCalculationRecord, CsvExportData liftVanCalculationResult, AnalysisType analysisType, ProbabilisticType probabilisticType) + { + switch (analysisType) + { + case AnalysisType.NoAdaption: + switch (probabilisticType) + { + case ProbabilisticType.Deterministic: + return SelectStabilityNormativeResultDeterministicNormal(liftVanCalculationResult, bishopCalculationRecord); + case ProbabilisticType.Probabilistic: + case ProbabilisticType.ProbabilisticFragility: + return SelectStabilityNormativeResultProbabilisticNormal(liftVanCalculationResult, bishopCalculationRecord); + default: + throw new ArgumentOutOfRangeException("probabilisticType"); + } + case AnalysisType.AdaptNWO: + case AnalysisType.AdaptGeometry: + switch (probabilisticType) + { + case ProbabilisticType.Deterministic: + return SelectStabilityNormativeResultDeterministicDesign(liftVanCalculationResult, bishopCalculationRecord); + case ProbabilisticType.Probabilistic: + case ProbabilisticType.ProbabilisticFragility: + return SelectStabilityNormativeResultProbabilisticDesign(liftVanCalculationResult, bishopCalculationRecord); + default: + throw new ArgumentOutOfRangeException("probabilisticType"); + } + default: + throw new ArgumentOutOfRangeException("analysisType"); + } + } + + /// + /// Select which result is the norm for stability Bishop/UpliftVan normal deterministic calculation + /// + /// + /// + /// + private CsvExportData SelectStabilityNormativeResultDeterministicNormal(CsvExportData liftVanCalculationResult, CsvExportData bishopCalculationRecord) + { + if ((liftVanCalculationResult != null) && (liftVanCalculationResult.StabilitySafetyFactor.HasValue)) + { + if ((bishopCalculationRecord != null) && (bishopCalculationRecord.StabilitySafetyFactor.HasValue)) + { + return (liftVanCalculationResult.StabilitySafetyFactor.Value < bishopCalculationRecord.StabilitySafetyFactor.Value + ? liftVanCalculationResult + : bishopCalculationRecord); + } + else + { + return liftVanCalculationResult; + } + } + else + { + return bishopCalculationRecord; + } + } + + /// + /// Select which result is the norm for stability Bishop/UpliftVan design probabilistic calculation + /// + /// + /// + /// + private CsvExportData SelectStabilityNormativeResultProbabilisticDesign(CsvExportData liftVanCalculationResult, CsvExportData bishopCalculationRecord) + { + throw new ApplicationException("Not implemented yet"); + } + + /// + /// Select which result is the norm for stability Bishop/UpliftVan design deterministic calculation + /// + /// + /// + /// + private CsvExportData SelectStabilityNormativeResultDeterministicDesign(CsvExportData liftVanCalculationResult, CsvExportData bishopCalculationRecord) + { + if ((liftVanCalculationResult != null) && (liftVanCalculationResult.StabilitySafetyFactor.HasValue)) + { + if ((bishopCalculationRecord != null) && (bishopCalculationRecord.StabilitySafetyFactor.HasValue)) + { + bool dla = liftVanCalculationResult.DikeLength.HasValue; + dla = dla && bishopCalculationRecord.DikeLength.HasValue; + if (dla && (Math.Abs(liftVanCalculationResult.DikeLength.Value - bishopCalculationRecord.DikeLength.Value) < GeometryPoint.Precision)) + { + return (liftVanCalculationResult.StabilitySafetyFactor < + bishopCalculationRecord.StabilitySafetyFactor + ? liftVanCalculationResult + : bishopCalculationRecord); + } + else + { + return (liftVanCalculationResult.DikeLength > bishopCalculationRecord.DikeLength + ? liftVanCalculationResult + : bishopCalculationRecord); + } + } + else + { + return liftVanCalculationResult; + } + } + else + { + return bishopCalculationRecord; + } + } + + /// + /// Select which result is the norm for stability Bishop/UpliftVan normal probabilistic calculation + /// + /// + /// + /// + private CsvExportData SelectStabilityNormativeResultProbabilisticNormal(CsvExportData liftVanCalculationResult, CsvExportData bishopCalculationRecord) + { + throw new ApplicationException("Not implemented yet"); + } + + /// + /// Create PLLines with selected model + /// + /// + /// + /// + /// + /// + /// the created pl lines + private PLLines CreateAllPLLines(out UpliftSituation upliftSituation, double waterLevel, double? waterLevelLow, Location location, SoilGeometryProbability soilProfileProbability, SurfaceLine2 surfaceLine) + { + switch (location.PLLineCreationMethod) + { + case PLLineCreationMethod.ExpertKnowledgeLinearInDike: + case PLLineCreationMethod.ExpertKnowledgeRRD: + case PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD: + return CreateAllPLLinesExpertKnowledge(out upliftSituation, waterLevel, waterLevelLow, location, soilProfileProbability, surfaceLine); +// case PLLineCreationMethod.DupuitStatic: +// string geometryDirectory = DamProjectData.ProjectWorkingPath; +// return CreateAllPLLinesDupuit(out upliftSituation, location, soilProfileProbability, surfaceLine, geometryDirectory, waterLevel); ##Bka + case PLLineCreationMethod.DupuitDynamic: + throw new DamCalculationException("PL-Line creation with DupuitDynamic not yet implemented"); + default: + upliftSituation.Pl3HeadAdjusted = 0; + upliftSituation.Pl3LocationXMinUplift = 0; + upliftSituation.Pl3MinUplift = 0; + upliftSituation.Pl4HeadAdjusted = 0; + upliftSituation.Pl4LocationXMinUplift = 0; + upliftSituation.Pl4MinUplift = 0; + upliftSituation.IsUplift = false; // must be determined later on; just to avoid compiler error + return null; + } + } + + /// + /// Create PLLines with Dupuit model + /// + /// the created pl lines +// private PLLines CreateAllPLLinesDupuit(out UpliftSituation upliftSituation, Location location, SoilGeometryProbability soilProfileProbability, +// SurfaceLine2 surfaceLine, String geometryDirectory, double waterLevel) +// { +// var timeSerieIn = new TimeSerie(); +// timeSerieIn.Entries.Add(new TimeSerieEntry(DateTime.Now, waterLevel)); +// var plLinesCreatorDupuit = new PLLinesCreatorDupuit +// { +// Geometry2DData = Geometry2DDataCreator.CreateGeometry2DData(location, soilProfileProbability, surfaceLine, geometryDirectory), +// SurfaceLine = location.LocalXZSurfaceLine2, +// WaterLevelTimeserie = timeSerieIn, +// SoilList = location.SoilList, +// PolderLevel = location.PolderLevel, +// IsReverseLayerOrder = true +// }; +// +// upliftSituation.Pl3HeadAdjusted = 0; +// upliftSituation.Pl3LocationXMinUplift = 0; +// upliftSituation.Pl3MinUplift = 0; +// upliftSituation.Pl4HeadAdjusted = 0; +// upliftSituation.Pl4LocationXMinUplift = 0; +// upliftSituation.Pl4MinUplift = 0; +// upliftSituation.IsUplift = false; // must be determined later on; just to avoid compiler error +// plLinesCreatorDupuit.CreateAllPlLines(); +// +// return null; +// } + + /// + /// Create PLLines with expert knowledge + /// + /// + /// + /// + /// + /// + /// the created pl lines + private PLLines CreateAllPLLinesExpertKnowledge(out UpliftSituation upliftSituation, double waterLevel, + double? waterLevelLow, Location location, SoilGeometryProbability soilProfileProbability, + SurfaceLine2 surfaceLine) + { + var plLinesCreator = new PLLinesCreator(); + // Determine geometry type + SoilGeometryType soilGeometryType = soilProfileProbability.SoilGeometryType; + string mapForSoilGeometries2D = location.MapForSoilGeometries2D; + SoilProfile1D soilProfile = soilProfileProbability.SoilProfile; + string soilGeometry2DName = soilProfileProbability.SoilGeometry2DName; + if ((soilProfileProbability.SoilGeometry2DName != null) && (mapForSoilGeometries2D != null)) + { + soilGeometry2DName = Path.Combine(mapForSoilGeometries2D, soilGeometry2DName); + soilGeometry2DName = Path.Combine(ProjectDataDirectory, soilGeometry2DName); + } + + plLinesCreator.WaterLevelRiverHigh = waterLevel; + plLinesCreator.WaterLevelRiverLow = waterLevelLow; + plLinesCreator.IsUseLowWaterLevel = (damProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside); + + plLinesCreator.SurfaceLine = surfaceLine; + plLinesCreator.WaterLevelPolder = location.PolderLevel; + plLinesCreator.HeadInPLLine2 = location.HeadPL2; + plLinesCreator.HeadInPLLine3 = location.HeadPl3; + plLinesCreator.HeadInPLLine4 = location.HeadPl4; + plLinesCreator.ModelParametersForPLLines = location.CreateModelParametersForPLLines(); + plLinesCreator.SoilProfile = soilProfile; + plLinesCreator.SoilGeometry2DName = soilGeometry2DName; + plLinesCreator.SoilGeometryType = soilGeometryType; + plLinesCreator.GaugePLLines = location.GaugePLLines; + plLinesCreator.Gauges = location.Gauges; + plLinesCreator.GaugeMissVal = location.GaugeMissVal; + plLinesCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; // for stability this must set to true + plLinesCreator.SoilList = location.SoilList; + plLinesCreator.DikeEmbankmentMaterial = location.SoilList.GetSoilByName(location.DikeEmbankmentMaterial); + plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; + plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; + plLinesCreator.PlLineOffsetBelowShoulderBaseInside = location.PlLineOffsetBelowShoulderBaseInside; + plLinesCreator.PlLineOffsetBelowDikeToeAtPolder = location.PlLineOffsetBelowDikeToeAtPolder; + plLinesCreator.PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle; + plLinesCreator.PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest; + plLinesCreator.UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle; + plLinesCreator.UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest; + plLinesCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; + + //PLLines plLines = plLinesCreator.CreateAllPLLines(location); ##Bka + upliftSituation.Pl3HeadAdjusted = plLinesCreator.Pl3HeadAdjusted; + upliftSituation.Pl3LocationXMinUplift = plLinesCreator.Pl3LocationXMinUplift; + upliftSituation.Pl3MinUplift = plLinesCreator.Pl3MinUplift; + upliftSituation.Pl4HeadAdjusted = plLinesCreator.Pl4HeadAdjusted; + upliftSituation.Pl4LocationXMinUplift = plLinesCreator.Pl4LocationXMinUplift; + upliftSituation.Pl4MinUplift = plLinesCreator.Pl4MinUplift; + upliftSituation.IsUplift = false; // must be determined later on; just to avoid compiler error + return null; //plLines; ##Bka + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/LayerDetector.cs (revision 334) @@ -0,0 +1,367 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + ///When publisherEventArgs vertical is drawn in the Geometry, this reports the intersection layers. + /// + /// Step 1: To Determine the possibility of Surface and Vertical intersection, Min/Max of each surface + /// is checked with Vertical's X coordinate. + /// Step 2: Intersection Points of each surface with the vertical are determined and added to pointlist + /// in sorted order (greatest Y at first). + /// Step 3: For forming the Intersection Curves, the consecutive points in the pointlist are checked if + /// their mid-point lies in the surface and not in the innerloop. They are stored in the sorted order. + /// + public class LayerDetector + { + private readonly List intersectionSurfacesList = new List(); + private readonly List layerList = new List(); + private readonly List pointList = new List(); + private readonly IList soilSurfaces; + + private double verticalXCoordinate; + + /// + /// Initializes a new instance of the class. + /// + /// The soil surfaces. + public LayerDetector(IList soilSurfaces) + { + this.soilSurfaces = soilSurfaces; + } + + /// + /// Gets the layer list. + /// + /// + /// The layer list. + /// + public List LayerList + { + get + { + return layerList; + } + } + + + /// + /// Determines the materials. + /// + /// A vertical x coordinate. + public void DetermineMaterials(double aVerticalXCoordinate) + { + verticalXCoordinate = aVerticalXCoordinate; + + // The detection process + StartDetection(); + } + + private void StartDetection() + { + ClearLists(); + GetIntersectionPointList(); + DeleteDuplicateCurve(); + } + + private void GetIntersectionPointList() + { + foreach (var surface in soilSurfaces) + { + if (intersectionSurfacesList.Contains(surface) == false) + { + foreach (var curve in surface.GeometrySurface.OuterLoop.CurveList) + { + FindIntersections(curve.HeadPoint, curve.EndPoint, surface); + } + // check if it has inner loops + if (surface.GeometrySurface.InnerLoops.Count > 0) + { + List loopList = surface.GeometrySurface.InnerLoops; + foreach (var loop in loopList) + { + foreach (var curve in loop.CurveList) + { + FindIntersections(curve.HeadPoint, curve.EndPoint, surface); + } + } + } + //create intersection curves + if (pointList.Count > 0) + { + GetLayerList(); + pointList.Clear(); + } + } + } + } + + // finds intersections with regard to publisherEventArgs curve + private void FindIntersections(Point2D aHeadpoint, Point2D aEndPoint, SoilLayer2D aSurfaceRefKey) + { + double maxvalue = 999999999.0; + double minvalue = -999999999.0; + var verticalHeadPoint = new Point2D(verticalXCoordinate, maxvalue); + var verticalEndPoint = new Point2D(verticalXCoordinate, minvalue); + Point2D intersectionPoint; + + LineIntersection intersectionResult = Routines2D.DetermineIf2DLinesIntersectStrickly(verticalHeadPoint.X, verticalHeadPoint.Z, + verticalEndPoint.X, verticalEndPoint.Z, aHeadpoint.X, aHeadpoint.Z, aEndPoint.X, aEndPoint.Z, out intersectionPoint); + + if (intersectionResult == LineIntersection.Intersects) + { + AddPointToList(new LayerIntersectionPoint(intersectionPoint, aSurfaceRefKey)); + } + else if (intersectionResult == LineIntersection.NoIntersection || intersectionResult == LineIntersection.Parallel) + { + const double cEpsilon = 1.0e-3; + if ((Routines2D.DoesPointExistInLine(verticalHeadPoint.X, verticalHeadPoint.Z, verticalEndPoint.X, verticalEndPoint.Z, + aHeadpoint.X, aHeadpoint.Z, cEpsilon)) && (Routines2D.DoesPointExistInLine(verticalHeadPoint.X, verticalHeadPoint.Z, + verticalEndPoint.X, verticalEndPoint.Z, aEndPoint.X, aEndPoint.Z, cEpsilon))) + { + AddPointToList(new LayerIntersectionPoint(aHeadpoint, aSurfaceRefKey)); + AddPointToList(new LayerIntersectionPoint(aEndPoint, aSurfaceRefKey)); + } + } + } + + private void GetLayerList() + { + int pointCount = pointList.Count; + + if (pointCount > 1) + { + object point1 = null; + + for (int index = 0; index < pointCount; index++) + { + if (point1 == null) + { + point1 = pointList[index]; + } + else + { + //point not same condition + bool notSameCondition = ((pointList[index].IntersectionPoint.X.IsNearEqual(( + (LayerIntersectionPoint) point1).IntersectionPoint.X)) && (pointList[index].IntersectionPoint.Z.IsNearEqual(( + (LayerIntersectionPoint) point1).IntersectionPoint.Z))); + + if (notSameCondition == false) + { + object point2 = pointList[index]; + FindLayer((LayerIntersectionPoint) point1, (LayerIntersectionPoint) point2); + point1 = pointList[index]; + } + } + } + } + } + + private void ClearLists() + { + pointList.Clear(); + layerList.Clear(); + intersectionSurfacesList.Clear(); + } + + // To make it top to bottom + private void CheckTopToBottom(ref Point2D aHeadPoint, ref Point2D aEndPoint) + { + if (aHeadPoint.Z.IsLessThan(aEndPoint.Z)) + { + var temp = aHeadPoint; + aHeadPoint = aEndPoint; + aEndPoint = temp; + } + } + + // Finds what kind of passage does this curve make with regard to the surface + private void FindLayer(LayerIntersectionPoint aPoint1, LayerIntersectionPoint aPoint2) + { + var midPoint = new GeometryPoint() + { + X = (aPoint1.IntersectionPoint.X + aPoint2.IntersectionPoint.X)/2, + Z = (aPoint1.IntersectionPoint.Z + aPoint2.IntersectionPoint.Z)/2 + }; + + // check where the mid point lies + PointInPolygon polygonResult = Routines2D.CheckIfPointIsInPolygon(aPoint1.SurfaceRefKey.GeometrySurface.OuterLoop, + midPoint.X, midPoint.Z); + + + var startPoint = aPoint1.IntersectionPoint; + var endPoint = aPoint2.IntersectionPoint; + + Soil soil = aPoint1.SurfaceRefKey.Soil; + var isAquifer = aPoint1.SurfaceRefKey.IsAquifer; + if (polygonResult == PointInPolygon.InsidePolygon || polygonResult == PointInPolygon.OnPolygonEdge) + { + bool isPresentInInnerLoop = false; + List innerLoopList = aPoint1.SurfaceRefKey.GeometrySurface.InnerLoops; + foreach (var innerLoop in innerLoopList) + { + PointInPolygon innerPolygonResult = Routines2D.CheckIfPointIsInPolygon(innerLoop, midPoint.X, midPoint.Z); + if (innerPolygonResult != PointInPolygon.OutsidePolygon) + { + isPresentInInnerLoop = true; + } + } + if (isPresentInInnerLoop == false) + { + var layerCurve = new Layer(startPoint, endPoint, soil) + { + IsAquifer = isAquifer + }; + AddLayerToList(layerCurve); + } + } + } + + // Adds the LayerIntersectionCurve in publisherEventArgs sorted order - Top to bottom + private void AddLayerToList(Layer aLayer) + { + int count = layerList.Count; + bool isAdded = false; + var startPoint = aLayer.StartPoint; + var endPoint = aLayer.EndPoint; + CheckTopToBottom(ref startPoint, ref endPoint); + aLayer.StartPoint = startPoint; + aLayer.EndPoint = endPoint; + + if (count == 0) + { + layerList.Add(aLayer); + } + else + { + for (int index = 0; index < count; index++) + { + if (aLayer.StartPoint.Z.IsGreaterThanOrEqualTo(layerList[index].StartPoint.Z)) + { + layerList.Insert(index, aLayer); + isAdded = true; + break; + } + } + if (isAdded == false) + { + layerList.Add(aLayer); + } + } + } + + // Adds the LayerIntersectionPoints (ignores duplicates when found within same surface) + private void AddPointToList(LayerIntersectionPoint aPoint) + { + if (intersectionSurfacesList.Contains(aPoint.SurfaceRefKey) == false) + { + intersectionSurfacesList.Add(aPoint.SurfaceRefKey); + } + + int count = pointList.Count; + bool isPointFound = false; + if (count > 0) + { + for (int index = 0; index < count; index++) // to find duplicate + { + if ((aPoint.IntersectionPoint.X.IsNearEqual(pointList[index].IntersectionPoint.X)) + && (aPoint.IntersectionPoint.Z.IsNearEqual(pointList[index].IntersectionPoint.Z)) + && (aPoint.SurfaceRefKey == pointList[index].SurfaceRefKey)) + { + isPointFound = true; + break; + } + } + if (isPointFound == false) // to be added in the sorted order Z greater at the top + { + bool isAdded = false; + for (int index = 0; index < count; index++) + { + if (aPoint.IntersectionPoint.Z.IsGreaterThanOrEqualTo(pointList[index].IntersectionPoint.Z)) + { + pointList.Insert(index, aPoint); + isAdded = true; + break; + } + } + + if (isAdded == false) + { + pointList.Add(aPoint); + } + } + } + else + { + pointList.Add(aPoint); + } + } + + /// + /// if two surfaces share the same curve choose any one surface + /// + private void DeleteDuplicateCurve() + { + var duplicateList = new List(); + int curveCount = layerList.Count; + object curve1 = null; + + for (int index = 0; index < curveCount; index++) + { + if (curve1 == null) + { + curve1 = layerList[index]; + } + else + { + var curve2 = layerList[index]; + + // check if there is overlapping + var curveOne = (Layer) curve1; + var curveTwo = curve2; + + if (curveOne.StartPoint.Z.IsGreaterThanOrEqualTo(curveTwo.StartPoint.Z) && curveOne.EndPoint.Z.IsLessThanOrEqualTo(curveTwo.EndPoint.Z)) + { + duplicateList.Add(layerList[index]); + } + // Case - No space between two consecutive curves + else + { + curve1 = layerList[index]; + } + } + } + + for (int index = 0; index < duplicateList.Count; index++) + { + if (layerList.Contains(duplicateList[index])) + { + layerList.Remove(duplicateList[index]); + } + } + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Deltares.DamEngine.Data.csproj (revision 334) @@ -0,0 +1,192 @@ + + + + + Debug + AnyCPU + {B7A49C1A-1C91-4D72-ABA9-9FBAC2509D8E} + Library + Properties + Deltares.DamEngine.Data + Deltares.DamEngine.Data + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs (revision 334) @@ -0,0 +1,717 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Interface for providing the 1D Soil Profile + /// + public interface ISoilProfileProvider + { + /// + /// Gets the soil profile. + /// + /// + /// The soil profile. + /// + SoilProfile1D SoilProfile { get; } + } + + /// + /// 1D Soil Profile Object + /// + public class SoilProfile1D : SoilProfile + { + private const double defaultBottomLayerHeight = 20.0; + + private readonly DelegatedList layers = new DelegatedList(); + private double bottomLevel = double.NaN; + + /// + /// Default constructor + /// + public SoilProfile1D() + { + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilProfile1D"); + layers.AddMethod = AddLayer; + } + + /// + /// Constructor to construct simple soilprofile + /// + /// + /// + /// + public SoilProfile1D(double topLevel, double bottomLevel, Soil soil) + : this() + { + this.bottomLevel = bottomLevel; + layers.Add(new SoilLayer1D(soil, topLevel)); + } + + /// + /// Gets the soil layer collection for this profile + /// + public IList Layers + { + get + { + return layers; + } + } + + /// + /// Gets the number of layers. + /// + /// + /// The layer count. + /// + [XmlIgnore] + public int LayerCount + { + get + { + return layers.Count; + } + } + + /// + /// Gets or sets the bottom level. + /// + /// + /// The bottom level. + /// + public double BottomLevel + { + get + { + if (double.IsNaN(bottomLevel) && layers.Count > 0) + { + bottomLevel = Layers.Last().TopLevel - defaultBottomLayerHeight; + } + + return bottomLevel; + } + set + { + if (double.IsNaN(bottomLevel) || (Math.Abs(value - bottomLevel) > GeometryConstants.Accuracy)) + { + bottomLevel = value; + } + } + } + + /// + /// Gets or sets the top level. + /// + /// + /// The top level. + /// + public double TopLevel + { + get + { + return layers.Any() ? layers.First().TopLevel : BottomLevel; + } + } + + /// + /// The highest aquifer layer, can be null if not aquifer is present + /// + [Validate] + public SoilLayer1D TopAquiferLayer + { + get + { + IList sortedLayers = Layers.OrderByDescending(l => l.TopLevel).ToList(); + SoilLayer1D aquiferLayer = null; + + // Search the highest aquifer layer + for (int layerIndex = 0; layerIndex < sortedLayers.Count; layerIndex++) + { + var layer = sortedLayers[layerIndex]; + if (IsAquiferLayer(layer)) + { + aquiferLayer = layer; + break; + } + } + return aquiferLayer; + } + } + + /// + /// Gets the toppest aquifer layer of the deepest cluster of aquifers + /// + /// + /// The toppest aquifer layer in the deepest cluster of aquifers + /// + public SoilLayer1D BottomAquiferLayer + { + get + { + IList sortedLayers = Layers.OrderBy(l => l.TopLevel).ToList(); + SoilLayer1D aquiferLayer = null; + int aquiferIndex = -1; + + // Search deepest aquifer layer + for (int layerIndex = 0; layerIndex < sortedLayers.Count; layerIndex++) + { + SoilLayer1D layer = sortedLayers[layerIndex]; + if (IsAquiferLayer(layer)) + { + aquiferIndex = layerIndex; + aquiferLayer = layer; + break; + } + } + + // aquifer may consists of more then 1 connected (aquifer) layers + // Search all layers above the first found aquifer to find top aquifer layer + if (aquiferIndex >= 0) + { + for (int layerIndex = aquiferIndex + 1; layerIndex < sortedLayers.Count; layerIndex++) + { + var layer = sortedLayers[layerIndex]; + if (IsAquiferLayer(layer)) + { + aquiferLayer = layer; + } + else + { + break; + } + } + } + return aquiferLayer; + } + } + + /// + /// Gets the highest aquifer in the highest cluster of in-between aquifers. + /// The top layer of a cluster of in-between aquifer can't be the highest layer of the soil profile. + /// + /// + /// The highest aquifer in the highest in-between cluster of aquifers + /// + public SoilLayer1D InBetweenAquiferLayer + { + get + { + IList sortedLayers = Layers.OrderByDescending(l => l.TopLevel).ToList(); + SoilLayer1D aquiferLayer = null; + + // Search the highest aquifer layer with an aquitard above + for (int layerIndex = 1; layerIndex < sortedLayers.Count; layerIndex++) + { + var previousLayer = sortedLayers[layerIndex - 1]; + var layer = sortedLayers[layerIndex]; + if (IsAquiferLayer(layer) && !IsAquiferLayer(previousLayer)) + { + aquiferLayer = layer; + break; + } + } + + // If highest aquifer layer is bottom aquifer layer, there is no in between aquiferlayer + if (aquiferLayer == BottomAquiferLayer) + { + aquiferLayer = null; + } + return aquiferLayer; + } + } + + /// + /// Gets the lowest layer in the highest cluster of in-between aquifers + /// + /// + /// The lowest layer in the highest cluster of in-between aquifers + /// + public SoilLayer1D BottomLayerOfInBetweenAquiferCluster + { + get + { + IList sortedLayers = Layers.OrderByDescending(l => l.TopLevel).ToList(); + SoilLayer1D highestAquiferLayer = null; + SoilLayer1D aquiferLayer = null; + int indexHighestAquifer = -1; + + // Search the index of the highest aquifer layer + for (int layerIndex = 1; layerIndex < sortedLayers.Count; layerIndex++) + { + var previousLayer = sortedLayers[layerIndex - 1]; + var layer = sortedLayers[layerIndex]; + if (IsAquiferLayer(layer) && !IsAquiferLayer(previousLayer)) + { + highestAquiferLayer = layer; + indexHighestAquifer = layerIndex; + break; + } + } + + // If highest aquifer layer is bottom aquifer layer, there is no in between aquiferlayer + if (highestAquiferLayer == BottomAquiferLayer) + { + return null; + } + + // in-between aquifers cluster may consists of more then 1 connected (aquifer) layers. + // Search all layers below the found highest aquifer to find bottom aquifer layer. + if (indexHighestAquifer >= 0) + { + for (int layerIndex = indexHighestAquifer; layerIndex < sortedLayers.Count; layerIndex++) + { + var layer = sortedLayers[layerIndex]; + + if (IsAquiferLayer(layer)) + { + aquiferLayer = layer; + } + else + { + break; + } + } + } + return aquiferLayer; + } + } + + /// + /// Gets (calculates) the height for a given layer in the profile + /// + /// The layer to process + /// The height + public double GetLayerHeight(SoilLayer1D soilLayer) + { + var layerIndex = layers.IndexOf(soilLayer); + var soilLayerBelow = (layerIndex < layers.Count - 1) ? layers[layerIndex + 1] : null; + var levelBelow = (soilLayerBelow != null) ? soilLayerBelow.TopLevel : BottomLevel; + return soilLayer.TopLevel - levelBelow; + } + + /// + /// Make sure the last layer has a height + /// + public void EnsureLastLayerHasHeight() + { + var bottomLayer = Layers.Last(); + if (bottomLayer.Height.IsZero()) + { + BottomLevel -= defaultBottomLayerHeight; + } + } + + /// + /// Determines the infiltration layer. + /// + /// Length of the penetration. + public void DetermineInfiltrationLayer(double penetrationLength) + { + SoilLayer1D infiltrationLayer = null; + + SoilLayer1D bottomAquiferLayer = BottomAquiferLayer; + + if (penetrationLength > 0 && bottomAquiferLayer != null) + { + SoilLayer1D inBetweenAquiferLayer = InBetweenAquiferLayer; + + double aquiferBottom = inBetweenAquiferLayer == null ? + Double.PositiveInfinity : inBetweenAquiferLayer.BottomLevel; + + IList infiltrationLayers = + layers.Where(l => l.TopLevel <= aquiferBottom && l.TopLevel > bottomAquiferLayer.TopLevel) + .ToList(); + + if (infiltrationLayers.Count > 0) + { + double separationLevel = bottomAquiferLayer.TopLevel + penetrationLength; + + if (separationLevel <= infiltrationLayers.First().TopLevel) + { + infiltrationLayer = layers.Last(l => l.TopLevel >= separationLevel); + } + } + } + } + + /// + /// Validates this instance (using validator mechanism). + /// + /// + [Validate] + public ValidationResult[] Validate() + { + SoilLayer1D erroneousLayer; + + if (LayerCount == 0) + { + var error = String.Format(LocalizationManager.GetTranslatedText(this, "SoilProfileWithoutLayers"), Name); + return new[] + { + new ValidationResult(ValidationResultType.Error, + error, "", this) + }; + } + + if (!IsStrictlyDescending(out erroneousLayer)) + { + var error = String.Format(LocalizationManager.GetTranslatedText(this, "SoilProfileLayersNotDescending"), + Name, erroneousLayer.Name); + return new[] + { + new ValidationResult(ValidationResultType.Error, + error, "", this) + }; + } + + if (HasInvalidThicknessLayers(out erroneousLayer)) + { + var error = String.Format(LocalizationManager.GetTranslatedText(this, "SoilProfileInvalidLayerThickness"), + Name, erroneousLayer.Name); + return new[] + { + new ValidationResult(ValidationResultType.Error, + error, "", this) + }; + } + + if (HasLayersWithoutSoil(out erroneousLayer)) + { + var error = String.Format(LocalizationManager.GetTranslatedText(this, "SoilProfileLayerWithoutSoil"), + Name, erroneousLayer.Name); + return new[] + { + new ValidationResult(ValidationResultType.Error, + error, "", this) + }; + } + return new ValidationResult[0]; + } + + /// + /// Gets the aquifer layers. + /// + /// list of Aquifer layers + public IList GetAquiferLayers() + { + return Layers.Where(IsAquiferLayer).OrderBy(l => l.TopLevel).ToList(); + } + + /// + /// Gets the bottom level. + /// + /// The soil layer. + /// Bottom level + public double GetBottomLevel(SoilLayer1D soilLayer) + { + var layerBelow = GetLayerBelow(soilLayer); + + return layerBelow != null ? layerBelow.TopLevel : BottomLevel; + } + + /// + /// Ares the layers ordered descending. + /// + /// + /// true if all layers are ordered descending; otherwise, false. + /// + private bool AreLayersOrderedByDescending() + { + // check for empty list + if (Layers.Count <= 1) + { + return true; + } + + var current = Layers[0]; + for (int i = 1; i < Layers.Count; ++i) + { + var previous = current; + current = Layers[i]; + + if (current.TopLevel > previous.TopLevel) + { + return false; + } + } + + return true; + } + + /// + /// Determines whether the layers are strictly ordered in descending order. + /// If erroneous layer is found, false is returned and the layer + /// is stored in the parameter + /// + /// The erroneous layer. + /// true if the layers are strictly ordered in descending order; otherwise, false. + private bool IsStrictlyDescending(out SoilLayer1D erroneousLayer) + { + for (int i = 1; i < layers.Count; i++) + { + if (layers[i].TopLevel > layers[i - 1].TopLevel) + { + erroneousLayer = layers[i]; + return false; + } + } + + erroneousLayer = null; + return true; + } + + /// + /// Determines whether there are layers with invalid thickness. + /// + /// The erroneous layer. + /// True when a layer with invalid thickness exists + private bool HasInvalidThicknessLayers(out SoilLayer1D erroneousLayer) + { + for (int i = 1; i < layers.Count; i++) + { + if (layers[i].TopLevel >= layers[i - 1].TopLevel) + { + erroneousLayer = layers[i]; + return true; + } + } + // check bottom layer using bottom of profile + if (layers.Count > 0 && layers[layers.Count - 1].TopLevel <= BottomLevel) + { + erroneousLayer = layers[layers.Count - 1]; + return true; + } + erroneousLayer = null; + return false; + } + + /// + /// Determines whether there are layers without soil. + /// + /// The erroneous layer. + /// true when a layer without soil is found + private bool HasLayersWithoutSoil(out SoilLayer1D erroneousLayer) + { + for (int i = 0; i < layers.Count; i++) + { + if (layers[i].Soil == null) + { + erroneousLayer = layers[i]; + return true; + } + } + erroneousLayer = null; + return false; + } + + /// + /// Gets the layer by inset offset, seen from the given layer plus the given offset. + /// + /// The layer. + /// The offset. + /// the found layer, if no layer found, null + private SoilLayer1D GetLayerByInsetOffset(SoilLayer1D layer, int offset) + { + // only works if list is sorted + if (!AreLayersOrderedByDescending()) + { + layers.Sort(); + } + + int index = GetLayerIndexAt(layer); + + // was the layer found? + if (index < 0 || index >= layers.Count) + { + return null; + } + + // is there a layer at the specified offset? + int requestedIndex = index + offset; + if (requestedIndex < 0 || requestedIndex >= layers.Count) + { + return null; + } + + // return the valid layer + return layers[requestedIndex]; + } + + /// + /// Gets the layer below the given layer. + /// + /// The given layer. + /// The found layer + public SoilLayer1D GetLayerBelow(SoilLayer1D layer) + { + return GetLayerByInsetOffset(layer, 1); + } + + /// + /// Gets the layer index of the given layer. + /// + /// The layer. + /// The index, -1 if not found + private int GetLayerIndexAt(SoilLayer1D layer) + { + if (layer == null) + { + return -1; + } + + for (int i = 0; i < layers.Count; ++i) + { + if (layers[i] == layer) + { + return i; + } + } + return -1; + } + + /// + /// Gets the top level of highest aquifer. + /// + /// + public double GetTopLevelOfHighestAquifer() + { + double topLevel; + if (InBetweenAquiferLayer != null) + { + topLevel = InBetweenAquiferLayer.TopLevel; + } + else + { + topLevel = BottomAquiferLayer.TopLevel; + } + return topLevel; + } + + /// + /// Gets the total soil pressure, including the eventual free water on surface + /// + /// The level for wich the total pressure is calculated + /// The phreatic level + /// Unit weight of the water + /// The soil pressure + public double GetTotalPressure(double z, double phreaticLevel, double unitWeightWater) + { + double pressure = 0; + + // see if free water is at surface + double surfaceLevel = Layers[0].TopLevel; + if (z > surfaceLevel) + { + return Math.Max(0, (phreaticLevel - z)*unitWeightWater); + } + + if (phreaticLevel > surfaceLevel) + { + if (z < phreaticLevel) + { + pressure += (phreaticLevel - Math.Max(Layers[0].TopLevel, z))*unitWeightWater; + } + } + + foreach (var layer in Layers) + { + if (layer.Height > 0 && layer.Soil != null) + { + if (z >= layer.TopLevel) + { + continue; + } + if (z <= layer.BottomLevel) + { + if (phreaticLevel <= layer.BottomLevel) + { + pressure += layer.Height*layer.Soil.AbovePhreaticLevel; + } + else if (phreaticLevel >= layer.TopLevel) + { + pressure += layer.Height*layer.Soil.BelowPhreaticLevel; + } + else + { + pressure += (phreaticLevel - layer.BottomLevel)*layer.Soil.BelowPhreaticLevel; + pressure += (layer.TopLevel - phreaticLevel)*layer.Soil.AbovePhreaticLevel; + } + } + else + { + if (phreaticLevel <= z) + { + pressure += (layer.TopLevel - z)*layer.Soil.AbovePhreaticLevel; + } + else if (phreaticLevel >= layer.TopLevel) + { + pressure += (layer.TopLevel - z)*layer.Soil.BelowPhreaticLevel; + } + else + { + pressure += (layer.TopLevel - phreaticLevel)*layer.Soil.AbovePhreaticLevel; + pressure += (phreaticLevel - z)*layer.Soil.BelowPhreaticLevel; + } + } + } + } + + return pressure; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + private void AddLayer(SoilLayer1D layer) + { + layer.SoilProfile = this; + } + + /// + /// Determines whether the specified layer is an aquifer layer. + /// + /// The layer. + /// true if layer is aquifer layer; otherwise, false. + private static bool IsAquiferLayer(SoilLayer1D layer) + { + return (layer.IsAquifer); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilLayer2D.cs (revision 334) @@ -0,0 +1,77 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// 2D Soil Layer Object + /// + [Serializable] + public class SoilLayer2D : SoilLayer + { + // 2 associated objects + private GeometrySurface geometrySurface; + + /// + /// Gets and sets the GeometrySurface + /// + public GeometrySurface GeometrySurface + { + get + { + return geometrySurface; + } + set + { + geometrySurface = value; + } + } + + /// + /// Gets or sets the name. + /// + /// + /// The name. + /// + public override string Name + { + get + { + return Soil != null ? Soil.Name : LocalizationManager.GetTranslatedText(this, "NoSoilAssigned"); + } + set{} // ignore + } + + /// + /// Gets the geometry bounds. + /// + /// the geometry bounds + public override GeometryBounds GetGeometryBounds() + { + return GeometrySurface == null ? + base.GetGeometryBounds() : GeometrySurface.GetGeometryBounds(); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculatorException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculatorException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/DAMFailureMechanismeCalculatorException.cs (revision 334) @@ -0,0 +1,52 @@ +// Copyright (C) Stichting Deltares 2017. 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; +using Deltares.DamEngine.Data.Design; + +namespace Deltares.DamEngine.Calculators +{ + [Serializable] + public class DamFailureMechanismeCalculatorException : Exception + { + public DamFailureMechanismeCalculatorException() + { + } + + public DamFailureMechanismeCalculatorException(string message) + : base(message) + { + } + + public DamFailureMechanismeCalculatorException(string message, Exception inner) + : base(message, inner) + { + } + + protected DamFailureMechanismeCalculatorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + public Scenario Scenario { get; set; } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/Dike.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/Dike.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/Dike.cs (revision 334) @@ -0,0 +1,410 @@ +// Copyright (C) Stichting Deltares 2017. 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.NWO; +using Deltares.DamEngine.Data.General.PlLines; +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 +{ + public class DikeException : Exception + { + public DikeException(string message) + : base(message) + { + } + } + + public class DikeParameterNames + { + public const string MapForSoilGeometries2D = "MapForSoilGeometries2D"; + } + + 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 nonWaterRetainingObjects; + private IList soilProfiles; + private string soilDatabaseName = ""; + private List databaseSoils = new List(); + + public Dike() + { + this.Name = "Dijkring"; + this.MapForSoilGeometries2D = ""; + + this.locations = new List(); + this.soilProfiles = new List(); + + // this.surfaceLines = new DelegatedList { AddMethod = ConvertAddedOldSurfaceLineToNewFormat }; + SurfaceLines2 = new List(); + this.pl1Lines = new List(); + this.soilList = new SoilList(); + this.nonWaterRetainingObjects = new List(); + 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; } + + public virtual string SoilDatabaseName + { + get { return this.soilDatabaseName; } + set + { + this.soilDatabaseName = value; + UpdateLocationsDatabaseName(); + } + } + + /// + /// Updates the locations for scenarios. + /// + public void UpdateLocationsForScenarios() + { + foreach (Location location in this.Locations) + { + foreach (Scenario scenario in location.Scenarios) + { + scenario.Location = location; + } + } + } + + /// + /// Updates the name soil database for all locations. + /// + public void UpdateLocationsDatabaseName() + { + foreach (Location location in this.Locations) + { + location.SoildatabaseName = this.SoilDatabaseName; + } + + } + + /// + /// 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; } + } + + 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 virtual IList NonWaterRetainingObjects + { + get { return this.nonWaterRetainingObjects; } + set { this.nonWaterRetainingObjects = 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; } + } + + public void Validate() + { + if (Locations == null || Locations.Count < 1) + { + throw new DikeException("The dike ring has no locations defined"); + } + foreach (Location location in Locations) + { + if (location.LocalXZSurfaceLine2 != null) + { + var validator = new SurfaceLine2Validator(); + var validationResults = validator.ValidateCharacteristicPointsAreOrdered(location.LocalXZSurfaceLine2) + .Concat(validator.ValidateGeometryPointsAreOrdered(location.LocalXZSurfaceLine2)).ToArray(); + if (validationResults.Length > 0) + { + throw new SurfaceLineException(validationResults[0].Text); + } + } + } + } + + + /// + /// 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.SoilProfile.Layers.Find(l => String.Equals(l.Soil.Name, invalidSoil.Name, StringComparison.CurrentCultureIgnoreCase)); + + if (fl != null) + { + soilProf = spp.SoilProfile.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.SurfaceLine2 != null)); + + // Report which locations are not added because no valid surfaceline is found + var deletedLocations = new List(); + deletedLocations.AddRange(this.Locations.Where(loc => loc.SurfaceLine2 == 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.SoildatabaseName = this.SoilDatabaseName; + location.SoilList = this.SoilList; + location.MapForSoilGeometries2D = this.MapForSoilGeometries2D; + + location.Gauges.Clear(); + location.Gauges.AddRange(Gauges); + + location.GaugePLLines.Clear(); + location.GaugePLLines.AddRange(GaugePLLines); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/FailureMechanismeParamatersMStab.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/FailureMechanismeParamatersMStab.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/FailureMechanismeParamatersMStab.cs (revision 334) @@ -0,0 +1,114 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.General.PlLines; +using Deltares.DamEngine.Data.Geotechnics; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + public class FailureMechanismeParamatersMStab : IAssignable, ICloneable + { + /// + /// Additinal specifications/settings of calculation using MStab + /// + public FailureMechanismeParamatersMStab() + { + this.MStabParameters = new MStabParameters(); + this.IsStabilityCheckOnUplift = false; + } + public Location Location { get; set; } + public SurfaceLine2 SurfaceLine { get; set; } + public PLLines PLLines { get; set; } + public DupuitPLLines DupuitPLLines { get; set; } + public SoilProfile1D SoilProfile { get; set; } + public string SoilGeometry2DName { get; set; } + public double RiverLevel { get; set; } + public double DikeTableHeight { get; set; } + public double MaxWaterLevel { get; set; } + public double RiverLevelDecimateHeight { get; set; } + public double RequiredProbabilityOfFailure { get; set; } + public double TrafficLoad { get; set; } + /// + /// Indicates whether in stability calculation a check on uplift will be performed before performin UpliftVan calculation. + /// Default it is false (set in constructor) + /// + public bool IsStabilityCheckOnUplift { get; set; } + public MStabDesignEmbankment Design { get; set; } + [Validate] + public MStabParameters MStabParameters { get; set; } + + /// + /// Checks whether all rerquired data is there. + /// + public bool IsComplete + { + get + { + return + !string.IsNullOrEmpty(this.MStabParameters.SoilDatabaseName) && + this.PLLines != null && + (this.SoilProfile != null || this.MStabParameters.GeometryCreationOptions.SoilGeometry2DFilename != "") && + this.Location != null && + this.SurfaceLine != null && + !string.IsNullOrEmpty(this.MStabParameters.ProjectFileName); + } + } + + /// + /// Performs the Assignment + /// + /// + public void Assign(FailureMechanismeParamatersMStab failureMechanismeParamatersMStab) + { + this.Location = failureMechanismeParamatersMStab.Location; + this.SurfaceLine = failureMechanismeParamatersMStab.SurfaceLine; + this.SoilProfile = failureMechanismeParamatersMStab.SoilProfile; + this.SoilGeometry2DName = failureMechanismeParamatersMStab.SoilGeometry2DName; + this.PLLines = failureMechanismeParamatersMStab.PLLines; + + this.RiverLevel = failureMechanismeParamatersMStab.RiverLevel; + this.DikeTableHeight = failureMechanismeParamatersMStab.DikeTableHeight; + this.MaxWaterLevel = failureMechanismeParamatersMStab.MaxWaterLevel; + this.RiverLevelDecimateHeight = failureMechanismeParamatersMStab.RiverLevelDecimateHeight; + this.RequiredProbabilityOfFailure = failureMechanismeParamatersMStab.RequiredProbabilityOfFailure; + this.TrafficLoad = failureMechanismeParamatersMStab.TrafficLoad; ; + this.Design = failureMechanismeParamatersMStab.Design; + + this.MStabParameters.Assign(failureMechanismeParamatersMStab.MStabParameters); + } + + /// + /// Clones the object. + /// + /// FailureMechanismeParamatersMStab + public FailureMechanismeParamatersMStab Clone() + { + FailureMechanismeParamatersMStab failureMechanismeParamatersMStab = new FailureMechanismeParamatersMStab(); + failureMechanismeParamatersMStab.MStabParameters = this.MStabParameters.Clone(); + failureMechanismeParamatersMStab.Assign(this); + + return failureMechanismeParamatersMStab; + } + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/LocationJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/LocationJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/LocationJob.cs (revision 334) @@ -0,0 +1,609 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.General.TimeSeries; +using Deltares.DamEngine.Data.RWScenarios; +using Deltares.DamEngine.Data.Standard.Calculation; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.General +{ + public interface ILocationJob + { + Location Location { get; } + IEnumerable RWScenarioResults { get; } + bool HasRWScenarioResults { get; } + } + + public class LocationJob : DamJob, ILocationJob + { + private TimeSerie waterLevelTimeSerie = new TimeSerie(); + private LocationResult locationResult = new LocationResult(); + + private static ScenarioType currentScenarioType = ScenarioType.Scenario01; + private static string currentProfileName = ""; + private static string currentScenarioName = ""; + private static string currentCalculation = ""; + private static DateTime currentTime = DateTime.Today; + private static DamProjectType damProjectType = DamProjectType.Calamity; + private static ProbabilisticType probabilisticType = ProbabilisticType.Deterministic; + + private double designRequiredFactor = 0.0; + + public LocationJob() + { + } + + public LocationJob(object subject) + : base(subject) + { + } + + /// + /// TODO: what todo when location is null? + /// + public double XRd { get { return this.Location == null ? 0 : this.Location.XRd; } } + public double YRd { get { return this.Location == null ? 0 : this.Location.YRd; } } + + [XmlIgnore] + [Validate] + public Location Location + { + get + { + return this.Subject as Location; + } + set + { + this.Subject = value; + } + } + + public TimeSerie WaterLevelTimeSerie + { + get { return waterLevelTimeSerie; } + set + { + waterLevelTimeSerie = value; + } + } + + public virtual IEnumerable RWScenarioResults + { + get + { + return !this.HasRWScenarioResults ? + new List() : this.locationResult.RWScenariosResult.RWScenarioResults; + } + } + + public virtual IEnumerable SchematizationFactorResults + { + get + { + return !this.HasSchematizationFactorResults ? + new List() : this.locationResult.SchematizationFactorsResult.SchematizationFactorResults; + } + } + + public bool HasRWScenarioResults + { + get { return this.locationResult != null && this.locationResult.RWScenariosResult != null && + this.locationResult.RWScenariosResult.RWScenarioResults.Any(); + } + } + + public bool HasSchematizationFactorResults + { + get { return this.locationResult != null && this.locationResult.SchematizationFactorsResult != null; } + } + + public virtual LocationResult LocationResult + { + get { return locationResult; } + set + { + locationResult = value; + } + } + + private bool HasUsableStabilityTimeSerieEntries() + { + var res = false; + foreach (var timeSerieEntry in locationResult.StabilityTimeSerie.Entries) + { + if (timeSerieEntry.Value != Double.NaN) + { + res = true; + break; + } + } + return res; + } + + public bool HasLocationResults + { + get + { + if (locationResult == null) + return false; + return ((locationResult.PipingTimeSerie != null && locationResult.PipingTimeSerie.Entries.Count > 0) || + (locationResult.StabilityTimeSerie != null && + locationResult.StabilityTimeSerie.Entries.Count > 0 && HasUsableStabilityTimeSerieEntries())); + } + } + + public LocationResult GetLocationResultWithStabilityTimeSerie(string locationName) + { + LocationResult result = null; + if (locationResult != null && locationResult.StabilityTimeSerie != null && + locationResult.StabilityTimeSerie.LocationId == locationName && + locationResult.StabilityTimeSerie.Entries != null && locationResult.StabilityTimeSerie.Entries.Count > 1) + { + result = locationResult; + } + return result; + } + + public LocationResult GetFirstLocationResultWithStabilityTimeSerie() + { + LocationResult result = null; + if (locationResult != null && locationResult.StabilityTimeSerie != null && + locationResult.StabilityTimeSerie.Entries != null && locationResult.StabilityTimeSerie.Entries.Count > 1) + { + result = locationResult; + } + return result; + } + + public RWScenarioProfileResult GetAssesmentResultByProfile(ScenarioType scenarioType, string profileName) + { + if (this.HasRWScenarioResults) + { + RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); + if (scenarioResult != null) + { + foreach (var res in scenarioResult.RWScenarioProfileResults) + { + if (res.SoilProfileName == profileName) + return res; + } + } + } + + return null; + } + + public CsvExportData GetFirstDesignResult() + { + if (this.HasScenarioResults) + { + Scenario scenario = Location.Scenarios[0]; + if (scenario != null && scenario.CalculationResults.Count > 0) + { + return scenario.CalculationResults[0]; + } + } + return null; + } + + public CsvExportData GetDesignResultByProfileScenarioAndCalculationName(string profileName, string scenarioName, + string calculationName) + { + if (this.HasScenarioResults) + { + foreach (var scenario in Location.Scenarios) + { + foreach (var calculationResult in scenario.CalculationResults) + { + if (calculationResult.ProfileName == profileName && + calculationResult.ScenarioName == scenarioName && + calculationResult.Calculation == calculationName) + return calculationResult; + } + } + } + return null; + } + + /// + /// Return the result of the profile with highest probability of occurrence + /// + /// + /// + public RWScenarioProfileResult GetRWScenarioResultOfProfileWithHighestProbablilityOfOccurrence(ScenarioType scenarioType) + { + if (this.HasRWScenarioResults) + { + RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); + if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) + { + RWScenarioProfileResult rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[0]; + for (int i = 1; i < scenarioResult.RWScenarioProfileResults.Count; i++) + { + if (scenarioResult.RWScenarioProfileResults[i].SoilProfileProbability > rwScenarioProfileResult.SoilProfileProbability) + { + rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[i]; + } + } + return rwScenarioProfileResult; + } + } + return null; + } + + /// + /// Return result with the lowest safetyfactor + /// + /// + /// + public RWScenarioProfileResult GetRWScenarioResultWithLowestSafetyFactor(ScenarioType scenarioType) + { + if (this.HasRWScenarioResults) + { + RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); + if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) + { + RWScenarioProfileResult rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[0]; + for (int i = 1; i < scenarioResult.RWScenarioProfileResults.Count; i++) + { + if (scenarioResult.RWScenarioProfileResults[i].SafetyFactor < rwScenarioProfileResult.SafetyFactor) + { + rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[i]; + } + } + return rwScenarioProfileResult; + } + } + return null; + } + + public bool HasScenarioResults + { + get + { + List scenarios = Location.Scenarios; + foreach (var scenario in scenarios) + { + foreach (var calculationResult in scenario.CalculationResults) + { + if (ProbabilisticType == ProbabilisticType.Deterministic) + { + if ((calculationResult.SafetyFactor != null) || (calculationResult.CalculationResult == CalculationResult.UnexpectedError) ) + { + return true; + } + } + else + { + if (calculationResult.FailureProbability != null) + { + return true; + } + } + } + } + return false; + } + } + + /// + /// Get lowest safetyfactor of all scenarios + /// + /// + private double GetLowestRealSafetyFactorFromScenarios() + { + var res = double.MaxValue; + List scenarios = Location.Scenarios; + foreach (var scenario in scenarios) + { + foreach (var calculationResult in scenario.CalculationResults) + { + if (calculationResult.CalculationResult == CalculationResult.UnexpectedError) + { + res = -1; + } + if (calculationResult.SafetyFactor != null) + { + if (calculationResult.SafetyFactor.Value < res) + { + res = calculationResult.SafetyFactor.Value; + if (calculationResult.RequiredSafetyFactor != null) + { + designRequiredFactor = calculationResult.RequiredSafetyFactor.Value; + } + } + } + } + } + if (res == double.MaxValue) res = DamGlobalConstants.NoRunValue; + return res; + } + + /// + /// Get highest porbability of failure of all scenarios + /// + /// + private double GetHighestRealPropbabilityFromScenarios() + { + var res = double.MinValue; + List scenarios = Location.Scenarios; + foreach (var scenario in scenarios) + { + foreach (var calculationResult in scenario.CalculationResults) + { + if (calculationResult.Calculation.Equals("FlowSlide")) + { + designRequiredFactor = 1.0; // This is a hack to make FlowSlide color display correct; + // TODO: make a good generic method to display colored results + } + else + { + if (calculationResult.PipingFailureProbability != null) + { + if (calculationResult.PipingFailureProbability.Value > res && + calculationResult.PipingFailureProbability.Value < DamGlobalConstants.NoRunValue) + { + res = calculationResult.PipingFailureProbability.Value; + if (calculationResult.RequiredFailureProbability != null) + { + designRequiredFactor = calculationResult.RequiredFailureProbability.Value; + } + } + } + + } + } + } + if (res == double.MinValue) res = DamGlobalConstants.NoRunValue; + return res; + } + + [XmlIgnore] + public double SafetyFactor + { + get + { + if (DamProjectType == DamProjectType.Calamity) + { + if (this.HasLocationResults) + { + TimeSerie timeSerie = this.LocationResult.StabilityTimeSerie; + return timeSerie.GetValue(CurrentTime); + } + else + { + return DamGlobalConstants.NoRunValue; + } + } + else if (DamProjectType == DamProjectType.Assessment) + { + if (this.HasRWScenarioResults && GetRWScenarioResultWithLowestSafetyFactor(currentScenarioType) != null) + { + return GetRWScenarioResultWithLowestSafetyFactor(currentScenarioType).SafetyFactor; + } + else + { + if (this.locationResult.RWScenariosResult != null && + this.locationResult.RWScenariosResult.CalculationResult == CalculationResult.RunFailed) + { + // DamGlobalConstants.NoRunValue is the default result resulting in NoRun whereas the + // status must be failed. So when failed set to -1. + return -1; + } + else + { + return DamGlobalConstants.NoRunValue; + } + } + } + else if (DamProjectType == DamProjectType.Design) + { + return GetLowestRealSafetyFactorFromScenarios(); + } + else + { + return DamGlobalConstants.NoRunValue; + } + } + } + + public double DetrimentFactor + { + get + { + if (DamProjectType == DamProjectType.Design) + { + return designRequiredFactor; + } + else + { + // For Piping in Assesment projects, ignore the given detriment factor and use the required safety for Piping + if (DamProjectType == DamProjectType.Assessment && (currentScenarioType == ScenarioType.Scenario10 || currentScenarioType == ScenarioType.Scenario11)) + { + return DamGlobalConstants.RequiredSafetyPipingForAssessment; + } + return this.Location.DetrimentFactor; + } + } + } + + [XmlIgnore] + public double FailureProbability + { + get + { + if (DamProjectType == DamProjectType.Calamity) + { + return DamGlobalConstants.NoRunValue; + } + else if (DamProjectType == DamProjectType.Assessment) + { + return DamGlobalConstants.NoRunValue; + } + else if (DamProjectType == DamProjectType.Design) + { + return GetHighestRealPropbabilityFromScenarios(); + } + else + { + return DamGlobalConstants.NoRunValue; + } + } + } + + [XmlIgnore] + public double RequiredProbability + { + get + { + if (DamProjectType == DamProjectType.Design) + { + return designRequiredFactor; // only for piping at the moment + } + else + { + return 1; //#Bka: for now return 1 if not piping probabilistic. + } + } + } + + public bool AreRWScenarioResultsMixed(ScenarioType scenarioType) + { + if (this.HasRWScenarioResults) + { + RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); + if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) + { + var aboveRequiredSafety = false; + var belowRequiredSafety = false; + for (int i = 0; i < scenarioResult.RWScenarioProfileResults.Count; i++) + { + if (!aboveRequiredSafety) + { + aboveRequiredSafety = scenarioResult.RWScenarioProfileResults[i].SafetyFactor >= DetrimentFactor; + } + if (!belowRequiredSafety) + { + belowRequiredSafety = scenarioResult.RWScenarioProfileResults[i].SafetyFactor < DetrimentFactor; + } + } + return aboveRequiredSafety && belowRequiredSafety; + } + } + return false; + } + + [XmlIgnore] + public JobResult Result + { + get + { + if (ProbabilisticType == ProbabilisticType.Deterministic) + { + if (DamProjectType == DamProjectType.Assessment && AreRWScenarioResultsMixed(currentScenarioType)) + { + return JobResult.Mixed; + } + return JobResultInterpreter.GetJobResult(SafetyFactor, DetrimentFactor, true); + } + else + { + return JobResultInterpreter.GetJobResult(FailureProbability, RequiredProbability, false); + } + } + } + + [XmlIgnore] + public double X + { + get { return this.Location.XRd; } + set { this.Location.XRd = value; } + } + + [XmlIgnore] + public double Y + { + get { return this.Location.YRd; } + set { this.Location.YRd = value; } + } + + [XmlIgnore] + public static ScenarioType CurrentScenarioType + { + get { return currentScenarioType; } + set { currentScenarioType = value; } + } + + [XmlIgnore] + public static string CurrentProfileName + { + get { return currentProfileName; } + set { currentProfileName = value; } + } + + [XmlIgnore] + public static string CurrentScenarioName + { + get { return currentScenarioName; } + set { currentScenarioName = value; } + } + + [XmlIgnore] + public static string CurrentCalculation + { + get { return currentCalculation; } + set { currentCalculation = value; } + } + + [XmlIgnore] + public static DateTime CurrentTime + { + get { return currentTime; } + set { currentTime = value; } + } + + [XmlIgnore] + public static DamProjectType DamProjectType + { + get { return damProjectType; } + set { damProjectType = value; } + } + + [XmlIgnore] + public static ProbabilisticType ProbabilisticType + { + get { return probabilisticType; } + set { probabilisticType = value; } + } + + public override string ToString() + { + return this.Location != null ? this.Location.ToString() : ""; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/DupuitPLLines.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/DupuitPLLines.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/PlLines/DupuitPLLines.cs (revision 334) @@ -0,0 +1,36 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; + +namespace Deltares.DamEngine.Data.General.PlLines +{ + public class DupuitPLLines + { + private List plLines = new List(); + + public List PLLines + { + get { return plLines; } + set { plLines = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/CompositeJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/CompositeJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/CompositeJob.cs (revision 334) @@ -0,0 +1,90 @@ +// Copyright (C) Stichting Deltares 2017. 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.Collections.Generic; + +namespace Deltares.DamEngine.Data.General +{ + public class CompositeJob : DamJob + { + private IList jobs = new List(); + + public CompositeJob() + { + } + + public CompositeJob(object subject) : base(subject) + { + } + + public override bool? Run + { + get + { + bool containsRun = false; + bool containsNoRun = false; + + foreach (DamJob job in jobs) + { + if (!job.Run.HasValue) + { + containsRun = true; + containsNoRun = true; + } + else if (job.Run.Value) + { + containsRun = true; + } + else + { + containsNoRun = true; + } + } + + if (containsRun && containsNoRun) + { + return null; + } + else if (containsRun) + { + return true; + } + else + { + return false; + } + } + set + { + foreach (DamJob job in jobs) + { + job.Run = value; + } + } + } + + public virtual IList Jobs + { + get { return jobs; } + set { jobs = value; } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/SchematizationFactor/SchematizationFactorData.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/SchematizationFactor/SchematizationFactorData.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/SchematizationFactor/SchematizationFactorData.cs (revision 334) @@ -0,0 +1,67 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General.SchematizationFactor +{ + public class SchematizationFactorData + { + private double schematizationFactorMin = 1.05; + private double schematizationFactorMax = 1.25; + private double schematizationFactorDelta = 0.025; + private double requiredProbability = 70.0; + + public double SchematizationFactorMin + { + get { return schematizationFactorMin; } + set + { + schematizationFactorMin = value; + } + } + + public double SchematizationFactorMax + { + get { return schematizationFactorMax; } + set + { + schematizationFactorMax = value; + } + } + + public double SchematizationFactorDelta + { + get { return schematizationFactorDelta; } + set + { + schematizationFactorDelta = value; + } + } + + public double RequiredProbability + { + get { return requiredProbability; } + set + { + requiredProbability = value; + } + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineHeightAdapter.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineHeightAdapter.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Design/SurfaceLineHeightAdapter.cs (revision 334) @@ -0,0 +1,180 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.Geometry; +using Deltares.DamEngine.Data.Geotechnics; + +namespace Deltares.DamEngine.Calculators.Dikes_Design +{ + public class SurfaceLineHeightAdapterException : Exception + { + public SurfaceLineHeightAdapterException(string message) : base(message) { } + } + + public class SurfaceLineHeightAdapter : SurfaceLineAdapter + { + public SurfaceLineHeightAdapter(SurfaceLine2 surfaceLine, Location location) : base(surfaceLine, location) + { + } + + /// + /// Constructs a new surface line with a new height + /// + /// + /// There are a few scenarios of that will be handled: + /// - one without a shoulder inside + /// - one with a shoulder inside but the adaption will remove the shoulder completly + /// - one with a shoulder but a part of the shoulder remains intact + /// - one where the new top falls completely above the old top + /// + /// The new height + /// The adapted surface line + /// + public SurfaceLine2 ConstructNewSurfaceLine(double newDikeHeight) + { + + //Input data + GeometryPoint pointAtTopRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + GeometryPoint pointAtTopPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + GeometryPoint pointDikeToeInward = surfaceLine.GetDikeToeInward(); + GeometryPoint startingPoint = surfaceLine.GetStartingPoint(); + + surfaceLine.RemoveSegmentBetween(startingPoint.X, pointAtTopRiver.X); + GeometryPoint newPointAtTopRiver; + GeometryPoint oldPointAtTopRiver = null; + if (Location.UseNewDikeSlopeOutside) + { + var newOutsideSlopePoint = new GeometryPoint + { + X = pointAtTopRiver.X + 100, + Z = pointAtTopRiver.Z + 100*Location.NewDikeSlopeOutside + }; + newPointAtTopRiver = LineHelper.GetIntersectionPointWithExtrapolation(pointAtTopRiver, newOutsideSlopePoint, + new GeometryPoint(pointAtTopRiver.X, newDikeHeight), + new GeometryPoint(pointAtTopPolder.X, newDikeHeight)); + oldPointAtTopRiver = new GeometryPoint {X = pointAtTopRiver.X, Z = pointAtTopRiver.Z}; + } + else + { + newPointAtTopRiver = LineHelper.GetIntersectionPointWithExtrapolation(startingPoint,pointAtTopRiver, + new GeometryPoint(pointAtTopRiver.X, newDikeHeight), + new GeometryPoint(pointAtTopPolder.X, newDikeHeight)); + } + // Determine the new point at DIKE TOP RIVER + + + double dikeTopWidth = pointAtTopPolder.X - pointAtTopRiver.X; + if (Location.UseNewDikeTopWidth) + { + dikeTopWidth = Location.NewDikeTopWidth; + } + + // Determine the new point at DIKE TOP POLDER + GeometryPoint newPointAtTopPolder = new GeometryPoint(newPointAtTopRiver.X + dikeTopWidth, newDikeHeight); + + var slopeTangentInside = (pointAtTopPolder.Z - pointDikeToeInward.Z) / (pointDikeToeInward.X - pointAtTopPolder.X); + if (Location.UseNewDikeSlopeInside) + { + slopeTangentInside = Location.NewDikeSlopeInside; + } + // check case where the new top falls completely above the old top + var intersectionPointDikeTop = IntersectionpointWithOldDikeTop(newPointAtTopPolder, slopeTangentInside); + if (intersectionPointDikeTop != null) + { + // Remove all points between old dike top river and old dike top polder + surfaceLine.RemoveSegmentBetween(pointAtTopRiver.X, pointAtTopPolder.X); + // Add new dike top river, new dike top polder + surfaceLine.AddCharacteristicPoint(newPointAtTopRiver, CharacteristicPointType.DikeTopAtRiver); + surfaceLine.AddCharacteristicPoint(newPointAtTopPolder, CharacteristicPointType.DikeTopAtPolder); + // check if intersection point equals old dike top polder, if so the ready else add intersection point as normal point + if (!pointAtTopPolder.LocationEquals(intersectionPointDikeTop)) + { + surfaceLine.EnsurePoint(intersectionPointDikeTop.X, intersectionPointDikeTop.Z); + } + surfaceLine.SortPoints(); + return surfaceLine; + } + + // Remove points on inside slope + surfaceLine.RemoveSegmentBetween(pointAtTopPolder.X, pointDikeToeInward.X); + // Store the ditch (if any) + var ditchDefinition = GetDitchDefinition(); + // Delete the ditch from the surfaceline (if any) + RemoveExistingDitch(ditchDefinition); + // Adjust for the new slope + var slopePoint = ReplaceBaseInsideForNewSlope(newPointAtTopPolder, slopeTangentInside); + // Reset pointDikeToeInward for new position + pointDikeToeInward = surfaceLine.GetDikeToeInward(); + // Remove all points between "old" dike top river side and new toe inward + surfaceLine.RemoveSegmentBetween(pointAtTopRiver.X, pointDikeToeInward.X); + if (slopePoint != null) + { + // if the slope point exists (new end point of slope coincides with shouldertopinside), it has to be + // re-added as "normal" point because it was deleted in the former RemoveSegmentBetween. + surfaceLine.AddCharacteristicPoint(slopePoint, CharacteristicPointType.None); + } + // Adjust position of "old" dike top river + surfaceLine.EnsurePointOfType(newPointAtTopRiver.X, newPointAtTopRiver.Z, CharacteristicPointType.DikeTopAtRiver); + if (Location.UseNewDikeSlopeOutside) + { + // Re-add the old dike top river as "normal" point + surfaceLine.AddCharacteristicPoint(oldPointAtTopRiver, CharacteristicPointType.None); + } + // Add the new dike top at polder side + surfaceLine.EnsurePointOfType(newPointAtTopPolder.X, newPointAtTopPolder.Z, CharacteristicPointType.DikeTopAtPolder); + // Restore Ditch (if any) + RestoreDitch(ditchDefinition); + // Restore traffic load + RestoreTrafficLoad(); + surfaceLine.SortPoints(); + + return surfaceLine; + } + + /// + /// Tries to find the intersection point between the old dike top and the new inside slope starting at the new + /// dike top at polder side. + /// + /// + /// + /// The intersection point when found else null + private GeometryPoint IntersectionpointWithOldDikeTop(GeometryPoint newPointAtTopPolder, double slopeTangent) + { + GeometryPoint res = null; + var newPoint = new GeometryPoint + { + X = newPointAtTopPolder.X + 100, + Z = newPointAtTopPolder.Z - 100*slopeTangent + }; + GeometryPoint dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + var ip = LineHelper.GetIntersectionPointWithExtrapolation(newPointAtTopPolder, newPoint, + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver), + dikeTopAtPolder); + if (ip != null && ip.X <= dikeTopAtPolder.X) + { + res = ip; + } + return res; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSMStabDAMInterface.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSMStabDAMInterface.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Interfaces/DGSMStabDAMInterface.cs (revision 334) @@ -0,0 +1,145 @@ +// Copyright (C) Stichting Deltares 2017. 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.Runtime.InteropServices; +using System.Text; + +namespace Deltares.DamEngine.Calculators.Interfaces +{ + public class DGSMStabDAMInterface : DgsStandardDllInterface + { + + public struct LegacyCoordinate + { + public double x; + public double z; + } + + private const string DllFileName = @"DGSMStabDAM.dll"; + + [DllImport(DllFileName)] + static extern int GetDamLicenseType(); + [DllImport(DllFileName)] + static extern int GetDamLiveLicenseType(); + [DllImport(DllFileName)] + static extern int DllGetVersion(out DllVersionInfoStructure dllVersionInfoStructure); + [DllImport(DllFileName)] + static extern string GetDescription(StringBuilder errorMessage, ref int bufferSize); + [DllImport(DllFileName)] + static extern int GetErrorMessage(StringBuilder errorMessage, ref int bufferSize); + [DllImport(DllFileName)] + static extern int CreateMStabProject(string inputXmlString); + [DllImport(DllFileName)] + static extern int ConvertGeometry2DTo1D(string inputXML, StringBuilder outputXML, ref int bufferSize); + [DllImport(DllFileName)] + static extern int CreateGeometry2DData(string inputXML, StringBuilder outputXML, ref int bufferSize); + [DllImport(DllFileName)] + static extern double CalculatePipingLength(int pointCount, ref LegacyCoordinate[] headLinePoints); + + + /// + /// Gets the type of the license for DAM. + /// + /// + public int DamLicenseType() + { + return (GetDamLicenseType()); + } + + /// + /// Gets the type of the license for DAMLive. + /// + /// + public int DamLiveLicenseType() + { + return (GetDamLiveLicenseType()); + } + + /// + /// Gets DllVersion + /// + /// version as string + new public string GetDllVersion() + { + DllVersionInfoStructure dllInfo; + var returnValue = DllGetVersion(out dllInfo); + return dllInfo.DwBuildNumber.ToString(); + } + + /// + /// Create ProjectFile for MStab + /// + /// Error number + public int CreateProjectFile(string inputXmlString) + { + return (CreateMStabProject(inputXmlString)); + } + + /// + /// returns ErrorMessage + /// + /// Error as string + new public string ErrorMessage() + { + const int maxErrorMessageLength = 50; + int errorMessageLength = maxErrorMessageLength; + var errorMessage = new StringBuilder(maxErrorMessageLength); + int returnCode = GetErrorMessage(errorMessage, ref errorMessageLength); + if (returnCode == DllErrorOutputBufferTooSmall) + { + errorMessage = new StringBuilder(errorMessageLength); + returnCode = GetErrorMessage(errorMessage, ref errorMessageLength); + } + if (returnCode == DllErrorNone) + { + return errorMessage.ToString(); + } + else + { + return "Unknow error"; + } + } + + /// + /// converts 2D geometry to 1D + /// + /// Error as integer + public int Geometry2DTo1DConversion(string inputXML, StringBuilder outputXML, ref int bufferSize) + { + return (ConvertGeometry2DTo1D(inputXML, outputXML, ref bufferSize)); + } + + public int CreateGeometry2DDataFromGeometry2D(string inputXML, StringBuilder outputXML, ref int bufferSize) + { + return (CreateGeometry2DData(inputXML, outputXML, ref bufferSize)); + } + + /// + /// calculates the pipinglength + /// + /// pipinglength as double + public double PipingLengthCalculation(int pointCount, ref LegacyCoordinate[] headLinePoints) + { + return (CalculatePipingLength(pointCount, ref headLinePoints)); + } + + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenarioSelector.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenarioSelector.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Dikes Assessment Regional/RWScenarioSelector.cs (revision 334) @@ -0,0 +1,248 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.RWScenarios; + +namespace Deltares.DamEngine.Calculators.Dikes_Assessment_Regional +{ + public class RWScenarioSelector + { + public RWScenarioSelector() + { + } + + public PipingModelType PipingModelType { get; set; } + public MStabParameters MStabParameters { get; set; } + + private bool WillChoicesResultInScenarios(params Enum[] previousChoices) + { + if (previousChoices.Length >= 2) + { + if (previousChoices[0].Equals(LoadSituation.Dry) && previousChoices[1].Equals(DikeDrySensitivity.None)) + { + return false; + } + } + + return true; + } + + public RWScenarioProfileResult[] GetScenarios(Location location, SoilGeometryProbability soilGeometryProbability) + { + List scenarios = new List(); + + RWEvaluator[] evaluators = new RWEvaluator[] + { + new DikeMaterialRWEvaluator(), + new HydraulicShortcutRWEvaluator(), + new UpliftRWEvaluator() + }; + + Enum[] choices = new Enum[evaluators.Length + 1]; + foreach (LoadSituation loadSituation in Enum.GetValues(typeof(LoadSituation))) + { + choices[0] = loadSituation; + + bool resultsInScenarios = true; + + for (int i = 1; i < evaluators.Length + 1; i++) + { + choices[i] = evaluators[i - 1].Evaluate(location, new SoilGeometry(soilGeometryProbability.SoilProfile, null), choices.ToArray()); + + //Is het een doorlopende tak? Zo niet break af (afbreken als geen veenkade en droge belastingsituatie + resultsInScenarios = WillChoicesResultInScenarios(choices.ToArray()); + + if (!resultsInScenarios) + { + break; + } + } + + if (resultsInScenarios) + { + if (choices[0].Equals(LoadSituation.Wet)) + { + if (choices[1].Equals(DikeDrySensitivity.None)) + { + if (choices[2].Equals(HydraulicShortcutType.NoHydraulicShortcut)) + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario08, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario04, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario08, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario10, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + else // HydraulicShortcutType.HydraulicShortcut + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario07, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario03, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario07, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario10, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + } + else // DikeDrySensitivity.Dry + { + if (choices[2].Equals(HydraulicShortcutType.NoHydraulicShortcut)) + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario08, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario04, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario08, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario10, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + else // HydraulicShortcutType.HydraulicShortcut + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario07, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario03, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario07, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario10, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + } + } + else // LoadSituation.Dry + { + if (choices[1].Equals(DikeDrySensitivity.Dry)) + { + if (choices[2].Equals(HydraulicShortcutType.NoHydraulicShortcut)) + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario06, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario02, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario06, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario09, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.HorizontalBalance)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario11, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + else // HydraulicShortcutType.HydraulicShortcut + { + if (choices[3].Equals(UpliftType.NoUplift)) + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario05, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + } + else // UpliftType.Uplift + { + scenarios.Add(this.GetScenario(ScenarioType.Scenario01, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.UpliftVan)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario05, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.Bishop)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario09, choices, location, soilGeometryProbability, FailureMechanismSystemType.StabilityInside, MStabModelType.HorizontalBalance)); + scenarios.Add(this.GetScenario(ScenarioType.Scenario11, choices, location, soilGeometryProbability, FailureMechanismSystemType.Piping, PipingModelType)); + } + } + } + } + } + } + + return scenarios.ToArray(); + } + + private RWScenarioProfileResult GetScenario(ScenarioType scenarioType, Enum[] choices, Location location, + SoilGeometryProbability soilGeometryProbability, FailureMechanismSystemType failureMechanismType, MStabModelType modelOption) + { + RWScenarioProfileResult scenario = new RWScenarioProfileResult(); + scenario.Location = location; + scenario.SoilGeometryProbability = soilGeometryProbability; + scenario.FailureMechanismType = failureMechanismType; + scenario.MstabModelOption = modelOption; + scenario.PipingModelOption = PipingModelType; + scenario.MStabParameters = MStabParameters; + scenario.LoadSituation = (LoadSituation)choices[0]; + scenario.DikeDrySensitivity = (DikeDrySensitivity)choices[1]; + scenario.HydraulicShortcutType = (HydraulicShortcutType)choices[2]; + scenario.UpliftType = (UpliftType)choices[3]; + + scenario.ScenarioType = scenarioType; + + //if (scenario.IsDry) + //{ + // // Soils are not transferred to the computational core at the moment, therefore this code has no meaning at the moment + // // You could say the same about soils in general in the DAM C# code + // SoilProfile drySoilProfile = soilProfile.Clone(); + // foreach (Layer layer in drySoilProfile.Layers) + // { + // layer.Soil.AbovePhreaticLevel = layer.Soil.DryUnitWeight; + // } + //} + + return scenario; + } + + private RWScenarioProfileResult GetScenario(ScenarioType scenarioType, Enum[] choices, Location location, + SoilGeometryProbability soilGeometryProbability, FailureMechanismSystemType failureMechanismType, PipingModelType pipingModelType) + { + RWScenarioProfileResult scenario = new RWScenarioProfileResult(); + scenario.Location = location; + scenario.SoilGeometryProbability = soilGeometryProbability; + scenario.FailureMechanismType = failureMechanismType; + scenario.MstabModelOption = MStabModelType.Bishop; + scenario.PipingModelOption = pipingModelType; + + scenario.LoadSituation = (LoadSituation)choices[0]; + scenario.DikeDrySensitivity = (DikeDrySensitivity)choices[1]; + scenario.HydraulicShortcutType = (HydraulicShortcutType)choices[2]; + scenario.UpliftType = (UpliftType)choices[3]; + + scenario.ScenarioType = scenarioType; + + //if (scenario.IsDry) + //{ + // // Soils are not transferred to the computational core at the moment, therefore this code has no meaning at the moment + // // You could say the same about soils in general in the DAM C# code + // SoilProfile drySoilProfile = soilProfile.Clone(); + // foreach (Layer layer in drySoilProfile.Layers) + // { + // layer.Soil.AbovePhreaticLevel = layer.Soil.DryUnitWeight; + // } + //} + + return scenario; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculationException.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculationException.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/Stability/StabilityCalculationException.cs (revision 334) @@ -0,0 +1,43 @@ +// Copyright (C) Stichting Deltares 2017. 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.Stability +{ + [Serializable] + public class StabilityCalculationException : Exception + { + public StabilityCalculationException() {} + + public StabilityCalculationException(string message) + : base(message) {} + + public StabilityCalculationException(string message, Exception inner) + : base(message, inner) {} + + protected StabilityCalculationException( + SerializationInfo info, + StreamingContext context) + : base(info, context) {} + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Soil.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Soil.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/Soil.cs (revision 334) @@ -0,0 +1,431 @@ +// Copyright (C) Stichting Deltares 2017. 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.Xml.Serialization; +using Deltares.DamEngine.Data.Standard; +using Deltares.DamEngine.Data.Standard.Language; + +namespace Deltares.DamEngine.Data.Geotechnics +{ + /// + /// Soil class, representing a specific soil material and its properties + /// + [Serializable] + public class Soil : IName + { + // Stability properties + private string name = ""; + private DilatancyType dilatancyType = DilatancyType.Phi; + private ShearStrengthModel shearStrengthModel = ShearStrengthModel.CPhi; + private double belowPhreaticLevel = double.NaN; + private double abovePhreaticLevel = double.NaN; + private double dryUnitWeight = double.NaN; + private double cohesion = double.NaN; + private double frictionAngle = double.NaN; + private double poP = double.NaN; + private double ocr = double.NaN; + private double ratioCuPc = double.NaN; + private double cuTop = double.NaN; + private double cuBottom = double.NaN; + private bool usePop = true; + private double strengthIncreaseExponent = double.NaN; + private SoilType soilType; + + /// + /// Initializes a new instance of the class. + /// + public Soil() + { + Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSoilMaterial"); + soilType = SoilType.Sand; + } + + + /// + /// Initializes a new instance of the class. + /// + /// The name. + /// Unit weight below phreatic level + /// Unit weight above phreatic level + public Soil(string name, double belowPhreaticLevel, double abovePhreaticLevel) : this() + { + Name = name; + AbovePhreaticLevel = abovePhreaticLevel; + BelowPhreaticLevel = belowPhreaticLevel; + } + + /// + /// Initializes a new instance of the class. + /// + /// The name. + public Soil(string name) : this() + { + Name = name; + } + + /// + /// Gets or sets the type of the soil. + /// + /// + /// The type of the soil. + /// + public virtual SoilType SoilType + { + get + { + return soilType; + } + set + { + if (!soilType.Equals(value)) + { + soilType = value; + } + } + } + + #region property Name + + /// + /// Gets or sets the name of the soil. + /// + public string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return Name; + } + + #endregion property Name + + + #region property BelowPhreaticLevel + + /// + /// Unit Weight below the phreatic level (kN/m3) + /// + public double BelowPhreaticLevel + { + set + { + belowPhreaticLevel = value; + } + get + { + return belowPhreaticLevel; + } + } + #endregion + + #region property AbovePhreaticLevel + + /// + /// Unit Weight above the phreatic level (kN/m3) + /// + public double AbovePhreaticLevel + { + set + { + abovePhreaticLevel = value; + } + get + { + return abovePhreaticLevel; + } + } + + #endregion + + #region property DryUnitWeight + + /// + /// Ovendry unit weight [kN/m3] + /// + public double DryUnitWeight + { + get + { + return dryUnitWeight; + } + set + { + if (!dryUnitWeight.Equals(value)) + { + dryUnitWeight = value; + } + } + } + + #endregion property DryUnitWeight + + #region property Cohesion + + /// + /// Cohesion (the force that holds together molecules or like particles within a soil) [kN/m2] + /// + public double Cohesion + { + get + { + return cohesion; + } + set + { + cohesion = value; + } + } + + #endregion + + #region property FrictionAngle + + /// + /// Critical state friction angle (deg) + /// + public double FrictionAngle //gedaan + { + get + { + return frictionAngle; + } + set + { + frictionAngle = value; + } + } + #endregion property FrictionAngle + + + + #region property POP + + /// + /// Pre-overburden pressure (POP) + /// Equal to pre-consolidation stress minus effective stress + /// + public double PoP + { + get + { + return poP; + } + set + { + poP = value; + } + } + #endregion property POP + + #region property OCR + + /// + /// Over-consolidation ratio (OCR) + /// + public double Ocr + { + get + { + return ocr; + } + set + { + ocr = value; + } + } + #endregion property OCR + + #region property RatioCuPc + + /// + /// Ratio Cu/Pc + /// + public double RatioCuPc + { + get + { + return ratioCuPc; + } + set + { + ratioCuPc = value; + } + } + #endregion property RatioCuPc + + + + #region property CuTop + + /// + /// Cu Top + /// + public double CuTop + { + get + { + return cuTop; + } + set + { + cuTop = value; + } + } + #endregion property CuTop + + #region property CuBottom + + /// + /// Cu Bottom + /// + public double CuBottom + { + get + { + return cuBottom; + } + set + { + cuBottom = value; + } + } + #endregion property CuBottom + + #region property UsePop + + /// + /// Use POP for shear strength model + /// + public bool UsePop + { + get + { + return usePop; + } + set + { + usePop = value; + } + } + #endregion property UsePop + + #region property DilatancyType + + /// + /// Dilatancy (shear thickening) type + /// + public DilatancyType DilatancyType + { + get + { + return dilatancyType; + } + set + { + if (!dilatancyType.Equals(value)) + { + dilatancyType = value; + } + } + } + + #endregion property DilatancyType + + #region property StrengthIncreaseExponent + + /// + /// Gets or sets the strength increase exponent. + /// + /// + /// The strength increase exponent. + /// + public double StrengthIncreaseExponent + { + get + { + return strengthIncreaseExponent; + } + set + { + strengthIncreaseExponent = value; + } + } + #endregion property StrengthIncreaseExponent + + #region property ShearStrengthModel + + /// + /// Shear strength model to use + /// + [XmlAttribute("ShearStrengthModel")] + public ShearStrengthModel ShearStrengthModel + { + get + { + return shearStrengthModel; + } + set + { + shearStrengthModel = value; + } + } + #endregion property ShearStrengthModel + + + /// + /// Assigns the specified a soil. + /// + /// a soil. + public void Assign(Soil aSoil) + { + name = aSoil.Name; + dilatancyType = aSoil.DilatancyType; + shearStrengthModel = aSoil.ShearStrengthModel; + belowPhreaticLevel = aSoil.BelowPhreaticLevel; + abovePhreaticLevel = aSoil.AbovePhreaticLevel; + cohesion = aSoil.Cohesion; + frictionAngle = aSoil.FrictionAngle; + poP = aSoil.PoP; + ocr = aSoil.Ocr; + ratioCuPc = aSoil.RatioCuPc; + cuTop = aSoil.CuTop; + cuBottom = aSoil.CuBottom; + usePop = aSoil.UsePop; + strengthIncreaseExponent = aSoil.StrengthIncreaseExponent; + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryData.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryData.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryData.cs (revision 334) @@ -0,0 +1,809 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of the DAM Engine. +// +// The DAM Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Deltares.DamEngine.Data.Standard.Language; +using Deltares.DamEngine.Data.Standard.Validation; + +namespace Deltares.DamEngine.Data.Geometry +{ + /// + /// Class containing the geometry data + /// + /// + public class GeometryData : GeometryObject + { + private readonly List curveDataList = new List(); + + private readonly List loopDataList = new List(); + private readonly List pointDataList = new List(); + private readonly List surfaceDataList = new List(); + private readonly GeometryPointString surfaceLine = new GeometryPointString(); + private double bottom = GeometryConstants.DefaultBottomLimitGeometry; + + private double left = GeometryConstants.DefaultLeftLimitGeometry; + + private double right = GeometryConstants.DefaultRightLimitGeometry; + + private bool updatingSurfaceLine; + + #region Repairer Id's and property names + + private const string sameStartAndEndPointRepairerId = "Same start and end point"; + private const string sameStartAndEndPointRepairerPropertyName = "Points"; + private const string noSoilRepairerId = "No Soil"; + private const string noSoilRepairerPropertyName = "None"; + + #endregion + + #region properties + + /// + /// Gets the points. + /// + /// + /// The points. + /// + [XmlArray("Points")] + [Validate] + public IList Points + { + get + { + return pointDataList; + } + } + + /// + /// gets the Curve data list. + /// + /// + /// The curves. + /// + public List Curves + { + get + { + return curveDataList; + } + } + + /// + /// gets the Loop data list. + /// + /// + /// The loops. + /// + public List Loops + { + get + { + return loopDataList; + } + } + + /// + /// gets the Surface data list. + /// + public List Surfaces + { + get + { + return surfaceDataList; + } + } + + /// + /// Gets the minimum geometry points x. + /// + /// + /// The minimum geometry points x. + /// + [XmlIgnore] + public double MinGeometryPointsX + { + get + { + return Points.Select(geometryPoint => geometryPoint.X).Concat(new[] + { + double.MaxValue + }).Min(); + } + } + + /// + /// Gets the minimum geometry points z. + /// + /// + /// The minimum geometry points z. + /// + [XmlIgnore] + public double MinGeometryPointsZ + { + get + { + return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[] + { + double.MaxValue + }).Min(); + } + } + + /// + /// Gets the maximum geometry points x. + /// + /// + /// The maximum geometry points x. + /// + [XmlIgnore] + public double MaxGeometryPointsX + { + get + { + return Points.Select(geometryPoint => geometryPoint.X).Concat(new[] + { + double.MinValue + }).Max(); + } + } + + /// + /// Gets the maximum geometry points z. + /// + /// + /// The maximum geometry points z. + /// + [XmlIgnore] + public double MaxGeometryPointsZ + { + get + { + return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[] + { + double.MinValue + }).Max(); + } + } + + /// + /// Gets or sets the left. + /// + /// + /// The left. + /// + public double Left + { + get + { + return left; + } + set + { + left = value; + } + } + + /// + /// Gets or sets the right. + /// + /// + /// The right. + /// + public double Right + { + get + { + return right; + } + set + { + right = value; + } + } + + /// + /// Gets or sets the bottom. + /// + /// + /// The bottom. + /// + public double Bottom + { + get + { + return bottom; + } + set + { + bottom = value; + } + } + + /// + /// Gets all points on the Left boundary. + /// + /// + private List GetLeftPoints() + { + var geometryPoints = pointDataList.Where(gp => Math.Abs(gp.X - Left) < GeometryConstants.Accuracy).ToList(); + return geometryPoints; + } + + /// + /// Gets all points on the Right boundary. + /// + /// + private List GetRightPoints() + { + var geometryPoints = pointDataList.Where(point => Math.Abs(point.X - Right) < GeometryConstants.Accuracy).ToList(); + return geometryPoints; + } + + /// + /// Gets the geometry bounds. + /// + /// + public override GeometryBounds GetGeometryBounds() + { + return new GeometryBounds(Left, Right, Bottom, + Bottom + Math.Min(Right - Left, 20)); + } + + #endregion + + #region Functions + + #region create functions + + /// + /// Adjust the Geometry Bottom, Left and Right properties to the currently contained surfaces + /// + public void Rebox() + { + double xMin = double.MaxValue; + double xMax = double.MinValue; + double zMin = double.MaxValue; + double zMax = double.MinValue; + + foreach (var point in pointDataList) + { + xMin = Math.Min(point.X, xMin); + xMax = Math.Max(point.X, xMax); + zMin = Math.Min(point.Z, zMin); + zMax = Math.Max(point.Z, zMax); + } + bottom = zMin; + left = xMin; + right = xMax; + } + + #endregion + + #region remove functions + + /// + /// Clears this instance. + /// + public void Clear() + { + pointDataList.Clear(); + curveDataList.Clear(); + surfaceDataList.Clear(); + +// newlyEffectedPoints.Clear(); +// newlyEffectedCurves.Clear(); + } + /// + /// deletes all the Loop from IGeometryLoop. + /// + private void DeleteAllLoops() + { + Loops.Clear(); + } + + #endregion + + #region other functions + + #region calculation function + + /// + /// CheckIfIntersectStricktly + /// Determines if two lines intersect each other stricktly (so no extrapolated points). + /// + /// Line 1 GeometryPoint 1 + /// Line 1 GeometryPoint 2 + /// Line 2 GeometryPoint 1 + /// Line 2 GeometryPoint 2 + /// Intersection coordinates + /// True if lines intersect each other + private static bool CheckIfIntersectStricktly(Point2D beginPoint1, Point2D endPoint1, + Point2D beginPoint2, Point2D endPoint2, + ref Point2D intersect) + { + Point2D ip; + var res = Routines2D.DetermineIf2DLinesIntersectStrickly(beginPoint1.X, beginPoint1.Z, endPoint1.X, endPoint1.Z, beginPoint2.X, + beginPoint2.Z, endPoint2.X, endPoint2.Z, out ip); + if (ip != null) + { + intersect = ip; + } + return res == LineIntersection.Intersects; + } + + /// + /// CheckIfIntersectStricktly + /// Determines if two lines intersect each other stricktly (so no extrapolated points). + /// + /// Line 1 GeometryPoint 1 + /// Line 1 GeometryPoint 2 + /// Line 2 GeometryPoint 1 + /// Line 2 GeometryPoint 2 + /// Intersection coordinates + /// True if lines intersect each other + public static bool CheckIfIntersect(double[] aL1P1, double[] aL1P2, double[] aL2P1, double[] aL2P2, + ref double[] aIntersect) + { + var p1 = new Point2D(aL1P1[0], aL1P1[1]); + var p2 = new Point2D(aL1P2[0], aL1P2[1]); + var p3 = new Point2D(aL2P1[0], aL2P1[1]); + var p4 = new Point2D(aL2P2[0], aL2P2[1]); + var ip = new Point2D(); + var res = CheckIfIntersectStricktly(p1, p2, p3, p4, ref ip); + if (res) + { + aIntersect[0] = ip.X; + aIntersect[1] = ip.Z; + } + return res; + } + + /// + /// Gets the height of the surface(s) intersected at the given x. + /// + /// The x. + /// + public double GetSurfaceHeight(double x) + { + double surfaceHeight = -Double.MaxValue; + double[] intersectionPoints = IntersectLayers(x, -9999); + for (int i = 0; i < intersectionPoints.Length; i++) + { + if (intersectionPoints[i] > surfaceHeight) + { + surfaceHeight = intersectionPoints[i]; + } + } + + return surfaceHeight; + } + + /// + /// All the Intersection of layers in respect with a given vertical are detemined here. + /// + /// Startingpoint of the Vertical (X) + /// Startingpoint of the Vertical (Y) + /// List of Z intersection coordinates + private double[] IntersectLayers(double aXCoord, double aZCoord) + { + if (Surfaces == null) + { + throw new Exception("Empty Surfaces in IntersectLayers"); + } + + var beginPoint2 = new Point2D() + { + X = aXCoord, Z = aZCoord + }; + + var endPoint2 = new Point2D() + { + X = aXCoord, Z = 99999 + }; + + var referencePoint = new Point2D(); + + var intersections = new List(); + + for (int surfaceIndexLocal = 0; surfaceIndexLocal < Surfaces.Count; surfaceIndexLocal++) + { + var outerLoopCurveList = Surfaces[surfaceIndexLocal].OuterLoop.CurveList; + for (int curveIndexLocal = 0; curveIndexLocal < outerLoopCurveList.Count; curveIndexLocal++) + { + //Check for each curve if it intersects with x coordinate + Point2D beginPoint1 = outerLoopCurveList[curveIndexLocal].GetHeadPoint(CurveDirection.Forward); + Point2D endPoint1 = outerLoopCurveList[curveIndexLocal].GetEndPoint(CurveDirection.Forward); + + if (Math.Max(beginPoint1.X, endPoint1.X) >= aXCoord && + Math.Min(beginPoint1.X, endPoint1.X) <= aXCoord) + { + if (CheckIfIntersectStricktly(beginPoint1, endPoint1, beginPoint2, endPoint2, + ref referencePoint)) + { + if (referencePoint.Z > aZCoord && intersections.Contains(referencePoint.Z) == false) + { + intersections.Add(referencePoint.Z); + } + } + } + } + } + + return intersections.ToArray(); + } + + /// + /// Returns a list of boundary curves. These are curves which are used in only one surface so they have to be on a boundary (inner or outer) + /// + /// + private List GetBoundaryCurves() + { + var curves = new List(); + var loops = new List(); + foreach (var surface in Surfaces) + { + loops.Add(surface.OuterLoop); + // Todo Ask Rob/Tom: when a real "doughnut" type surface (so hole in the center) is permitted, adding the innerloops here will + // result in a wrong list of curves (because it will include the inner loop curves defining the hole) for its actual purpose: + // the determination of the surfaceline. When there is always a surface defined within the "dougnut" (so no real hole), + // this code will work and the innerloop must even be added to prevent finding internal boundaries. So this depends on the specs! + loops.AddRange(surface.InnerLoops); + } + + foreach (var loop in loops) + { + foreach (var curve in loop.CurveList) + { + if (curves.Contains(curve)) + { + // Second appearance, remove + curves.Remove(curve); + } + else + { + curves.Add(curve); + } + } + } + return curves; + } + + #endregion + + + #endregion + + #endregion + + /// + /// Ordered list of all geometry points at the surface + /// + public virtual GeometryPointString SurfaceLine + { + get + { + if (surfaceLine.CalcPoints.Count == 0 && pointDataList.Count > 0) + { + UpdateSurfaceLine(); + } + return surfaceLine; + } + } + + /// + /// Checks geometry for loose curves and AutoRegeneration + /// + /// + [Validate] + public ValidationResult[] ValidateGeometry() + { + var validationList = new List(); + { + foreach (var point in Points) + { + foreach (var point1 in Points) + { + if (point != point1) + { + bool isValidated = false; + foreach (var validatedItem in validationList) + { + if (validatedItem.Subject == point) + { + isValidated = true; + } + } + if (!isValidated) + { + if (Math.Abs(point.X - point1.X) < GeometryConstants.Accuracy && + Math.Abs(point.Z - point1.Z) < GeometryConstants.Accuracy) + { + validationList.Add(new ValidationResult(ValidationResultType.Error, + point + " and " + + point1 + " values are same.", + point1, sameStartAndEndPointRepairerPropertyName, + sameStartAndEndPointRepairerId)); + } + } + } + } + } + } + if (Surfaces.Count < 1) + { + validationList.Add(new ValidationResult(ValidationResultType.Error, "No soil surface available.", + this, noSoilRepairerPropertyName, noSoilRepairerId)); + } + return validationList.ToArray(); + } + + /// + /// Updates the line at the top of the geometry + /// + private void UpdateSurfaceLine() + { + if (updatingSurfaceLine) + { + return; + } + + updatingSurfaceLine = true; + + var bCurves = GetBoundaryCurves(); + if (bCurves.Count == 0) + { + surfaceLine.CalcPoints.Clear(); + } + var curvesCopy = GetCurvesCopy(bCurves); + var curves = GetTopCurves(curvesCopy); + CreateSurfaceLinePointString(curves); + + updatingSurfaceLine = false; + } + + /// + /// Removes the boundary curves from the given list of curves. + /// The boundaries themselves are determined from the given geometry + /// + /// The curves. + /// The geometry (as string). + private static void RemoveBoundaryCurves(List curves, GeometryPointString geometry) + { + var minX = geometry.GetMinX(); + var maxX = geometry.GetMaxX(); + var minZ = geometry.GetMinZ(); + foreach (var curve in curves.ToArray()) + { + if (IsBoundaryCurve(curve, minX, maxX, minZ)) + { + curves.Remove(curve); + } + } + } + + /// + /// get all geometrypoints from all geometrycurves + /// + /// + /// + private static GeometryPointString GetAllPointsFromCurveList(List curveList) + { + var result = new GeometryPointString(); + foreach (var curve in curveList) + { + result.CalcPoints.Add(curve.EndPoint); + result.CalcPoints.Add(curve.HeadPoint); + } + return result; + } + + /// + /// Gets next connected top curve in list of curves + /// + /// + /// + /// + /// + private GeometryCurve GetNextTopCurve(GeometryCurve curve, List boundaryCurves, + List excludedCurves) + { + // if current curve ends on right limit then that must have been the last one so stop the search + if (Math.Abs(curve.HeadPoint.X - Right) < GeometryConstants.Accuracy || Math.Abs(curve.EndPoint.X - Right) < GeometryConstants.Accuracy) + { + return null; + } + foreach (var geometryCurve in boundaryCurves) + { + if (geometryCurve != curve && !excludedCurves.Contains(geometryCurve)) + { + if (AreConnected(curve, geometryCurve)) + { + return geometryCurve; + } + } + } + return null; + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + return LocalizationManager.GetTranslatedText(this, "GeometryData"); + } + + /// + /// Synchronizes the loops. + /// + public void SynchronizeLoops() + { + DeleteAllLoops(); + foreach (var surface in Surfaces) + { + // #Bka: as real donuts (or holes in geom) are not allowed, there can be no innerloop that + // is NOT an outerloop for another surface. So no need to sync innerloops. + if (surface.OuterLoop != null && surface.OuterLoop.IsLoop()) + { + loopDataList.Add(surface.OuterLoop); + } + } + } + + /// + /// create a copy of the curves + /// + /// + /// + private List GetCurvesCopy(List bCurves) + { + var outerloopCurvesCopy = new List(bCurves); + return outerloopCurvesCopy; + } + + /// + /// Create a surface line from points in curves + /// Precondition is that the curves start at the left boundary and are connected left to right + /// (not neccesarily neat head-end) + /// + /// + /// + private void CreateSurfaceLinePointString(List curves) + { + surfaceLine.CalcPoints.Clear(); + + if (curves.Count == 0) + { + return; + } + + var reversed = false; + // The headpoint of the first curve must be on the left boundary otherwise the + // surface line will be in the wrong order. So make sure. + if (!(Math.Abs(curves[0].HeadPoint.X - Left) < GeometryConstants.Accuracy)) + { + curves[0].Reverse(); + reversed = true; + } + + foreach (var curve in curves) + { + if (!surfaceLine.CalcPoints.Contains(curve.HeadPoint)) + { + surfaceLine.CalcPoints.Add(curve.HeadPoint); + } + if (!surfaceLine.CalcPoints.Contains(curve.EndPoint)) + { + surfaceLine.CalcPoints.Add(curve.EndPoint); + } + } + + if (reversed) + { + curves[0].Reverse(); + } + } + + /// + /// get curves of the top side of the outerloop, vertical curves are omitted + /// + /// + /// + private List GetTopCurves(List curves) + { + GeometryCurve topCurve; + // Remove all curves on the geometry boundary + if (GetLeftPoints().Count > 0 && GetRightPoints().Count > 0) + { + foreach (var curve in curves.ToArray()) + { + if (IsBoundaryCurve(curve, Left, Right, Bottom)) + { + curves.Remove(curve); + } + } + // Make sure you start with topcurve = curve at the left top position + topCurve = curves.Where(g => Math.Abs(g.HeadPoint.X - Left) < GeometryConstants.Accuracy || + Math.Abs(g.EndPoint.X - Left) < GeometryConstants.Accuracy) + .OrderByDescending(c => c.HeadPoint.Z) + .FirstOrDefault(); + } + else + { + GeometryPointString gString = GetAllPointsFromCurveList(curves); + RemoveBoundaryCurves(curves, gString); + var minX = gString.GetMinX(); + // Make sure you start with topcurve = curve at the left top position + topCurve = + curves.Where(g => Math.Abs(g.HeadPoint.X - minX) < GeometryConstants.Accuracy || + Math.Abs(g.EndPoint.X - minX) < GeometryConstants.Accuracy).OrderByDescending(c => c.HeadPoint.Z).FirstOrDefault(); + } + var topCurvesLocal = new List(); + while (topCurve != null) + { + topCurvesLocal.Add(topCurve); + topCurve = GetNextTopCurve(topCurve, curves, topCurvesLocal); + } + + return topCurvesLocal; + } + + /// + /// Indicates whether a curve is on the boundary of the geometry + /// + /// + /// + /// + /// + /// + private static bool IsBoundaryCurve(GeometryCurve curve, double minX, double maxX, double minZ) + { + if (Math.Abs(curve.HeadPoint.X - minX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - minX) < GeometryConstants.Accuracy) + { + return true; + } + + if (Math.Abs(curve.HeadPoint.X - maxX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - maxX) < GeometryConstants.Accuracy) + { + return true; + } + + if (Math.Abs(curve.HeadPoint.Z - minZ) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.Z - minZ) < GeometryConstants.Accuracy) + { + return true; + } + + return false; + } + + private bool AreConnected(GeometryCurve curve1, GeometryCurve curve2) + { + return (curve1.HeadPoint == curve2.HeadPoint || curve1.HeadPoint == curve2.EndPoint || + curve1.EndPoint == curve2.HeadPoint || curve1.EndPoint == curve2.EndPoint); + } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoardJob.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoardJob.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/WaterBoardJob.cs (revision 334) @@ -0,0 +1,46 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.General +{ + public class WaterBoardJob : CompositeJob + { + public WaterBoardJob() + { + } + public WaterBoardJob(object subject): base(subject) + { + } + + public bool AreAllDikeLocationsWaterLevelTimeSeriesAssigned() + { + bool areAssigned = true; + foreach (DamJob damJob in Jobs) + { + if (damJob.GetType() == typeof(DikeJob)) + { + areAssigned = areAssigned && (((DikeJob)damJob).AreAllLocationWaterLevelTimeSeriesAssigned()); + } + } + return areAssigned; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ThrowHelper.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ThrowHelper.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Calculators/General/ThrowHelper.cs (revision 334) @@ -0,0 +1,281 @@ +// Copyright (C) Stichting Deltares 2017. 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.Linq; +using System.Reflection; +using System.Resources; +using Deltares.DamEngine.Data.General; + +namespace Deltares.DamEngine.Calculators.General +{ + /// + /// Declares the string resource names + /// + internal enum StringResourceNames + { + CsvFileNotFound, + CsvFileNotValid, + CsvHeaderEmptyOrNull, + CsvHeaderNotValid, + CsvObjectMaterializerNotValid, + CsvSplitterPatternNotValid, + DataImportArgumentNull, + EntityAlreadyExist, + EntityFactoryArgumentNull, + ImportFileNotExist, + ImportFolderNotExist, + ImportFolderNullOrEmpty, + MStabExecutableFileNameNotFound, + SlopeWExecutableFileNameNotFound, + OutputFileNotExist, + OutputFileHasNoContent, + OutputFileNameNotValid, + ProjectFileNameNullOrEmpty, + ProjectFileNotExist, + SegmentIdArgumentNullOrEmpty, + SoilProfileIdArgumentNullOrEmpty, + SurfaceLineIdArgumentNullOrEmpty, + RequiredEntityDoesNotExist, + ImportFilesNotValidated, + RequiredParameterMissing, + SurfacelineIsNotInsideSoilprofile, + TopLayerToBeEvaluatedNotInsideSoilprofile, + SoilAttachedToLayerNotValid, + ImportDataNotValid, + ImportedLocationDoesntHaveValidSurfaceLines, + ImportedLocationDoesntHaveValidPL1Lines, + SurfaceLinePointNotExtists, + NonExistentLocation, + TwoSandlayersRequiredInSoilProfile, + CsvColumnIndexAlreadyExists, + WaterLevelInputFileNullOrEmpty, + NoSoilProfileDefinedForLocation, + LocationHasNoSegment, + FileNameNotValid, + GaugeIdArgumentNullOrEmpty, + LocationIdArgumentNullOrEmpty, + ImportedLocationDoesntHaveSoilprofile, + SoildatabaseNotFound, + SurfaceLineNotAssigned, + SoilProfileNotAssigned, + SoilListIsNull, + PL1NotCreated, + NonWaterRetainingObjectCategoryArgumentNullOrEmpty, + NonWaterRetainingObjectTypeArgumentNullOrEmpty + } + + /// + /// Defines a helper class for getting string resources + /// + /// + /// The class implements a singleton pattern + /// + internal class StringResources + { + /// + /// Holds a single reference to this class + /// + private static StringResources instance; + + /// + /// The sync method for making this class thread safe + /// + private static readonly object sync = new object(); + + /// + /// The actual resource manager + /// + private readonly ResourceManager resources; + + // Methods + internal StringResources() + { + this.resources = new ResourceManager("Deltares.Dam.Data.Properties.Resources", Assembly.GetExecutingAssembly()); + } + + /// + /// Gets the sinlgeton instance + /// + /// A reference to this class instance + private static StringResources GetInstance() + { + if (instance == null) + { + lock (sync) + { + if (instance == null) + { + instance = new StringResources(); + } + } + } + return instance; + } + + /// + /// Getst the string from the from the resource manager + /// + /// The name of the resource + /// The resource string + public static string GetString(string name) + { + var loader = GetInstance(); + if (loader == null) + { + return null; + } + return loader.resources.GetString(name, CultureInfo.CurrentCulture); + } + } + + /// + /// + /// + internal static class ThrowHelper + { + internal static string GetResourceString(StringResourceNames resourceNames) + { + return StringResources.GetString(resourceNames.ToString()); + } + + internal static void ThrowIfArgumentNull(object value, StringResourceNames resourceNamesName) + { + if (value == null) + throw new ArgumentNullException(StringResources.GetString(GetResourceString(resourceNamesName))); + } + + internal static void ThrowIfStringArgumentNullOrEmpty(string value, StringResourceNames resourceNamesName) + { + if (string.IsNullOrEmpty(value) || value.Trim() == "") + throw new ArgumentException(GetResourceString(resourceNamesName)); + } + + internal static void ThrowIfFileNameNullOrEmpty(string fileName) + { + ThrowIfFileNameNullOrEmpty(fileName, StringResourceNames.FileNameNotValid); + } + + internal static void ThrowIfFileNameNullOrEmpty(string fileName, StringResourceNames resourceName) + { + ThrowIfFileNameNullOrEmpty(fileName, resourceName); + } + + internal static void ThrowIfFileNameNullOrEmpty(string fileName, StringResourceNames resourceName) + where TException : Exception + { + ThrowWhenConditionIsTrue(resourceName, + () => string.IsNullOrEmpty(fileName) || fileName.Trim() == ""); + } + + internal static void ThrowIfFileNotExist(string fileName, StringResourceNames resourceNamesName) + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(string.Format(GetResourceString(resourceNamesName), String.Format("{0} in {1}", (fileName ?? ""), DamProjectData.ProjectWorkingPath))); + } + + internal static void ThrowIfDirectoryNotExist(string dirName, StringResourceNames resourceNamesName) + { + if (!Directory.Exists(dirName)) + throw new DirectoryNotFoundException(string.Format(GetResourceString(resourceNamesName), dirName ?? "supplied")); + } + + internal static void ThrowWhenConditionIsTrue(Func condition, Func exceptionFactory) + where TException : Exception + { + if (condition()) + throw exceptionFactory(); + } + + public static void ThrowWhenConditionIsTrue(string message, Func condition) + where TException : Exception + { + var exception = (Exception)Activator.CreateInstance(typeof(TException), new object[] { message }); + + if (condition()) + throw exception; + } + + internal static void ThrowWhenConditionIsTrue(StringResourceNames resourceName, Func condition) + where TException : Exception + { + var exception = (Exception)Activator.CreateInstance( + typeof(TException), new object[] { GetResourceString(resourceName) }); + + if (condition()) + throw exception; + } + + internal static void ThrowWhenConditionIsTrue(TArgument arg, StringResourceNames resourceName, + Func condition, Func exceptionFactory) + where TException : Exception + { + var exception = exceptionFactory(resourceName); + if (condition(arg)) + throw exception; + } + + public static void ThrowWhenParameterIsMissing(object owner, string parameterName, object parameterValue) + { + if (parameterValue == null) + { + throw new ParameterMissingException( + string.Format(GetResourceString(StringResourceNames.RequiredParameterMissing), parameterName, owner.GetType().Name)); + } + } + + public static void ThrowWhenParameterIsMissing(object owner, string propertyName) + { + var pi = owner.GetType().GetProperty(propertyName); + var propertyValue = pi.GetValue(owner, null); + + if (propertyValue == null) + { + throw new ParameterMissingException( + string.Format(GetResourceString(StringResourceNames.RequiredParameterMissing), propertyName, owner.GetType().Name)); + } + } + + public static void ThrowWhenRequiredEntityDoesntExistInLookup(object id) where T : new() + { + throw new RequiredEntityNotExistException( + GetResourceString(StringResourceNames.RequiredEntityDoesNotExist), + typeof(T), + id); + } + + public static T ThrowWhenRequiredEntityDoesntExistInLookup(IEnumerable lookup, object id, Func predicate) where T : new() + { + var entity = lookup.FirstOrDefault(predicate); + if (Equals(entity, default(T))) + { + throw new RequiredEntityNotExistException( + GetResourceString(StringResourceNames.RequiredEntityDoesNotExist), + typeof(T), + id); + } + return entity; + } + } +} Index: dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelParameters.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelParameters.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/General/ModelParameters.cs (revision 334) @@ -0,0 +1,78 @@ +// Copyright (C) Stichting Deltares 2017. 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 Deltares.DamEngine.Data.Probabilistic; + +namespace Deltares.DamEngine.Data.General +{ + public class ModelParameters + { + public double TrafficLoad { get; set; } // moved to location + public double MinimalCircleDepth { get; set; } // to be moved to location + public double LevelReductionInside { get; set; } // not used yet; to be moved to location + public double LevelReductionOutside { get; set; } // not used yet; to be moved to location + public string MapForSoilGeometries2D { get; set; } // ??? + public ModelParametersForPLLines ModelParametersForPLLines { get; set; } // to be moved to location + public ModelFactors ModelFactors { get; set; } // to be moved to location + public DistributionType LayerHeightDistribution { get; set; } // to be moved to location + public double LayerHeightDeviation { get; set; } // to be moved to location + + public ModelParameters() + { + ModelParametersForPLLines = new ModelParametersForPLLines(); + ModelFactors = new ModelFactors + { + // Default values for ModelFactors in ModelParameters + // These can be overruled by reading them from the ModelParameters.csv file + // Or they can be overruled per scenario in the scearios.csv file + RequiredSafetyFactorStabilityInnerSlope = 1.0, + RequiredSafetyFactorStabilityOuterSlope = 1.0, + RequiredSafetyFactorPiping = 1.0, + RequiredProbabilityOfFailureStabilityInnerslope = 0.00000001, + RequiredProbabilityOfFailureStabilityOuterslope = 0.00000001, + RequiredProbabilityOfFailurePiping = 0.00000001, + UpliftCriterionPiping = 1.2, + UpliftCriterionStability = 1.2 + }; + } + + public static void AssignDefaultToNullValues(ModelFactors modelFactors) + { + var defaults = new ModelParameters().ModelFactors.AllValues; + + for (var i = 0; i < defaults.Length; ++i) + { + if (modelFactors.AllValues[i] == null) + { + modelFactors.AllValues[i] = defaults[i]; + } + } + } + } + + public class ModelParametersForPLLines + { + public virtual double PenetrationLength { get; set; } + public virtual double DampingFactorPL3 { get; set; } + public virtual double DampingFactorPL4 { get; set; } + public virtual PLLineCreationMethod PLLineCreationMethod { get; set; } + } +} \ No newline at end of file Index: dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/ShearStrengthModel.cs =================================================================== diff -u --- dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/ShearStrengthModel.cs (revision 0) +++ dam engine/trunk/src/Deltares.DamEngine.Data/Geotechnics/ShearStrengthModel.cs (revision 334) @@ -0,0 +1,74 @@ +// Copyright (C) Stichting Deltares 2017. 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.Data.Geotechnics +{ + /// + /// Shear Strength model type enumerator + /// + public enum ShearStrengthModel + { + /// + /// The none + /// + None = 1, + + /// + /// The c phi + /// + CPhi = 2, + + /// + /// The stress table + /// + StressTable = 3, + + /// + /// The pseudo values + /// + PseudoValues = 4, + + /// + /// The cu measured + /// + CuMeasured = 5, + + /// + /// The cu calculated + /// + CuCalculated = 6, + + /// + /// The cu gradient + /// + CuGradient = 7, + + /// + /// The cu calculated yield + /// + CuCalculatedYield = 8, + + /// + /// CPhi or CuCalculated dependent if below or above phreatic line + /// + CPhiOrCuCalculated = 9 + } +}