// 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
{
///
/// The result of parsing the illustration points in the Hydra-Ring database.
///
public readonly GeneralResult Output = new GeneralResult();
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;
private IDictionary subMechanisms;
private IDictionary faultTrees;
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);
}
}
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 (Output.IllustrationPoints == null)
{
SetSubMechanismAsRootIllustrationPoint();
}
}
///
/// 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()
{
var rootIllustrationPoints = new Dictionary();
foreach (Tuple windDirectionClosingSituation in GetAllWindDirectionClosingSituationCombinations())
{
string submechanismIllustrationPointName = subMechanisms.First().Value;
double subMechanismIllustrationPointBeta = subMechanismBetaValues.First().Value;
var illustrationPoint = new SubMechanismIllustrationPoint(submechanismIllustrationPointName,
subMechanismIllustrationPointBeta);
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)
{
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 = name,
Duration = duration,
Alpha = alpha
});
}
}
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 beta = 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] = beta;
}
}
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 = name,
Duration = duration,
Alpha = alpha,
Realization = realization
});
}
}
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 beta = Convert.ToDouble(readSubMechanismBetaValue[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] = beta;
}
}
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 = description,
Value = value
});
}
}
private void ParseFaultTree(HydraRingDatabaseReader reader)
{
IEnumerable> windDirectionClosingSituations =
GetAllWindDirectionClosingSituationCombinations();
Dictionary[] readFaultTrees = GetIterator(reader).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(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);
string submechanismIllustrationPointName = subMechanisms[subMechanismId];
double subMechanismIllustrationPointBeta = subMechanismBetaValues[dataKey];
var illustrationPoint = new SubMechanismIllustrationPoint(submechanismIllustrationPointName,
subMechanismIllustrationPointBeta);
if (subMechanismStochasts.ContainsKey(dataKey))
{
AddRange(illustrationPoint.Stochasts, subMechanismStochasts[dataKey]);
}
if (subMechanismResults.ContainsKey(dataKey))
{
AddRange(illustrationPoint.Results, subMechanismResults[dataKey]);
}
return new IllustrationPointTreeNode(illustrationPoint);
}
private static void AddRange(ICollection collection, IEnumerable itemsToAdd)
{
foreach (T item in itemsToAdd)
{
collection.Add(item);
}
}
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);
}
Output.Beta = ConvertToDouble(betaValues[0][IllustrationPointsDatabaseConstants.BetaValue],
IllustrationPointsDatabaseConstants.BetaValue);
}
///
/// Converts to .
///
///
/// 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);
}
private void ParseGeneralAlphaValues(HydraRingDatabaseReader reader)
{
Output.Stochasts = GetIterator(reader).Select(a => new Stochast
{
Name = Convert.ToString(a[IllustrationPointsDatabaseConstants.StochastName]),
Duration = ConvertToDouble(a[IllustrationPointsDatabaseConstants.Duration], IllustrationPointsDatabaseConstants.Duration),
Alpha = ConvertToDouble(a[IllustrationPointsDatabaseConstants.AlphaValue], IllustrationPointsDatabaseConstants.AlphaValue)
}).ToArray();
}
private void ParseClosingSituations(HydraRingDatabaseReader reader)
{
closingSituations = GetIterator(reader).ToDictionary(
r => Convert.ToInt32(r[IllustrationPointsDatabaseConstants.ClosingSituationId]),
r => Convert.ToString(r[IllustrationPointsDatabaseConstants.ClosingSituationName]));
}
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)
{
Output.GoverningWind = 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;
}
}
}
}