// Copyright (C) Stichting Deltares 2023. 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.General.PlLines; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; namespace Deltares.DamEngine.Calculators.Uplift { /// /// Determie uplift location and uplift factor /// public class UpliftLocationDeterminator { public bool IsUseOvenDryUnitWeight { get; set; } public PlLines PlLines { get; set; } public SurfaceLine2 SurfaceLine { get; set; } public SoilProfile1D SoilProfile { get; set; } public SoilProfile2D SoilProfile2D { get; set; } public string SoilGeometry2DName { get; set; } public Soil DikeEmbankmentMaterial { get; set; } // public SoilbaseDB SoilBaseDB { get; set; } public SoilList SoilList { get; set; } public double XSoilGeometry2DOrigin { get; set; } /// /// Constructor /// public UpliftLocationDeterminator() { IsUseOvenDryUnitWeight = false; } /// /// Get location nearest dike with and upliftfactor lower than required /// /// location and upliftfactor public UpliftLocationAndResult GetLocationAndResult(double upliftCriterion) { ThrowIfNoPlLinesDefined(); ThrowIfNoSurfaceLinDefined(); ThrowIfNoSoilProfileDefined(); return GetLocationInPolderNearestDikeWithUpliftFactorLowerThanRequired(upliftCriterion); } /// /// Get location nearest dike with and upliftfactor lower than required /// /// location and upliftfactor public UpliftLocationAndResult GetLocationInPolderNearestDikeWithUpliftFactorLowerThanRequired(double upliftCriterion) { ThrowIfNoPlLinesDefined(); ThrowIfNoSurfaceLinDefined(); ThrowIfNoSoilProfileDefined(); GeometryPoint startSurfacePoint = SurfaceLine.GetDikeToeInward(); IEnumerable relevantSurfacePointsList = from GeometryPoint point in SurfaceLine.Geometry.Points where point.X >= startSurfacePoint.X orderby point.X ascending select point; bool foundUpliftFactor = false; UpliftLocationAndResult upliftLocationAndResult = null; foreach (GeometryPoint surfacePoint in relevantSurfacePointsList) { upliftLocationAndResult = GetUpliftFactorAtPoint(surfacePoint); if ((upliftLocationAndResult != null) && (upliftLocationAndResult.UpliftFactor < upliftCriterion)) { foundUpliftFactor = true; upliftLocationAndResult.X = surfacePoint.X; upliftLocationAndResult.Z = surfacePoint.Z; break; } } return foundUpliftFactor ? upliftLocationAndResult : null; } /// /// Create upliftcalculator at given point /// /// GeometryPoint for which to calculate upliftfactor /// Top of layer where uplift occurs /// location and upliftfactor private UpliftCalculator CreateUpliftCalculator(GeometryPoint point, double topOfLayer, SoilProfile1D soilProfile) { PlLine phreaticLine = PlLines.Lines[PlLineType.Pl1]; return new UpliftCalculator { PhreaticLevel = phreaticLine.ZFromX(point.X), SoilProfile = soilProfile, TopOfLayerToBeEvaluated = topOfLayer, SurfaceLevel = point.Z, UnitWeightSoilEmbankment = (this.DikeEmbankmentMaterial == null) ? (double?) null : this.DikeEmbankmentMaterial.AbovePhreaticLevel, IsUseOvenDryUnitWeight = this.IsUseOvenDryUnitWeight }; } /// /// Calculate upliftfactor for given point /// /// /// location and upliftfactor public UpliftLocationAndResult GetUpliftFactorAtPoint(GeometryPoint point) { SoilProfile1D soilProfileInCurrentPoint = GetSoilProfileBelowPoint(point.X); double upliftFactorForInBetweenSandLayer = double.MaxValue; if (soilProfileInCurrentPoint.InBetweenAquiferLayer != null) { // Check if inbetween sandlayer below surface double topInBetweenSandLayer = soilProfileInCurrentPoint.InBetweenAquiferLayer.TopLevel; if (topInBetweenSandLayer < point.Z) { // There is an aquitard above the aquifer, for which we can determine the uplift factor UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, topInBetweenSandLayer, soilProfileInCurrentPoint); if ( (PlLines.Lines[PlLineType.Pl4] != null) && (PlLines.Lines[PlLineType.Pl4].Points.Count > 0 )) upliftFactorForInBetweenSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl4].ZFromX(point.X)); } else { if (soilProfileInCurrentPoint.GetBottomLevel(soilProfileInCurrentPoint.InBetweenAquiferLayer) < point.Z) { // The surface cuts into the aquifer so the level to be evaluated is at surfacelevel UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, point.Z, soilProfileInCurrentPoint); if ((PlLines.Lines[PlLineType.Pl4] != null) && (PlLines.Lines[PlLineType.Pl4].Points.Count > 0)) upliftFactorForInBetweenSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl4].ZFromX(point.X)); } } } double upliftFactorForBottomSandLayer = double.MaxValue; if (soilProfileInCurrentPoint.BottomAquiferLayer != null) { // Check if bottom sandlayer below surface double topBottomSandLayer = soilProfileInCurrentPoint.BottomAquiferLayer.TopLevel; if (topBottomSandLayer < point.Z) { UpliftCalculator upliftCalculatorForBottomSandLayer = CreateUpliftCalculator(point, soilProfileInCurrentPoint.BottomAquiferLayer.TopLevel, soilProfileInCurrentPoint); if ((PlLines.Lines[PlLineType.Pl3] != null) && (PlLines.Lines[PlLineType.Pl3].Points.Count > 0)) upliftFactorForBottomSandLayer = upliftCalculatorForBottomSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl3].ZFromX(point.X)); } else { if (soilProfileInCurrentPoint.GetBottomLevel(soilProfileInCurrentPoint.BottomAquiferLayer) < point.Z) { // The surface cuts into the aquifer so the level to be evaluated is at surfacelevel UpliftCalculator upliftCalculatorForInBetweenSandLayer = CreateUpliftCalculator(point, point.Z, soilProfileInCurrentPoint); if ((PlLines.Lines[PlLineType.Pl3] != null) && (PlLines.Lines[PlLineType.Pl3].Points.Count > 0)) upliftFactorForBottomSandLayer = upliftCalculatorForInBetweenSandLayer.CalculateUpliftFactor(PlLines.Lines[PlLineType.Pl3].ZFromX(point.X)); } } } if((upliftFactorForBottomSandLayer == double.MaxValue) && (upliftFactorForInBetweenSandLayer == double.MaxValue)) return null; if (upliftFactorForBottomSandLayer < upliftFactorForInBetweenSandLayer) { return new UpliftLocationAndResult(point, upliftFactorForBottomSandLayer, soilProfileInCurrentPoint.BottomAquiferLayer.Name); } else { return new UpliftLocationAndResult(point, upliftFactorForInBetweenSandLayer, soilProfileInCurrentPoint.InBetweenAquiferLayer.Name); } } /// /// Determine location with lowest upliftfactor /// /// location and upliftfactor public UpliftLocationAndResult GetLocationAtWithLowestUpliftFactor() { double? lowestUpliftFactor = null; ThrowIfNoPlLinesDefined(); ThrowIfNoSurfaceLinDefined(); ThrowIfNoSoilProfileDefined(); GeometryPoint startSurfacePoint = SurfaceLine.GetDikeToeInward(); IEnumerable relevantSurfacePointsList = from GeometryPoint point in SurfaceLine.Geometry.Points where point.X >= startSurfacePoint.X orderby point.X ascending select point; UpliftLocationAndResult upliftLocationAndResult = null; UpliftLocationAndResult lowestUpliftLocationAndResult = null; foreach (GeometryPoint surfacePoint in relevantSurfacePointsList) { upliftLocationAndResult = GetUpliftFactorAtPoint(surfacePoint); if (upliftLocationAndResult != null) { if (!lowestUpliftFactor.HasValue || upliftLocationAndResult.UpliftFactor < lowestUpliftFactor) { lowestUpliftFactor = upliftLocationAndResult.UpliftFactor; lowestUpliftLocationAndResult = upliftLocationAndResult; } } } return lowestUpliftLocationAndResult; } /// /// /// /// /// private SoilProfile1D GetSoilProfileBelowPoint(double xCoordinate) { if (this.SoilProfile != null) { var soilProfile1D = SoilProfileHelper.DetermineForSurfaceLineCorrected1DProfileAtX(SoilProfile, SurfaceLine, xCoordinate, DikeEmbankmentMaterial); return soilProfile1D; } if (SoilProfile2D != null) { return SoilProfile2D.GetSoilProfile1D(xCoordinate); } // This possibly should become conversion from StixFile throw new NotImplementedException(@"Using full 2D geometry (based on stix file) not yet available."); } /// /// Check on precondition /// private void ThrowIfNoPlLinesDefined() { if (PlLines == null) throw new UpliftLocationDeterminatorException("Required pllines not found"); } /// /// Check on precondition /// private void ThrowIfNoSurfaceLinDefined() { if (SurfaceLine == null) throw new UpliftLocationDeterminatorException("Required surfaceLine line not found"); } /// /// Check on precondition /// private void ThrowIfNoSoilProfileDefined() { if (SoilProfile == null && (SoilGeometry2DName == null || SoilGeometry2DName == "") && SoilProfile2D == null) throw new UpliftLocationDeterminatorException("Required soilProfile not found"); } } }