// 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.Data.Output.IllustrationPoints;
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 double beta = double.NaN;
private WindDirection governingWindDirection;
private IEnumerable stochasts;
private Dictionary rootIllustrationPoints;
private IDictionary windDirections;
private IDictionary closingSituations;
private IDictionary subMechanisms;
private IDictionary faultTrees;
///
/// The result of parsing the illustration points in the Hydra-Ring database.
///
public GeneralResult Output { get; private set; }
public void Parse(string workingDirectory, int sectionId)
{
string query = string.Concat(
IllustrationPointQueries.ClosingSituations,
IllustrationPointQueries.WindDirections,
IllustrationPointQueries.SubMechanisms,
IllustrationPointQueries.FaultTrees,
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 (Exception e) when (e is HydraRingDatabaseReaderException || e is SQLiteException)
{
throw new HydraRingFileParserException(Resources.IllustrationPointsParser_Parse_Could_not_read_illustration_point_data, e);
}
}
///
/// Parses the illustration point database results.
///
/// The database reader.
/// Thrown when parsing the results from .
private void ParseResultsFromReader(HydraRingDatabaseReader reader)
{
ParseClosingSituations(reader);
ProceedOrThrow(reader);
ParseWindDirections(reader);
ProceedOrThrow(reader);
ParseSubMechanisms(reader);
ProceedOrThrow(reader);
ParseFaultTrees(reader);
ProceedOrThrow(reader);
ParseGeneralAlphaValues(reader);
ProceedOrThrow(reader);
ParseGeneralBetaValue(reader);
ProceedOrThrow(reader);
ParseFaultTreeAlphaValues(reader);
ProceedOrThrow(reader);
ParseFaultTreeBetaValues(reader);
ProceedOrThrow(reader);
ParseSubMechanismAlphaValues(reader);
ProceedOrThrow(reader);
ParseSubMechanismBetaValues(reader);
ProceedOrThrow(reader);
ParseSubMechanismResults(reader);
ProceedOrThrow(reader);
ParseFaultTree(reader);
if (rootIllustrationPoints == null)
{
SetSubMechanismAsRootIllustrationPoint();
}
if (governingWindDirection != null && stochasts != null && rootIllustrationPoints != null)
{
Output = new GeneralResult(beta, governingWindDirection, stochasts, rootIllustrationPoints);
}
}
///
/// Proceeds to the next result in the data set.
///
/// The database reader.
/// Thrown there was no other result in the data set.
private static void ProceedOrThrow(HydraRingDatabaseReader reader)
{
if (!reader.NextResult())
{
throw new HydraRingFileParserException(Resources.IllustrationPointsParser_Parse_Could_not_read_illustration_point_data);
}
}
private void SetSubMechanismAsRootIllustrationPoint()
{
rootIllustrationPoints = new Dictionary();
foreach (Tuple windDirectionClosingSituation in GetAllWindDirectionClosingSituationCombinations())
{
string submechanismIllustrationPointName = subMechanisms.First().Value;
double subMechanismIllustrationPointBeta = subMechanismBetaValues.First().Value;
var illustrationPointStochasts = new List();
AddRange(illustrationPointStochasts, subMechanismStochasts.First().Value);
var illustrationPointResults = new List();
AddRange(illustrationPointResults, subMechanismResults.First().Value);
var illustrationPoint = new SubMechanismIllustrationPoint(submechanismIllustrationPointName,
illustrationPointStochasts,
illustrationPointResults,
subMechanismIllustrationPointBeta);
rootIllustrationPoints[CreateFaultTreeKey(windDirectionClosingSituation)] =
new IllustrationPointTreeNode(illustrationPoint);
}
}
///
/// Parses objects from the .
///
/// The database reader.
/// Throw when the read
/// or is .
private void ParseFaultTreeAlphaValues(HydraRingDatabaseReader reader)
{
foreach (Dictionary readFaultTreeAlphaValue in GetIterator(reader))
{
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 = ConvertToDouble(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.Duration],
IllustrationPointsDatabaseConstants.Duration);
double alpha = ConvertToDouble(readFaultTreeAlphaValue[IllustrationPointsDatabaseConstants.AlphaValue],
IllustrationPointsDatabaseConstants.AlphaValue);
var key = new ThreeKeyIndex(windDirectionId, closingSituationid, faultTreeId);
if (!faultTreeStochasts.ContainsKey(key))
{
faultTreeStochasts[key] = new List();
}
faultTreeStochasts[key].Add(new Stochast(name, duration, alpha));
}
}
///
/// Parses fault tree beta values from the .
///
/// The database reader.
/// Throw when:
///
/// - The read is ;
/// - Multiple values for beta of illustration point found.
///
///
private void ParseFaultTreeBetaValues(HydraRingDatabaseReader reader)
{
foreach (Dictionary readFaultTreeBetaValue in GetIterator(reader))
{
int faultTreeId = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.FaultTreeId]);
int windDirectionId = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.WindDirectionId]);
int closingSituationid = Convert.ToInt32(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]);
double faultTreeBeta = ConvertToDouble(readFaultTreeBetaValue[IllustrationPointsDatabaseConstants.BetaValue],
IllustrationPointsDatabaseConstants.BetaValue);
var threeKeyIndex = new ThreeKeyIndex(windDirectionId, closingSituationid, faultTreeId);
if (faultTreeBetaValues.ContainsKey(threeKeyIndex))
{
throw new HydraRingFileParserException(Resources.IllustrationPointsParser_Parse_Multiple_values_for_beta_of_illustration_point_found);
}
faultTreeBetaValues[threeKeyIndex] = faultTreeBeta;
}
}
///
/// Parses objects from the .
///
/// The database reader.
/// Throw when the read ,
/// , or
/// is .
private void ParseSubMechanismAlphaValues(HydraRingDatabaseReader reader)
{
foreach (Dictionary readSubMechanismAlphaValue in GetIterator(reader))
{
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 = ConvertToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.Duration],
IllustrationPointsDatabaseConstants.Duration);
double alpha = ConvertToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.AlphaValue],
IllustrationPointsDatabaseConstants.AlphaValue);
double realization = ConvertToDouble(readSubMechanismAlphaValue[IllustrationPointsDatabaseConstants.Realization],
IllustrationPointsDatabaseConstants.Realization);
var key = new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId);
if (!subMechanismStochasts.ContainsKey(key))
{
subMechanismStochasts[key] = new List();
}
subMechanismStochasts[key].Add(new RealizedStochast(name, duration, alpha, realization));
}
}
///
/// Parses sub-mechanism beta values from the .
///
/// The database reader.
/// Throw when:
///
/// - The read is ;
/// - Multiple values for beta of illustration point found.
///
///
private void ParseSubMechanismBetaValues(HydraRingDatabaseReader reader)
{
foreach (Dictionary readSubMechanismBetaValue in GetIterator(reader))
{
int subMechanismId = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.SubMechanismId]);
int windDirectionId = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.WindDirectionId]);
int closingSituationid = Convert.ToInt32(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.ClosingSituationId]);
double subMechanismBeta = ConvertToDouble(readSubMechanismBetaValue[IllustrationPointsDatabaseConstants.BetaValue],
IllustrationPointsDatabaseConstants.BetaValue);
var threeKeyIndex = new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId);
if (subMechanismBetaValues.ContainsKey(threeKeyIndex))
{
throw new HydraRingFileParserException(Resources.IllustrationPointsParser_Parse_Multiple_values_for_beta_of_illustration_point_found);
}
subMechanismBetaValues[threeKeyIndex] = subMechanismBeta;
}
}
///
/// Parses objects from the .
///
/// The database reader.
/// Throw when the read
/// is .
private void ParseSubMechanismResults(HydraRingDatabaseReader reader)
{
foreach (Dictionary readSubMechanismResult in GetIterator(reader))
{
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 = ConvertToDouble(readSubMechanismResult[IllustrationPointsDatabaseConstants.IllustrationPointResultValue],
IllustrationPointsDatabaseConstants.IllustrationPointResultValue);
var key = new ThreeKeyIndex(windDirectionId, closingSituationid, subMechanismId);
if (!subMechanismResults.ContainsKey(key))
{
subMechanismResults[key] = new List();
}
subMechanismResults[key].Add(new IllustrationPointResult(description, value));
}
}
private void ParseFaultTree(HydraRingDatabaseReader reader)
{
IEnumerable> windDirectionClosingSituations =
GetAllWindDirectionClosingSituationCombinations();
Dictionary[] readFaultTrees = GetIterator(reader).ToArray();
if (readFaultTrees.Length > 0)
{
List> results = CreateResultTuples(readFaultTrees);
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);
}
}
}
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(faultTrees[faultTreeId], faultTreeBetaValues[dataKey], 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 illustrationPointStochasts = new List();
var illustrationPointResults = new List();
if (subMechanismStochasts.ContainsKey(dataKey))
{
AddRange(illustrationPointStochasts, subMechanismStochasts[dataKey]);
}
if (subMechanismResults.ContainsKey(dataKey))
{
AddRange(illustrationPointResults, subMechanismResults[dataKey]);
}
string submechanismIllustrationPointName = subMechanisms[subMechanismId];
double subMechanismIllustrationPointBeta = subMechanismBetaValues[dataKey];
var illustrationPoint = new SubMechanismIllustrationPoint(submechanismIllustrationPointName,
illustrationPointStochasts,
illustrationPointResults,
subMechanismIllustrationPointBeta);
return new IllustrationPointTreeNode(illustrationPoint);
}
private static void AddRange(ICollection collection, IEnumerable itemsToAdd)
{
foreach (T item in itemsToAdd)
{
collection.Add(item);
}
}
///
/// Parses beta values from the .
///
/// The database reader.
/// Throw when:
///
/// - The read is ;
/// - Multiple values for beta of illustration point found.
///
///
private void ParseGeneralBetaValue(HydraRingDatabaseReader reader)
{
Dictionary[] betaValues = GetIterator(reader).ToArray();
if (betaValues.Length != 1)
{
throw new HydraRingFileParserException(Resources.IllustrationPointsParser_Parse_Multiple_values_for_beta_of_illustration_point_found);
}
beta = ConvertToDouble(betaValues[0][IllustrationPointsDatabaseConstants.BetaValue],
IllustrationPointsDatabaseConstants.BetaValue);
}
///
/// Converts to .
///
/// The object to convert.
/// The identifier.
/// The converted double.
/// Throw when
/// is .
///
private static double ConvertToDouble(object doubleValue, string identifier)
{
if (doubleValue.Equals(DBNull.Value))
{
throw new HydraRingFileParserException(string.Format(Resources.IllustrationPointsParser_Parse_Column_0_is_Null, identifier));
}
return Convert.ToDouble(doubleValue);
}
///
/// Parses objects from the .
///
/// The database reader.
/// Throw when the read
/// or is .
private void ParseGeneralAlphaValues(HydraRingDatabaseReader reader)
{
stochasts = GetIterator(reader).Select(a =>
{
string name = Convert.ToString(a[IllustrationPointsDatabaseConstants.StochastName]);
double duration = ConvertToDouble(a[IllustrationPointsDatabaseConstants.Duration], IllustrationPointsDatabaseConstants.Duration);
double alpha = ConvertToDouble(a[IllustrationPointsDatabaseConstants.AlphaValue], IllustrationPointsDatabaseConstants.AlphaValue);
return new Stochast(name, duration, alpha);
}).ToArray();
}
private void ParseClosingSituations(HydraRingDatabaseReader reader)
{
closingSituations = GetIterator(reader).ToDictionary(
r => Convert.ToInt32(r[IllustrationPointsDatabaseConstants.ClosingSituationId]),
r => Convert.ToString(r[IllustrationPointsDatabaseConstants.ClosingSituationName]));
}
///
/// Parses objects from the .
///
/// The database reader.
/// Throw when the read
/// is .
private void ParseWindDirections(HydraRingDatabaseReader reader)
{
windDirections = new Dictionary();
foreach (Dictionary readWindDirection in GetIterator(reader))
{
int key = Convert.ToInt32(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionId]);
string name = Convert.ToString(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionName]);
double angle = ConvertToDouble(readWindDirection[IllustrationPointsDatabaseConstants.WindDirectionAngle],
IllustrationPointsDatabaseConstants.WindDirectionAngle);
bool isGoverning = Convert.ToBoolean(readWindDirection[IllustrationPointsDatabaseConstants.IsGoverning]);
var windDirection = new WindDirection(name, angle);
windDirections[key] = windDirection;
if (isGoverning)
{
governingWindDirection = windDirection;
}
}
}
private void ParseSubMechanisms(HydraRingDatabaseReader reader)
{
subMechanisms = GetIterator(reader).ToDictionary(
r => Convert.ToInt32(r[IllustrationPointsDatabaseConstants.SubMechanismId]),
r => Convert.ToString(r[IllustrationPointsDatabaseConstants.SubMechanismName]));
}
private void ParseFaultTrees(HydraRingDatabaseReader reader)
{
faultTrees = GetIterator(reader).ToDictionary(
r => Convert.ToInt32(r[IllustrationPointsDatabaseConstants.FaultTreeId]),
r => Convert.ToString(r[IllustrationPointsDatabaseConstants.FaultTreeName]));
}
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;
}
}
}
}