Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs =================================================================== diff -u -r935ddb05bb15494732dea93d6c67a40bb318fb85 -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs (.../PipingSoilProfile.cs) (revision 935ddb05bb15494732dea93d6c67a40bb318fb85) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingSoilProfile.cs (.../PipingSoilProfile.cs) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -115,9 +115,9 @@ /// does not contain . public double GetLayerThickness(PipingSoilLayer layer) { - var orderedLayers = layers.OrderBy(l => l.Top); + var layersOrderedByTopAscending = layers.Reverse(); var previousLevel = Bottom; - foreach (var oLayer in orderedLayers) + foreach (var oLayer in layersOrderedByTopAscending) { if (ReferenceEquals(layer, oLayer)) { @@ -132,5 +132,56 @@ { return Name; } + + /// + /// Retrieves the thickness of the topmost aquifer layer under a certain . + /// Only the thickness of the part of the aquifer layer under the level is determined. + /// Aquifer layers above are not considered. + /// + /// The level under which the aquifer layer is sought. + /// The thickness of the part of the topmost aquifer layer under the . + /// is less than . + public double GetTopAquiferLayerThicknessBelowLevel(double level) + { + ValidateLevelToBottom(level); + + PipingSoilLayer currentTopAquiferLayer = null; + foreach (var pipingSoilLayer in Layers) + { + if (pipingSoilLayer.Top > level) + { + currentTopAquiferLayer = null; + } + if (currentTopAquiferLayer != null && pipingSoilLayer.Top <= level) + { + break; + } + if (pipingSoilLayer.IsAquifer) + { + currentTopAquiferLayer = pipingSoilLayer; + } + } + return GetLayerThicknessBelowLevel(currentTopAquiferLayer, level); + } + + private void ValidateLevelToBottom(double level) + { + if (level < Bottom) + { + var message = string.Format(Resources.PipingSoilProfile_GetTopAquiferLayerThicknessBelowLevel_Level_0_below_Bottom_1_, level, Bottom); + throw new ArgumentException(message); + } + } + + private double GetLayerThicknessBelowLevel(PipingSoilLayer layer, double level) + { + var thickness = double.NaN; + if (layer != null) + { + double thicknessAboveLevel = Math.Max(0, layer.Top - level); + thickness = GetLayerThickness(layer) - thicknessAboveLevel; + } + return thickness; + } } } \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.Designer.cs =================================================================== diff -u -ra887863a3992744a394591e17072811eb9478ebc -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision a887863a3992744a394591e17072811eb9478ebc) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -241,6 +241,15 @@ } /// + /// Looks up a localized string similar to Level {0} is below the bottom of the soil profile {1}.. + /// + public static string PipingSoilProfile_GetTopAquiferLayerThicknessBelowLevel_Level_0_below_Bottom_1_ { + get { + return ResourceManager.GetString("PipingSoilProfile_GetTopAquiferLayerThicknessBelowLevel_Level_0_below_Bottom_1_", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Eén of meerdere lagen hebben een top onder de bodem van het profiel.. /// public static string PipingSoilProfile_Layers_Layer_top_below_profile_bottom { Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.resx =================================================================== diff -u -ra887863a3992744a394591e17072811eb9478ebc -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.resx (.../Resources.resx) (revision a887863a3992744a394591e17072811eb9478ebc) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/Properties/Resources.resx (.../Resources.resx) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -204,4 +204,7 @@ Eén of meerdere lagen hebben een top onder de bodem van het profiel. + + Level {0} is below the bottom of the soil profile {1}. + \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/Extensions/PipingInputExtensions.cs =================================================================== diff -u -r935ddb05bb15494732dea93d6c67a40bb318fb85 -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/Extensions/PipingInputExtensions.cs (.../PipingInputExtensions.cs) (revision 935ddb05bb15494732dea93d6c67a40bb318fb85) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/Extensions/PipingInputExtensions.cs (.../PipingInputExtensions.cs) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -90,7 +90,7 @@ if (soilProfile != null && surfaceLine != null && !double.IsNaN(exitPointL)) { - thicknessTopAquiferLayer = GetTopAquiferLayerThicknessBelowSurfaceLine(soilProfile, surfaceLine, exitPointL); + thicknessTopAquiferLayer = soilProfile.GetTopAquiferLayerThicknessBelowLevel(surfaceLine.GetZAtL(exitPointL)); } return thicknessTopAquiferLayer; @@ -108,37 +108,6 @@ } } - private static double GetTopAquiferLayerThicknessBelowSurfaceLine(PipingSoilProfile profile, RingtoetsPipingSurfaceLine surfaceLine, double atL) - { - double surfaceLineTop = surfaceLine.GetZAtL(atL); - PipingSoilLayer[] layers = profile.Layers.ToArray(); - PipingSoilLayer topAquiferLayer = null; - var thickness = double.NaN; - - var i = layers.Length - 1; - - while (i >= 0) - { - PipingSoilLayer pipingSoilLayer = layers.ElementAt(i); - if (pipingSoilLayer.Top < surfaceLineTop && topAquiferLayer != null) - { - break; - } - if (pipingSoilLayer.IsAquifer) - { - topAquiferLayer = pipingSoilLayer; - } - i--; - } - - if (topAquiferLayer != null) - { - thickness = profile.GetLayerThickness(topAquiferLayer); - thickness -= Math.Max(0, topAquiferLayer.Top - surfaceLineTop); - } - return thickness; - } - private static void UpdateThicknessCoverageLayer(this PipingInput input) { double derivedThickness = GetThicknessCoverageLayer(input); Index: Ringtoets/Piping/test/Ringtoets.Piping.Data.Test/PipingSoilProfileTest.cs =================================================================== diff -u -rdc2b06cb5a46cf2508d28fe9a6f8dcaa710346a7 -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/test/Ringtoets.Piping.Data.Test/PipingSoilProfileTest.cs (.../PipingSoilProfileTest.cs) (revision dc2b06cb5a46cf2508d28fe9a6f8dcaa710346a7) +++ Ringtoets/Piping/test/Ringtoets.Piping.Data.Test/PipingSoilProfileTest.cs (.../PipingSoilProfileTest.cs) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -137,6 +137,255 @@ } [Test] + public void GetTopAquiferLayerThicknessBelowLevel_NoAquiferLayer_NaN() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1), + new PipingSoilLayer(1.1) + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.0); + + // Assert + Assert.IsNaN(result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_AquiferLayerAboveLevel_NaN() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.1) + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.0); + + // Assert + Assert.IsNaN(result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_AquiferLayerCompletelyBelowLevel_ReturnAquiferLayerThickness() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(2.2); + + // Assert + Assert.AreEqual(2.1, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_AquiferLayerPartlyBelowLevel_ReturnAquiferLayerThicknessUpTillLevel() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.6); + + // Assert + Assert.AreEqual(1.6, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_AquiferLayerTopEqualToLevel_ReturnAquiferLayerThickness() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(1.6) + { + IsAquifer = true + }, + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.6); + + // Assert + Assert.AreEqual(1.6, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_TwoAquiferLayersCompletelyBelowLevel_ReturnTopAquiferLayerThickness() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.1) + { + IsAquifer = true + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(2.2); + + // Assert + Assert.AreEqual(1.0, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_TopmostAquiferLayerTopEqualToLevel_ReturnTopAquiferLayerThickness() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.1) + { + IsAquifer = true + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(2.1); + + // Assert + Assert.AreEqual(1.0, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_TopmostAquiferLayerCompletelyAboveLevel_ReturnBottomAquiferLayerThickness() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.5) + { + IsAquifer = false + }, + new PipingSoilLayer(1.1) + { + IsAquifer = true + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.3); + + // Assert + Assert.AreEqual(1.1, result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_TopmostAquiferLayerPartlyAboveLevel_ReturnTopAquiferLayerThicknessUpTillLevel() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.1) + { + IsAquifer = true + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(1.5); + + // Assert + Assert.AreEqual(0.4, result, 1e-8); + } + + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_AllAquiferLayersAboveLevel_NaN() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(2.1) + { + IsAquifer = true + }, + new PipingSoilLayer(1.1) + { + IsAquifer = true + }, + new PipingSoilLayer(0.6) + { + IsAquifer = false + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, pipingSoilLayers); + + // Call + var result = profile.GetTopAquiferLayerThicknessBelowLevel(0.5); + + // Assert + Assert.IsNaN(result); + } + + [Test] + public void GetTopAquiferLayerThicknessBelowLevel_LevelBelowProfile_ArgumentException() + { + // Setup + var pipingSoilLayers = new[] + { + new PipingSoilLayer(1.1) + { + IsAquifer = true + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.5, pipingSoilLayers); + + // Call + TestDelegate call = () => profile.GetTopAquiferLayerThicknessBelowLevel(0.0); + + // Assert + var message = string.Format("Level {0} is below the bottom of the soil profile {1}.", 0.0, 0.5); + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(call, message); + } + + [Test] [TestCase(null)] [TestCase("")] [TestCase("some name")] Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Extensions/PipingInputExtensionsTest.cs =================================================================== diff -u -r935ddb05bb15494732dea93d6c67a40bb318fb85 -r96a31b6c1e568fbbe87fb72f13f0a76b065bdf77 --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Extensions/PipingInputExtensionsTest.cs (.../PipingInputExtensionsTest.cs) (revision 935ddb05bb15494732dea93d6c67a40bb318fb85) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Extensions/PipingInputExtensionsTest.cs (.../PipingInputExtensionsTest.cs) (revision 96a31b6c1e568fbbe87fb72f13f0a76b065bdf77) @@ -665,7 +665,7 @@ input.SetExitPointL(input.ExitPointL); // Assert - Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean); + Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean, 1e-8); } [Test] @@ -801,7 +801,7 @@ input.SetSurfaceLine(input.SurfaceLine); // Assert - Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean); + Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean, 1e-8); } [Test] @@ -937,7 +937,7 @@ input.SetSoilProfile(input.SoilProfile); // Assert - Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean); + Assert.AreEqual(expectedThickness, input.ThicknessAquiferLayer.Mean, 1e-8); } [Test] @@ -961,13 +961,13 @@ var input = CreateInputWithAquiferAndCoverageLayer(); input.SoilProfile = new PipingSoilProfile(String.Empty, 0, new[] { - new PipingSoilLayer(0.0) - { - IsAquifer = true - }, new PipingSoilLayer(2.0) { IsAquifer = false + }, + new PipingSoilLayer(0.0) + { + IsAquifer = true } }); @@ -986,11 +986,11 @@ var input = CreateInputWithAquiferAndCoverageLayer(); input.SoilProfile = new PipingSoilProfile(String.Empty, 0, new[] { - new PipingSoilLayer(1.5) + new PipingSoilLayer(2.5) { IsAquifer = true }, - new PipingSoilLayer(2.5) + new PipingSoilLayer(1.5) { IsAquifer = true } @@ -1028,13 +1028,13 @@ }); var soilProfile = new PipingSoilProfile(String.Empty, 0, new[] { - new PipingSoilLayer(1.0) - { - IsAquifer = true - }, new PipingSoilLayer(2.0) { IsAquifer = false + }, + new PipingSoilLayer(1.0) + { + IsAquifer = true } }); var input = new PipingInput(new GeneralPipingInput()); @@ -1086,27 +1086,24 @@ private static PipingInput CreateInputWithMultipleAquiferLayersUnderSurfaceLine(out double expectedThickness) { var surfaceLine = new RingtoetsPipingSurfaceLine(); - var firstAquiferThickness = 1.1; - var secondAquiferThickness = 2.2; - var totalAquiferThickness = firstAquiferThickness + secondAquiferThickness; surfaceLine.SetGeometry(new[] { - new Point3D(0, 0, totalAquiferThickness), - new Point3D(1.0, 0, totalAquiferThickness), + new Point3D(0, 0, 3.3), + new Point3D(1.0, 0, 3.3), }); var soilProfile = new PipingSoilProfile(String.Empty, 0, new[] { - new PipingSoilLayer(firstAquiferThickness) + new PipingSoilLayer(4.3) { - IsAquifer = true + IsAquifer = false }, - new PipingSoilLayer(firstAquiferThickness + secondAquiferThickness) + new PipingSoilLayer(3.3) { IsAquifer = true }, - new PipingSoilLayer(totalAquiferThickness + 1) + new PipingSoilLayer(1.1) { - IsAquifer = false + IsAquifer = true } }); var input = new PipingInput(new GeneralPipingInput()) @@ -1115,7 +1112,7 @@ SoilProfile = soilProfile, ExitPointL = 0.5 }; - expectedThickness = secondAquiferThickness; + expectedThickness = 2.2; return input; } #endregion