Index: Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs =================================================================== diff -u -r94e24e96e5e908960f5559c5d98021153f4e4120 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 94e24e96e5e908960f5559c5d98021153f4e4120) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -1612,6 +1612,15 @@ } /// + /// Looks up a localized string similar to De segmenten van de geometrie van de laag vormen geen lus.. + /// + public static string SoilLayer2D_CheckValidLoop_Loop_contains_disconnected_segments { + get { + return ResourceManager.GetString("SoilLayer2D_CheckValidLoop_Loop_contains_disconnected_segments", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Geen lagen gevonden voor de ondergrondschematisatie.. /// public static string SoilProfile_Cannot_construct_SoilProfile_without_layers { Index: Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx =================================================================== diff -u -r94e24e96e5e908960f5559c5d98021153f4e4120 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx (.../Resources.resx) (revision 94e24e96e5e908960f5559c5d98021153f4e4120) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx (.../Resources.resx) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -830,4 +830,7 @@ Eén of meerdere lagen hebben een top onder de bodem van de ondergrondschematisatie. + + De segmenten van de geometrie van de laag vormen geen lus. + \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj =================================================================== diff -u -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -132,10 +132,13 @@ + + + Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer1D.cs =================================================================== diff -u -r32535803492f107f7405399b93166d26446b77b7 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer1D.cs (.../SoilLayer1D.cs) (revision 32535803492f107f7405399b93166d26446b77b7) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer1D.cs (.../SoilLayer1D.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -19,146 +19,26 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. -using System; -using System.Drawing; - namespace Ringtoets.Common.IO.SoilProfile { /// /// This class represents profiles that were imported from D-Soil Model and will later on /// be used to create the necessary input for executing a calculation. /// - public class SoilLayer1D + public class SoilLayer1D : SoilLayerBase { - private string materialName; - /// /// Creates a new instance of , where the top is set to . /// /// The top level of the layer. public SoilLayer1D(double top) { Top = top; - MaterialName = string.Empty; - BelowPhreaticLevelMean = double.NaN; - BelowPhreaticLevelDeviation = double.NaN; - BelowPhreaticLevelShift = double.NaN; - DiameterD70Mean = double.NaN; - DiameterD70CoefficientOfVariation = double.NaN; - DiameterD70Shift = double.NaN; - PermeabilityMean = double.NaN; - PermeabilityCoefficientOfVariation = double.NaN; - PermeabilityShift = double.NaN; } /// /// Gets the top level of the . /// public double Top { get; } - - /// - /// Gets or sets a value indicating whether or not the is an aquifer. - /// - public bool IsAquifer { get; set; } - - /// - /// Gets or sets the mean of the distribution for the volumic weight of the - /// below the phreatic level. - /// - public double BelowPhreaticLevelMean { get; set; } - - /// - /// Gets or sets the deviation of the distribution for the volumic weight of the - /// below the phreatic level. - /// - public double BelowPhreaticLevelDeviation { get; set; } - - /// - /// Gets or sets the shift of the distribution for the volumic weight of the - /// below the phreatic level. - /// - public double BelowPhreaticLevelShift { get; set; } - - /// - /// Gets or sets the distribution for the volumic weight of the layer below the - /// phreatic level. - /// - public long? BelowPhreaticLevelDistribution { get; set; } - - /// - /// Gets or sets the mean of the distribution for the mean diameter of small scale tests - /// applied to different kinds of sand, on which the formula of Sellmeijer has been fit. - /// - public double DiameterD70Mean { get; set; } - - /// - /// Gets or sets the coefficient of variation of the distribution for the mean diameter - /// of small scale tests applied to different kinds of sand, on which the formula of Sellmeijer - /// has been fit. - /// - public double DiameterD70CoefficientOfVariation { get; set; } - - /// - /// Gets or sets the shift of the distribution for the mean diameter of small scale tests applied to different kinds of sand, - /// on which the formula of Sellmeijer has been fit. - /// [m] - /// - public double DiameterD70Shift { get; set; } - - /// - /// Gets or sets the distribution for the mean diameter of small scale tests applied to different kinds of sand, on which the - /// formula of Sellmeijer has been fit. - /// [m] - /// - public long? DiameterD70Distribution { get; set; } - - /// - /// Gets or sets the mean of the distribution for the the Darcy-speed with which water - /// flows through the aquifer layer. - /// - public double PermeabilityMean { get; set; } - - /// - /// Gets or sets the coefficient of variation of the distribution for the Darcy-speed - /// with which water flows through the aquifer layer. - /// - public double PermeabilityCoefficientOfVariation { get; set; } - - /// - /// Gets or sets the distribution for the Darcy-speed with which water flows through the aquifer layer. - /// [m/s] - /// - public long? PermeabilityDistribution { get; set; } - - /// - /// Gets or sets the shift of the distribution for the Darcy-speed with which water flows through the aquifer layer. - /// [m/s] - /// - public double PermeabilityShift { get; set; } - - /// - /// Gets or sets the name of the material that was assigned to the . - /// - /// Thrown when is null. - public string MaterialName - { - get - { - return materialName; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - materialName = value; - } - } - - /// - /// Gets or sets the that was used to represent the . - /// - public Color Color { get; set; } } } \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer2D.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer2D.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayer2D.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,121 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.ObjectModel; +using System.Linq; +using Core.Common.Base.Geometry; +using Ringtoets.Common.IO.Properties; + +namespace Ringtoets.Common.IO.SoilProfile +{ + /// + /// This class represents objects which were imported from a D-Soil Model database. + /// Instances of this class are transient and are not to be used once the D-Soil Model + /// database has been imported. + /// + public class SoilLayer2D : SoilLayerBase + { + private readonly Collection innerLoops; + private Segment2D[] outerLoop; + + /// + /// Creates a new instance of . + /// + public SoilLayer2D() + { + innerLoops = new Collection(); + } + + /// + /// Gets the outer loop of the as a of , + /// for which each of the segments are connected to the next. + /// + /// Thrown when the in + /// do not form a loop. + public IEnumerable OuterLoop + { + get + { + return outerLoop; + } + internal set + { + Segment2D[] loop = value.ToArray(); + CheckValidLoop(loop); + outerLoop = loop; + } + } + + /// + /// Gets the of inner loops (as of , + /// for which each of the segments are connected to the next) of the . + /// + public IEnumerable InnerLoops + { + get + { + return innerLoops; + } + } + + /// + /// Adds an inner loop to the geometry. + /// + /// The inner loop to add. + /// Thrown when the in + /// do not form a loop. + internal void AddInnerLoop(IEnumerable innerLoop) + { + Segment2D[] loop = innerLoop.ToArray(); + CheckValidLoop(loop); + innerLoops.Add(loop); + } + + private static void CheckValidLoop(Segment2D[] innerLoop) + { + if (innerLoop.Length == 1 || !IsLoopConnected(innerLoop)) + { + throw new ArgumentException(Resources.SoilLayer2D_CheckValidLoop_Loop_contains_disconnected_segments); + } + } + + private static bool IsLoopConnected(Segment2D[] segments) + { + int segmentCount = segments.Length; + if (segmentCount == 2) + { + return segments[0].Equals(segments[1]); + } + for (var i = 0; i < segmentCount; i++) + { + Segment2D segmentA = segments[i]; + Segment2D segmentB = segments[(i + 1) % segmentCount]; + if (!segmentA.IsConnected(segmentB)) + { + return false; + } + } + return true; + } + } +} \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayerBase.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayerBase.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilLayerBase.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,160 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.Drawing; + +namespace Ringtoets.Common.IO.SoilProfile +{ + /// + /// Class containing parameters which are defined for all soil layers. + /// + public abstract class SoilLayerBase + { + private string materialName; + + /// + /// Creates a new instance of . + /// + protected SoilLayerBase() + { + materialName = string.Empty; + BelowPhreaticLevelMean = double.NaN; + BelowPhreaticLevelDeviation = double.NaN; + BelowPhreaticLevelShift = double.NaN; + DiameterD70Mean = double.NaN; + DiameterD70CoefficientOfVariation = double.NaN; + DiameterD70Shift = double.NaN; + PermeabilityMean = double.NaN; + PermeabilityCoefficientOfVariation = double.NaN; + PermeabilityShift = double.NaN; + } + + /// + /// Gets or sets a value representing whether the layer is an aquifer. + /// + public bool IsAquifer { get; set; } + + /// + /// Gets or sets the name of the material that was assigned to the layer. + /// + /// Thrown when is null. + public string MaterialName + { + get + { + return materialName; + } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + materialName = value; + } + } + + /// + /// Gets or sets the value representing the color that was used to represent the layer. + /// + public Color Color { get; set; } + + /// + /// Gets or sets the distribution for the volumic weight of the layer below the + /// phreatic level. + /// [kN/m³] + /// + public long? BelowPhreaticLevelDistribution { get; set; } + + /// + /// Gets or sets the shift of the distribution for the volumic weight of the layer + /// below the phreatic level. + /// [kN/m³] + /// + public double BelowPhreaticLevelShift { get; set; } + + /// + /// Gets or sets the mean of the distribution for the volumic weight of the layer + /// below the phreatic level. + /// [kN/m³] + /// + public double BelowPhreaticLevelMean { get; set; } + + /// + /// Gets or sets the deviation of the distribution for the volumic weight of the layer below the phreatic level. + /// [kN/m³] + /// + public double BelowPhreaticLevelDeviation { get; set; } + + /// + /// Gets or sets the distribution for the mean diameter of small scale tests applied to different kinds of sand, on which the + /// formula of Sellmeijer has been fit. + /// [m] + /// + public long? DiameterD70Distribution { get; set; } + + /// + /// Gets or sets the shift of the distribution for the mean diameter of small scale tests applied to different kinds of sand, + /// on which the formula of Sellmeijer has been fit. + /// [m] + /// + public double DiameterD70Shift { get; set; } + + /// + /// Gets or sets the mean of the distribution for the mean diameter of small scale tests applied to different kinds of sand, + /// on which the formula of Sellmeijer has been fit. + /// [m] + /// + public double DiameterD70Mean { get; set; } + + /// + /// Gets or sets the coefficient of variation of the distribution for the mean diameter of small scale tests applied to different kinds of sand, + /// on which the formula of Sellmeijer has been fit. + /// [m] + /// + public double DiameterD70CoefficientOfVariation { get; set; } + + /// + /// Gets or sets the distribution for the Darcy-speed with which water flows through the aquifer layer. + /// [m/s] + /// + public long? PermeabilityDistribution { get; set; } + + /// + /// Gets or sets the shift of the distribution for the Darcy-speed with which water flows through the aquifer layer. + /// [m/s] + /// + public double PermeabilityShift { get; set; } + + /// + /// Gets or sets the mean of the distribution for the the Darcy-speed with which water flows through the aquifer layer. + /// [m/s] + /// + public double PermeabilityMean { get; set; } + + /// + /// Gets or sets the coefficient of variation of the distribution for the Darcy-speed with which water flows through the aquifer layer. + /// [m/s] + /// + public double PermeabilityCoefficientOfVariation { get; set; } + } +} \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1D.cs =================================================================== diff -u -r6f3f1fabca21935a2198e59ee423f833b75a3d36 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1D.cs (.../SoilProfile1D.cs) (revision 6f3f1fabca21935a2198e59ee423f833b75a3d36) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1D.cs (.../SoilProfile1D.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -56,6 +56,9 @@ Layers = layers; } + /// + /// Gets the database identifier of the soil profile. + /// public long Id { get; } /// Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs =================================================================== diff -u -r6f3f1fabca21935a2198e59ee423f833b75a3d36 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision 6f3f1fabca21935a2198e59ee423f833b75a3d36) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -132,6 +132,11 @@ var properties = new RequiredProfileProperties(this); var soilLayers = new List(); + if (properties.LayerCount == 0) + { + throw new SoilProfileReadException(Resources.SoilProfile_Cannot_construct_SoilProfile_without_layers, properties.ProfileName); + } + for (var i = 1; i <= properties.LayerCount; i++) { soilLayers.Add(ReadSoilLayerFrom(this, properties.ProfileName)); Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2D.cs =================================================================== diff -u -r58d98ab4a0a75497b2752eff1a931f6f7ee3fa8a -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2D.cs (.../SoilProfile2D.cs) (revision 58d98ab4a0a75497b2752eff1a931f6f7ee3fa8a) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2D.cs (.../SoilProfile2D.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -19,6 +19,8 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. +using System.Collections.Generic; + namespace Ringtoets.Common.IO.SoilProfile { /// @@ -29,12 +31,23 @@ /// /// Creates a new instance of . /// + /// The database identifier of the soil profile. /// The name of the profile. - public SoilProfile2D(string name) + /// The collection of layers that should be part of the profile. + public SoilProfile2D(long id, string name, IEnumerable layers) { + Id = id; Name = name; + Layers = layers; } + /// + /// Gets the database identifier of the soil profile. + /// + public long Id { get; } + + public IEnumerable Layers { get; } + public string Name { get; } } } \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2DReader.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2DReader.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile2DReader.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,337 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.Data; +using System.Data.SQLite; +using Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.Utils.Builders; +using Ringtoets.Common.IO.Properties; +using Ringtoets.Common.IO.SoilProfile.Schema; + +namespace Ringtoets.Common.IO.SoilProfile +{ + /// + /// This class reads a DSoil database file and reads 2d profiles from this database. + /// + public class SoilProfile2DReader : SqLiteDatabaseReaderBase, IRowBasedDatabaseReader + { + private IDataReader dataReader; + + /// + /// Creates a new instance of , which will use the + /// as its source. + /// + /// The path of the database file to open. + /// Thrown when: + /// + /// The contains invalid characters. + /// No file could be found at . + /// + /// + public SoilProfile2DReader(string databaseFilePath) : base(databaseFilePath) {} + + /// + /// Gets a value indicating whether or not more soil profiles can be read using + /// the . + /// + public bool HasNext { get; private set; } + + /// + /// Initializes the database reader. + /// + public void Initialize() + { + PrepareReader(); + MoveNext(); + } + + /// + /// Reads the information for the next soil profile from the database and creates a + /// instance of the information. + /// + /// The next from the database, or null + /// if no more soil profile can be read. + /// Thrown when reading properties of the profile failed. + /// Thrown when the database returned incorrect + /// values for required properties. + public SoilProfile2D ReadSoilProfile() + { + try + { + return TryReadSoilProfile(); + } + catch (SystemException exception) when (exception is FormatException || + exception is OverflowException || + exception is InvalidCastException) + { + string message = new FileReaderErrorMessageBuilder(Path).Build(Resources.SoilProfileReader_Error_reading_soil_profile_from_database); + throw new CriticalFileReadException(message, exception); + } + } + + public void MoveNext() + { + HasNext = MoveNext(dataReader); + } + + public T Read(string columnName) + { + return (T) dataReader[columnName]; + } + + public T ReadOrDefault(string columnName) + { + object valueObject = dataReader[columnName]; + if (valueObject.Equals(DBNull.Value)) + { + return default(T); + } + return (T) valueObject; + } + + protected override void Dispose(bool disposing) + { + if (dataReader != null) + { + dataReader.Close(); + dataReader.Dispose(); + dataReader = null; + } + base.Dispose(disposing); + } + + private void PrepareReader() + { + string subQueryGetNumberOfLayerProfile2D = + $"SELECT SP2D_ID, COUNT(*) as {SoilProfileTableDefinitions.LayerCount} " + + "FROM SoilLayer2D " + + "GROUP BY SP2D_ID"; + string subQueryGetMaterialPropertiesOfLayer = + "SELECT " + + "mat.MA_ID, " + + $"mat.MA_Name as {SoilProfileTableDefinitions.MaterialName}, " + + $"max(case when pn.PN_Name = 'Color' then pv.PV_Value end) {SoilProfileTableDefinitions.Color}, " + + $"max(case when pn.PN_Name = 'BelowPhreaticLevelStochast' then s.ST_Dist_Type end) {SoilProfileTableDefinitions.BelowPhreaticLevelDistribution}, " + + $"max(case when pn.PN_Name = 'BelowPhreaticLevelStochast' then s.ST_Shift end) {SoilProfileTableDefinitions.BelowPhreaticLevelShift}, " + + $"max(case when pn.PN_Name = 'BelowPhreaticLevelStochast' then s.ST_Mean end) {SoilProfileTableDefinitions.BelowPhreaticLevelMean}, " + + $"max(case when pn.PN_Name = 'BelowPhreaticLevelStochast' then s.ST_Deviation end) {SoilProfileTableDefinitions.BelowPhreaticLevelDeviation}, " + + $"max(case when pn.PN_Name = 'PermeabKxStochast' then s.ST_Dist_Type end) {SoilProfileTableDefinitions.PermeabilityDistribution}, " + + $"max(case when pn.PN_Name = 'PermeabKxStochast' then s.ST_Shift end) {SoilProfileTableDefinitions.PermeabilityShift}, " + + $"max(case when pn.PN_Name = 'PermeabKxStochast' then s.ST_Mean end) {SoilProfileTableDefinitions.PermeabilityMean}, " + + $"max(case when pn.PN_Name = 'PermeabKxStochast' then s.ST_Variation end) {SoilProfileTableDefinitions.PermeabilityCoefficientOfVariation}, " + + $"max(case when pn.PN_Name = 'DiameterD70Stochast' then s.ST_Dist_Type end) {SoilProfileTableDefinitions.DiameterD70Distribution}, " + + $"max(case when pn.PN_Name = 'DiameterD70Stochast' then s.ST_Shift end) {SoilProfileTableDefinitions.DiameterD70Shift}, " + + $"max(case when pn.PN_Name = 'DiameterD70Stochast' then s.ST_Mean end) {SoilProfileTableDefinitions.DiameterD70Mean}, " + + $"max(case when pn.PN_Name = 'DiameterD70Stochast' then s.ST_Variation end) {SoilProfileTableDefinitions.DiameterD70CoefficientOfVariation} " + + "FROM ParameterNames AS pn " + + "LEFT JOIN ParameterValues AS pv USING(PN_ID) " + + "LEFT JOIN Stochast AS s USING(PN_ID) " + + "JOIN Materials AS mat " + + "WHERE pv.MA_ID = mat.MA_ID OR s.MA_ID = mat.MA_ID " + + "GROUP BY mat.MA_ID "; + + string subQueryGetLayerPropertiesOfLayer2D = + "SELECT " + + "SL2D_ID, " + + $"PV_Value as {SoilProfileTableDefinitions.IsAquifer} " + + "FROM ParameterNames " + + "JOIN LayerParameterValues USING(PN_ID) " + + $"WHERE PN_NAME = '{SoilProfileTableDefinitions.IsAquifer}'"; + + string querySoilProfile21D = + "SELECT " + + $"sp2d.SP2D_Name as {SoilProfileTableDefinitions.ProfileName}, " + + $"layerCount.{SoilProfileTableDefinitions.LayerCount}, " + + $"sl2d.GeometrySurface as {SoilProfileTableDefinitions.LayerGeometry}, " + + $"mpl.X as {SoilProfileTableDefinitions.IntersectionX}, " + + $"{SoilProfileTableDefinitions.MaterialName}, " + + $"{SoilProfileTableDefinitions.IsAquifer}, " + + $"{SoilProfileTableDefinitions.Color}, " + + $"{SoilProfileTableDefinitions.BelowPhreaticLevelDistribution}, " + + $"{SoilProfileTableDefinitions.BelowPhreaticLevelShift}, " + + $"{SoilProfileTableDefinitions.BelowPhreaticLevelMean}, " + + $"{SoilProfileTableDefinitions.BelowPhreaticLevelDeviation}, " + + $"{SoilProfileTableDefinitions.DiameterD70Distribution}, " + + $"{SoilProfileTableDefinitions.DiameterD70Shift}, " + + $"{SoilProfileTableDefinitions.DiameterD70Mean}, " + + $"{SoilProfileTableDefinitions.DiameterD70CoefficientOfVariation}, " + + $"{SoilProfileTableDefinitions.PermeabilityDistribution}, " + + $"{SoilProfileTableDefinitions.PermeabilityShift}, " + + $"{SoilProfileTableDefinitions.PermeabilityMean}, " + + $"{SoilProfileTableDefinitions.PermeabilityCoefficientOfVariation}, " + + $"sp2d.SP2D_ID as {SoilProfileTableDefinitions.SoilProfileId} " + + "FROM Mechanism AS m " + + "JOIN Segment AS segment USING(ME_ID) " + + "JOIN (SELECT SSM_ID, SP1D_ID, SP2D_ID FROM StochasticSoilProfile GROUP BY SSM_ID, SP1D_ID, SP2D_ID) ssp USING(SSM_ID) " + + "JOIN SoilProfile2D sp2d USING (SP2D_ID) " + + "JOIN (" + + subQueryGetNumberOfLayerProfile2D + + ") layerCount USING (SP2D_ID) " + + "JOIN SoilLayer2D sl2d USING (SP2D_ID) " + + "LEFT JOIN MechanismPointLocation mpl USING(ME_ID, SP2D_ID) " + + "LEFT JOIN (" + + subQueryGetMaterialPropertiesOfLayer + + ") materialProperties USING(MA_ID) " + + "LEFT JOIN (" + + subQueryGetLayerPropertiesOfLayer2D + + ") layerProperties USING(SL2D_ID) " + + "GROUP BY sp2d.SP2D_ID, sl2d.SL2D_ID;"; + + try + { + dataReader = CreateDataReader(querySoilProfile21D); + } + catch (SQLiteException exception) + { + string message = new FileReaderErrorMessageBuilder(Path).Build(Resources.SoilProfileReader_Error_reading_soil_profile_from_database); + throw new CriticalFileReadException(message, exception); + } + } + + private SoilProfile2D TryReadSoilProfile() + { + var properties = new RequiredProfileProperties(this); + + var soilLayers = new List(); + + if (properties.LayerCount == 0) + { + MoveNext(); + } + else + { + for (var i = 1; i <= properties.LayerCount; i++) + { + soilLayers.Add(ReadSoilLayerFrom(this, properties.ProfileName)); + MoveNext(); + } + } + + return new SoilProfile2D(properties.ProfileId, + properties.ProfileName, + soilLayers); + } + + /// + /// Reads a from the given . + /// + /// Thrown when reading properties of the layers failed. + private static SoilLayer2D ReadSoilLayerFrom(IRowBasedDatabaseReader reader, string profileName) + { + var properties = new Layer2DProperties(reader, profileName); + + return new SoilLayer2D(); + } + + private class Layer2DProperties : LayerProperties + { + /// + /// Creates a new instance of , which contains properties + /// that are required to create a complete . If these properties + /// cannot be read, then the reader can proceed to the next profile. + /// + /// The to read the required layer property values from. + /// The profile name used in generating exceptions messages if casting failed. + /// Thrown when the values in the database could not be + /// casted to the expected column types. + internal Layer2DProperties(IRowBasedDatabaseReader reader, string profileName) + : base(reader, profileName) + { + const string readColumn = SoilProfileTableDefinitions.LayerGeometry; + try + { + GeometryValue = reader.Read(readColumn); + } + catch (InvalidCastException e) + { + string message = new FileReaderErrorMessageBuilder(reader.Path) + .WithSubject(string.Format(Resources.SoilProfileReader_SoilProfileName_0_, profileName)) + .Build(string.Format(Resources.SoilProfileReader_Profile_has_invalid_value_on_Column_0_, readColumn)); + throw new SoilProfileReadException(message, profileName, e); + } + } + + /// + /// Gets the geometry for the layer. + /// + public byte[] GeometryValue { get; } + } + + private class RequiredProfileProperties + { + /// + /// Creates a new instance of , which contains properties + /// that are required to create a complete . If these properties + /// cannot be read, then the reader can proceed to the next profile. + /// + /// The to read the required profile property values from. + /// Thrown when the values in the database could not be + /// casted to the expected column types. + internal RequiredProfileProperties(IRowBasedDatabaseReader reader) + { + string readColumn = SoilProfileTableDefinitions.ProfileName; + try + { + ProfileName = reader.Read(SoilProfileTableDefinitions.ProfileName); + + readColumn = SoilProfileTableDefinitions.IntersectionX; + IntersectionX = reader.Read(readColumn); + + readColumn = SoilProfileTableDefinitions.LayerCount; + LayerCount = reader.Read(readColumn); + + readColumn = SoilProfileTableDefinitions.SoilProfileId; + ProfileId = reader.Read(readColumn); + } + catch (InvalidCastException e) + { + string message = new FileReaderErrorMessageBuilder(reader.Path) + .WithSubject(string.Format(Resources.SoilProfileReader_SoilProfileName_0_, ProfileName)) + .Build(string.Format(Resources.SoilProfileReader_Profile_has_invalid_value_on_Column_0_, readColumn)); + throw new SoilProfileReadException(message, ProfileName, e); + } + } + + /// + /// The 1d intersection of the profile. + /// + public double IntersectionX { get; } + + /// + /// The name of the profile to read. + /// + public string ProfileName { get; } + + /// + /// The number of layers that the profile has to read. + /// + public long LayerCount { get; } + + /// + /// Gets the database identifier of the profile. + /// + public long ProfileId { get; } + } + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj =================================================================== diff -u -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -115,9 +115,12 @@ + + + Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer1DTest.cs =================================================================== diff -u -ra98b1f041d0befb17b61cbab82450309521c2fc7 -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer1DTest.cs (.../SoilLayer1DTest.cs) (revision a98b1f041d0befb17b61cbab82450309521c2fc7) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer1DTest.cs (.../SoilLayer1DTest.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -39,51 +39,27 @@ var layer = new SoilLayer1D(top); // Assert - Assert.NotNull(layer); + Assert.IsInstanceOf(layer); Assert.AreEqual(top, layer.Top); Assert.IsFalse(layer.IsAquifer); Assert.IsEmpty(layer.MaterialName); Assert.AreEqual(Color.Empty, layer.Color); + Assert.IsNull(layer.BelowPhreaticLevelDistribution); + Assert.IsNaN(layer.BelowPhreaticLevelShift); Assert.IsNaN(layer.BelowPhreaticLevelMean); Assert.IsNaN(layer.BelowPhreaticLevelDeviation); - Assert.IsNaN(layer.BelowPhreaticLevelShift); + Assert.IsNull(layer.DiameterD70Distribution); + Assert.IsNaN(layer.DiameterD70Shift); Assert.IsNaN(layer.DiameterD70Mean); Assert.IsNaN(layer.DiameterD70CoefficientOfVariation); + Assert.IsNull(layer.PermeabilityDistribution); + Assert.IsNaN(layer.PermeabilityShift); Assert.IsNaN(layer.PermeabilityMean); Assert.IsNaN(layer.PermeabilityCoefficientOfVariation); } - - [Test] - public void MaterialName_Null_ThrowsArgumentNullException() - { - // Setup - double top = new Random(22).NextDouble(); - var layer = new SoilLayer1D(top); - - // Call - TestDelegate test = () => layer.MaterialName = null; - - // Assert - string paramName = Assert.Throws(test).ParamName; - Assert.AreEqual("value", paramName); - } - - [Test] - public void MaterialName_NotNullValue_ValueSet() - { - // Setup - double top = new Random(22).NextDouble(); - var layer = new SoilLayer1D(top); - string materialName = "a name"; - - // Call - layer.MaterialName = materialName; - - // Assert - Assert.AreEqual(materialName, layer.MaterialName); - } + } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer2DTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer2DTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayer2DTest.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,61 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.Drawing; +using NUnit.Framework; +using Ringtoets.Common.IO.SoilProfile; + +namespace Ringtoets.Common.IO.Test.SoilProfile +{ + [TestFixture] + public class SoilLayer2DTest + { + [Test] + public void Constructor_ReturnsNewInstanceWithTopSet() + { + // Call + var layer = new SoilLayer2D(); + + // Assert + Assert.IsInstanceOf(layer); + Assert.IsFalse(layer.IsAquifer); + Assert.IsEmpty(layer.MaterialName); + Assert.AreEqual(Color.Empty, layer.Color); + Assert.IsNull(layer.OuterLoop); + CollectionAssert.IsEmpty(layer.InnerLoops); + + Assert.IsNull(layer.BelowPhreaticLevelDistribution); + Assert.IsNaN(layer.BelowPhreaticLevelShift); + Assert.IsNaN(layer.BelowPhreaticLevelMean); + Assert.IsNaN(layer.BelowPhreaticLevelDeviation); + + Assert.IsNull(layer.DiameterD70Distribution); + Assert.IsNaN(layer.DiameterD70Shift); + Assert.IsNaN(layer.DiameterD70Mean); + Assert.IsNaN(layer.DiameterD70CoefficientOfVariation); + + Assert.IsNull(layer.PermeabilityDistribution); + Assert.IsNaN(layer.PermeabilityShift); + Assert.IsNaN(layer.PermeabilityMean); + Assert.IsNaN(layer.PermeabilityCoefficientOfVariation); + } + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayerBaseTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayerBaseTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilLayerBaseTest.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,90 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.Drawing; +using NUnit.Framework; +using Ringtoets.Common.IO.SoilProfile; + +namespace Ringtoets.Common.IO.Test.SoilProfile +{ + [TestFixture] + public class SoilLayerBaseTest + { + [Test] + public void Constructor_ReturnsNewInstanceWithTopSet() + { + // Call + var layer = new TestSoilLayerBase(); + + // Assert + Assert.IsNotNull(layer); + Assert.IsFalse(layer.IsAquifer); + Assert.IsEmpty(layer.MaterialName); + Assert.AreEqual(Color.Empty, layer.Color); + + Assert.IsNull(layer.BelowPhreaticLevelDistribution); + Assert.IsNaN(layer.BelowPhreaticLevelShift); + Assert.IsNaN(layer.BelowPhreaticLevelMean); + Assert.IsNaN(layer.BelowPhreaticLevelDeviation); + + Assert.IsNull(layer.DiameterD70Distribution); + Assert.IsNaN(layer.DiameterD70Shift); + Assert.IsNaN(layer.DiameterD70Mean); + Assert.IsNaN(layer.DiameterD70CoefficientOfVariation); + + Assert.IsNull(layer.PermeabilityDistribution); + Assert.IsNaN(layer.PermeabilityShift); + Assert.IsNaN(layer.PermeabilityMean); + Assert.IsNaN(layer.PermeabilityCoefficientOfVariation); + } + + [Test] + public void MaterialName_Null_ThrowsArgumentNullException() + { + // Setup + var soilLayer = new TestSoilLayerBase(); + + // Call + TestDelegate test = () => soilLayer.MaterialName = null; + + // Assert + string paramName = Assert.Throws(test).ParamName; + Assert.AreEqual("value", paramName); + } + + [Test] + public void MaterialName_NotNullValue_ValueSet() + { + // Setup + var soilLayer = new TestSoilLayerBase(); + const string materialName = "a name"; + + // Call + soilLayer.MaterialName = materialName; + + // Assert + Assert.AreEqual(materialName, soilLayer.MaterialName); + } + + private class TestSoilLayerBase : SoilLayerBase {} + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DReaderTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DReaderTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DReaderTest.cs (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1,134 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU 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 General Public License for more details. +// +// You should have received a copy of the GNU 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.ObjectModel; +using System.IO; +using System.Linq; +using Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.TestUtil; +using Core.Common.Utils.Builders; +using NUnit.Framework; +using Ringtoets.Common.IO.SoilProfile; + +namespace Ringtoets.Common.IO.Test.SoilProfile +{ + [TestFixture] + public class SoilProfile2DReaderTest + { + private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Common.IO, nameof(SoilProfile2DReader)); + + [Test] + public void Constructor_NonExistingPath_ThrowsCriticalFileReadException() + { + // Setup + string testFile = Path.Combine(testDataPath, "does not exist"); + + // Call + TestDelegate test = () => + { + using (new SoilProfile2DReader(testFile)) {} + }; + + // Assert + var exception = Assert.Throws(test); + string expectedMessage = new FileReaderErrorMessageBuilder(testFile).Build("Het bestand bestaat niet."); + Assert.AreEqual(expectedMessage, exception.Message); + } + + [Test] + [TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))] + public void Constructor_FileNullOrEmpty_ThrowsCriticalFileReadException(string fileName) + { + // Call + TestDelegate test = () => + { + using (new SoilProfile2DReader(fileName)) {} + }; + + // Assert + Assert.Throws(test); + } + + [Test] + public void Constructor_PathToExistingFile_ExpectedValues() + { + // Setup + string dbFile = Path.Combine(testDataPath, "emptySchema.soil"); + + // Call + using (var reader = new SoilProfile2DReader(dbFile)) + { + // Assert + Assert.AreEqual(dbFile, reader.Path); + Assert.IsInstanceOf(reader); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] + public void Initialize_IncorrectFormatFile_ThrowsCriticalFileReadException() + { + // Setup + string dbFile = Path.Combine(testDataPath, "text.txt"); + + using (var reader = new SoilProfile2DReader(dbFile)) + { + // Call + TestDelegate test = () => reader.Initialize(); + + // Assert + var exception = Assert.Throws(test); + + string expectedMessage = new FileReaderErrorMessageBuilder(dbFile).Build( + "Kon geen ondergrondschematisaties verkrijgen uit de database."); + Assert.AreEqual(expectedMessage, exception.Message); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] + public void ReadSoilProfile_DatabaseWith2DSoilProfile_ReturnOneProfile() + { + // Setup + string dbFile = Path.Combine(testDataPath, "2dprofile.soil"); + + var result = new Collection(); + using (var reader = new SoilProfile2DReader(dbFile)) + { + reader.Initialize(); + + // Call + while (reader.HasNext) + { + result.Add(reader.ReadSoilProfile()); + } + } + + // Assert + Assert.AreEqual(1, result.Count); + Assert.AreEqual("Profile", result[0].Name); + Assert.AreEqual(3, result[0].Layers.Count()); + } + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DTest.cs =================================================================== diff -u -ree206fe08782d701c721a3cee64ab452352e1b0a -recd4d4b6e6b86aea559e4dee86f46850ee1477bf --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DTest.cs (.../SoilProfile2DTest.cs) (revision ee206fe08782d701c721a3cee64ab452352e1b0a) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilProfile2DTest.cs (.../SoilProfile2DTest.cs) (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -31,14 +31,21 @@ public void Constructor_ValidArguments_ReturnsExpectedProperties() { // Setup + const long id = 12; const string name = "some name"; + var soilLayer2Ds = new[] + { + new SoilLayer2D() + }; // Call - var soilProfile2D = new SoilProfile2D(name); + var soilProfile2D = new SoilProfile2D(id, name, soilLayer2Ds); // Assert Assert.IsInstanceOf(soilProfile2D); + Assert.AreEqual(id, soilProfile2D.Id); Assert.AreEqual(name, soilProfile2D.Name); + CollectionAssert.AreEqual(soilLayer2Ds, soilProfile2D.Layers); } } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/1dprofile.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/2dprofile.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/emptyschema.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/text.txt =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/text.txt (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SoilProfile2DReader/text.txt (revision ecd4d4b6e6b86aea559e4dee86f46850ee1477bf) @@ -0,0 +1 @@ \ No newline at end of file