// 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; using System.IO; using Core.Common.IO.Exceptions; using Core.Common.Utils; using log4net; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Service; using Ringtoets.DuneErosion.Data; using Ringtoets.DuneErosion.Service.Properties; using Ringtoets.HydraRing.Calculation.Calculator; using Ringtoets.HydraRing.Calculation.Calculator.Factory; using Ringtoets.HydraRing.Calculation.Data.Input.Hydraulics; using Ringtoets.HydraRing.Calculation.Exceptions; namespace Ringtoets.DuneErosion.Service { /// /// Service that provides methods for performing Hydra-Ring calculations for dune erosion. /// public class DuneErosionBoundaryCalculationService { private static readonly ILog log = LogManager.GetLogger(typeof(DuneErosionBoundaryCalculationService)); private bool canceled; private IDunesBoundaryConditionsCalculator calculator; /// /// Performs a dune erosion calculation based on the supplied /// and sets the if the calculation is successful. /// Error and status information is logged during the execution of the operation. /// /// The that holds information required to perform the calculation. /// The that holds information about the contribution and /// the general inputs used in the calculation. /// The id of the assessment section. /// The norm of the assessment section. /// The path which points to the hydraulic boundary database file. /// Thrown when: /// /// The contains invalid characters. /// The contribution of the failure mechanism is zero. /// The target propability or the calculated propability falls outside the [0.0, 1.0] range and is not . /// /// Thrown when: /// /// No settings database file could be found at the location of /// with the same name. /// Unable to open settings database file. /// Unable to read required data from database file. /// /// /// Thrown when an error occurs during parsing of the Hydra-Ring output. /// Thrown when an error occurs during the calculation. public void Calculate(DuneLocation duneLocation, DuneErosionFailureMechanism failureMechanism, string ringId, double norm, string hydraulicBoundaryDatabaseFilePath) { string hlcdDirectory = Path.GetDirectoryName(hydraulicBoundaryDatabaseFilePath); calculator = HydraRingCalculatorFactory.Instance.CreateDunesBoundaryConditionsCalculator(hlcdDirectory, ringId); string calculationName = duneLocation.Name; CalculationServiceHelper.LogCalculationBeginTime(calculationName); var mechanismSpecificNorm = GetFailureMechanismSpecificNorm(failureMechanism, norm, calculationName); var exceptionThrown = false; try { DunesBoundaryConditionsCalculationInput calculationInput = CreateInput(duneLocation, mechanismSpecificNorm, hydraulicBoundaryDatabaseFilePath); calculator.Calculate(calculationInput); if (string.IsNullOrEmpty(calculator.LastErrorFileContent)) { duneLocation.Output = CreateDuneLocationOutput(duneLocation.Name, calculationInput.Beta, mechanismSpecificNorm); } } catch (HydraRingFileParserException) { if (!canceled) { string lastErrorContent = calculator.LastErrorFileContent; if (string.IsNullOrEmpty(lastErrorContent)) { log.ErrorFormat(Resources.DuneErosionBoundaryCalculationService_Calculate_Error_in_dune_erosion_0_calculation_no_error_report, calculationName); } else { log.ErrorFormat(Resources.DuneErosionBoundaryCalculationService_Calculate_Error_in_dune_erosion_0_calculation_click_details_for_last_error_report_1, calculationName, lastErrorContent); } exceptionThrown = true; throw; } } finally { string lastErrorFileContent = calculator.LastErrorFileContent; bool hasErrorOccurred = CalculationServiceHelper.HasErrorOccurred(canceled, exceptionThrown, lastErrorFileContent); if (hasErrorOccurred) { log.ErrorFormat(Resources.DuneErosionBoundaryCalculationService_Calculate_Error_in_dune_erosion_0_calculation_click_details_for_last_error_report_1, calculationName, lastErrorFileContent); } FinalizeCalculation(calculationName, true); if (hasErrorOccurred) { throw new HydraRingCalculationException(lastErrorFileContent); } } } /// /// Cancels any ongoing dune erosion calculation. /// public void Cancel() { if (calculator != null) { calculator.Cancel(); } canceled = true; } /// /// Get the specific norm of the . /// /// The failure mechanism to get the norm for. /// The assessment section norm. /// The name of the calculation. /// The failure mechanism specific norm. /// Thrown when the contribution of the failure mechanism is zero. private double GetFailureMechanismSpecificNorm(DuneErosionFailureMechanism failureMechanism, double assessmentSectionNorm, string calculationName) { if (Math.Abs(failureMechanism.Contribution) < 1e-6) { string errorMessage = Resources.DuneErosionBoundaryCalculationService_Calculate_Contribution_is_zero; log.Error(errorMessage); FinalizeCalculation(calculationName, false); throw new ArgumentException(errorMessage); } return failureMechanism.GetMechanismSpecificNorm(assessmentSectionNorm); } private void FinalizeCalculation(string calculationName, bool calculationExecuted) { if (calculationExecuted) { log.InfoFormat(Resources.DuneErosionBoundaryCalculationService_Calculate_Calculation_temporary_directory_can_be_found_on_location_0, calculator.OutputDirectory); } CalculationServiceHelper.LogCalculationEndTime(calculationName); } /// /// Create the output of the calculation. /// /// The name of the location. /// The target reliability for the calculation. /// The target probability for the calculation. /// A . /// Thrown when /// or the calculated propability falls outside the [0.0, 1.0] range and is not . private DuneLocationOutput CreateDuneLocationOutput(string duneLocationName, double targetReliability, double targetProbability) { double reliability = calculator.ReliabilityIndex; double probability = StatisticsConverter.ReliabilityToProbability(reliability); CalculationConvergence converged = RingtoetsCommonDataCalculationService.GetCalculationConvergence( calculator.ReliabilityIndex, targetProbability); if (converged != CalculationConvergence.CalculatedConverged) { log.WarnFormat(Resources.DuneErosionBoundaryCalculationService_CreateDuneLocationOutput_Calculation_for_location_0_not_converged, duneLocationName); } return new DuneLocationOutput(calculator.WaterLevel, calculator.WaveHeight, calculator.WavePeriod, targetProbability, targetReliability, probability, reliability, converged); } /// /// Creates the input used in the calculation. /// /// The to create the input for. /// The norm of the failure mechanism to use. /// The filepath to the hydraulic boundary database. /// A with all needed input data. /// Thrown when the /// contains invalid characters. /// Thrown when: /// /// No settings database file could be found at the location of /// with the same name. /// Unable to open settings database file. /// Unable to read required data from database file. /// /// private static DunesBoundaryConditionsCalculationInput CreateInput(DuneLocation duneLocation, double norm, string hydraulicBoundaryDatabaseFilePath) { var dunesBoundaryConditionsCalculationInput = new DunesBoundaryConditionsCalculationInput(1, duneLocation.Id, norm, duneLocation.Orientation); HydraRingSettingsDatabaseHelper.AssignSettingsFromDatabase(dunesBoundaryConditionsCalculationInput, hydraulicBoundaryDatabaseFilePath); return dunesBoundaryConditionsCalculationInput; } } }