// Copyright (C) Stichting Deltares 2017. 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.Base.IO; using Core.Common.Util; using log4net; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Service; using Ringtoets.Common.Service.MessageProviders; 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 locations. /// public class DuneLocationCalculationService : TargetProbabilityCalculationService { private static readonly ILog log = LogManager.GetLogger(typeof(DuneLocationCalculationService)); private bool canceled; private IDunesBoundaryConditionsCalculator calculator; /// /// Performs the provided and sets its output if the calculation is successful. /// Error and status information is logged during the execution of the operation. /// /// The to perform. /// The norm to use during the calculation. /// The path which points to the hydraulic /// boundary database file. /// The preprocessor directory. /// The object which is used to build log messages. /// Preprocessing is disabled when equals . /// Thrown when or /// is null. /// Thrown when: /// /// The contains invalid characters. /// The contribution of the failure mechanism is zero. /// The target probability or the calculated probability 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 while performing /// the calculation. public void Calculate(DuneLocationCalculation duneLocationCalculation, double norm, string hydraulicBoundaryDatabaseFilePath, string preprocessorDirectory, ICalculationMessageProvider messageProvider) { if (duneLocationCalculation == null) { throw new ArgumentNullException(nameof(duneLocationCalculation)); } if (messageProvider == null) { throw new ArgumentNullException(nameof(messageProvider)); } string hlcdDirectory = Path.GetDirectoryName(hydraulicBoundaryDatabaseFilePath); DuneLocation duneLocation = duneLocationCalculation.DuneLocation; string duneLocationName = duneLocation.Name; CalculationServiceHelper.LogCalculationBegin(); calculator = HydraRingCalculatorFactory.Instance.CreateDunesBoundaryConditionsCalculator(hlcdDirectory, preprocessorDirectory); var exceptionThrown = false; try { DunesBoundaryConditionsCalculationInput calculationInput = CreateInput(duneLocation, norm, hydraulicBoundaryDatabaseFilePath, !string.IsNullOrEmpty(preprocessorDirectory)); calculator.Calculate(calculationInput); if (string.IsNullOrEmpty(calculator.LastErrorFileContent)) { duneLocationCalculation.Output = CreateDuneLocationCalculationOutput(duneLocationName, calculationInput.Beta, norm); } } catch (HydraRingCalculationException) { if (!canceled) { string lastErrorContent = calculator.LastErrorFileContent; log.Error(string.IsNullOrEmpty(lastErrorContent) ? string.Format(Resources.DuneLocationCalculationService_Calculate_Error_in_DuneLocationCalculation_0_no_error_report, duneLocationName) : string.Format(Resources.DuneLocationCalculationService_Calculate_Error_in_DuneLocationCalculation_0_click_details_for_last_error_report_1, duneLocationName, lastErrorContent)); exceptionThrown = true; throw; } } finally { string lastErrorFileContent = calculator.LastErrorFileContent; bool hasErrorOccurred = CalculationServiceHelper.HasErrorOccurred(canceled, exceptionThrown, lastErrorFileContent); if (hasErrorOccurred) { log.ErrorFormat(Resources.DuneLocationCalculationService_Calculate_Error_in_DuneLocationCalculation_0_click_details_for_last_error_report_1, duneLocationName, lastErrorFileContent); } log.InfoFormat(Resources.DuneLocationCalculationService_Calculate_Calculation_temporary_directory_can_be_found_on_location_0, calculator.OutputDirectory); CalculationServiceHelper.LogCalculationEnd(); if (hasErrorOccurred) { throw new HydraRingCalculationException(lastErrorFileContent); } } } /// /// Cancels any ongoing dune location calculation. /// public void Cancel() { calculator?.Cancel(); canceled = true; } /// /// 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 probability falls outside the [0.0, 1.0] range and is not . private DuneLocationCalculationOutput CreateDuneLocationCalculationOutput(string duneLocationName, double targetReliability, double targetProbability) { double reliability = calculator.ReliabilityIndex; double probability = StatisticsConverter.ReliabilityToProbability(reliability); CalculationConvergence converged = RingtoetsCommonDataCalculationService.GetCalculationConvergence(calculator.Converged); if (converged != CalculationConvergence.CalculatedConverged) { log.WarnFormat(Resources.DuneLocationCalculationService_CreateDuneLocationCalculationOutput_Calculation_for_DuneLocation_0_not_converged, duneLocationName); } return new DuneLocationCalculationOutput(converged, new DuneLocationCalculationOutput.ConstructionProperties { WaterLevel = calculator.WaterLevel, WaveHeight = calculator.WaveHeight, WavePeriod = calculator.WavePeriod, TargetProbability = targetProbability, TargetReliability = targetReliability, CalculatedProbability = probability, CalculatedReliability = reliability }); } /// /// Creates the input used in the calculation. /// /// The to create the input for. /// The norm of the failure mechanism to use. /// The file path to the hydraulic /// boundary database. /// Indicator whether to use the preprocessor in the calculation. /// 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, bool usePreprocessor) { var dunesBoundaryConditionsCalculationInput = new DunesBoundaryConditionsCalculationInput(1, duneLocation.Id, norm); HydraRingSettingsDatabaseHelper.AssignSettingsFromDatabase(dunesBoundaryConditionsCalculationInput, hydraulicBoundaryDatabaseFilePath, usePreprocessor); return dunesBoundaryConditionsCalculationInput; } } }