// 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.Collections.Generic; using System.Data.SQLite; using System.Linq; using Ringtoets.HydraRing.Calculation.Exceptions; using Ringtoets.HydraRing.Calculation.Properties; using Ringtoets.HydraRing.Calculation.Readers; namespace Ringtoets.HydraRing.Calculation.Parsers.IllustrationPoints { /// /// Parser for transforming values for illustration points from the database into a data structure. /// public class IllustrationPointsParser : IHydraRingFileParser { private readonly Dictionary> faultTreeStochasts = new Dictionary>(); private readonly Dictionary faultTreeBetaValues = new Dictionary(); private readonly Dictionary> subMechanismStochasts = new Dictionary>(); private readonly Dictionary subMechanismBetaValues = new Dictionary(); private readonly Dictionary> subMechanismResults = new Dictionary>(); private IDictionary windDirections; private IDictionary closingSituations; /// /// The result of parsing the illustration points in the Hydra-Ring database. /// public readonly GeneralResult Output = new GeneralResult(); public void Parse(string workingDirectory, int sectionId) { string query = string.Concat( IllustrationPointQueries.ClosingSituations, IllustrationPointQueries.WindDirections, IllustrationPointQueries.GeneralAlphaValues, IllustrationPointQueries.GeneralBetaValues, IllustrationPointQueries.FaultTreeAlphaValues, IllustrationPointQueries.FaultTreeBetaValues, IllustrationPointQueries.SubMechanismAlphaValues, IllustrationPointQueries.SubMechanismBetaValues, IllustrationPointQueries.SubMechanismIllustrationPointResults, IllustrationPointQueries.RecursiveFaultTree); try { using (var reader = new HydraRingDatabaseReader(workingDirectory, query, sectionId)) { ParseResultsFromReader(reader); } } catch (SQLiteException e) { throw new HydraRingFileParserException(Resources.Parse_Cannot_read_result_in_output_file, e); } catch (HydraRingDatabaseReaderException e) { throw new HydraRingFileParserException("Er konden geen illustratiepunten worden uitgelezen.", e); } } private void ParseResultsFromReader(HydraRingDatabaseReader reader) { ParseClosingSituations(reader); reader.NextResult(); ParseWindDirections(reader); reader.NextResult(); ParseGeneralAlphaValues(reader); reader.NextResult(); ParseGeneralBetaValue(reader); reader.NextResult(); ParseFaultTreeAlphaValues(reader); reader.NextResult(); ParseFaultTreeBetaValues(reader); reader.NextResult(); ParseSubMechanismAlphaValues(reader); reader.NextResult(); ParseSubMechanismBetaValues(reader); reader.NextResult(); ParseSubMechanismResults(reader); reader.NextResult(); ParseFaultTree(reader); if (Output.IllustrationPoints == null) { SetSubMechanismAsRootIllustrationPoint(); } } private void SetSubMechanismAsRootIllustrationPoint() { var rootIllustrationPoints = new Dictionary(); foreach (Tuple windDirectionClosingSituation in GetAllWindDirectionClosingSituationCombinations()) { var illustrationPoint = new SubMechanismIllustrationPoint { Beta = subMechanismBetaValues.First().Value }; AddRange(illustrationPoint.Results, subMechanismResults.First().Value); AddRange(illustrationPoint.Stochasts, subMechanismStochasts.First().Value); rootIllustrationPoints[CreateFaultTreeKey(windDirectionClosingSituation)] = new IllustrationPointTreeNode(illustrationPoint); } Output.IllustrationPoints = rootIllustrationPoints; } private void ParseFaultTreeAlphaValues(HydraRingDatabaseReader reader) { Dictionary[] readFaultTreeAlphaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); foreach (Dictionary readFaultTreeAlphaValue in readFaultTreeAlphaValues) { int faultTreeId = Convert.ToInt32(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.FaultTreeId]); int windDirectionId = Convert.ToInt32(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.WindDirectionId]); int closingSituationid = Convert.ToInt32(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]); string name = Convert.ToString(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.StochastName]); double duration = Convert.ToDouble(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.Duration]); double alpha = Convert.ToDouble(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.AlphaValue]); var key = new ThreeKeyIndex(windDirectionId, closingSituationid, faultTreeId); if (!faultTreeStochasts.ContainsKey(key)) { faultTreeStochasts[key] = new List(); } faultTreeStochasts[key].Add(new Stochast { Name = name, Duration = duration, Alpha = alpha }); } } private void ParseFaultTreeBetaValues(HydraRingDatabaseReader reader) { Dictionary[] readFaultTreeBetaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); foreach (Dictionary readFaultTreeBetaValue in readFaultTreeBetaValues) { int faultTreeId = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.FaultTreeId]); int windDirectionId = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.WindDirectionId]); int closingSituationid = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]); double beta = Convert.ToDouble(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.BetaValue]); faultTreeBetaValues[new ThreeKeyIndex(windDirectionId, closingSituationid, faultTreeId)] = beta; } } private void ParseSubMechanismAlphaValues(HydraRingDatabaseReader reader) { Dictionary[] readSubMechanismAlphaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); foreach (Dictionary readSubMechanismAlphaValue in readSubMechanismAlphaValues) { int subMechanismId = Convert.ToInt32(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.SubMechanismId]); int windDirectionId = Convert.ToInt32(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.WindDirectionId]); int closingSituationid = Convert.ToInt32(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]); string name = Convert.ToString(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.StochastName]); double duration = Convert.ToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.Duration]); double alpha = Convert.ToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.AlphaValue]); double realization = Convert.ToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.Realization]); var key = new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId); if (!subMechanismStochasts.ContainsKey(key)) { subMechanismStochasts[key] = new List(); } subMechanismStochasts[key].Add(new RealizedStochast { Name = name, Duration = duration, Alpha = alpha, Realization = realization }); } } private void ParseSubMechanismBetaValues(HydraRingDatabaseReader reader) { Dictionary[] readSubMechanismBetaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); foreach (Dictionary readSubMechanismBetaValue in readSubMechanismBetaValues) { int subMechanismId = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.SubMechanismId]); int windDirectionId = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.WindDirectionId]); int closingSituationid = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]); double beta = Convert.ToDouble(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.BetaValue]); subMechanismBetaValues[new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId)] = beta; } } private void ParseSubMechanismResults(HydraRingDatabaseReader reader) { Dictionary[] readSubMechanismResults = GetIterator(reader).TakeWhile(r => r != null).ToArray(); foreach (Dictionary readSubMechanismResult in readSubMechanismResults) { int subMechanismId = Convert.ToInt32(readSubMechanismResult[IllustrationPointsDatabaseConstants.SubMechanismId]); int windDirectionId = Convert.ToInt32(readSubMechanismResult[IllustrationPointsDatabaseConstants.WindDirectionId]); int closingSituationid = Convert.ToInt32(readSubMechanismResult[IllustrationPointsDatabaseConstants.ClosingSituationId]); string description = Convert.ToString(readSubMechanismResult[IllustrationPointsDatabaseConstants.IllustrationPointResultDescription]); double value = Convert.ToDouble(readSubMechanismResult[IllustrationPointsDatabaseConstants.IllustrationPointResultValue]); var key = new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId); if (!subMechanismResults.ContainsKey(key)) { subMechanismResults[key] = new List(); } subMechanismResults[key].Add(new IllustrationPointResult { Description = description, Value = value }); } } private void ParseFaultTree(HydraRingDatabaseReader reader) { IEnumerable> windDirectionClosingSituations = GetAllWindDirectionClosingSituationCombinations(); Dictionary[] readFaultTrees = GetIterator(reader).TakeWhile(r => r != null).ToArray(); if (readFaultTrees.Length > 0) { List> results = CreateResultTuples(readFaultTrees); var rootIllustrationPoints = new Dictionary(); foreach (Tuple windDirectionClosingSituation in windDirectionClosingSituations) { Tuple root = results.Single(r => !r.Item1.HasValue); rootIllustrationPoints[CreateFaultTreeKey(windDirectionClosingSituation)] = BuildFaultTree(windDirectionClosingSituation, root.Item2, root.Item4, results); } Output.IllustrationPoints = rootIllustrationPoints; } } private static List> CreateResultTuples(Dictionary[] readFaultTrees) { var results = new List>(); foreach (Dictionary readFaultTree in readFaultTrees) { object parentIdObject = readFaultTree[IllustrationPointsDatabaseConstants.RecursiveFaultTreeParentId]; int? parentId = parentIdObject != DBNull.Value ? Convert.ToInt32(parentIdObject) : (int?) null; int id = Convert.ToInt32(readFaultTree[IllustrationPointsDatabaseConstants.RecursiveFaultTreeId]); string type = Convert.ToString(readFaultTree[IllustrationPointsDatabaseConstants.RecursiveFaultTreeType]); string combine = Convert.ToString(readFaultTree[IllustrationPointsDatabaseConstants.RecursiveFaultTreeCombine]); results.Add(Tuple.Create( parentId, id, type == "faulttree" ? typeof(FaultTreeIllustrationPoint) : typeof(SubMechanismIllustrationPoint), combine == "and" ? CombinationType.And : CombinationType.Or)); } return results; } private static WindDirectionClosingSituation CreateFaultTreeKey(Tuple windDirectionClosingSituation) { return new WindDirectionClosingSituation(windDirectionClosingSituation.Item2, windDirectionClosingSituation.Item4); } private IEnumerable> GetAllWindDirectionClosingSituationCombinations() { return windDirections.SelectMany(windDirection => closingSituations.Select( closingSituation => Tuple.Create(windDirection.Key, windDirection.Value, closingSituation.Key, closingSituation.Value))); } private IllustrationPointTreeNode BuildFaultTree( Tuple windDirectionClosingSituation, int faultTreeId, CombinationType combinationType, ICollection> results) { var dataKey = new ThreeKeyIndex(windDirectionClosingSituation.Item1, windDirectionClosingSituation.Item3, faultTreeId); var illustrationPoint = new FaultTreeIllustrationPoint { Beta = faultTreeBetaValues[dataKey], Combine = combinationType }; if (faultTreeStochasts.ContainsKey(dataKey)) { AddRange(illustrationPoint.Stochasts, faultTreeStochasts[dataKey]); } var node = new IllustrationPointTreeNode(illustrationPoint); foreach (Tuple child in results.Where(r => r.Item1 == faultTreeId)) { node.Children.Add(child.Item3 == typeof(FaultTreeIllustrationPoint) ? BuildFaultTree(windDirectionClosingSituation, child.Item2, child.Item4, results) : BuildSubMechanism(windDirectionClosingSituation, child.Item2)); } return node; } private IllustrationPointTreeNode BuildSubMechanism(Tuple windDirectionClosingSituation, int subMechanismId) { var dataKey = new ThreeKeyIndex(windDirectionClosingSituation.Item1, windDirectionClosingSituation.Item3, subMechanismId); var illustrationPoint = new SubMechanismIllustrationPoint { Beta = subMechanismBetaValues[dataKey] }; if (subMechanismStochasts.ContainsKey(dataKey)) { AddRange(illustrationPoint.Stochasts, subMechanismStochasts[dataKey]); } if (subMechanismResults.ContainsKey(dataKey)) { AddRange(illustrationPoint.Results, subMechanismResults[dataKey]); } return new IllustrationPointTreeNode(illustrationPoint); } private void AddRange(ICollection collection, IEnumerable itemsToAdd) { foreach (T item in itemsToAdd) { collection.Add(item); } } private void ParseGeneralBetaValue(HydraRingDatabaseReader reader) { IEnumerable> betaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); if (betaValues.Count() != 1) { throw new HydraRingFileParserException("Ongeldig aantal beta-waarden gevonden in de uitvoer database."); } Output.Beta = Convert.ToDouble(betaValues.First()[IllustrationPointsDatabaseConstants.BetaValue]); } private void ParseGeneralAlphaValues(HydraRingDatabaseReader reader) { IEnumerable> alphaValues = GetIterator(reader).TakeWhile(r => r != null).ToArray(); Output.Stochasts = alphaValues.Select(a => new Stochast { Name = Convert.ToString(a[IllustrationPointsDatabaseConstants.StochastName]), Duration = Convert.ToDouble(a[IllustrationPointsDatabaseConstants.Duration]), Alpha = Convert.ToDouble(a[IllustrationPointsDatabaseConstants.AlphaValue]) }); } private void ParseClosingSituations(HydraRingDatabaseReader reader) { IEnumerable> readClosingSituations = GetIterator(reader).TakeWhile(r => r != null).ToArray(); closingSituations = readClosingSituations.ToDictionary( r => Convert.ToInt32(r[IllustrationPointsDatabaseConstants.ClosingSituationId]), r => Convert.ToString(r[IllustrationPointsDatabaseConstants.ClosingSituationName])); } private void ParseWindDirections(HydraRingDatabaseReader reader) { IEnumerable> readWindDirections = GetIterator(reader).TakeWhile(r => r != null).ToArray(); windDirections = new Dictionary(); foreach (Dictionary readWindDirection in readWindDirections) { int key = Convert.ToInt32(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionId]); string name = Convert.ToString(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionName]); double angle = Convert.ToDouble(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionAngle]); bool isGoverning = Convert.ToBoolean(readWindDirection[IllustrationPointsDatabaseConstants.IsGoverning]); var windDirection = new WindDirection { Name = name, Angle = angle }; windDirections[key] = windDirection; if (isGoverning) { Output.GoverningWind = windDirection; } } } private static IEnumerable> GetIterator(HydraRingDatabaseReader reader) { Dictionary nextLine = reader.ReadLine(); while (nextLine != null) { yield return nextLine; nextLine = reader.ReadLine(); } } private struct ThreeKeyIndex { private readonly int windDirectionId; private readonly int closingSituationId; private readonly int illustrationPointId; public ThreeKeyIndex(int windDirectionId, int closingSituationId, int illustrationPointId) { this.windDirectionId = windDirectionId; this.closingSituationId = closingSituationId; this.illustrationPointId = illustrationPointId; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } return obj.GetType() == GetType() && Equals((ThreeKeyIndex) obj); } public override int GetHashCode() { unchecked { int hashCode = windDirectionId; hashCode = (hashCode * 397) ^ closingSituationId; hashCode = (hashCode * 397) ^ illustrationPointId; return hashCode; } } private bool Equals(ThreeKeyIndex other) { return windDirectionId == other.windDirectionId && closingSituationId == other.closingSituationId && illustrationPointId == other.illustrationPointId; } } } }