// Copyright (C) Stichting Deltares 2017. 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; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard; namespace Deltares.DamEngine.Data.General.Sensors { /// /// Association class for sensor data and a location /// public class SensorLocation { #region Business Rules /// /// Specication to test if the value of the candidate is valid /// // internal class IgnoreOrLocationData : PredicateSpecification // { // public IgnoreOrLocationData() // : base(x => x == DataSourceTypeSensors.Ignore || x == DataSourceTypeSensors.LocationData) // { // Description = "Only Ignore or LocationData value allowed for this property."; // } // } /// /// Specication to test if the value of the candidate is valid /// // internal class SensorOrLocationData : PredicateSpecification // { // public SensorOrLocationData() // : base(x => x == DataSourceTypeSensors.Sensor || x == DataSourceTypeSensors.LocationData) // { // Description = "Only Sensor or LocationData value allowed for this property."; // } // } #endregion /// /// Constructor is needed for XML deserialization /// public SensorLocation() { PL1WaterLevelAtRiver = DataSourceTypeSensors.LocationData; PL1WaterLevelAtPolder = DataSourceTypeSensors.LocationData; } private Group sensorGroup; /// /// Gets the PL line offset below dike top at river. /// public double PLLineOffsetBelowDikeTopAtRiver { get { return Location.PlLineOffsetBelowDikeTopAtRiver; } } /// /// Gets the PL line offset below dike top at polder. /// public double PLLineOffsetBelowDikeTopAtPolder { get { return Location.PLLineOffsetDryBelowDikeTopAtPolder; } } /// /// Gets the PL line offset below dike toe at polder. /// public double PLLineOffsetBelowDikeToeAtPolder { get { return Location.PlLineOffsetBelowDikeToeAtPolder; } } /// /// Gets the PL line offset dry below shoulder base inside. /// public double PLLineOffsetDryBelowShoulderBaseInside { get { return Location.PlLineOffsetBelowShoulderBaseInside; } } /// /// Gets or sets the DAM location. /// /// /// The location. /// // [Specification(typeof(NotNullSpecification))] public Location Location { get; set; } /// /// Gets the location Name. /// /// /// If the Name is empty it could indicate that there is no reference /// to a valid location /// public string LocationName { get { return (Location != null) ? Location.Name : string.Empty; } } /// /// Gets or sets the sensor group. /// /// /// The group. /// // [Specification(typeof(NotNullSpecification))] public Group Group { get { return sensorGroup; } set { sensorGroup = value; } } public void ResetGroupID(int id) { sensorGroup.ID = id; } /// /// Gets the group ID. /// /// /// If the ID has value -1 then the there is no valid reference (null) /// or the group is transient. /// public int GroupID { get { if (sensorGroup == null) return -1; return sensorGroup.ID; } } /// /// Gets the sensor selection. /// public IEnumerable Sensors { get { if (sensorGroup == null) return new Sensor[0]; return sensorGroup.Selection; } } /// /// Gets or sets the PL3 data source type. /// /// /// The PL3. /// // [Specification(typeof(SensorOrLocationData))] public DataSourceTypeSensors PL3 { get; set; } /// /// Gets or sets the PL4 data source type. /// /// /// The PL4. /// // [Specification(typeof(SensorOrLocationData))] public DataSourceTypeSensors PL4 { get; set; } /// /// Gets or sets the outer water level data source type. /// /// /// The outer water level. /// // [Specification(typeof(SensorOrLocationData))] public DataSourceTypeSensors PL1WaterLevelAtRiver { get; set; } /// /// Gets or sets the PL1 PL line offset below dike top at river data source type. /// /// /// Data source type for PL1 PLLine offset below dike top at river. /// // [Specification(typeof(IgnoreOrLocationData))] public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtRiver { get; set; } /// /// Gets or sets the PL1 PL line offset below dike top at polder data source type /// /// /// The PL1 PL line offset below dike top at polder. /// // [Specification(typeof(IgnoreOrLocationData))] public DataSourceTypeSensors PL1PLLineOffsetBelowDikeTopAtPolder { get; set; } /// /// Gets or sets the PL1 PL line offset below shoulder base inside data source type /// /// /// The PL1 PL line offset below shoulder base inside. /// // [Specification(typeof(IgnoreOrLocationData))] public DataSourceTypeSensors PL1PLLineOffsetBelowShoulderBaseInside { get; set; } /// /// Gets or sets the PL1 PL line offset below dike toe at polder data source type. /// /// /// The PL1 PL line offset below dike toe at polder. /// //[Specification(typeof(IgnoreOrLocationData))] public DataSourceTypeSensors PL1PLLineOffsetBelowDikeToeAtPolder { get; set; } /// /// Gets or sets the PL1 polder level data source type. /// /// /// The PL1 polder level. /// //[Specification(typeof(SensorOrLocationData))] public DataSourceTypeSensors PL1WaterLevelAtPolder { get; set; } /// /// Gets the sensor count. /// public int SensorCount { get { return sensorGroup == null ? 0 : Group.SensorCount; } } public SurfaceLine2 SurfaceLine { get { return Location.SurfaceLine2; } } public double RiverLevel { get { return Location.RiverLevel; } } public double PolderLevel { get { return Location.PolderLevel; } } public double? HeadPl3 { get { return Location.HeadPl3; } } public double? HeadPl4 { get { return Location.HeadPl4; } } public string Alias { get; set; } // ToDo Tom/Kin Sun Waarvoor nodig? Wordt nergens gebruikt. Kan gewoon weg!? public string Profile { get; //{ return SoilProfile2D } ; set; } public string MStabFile { get; //{ return SoilProfile2D } ; set; } /// /// Gets the PiezometricHead type sensors sorted by relative location along profile. /// /// Type of the pl line. /// // internal SortedDictionary GetSensorsSortedByRelativeLocationAlongProfile(PLLineType plLineType) // { // var calculatedRelativeLocations = BuildRelativeLocationTable(); // // var table = new SortedDictionary(); // // // leave out the water level and polder level sensors // var candidateSensors = // Sensors.GetBySpecification(new PiezometricHeadSensorSpecification()); // // foreach (var sensor in candidateSensors) // { // if (sensor.PLLineMappings.Contains(plLineType)) // { // double relativeLocation = sensor.RelativeLocationSpecified ? // sensor.RelativeLocation : calculatedRelativeLocations[sensor]; // // if (table.ContainsKey(relativeLocation)) // { // throw new InvalidOperationException( // "Error creating lookup table with sensors sorted by relative location along profile. The x-location " + relativeLocation + " already exists. Sensor " + sensor); // } // // table.Add(relativeLocation, sensor); // } // } // return table; // } ##Bka /// /// Builds the relative location table. /// /// internal IDictionary BuildRelativeLocationTable() { var surfaceLevelOutside = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); if (surfaceLevelOutside == null) throw new InvalidOperationException("No SurfaceLevelOutside point on surface line defined"); double startPoint = surfaceLevelOutside.X; var dict = new Dictionary(); foreach (Sensor sensor in Sensors) { double relativeLocation = startPoint + (Location.XRdDikeLine - sensor.XRd); dict.Add(sensor, relativeLocation); } return dict; } internal static class MemberNames { internal static readonly string OffsetBelowDikeToeAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeToeAtPolder); internal static readonly string OffsetBelowDikeTopAtPolder = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtPolder); internal static readonly string OffsetBelowDikeTopAtRiver = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowDikeTopAtRiver); internal static readonly string OffsetBelowShoulderBaseInside = StaticReflection.GetMemberName(x => x.PL1PLLineOffsetBelowShoulderBaseInside); internal static readonly string WaterLevelAtRiver = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtRiver); internal static readonly string PolderLevel = StaticReflection.GetMemberName(x => x.PL1WaterLevelAtPolder); internal static readonly string PL3 = StaticReflection.GetMemberName(x => x.PL3); internal static readonly string PL4 = StaticReflection.GetMemberName(x => x.PL4); } public double? GetValue(Expression> expression, IDictionary sensorValues, Sensor sensor) { if (sensorValues == null) throw new ArgumentNullException("sensorValues"); if (sensor == null) throw new ArgumentNullException("sensor"); if (!sensorValues.ContainsKey(sensor)) throw new ArgumentException("The given sensor is not an item/key in the table of sensor values"); var memberName = StaticReflection.GetMemberName(expression); if (memberName == MemberNames.OffsetBelowDikeToeAtPolder) { if (PL1PLLineOffsetBelowDikeToeAtPolder == DataSourceTypeSensors.LocationData) return Location.PlLineOffsetBelowDikeToeAtPolder; } if (memberName == MemberNames.OffsetBelowDikeTopAtPolder) { if (PL1PLLineOffsetBelowDikeTopAtPolder == DataSourceTypeSensors.LocationData) return Location.PlLineOffsetBelowDikeTopAtPolder; } if (memberName == MemberNames.OffsetBelowDikeTopAtRiver) { if (PL1PLLineOffsetBelowDikeTopAtRiver == DataSourceTypeSensors.LocationData) return Location.PlLineOffsetBelowDikeTopAtRiver; } if (memberName == MemberNames.OffsetBelowShoulderBaseInside) { if (PL1PLLineOffsetBelowShoulderBaseInside == DataSourceTypeSensors.LocationData) return Location.PlLineOffsetBelowShoulderBaseInside; } if (memberName == MemberNames.WaterLevelAtRiver) { if (PL1WaterLevelAtRiver == DataSourceTypeSensors.LocationData) return Location.RiverLevel; if (PL1WaterLevelAtRiver == DataSourceTypeSensors.Sensor) return sensorValues[sensor]; } if (memberName == MemberNames.PolderLevel) { if (PL1WaterLevelAtPolder == DataSourceTypeSensors.LocationData) return Location.PolderLevel; if (PL1WaterLevelAtPolder == DataSourceTypeSensors.Sensor) return sensorValues[sensor]; } if (memberName == MemberNames.PL3) { if (PL3 == DataSourceTypeSensors.LocationData) return Location.HeadPl3; if (PL3 == DataSourceTypeSensors.Sensor) return sensorValues[sensor]; } if (memberName == MemberNames.PL4) { if (PL4 == DataSourceTypeSensors.LocationData) return Location.HeadPl4; if (PL4 == DataSourceTypeSensors.Sensor) return sensorValues[sensor]; } return null; } /// /// Determines whether this instance is valid. /// /// /// true if this instance is valid; otherwise, false. /// // public bool IsValid() // { // return !Validator.Validate(this).Any(); // } /// /// Gets or sets the GetGroups function (injectable list, for UI purposes). /// /// /// The list of available Groups. /// public static Func> GetGroups { get; set; } } }