// 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.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Linq;
using Ringtoets.HydraRing.Calculation.Data;
using Ringtoets.HydraRing.Calculation.Data.Defaults;
using Ringtoets.HydraRing.Calculation.Data.Input;
using Ringtoets.HydraRing.Calculation.Data.Settings;
using Ringtoets.HydraRing.Calculation.Providers;
namespace Ringtoets.HydraRing.Calculation.Services
{
///
/// Service for generating the database creation script that is necessary for performing Hydra-Ring calculations.
/// The following Hydra-Ring features are not exposed (yet):
///
/// -
/// Combination of multiple sections
///
/// -
/// Coupling two hydraulic boundary stations
///
/// -
/// Performing revetment calculations (DesignTables > LayerId)
///
/// -
/// Performing piping calculations (DesignTables > AlternativeId)
///
/// -
/// Type III calculations (DesignTables > Method)
///
///
/// In the end, the configuration can be used to generate a Hydra-Ring database creation script.
///
internal class HydraRingConfigurationService
{
private struct InputWithSettings
{
public HydraRingCalculationInput Input;
public DesignTablesSetting DesignTablesSetting;
public HydraulicModelsSetting HydraulicModelsSetting;
public Dictionary NumericsSetting;
public InputWithSettings(HydraRingCalculationInput hydraRingCalculationInput, DesignTablesSetting designTablesSetting, HydraulicModelsSetting hydraulicModelsSetting, Dictionary numericsSetting)
{
Input = hydraRingCalculationInput;
DesignTablesSetting = designTablesSetting;
NumericsSetting = numericsSetting;
HydraulicModelsSetting = hydraulicModelsSetting;
}
}
private const double defaultLayerId = 1;
private const double defaultAlternativeId = 1;
private const double defaultHydraRingValue = 0.0;
private readonly double? defaultHydraRingNullValue = null;
private readonly string ringId;
private readonly IList hydraRingInputsAndSettings = new List();
private readonly FailureMechanismDefaultsProvider failureMechanismDefaultsProvider = new FailureMechanismDefaultsProvider();
private readonly VariableDefaultsProvider variableDefaultsProvider = new VariableDefaultsProvider();
private readonly NumericsSettingsProvider numericsSettingsProvider = new NumericsSettingsProvider();
private readonly DesignTablesSettingsProvider designTablesSettingsProvider = new DesignTablesSettingsProvider();
private readonly HydraulicModelsSettingsProvider hydraulicModelsSettingsProvider = new HydraulicModelsSettingsProvider();
private readonly HydraRingUncertaintiesType uncertaintiesType;
///
/// Creates a new instance of the class.
///
/// The id of the ring to perform Hydra-Ring calculations for.
/// The to use while performing Hydra-Ring calculations.
public HydraRingConfigurationService(string ringId, HydraRingUncertaintiesType uncertaintiesType)
{
this.ringId = ringId;
this.uncertaintiesType = uncertaintiesType;
}
///
/// Gets the id of the ring to perform Hydra-Ring calculations for.
///
public string RingId
{
get
{
return ringId;
}
}
///
/// Gets the to use while performing Hydra-Ring calculations.
///
public HydraRingUncertaintiesType UncertaintiesType
{
get
{
return uncertaintiesType;
}
}
///
/// Adds Hydra-Ring calculation input to the configuration.
///
/// The calculation input to add to the configuration.
/// Thrown when with
/// the same has already been added.
public void AddHydraRingCalculationInput(HydraRingCalculationInput hydraRingCalculationInput)
{
AddHydraRingCalculationInput(hydraRingCalculationInput,
null,
null,
null);
}
///
/// Adds Hydra-Ring calculation input to the configuration.
///
/// The calculation input to add to the configuration.
/// The settings for the design table when performing the calculation with given .
/// The dictionary containing numerics settings per submechanism for the given .
/// The settings for the hydraulic models when performing the calculation with given .
/// Thrown when with
/// the same has already been added.
public void AddHydraRingCalculationInput(HydraRingCalculationInput input, DesignTablesSetting designTablesSetting,
Dictionary numericsSettings, HydraulicModelsSetting hydraulicModelsSetting)
{
if (hydraRingInputsAndSettings.Any(h => h.Input.Section.SectionId == input.Section.SectionId))
{
throw new ArgumentException(@"Section id is not unique", "input");
}
if (hydraRingInputsAndSettings.Count > 0 && hydraRingInputsAndSettings.First().Input.FailureMechanismType != input.FailureMechanismType)
{
throw new NotSupportedException("Running calculations for multiple failure mechanism types is not supported.");
}
hydraRingInputsAndSettings.Add(new InputWithSettings(
input,
designTablesSetting,
hydraulicModelsSetting, numericsSettings));
}
///
/// Generates the database creation script necessary for performing Hydra-Ring calculations.
///
/// The database creation script.
public void WriteDataBaseCreationScript(string databaseFilePath)
{
var configurationDictionary = new Dictionary>();
configurationDictionary["HydraulicModels"] = GetHydraulicModelsConfiguration();
configurationDictionary["Sections"] = GetSectionsConfiguration();
configurationDictionary["DesignTables"] = GetDesignTablesConfiguration();
configurationDictionary["Numerics"] = GetNumericsConfiguration();
configurationDictionary["VariableDatas"] = GetVariableDatasConfiguration();
configurationDictionary["CalculationProfiles"] = GetCalculationProfilesConfiguration();
configurationDictionary["SectionFaultTreeModels"] = GetSectionFaultTreeModelsConfiguration();
configurationDictionary["SectionSubMechanismModels"] = GetSectionSubMechanismModelsConfiguration();
configurationDictionary["Fetches"] = new List();
configurationDictionary["AreaPoints"] = new List();
configurationDictionary["PresentationSections"] = new List();
configurationDictionary["Profiles"] = GetProfilesConfiguration();
configurationDictionary["ForelandModels"] = GetForlandModelsConfiguration();
configurationDictionary["Forelands"] = GetForelandsConfiguration();
configurationDictionary["ProbabilityAlternatives"] = new List();
configurationDictionary["SetUpHeights"] = new List();
configurationDictionary["CalcWindDirections"] = new List();
configurationDictionary["Swells"] = new List();
configurationDictionary["WaveReductions"] = new List();
configurationDictionary["Areas"] = GetAreasConfiguration();
configurationDictionary["Projects"] = GetProjectsConfiguration();
configurationDictionary["Breakwaters"] = GetBreakWatersConfiguration();
File.WriteAllText(databaseFilePath, GenerateDataBaseCreationScript(configurationDictionary));
}
private IList GetHydraulicModelsConfiguration()
{
var timeIntegrationSchemeId = 1;
if(hydraRingInputsAndSettings.Count > 0)
{
HydraulicModelsSetting hydraulicModelsSetting = hydraulicModelsSettingsProvider.GetHydraulicModelsSetting(
hydraRingInputsAndSettings.First().Input.FailureMechanismType,
ringId);
timeIntegrationSchemeId = hydraulicModelsSetting.TimeIntegrationSchemeId;
}
return new List
{
new OrderedDictionary
{
{
"TimeIntegrationSchemeID", timeIntegrationSchemeId
},
{
"UncertaintiesID", (int) UncertaintiesType
},
{
"DataSetName", "WTI 2017" // Fixed: use the WTI 2017 set of station locations
}
}
};
}
private IList GetSectionsConfiguration()
{
var orderedDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
HydraRingSection hydraRingSection = hydraRingCalculationInput.Section;
orderedDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingSection.SectionId
},
{
"PresentationId", 1 // Fixed: no support for combination of multiple sections
},
{
"MainMechanismId", 1 // Fixed: no support for combination of multiple sections
},
{
"Name", hydraRingSection.SectionId // Just use the section id
},
{
"Description", hydraRingSection.SectionId // Just use the section id
},
{
"RingCoordinateBegin", defaultHydraRingValue // No support for coordinates
},
{
"RingCoordinateEnd", defaultHydraRingValue // No support for coordinates
},
{
"XCoordinate", defaultHydraRingValue // No support for coordinates
},
{
"YCoordinate", defaultHydraRingValue // No support for coordinates
},
{
"StationId1", hydraRingCalculationInput.HydraulicBoundaryLocationId
},
{
"StationId2", hydraRingCalculationInput.HydraulicBoundaryLocationId // Same as "StationId1": no support for coupling two stations
},
{
"Relative", 100.0 // Fixed: no support for coupling two stations
},
{
"Normal", GetHydraRingValue(hydraRingSection.CrossSectionNormal)
},
{
"Length", GetHydraRingValue(hydraRingSection.SectionLength)
}
});
}
return orderedDictionaries;
}
private IList GetDesignTablesConfiguration()
{
var orderedDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(hydraRingCalculationInput.FailureMechanismType);
DesignTablesSetting designTablesSetting = designTablesSettingsProvider.GetDesignTablesSetting(hydraRingCalculationInput.FailureMechanismType, ringId);
orderedDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"MechanismId", failureMechanismDefaults.MechanismId
},
{
"LayerId", defaultLayerId // Fixed: no support for revetments
},
{
"AlternativeId", defaultAlternativeId // Fixed: no support for piping
},
{
"Method", hydraRingCalculationInput.CalculationTypeId
},
{
"VariableId", hydraRingCalculationInput.VariableId
},
{
"LoadVariableId", defaultHydraRingValue // Fixed: not relevant
},
{
"TableMin", defaultHydraRingValue // Fixed: no support for type III calculations (see "Method")
},
{
"TableMax", defaultHydraRingValue // Fixed: no support for type III calculations (see "Method")
},
{
"TableStepSize", defaultHydraRingValue // Fixed: no support for type III calculations (see "Method")
},
{
"ValueMin", GetHydraRingValue(designTablesSetting.ValueMin)
},
{
"ValueMax", GetHydraRingValue(designTablesSetting.ValueMax)
},
{
"Beta", GetHydraRingValue(hydraRingCalculationInput.Beta)
}
});
}
return orderedDictionaries;
}
private IList GetNumericsConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(hydraRingCalculationInput.FailureMechanismType);
foreach (int subMechanismId in failureMechanismDefaults.SubMechanismIds)
{
var numericsSetting = numericsSettingsProvider.GetNumericsSetting(hydraRingCalculationInput.FailureMechanismType, subMechanismId, ringId);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"MechanismId", failureMechanismDefaults.MechanismId
},
{
"LayerId", defaultLayerId // Fixed: no support for revetments
},
{
"AlternativeId", defaultAlternativeId // Fixed: no support for piping
},
{
"SubMechanismId", subMechanismId
},
{
"Method", numericsSetting.CalculationTechniqueId
},
{
"FormStartMethod", numericsSetting.FormStartMethod
},
{
"FormNumberOfIterations", numericsSetting.FormNumberOfIterations
},
{
"FormRelaxationFactor", GetHydraRingValue(numericsSetting.FormRelaxationFactor)
},
{
"FormEpsBeta", GetHydraRingValue(numericsSetting.FormEpsBeta)
},
{
"FormEpsHOH", GetHydraRingValue(numericsSetting.FormEpsHoh)
},
{
"FormEpsZFunc", GetHydraRingValue(numericsSetting.FormEpsZFunc)
},
{
"DsStartMethod", numericsSetting.DsStartMethod
},
{
"DsIterationmethod", 1 // Fixed: not relevant
},
{
"DsMinNumberOfIterations", numericsSetting.DsMinNumberOfIterations
},
{
"DsMaxNumberOfIterations", numericsSetting.DsMaxNumberOfIterations
},
{
"DsVarCoefficient", GetHydraRingValue(numericsSetting.DsVarCoefficient)
},
{
"NiUMin", GetHydraRingValue(numericsSetting.NiUMin)
},
{
"NiUMax", GetHydraRingValue(numericsSetting.NiUMax)
},
{
"NiNumberSteps", numericsSetting.NiNumberSteps
}
});
}
}
return orderDictionaries;
}
private IList GetVariableDatasConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(hydraRingCalculationInput.FailureMechanismType);
foreach (HydraRingVariable hydraRingVariable in hydraRingCalculationInput.Variables)
{
var variableDefaults = variableDefaultsProvider.GetVariableDefaults(hydraRingCalculationInput.FailureMechanismType, hydraRingVariable.VariableId);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"MechanismId", failureMechanismDefaults.MechanismId
},
{
"LayerId", defaultLayerId // Fixed: no support for revetments
},
{
"AlternativeId", defaultAlternativeId // Fixed: no support for piping
},
{
"VariableId", hydraRingVariable.VariableId
},
{
"Value", GetHydraRingValue(hydraRingVariable.Value)
},
{
"DistributionType", (int?) hydraRingVariable.DistributionType
},
{
"Parameter1", hydraRingVariable.DistributionType != HydraRingDistributionType.Deterministic
? GetHydraRingValue(hydraRingVariable.Mean)
: defaultHydraRingValue
},
{
"Parameter2", hydraRingVariable.DistributionType != HydraRingDistributionType.Deterministic
&& hydraRingVariable.DeviationType == HydraRingDeviationType.Standard
? GetHydraRingNullableValue(hydraRingVariable.Variability)
: defaultHydraRingNullValue
},
{
"Parameter3", hydraRingVariable.DistributionType == HydraRingDistributionType.LogNormal
? GetHydraRingNullableValue(hydraRingVariable.Shift)
: defaultHydraRingNullValue
},
{
"Parameter4", defaultHydraRingNullValue // Fixed: Not relevant
},
{
"DeviationType", (int?) hydraRingVariable.DeviationType
},
{
"CoefficientOfVariation", hydraRingVariable.DistributionType != HydraRingDistributionType.Deterministic
&& hydraRingVariable.DeviationType == HydraRingDeviationType.Variation
? GetHydraRingValue(hydraRingVariable.Variability)
: defaultHydraRingValue
},
{
"CorrelationLength", GetHydraRingValue(variableDefaults.CorrelationLength)
}
});
}
}
return orderDictionaries;
}
private IList GetProfilesConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
for (var i = 0; i < hydraRingCalculationInput.ProfilePoints.Count(); i++)
{
HydraRingProfilePoint hydraRingProfilePoint = hydraRingCalculationInput.ProfilePoints.ElementAt(i);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"SequenceNumber", i + 1
},
{
"XCoordinate", GetHydraRingValue(hydraRingProfilePoint.X)
},
{
"ZCoordinate", GetHydraRingValue(hydraRingProfilePoint.Z)
}
});
}
}
return orderDictionaries;
}
private IList GetCalculationProfilesConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
for (var i = 0; i < hydraRingCalculationInput.ProfilePoints.Count(); i++)
{
HydraRingProfilePoint hydraRingProfilePoint = hydraRingCalculationInput.ProfilePoints.ElementAt(i);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"SequenceNumber", i + 1
},
{
"XCoordinate", GetHydraRingValue(hydraRingProfilePoint.X)
},
{
"ZCoordinate", GetHydraRingValue(hydraRingProfilePoint.Z)
},
{
"Roughness", GetHydraRingValue(hydraRingProfilePoint.Roughness)
}
});
}
}
return orderDictionaries;
}
private IList GetForlandModelsConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings.Where(i => i.Input.ForelandsPoints.Any()))
{
HydraRingCalculationInput input = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(input.FailureMechanismType);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", input.Section.SectionId
},
{
"MechanismId", failureMechanismDefaults.MechanismId
},
{
"Model", 3
}
});
}
return orderDictionaries;
}
private IList GetForelandsConfiguration()
{
var orderDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
for (var i = 0; i < hydraRingCalculationInput.ForelandsPoints.Count(); i++)
{
var forelandPoint = hydraRingCalculationInput.ForelandsPoints.ElementAt(i);
orderDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"SequenceNumber", i + 1
},
{
"XCoordinate", GetHydraRingValue(forelandPoint.X)
},
{
"ZCoordinate", GetHydraRingValue(forelandPoint.Z)
}
});
}
}
return orderDictionaries;
}
private IList GetBreakWatersConfiguration()
{
var orderedDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
if (hydraRingCalculationInput.BreakWater != null)
{
orderedDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"Type", hydraRingCalculationInput.BreakWater.Type
},
{
"Height", GetHydraRingValue(hydraRingCalculationInput.BreakWater.Height)
}
});
}
}
return orderedDictionaries;
}
private IList GetSectionFaultTreeModelsConfiguration()
{
var orderedDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(hydraRingCalculationInput.FailureMechanismType);
orderedDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"MechanismId", failureMechanismDefaults.MechanismId
},
{
"LayerId", defaultLayerId // Fixed: no support for revetments
},
{
"AlternativeId", defaultAlternativeId // Fixed: no support for piping
},
{
"FaultTreeModelId", failureMechanismDefaults.FaultTreeModelId
}
});
}
return orderedDictionaries;
}
private IList GetSectionSubMechanismModelsConfiguration()
{
var orderedDictionaries = new List();
foreach (InputWithSettings inputWithSettings in hydraRingInputsAndSettings)
{
HydraRingCalculationInput hydraRingCalculationInput = inputWithSettings.Input;
FailureMechanismDefaults failureMechanismDefaults = failureMechanismDefaultsProvider.GetFailureMechanismDefaults(hydraRingCalculationInput.FailureMechanismType);
foreach (var subMechanismId in failureMechanismDefaults.SubMechanismIds)
{
var subMechanismModelId = hydraRingCalculationInput.GetSubMechanismModelId(subMechanismId);
if (subMechanismModelId != null)
{
orderedDictionaries.Add(new OrderedDictionary
{
{
"SectionId", hydraRingCalculationInput.Section.SectionId
},
{
"LayerId", defaultLayerId // Fixed: no support for revetments
},
{
"AlternativeId", defaultAlternativeId // Fixed: no support for piping
},
{
"SubMechanismId", subMechanismId
},
{
"SubMechanismModelId", subMechanismModelId
}
});
}
}
}
return orderedDictionaries;
}
private IList GetAreasConfiguration()
{
return new List
{
new OrderedDictionary
{
{
"aDefault", 1 // Fixed: not relevant
},
{
"bDefault", "1" // Fixed: not relevant
},
{
"cDefault", "Nederland" // Fixed: not relevant
}
}
};
}
private IList GetProjectsConfiguration()
{
return new List
{
new OrderedDictionary
{
{
"aDefault", 1 // Fixed: not relevant
},
{
"bDefault", "WTI 2017" // Fixed: not relevant
},
{
"cDefault", "Ringtoets calculation" // Fixed: not relevant
}
}
};
}
private static string GenerateDataBaseCreationScript(Dictionary> configurationDictionary)
{
var lines = new List();
foreach (var tableName in configurationDictionary.Keys)
{
lines.Add("DELETE FROM [" + tableName + "];");
if (configurationDictionary[tableName].Count <= 0)
{
lines.Add("");
continue;
}
foreach (var orderedDictionary in configurationDictionary[tableName])
{
var valueStrings = new List();
foreach (var val in orderedDictionary.Values)
{
if (val == null)
{
valueStrings.Add("NULL");
continue;
}
if (val is string)
{
valueStrings.Add("'" + val + "'");
continue;
}
if (val is double)
{
valueStrings.Add(((double) val).ToString(CultureInfo.InvariantCulture));
continue;
}
valueStrings.Add(val.ToString());
}
var valuesString = string.Join(", ", valueStrings);
lines.Add("INSERT INTO [" + tableName + "] VALUES (" + valuesString + ");");
}
lines.Add("");
}
return string.Join(Environment.NewLine, lines);
}
private static double GetHydraRingValue(double value)
{
return !double.IsNaN(value) ? value : defaultHydraRingValue;
}
private double? GetHydraRingNullableValue(double value)
{
return !double.IsNaN(value) ? value : defaultHydraRingNullValue;
}
}
}