using System; using System.Collections.Generic; using System.IO; using System.Xml.Linq; using Deltares.DamEngine.Calculators.General; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStability.Assemblers; using Deltares.DamEngine.Calculators.Properties; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard.Logging; namespace Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStability { public static class MStabXmlDoc { /// /// Create XML definition for Stability calculation /// /// /// /// /// /// /// /// /// /// /// public static XDocument CreateMStabXmlDoc(string mstabProjectFilename, DesignScenario scenario, SoilGeometryProbability subSoilScenario, double riverLevel, MStabDesignEmbankment mstabDesignEmbankment, SurfaceLine2 surfaceLine, double? trafficLoad, double requiredSafetyFactor, out List errorMessages) { errorMessages = new List(); var profile1D = subSoilScenario.SoilProfile1D; var soilGeometry2DName = subSoilScenario.StiFileName; ConsistencyCheck(scenario, profile1D, soilGeometry2DName); FailureMechanismeParamatersMStab failureMechanismeParamatersMStab = new FailureMechanismeParamatersMStab(); failureMechanismeParamatersMStab.Location = scenario.Location; if (profile1D != null) { failureMechanismeParamatersMStab.SoilProfile = profile1D; // 1d-geometry failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.SoilProfileType = SoilProfileType.ProfileType1D; } else { // 2d-geometry failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.SoilProfileType = SoilProfileType.ProfileType2D; } // 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.ModelParametersForPLLines.PLLineCreationMethod); if (scenario.Location.IntrusionVerticalWaterPressure != null) failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = scenario.Location.IntrusionVerticalWaterPressure.Value; failureMechanismeParamatersMStab.MStabParameters.GeometryCreationOptions.PenetrationLength = scenario.Location.ModelParametersForPLLines.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; if (trafficLoad != null) failureMechanismeParamatersMStab.TrafficLoad = trafficLoad.Value; // 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?.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, SafetyFactorZone1A = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? requiredSafetyFactor, SafetyFactorZone1B = scenario.ModelFactors.RequiredSafetyFactorStabilityInnerSlope ?? requiredSafetyFactor, XCoordinateDikeTopAtPolder = dikeTopAtPolder.X, XCoordinateDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X, XCoordinateStartRestProfile = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X }; if (scenario.Location.StabilityOptions?.ZoneAreaRestSlopeCrestWidth != null) { failureMechanismeParamatersMStab.MStabParameters.ZoneAreas.DikeTableWidth = scenario.Location.StabilityOptions.ZoneAreaRestSlopeCrestWidth.Value; } } if (failureMechanismeParamatersMStab.MStabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone)) { failureMechanismeParamatersMStab.MStabParameters.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; // ToDo bka #zant: riverLevelLow is not used. In classic it was used in CreateAllPLLines } double? riverLevelHigh = riverLevel; var surfaceLevelOutside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); if (riverLevelHigh < surfaceLevelOutside.Z) { var riverLevelHighIsBelowSurfaceLevelOutside = Path.GetFileName(mstabProjectFilename) + ": " + Resources.MStabXmlDoc_CreateMStabXmlDoc_RiverLevelHighIsBelowSurfaceLevelOutside; LogMessage logMessage = new LogMessage(LogMessageType.Warning, null, string.Format(riverLevelHighIsBelowSurfaceLevelOutside, riverLevelHigh, surfaceLevelOutside.Z)); errorMessages.Add(logMessage); } var currentSurfaceLine = scenario.GetMostRecentSurfaceLine(subSoilScenario.SoilProfile1D, Path.GetFileName(soilGeometry2DName)); if (currentSurfaceLine == null) { currentSurfaceLine = surfaceLine; } var waterLevel = riverLevelHigh.Value; UpliftSituation upliftSituation; failureMechanismeParamatersMStab.PLLines = PlLinesHelper.CreatePlLinesForStability( scenario.Location, subSoilScenario, waterLevel, soilGeometry2DName, out upliftSituation); // // ToDo zant Move this CreateAllPLLines to CalculationHelper. riverLevelLow used for stability outwards only // var calculator = new StabilityCalculator(failureMechanismeParamatersMStab, // ProgramType.MStab, // scenario.Location.ModelParametersForPLLines, // scenario.Location.TrafficLoad, // scenario.Location.MinimalCircleDepth, // requiredSafetyFactor, // "", // null, // scenario.Location.GaugePLLines, // scenario.Location.Gauges, // scenario.Location.SoilList); // failureMechanismeParamatersMStab.PLLines = calculator.CreateAllPLLines( // scenario.Location, surfaceLine, soilProfile, soilGeometry2DName, waterLevel, riverLevelLow); // Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculation if (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 = CalculationHelper.GetLocationWithLowestUpliftFactor(currentSurfaceLine, subSoilScenario.SoilProfile1D, 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; 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; } public static MStabForbiddenZone CreateForbiddenZone(DesignScenario scenario, SurfaceLine2 surfaceLine) { var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); // Zonestype is ForbiddenZone; TODO: Combine with code in StabilityCalculator? var zoneFactor = 1.0; if (scenario.Location.StabilityOptions?.ForbiddenZoneFactor != null) { zoneFactor = scenario.Location.StabilityOptions.ForbiddenZoneFactor.Value; } double maxZoneX = dikeTopAtPolder.X + zoneFactor * (surfaceLine.GetDikeToeInward().X - dikeTopAtPolder.X); return new MStabForbiddenZone { IsXEntryMinUsed = false, XEntryMin = 0.0, IsXEntryMaxUsed = true, XEntryMax = maxZoneX }; } /// /// /// /// /// /// public static void ConsistencyCheck(DesignScenario 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)); } } } } }