// 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.Collections.Generic; using System.Linq; using Core.Common.Base.Data; using log4net; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.Probabilistics; using Ringtoets.Common.IO.Exceptions; using Ringtoets.Common.IO.FileImporters; using Ringtoets.Common.IO.Readers; using Ringtoets.Piping.Data; using Ringtoets.Piping.IO.Properties; using Ringtoets.Piping.IO.Readers; using Ringtoets.Piping.IO.Schema; using Ringtoets.Piping.Primitives; using RingtoetsCommonIOResources = Ringtoets.Common.IO.Properties.Resources; namespace Ringtoets.Piping.IO.Importers { /// /// Imports a piping configuration from an XML file and stores it on a /// . /// public class PipingConfigurationImporter : CalculationConfigurationImporter { private static readonly ILog log = LogManager.GetLogger(typeof(PipingConfigurationImporter)); private readonly IEnumerable hydraulicBoundaryLocations; private readonly PipingFailureMechanism failureMechanism; /// /// Creates a new instance of . /// /// The path to the file to import from. /// The calculation group to update. /// The hydraulic boundary locations /// used to check if the imported objects contain the right location. /// The piping failure mechanism used to check /// if the imported objects contain the right data. /// Thrown when any parameter is /// null. public PipingConfigurationImporter(string filePath, CalculationGroup importTarget, IEnumerable hydraulicBoundaryLocations, PipingFailureMechanism failureMechanism) : base(filePath, importTarget) { if (hydraulicBoundaryLocations == null) { throw new ArgumentNullException(nameof(hydraulicBoundaryLocations)); } if (failureMechanism == null) { throw new ArgumentNullException(nameof(failureMechanism)); } this.hydraulicBoundaryLocations = hydraulicBoundaryLocations; this.failureMechanism = failureMechanism; } protected override ICalculationBase ProcessReadItem(IReadConfigurationItem readItem) { var readCalculationGroup = readItem as ReadCalculationGroup; if (readCalculationGroup != null) { return ProcessCalculationGroup(readCalculationGroup); } var readCalculation = readItem as ReadPipingCalculation; if (readCalculation != null) { return ProcessCalculation(readCalculation); } return null; } protected override ICollection ReadConfigurationItems(string filePath) { return new PipingConfigurationReader(FilePath).Read().ToList(); } private CalculationGroup ProcessCalculationGroup(ReadCalculationGroup readCalculationGroup) { var group = new CalculationGroup(readCalculationGroup.Name, true); foreach (IReadConfigurationItem item in readCalculationGroup.Items) { ICalculationBase processedItem = ProcessReadItem(item); if (processedItem != null) { group.Children.Add(processedItem); } } return group; } private PipingCalculationScenario ProcessCalculation(ReadPipingCalculation readCalculation) { var pipingCalculation = new PipingCalculationScenario(new GeneralPipingInput()) { Name = readCalculation.Name }; try { ReadHydraulicBoundaryData(readCalculation, pipingCalculation); ReadSurfaceLine(readCalculation, pipingCalculation); ReadEntryExitPoint(readCalculation, pipingCalculation); ReadStochasticSoilModel(readCalculation, pipingCalculation); ReadStochasticSoilProfile(readCalculation, pipingCalculation); ReadStochasts(readCalculation, pipingCalculation); } catch (CriticalFileValidationException e) { string message = string.Format(Resources.PipingConfigurationImporter_ValidateCalculation_Error_message_0_calculation_1_skipped, e.Message, readCalculation.Name); log.Error(message, e); return null; } return pipingCalculation; } /// /// Reads the hydraulic boundary location or the assessment level that is manually set. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when the /// has a set which is not available in . private void ReadHydraulicBoundaryData(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { if (readCalculation.HydraulicBoundaryLocation != null) { HydraulicBoundaryLocation location = hydraulicBoundaryLocations .FirstOrDefault(l => l.Name == readCalculation.HydraulicBoundaryLocation); if (location == null) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadHydraulicBoundaryLocation_Hydraulic_boundary_location_0_does_not_exist, readCalculation.HydraulicBoundaryLocation)); } pipingCalculation.InputParameters.HydraulicBoundaryLocation = location; } else if (readCalculation.AssessmentLevel.HasValue) { pipingCalculation.InputParameters.UseAssessmentLevelManualInput = true; pipingCalculation.InputParameters.AssessmentLevel = (RoundedDouble) readCalculation.AssessmentLevel; } } /// /// Reads the surface line. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when the /// has a set which is not available in the failure mechanism. private void ReadSurfaceLine(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { if (readCalculation.SurfaceLine != null) { RingtoetsPipingSurfaceLine surfaceLine = failureMechanism.SurfaceLines .FirstOrDefault(sl => sl.Name == readCalculation.SurfaceLine); if (surfaceLine == null) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadSurfaceLine_SurfaceLine_0_does_not_exist, readCalculation.SurfaceLine)); } pipingCalculation.InputParameters.SurfaceLine = surfaceLine; } } /// /// Reads the entry point and exit point. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when the entry point or exit point is invalid. private static void ReadEntryExitPoint(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { bool hasEntryPoint = readCalculation.EntryPointL.HasValue; bool hasExitPoint = readCalculation.ExitPointL.HasValue; if (readCalculation.SurfaceLine == null && (hasEntryPoint || hasExitPoint)) { throw new CriticalFileValidationException(Resources.PipingConfigurationImporter_ReadSurfaceLine_EntryPointL_or_ExitPointL_defined_without_SurfaceLine); } if (hasEntryPoint) { var entryPoint = (double) readCalculation.EntryPointL; PerformActionHandlingAnyArgumentOutOfRangeException( () => pipingCalculation.InputParameters.EntryPointL = (RoundedDouble) entryPoint, string.Format(Resources.PipingConfigurationImporter_ReadEntryExitPoint_Entry_point_invalid, entryPoint)); } if (hasExitPoint) { var exitPoint = (double) readCalculation.ExitPointL; PerformActionHandlingAnyArgumentOutOfRangeException( () => pipingCalculation.InputParameters.ExitPointL = (RoundedDouble) exitPoint, string.Format(Resources.PipingConfigurationImporter_ReadEntryExitPoint_Exit_point_invalid, exitPoint)); } } /// /// Reads the stochastic soil model. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when /// /// the has a set /// which is not available in the failure mechanism. /// The does not intersect with the /// when this is set. /// /// private void ReadStochasticSoilModel(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { if (readCalculation.StochasticSoilModel != null) { StochasticSoilModel soilModel = failureMechanism.StochasticSoilModels .FirstOrDefault(ssm => ssm.Name == readCalculation.StochasticSoilModel); if (soilModel == null) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadStochasticSoilModel_Stochastische_soil_model_0_does_not_exist, readCalculation.StochasticSoilModel)); } if (pipingCalculation.InputParameters.SurfaceLine != null && !soilModel.IntersectsWithSurfaceLineGeometry(pipingCalculation.InputParameters.SurfaceLine)) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadStochasticSoilModel_Stochastische_soil_model_0_does_not_intersect_with_surfaceLine_1, readCalculation.StochasticSoilModel, readCalculation.SurfaceLine)); } pipingCalculation.InputParameters.StochasticSoilModel = soilModel; } } /// /// Reads the stochastic soil profile. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when the has: /// /// a set but no is specified; /// a set which is not available in the . /// /// private static void ReadStochasticSoilProfile(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { if (readCalculation.StochasticSoilProfile != null) { if (pipingCalculation.InputParameters.StochasticSoilModel == null) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadStochasticSoilProfile_No_soil_model_provided_for_soil_profile_with_name_0, readCalculation.StochasticSoilProfile)); } StochasticSoilProfile soilProfile = pipingCalculation.InputParameters.StochasticSoilModel.StochasticSoilProfiles .FirstOrDefault(ssp => ssp.SoilProfile.Name == readCalculation.StochasticSoilProfile); if (soilProfile == null) { throw new CriticalFileValidationException(string.Format(Resources.PipingConfigurationImporter_ReadStochasticSoilProfile_Stochastic_soil_profile_0_does_not_exist_within_soil_model_1, readCalculation.StochasticSoilProfile, readCalculation.StochasticSoilModel)); } pipingCalculation.InputParameters.StochasticSoilProfile = soilProfile; } } /// /// Reads the stochasts. /// /// The calculation read from the imported file. /// The calculation to configure. /// Thrown when a stochast value (mean or standard deviation) is invalid. private static void ReadStochasts(ReadPipingCalculation readCalculation, PipingCalculationScenario pipingCalculation) { if (readCalculation.PhreaticLevelExitMean.HasValue && readCalculation.PhreaticLevelExitStandardDeviation.HasValue) { var normalDistribution = new NormalDistribution(); var mean = (double) readCalculation.PhreaticLevelExitMean; PerformActionHandlingAnyArgumentOutOfRangeException( () => normalDistribution.Mean = (RoundedDouble) mean, string.Format(Resources.PipingConfigurationImporter_ReadStochasts_Invalid_mean_0_for_stochast_with_name_1, mean, PipingConfigurationSchemaIdentifiers.PhreaticLevelExitStochastName)); var standardDeviation = (double) readCalculation.PhreaticLevelExitStandardDeviation; PerformActionHandlingAnyArgumentOutOfRangeException( () => normalDistribution.StandardDeviation = (RoundedDouble) standardDeviation, string.Format(Resources.PipingConfigurationImporter_ReadStochasts_Invalid_standard_deviation_0_for_stochast_with_name_1, standardDeviation, PipingConfigurationSchemaIdentifiers.PhreaticLevelExitStochastName)); pipingCalculation.InputParameters.PhreaticLevelExit = normalDistribution; } if (readCalculation.DampingFactorExitMean.HasValue && readCalculation.DampingFactorExitStandardDeviation.HasValue) { var logNormalDistribution = new LogNormalDistribution(); var mean = (double) readCalculation.DampingFactorExitMean; PerformActionHandlingAnyArgumentOutOfRangeException( () => logNormalDistribution.Mean = (RoundedDouble) mean, string.Format(Resources.PipingConfigurationImporter_ReadStochasts_Invalid_mean_0_for_stochast_with_name_1, mean, PipingConfigurationSchemaIdentifiers.DampingFactorExitStochastName)); var standardDeviation = (double) readCalculation.DampingFactorExitStandardDeviation; PerformActionHandlingAnyArgumentOutOfRangeException( () => logNormalDistribution.StandardDeviation = (RoundedDouble) standardDeviation, string.Format(Resources.PipingConfigurationImporter_ReadStochasts_Invalid_standard_deviation_0_for_stochast_with_name_1, standardDeviation, PipingConfigurationSchemaIdentifiers.DampingFactorExitStochastName)); pipingCalculation.InputParameters.DampingFactorExit = logNormalDistribution; } } /// /// Performs the provided and handles any thrown . /// /// The action to perform. /// The error message to provide when rethrowing any thrown . /// Thrown when throws an . private static void PerformActionHandlingAnyArgumentOutOfRangeException(Action action, string errorMessage) { try { action(); } catch (ArgumentOutOfRangeException e) { throw new CriticalFileValidationException($"{errorMessage} {e.Message}"); } } } }