Index: DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/Deltares.DamEngine.IntegrationTests.csproj =================================================================== diff -u -r6248 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/Deltares.DamEngine.IntegrationTests.csproj (.../Deltares.DamEngine.IntegrationTests.csproj) (revision 6248) +++ DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/Deltares.DamEngine.IntegrationTests.csproj (.../Deltares.DamEngine.IntegrationTests.csproj) (revision 6300) @@ -137,6 +137,9 @@ PreserveNewest + + PreserveNewest + Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs =================================================================== diff -u -r6264 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (.../OperationalCalculator.cs) (revision 6264) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesOperational/OperationalCalculator.cs (.../OperationalCalculator.cs) (revision 6300) @@ -61,10 +61,14 @@ /// private readonly IDictionary>> values = new Dictionary>>(); + + private readonly IDictionary> waterLevelValues = + new Dictionary>(); private TimeSerieCollection inputTimeSerieCollection; private TimeSerieCollection outputTimeSerieCollection; private string outputParameter; + private bool isCalamity; /// /// Executes operational calculation. @@ -81,32 +85,44 @@ damProjectData.CalculationMessages.Clear(); } + isCalamity = damProjectData.SensorData == null; outputParameter = DetermineOutputParameter(damProjectData.DamProjectCalculationSpecification.CurrentSpecification); // counter to determine if locations are processed var locationCount = 0; inputTimeSerieCollection = damProjectData.Dike.InputTimeSerieCollection; outputTimeSerieCollection = new TimeSerieCollection(); - IEnumerable locations = damProjectData.Dike.Locations.GetBySpecification(new LocationsWithSensorData()); + IEnumerable locations = isCalamity ? damProjectData.Dike.Locations : damProjectData.Dike.Locations.GetBySpecification(new LocationsWithSensorData()); foreach (Location location in locations) { - location.ModelParametersForPlLines.PlLineCreationMethod = PlLineCreationMethod.Sensors; + if (isCalamity) + { + PrepareWaterLevelDataLookup(location); + } + else + { + location.ModelParametersForPlLines.PlLineCreationMethod = PlLineCreationMethod.Sensors; + PrepareSensorDataLookup(location); + } - PrepareSensorDataLookup(location); InitializeOutputSeries(location); locationCount++; } - damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Info, null, - $"There are {locationCount} locations with sensor data")); + if (!isCalamity) + { + damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Info, null, + $"There are {locationCount} locations with sensor data")); + } + if (!locations.Any()) { damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Error, null, "No location to process.")); return; } - // Prepare the designCalculatorTasks + // Prepare the operationalCalculatorTasks var operationalCalculatorTasks = new List(); foreach (TimeSerie series in outputTimeSerieCollection.Series) { @@ -121,9 +137,15 @@ designScenario = location.Scenarios[0]; } - IDictionary sensorValues = values[entry.DateTime][location]; - if (!ContainsMissingValues(sensorValues, series.MissVal)) + var canProcessCalculation = true; + if (!isCalamity) { + IDictionary sensorValues = values[entry.DateTime][location]; + canProcessCalculation = !ContainsMissingValues(sensorValues, series.MissVal); + } + + if (canProcessCalculation) + { FailureMechanismSystemType soilProbabilityFailureMechanismSystemType = damProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType; SoilGeometryProbability soiProfileProbability = location.Segment.GetMostProbableSoilGeometryProbability( ConversionHelper.ConvertToSegmentFailureMechanismType(soilProbabilityFailureMechanismSystemType)); @@ -229,8 +251,8 @@ damKernelInput.SubSoilScenario = soiProfileProbability.Copy(); damKernelInput.TimeStepDateTime = timeSerieEntry.DateTime.Copy(); damKernelInput.DamFailureMechanismeCalculationSpecification = damFailureMechanismCalculationSpecification; - damKernelInput.RiverLevelHigh = Double.NaN; - damKernelInput.RiverLevelLow = null; + damKernelInput.RiverLevelHigh = isCalamity ? waterLevelValues[timeSerieEntry.DateTime][location]: double.NaN; + damKernelInput.RiverLevelLow = isCalamity ? waterLevelValues[timeSerieEntry.DateTime][location] : null; damKernelInput.FilenamePrefix = $"Dik(dike)_Loc({location.Name})_Stp({timeStepIndex})_Mdl({damFailureMechanismCalculationSpecification.StabilityModelType})_{DateToTimeStamp(timeSerieEntry.DateTime)}"; damKernelInput.CurrentEmbankmentSoil = location.GetDikeEmbankmentSoil(); SynchronizeLocationDataWithScenarioData(designScenario, location); @@ -434,7 +456,7 @@ } /// - /// Prepares the output time series and the calculation arguments (sensor data). + /// Prepares the calculation arguments (sensor data). /// /// The location. private void PrepareSensorDataLookup(Location location) @@ -450,7 +472,7 @@ IEnumerable series = inputTimeSerieCollection.GetSeriesByLocationId(sensor.Name); ThrowIfSensorNotExists(sensor, series.Any()); - // Prepare the output time series and set sensor values + // Set sensor values foreach (TimeSerie timeSeries in series) { ThrowIfTimeEntryCountDontMatch(firstSeriesEntries, timeSeries, hasFirstSeriesEntries); @@ -478,7 +500,45 @@ location.SensorLocation.SensorValues = values; // Todo #The: only set sensorvalues to values for this location } + + /// + /// Prepares the water level data. + /// + /// The location. + private void PrepareWaterLevelDataLookup(Location location) + { + // these variable are used to determine differences in time series entries + var firstSeriesEntries = new HashSet(); + var hasFirstSeriesEntries = false; + + IEnumerable series = inputTimeSerieCollection.GetSeriesByLocationId(location.Name); + + // Set sensor values + foreach (TimeSerie timeSeries in series) + { + ThrowIfTimeEntryCountDontMatch(firstSeriesEntries, timeSeries, hasFirstSeriesEntries); + + foreach (TimeSerieEntry entry in timeSeries.Entries) + { + DateTime key = entry.DateTime; + if (hasFirstSeriesEntries) + { + ThrowIfTimeEntriesKeysDontMatch(key, firstSeriesEntries); + } + + if (!hasFirstSeriesEntries) + { + firstSeriesEntries.Add(key); + } + + // everything ok set data into internal lookup + SetWaterLevelValue(key, entry.Value, location); + } + hasFirstSeriesEntries = true; + } + } + /// /// Sets the sensor value. /// @@ -507,7 +567,30 @@ values[timeStep][location].Add(sensor, value); } + + /// + /// Sets the water level value. + /// + /// The time step. + /// The value. + /// The location. + private void SetWaterLevelValue(DateTime timeStep, double value, Location location) + { + if (!waterLevelValues.ContainsKey(timeStep)) + { + waterLevelValues.Add(timeStep, new Dictionary()); + } + if (!waterLevelValues[timeStep].ContainsKey(location)) + { + waterLevelValues[timeStep].Add(location, value); + } + else + { + throw new OperationalCalculatorException(string.Format(Resources.OperationalCalculatorWaterLevelAlreadyExistsInInputTimeSerie, location.Name, timeStep.ToString(CultureInfo.CurrentCulture))); + } + } + /// /// Throws when the sensor not exists. /// @@ -526,7 +609,7 @@ } /// - /// Throws if time entry count dont match. + /// Throws if time entry count don't match. /// /// The first series entries. /// The time series. @@ -610,7 +693,7 @@ } /// - /// Specifies a location with valid sensor data. The objects that are satisfied by the + /// Specifies a location with valid sensor data. The objects that are satisfied by /// the specification (predicate) will be used in this calculator. /// See ReadSensorDataAndPrepareOutputSeries and Locations.GetBySpecification(p) /// Index: DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/Calamity/PulauTekongCalamity.xml =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/Calamity/PulauTekongCalamity.xml (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/Calamity/PulauTekongCalamity.xml (revision 6300) @@ -0,0 +1,1433 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs =================================================================== diff -u -r6133 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 6133) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 6300) @@ -294,6 +294,12 @@ } } + internal static string OperationalCalculatorWaterLevelAlreadyExistsInInputTimeSerie { + get { + return ResourceManager.GetString("OperationalCalculatorWaterLevelAlreadyExistsInInputTimeSerie", resourceCulture); + } + } + internal static string SoilProfileValidator_General { get { return ResourceManager.GetString("SoilProfileValidator_General", resourceCulture); Index: DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/CalamityTests.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/CalamityTests.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/IntegrationTests/CalamityTests.cs (revision 6300) @@ -0,0 +1,79 @@ +// Copyright (C) Stichting Deltares 2024. All rights reserved. +// +// This file is part of the Dam Engine. +// +// The Dam Engine is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero 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.IO; +using Deltares.DamEngine.Io.XmlOutput; +using Deltares.DamEngine.TestHelpers; +using NUnit.Framework; + +namespace Deltares.DamEngine.IntegrationTests.IntegrationTests; + +[TestFixture] +public class CalamityTests +{ + private const double tolerance = 0.00051; + + [Test] + [Category(Categories.Slow)] + public void GivenCalamityInputFile_WhenRun_ThenOutputIsCorrect() + { + const string calcDir = "TestCalamity"; + if (Directory.Exists(calcDir)) + { + Directory.Delete(calcDir, true); + } + string outputFileName = Path.Combine(calcDir, "Output.xml"); + + Directory.CreateDirectory(calcDir); + // Based on "DamUI\trunk\src\Dam\Deltares.Dam.IntegrationTests\TestData\Calamity\PulauTekongCalamity.damx" + const string inputFileName = @"TestFiles\Calamity\PulauTekongCalamity.xml"; + string inputString = File.ReadAllText(inputFileName); + inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used + inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used + + Output output = GeneralHelper.RunAfterInputValidation(inputString, false, outputFileName); + + Assert.That(output.Results.OperationalOutputTimeSeries, Has.Length.EqualTo(5)); + Assert.Multiple(() => + { + Assert.That(output.Results.OperationalOutputTimeSeries[0].LocationId, Is.EqualTo("CD CS1 X1")); + Assert.That(output.Results.OperationalOutputTimeSeries[0].Entries.TimeSerieEntryOutput, Has.Length.EqualTo(3)); + Assert.That(output.Results.OperationalOutputTimeSeries[0].Entries.TimeSerieEntryOutput[0].Value, Is.EqualTo(1.4078).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[0].Entries.TimeSerieEntryOutput[1].Value, Is.EqualTo(1.4083).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[0].Entries.TimeSerieEntryOutput[2].Value, Is.EqualTo(1.4053).Within(tolerance)); + + Assert.That(output.Results.OperationalOutputTimeSeries[1].LocationId, Is.EqualTo("CD CS2 X3")); + Assert.That(output.Results.OperationalOutputTimeSeries[1].Entries.TimeSerieEntryOutput, Has.Length.EqualTo(3)); + Assert.That(output.Results.OperationalOutputTimeSeries[1].Entries.TimeSerieEntryOutput[0].Value, Is.EqualTo(0.9985).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[1].Entries.TimeSerieEntryOutput[1].Value, Is.EqualTo(0.9950).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[1].Entries.TimeSerieEntryOutput[2].Value, Is.EqualTo(0.9891).Within(tolerance)); + + // The following locations were not present in the Water level time series input so no result available + for (int i = 2; i < 5; i++) + { + Assert.That(output.Results.OperationalOutputTimeSeries[i].Entries.TimeSerieEntryOutput, Has.Length.EqualTo(3)); + Assert.That(output.Results.OperationalOutputTimeSeries[i].Entries.TimeSerieEntryOutput[0].Value, Is.EqualTo(double.NaN).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[i].Entries.TimeSerieEntryOutput[1].Value, Is.EqualTo(double.NaN).Within(tolerance)); + Assert.That(output.Results.OperationalOutputTimeSeries[i].Entries.TimeSerieEntryOutput[2].Value, Is.EqualTo(double.NaN).Within(tolerance)); + } + }); + } +} \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/InputForDebugging.xml =================================================================== diff -u -r6197 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/InputForDebugging.xml (.../InputForDebugging.xml) (revision 6197) +++ DamEngine/trunk/src/Deltares.DamEngine.IntegrationTests/TestFiles/InputForDebugging.xml (.../InputForDebugging.xml) (revision 6300) @@ -1,433 +1,1431 @@ - - + + - - - + + + - + - + - - - + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + - - + - + - - - - - - - - - + + + + - + - - - - - - - - - - + + + + + + + + + - + - - - - + + + + - + - - - - + + + + + + + + + - + - - - - - + + + + - + - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx =================================================================== diff -u -r6133 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx (.../Resources.resx) (revision 6133) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx (.../Resources.resx) (revision 6300) @@ -241,6 +241,9 @@ Location '{0}', subsoil scenario '{1}', timestep '{2}', timestamp '{3}': The validation for this calculation failed. + + Value for location {0} and time step {1} already exists. Check the time series data. + No input object defined for Macro Stability Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx =================================================================== diff -u -r6133 -r6300 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 6133) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 6300) @@ -177,6 +177,9 @@ Locatie '{0}', ondergrond profiel '{1}', tijdstap '{2}', tijdstip '{3}': Validatie is gefaald. + + Waarde voor locatie {0} en tijdstap {1} bestaat al. Controleer de tijdreeksgegevens. + Het aanpassen van de helling van het dijkprofiel is mislukt. Waarschijnlijk is de nieuwe helling te steil of te flauw.