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) ///