// Copyright (C) Stichting Deltares 2018. 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.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.Properties; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.RegionalAssessmentResults; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Language; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamPiping.BlighCalculator; using Deltares.DamPiping.Sellmeijer4ForcesCalculator; namespace Deltares.DamEngine.Calculators.DikesAssessmentRegional { /// /// Exception for RegionalScenariosCalculation class /// public class RegionalScenariosCalculationException : ApplicationException { public RegionalScenariosCalculationException() { } public RegionalScenariosCalculationException(string message) : base(message) { } } /// /// Class to perform the calculation of reginal scenarios /// /// public class RegionalScenariosCalculation : ICalculation { private DamProjectData damProjectData; public List Execute(DamProjectData aDamProjectData) { damProjectData = aDamProjectData; maxCalculationCores = damProjectData.MaxCalculationCores; var dj = damProjectData.DikeJob; evaluationJob = damProjectData.GetEvaluationJob(); //evaluationJob.Locations.AddRange(); Run(); return new List(); } private IKernelWrapper CreateKernelWrapperforJob(DamFailureMechanismeCalculationSpecification currentSpecification, Location location, SoilGeometryProbability soilGeometryProbability, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput) { IKernelWrapper kernelWrapper = KernelWrapperHelper.CreateKernelWrapper(currentSpecification); if (kernelWrapper == null) { throw new NotImplementedException(Resources.DesignCalculatorKernelNotImplemented); } //damProjectData.DesignCalculations = new List(); var calculationMessages = new List(); // Prepare input var damKernelInput = new DamKernelInput(); var projectPath = damProjectData.ProjectPath != "" ? damProjectData.ProjectPath : Directory.GetCurrentDirectory(); damKernelInput.ProjectDir = projectPath; damKernelInput.CalculationDir = Path.Combine(projectPath, damProjectData.CalculationMap); damKernelInput.Location = location; damKernelInput.SubSoilScenario = soilGeometryProbability; //damKernelInput.DesignScenario = location.Scenarios[designScenarioIndex]; damKernelInput.DamFailureMechanismeCalculationSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification; damKernelInput.RiverLevelHigh = damKernelInput.DesignScenario.RiverLevel;// #Bka hier geen Dscen damKernelInput.RiverLevelLow = damKernelInput.DesignScenario.RiverLevelLow;// #Bka hier geen Dscen AnalysisType analysisType = DamProjectCalculationSpecification.SelectedAnalysisType; // SynchronizeDesignScenarioDataWithLocationData(damKernelInput.DesignScenario, damKernelInput.Location); // IKernelDataInput kernelDataInput; //IKernelDataOutput kernelDataOutput; PrepareResult prepareResult = kernelWrapper.Prepare(damKernelInput, 0, out kernelDataInput, out kernelDataOutput); // Sometimes the kernelDataInput is not created (p.e when soilprofileprobablility is meant for // stability where Piping calc is wanted). In that case, do nothing but just skip. if (prepareResult == PrepareResult.Successful) { // switch (analysisType) // { // case AnalysisType.AdaptGeometry: // PerformDesignCalculation(kernelWrapper, kernelDataInput, kernelDataOutput, // damKernelInput, calculationMessages, damProjectData.DesignCalculations); // break; // case AnalysisType.NoAdaption: // PerformSingleCalculation(kernelWrapper, kernelDataInput, kernelDataOutput, // damKernelInput, calculationMessages, damProjectData.DesignCalculations); // break; // // } } else { if (prepareResult == PrepareResult.NotRelevant) { calculationMessages.Add(new LogMessage(LogMessageType.Info, null, string.Format(Resources.DesignCalculatorIrrelevant, location.Name, soilGeometryProbability.ToString(), damKernelInput.DesignScenario.LocationScenarioID))); // #Bka hier geen Dscen } if (prepareResult == PrepareResult.Failed) { calculationMessages.Add(new LogMessage(LogMessageType.Error, null, string.Format(Resources.DesignCalculatorPrepareError, location.Name, soilGeometryProbability.ToString(), damKernelInput.DesignScenario.LocationScenarioID)));// #Bka hier geen Dscen } } return kernelWrapper;//calculationMessages; } private EvaluationJob evaluationJob = null; private GetValuesDelegate getValuesDelegate; private ProgressDelegate progressDelegate; private SendMessageDelegate sendMessageDelegate; private string mstabExePath = @".\DGeoStability.exe"; private int maxCalculationCores = 255; private Dictionary runningJobs = new Dictionary(); private bool isSkipStabilityCalculation = false; /// /// Gets or sets the type of the piping model. /// /// /// The type of the piping model. /// public PipingModelType PipingModelType { get; set; } /// /// Gets or sets the m stab parameters. /// /// /// The m stab parameters. /// public MStabParameters MStabParameters { get; set; } #region ICalculation Members /// /// Gets the results. /// /// The results. /// public CalculationResult GetResults(ref string results) { // try // { // XmlSerializer serializer = new XmlSerializer(); // results = serializer.SerializeToString(this.evaluationJob); // return CalculationResult.Succeeded; // } // catch // { // return CalculationResult.UnexpectedError; // }##Bka return CalculationResult.UnexpectedError; } /// /// Loads the specified input. /// /// The input. /// public CalculationResult Load(string input) { // try // { // XmlDeserializer deserializer = new XmlDeserializer(); // this.evaluationJob = (EvaluationJob)deserializer.XmlDeserializeFromString(input, typeof(EvaluationJob), new DefaultClassFactory()); // return CalculationResult.Succeeded; // } // catch // { // return CalculationResult.UnexpectedError; // }##Bka return CalculationResult.UnexpectedError; } /// /// Registers the get values. /// /// The get values delegate. /// public CalculationResult RegisterGetValues(GetValuesDelegate aGetValuesDelegate) { getValuesDelegate = aGetValuesDelegate; return CalculationResult.Succeeded; } /// /// Registers the progress. /// /// The progress delegate. /// public CalculationResult RegisterProgress(ProgressDelegate aProgressDelegate) { progressDelegate = aProgressDelegate; return CalculationResult.Succeeded; } /// /// Registers the send debug information. /// /// The send debug information delegate. /// public CalculationResult RegisterSendDebugInfo(SendDebugInfodelegate sendDebugInfoDelegate) { return CalculationResult.Succeeded; } /// /// Registers the send message. /// /// The send message delegate. /// public CalculationResult RegisterSendMessage(SendMessageDelegate aSendMessageDelegate) { sendMessageDelegate = aSendMessageDelegate; return CalculationResult.Succeeded; } /// /// Registers the set values. /// /// The set values delegate. /// public CalculationResult RegisterSetValues(SetValuesDelegate setValuesDelegate) { return CalculationResult.Succeeded; } /// /// Registers the user abort. /// /// The user abort delegate. /// public CalculationResult RegisterUserAbort(UserAbortDelegate userAbortDelegate) { return CalculationResult.Succeeded; } /// /// Runs this instance. /// /// public CalculationResult Run() { try { List tasks = FillQueue(); General.Parallel.Run(tasks, RunTask, progressDelegate, maxCalculationCores); FillResults(tasks); return CalculationResult.Succeeded; } catch(Exception exception) { sendMessageDelegate(new LogMessage(LogMessageType.Warning, null, "Unexpected error:" + exception.Message)); throw exception; } } /// /// Validates this instance. /// /// public CalculationResult Validate() { return CalculationResult.Succeeded; } #endregion /// /// Gets the version. /// /// /// The version. /// public string Version { get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } /// /// Gets or sets the mstab executable path. /// /// /// The mstab executable path. /// public string MStabExePath { get { return mstabExePath; } set { mstabExePath = value; } } /// /// Gets or sets a value indicating whether this instance is skip stability calculation. /// /// /// true if this instance is skip stability calculation; otherwise, false. /// public bool IsSkipStabilityCalculation { get { return isSkipStabilityCalculation; } set { isSkipStabilityCalculation = value; } } private List FillQueue() { List tasks = new List(); evaluationJob.FailedEvaluatedLocations = new List(); foreach (var location in evaluationJob.Locations) { if (location.Segment == null) { // Add this location to the failed locations if (evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) { evaluationJob.FailedEvaluatedLocations.Add(location); var locationHasNoSegment = LocalizationManager.GetTranslatedText(GetType(), "LocationHasNoSegment"); sendMessageDelegate(new LogMessage(LogMessageType.Error, location, locationHasNoSegment)); } } else { // TODO: Ask Erik Vastenburg how to handle piping and stability soilprofiles when determining RWScenarios // For now we only use the stability profiles. var soilGeometryProbabilities = location.Segment.SoilProfileProbabilities.Where(s => (s.SegmentFailureMechanismType == null) || (s.SegmentFailureMechanismType.Value == FailureMechanismSystemType.StabilityInside)).ToList(); if (soilGeometryProbabilities.Count == 0) { evaluationJob.FailedEvaluatedLocations.Add(location); sendMessageDelegate( new LogMessage(LogMessageType.Warning, location, string.Format("Location has no soilprofiles: ") + string.Format("Segment: {0}", location.Segment.Name))); } else { foreach (SoilGeometryProbability soilGeometryProbability in soilGeometryProbabilities) { if (soilGeometryProbability.SoilProfileType == SoilProfileType.ProfileType2D || soilGeometryProbability.SoilProfileType == SoilProfileType.ProfileTypeStiFile) { evaluationJob.FailedEvaluatedLocations.Add(location); sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, LocalizationManager.GetTranslatedText(this, "Geometry2DNotSupportedInRegionalAssessment") + string.Format("Segment: {0}", location.Segment.Name))); } else { SoilProfile soilProfile = soilGeometryProbability.SoilProfile1D; IList regionalScenarios; try { regionalScenarios = GetRegionalScenarios(location, soilGeometryProbability); } catch (Exception e) { regionalScenarios = null; // Add this location to the failed locations if (evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) { evaluationJob.FailedEvaluatedLocations.Add(location); sendMessageDelegate( new LogMessage(LogMessageType.Warning, location, String.Format("Cannot generate scenarios: {0}", e.Message) + String.Format("Soilprofile: {0}", soilProfile.Name))); } } if (regionalScenarios != null) { foreach (RegionalScenarioProfileResult job in regionalScenarios) { tasks.Add(job); } } } } } } } return tasks; } private IList GetRegionalScenarios(Location location, SoilGeometryProbability soilGeometryProbability) { RegionalScenarioSelector selector = new RegionalScenarioSelector { PipingModelType = PipingModelType, MStabParameters = MStabParameters }; return selector.GetScenarios(location, soilGeometryProbability); } private void RunTask(object task) { var job = (RegionalScenarioProfileResult)task; try { if (!IsSkipStabilityCalculation) { ProcessJob(job); } else { job.CalculationResult = CalculationResult.NoRun; } } catch (Exception e) { job.CalculationResult = CalculationResult.UnexpectedError; sendMessageDelegate(new LogMessage(LogMessageType.Warning, job, String.Format(job.LocationName + " Error: {0}", e.Message))); } } /// /// Select which job processor to use, depending on failuremechanism /// /// private void ProcessJob(RegionalScenarioProfileResult job) { Debug.WriteLine(String.Format("Job {0}, location {1}, Scenario {2}", job.FailureMechanismType.ToString(), job.LocationName, job.ScenarioType.ToString())); switch (job.FailureMechanismType) { case FailureMechanismSystemType.StabilityInside: ProcessJobStability(job); break; case FailureMechanismSystemType.Piping: ProcessJobPiping(job); break; default: throw new RegionalScenariosCalculationException(String.Format("Failuremechanism {0} not yet implemented for scenario calculation", job.FailureMechanismType)); } } /// /// Process a job for failuremechanism Piping /// /// private void ProcessJobPiping(RegionalScenarioProfileResult job) { if (job.Location.ModelFactors.UpliftCriterionPiping.HasValue) { // var modelParametersForPLLines = new ModelParametersForPlLines(); // var calculator = GetCalculatorForPipingModel(job, modelParametersForPLLines); // double waterLevel; // switch (job.LoadSituation) // { // case LoadSituation.Dry: // waterLevel = job.Location.BoezemLevelLbp; // break; // default: // LoadSituation.Wet // waterLevel = job.Location.BoezemLevelTp; // break; // } // //job.SoilGeometryProbability.SoilProfile1D.EnsureUniqueLayerIds(); // var calculationName = GetCalculationNameForPipingCalculator(job); // calculator.FilenameCalculation = Path.Combine(Path.Combine(damProjectData.ProjectPath, job.FailureMechanismType.ToString()), calculationName); // calculator.IsHydraulicShortcut = (job.HydraulicShortcutType == HydraulicShortcutType.HydraulicShortcut); // double? pipingFactor = calculator.CalculatePipingFactor(job.Location, job.Location.SurfaceLine, job.SoilGeometryProbability.SoilProfile1D, waterLevel); // job.BaseFileName = calculator.FilenameCalculation; // // job.RegionalResultType = RegionalResultType.SafetyFactor; // if (pipingFactor.HasValue) // { // job.SafetyFactor = pipingFactor.Value; // job.CalculationResult = CalculationResult.Succeeded; // job.ProbabilityOfFailure = double.NaN; // job.RegionalResultType = RegionalResultType.SafetyFactor; // } // // else // { // job.SafetyFactor = double.NaN; // job.CalculationResult = CalculationResult.RunFailed; // } } else { throw new RegionalScenariosCalculationException(String.Format("Uplift criterion not defined for location {0}", job.Location.Name)); } } private string GetCalculationNameForPipingCalculator(RegionalScenarioProfileResult job) { string calculationName; switch (job.PipingModelOption) { case PipingModelType.SellmeijerVnk : calculationName = String.Format("Calc(SellmeijerVnk)_Loc({0})_Pro({1}))", job.LocationName, job.SoilProfileName); break; case PipingModelType.Sellmeijer4Forces: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))", job.LocationName, job.SoilProfileName); break; // Set Sellmeijer4Forces as default. default: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))", job.LocationName, job.SoilProfileName); break; } calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); return calculationName; } /// /// Determines the proper calculator for pipng /// /// /// /// proper piping calculator // private PipingCalculator GetCalculatorForPipingModel(RegionalScenarioProfileResult job, ModelParametersForPLLines modelParametersForPlLines) // { // PipingCalculator calculator; // switch (job.PipingModelOption) // { // case PipingModelType.SellmeijerVnk: calculator = new PipingCalculatorSellmeijer(modelParametersForPLLines, // 1.0, null, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); // break; // case PipingModelType.Sellmeijer4Forces: calculator = new PipingCalculatorSellmeijer4Forces(modelParametersForPLLines, // 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); // break; // case PipingModelType.Bligh: calculator = new PipingCalculatorBligh(modelParametersForPLLines, // 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value); // break; // default: // throw new RegionalScenariosCalculationException(String.Format("Piping model {0} not yet implemented for scenario calculation", job.PipingModelOption)); // } // return calculator; // } /// /// Process a job for failuremechanism Stability /// /// private void ProcessJobStability(RegionalScenarioProfileResult job) { // StabilityCalculation calculator = new StabilityCalculation(); var currentSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification; currentSpecification.FailureMechanismSystemType = job.FailureMechanismType; IKernelDataInput kernelDataInput; IKernelDataOutput kernelDataOutput; var calculator = CreateKernelWrapperforJob(currentSpecification, job.Location, job.SoilGeometryProbability, out kernelDataInput, out kernelDataOutput); lock (runningJobs) { runningJobs[calculator] = job; } // calculator.MStabExePath = this.MStabExePath; // calculator.RegisterSendMessage(this.SendStabilityMessage); // // string soilDatabaseName = job.Location.StabilityOptions.SoilDatabaseName; // DamFailureMechanismeCalculationSpecification damCalculation = // calculator.GetSpecification(this.evaluationJob.DikeName, soilDatabaseName, job.Location, new SoilGeometry(job.SoilGeometryProbability.SoilProfile1D, null), // (MStabModelType)job.MstabModelOption, job.LoadSituation, job.DikeDrySensitivity, job.HydraulicShortcutType, MStabParameters); // // calculator.SaveToFile(damCalculation.FailureMechanismParametersMStab); // string inputFile = damCalculation.FailureMechanismParametersMStab.MStabParameters.ProjectFileName; // // job.BaseFileName = inputFile.Replace(DamProject.ProjectWorkingPath, @"").Replace(".sti", ""); // calculator.Load(inputFile); List messages; calculator.Execute(kernelDataInput, kernelDataOutput, out messages); job.CalculationResult = CalculationResult.Succeeded; //Run(); if (job.CalculationResult == CalculationResult.Succeeded) { string resultMessage = ""; List results; var input = (DamKernelInput) kernelDataInput; calculator.PostProcess(input, kernelDataOutput, resultMessage, out results); //string results = ""; job.SafetyFactor = results[0].SafetyFactor.Value; job.CalculationResult = results[0].CalculationResult; job.RegionalResultType = RegionalResultType.SafetyFactor; //XmlDeserializer deserializer = new XmlDeserializer(); // RegionalResult result = (RegionalResult)deserializer.XmlDeserializeFromString(results, typeof(RegionalResult)); // job.SafetyFactor = result.SafetyFactor; // job.ProbabilityOfFailure = result.ProbabilityOfFailure; // job.RegionalResultType = result.RegionalResultType; // job.CalculationResult = result.CalculationResult; } else { job.RegionalResultType = (currentSpecification.FailureMechanismParametersMStab.MStabParameters.IsProbabilistic ? RegionalResultType.ProbabilityOfFailure : RegionalResultType.SafetyFactor); job.SafetyFactor = double.NaN; job.ProbabilityOfFailure = double.NaN; } lock (runningJobs) { runningJobs.Remove(calculator); } } /// /// Log messages /// /// private void SendStabilityMessage(LogMessage logMessage) { lock (runningJobs) { if (logMessage.Subject != null) { var job = (RegionalScenarioProfileResult)runningJobs[(ICalculation)logMessage.Subject]; logMessage.Subject = job.Location; } } this.sendMessageDelegate(logMessage); } /// /// Fill the results for the scenarios /// private void FillResults(List tasks) { // Fill scenariosResult structure with jobs just run foreach (Location location in this.evaluationJob.Locations) { try { RegionalScenariosResult scenariosResult = new RegionalScenariosResult(); if (this.evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0) { // scenarios were succesfully created, so results are available foreach (RegionalScenarioProfileResult job in tasks) { if (job.LocationName.Equals(location.Name)) { RegionalScenarioResult scenarioResult = null; foreach (var existingScenarioResult in scenariosResult.RegionalScenarioResults) { if (existingScenarioResult.ScenarioType == job.ScenarioType) { scenarioResult = existingScenarioResult; } } if (scenarioResult == null) { scenarioResult = new RegionalScenarioResult(); scenarioResult.ScenarioType = job.ScenarioType; scenariosResult.RegionalScenarioResults.Add(scenarioResult); } scenarioResult.RegionalScenarioProfileResults.Add(job); } } // Combine results foreach (var scenarioResult in scenariosResult.RegionalScenarioResults) { this.CombineProfiles(scenarioResult); } this.CombineScenarios(scenariosResult); } else { // scenarios were not succesfully created, so results are not available // no succesful calculations found scenariosResult.CalculationResult = CalculationResult.RunFailed; scenariosResult.SafetyFactor = double.NaN; } // scenariosResult are the results of all scenarios for one location. evaluationJob.Results.Add(scenariosResult); } catch (Exception e) { RegionalScenariosResult scenariosResult = new RegionalScenariosResult { CalculationResult = CalculationResult.RunFailed, SafetyFactor = double.NaN }; sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, String.Format("Error in location {0}: {1}", location.Name, e.Message))); } } } private void CombineProfiles(RegionalScenarioResult scenarioResult) { // combine results of profiles scenarioResult.SafetyFactor = Double.MaxValue; foreach (var profileResult in scenarioResult.RegionalScenarioProfileResults) { if (profileResult.CalculationResult == CalculationResult.Succeeded) { if (profileResult.SafetyFactor < scenarioResult.SafetyFactor) { scenarioResult.SafetyFactor = profileResult.SafetyFactor; } scenarioResult.CalculationResult = CalculationResult.Succeeded; } } if (scenarioResult.CalculationResult != CalculationResult.Succeeded) { // no succesful calculations found scenarioResult.CalculationResult = scenarioResult.RegionalScenarioProfileResults[0].CalculationResult; scenarioResult.SafetyFactor = scenarioResult.RegionalScenarioProfileResults[0].SafetyFactor; } } private void CombineScenarios(RegionalScenariosResult scenariosResult) { // combine results of scenarios scenariosResult.SafetyFactor = Double.MaxValue; foreach (var scenarioResult in scenariosResult.RegionalScenarioResults) { if (scenarioResult.CalculationResult == CalculationResult.Succeeded) { if (scenarioResult.SafetyFactor < scenariosResult.SafetyFactor) { scenariosResult.SafetyFactor = scenarioResult.SafetyFactor; } scenariosResult.CalculationResult = CalculationResult.Succeeded; } } } } }