// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // // You should have received a copy of the GNU 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.Collections.Generic; using System.Linq; using Core.Common.Base.IO; using log4net; using Ringtoets.Common.Data.AssessmentSection; using Ringtoets.Common.Data.DikeProfiles; using Ringtoets.Common.Data.FailureMechanism; using Ringtoets.Common.Service; using Ringtoets.GrassCoverErosionInwards.Data; using Ringtoets.GrassCoverErosionInwards.Service.Properties; using Ringtoets.HydraRing.Calculation.Calculator; using Ringtoets.HydraRing.Calculation.Data; using Ringtoets.HydraRing.Calculation.Data.Input.Hydraulics; using Ringtoets.HydraRing.Calculation.Data.Input.Overtopping; using Ringtoets.HydraRing.Calculation.Parsers; using Ringtoets.HydraRing.IO; using RingtoetsCommonServiceResources = Ringtoets.Common.Service.Properties.Resources; namespace Ringtoets.GrassCoverErosionInwards.Service { /// /// Service that provides methods for performing Hydra-Ring calculations for grass cover erosion inwards calculations. /// public class GrassCoverErosionInwardsCalculationService { private static readonly ILog log = LogManager.GetLogger(typeof(GrassCoverErosionInwardsCalculationService)); public ProgressChangedDelegate OnProgress; /// /// Performs validation over the values on the given . Error and status information is logged during /// the execution of the operation. /// /// The for which to validate the values. /// The for which to validate the values. /// Truec> if has no validation errors; Falsec> otherwise. public bool Validate(GrassCoverErosionInwardsCalculation calculation, IAssessmentSection assessmentSection) { CalculationServiceHelper.LogValidationBeginTime(calculation.Name); var messages = ValidateInput(calculation.InputParameters, assessmentSection); CalculationServiceHelper.LogMessagesAsError(RingtoetsCommonServiceResources.Error_in_validation_0, messages); CalculationServiceHelper.LogValidationEndTime(calculation.Name); return !messages.Any(); } /// /// Performs a grass cover erosion inwards dike height calculation based on the supplied /// and sets if the calculation was successful. /// Error and status information is logged during the execution of the operation. /// /// The that holds all the information required to perform the calculation. /// The that holds information about the norm used in the calculation. /// The to create input with. /// Calculation input parameters that apply to all instances. /// The amount of contribution for this failure mechanism in the assessment section. /// The directory of the HLCD file that should be used for performing the calculation. /// A double with a value on a successful calculation, double.NaN otherwise. internal void CalculateDikeHeight(GrassCoverErosionInwardsCalculation calculation, IAssessmentSection assessmentSection, FailureMechanismSection failureMechanismSection, GeneralGrassCoverErosionInwardsInput generalInput, double failureMechanismContribution, string hlcdDirectory) { var calculateDikeHeight = calculation.InputParameters.CalculateDikeHeight; var totalSteps = calculateDikeHeight ? 2 : 1; var calculationName = calculation.Name; NotifyProgress("Uitvoeren overloop en overslag berekening", 1, totalSteps); CalculationServiceHelper.LogCalculationBeginTime(calculationName); var overtoppingCalculator = new OvertoppingCalculator(hlcdDirectory, assessmentSection.Id); var overtoppingCalculationInput = CreateOvertoppingInput(calculation, failureMechanismSection, generalInput); var dikeHeightCalculator = new DikeHeightCalculator(hlcdDirectory, assessmentSection.Id); var dikeHeightCalculationInput = CreateDikeHeightInput(calculation, assessmentSection, failureMechanismSection, generalInput); double? dikeHeight = null; try { CalculateOvertopping(overtoppingCalculator, overtoppingCalculationInput, calculationName); if (calculateDikeHeight) { NotifyProgress("Uitvoeren dijkhoogte berekening", 2, totalSteps); CalculateDikeHeight(dikeHeightCalculator, dikeHeightCalculationInput, calculationName); dikeHeight = dikeHeightCalculator.DikeHeight; } calculation.Output = new GrassCoverErosionInwardsOutput( overtoppingCalculator.WaveHeight, overtoppingCalculator.IsOvertoppingDominant, ProbabilityAssessmentService.Calculate( assessmentSection.FailureMechanismContribution.Norm, failureMechanismContribution, generalInput.N, overtoppingCalculator.ExceedanceProbabilityBeta), dikeHeight); } finally { CalculationServiceHelper.LogCalculationEndTime(calculationName); } } private void NotifyProgress(string stepName, int currentStepNumber, int totalStepNumber) { if (OnProgress != null) { OnProgress(stepName, currentStepNumber, totalStepNumber); } } private static void CalculateOvertopping(OvertoppingCalculator overtoppingCalculator, OvertoppingCalculationInput overtoppingCalculationInput, string calculationName) { try { overtoppingCalculator.Calculate(overtoppingCalculationInput); } catch (HydraRingFileParserException) { log.ErrorFormat(Resources.GrassCoverErosionInwardsCalculationService_Calculate_Error_in_grass_cover_erosion_inwards_0_calculation, calculationName); throw; } finally { log.InfoFormat("Overloop berekeningsverslag. Klik op details voor meer informatie.\n{0}", overtoppingCalculator.OutputFileContent); } } private static void CalculateDikeHeight(DikeHeightCalculator dikeHeightCalculator, DikeHeightCalculationInput dikeHeightCalculationInput, string calculationName) { try { dikeHeightCalculator.Calculate(dikeHeightCalculationInput); } catch (HydraRingFileParserException) { log.ErrorFormat(Resources.GrassCoverErosionInwardsCalculationService_Calculate_Error_in_hbn_grass_cover_erosion_inwards_0_calculation, calculationName); } finally { log.InfoFormat("Dijkhoogte berekeningsverslag. Klik op details voor meer informatie.\n{0}", dikeHeightCalculator.OutputFileContent); } } private static OvertoppingCalculationInput CreateOvertoppingInput(GrassCoverErosionInwardsCalculation calculation, FailureMechanismSection failureMechanismSection, GeneralGrassCoverErosionInwardsInput generalInput) { return new OvertoppingCalculationInput(calculation.InputParameters.HydraulicBoundaryLocation.Id, new HydraRingSection(1, failureMechanismSection.GetSectionLength(), calculation.InputParameters.Orientation), calculation.InputParameters.DikeHeight, generalInput.CriticalOvertoppingModelFactor, generalInput.FbFactor.Mean, generalInput.FbFactor.StandardDeviation, generalInput.FnFactor.Mean, generalInput.FnFactor.StandardDeviation, generalInput.OvertoppingModelFactor, calculation.InputParameters.CriticalFlowRate.Mean, calculation.InputParameters.CriticalFlowRate.StandardDeviation, generalInput.FrunupModelFactor.Mean, generalInput.FrunupModelFactor.StandardDeviation, generalInput.FshallowModelFactor.Mean, generalInput.FshallowModelFactor.StandardDeviation, ParseProfilePoints(calculation.InputParameters.DikeGeometry), ParseForeshore(calculation.InputParameters), ParseBreakWater(calculation.InputParameters)); } private static DikeHeightCalculationInput CreateDikeHeightInput(GrassCoverErosionInwardsCalculation calculation, IAssessmentSection assessmentSection, FailureMechanismSection failureMechanismSection, GeneralGrassCoverErosionInwardsInput generalInput) { return new DikeHeightCalculationInput(calculation.InputParameters.HydraulicBoundaryLocation.Id, assessmentSection.FailureMechanismContribution.Norm, new HydraRingSection(1, failureMechanismSection.GetSectionLength(), calculation.InputParameters.Orientation), generalInput.CriticalOvertoppingModelFactor, generalInput.FbFactor.Mean, generalInput.FbFactor.StandardDeviation, generalInput.FnFactor.Mean, generalInput.FnFactor.StandardDeviation, generalInput.OvertoppingModelFactor, calculation.InputParameters.CriticalFlowRate.Mean, calculation.InputParameters.CriticalFlowRate.StandardDeviation, generalInput.FrunupModelFactor.Mean, generalInput.FrunupModelFactor.StandardDeviation, generalInput.FshallowModelFactor.Mean, generalInput.FshallowModelFactor.StandardDeviation, ParseProfilePoints(calculation.InputParameters.DikeGeometry), ParseForeshore(calculation.InputParameters), ParseBreakWater(calculation.InputParameters)); } private static HydraRingBreakWater ParseBreakWater(GrassCoverErosionInwardsInput input) { return input.UseBreakWater ? new HydraRingBreakWater((int) input.BreakWater.Type, input.BreakWater.Height) : null; } private static IEnumerable ParseForeshore(GrassCoverErosionInwardsInput input) { return input.UseForeshore ? input.ForeshoreGeometry.Select(c => new HydraRingForelandPoint(c.X, c.Y)) : new HydraRingForelandPoint[0]; } private static IEnumerable ParseProfilePoints(RoughnessPoint[] roughnessProfilePoints) { for (var i = 0; i < roughnessProfilePoints.Length; i++) { var roughnessProfilePoint = roughnessProfilePoints[i]; if (i == 0) { yield return new HydraRingRoughnessProfilePoint(roughnessProfilePoint.Point.X, roughnessProfilePoint.Point.Y, 1.0); } else { var precedingRoughnessProfilePoint = roughnessProfilePoints[i - 1]; yield return new HydraRingRoughnessProfilePoint(roughnessProfilePoint.Point.X, roughnessProfilePoint.Point.Y, precedingRoughnessProfilePoint.Roughness); } } } private static string[] ValidateInput(GrassCoverErosionInwardsInput inputParameters, IAssessmentSection assessmentSection) { List validationResult = new List(); if (inputParameters.HydraulicBoundaryLocation == null) { validationResult.Add(RingtoetsCommonServiceResources.CalculationService_ValidateInput_No_hydraulic_boundary_location_selected); } var validationProblem = HydraulicDatabaseHelper.ValidatePathForCalculation(assessmentSection.HydraulicBoundaryDatabase.FilePath); if (!string.IsNullOrEmpty(validationProblem)) { validationResult.Add(validationProblem); } if (inputParameters.DikeProfile == null) { validationResult.Add(RingtoetsCommonServiceResources.CalculationService_ValidateInput_No_dike_profile_selected); } if (inputParameters.UseBreakWater) { if (double.IsNaN(inputParameters.BreakWater.Height) || double.IsInfinity(inputParameters.BreakWater.Height)) { validationResult.Add(RingtoetsCommonServiceResources.ValidationService_ValidateInput_invalid_BreakWaterHeight_value); } } return validationResult.ToArray(); } } }