// 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.Base; using Core.Common.Base.Data; using Core.Common.Base.Geometry; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.DikeProfiles; using Ringtoets.HydraRing.Data; using Ringtoets.Revetment.Data.Properties; using RingtoetsCommonDataResources = Ringtoets.Common.Data.Properties.Resources; namespace Ringtoets.Revetment.Data { /// /// Class that holds all wave conditions calculation specific input parameters. /// public class WaveConditionsInput : Observable, ICalculationInput, IUseBreakWater, IUseForeshore { private const double designWaterLevelSubstraction = 0.01; private ForeshoreProfile foreshoreProfile; private RoundedDouble upperBoundaryRevetment; private RoundedDouble lowerBoundaryRevetment; private RoundedDouble upperBoundaryWaterLevels; private RoundedDouble lowerBoundaryWaterLevels; private RoundedDouble orientation; /// /// Creates a new instance of . /// public WaveConditionsInput() { orientation = new RoundedDouble(2); upperBoundaryRevetment = new RoundedDouble(2, double.NaN); lowerBoundaryRevetment = new RoundedDouble(2, double.NaN); StepSize = WaveConditionsInputStepSize.Half; upperBoundaryWaterLevels = new RoundedDouble(2, double.NaN); lowerBoundaryWaterLevels = new RoundedDouble(2, double.NaN); UpdateForeshoreProfileParameters(); } /// /// Gets or sets the hydraulic boundary location from which to use the assessment level. /// public HydraulicBoundaryLocation HydraulicBoundaryLocation { get; set; } /// /// Gets the assessment level from the current hydraulic boundary location, or if there is no /// location selected. /// public RoundedDouble AssessmentLevel { get { return HydraulicBoundaryLocation != null ? HydraulicBoundaryLocation.DesignWaterLevel : new RoundedDouble(2, double.NaN); } } /// /// Gets or sets the foreshore profile. /// public ForeshoreProfile ForeshoreProfile { get { return foreshoreProfile; } set { foreshoreProfile = value; UpdateForeshoreProfileParameters(); } } /// /// Gets or sets the orientation of the foreshore profile geometry with respect to North /// in degrees. A positive value equals a clockwise rotation. /// ///Thrown when the value of the orientation /// is not in the interval [0, 360]. public RoundedDouble Orientation { get { return orientation; } set { RoundedDouble newOrientation = value.ToPrecision(orientation.NumberOfDecimalPlaces); if (!double.IsNaN(newOrientation) && (newOrientation < 0 || newOrientation > 360)) { throw new ArgumentOutOfRangeException("value", RingtoetsCommonDataResources.Orientation_Value_needs_to_be_between_0_and_360); } orientation = newOrientation; } } /// /// Gets the upper boundary based on . /// public RoundedDouble UpperBoundaryDesignWaterLevel { get { return new RoundedDouble(2, AssessmentLevel - designWaterLevelSubstraction); } } /// /// Gets or sets the lower boundary of the revetment. /// /// Thrown when value is larger than or equal to . /// When the value is smaller than -50, it will be set to -50. public RoundedDouble LowerBoundaryRevetment { get { return lowerBoundaryRevetment; } set { RoundedDouble newLowerBoundaryRevetment = value.ToPrecision(lowerBoundaryRevetment.NumberOfDecimalPlaces); newLowerBoundaryRevetment = ValidateLowerBoundaryInRange(newLowerBoundaryRevetment); ValidateRevetmentBoundaries(newLowerBoundaryRevetment, UpperBoundaryRevetment); lowerBoundaryRevetment = newLowerBoundaryRevetment; } } /// /// Gets or sets the upper boundary of the revetment. /// /// Thrown when value is smaller than or equal to . /// When the value is larger than 1000, it will be set to 1000. public RoundedDouble UpperBoundaryRevetment { get { return upperBoundaryRevetment; } set { RoundedDouble newUpperBoundaryRevetment = value.ToPrecision(upperBoundaryRevetment.NumberOfDecimalPlaces); newUpperBoundaryRevetment = ValidateUpperBoundaryInRange(newUpperBoundaryRevetment); ValidateRevetmentBoundaries(LowerBoundaryRevetment, newUpperBoundaryRevetment); upperBoundaryRevetment = newUpperBoundaryRevetment; } } /// /// Gets or sets the step size used for determining . /// public WaveConditionsInputStepSize StepSize { get; set; } /// /// Gets or sets the lower boundary of the range. /// /// Thrown when value is larger than or equal to . /// /// /// Setting this property is optional when it comes to determining ; if the value /// equals , only will be taken into account. /// When the value is smaller than -50, it will be set to -50. /// /// public RoundedDouble LowerBoundaryWaterLevels { get { return lowerBoundaryWaterLevels; } set { RoundedDouble newLowerBoundaryWaterLevels = value.ToPrecision(lowerBoundaryWaterLevels.NumberOfDecimalPlaces); newLowerBoundaryWaterLevels = ValidateLowerBoundaryInRange(newLowerBoundaryWaterLevels); ValidateWaterLevelBoundaries(newLowerBoundaryWaterLevels, UpperBoundaryWaterLevels); lowerBoundaryWaterLevels = newLowerBoundaryWaterLevels; } } /// /// Gets or sets the upper boundary of the range. /// /// Thrown when value is smaller than or equal to . /// /// /// Setting this property is optional when it comes to determining ; if the value /// equals , only and /// will be taken into account. /// When the value is larger than 1000, it will be set to 1000. /// /// public RoundedDouble UpperBoundaryWaterLevels { get { return upperBoundaryWaterLevels; } set { RoundedDouble newUpperBoundaryWaterLevels = value.ToPrecision(upperBoundaryWaterLevels.NumberOfDecimalPlaces); newUpperBoundaryWaterLevels = ValidateUpperBoundaryInRange(newUpperBoundaryWaterLevels); ValidateWaterLevelBoundaries(LowerBoundaryWaterLevels, newUpperBoundaryWaterLevels); upperBoundaryWaterLevels = newUpperBoundaryWaterLevels; } } /// /// Gets the water levels to perform a wave conditions calculation for. /// public IEnumerable WaterLevels { get { return DetermineWaterLevels(); } } /// /// Gets or sets whether needs to be taken into account. /// public bool UseBreakWater { get; set; } /// /// Gets the . /// public BreakWater BreakWater { get; private set; } /// /// Gets or sets whether the needs to be taken into account. /// public bool UseForeshore { get; set; } /// /// Gets the geometry of the foreshore. /// public RoundedPoint2DCollection ForeshoreGeometry { get { return foreshoreProfile != null ? foreshoreProfile.Geometry : new RoundedPoint2DCollection(2, Enumerable.Empty()); } } private static RoundedDouble ValidateUpperBoundaryInRange(RoundedDouble boundary) { if (boundary > 1000) { boundary = new RoundedDouble(boundary.NumberOfDecimalPlaces, 1000); } return boundary; } private static RoundedDouble ValidateLowerBoundaryInRange(RoundedDouble boundary) { if (boundary < -50) { boundary = new RoundedDouble(boundary.NumberOfDecimalPlaces, -50); } return boundary; } private static void ValidateRevetmentBoundaries(RoundedDouble lowerBoundary, RoundedDouble upperBoundary) { ValidateBoundaries(lowerBoundary, upperBoundary, Resources.WaveConditionsInput_ValidateRevetmentBoundaries_Upper_boundary_revetment_must_be_above_lower_boundary_revetment); } private static void ValidateWaterLevelBoundaries(RoundedDouble lowerBoundary, RoundedDouble upperBoundary) { ValidateBoundaries(lowerBoundary, upperBoundary, Resources.WaveConditionsInput_ValidateWaterLevelBoundaries_Upper_boundary_water_levels_must_be_above_lower_boundary_water_levels); } private static void ValidateBoundaries(RoundedDouble lowerBoundary, RoundedDouble upperBoundary, string exceptionMessage) { if (!double.IsNaN(lowerBoundary) && !double.IsNaN(upperBoundary) && lowerBoundary >= upperBoundary) { throw new ArgumentOutOfRangeException(null, exceptionMessage); } } private IEnumerable DetermineWaterLevels() { var waterLevels = new List(); var upperBoundary = new RoundedDouble(2, Math.Min(UpperBoundaryDesignWaterLevel, Math.Min(UpperBoundaryRevetment, !double.IsNaN(UpperBoundaryWaterLevels) ? UpperBoundaryWaterLevels : double.MaxValue))); var lowerBoundary = new RoundedDouble(2, Math.Max(LowerBoundaryRevetment, !double.IsNaN(LowerBoundaryWaterLevels) ? LowerBoundaryWaterLevels : double.MinValue)); if (double.IsNaN(upperBoundary) || double.IsNaN(lowerBoundary) || (lowerBoundary >= upperBoundary)) { return waterLevels; } waterLevels.Add(upperBoundary); double stepSizeValue = StepSize.AsValue(); RoundedDouble currentWaterLevel = new RoundedDouble(2, Math.Ceiling(upperBoundary/stepSizeValue)*stepSizeValue - stepSizeValue); while (currentWaterLevel > lowerBoundary) { waterLevels.Add(currentWaterLevel); currentWaterLevel = new RoundedDouble(currentWaterLevel.NumberOfDecimalPlaces, currentWaterLevel - stepSizeValue); } waterLevels.Add(lowerBoundary); return waterLevels; } private void UpdateForeshoreProfileParameters() { if (foreshoreProfile == null) { Orientation = (RoundedDouble) double.NaN; UseForeshore = false; UseBreakWater = false; BreakWater = GetDefaultBreakWater(); } else { Orientation = foreshoreProfile.Orientation; UseForeshore = foreshoreProfile.Geometry.Count() > 1; UseBreakWater = foreshoreProfile.HasBreakWater; BreakWater = foreshoreProfile.HasBreakWater ? new BreakWater(foreshoreProfile.BreakWater.Type, foreshoreProfile.BreakWater.Height) : GetDefaultBreakWater(); } } private static BreakWater GetDefaultBreakWater() { return new BreakWater(BreakWaterType.Dam, 0.0); } } }