// Copyright (C) Stichting Deltares 2017. 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; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Xml.Serialization; using Deltares.DamEngine.Calculators.Uplift; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Data.General.TimeSeries; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamEngine.Calculators.General; using Deltares.DamEngine.Calculators.PlLinesCreator; using Deltares.DamEngine.Calculators.Stability; using Deltares.DamEngine.Data.General.Results; using Parallel = Deltares.DamEngine.Calculators.General.Parallel; namespace Deltares.DamEngine.Calculators { public class DamProjectCalculator { private readonly DamProjectData damProjectData; private readonly Object lockObject = new object(); private int maxCalculationCores = 255; private string slopeWProgramPath = ""; private string mStabProgramPath = ""; private string calculationBaseDirectory = ""; /// /// Constructor /// /// public DamProjectCalculator(DamProjectData damProjectData) { this.damProjectData = damProjectData; } /// /// Base directory where the project is stored /// Needed to find the 2d geometries /// public string ProjectDataDirectory { get; set; } public ProgressDelegate Progress { get; set; } /// /// Properties /// public string CalculationBaseDirectory { get { return calculationBaseDirectory; } set { calculationBaseDirectory = value; } } public string MStabProgramPath { get { return mStabProgramPath; } set { mStabProgramPath = value; } } public string SlopeWProgramPath { get { return slopeWProgramPath; } set { slopeWProgramPath = value; } } public int MaxCalculationCores { get { return maxCalculationCores; } set { maxCalculationCores = value; } } /// /// Validate if all parameters are available for calculation of project /// public void ValidateGeneral() { // ToDo make this intelligent depending on the specification ThrowHelper.ThrowWhenConditionIsTrue("No actual calculation specified.", () => damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications.Count == 0); } /// /// Validate if all parameters are available for calculation of project /// public void ValidateSpecification() { // ToDo make this intelligent depending on the specification if (damProjectData.ProgramType == ProgramType.MStab) { ThrowHelper.ThrowIfFileNotExist(MStabProgramPath, StringResourceNames.MStabExecutableFileNameNotFound); } if (damProjectData.ProgramType == ProgramType.SlopeW) { ThrowHelper.ThrowIfFileNotExist(SlopeWProgramPath, StringResourceNames.SlopeWExecutableFileNameNotFound); } } /// /// Perform the calculations /// public List> Calculate(DamProjectData damProjectData, IList scenarios) { foreach (var scenario in scenarios) { if (damProjectData.Dike.Locations.Contains(scenario.Location)) { damProjectData.Dike.UpdateLocation(scenario.Location); break; } } ValidateGeneral(); Parallel.Run((IList) scenarios, RunScenario, Progress, MaxCalculationCores); var allCalculationResults = scenarios.Select(scenario => scenario.CalculationResults).ToList(); PostprocessForStabilityUpliftVanBishop(ref allCalculationResults); this.damProjectData.UpdateDesignCalculations(); return allCalculationResults; } /// /// Determine where lowest uplift factor occurs and the value of that factor /// /// /// /// /// /// /// /// public double? GetLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PLLines plLines, Location location) { var upliftLocationDeterminator = new UpliftLocationDeterminator() { SurfaceLine = surfaceLine, SoilProfile = soilProfile, SoilGeometry2DName = soilGeometry2DName, //SoilBaseDB = location.SoilbaseDB, SoilList = location.SoilList, DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(), PLLines = plLines, XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin }; UpliftLocationAndResult upliftLocationAndResult = upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor(); if (upliftLocationAndResult != null) { return upliftLocationAndResult.UpliftFactor; } return null; } /// /// Determines whether it is a combined stability bishop and liftvan calculation. /// /// The calculation specification. /// /// true if it is a stability bishop and liftvan calculation; otherwise, false. /// private bool IsStabilityBishopLiftVanCalculation(DamFailureMechanismeCalculationSpecification calculationSpecification) { return ((calculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && ((MStabModelType) calculationSpecification.CalculationModel == MStabModelType.BishopUpliftVan)); } /// /// Calculate one scenario /// /// private void RunScenario(object scenarioTask) { var scenario = (DesignScenario) scenarioTask; var scenarioName = scenario.Location.Name; Debug.WriteLine(String.Format("Start thread for location '{0}'", scenarioName)); Location oldLocation = null; try { oldLocation = scenario.Location; var scenarioId = scenario.LocationScenarioID; Debug.WriteLine("Location '{0}', scenario '{1}'", scenarioName, scenarioId); scenario.ClearResults(); scenario.ClearErrors(); CloneLocationOnScenario(scenario); if (scenario.PlLineOffsetBelowDikeToeAtPolder.HasValue) { scenario.Location.PlLineOffsetBelowDikeToeAtPolder = scenario.PlLineOffsetBelowDikeToeAtPolder.Value; } if (scenario.PlLineOffsetBelowDikeTopAtPolder.HasValue) { scenario.Location.PlLineOffsetBelowDikeTopAtPolder = scenario.PlLineOffsetBelowDikeTopAtPolder.Value; } if (scenario.PlLineOffsetBelowDikeTopAtRiver.HasValue) { scenario.Location.PlLineOffsetBelowDikeTopAtRiver = scenario.PlLineOffsetBelowDikeTopAtRiver.Value; } if (scenario.PlLineOffsetBelowShoulderBaseInside.HasValue) { scenario.Location.PlLineOffsetBelowShoulderBaseInside = scenario.PlLineOffsetBelowShoulderBaseInside.Value; } if (scenario.PlLineOffsetBelowDikeCrestMiddle.HasValue) { scenario.Location.PlLineOffsetBelowDikeCrestMiddle = scenario.PlLineOffsetBelowDikeCrestMiddle; } if (scenario.PlLineOffsetFactorBelowShoulderCrest.HasValue) { scenario.Location.PlLineOffsetFactorBelowShoulderCrest = scenario.PlLineOffsetFactorBelowShoulderCrest; } if (scenario.UsePlLineOffsetBelowDikeCrestMiddle.HasValue) { scenario.Location.UsePlLineOffsetBelowDikeCrestMiddle = scenario.UsePlLineOffsetBelowDikeCrestMiddle; } if (scenario.UsePlLineOffsetFactorBelowShoulderCrest.HasValue) { scenario.Location.UsePlLineOffsetFactorBelowShoulderCrest = scenario.UsePlLineOffsetFactorBelowShoulderCrest; } if (scenario.HeadPl3.HasValue) { scenario.Location.HeadPl3 = scenario.HeadPl3.Value; } if (scenario.HeadPl4.HasValue) { scenario.Location.HeadPl4 = scenario.HeadPl4.Value; } var selectedKernelType = StabilityKernelType.DamClassic; var damProjectCalculationSpecification = damProjectData.DamProjectCalculationSpecification; var spec = damProjectCalculationSpecification.DamCalculationSpecifications.First(); if (spec != null) { selectedKernelType = spec.StabilityKernelType; } if (DetermineStabilityUpliftForScenarios(scenario, selectedKernelType)) { // Save the results after each calculation, because these will be deleted in the next calculation var calculationresults = new List(); foreach (var calculationSpecification in damProjectCalculationSpecification.DamCalculationSpecifications) { var selectedProbabilisticType = damProjectCalculationSpecification.SelectedProbabilisticType; var analysisType = DamProjectCalculationSpecification.SelectedAnalysisType; Debug.WriteLine("Location '{0}', scenario '{1}' 10", scenarioName, scenarioId); ValidateSpecification(); if (IsStabilityBishopLiftVanCalculation(calculationSpecification)) { Debug.WriteLine("Location '{0}', scenario '{1}' 11", scenarioName, scenarioId); CalculateStabilityBishopUpliftvanForScenario(scenario, calculationSpecification, selectedProbabilisticType, analysisType); } else { Debug.WriteLine("Location '{0}', scenario '{1}' 15", scenarioName, scenarioId); CalculateOneCalculationTypeForScenario(scenario, calculationSpecification, selectedProbabilisticType, analysisType); } Debug.WriteLine("Location '{0}', scenario '{1}' 20", scenarioName, scenarioId); calculationresults.AddRange(scenario.CalculationResults); } // Assign the combined results to the scenario scenario.CalculationResults.Clear(); scenario.CalculationResults.AddRange(calculationresults); } } catch (Exception exception) { scenario.Errors.Add(exception.Message); } finally { if( oldLocation != null) { scenario.Location = oldLocation; } } } private void CloneLocationOnScenario(DesignScenario scenario) { lock (lockObject) { // // TODO missing clone method for Location. This is a dirty way of performing a clone. // var locationUsedInCalculation = new XmlSerializer().SerializeToString(scenario.Location); // var location = new XmlDeserializer().XmlDeserializeFromString(locationUsedInCalculation); // scenario.Location = location; ##Bka replace with object copier. } } /// /// Calculates combined stability bishop and upliftvan for scenario. /// /// The scenario. /// The calculation specification. /// Type of the probabilistic. /// Type of the analysis. private void CalculateStabilityBishopUpliftvanForScenario(DesignScenario scenario, DamFailureMechanismeCalculationSpecification calculationSpecification, ProbabilisticType probabilisticType, AnalysisType analysisType) { var bishopCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); bishopCalculationSpecification.Assign(calculationSpecification); bishopCalculationSpecification.CalculationModel = MStabModelType.Bishop; var liftvanCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); liftvanCalculationSpecification.Assign(calculationSpecification); liftvanCalculationSpecification.CalculationModel = MStabModelType.UpliftVan; // Make sure check on uplift is performed before doing UpliftVan calculation liftvanCalculationSpecification.FailureMechanismeParamatersMStab.IsStabilityCheckOnUplift = true; // First perform calculate Bishop CalculateOneCalculationTypeForScenario(scenario, bishopCalculationSpecification, probabilisticType, analysisType); // Save the results, because these will be deleted in the next calculation var calculationresults = new List(); calculationresults.AddRange(scenario.CalculationResults); // Now run LiftVan calculation CalculateOneCalculationTypeForScenario(scenario, liftvanCalculationSpecification, probabilisticType, analysisType); // Combine Bishop and Liftvan results and assign them to the scenario calculationresults.AddRange(scenario.CalculationResults); scenario.CalculationResults.Clear(); scenario.CalculationResults.AddRange(calculationresults); } /// /// Calculates one calculation type for scenario. /// /// The scenario. /// The dam failure mechanisme calculation specification. /// Type of the probabilistic. /// Type of the analysis. private void CalculateOneCalculationTypeForScenario( DesignScenario scenario, DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification, ProbabilisticType probabilisticType, AnalysisType analysisType) { var dike = damProjectData.Dike; var damProjectCalculatorLogBuilder = new DamProjectCalculatorCsvExportDataBuilder ( dike, scenario, damFailureMechanismeCalculationSpecification, analysisType, probabilisticType ); scenario.ClearResults(); scenario.ClearErrors(); var damFailureMechanismeCalculator = new DamFailureMechanismeCalculator( damProjectData.ProgramType, damFailureMechanismeCalculationSpecification, MStabProgramPath, SlopeWProgramPath, dike.MapForSoilGeometries2D, probabilisticType); damFailureMechanismeCalculator.CalculationBaseDirectory = CalculationBaseDirectory; if (analysisType == AnalysisType.AdaptNWO) { damFailureMechanismeCalculator.NonWaterRetainingObject = dike.NonWaterRetainingObjects[0]; } if (damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside || damFailureMechanismeCalculationSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside) { StabilityCalculator.ModelSubDirectory = damFailureMechanismeCalculationSpecification.FailureMechanismeParamatersMStab.MStabParameters.Model.ToString(); } try { damFailureMechanismeCalculator.Calculate(analysisType, scenario); foreach (var error in scenario.Errors) { var logMessage = new LogMessage(LogMessageType.Error, null, error); damFailureMechanismeCalculator.ErrorMessages.Add(logMessage); } foreach (var errorMessage in damFailureMechanismeCalculator.ErrorMessages) { //LogManager.Messages.Add(errorMessage);##Bka } var recordIndex = 0; var firstNwoSoilProfileProbability = true; var validSoilProfileProbabilities = DamFailureMechanismeCalculator.SelectProbabilitiesForFailureMechanism( damFailureMechanismeCalculationSpecification.FailureMechanismSystemType, scenario.Location.Segment.SoilProfileProbabilities); foreach (var soilProfileProbability in validSoilProfileProbabilities) { if (analysisType == AnalysisType.AdaptNWO) { if (firstNwoSoilProfileProbability) { // for NWO, only add results for every first soilProfileProbability as the others are already part of the nwo results. foreach (var nwoResult in scenario.NwoResults) { var resultMessage = scenario.GetResultMessage( nwoResult.SoilProfileProbability.SoilProfile, nwoResult.SoilProfileProbability.SoilGeometry2DName); // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a scv file damProjectCalculatorLogBuilder.Append( @"""", ++recordIndex, " - ", resultMessage, " - ", nwoResult.NwoId, " - ", nwoResult.LocationXrdStart, " - ", nwoResult.MStabResults.CalculationName, @"""" ); scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(nwoResult.SoilProfileProbability, scenario.NwoResults.IndexOf(nwoResult))); scenario.CalculationResult = CalculationResult.Succeeded; } foreach (var error in scenario.Errors) { damProjectCalculatorLogBuilder.Append(error); scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); scenario.CalculationResult = CalculationResult.Succeeded; } firstNwoSoilProfileProbability = false; } else { if (scenario.CalculationResult != CalculationResult.NoRun) { // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a csv file string resultMessage = scenario.GetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); damProjectCalculatorLogBuilder.Append( @"""", ++recordIndex, " - ", resultMessage, @"""" ); scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); } scenario.CalculationResult = CalculationResult.Succeeded; } } else { // The error message can contain "," and ";" and should therefor be surrounded with double quotes, so it will be read correctly as a scv file var resultMessage = scenario.GetResultMessage( soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName); damProjectCalculatorLogBuilder.Append( @"""", ++recordIndex, " - ", resultMessage, @"""" ); scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability, damFailureMechanismeCalculationSpecification.StabilityKernelType)); scenario.CalculationResult = CalculationResult.Succeeded; } } } catch (Exception exception) { damProjectCalculatorLogBuilder.Append("Error: ", exception.Message); var innerException = exception.InnerException; while (innerException != null) { damProjectCalculatorLogBuilder.Append(": ", innerException.Message); innerException = innerException.InnerException; } foreach (var error in scenario.Errors) { var logMessage = new LogMessage(LogMessageType.Error, null, error); //LogManager.Messages.Add(logMessage);##Bka } foreach (var errorMessage in damFailureMechanismeCalculator.ErrorMessages) { // LogManager.Messages.Add(errorMessage);##Bka } foreach (var soilProfileProbability in scenario.Location.Segment.SoilProfileProbabilities) { if (soilProfileProbability.SegmentFailureMechanismType == null || soilProfileProbability.SegmentFailureMechanismType == damFailureMechanismeCalculationSpecification.FailureMechanismSystemType) { scenario.CalculationResults.Add(damProjectCalculatorLogBuilder.Build(soilProfileProbability)); scenario.CalculationResult = CalculationResult.UnexpectedError; } } throw; } } /// /// Determine for each scenario if uplift occurs /// /// /// /// private bool DetermineStabilityUpliftForScenarios(DesignScenario scenario, StabilityKernelType stabilityKernelType) { if (stabilityKernelType == StabilityKernelType.AdvancedWti || stabilityKernelType == StabilityKernelType.AdvancedDotNet) { return true; } var res = true; Dike dike = damProjectData.Dike; double upliftCriterion = scenario.GetUpliftCriterionStability(scenario.Location.ModelFactors.UpliftCriterionStability); foreach (var soilProfileProbability in scenario.Location.Segment.SoilProfileProbabilities) { if (soilProfileProbability.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityInside || soilProfileProbability.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityOutside || soilProfileProbability.SegmentFailureMechanismType == null) { try { SurfaceLine2 surfaceLineWithNewHeight = DamFailureMechanismeCalculator.RedesignSurfaceLineHeight(FailureMechanismSystemType.StabilityInside, scenario, scenario.Location.LocalXZSurfaceLine2); // for scenarios the uplift should be calculated with the redesigned height, else a problem may occur with the waterlevel above the dike var upliftSituation = new UpliftSituation(); PLLines plLines = CreateAllPLLines(out upliftSituation, scenario.RiverLevel, scenario.RiverLevelLow, scenario.Location, soilProfileProbability, surfaceLineWithNewHeight); if (plLines != null) { string fullSoilGeometry2DName = (soilProfileProbability.SoilGeometry2DName == null) ? null : Path.Combine(ProjectDataDirectory, Path.Combine(dike.MapForSoilGeometries2D, soilProfileProbability.SoilGeometry2DName)); double? upliftFactor = GetLowestUpliftFactor(surfaceLineWithNewHeight, soilProfileProbability.SoilProfile, fullSoilGeometry2DName, plLines, scenario.Location); upliftSituation.IsUplift = (upliftFactor < upliftCriterion); } else { upliftSituation.IsUplift = false; } scenario.SetStabilityUpliftSituation(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, upliftSituation); } catch (Exception exception) { string errorMessage = String.Format("{0} in location '{1}' scenario '{2}' soilprofile '{3}'", exception.Message, scenario.Location.Name, scenario.LocationScenarioID, soilProfileProbability.SoilGeometryName); scenario.SetResultMessage(soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, exception.Message); var resultRecord = new DesignResult("Error: " + exception.Message, damProjectData.DamProjectCalculationSpecification.DamCalculationSpecifications[0], scenario, soilProfileProbability.SoilProfile, soilProfileProbability.SoilGeometry2DName, DamProjectCalculationSpecification.SelectedAnalysisType, 0, damProjectData.DamProjectCalculationSpecification.SelectedProbabilisticType); scenario.CalculationResults.Add(resultRecord); scenario.Errors.Add(errorMessage); scenario.CalculationResult = CalculationResult.RunFailed; res = false; } } } foreach (var error in scenario.Errors) { var logMessage = new LogMessage(LogMessageType.Error, null, error); //LogManager.Messages.Add(logMessage); ##Bka } return res; } /// /// Determines whether the specified calculation result is Bishop. /// /// The calculation result. /// /// true if it is Bishop; otherwise, false. /// private bool IsBishopResult(DesignResult calculationResult) { return ((calculationResult.DamFailureMechanismeCalculation.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && (calculationResult.DamFailureMechanismeCalculation.FailureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.Bishop)); } /// /// Determines whether the specified calculation result is UpliftVan. /// /// The calculation result. /// /// true if it is UpliftVan; otherwise, false. /// private bool IsUpliftVanResult(DesignResult calculationResult) { return ((calculationResult.DamFailureMechanismeCalculation.FailureMechanismSystemType == FailureMechanismSystemType.StabilityInside) && (calculationResult.DamFailureMechanismeCalculation.FailureMechanismeParamatersMStab.MStabParameters.Model == MStabModelType.UpliftVan)); } /// /// Create new results depending on Uplift /// /// private void PostprocessForStabilityUpliftVanBishop(ref List> allCalculationResults) { var normativeCalculationResults = new List(); var bishopCalculationResults = new List(); var upliftVanCalculationResults = new List(); // First collect all Bishop and Uplift calculations foreach (var calculationResults in allCalculationResults) { if (calculationResults.Count > 0) { foreach (var calculationResult in calculationResults) { if (IsBishopResult(calculationResult)) { bishopCalculationResults.Add(calculationResult); } if (IsUpliftVanResult(calculationResult)) { upliftVanCalculationResults.Add(calculationResult); } } } } if ((bishopCalculationResults.Any()) && (upliftVanCalculationResults.Any())) { var bishopLiftvancalculation = bishopCalculationResults[0].DamFailureMechanismeCalculation.Clone(); bishopLiftvancalculation.FailureMechanismeParamatersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan; foreach (var bishopCalculationRecord in bishopCalculationResults) { DesignResult liftVanCalculationResult = (from calculationResult in upliftVanCalculationResults where calculationResult.LocationName.Equals(bishopCalculationRecord.LocationName) && calculationResult.ScenarioName.Equals(bishopCalculationRecord.ScenarioName) && calculationResult.ProfileName.Equals(bishopCalculationRecord.ProfileName) select calculationResult).ToList().FirstOrDefault(); DesignResult normativeCalculationResult = SelectStabilityNormativeResult(bishopCalculationRecord, liftVanCalculationResult, DamProjectCalculationSpecification.SelectedAnalysisType); // Clone this result, to make sure the original won't be changed normativeCalculationResult = (DesignResult) normativeCalculationResult.Clone(); normativeCalculationResult.DamFailureMechanismeCalculation = bishopLiftvancalculation; normativeCalculationResults.Add(normativeCalculationResult); // Add the normative result also to the scenario normativeCalculationResult.Scenario.CalculationResults.Add(normativeCalculationResult); } allCalculationResults.Add(normativeCalculationResults); } } /// /// Select which result is the norm for stability Bishop/UpliftVan calculation /// /// /// /// private DesignResult SelectStabilityNormativeResult(DesignResult bishopCalculationRecord, DesignResult liftVanCalculationResult, AnalysisType analysisType) { switch (analysisType) { case AnalysisType.NoAdaption: { return SelectStabilityNormativeResultDeterministicNormal(liftVanCalculationResult, bishopCalculationRecord); } case AnalysisType.AdaptNWO: case AnalysisType.AdaptGeometry: { return SelectStabilityNormativeResultDeterministicDesign(liftVanCalculationResult, bishopCalculationRecord); } default: throw new ArgumentOutOfRangeException("analysisType"); } } /// /// Select which result is the norm for stability Bishop/UpliftVan normal deterministic calculation /// /// /// /// private DesignResult SelectStabilityNormativeResultDeterministicNormal(DesignResult liftVanCalculationResult, DesignResult bishopCalculationRecord) { if ((liftVanCalculationResult != null) && (liftVanCalculationResult.SafetyFactor.HasValue)) { if ((bishopCalculationRecord != null) && (bishopCalculationRecord.SafetyFactor.HasValue)) { return (liftVanCalculationResult.SafetyFactor.Value < bishopCalculationRecord.SafetyFactor.Value ? liftVanCalculationResult : bishopCalculationRecord); } else { return liftVanCalculationResult; } } else { return bishopCalculationRecord; } } /// /// Select which result is the norm for stability Bishop/UpliftVan design deterministic calculation /// /// /// /// private DesignResult SelectStabilityNormativeResultDeterministicDesign(DesignResult liftVanCalculationResult, DesignResult bishopCalculationRecord) { if ((liftVanCalculationResult != null) && (liftVanCalculationResult.SafetyFactor.HasValue)) { if ((bishopCalculationRecord != null) && (bishopCalculationRecord.SafetyFactor.HasValue)) { bool dla = liftVanCalculationResult.DikeLength.HasValue; dla = dla && bishopCalculationRecord.DikeLength.HasValue; if (dla && (Math.Abs(liftVanCalculationResult.DikeLength.Value - bishopCalculationRecord.DikeLength.Value) < GeometryPoint.Precision)) { return (liftVanCalculationResult.SafetyFactor < bishopCalculationRecord.SafetyFactor ? liftVanCalculationResult : bishopCalculationRecord); } else { return (liftVanCalculationResult.DikeLength > bishopCalculationRecord.DikeLength ? liftVanCalculationResult : bishopCalculationRecord); } } else { return liftVanCalculationResult; } } else { return bishopCalculationRecord; } } /// /// Create PLLines with selected model /// /// /// /// /// /// /// the created pl lines private PLLines CreateAllPLLines(out UpliftSituation upliftSituation, double waterLevel, double? waterLevelLow, Location location, SoilGeometryProbability soilProfileProbability, SurfaceLine2 surfaceLine) { switch (location.ModelParametersForPLLines.PLLineCreationMethod) { case PLLineCreationMethod.ExpertKnowledgeLinearInDike: case PLLineCreationMethod.ExpertKnowledgeRRD: case PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD: return CreateAllPLLinesExpertKnowledge(out upliftSituation, waterLevel, waterLevelLow, location, soilProfileProbability, surfaceLine); default: upliftSituation.Pl3HeadAdjusted = 0; upliftSituation.Pl3LocationXMinUplift = 0; upliftSituation.Pl3MinUplift = 0; upliftSituation.Pl4HeadAdjusted = 0; upliftSituation.Pl4LocationXMinUplift = 0; upliftSituation.Pl4MinUplift = 0; upliftSituation.IsUplift = false; // must be determined later on; just to avoid compiler error return null; } } /// /// Create PLLines with expert knowledge /// /// /// /// /// /// /// the created pl lines private PLLines CreateAllPLLinesExpertKnowledge(out UpliftSituation upliftSituation, double waterLevel, double? waterLevelLow, Location location, SoilGeometryProbability soilProfileProbability, SurfaceLine2 surfaceLine) { var plLinesCreator = new PLLinesCreator(); // Determine geometry type SoilGeometryType soilGeometryType = soilProfileProbability.SoilGeometryType; string mapForSoilGeometries2D = location.MapForSoilGeometries2D; SoilProfile1D soilProfile = soilProfileProbability.SoilProfile; string soilGeometry2DName = soilProfileProbability.SoilGeometry2DName; if ((soilProfileProbability.SoilGeometry2DName != null) && (mapForSoilGeometries2D != null)) { soilGeometry2DName = Path.Combine(mapForSoilGeometries2D, soilGeometry2DName); soilGeometry2DName = Path.Combine(ProjectDataDirectory, soilGeometry2DName); } plLinesCreator.WaterLevelRiverHigh = waterLevel; plLinesCreator.WaterLevelRiverLow = waterLevelLow; plLinesCreator.IsUseLowWaterLevel = (damProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside); plLinesCreator.SurfaceLine = surfaceLine; plLinesCreator.WaterLevelPolder = location.PolderLevel; plLinesCreator.HeadInPLLine2 = location.HeadPL2; plLinesCreator.HeadInPLLine3 = location.HeadPl3; plLinesCreator.HeadInPLLine4 = location.HeadPl4; plLinesCreator.ModelParametersForPLLines = location.ModelParametersForPLLines; plLinesCreator.SoilProfile = soilProfile; plLinesCreator.SoilGeometry2DName = soilGeometry2DName; plLinesCreator.SoilGeometryType = soilGeometryType; plLinesCreator.GaugePLLines = location.GaugePLLines; plLinesCreator.Gauges = location.Gauges; plLinesCreator.GaugeMissVal = location.GaugeMissVal; plLinesCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; // for stability this must set to true plLinesCreator.SoilList = location.SoilList; plLinesCreator.DikeEmbankmentMaterial = location.SoilList.GetSoilByName(location.DikeEmbankmentMaterial); plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; plLinesCreator.PlLineOffsetBelowShoulderBaseInside = location.PlLineOffsetBelowShoulderBaseInside; plLinesCreator.PlLineOffsetBelowDikeToeAtPolder = location.PlLineOffsetBelowDikeToeAtPolder; plLinesCreator.PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle; plLinesCreator.PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest; plLinesCreator.UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle; plLinesCreator.UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest; plLinesCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; //PLLines plLines = plLinesCreator.CreateAllPLLines(location); ##Bka upliftSituation.Pl3HeadAdjusted = plLinesCreator.Pl3HeadAdjusted; upliftSituation.Pl3LocationXMinUplift = plLinesCreator.Pl3LocationXMinUplift; upliftSituation.Pl3MinUplift = plLinesCreator.Pl3MinUplift; upliftSituation.Pl4HeadAdjusted = plLinesCreator.Pl4HeadAdjusted; upliftSituation.Pl4LocationXMinUplift = plLinesCreator.Pl4LocationXMinUplift; upliftSituation.Pl4MinUplift = plLinesCreator.Pl4MinUplift; upliftSituation.IsUplift = false; // must be determined later on; just to avoid compiler error return null; //plLines; ##Bka } } }