Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs =================================================================== diff -u -r4906 -r4909 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 4906) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 4909) @@ -88,7 +88,7 @@ SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(); Assert.Multiple(() => { - Assert.That(soilProfile1D.InBetweenAquiferClusters.Count, Is.EqualTo(2).Within(precision3Decimals)); + Assert.That(soilProfile1D.InBetweenAquiferClusters, Has.Count.EqualTo(2).Within(precision3Decimals)); Assert.That(soilProfile1D.InBetweenAquiferClusters[0].Item1.TopLevel, Is.EqualTo(-2.111).Within(precision3Decimals)); Assert.That(soilProfile1D.InBetweenAquiferClusters[0].Item2.BottomLevel, Is.EqualTo(-3.373).Within(precision3Decimals)); Assert.That(soilProfile1D.InBetweenAquiferClusters[1].Item1.TopLevel, Is.EqualTo(-4.151).Within(precision3Decimals)); @@ -264,7 +264,7 @@ Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); - Assert.That(waternet.WaternetLineList.Count, Is.EqualTo(1)); + Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(1)); Assert.That(waternet.WaternetLineList[0].HeadLine.Name, Is.SameAs(waternet.PhreaticLine.Name)); }); } @@ -858,7 +858,7 @@ AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[1].Points); AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[2].Points); - Assert.That(waternet.WaternetLineList.Count, Is.EqualTo(4)); + Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(4)); WaternetLine pl1WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl1WaternetLine.HeadLine.Name, Is.SameAs(waternet.PhreaticLine.Name)); @@ -1174,7 +1174,7 @@ AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[1].Points); AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[2].Points); - Assert.That(waternet.WaternetLineList.Count, Is.EqualTo(1)); + Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(1)); Assert.That(waternet.WaternetLineList[0].HeadLine.Name, Is.SameAs(waternet.PhreaticLine.Name)); } @@ -1220,7 +1220,7 @@ AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[1].Points); AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[2].Points); - Assert.That(waternet.WaternetLineList.Count, Is.EqualTo(1)); + Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(1)); Assert.That(waternet.WaternetLineList[0].HeadLine.Name, Is.SameAs(waternet.PhreaticLine.Name)); } Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs =================================================================== diff -u -r4906 -r4909 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs (.../SoilProfile1D.cs) (revision 4906) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilProfile1D.cs (.../SoilProfile1D.cs) (revision 4909) @@ -48,7 +48,7 @@ /// public class SoilProfile1D : SoilProfile { - private const double DefaultBottomLayerHeight = 20.0; + private const double defaultBottomLayerHeight = 20.0; private readonly DelegatedList layers = new DelegatedList(); private double bottomLevel = double.NaN; @@ -112,7 +112,7 @@ { if (double.IsNaN(bottomLevel) && layers.Count > 0) { - bottomLevel = Layers.Last().TopLevel - DefaultBottomLayerHeight; + bottomLevel = Layers.Last().TopLevel - defaultBottomLayerHeight; } return bottomLevel; @@ -214,53 +214,19 @@ { return null; } - - IList sortedLayers = Layers.OrderByDescending(l => l.TopLevel).ToList(); - IList<(SoilLayer1D, SoilLayer1D)> aquiferLayers = new List<(SoilLayer1D, SoilLayer1D)>(); - SoilLayer1D highestAquiferSoFar = null; - // Search the aquifer layers with an aquitard above - for (var layerIndex = 1; layerIndex < sortedLayers.Count - 1; layerIndex++) + IList sortedLayers = Layers.OrderByDescending(l => l.TopLevel).ToList(); + IList topLayers = DetermineTopLayersOfInBetweenAquiferClusters(sortedLayers); + if (topLayers.Count <= 0) { - SoilLayer1D previousLayer = sortedLayers[layerIndex - 1]; - SoilLayer1D layer = sortedLayers[layerIndex]; - SoilLayer1D nextLayer = sortedLayers[layerIndex + 1]; - - if (IsAquiferLayer(layer)) - { - if (!IsAquiferLayer(previousLayer)) - { - - if (!IsAquiferLayer(nextLayer)) - { - aquiferLayers.Add(new ValueTuple(layer, layer)); - } - else - { - highestAquiferSoFar = layer; - } - } - else - { - if (!IsAquiferLayer(nextLayer) && highestAquiferSoFar != null) - { - aquiferLayers.Add(new ValueTuple(highestAquiferSoFar, layer)); - highestAquiferSoFar = null; - } - } - } - - if (layerIndex >= sortedLayers.IndexOf(BottomAquiferLayer)) - { - break; - } + return null; } - return aquiferLayers.Count == 0 ? null : aquiferLayers; - + IList bottomLayers = DetermineBottomLayersOfInBetweenAquiferClusters(sortedLayers, layers.IndexOf(topLayers.First())); + return topLayers.Count != bottomLayers.Count ? null : topLayers.Select((topLayer, i) => new ValueTuple(topLayer, bottomLayers[i])).ToList(); } } - + /// /// 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. @@ -391,7 +357,7 @@ SoilLayer1D bottomLayer = Layers.Last(); if (bottomLayer.Height.IsZero()) { - BottomLevel -= DefaultBottomLayerHeight; + BottomLevel -= defaultBottomLayerHeight; } } @@ -576,6 +542,40 @@ return Name; } + private List DetermineTopLayersOfInBetweenAquiferClusters(IList sortedLayers) + { + List topLayers = []; + for (var layerIndex = 1; layerIndex < sortedLayers.Count - 1; layerIndex++) + { + SoilLayer1D previousLayer = sortedLayers[layerIndex - 1]; + SoilLayer1D layer = sortedLayers[layerIndex]; + + if (IsAquiferLayer(layer) && !IsAquiferLayer(previousLayer) && layerIndex < sortedLayers.IndexOf(BottomAquiferLayer)) + { + topLayers.Add(layer); + } + } + + return topLayers; + } + + private List DetermineBottomLayersOfInBetweenAquiferClusters(IList sortedLayers, int indexStart) + { + List bottomLayers = []; + for (int layerIndex = indexStart; layerIndex < sortedLayers.Count - 1; layerIndex++) + { + SoilLayer1D layer = sortedLayers[layerIndex]; + SoilLayer1D nextLayer = sortedLayers[layerIndex + 1]; + + if (IsAquiferLayer(layer) && !IsAquiferLayer(nextLayer) && layerIndex < sortedLayers.IndexOf(BottomAquiferLayer)) + { + bottomLayers.Add(layer); + } + } + + return bottomLayers; + } + /// /// Ares the layers ordered descending. /// Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs =================================================================== diff -u -r4906 -r4909 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 4906) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 4909) @@ -109,27 +109,7 @@ } } - plLine = plLines.Lines[PlLineType.Pl4]; - headLine = CreateLine(plLine, headLine4Name); - if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) - { - waternet.HeadLineList.Add(headLine); - if (soilProfile1D.InBetweenAquiferClusters != null) - { - foreach ((SoilLayer1D, SoilLayer1D) inBetweenAquiferCluster in soilProfile1D.InBetweenAquiferClusters) - { - if (inBetweenAquiferCluster is { Item1: not null, Item2: not null }) - { - double levelTop = inBetweenAquiferCluster.Item1.TopLevel; - double levelBottom = inBetweenAquiferCluster.Item2.BottomLevel; - WaternetLine waternetLine = CreateWaternetLine(levelTop, levelBottom, xLeft, xRight); - waternetLine.Name = waternetLine4Name; - waternetLine.HeadLine = headLine; - waternet.WaternetLineList.Add(waternetLine); - } - } - } - } + CreateWaternetLinesForInBetweenAquifers(plLines, soilProfile1D, xLeft, xRight, waternet); AdjustWaternetLineOfPhreaticLineWhenCoincidingWithOtherWaternetLines(waternet); return waternet; @@ -210,7 +190,7 @@ return waternetLine; } - internal static WaternetLine CreateWaternetLine(double levelTop, double levelBottom, double xLeft, double xRight) + private static WaternetLine CreateWaternetLine(double levelTop, double levelBottom, double xLeft, double xRight) { var waternetLine = new WaternetLine(); waternetLine.Points.Add(new GeometryPoint(xLeft, levelTop)); @@ -234,6 +214,28 @@ return xCoordinates; } + private static void CreateWaternetLinesForInBetweenAquifers(PlLines plLines, SoilProfile1D soilProfile1D, double xLeft, double xRight, Waternet waternet) + { + PlLine plLine = plLines.Lines[PlLineType.Pl4]; + var headLine = CreateLine(plLine, headLine4Name); + if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) + { + waternet.HeadLineList.Add(headLine); + if (soilProfile1D.InBetweenAquiferClusters != null) + { + foreach ((SoilLayer1D, SoilLayer1D) inBetweenAquiferCluster in soilProfile1D.InBetweenAquiferClusters.Where(layer => layer is { Item1: not null, Item2: not null })) + { + double levelTop = inBetweenAquiferCluster.Item1.TopLevel; + double levelBottom = inBetweenAquiferCluster.Item2.BottomLevel; + WaternetLine waternetLine = CreateWaternetLine(levelTop, levelBottom, xLeft, xRight); + waternetLine.Name = waternetLine4Name; + waternetLine.HeadLine = headLine; + waternet.WaternetLineList.Add(waternetLine); + } + } + } + } + private static void CreateWaternetLinesForInBetweenAquifers(Waternet waternet, SoilProfile2D soilProfile, PlLine plLine) { if (plLine == null) @@ -373,9 +375,9 @@ foreach (double xCoordinate in xCoordinatesAll) { SoilProfile1D crossSection = soilProfile.GetSoilProfile1D(xCoordinate); + // Determine if the layer is in range of the previous layer // If not, return empty coordinates, because the layer is interrupted - SoilLayer1D currentAquifer = GetSoilLayer1D(layerType, crossSection, indexInBetweenAquifer); if (previousAquiferLayer != null && currentAquifer != null && !AreHorizontallyConnected(previousAquiferLayer, currentAquifer)) @@ -392,14 +394,20 @@ // Perform a short validation that the coordinates are fully defined from the beginning to the end // of the profile. If not, the layer is not continuous. - if (!coordinates.Any() || coordinates.First().X != xCoordinates.First() || coordinates.Last().X != xCoordinates.Last()) + if (!IsLayerBoundaryContinuous(coordinates, xCoordinates.First(), xCoordinates.Last())) { return Enumerable.Empty(); } return coordinates; } + private static bool IsLayerBoundaryContinuous(List boundaryPoints, double leftGeometryBoundary, double rightGeometryBoundary) + { + return boundaryPoints.Any() && (Math.Abs(boundaryPoints.First().X - leftGeometryBoundary) < epsilon) + && Math.Abs(boundaryPoints.Last().X - rightGeometryBoundary) < epsilon; + } + private static SoilLayer1D GetSoilLayer1D(LayerType layerType, SoilProfile1D soilProfile1D, int indexInBetweenAquifer) { switch (layerType) @@ -565,15 +573,13 @@ { const double minimumDistance = 0.001; WaternetLine waternetLine1 = waternet.WaternetLineList.Find(w => w.Name == waternetLine1Name); - foreach (WaternetLine waternetLineOther in waternet.WaternetLineList.FindAll(w => w.Name != waternetLine1Name)) + foreach (GeometryPoint waternetLine1Point + in from waternetLineOther in waternet.WaternetLineList.FindAll(w => w.Name != waternetLine1Name) + from waternetLine1Point in waternetLine1.Points + where waternetLineOther.Points.Any(point => Math.Abs(point.Z - waternetLine1Point.Z) < epsilon) + select waternetLine1Point) { - foreach (GeometryPoint waternetLine1Point in waternetLine1.Points) - { - if (waternetLineOther.Points.Any(point => Math.Abs(point.Z - waternetLine1Point.Z) < epsilon)) - { - waternetLine1Point.Z += minimumDistance; - } - } + waternetLine1Point.Z += minimumDistance; } } @@ -586,19 +592,7 @@ if (xCoordinatesToBeAdded.Count > 0) { - for (var i = 0; i < xCoordinatesToBeAdded.Count; i++) - { - var point1 = new Point2D(xCoordinatesToBeAdded[i], Math.Max(line.BeginPoint.Z, line.EndPoint.Z) + 1); - var point2 = new Point2D(xCoordinatesToBeAdded[i], Math.Min(line.BeginPoint.Z, line.EndPoint.Z) - 1); - double zCoordinate = line.GetIntersectPointXz(new Line(point1, point2)).Z; - - var middlePoint = new Point2D(xCoordinatesToBeAdded[i], zCoordinate); - Point2D beginPoint = i == 0 ? line.BeginPoint : middlePoint; - Point2D endPoint = i == xCoordinatesToBeAdded.Count - 1 ? line.EndPoint : middlePoint; - - splitLines.Add(new Line(beginPoint, middlePoint)); - splitLines.Add(new Line(middlePoint, endPoint)); - } + SplitLineAtXCoordinate(xCoordinatesToBeAdded, line, splitLines); } else { @@ -609,6 +603,23 @@ return splitLines; } + private static void SplitLineAtXCoordinate(List xCoordinatesToBeAdded, Line line, List splitLines) + { + for (var i = 0; i < xCoordinatesToBeAdded.Count; i++) + { + var point1 = new Point2D(xCoordinatesToBeAdded[i], Math.Max(line.BeginPoint.Z, line.EndPoint.Z) + 1); + var point2 = new Point2D(xCoordinatesToBeAdded[i], Math.Min(line.BeginPoint.Z, line.EndPoint.Z) - 1); + double zCoordinate = line.GetIntersectPointXz(new Line(point1, point2)).Z; + + var middlePoint = new Point2D(xCoordinatesToBeAdded[i], zCoordinate); + Point2D beginPoint = i == 0 ? line.BeginPoint : middlePoint; + Point2D endPoint = i == xCoordinatesToBeAdded.Count - 1 ? line.EndPoint : middlePoint; + + splitLines.Add(new Line(beginPoint, middlePoint)); + splitLines.Add(new Line(middlePoint, endPoint)); + } + } + private static List DivideCurvesIntoLines(List curves) { var lines = new List();