Index: DamClients/DamUI/trunk/src/Dam/Forms/DamContext.cs =================================================================== diff -u -r6776 -r6811 --- DamClients/DamUI/trunk/src/Dam/Forms/DamContext.cs (.../DamContext.cs) (revision 6776) +++ DamClients/DamUI/trunk/src/Dam/Forms/DamContext.cs (.../DamContext.cs) (revision 6811) @@ -49,22 +49,6 @@ public bool Wti { get; set; } = true; /// - /// Returns a flag to indicate that this property must be validated - /// - /// The source - /// The member - /// the flag - public override bool? ShouldValidate(object source, string member) - { - if (source is DamSoil soil) - { - return ShouldValidateSoil(member, soil); - } - - return base.ShouldValidate(source, member); - } - - /// /// Method indicating a visibility override value for a given instance object. /// /// Object being evaluated. @@ -289,24 +273,6 @@ return base.GetFormat(type, source, member); } - private static bool ShouldValidateSoil(string member, DamSoil soil) - { - if (member == StaticReflection.GetMemberName(s => s.POP) || - member == StaticReflection.GetMemberName(s => s.RatioCuPc) || - member == StaticReflection.GetMemberName(s => s.StrengthIncreaseExponent)) - { - return soil.ShearStrengthModel == ShearStrengthModel.CuCalculated; - } - - if (member == StaticReflection.GetMemberName(s => s.Cohesion) || - member == StaticReflection.GetMemberName(s => s.FrictionAngle)) - { - return soil.ShearStrengthModel == ShearStrengthModel.CPhi; - } - - return true; - } - private bool? VisibleAccordingSoilUserFilter(string member) { if (alwaysVisibleProperties.Contains(member)) Index: DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/DamProjectData.cs =================================================================== diff -u -r6793 -r6811 --- DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/DamProjectData.cs (.../DamProjectData.cs) (revision 6793) +++ DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/DamProjectData.cs (.../DamProjectData.cs) (revision 6811) @@ -27,6 +27,7 @@ using System.Xml.Serialization; using Deltares.Dam.Data.IO; using Deltares.Dam.Data.Sensors; +using Deltares.Geotechnics.Soils; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; @@ -323,32 +324,6 @@ } } - /// - /// Updates the design calculations. - /// - private void UpdateDesignCalculations() - { - if (designCalculations == null) - { - designCalculations = new List(); - } - else - { - designCalculations.Clear(); - } - - List scenarios = CreateScenarioListForCalculation(); - foreach (Scenario scenario in scenarios) - { - if (scenario.CalculationResults != null && scenario.CalculationResults.Count > 0) - { - designCalculations.AddRange(scenario.CalculationResults); - } - } - - DataEventPublisher.DataListModified(designCalculations); - } - public LocationJob GetFirstLocationJobWithDesignResults() { foreach (LocationJob locationJob in LocationJobs) @@ -426,10 +401,10 @@ this) }; } - + return []; } - + public bool HasResults() { bool hasResults = waterBoard.Dikes.Count > 0 && waterBoardJob != null && waterBoardJob.Jobs.Count > 0; @@ -460,6 +435,52 @@ return new ValidationResult[0]; } + /// + /// The validation of the DAM soil materials depends on the failure mechanism type, that's why it is performed here + /// instead of just using the [Validate] attribute at the Dike.DamSoils property. + /// + /// A list of validation results. + [Validate] + public ValidationResult[] ValidateDamSoils() + { + var validationResults = new List(); + if (WaterBoard != null && WaterBoard.Dikes.Count > 0) + { + foreach (DamSoil damSoil in WaterBoard.Dikes[0].DamSoils) + { + validationResults.AddRange(Validator.ValidateProperty(damSoil, "AbovePhreaticLevel", "DamSoil")); + validationResults.AddRange(Validator.ValidateProperty(damSoil, "BelowPhreaticLevel", "DamSoil")); + + if (DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType == FailureMechanismSystemType.Piping) + { + validationResults.AddRange(Validator.ValidateProperty(damSoil, "DiameterD70", "DamSoil")); + validationResults.AddRange(Validator.ValidateProperty(damSoil, "PermeabKx", "DamSoil")); + } + + if (DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType is + FailureMechanismSystemType.StabilityOutside or FailureMechanismSystemType.StabilityInside) + { + switch (damSoil.ShearStrengthModel) + { + case ShearStrengthModel.CPhi: + validationResults.AddRange(Validator.ValidateProperty(damSoil, "Cohesion", "DamSoil")); + validationResults.AddRange(Validator.ValidateProperty(damSoil, "FrictionAngle", "DamSoil")); + break; + case ShearStrengthModel.CuCalculated: + validationResults.AddRange(Validator.ValidateProperty(damSoil, "RatioCuPc", "DamSoil")); + validationResults.AddRange(Validator.ValidateProperty(damSoil, "POP", "DamSoil")); + validationResults.AddRange(Validator.ValidateProperty(damSoil, "StrengthIncreaseExponent", "DamSoil")); + break; + } + + validationResults.AddRange(Validator.ValidateProperty(damSoil, "TrafficLoadDegreeOfConsolidation", "DamSoil")); + } + } + } + + return validationResults.ToArray(); + } + public void FillOverallSensorData() { if (SensorData != null) @@ -529,6 +550,32 @@ } } + /// + /// Updates the design calculations. + /// + private void UpdateDesignCalculations() + { + if (designCalculations == null) + { + designCalculations = new List(); + } + else + { + designCalculations.Clear(); + } + + List scenarios = CreateScenarioListForCalculation(); + foreach (Scenario scenario in scenarios) + { + if (scenario.CalculationResults != null && scenario.CalculationResults.Count > 0) + { + designCalculations.AddRange(scenario.CalculationResults); + } + } + + DataEventPublisher.DataListModified(designCalculations); + } + private List CreateScenarioListForDeletion() { var scenarios = new List(); @@ -577,6 +624,7 @@ break; } } + numberOfCalculatedJobs++; } } Index: DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data.Tests/DamProjectDataTests.cs =================================================================== diff -u --- DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data.Tests/DamProjectDataTests.cs (revision 0) +++ DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data.Tests/DamProjectDataTests.cs (revision 6811) @@ -0,0 +1,202 @@ +// Copyright (C) Stichting Deltares 2025. All rights reserved. +// +// This file is part of the application DAM - UI. +// +// DAM - UI 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.Linq; +using Deltares.Geotechnics.Soils; +using Deltares.Standard.Validation; +using NUnit.Framework; + +namespace Deltares.Dam.Data.Tests; + +[TestFixture] +public class DamProjectDataTests +{ + [Test] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CPhi, 5)] // GammaDry, GammaWet, Doc, Cohesion, Phi + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CuCalculated, 5)] // GammaDry, GammaWet, Doc, Cu/Pc, POP + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.StressTable, 3)] // GammaDry, GammaWet, Doc + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.SuTable, 3)] // GammaDry, GammaWet, Doc + [TestCase(FailureMechanismSystemType.StabilityOutside, ShearStrengthModel.CPhi, 5)] // GammaDry, GammaWet, Doc, Cohesion, Phi + [TestCase(FailureMechanismSystemType.Piping, ShearStrengthModel.None, 4)] // GammaDry, GammaWet, D70, permeability + public void GivenInvalidDamSoilOutsideValidRange_WhenValidating_ThenValidationErrorsAreReturnedOnlyForTheParametersUsed(FailureMechanismSystemType failureMechanismSystemType, ShearStrengthModel shearStrengthModel, int expectedErrorsCount) + { + DamSoil soil = CreateInvalidDamSoilWithParametersOutsideValidRange(); + soil.ShearStrengthModel = shearStrengthModel; + var damProjectData = new DamProjectData(); + damProjectData.WaterBoard = new WaterBoard(); + damProjectData.WaterBoard.Dikes.Add(new Dike()); + damProjectData.WaterBoard.Dikes[0].DamSoils.Add(soil); + var damCalculationSpecification = new DamFailureMechanismeCalculationSpecification + { + FailureMechanismSystemType = failureMechanismSystemType + }; + damProjectData.DamProjectCalculationSpecification = new DamProjectCalculationSpecification(); + damProjectData.DamProjectCalculationSpecification.CurrentSpecification = damCalculationSpecification; + + ValidationResult[] validationResults = damProjectData.ValidateDamSoils(); + + bool isPiping = failureMechanismSystemType == FailureMechanismSystemType.Piping; + bool isStability = failureMechanismSystemType is FailureMechanismSystemType.StabilityInside or FailureMechanismSystemType.StabilityOutside; + bool isMohrCoulomb = soil.ShearStrengthModel == ShearStrengthModel.CPhi; + bool isShansep = soil.ShearStrengthModel == ShearStrengthModel.CuCalculated; + + Assert.That(validationResults, Has.Length.EqualTo(expectedErrorsCount)); + Assert.Multiple(() => + { + Assert.That(validationResults.Any(v => v.Text.Contains("Unsaturated unit weight")), Is.True); + Assert.That(validationResults.Any(v => v.Text.Contains("Saturated unit weight")), Is.True); + Assert.That(validationResults.Any(v => v.Text.Contains("Traffic load degree of consolidation")), Is.EqualTo(isStability)); + Assert.That(validationResults.Any(v => v.Text.Contains("Cohesion")), Is.EqualTo(isStability && isMohrCoulomb)); + Assert.That(validationResults.Any(v => v.Text.Contains("Friction")), Is.EqualTo(isStability && isMohrCoulomb)); + Assert.That(validationResults.Any(v => v.Text.Contains("Ratio Su/Pc")), Is.EqualTo(isStability && isShansep)); + Assert.That(validationResults.Any(v => v.Text.Contains("Strength increase exp (m)")), Is.EqualTo(false)); // Exponent m has no valid range defined + Assert.That(validationResults.Any(v => v.Text.Contains("POP")), Is.EqualTo(isStability && isShansep)); + Assert.That(validationResults.Any(v => v.Text.Contains("Diameter D70")), Is.EqualTo(isPiping)); + Assert.That(validationResults.Any(v => v.Text.Contains("Permeability")), Is.EqualTo(isPiping)); + }); + } + + [Test] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CPhi, 4)] // GammaDry, GammaWet, Cohesion, Phi + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CuCalculated, 5)] // GammaDry, GammaWet, Cu/Pc, POP, m + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.StressTable, 2)] // GammaDry, GammaWet, + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.SuTable, 2)] // GammaDry, GammaWet + [TestCase(FailureMechanismSystemType.StabilityOutside, ShearStrengthModel.CPhi, 4)] // GammaDry, GammaWet, Cohesion, Phi + [TestCase(FailureMechanismSystemType.Piping, ShearStrengthModel.None, 4)] // GammaDry, GammaWet, D70, permeability + public void GivenInvalidDamSoilWithEmptyValues_WhenValidating_ThenValidationErrorsAreReturnedOnlyForTheParametersUsed(FailureMechanismSystemType failureMechanismSystemType, ShearStrengthModel shearStrengthModel, int expectedErrorsCount) + { + DamSoil soil = CreateInvalidDamSoilWithEmptyParameters(); + soil.ShearStrengthModel = shearStrengthModel; + var damProjectData = new DamProjectData(); + damProjectData.WaterBoard = new WaterBoard(); + damProjectData.WaterBoard.Dikes.Add(new Dike()); + damProjectData.WaterBoard.Dikes[0].DamSoils.Add(soil); + var damCalculationSpecification = new DamFailureMechanismeCalculationSpecification + { + FailureMechanismSystemType = failureMechanismSystemType + }; + damProjectData.DamProjectCalculationSpecification = new DamProjectCalculationSpecification(); + damProjectData.DamProjectCalculationSpecification.CurrentSpecification = damCalculationSpecification; + + ValidationResult[] validationResults = damProjectData.ValidateDamSoils(); + + bool isPiping = failureMechanismSystemType == FailureMechanismSystemType.Piping; + bool isStability = failureMechanismSystemType is FailureMechanismSystemType.StabilityInside or FailureMechanismSystemType.StabilityOutside; + bool isMohrCoulomb = soil.ShearStrengthModel == ShearStrengthModel.CPhi; + bool isShansep = soil.ShearStrengthModel == ShearStrengthModel.CuCalculated; + + Assert.That(validationResults, Has.Length.EqualTo(expectedErrorsCount)); + Assert.Multiple(() => + { + Assert.That(validationResults.Any(v => v.Text.Contains("Unsaturated unit weight")), Is.True); + Assert.That(validationResults.Any(v => v.Text.Contains("Saturated unit weight")), Is.True); + Assert.That(validationResults.Any(v => v.Text.Contains("Traffic load degree of consolidation")), Is.EqualTo(false)); // DoC can be empty + Assert.That(validationResults.Any(v => v.Text.Contains("Cohesion")), Is.EqualTo(isStability && isMohrCoulomb)); + Assert.That(validationResults.Any(v => v.Text.Contains("Friction")), Is.EqualTo(isStability && isMohrCoulomb)); + Assert.That(validationResults.Any(v => v.Text.Contains("Ratio Su/Pc")), Is.EqualTo(isStability && isShansep)); + Assert.That(validationResults.Any(v => v.Text.Contains("Strength increase exp (m)")), Is.EqualTo(isStability && isShansep)); + Assert.That(validationResults.Any(v => v.Text.Contains("POP")), Is.EqualTo(isStability && isShansep)); + Assert.That(validationResults.Any(v => v.Text.Contains("Diameter D70")), Is.EqualTo(isPiping)); + Assert.That(validationResults.Any(v => v.Text.Contains("Permeability")), Is.EqualTo(isPiping)); + }); + } + + [Test] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CPhi)] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.CuCalculated)] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.StressTable)] + [TestCase(FailureMechanismSystemType.StabilityInside, ShearStrengthModel.SuTable)] + [TestCase(FailureMechanismSystemType.StabilityOutside, ShearStrengthModel.CPhi)] + [TestCase(FailureMechanismSystemType.Piping, ShearStrengthModel.None)] + public void GivenValidDamSoilList_WhenValidating_ThenNoValidationErrorsAreReturned(FailureMechanismSystemType failureMechanismSystemType, ShearStrengthModel shearStrengthModel) + { + DamSoil soil = CreateValidDamSoil(); + soil.ShearStrengthModel = shearStrengthModel; + var damProjectData = new DamProjectData(); + damProjectData.WaterBoard = new WaterBoard(); + damProjectData.WaterBoard.Dikes.Add(new Dike()); + damProjectData.WaterBoard.Dikes[0].DamSoils.Add(soil); + var damCalculationSpecification = new DamFailureMechanismeCalculationSpecification + { + FailureMechanismSystemType = failureMechanismSystemType + }; + damProjectData.DamProjectCalculationSpecification = new DamProjectCalculationSpecification(); + damProjectData.DamProjectCalculationSpecification.CurrentSpecification = damCalculationSpecification; + + ValidationResult[] validationResults = damProjectData.ValidateDamSoils(); + + Assert.That(validationResults, Has.Length.EqualTo(0)); + } + + private static DamSoil CreateValidDamSoil() + { + var damSoil = new DamSoil(); + damSoil.AbovePhreaticLevel = 17; + damSoil.BelowPhreaticLevel = 15; + damSoil.DiameterD70 = 0.006; + damSoil.PermeabKx = 2.5e-5; + damSoil.Cohesion = 2.5; + damSoil.FrictionAngle = 30; + damSoil.RatioCuPc = 0.2; + damSoil.StrengthIncreaseExponent = 0.5; + damSoil.POP = 25; + damSoil.TrafficLoadDegreeOfConsolidation = 0.2; + damSoil.UseDefaultShearStrengthModel = false; + + return damSoil; + } + + private static DamSoil CreateInvalidDamSoilWithParametersOutsideValidRange() + { + var damSoil = new DamSoil(); + damSoil.AbovePhreaticLevel = -17; + damSoil.BelowPhreaticLevel = -15; + damSoil.DiameterD70 = -0.006; + damSoil.PermeabKx = -2.5e-5; + damSoil.Cohesion = -2.5; + damSoil.FrictionAngle = -30; + damSoil.RatioCuPc = -0.2; + damSoil.StrengthIncreaseExponent = -0.5; // Exponent m has no valid range defined + damSoil.POP = -25; + damSoil.TrafficLoadDegreeOfConsolidation = -0.2; + damSoil.UseDefaultShearStrengthModel = false; + + return damSoil; + } + + private static DamSoil CreateInvalidDamSoilWithEmptyParameters() + { + var damSoil = new DamSoil(); + damSoil.AbovePhreaticLevel = double.NaN; + damSoil.BelowPhreaticLevel = double.NaN; + damSoil.DiameterD70 = double.NaN; + damSoil.PermeabKx = double.NaN; + damSoil.Cohesion = double.NaN; + damSoil.FrictionAngle = double.NaN; + damSoil.RatioCuPc = double.NaN; + damSoil.StrengthIncreaseExponent = double.NaN; + damSoil.POP = double.NaN; + damSoil.TrafficLoadDegreeOfConsolidation = -double.NaN; + damSoil.UseDefaultShearStrengthModel = false; + + return damSoil; + } +} \ No newline at end of file Index: DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Dike.cs =================================================================== diff -u -r6793 -r6811 --- DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Dike.cs (.../Dike.cs) (revision 6793) +++ DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Dike.cs (.../Dike.cs) (revision 6811) @@ -98,7 +98,6 @@ set => soilList = value; } - [Validate] public virtual List DamSoils { get => damSoils;