// 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.Utils.Extensions;
using Ringtoets.Common.IO.Properties;
namespace Ringtoets.Common.IO.Structures
{
///
/// This class contains validations methods for objects.
///
public static class StructuresParameterRowsValidator
{
///
/// Denotes a small enough value, taking possible rounding into account, that the
/// value is too close to the value 0.0 that makes a coefficient of variation
/// too unreliable.
///
private const double valueTooCloseToZero = 1e-4;
private static readonly List closingStructureInflowModelTypeRuleKeywords = new List
{
StructureFilesKeywords.InflowModelTypeVerticalWall,
StructureFilesKeywords.InflowModelTypeLowSill,
StructureFilesKeywords.InflowModelTypeFloodedCulvert
};
private static readonly List stabilityPointStructureInflowModelTypeRuleKeywords = new List
{
StructureFilesKeywords.InflowModelTypeLowSill,
StructureFilesKeywords.InflowModelTypeFloodedCulvert
};
private static readonly Dictionary>> heightStructuresRules =
new Dictionary>>
{
{
StructureFilesKeywords.HeightStructureParameterKeyword1, StructureNormalOrientation
},
{
StructureFilesKeywords.HeightStructureParameterKeyword2, NormalDistributionRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword3, LogNormalDistributionRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword4, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword5, VariationCoefficientNormalDistributionRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword6, ProbabilityRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword7, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.HeightStructureParameterKeyword8, LogNormalDistributionRule
}
};
private static readonly Dictionary>> closingStructuresRules =
new Dictionary>>
{
{
StructureFilesKeywords.ClosingStructureParameterKeyword1, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword2, LogNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword3, StructureNormalOrientation
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword4, VariationCoefficientNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword5, NormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword6, NormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword7, NormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword8, LogNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword9, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword10, LogNormalDistributionRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword11, ProbabilityRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword12, ProbabilityRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword13, IdenticalApertures
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword14, ProbabilityRule
},
{
StructureFilesKeywords.ClosingStructureParameterKeyword15, ClosingStructureInflowModelTypeRule
}
};
private static readonly Dictionary>> stabilityPointStructuresRules =
new Dictionary>>
{
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword1, StructureNormalOrientation
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword2, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword3, LogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword4, VariationCoefficientNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword5, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword6, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword7, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword8, LogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword9, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword10, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword11, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword12, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword13, DoubleRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword14, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword15, PositiveDoubleRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword16, ProbabilityRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword17, PositiveDoubleRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword18, VariationCoefficientNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword19, VariationCoefficientNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword20, PositiveDoubleRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword21, ProbabilityRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword22, NormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword23, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword24, VariationCoefficientLogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword25, LogNormalDistributionRule
},
{
StructureFilesKeywords.StabilityPointStructureParameterKeyword26, StabilityPointStructureInflowModelTypeRule
}
};
///
/// Validates a collection of for a height structure.
///
/// The objects to validate.
/// A object containing the validation result.
/// Thrown when is null.
public static ValidationResult ValidateHeightStructuresParameters(IList structureParameterRows)
{
return ValidateStructuresParameters(structureParameterRows, heightStructuresRules);
}
///
/// Validates a collection of for a closing structure.
///
/// The objects to validate.
/// A object containing the validation result.
/// Thrown when is null.
public static ValidationResult ValidateClosingStructuresParameters(IList structureParameterRows)
{
return ValidateStructuresParameters(structureParameterRows, closingStructuresRules);
}
///
/// Validates a collection of for a stability point structure.
///
/// The objects to validate.
/// A object containing the validation result.
/// Thrown when is null.
public static ValidationResult ValidateStabilityPointStructuresParameters(IList structureParameterRows)
{
return ValidateStructuresParameters(structureParameterRows, stabilityPointStructuresRules);
}
private static ValidationResult ValidateStructuresParameters(IList structureParameterRows,
Dictionary>> rules)
{
if (structureParameterRows == null)
{
throw new ArgumentNullException("structureParameterRows");
}
var errorMessages = new List();
foreach (string name in rules.Keys)
{
int count = structureParameterRows.Count(row => string.Equals(row.ParameterId, name, StringComparison.OrdinalIgnoreCase));
if (count < 1)
{
errorMessages.Add(string.Format(Resources.StructuresParameterRowsValidator_Parameter_0_missing_or_invalid, name));
continue;
}
if (count > 1)
{
errorMessages.Add(string.Format(Resources.StructuresParameterRowsValidator_Parameter_0_repeated, name));
}
errorMessages.AddRange(rules[name](structureParameterRows.First(row => string.Equals(row.ParameterId, name, StringComparison.OrdinalIgnoreCase))));
}
return new ValidationResult(errorMessages);
}
private static List DoubleRule(StructuresParameterRow row)
{
return ValidateDoubleParameter(row, StructureFilesKeywords.NumericalValueColumnName);
}
private static List PositiveDoubleRule(StructuresParameterRow row)
{
return ValidatePositiveDoubleParameter(row, StructureFilesKeywords.NumericalValueColumnName);
}
private static List ValidateDoubleParameter(StructuresParameterRow row, string columnName)
{
var messages = new List();
double value = GetValueFromRowForColumn(row, columnName);
if (double.IsNaN(value) || double.IsInfinity(value))
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ValidateDoubleParameter_ParameterId_0_Line_1_ColumnName_2_not_number,
row.ParameterId, row.LineNumber, columnName.FirstToUpper()));
}
return messages;
}
private static List ValidatePositiveDoubleParameter(StructuresParameterRow row, string columnName)
{
var messages = new List();
double value = GetValueFromRowForColumn(row, columnName);
if (double.IsNaN(value) || double.IsInfinity(value) || value < 0)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ValidatePositiveDoubleParameter_ParameterId_0_Line_1_ColumnName_2_must_be_a_positive_number,
row.ParameterId, row.LineNumber, columnName.FirstToUpper()));
}
return messages;
}
private static double GetValueFromRowForColumn(StructuresParameterRow row, string columnName)
{
switch (columnName)
{
case StructureFilesKeywords.NumericalValueColumnName:
return row.NumericalValue;
case StructureFilesKeywords.VariationValueColumnName:
return row.VarianceValue;
default:
throw new NotImplementedException();
}
}
private static List ProbabilityRule(StructuresParameterRow row)
{
var messages = new List();
double mean = row.NumericalValue;
if (double.IsNaN(mean) || double.IsInfinity(mean) || mean <= 0 || mean > 1)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ProbabilityRule_ParameterId_0_Line_1_ColumnName_2_probability_out_of_range,
row.ParameterId, row.LineNumber, StructureFilesKeywords.NumericalValueColumnName.FirstToUpper()));
}
return messages;
}
private static List NormalDistributionRule(StructuresParameterRow row)
{
return ValidateStochasticVariableParameters(row, false, true);
}
private static List VariationCoefficientNormalDistributionRule(StructuresParameterRow row)
{
return ValidateStochasticVariableParameters(row, false, false);
}
private static List LogNormalDistributionRule(StructuresParameterRow row)
{
return ValidateStochasticVariableParameters(row, true, true);
}
private static List VariationCoefficientLogNormalDistributionRule(StructuresParameterRow row)
{
return ValidateStochasticVariableParameters(row, true, false);
}
private static List ValidateStochasticVariableParameters(StructuresParameterRow row, bool meanMustBeGreaterThanZero, bool variationAsStandardDeviation)
{
var messages = new List();
double mean = row.NumericalValue;
var numericalValueColumn1 = StructureFilesKeywords.NumericalValueColumnName;
messages.AddRange(meanMustBeGreaterThanZero ?
ValidatePositiveDoubleParameter(row, numericalValueColumn1) :
ValidateDoubleParameter(row, numericalValueColumn1));
VarianceType type = row.VarianceType;
if (type != VarianceType.StandardDeviation && type != VarianceType.CoefficientOfVariation)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_invalid_variancetype_value,
row.ParameterId, row.LineNumber, StructureFilesKeywords.VariationTypeColumnName.FirstToUpper()));
}
messages.AddRange(ValidatePositiveDoubleParameter(row, StructureFilesKeywords.VariationValueColumnName));
double absoluteMean = Math.Abs(mean);
if (variationAsStandardDeviation)
{
if (row.VarianceType == VarianceType.CoefficientOfVariation && absoluteMean < valueTooCloseToZero)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_mean_too_small_for_reliable_variation_value_conversion,
row.ParameterId, row.LineNumber, StructureFilesKeywords.NumericalValueColumnName.FirstToUpper()));
}
}
else
{
if (row.VarianceType == VarianceType.StandardDeviation && absoluteMean < valueTooCloseToZero)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_mean_too_small_for_reliable_variation_value_conversion,
row.ParameterId, row.LineNumber, StructureFilesKeywords.NumericalValueColumnName.FirstToUpper()));
}
}
return messages;
}
private static List StructureNormalOrientation(StructuresParameterRow row)
{
var messages = new List();
double orientation = row.NumericalValue;
if (!(orientation >= 0 && orientation <= 360))
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_orientation_out_of_range,
row.ParameterId, row.LineNumber, StructureFilesKeywords.NumericalValueColumnName.FirstToUpper()));
}
return messages;
}
private static List IdenticalApertures(StructuresParameterRow row)
{
var messages = new List();
double value = row.NumericalValue;
if (!IsValueWholeNumber(value) || value < 0)
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_value_must_be_positive_whole_number,
row.ParameterId, row.LineNumber, StructureFilesKeywords.NumericalValueColumnName.FirstToUpper()));
}
return messages;
}
private static bool IsValueWholeNumber(double value)
{
return (value%1) < double.Epsilon;
}
private static List ClosingStructureInflowModelTypeRule(StructuresParameterRow row)
{
var messages = new List();
string value = row.AlphanumericValue.ToLower();
if (!closingStructureInflowModelTypeRuleKeywords.Contains(value))
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_structure_type_invalid,
row.ParameterId, row.LineNumber, StructureFilesKeywords.AlphanumericalValueColumnName.FirstToUpper()));
}
return messages;
}
private static List StabilityPointStructureInflowModelTypeRule(StructuresParameterRow row)
{
var messages = new List();
string value = row.AlphanumericValue.ToLower();
if (!stabilityPointStructureInflowModelTypeRuleKeywords.Contains(value))
{
messages.Add(string.Format(Resources.StructuresParameterRowsValidator_ParameterId_0_Line_1_ColumnName_2_structure_type_invalid,
row.ParameterId, row.LineNumber, StructureFilesKeywords.AlphanumericalValueColumnName.FirstToUpper()));
}
return messages;
}
}
}