// Copyright (C) Stichting Deltares 2017. 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.Data; using System.Data.SQLite; using Core.Common.Base.IO; using Core.Common.IO.Readers; using Core.Common.Utils.Builders; using Ringtoets.Common.IO.Exceptions; using Ringtoets.Common.IO.Properties; using Ringtoets.Common.IO.SoilProfile.Schema; namespace Ringtoets.Common.IO.SoilProfile { /// /// This class reads a D-Soil Model file and reads stochastic soil model from this database. /// public class StochasticSoilModelReader : SqLiteDatabaseReaderBase { private readonly Dictionary soilProfile1Ds = new Dictionary(); private readonly Dictionary soilProfile2Ds = new Dictionary(); private IDataReader dataReader; private SegmentPointReader segmentPointReader; private long currentStochasticSoilModelId = -1; /// /// Creates a new instance of /// which will use the as its source. /// /// The path of the database file to open. /// Thrown when: /// /// The contains invalid characters; /// No file could be found at . /// /// public StochasticSoilModelReader(string databaseFilePath) : base(databaseFilePath) {} /// /// Gets a value indicating whether or not more stochastic soil models can be read using /// the . /// public bool HasNext { get; private set; } /// /// Gets the amount of that can be read from the database. /// public int StochasticSoilModelCount { get; private set; } /// /// Validates the database. /// /// Thrown when: /// /// The database version could not be read; /// The database version is incorrect; /// Required information for constraint evaluation could not be read; /// The database segment names are not unique; /// The query to fetch stochastic soil models from the database failed. /// /// public void Validate() { VerifyVersion(Path); VerifyConstraints(Path); InitializeReaders(); InitializeLookups(); } /// /// Reads the information for the next stochastic soil model from the database and creates a /// instance of the information. /// /// The next from the database, or null /// if no more soil models can be read. /// Thrown when the database returned incorrect /// values for required properties. /// Thrown when: /// /// No stochastic soil profiles could be read; /// The read failure mechanism type is not supported. /// /// public StochasticSoilModel ReadStochasticSoilModel() { try { return TryReadStochasticSoilModel(); } catch (SystemException exception) when (exception is FormatException || exception is OverflowException || exception is InvalidCastException) { string message = new FileReaderErrorMessageBuilder(Path).Build(Resources.StochasticSoilProfileDatabaseReader_StochasticSoilProfile_has_invalid_value); throw new CriticalFileReadException(message, exception); } } public void MoveNext() { HasNext = MoveNext(dataReader); } protected override void Dispose(bool disposing) { if (dataReader != null) { dataReader.Close(); dataReader.Dispose(); dataReader = null; } if (segmentPointReader != null) { segmentPointReader.Dispose(); segmentPointReader = null; } base.Dispose(disposing); } private void InitializeLookups() { using (var soilProfile1DReader = new SoilProfile1DReader(Path)) { soilProfile1DReader.Initialize(); while (soilProfile1DReader.HasNext) { try { SoilProfile1D soilProfile1D = soilProfile1DReader.ReadSoilProfile(); long soilProfileId = soilProfile1D.Id; if (!soilProfile1Ds.ContainsKey(soilProfileId)) { soilProfile1Ds.Add(soilProfileId, soilProfile1D); } } catch (SoilProfileReadException) { soilProfile1DReader.MoveNext(); } } } using (var soilProfile2DReader = new SoilProfile2DReader(Path)) { soilProfile2DReader.Initialize(); while (soilProfile2DReader.HasNext) { try { SoilProfile2D soilProfile2D = soilProfile2DReader.ReadSoilProfile(); long soilProfileId = soilProfile2D.Id; if (!soilProfile2Ds.ContainsKey(soilProfileId)) { soilProfile2Ds.Add(soilProfileId, soilProfile2D); } } catch (SoilProfileReadException) { soilProfile2DReader.MoveNext(); } } } } /// /// Creates a new from the data reader. /// /// The next from the database, or null /// if no more soil models can be read. /// Thrown when: /// /// No stochastic soil profiles could be read; /// The geometry could not be read; /// The read failure mechanism type is not supported. /// /// private StochasticSoilModel TryReadStochasticSoilModel() { if (!HasNext) { return null; } StochasticSoilModel stochasticSoilModel = CreateStochasticSoilModel(); currentStochasticSoilModelId = ReadStochasticSoilModelId(); SetGeometry(stochasticSoilModel); SetStochasticSoilProfiles(stochasticSoilModel); return stochasticSoilModel; } /// /// Sets objects that belong to soil model. /// /// The stochastic soil model of which the profiles to set. /// Thrown when: /// /// No stochastic soil profiles could be read; /// The read failure mechanism type is not supported. /// /// private void SetStochasticSoilProfiles(StochasticSoilModel stochasticSoilModel) { if (MoveToStochasticSoilModel(currentStochasticSoilModelId)) { stochasticSoilModel.StochasticSoilProfiles.AddRange(ReadStochasticSoilProfiles()); } } /// /// Sets the geometry points of from the database. /// /// The stochastic soil model of which the geometry to set. /// Thrown when the geometry could not be read. private void SetGeometry(StochasticSoilModel stochasticSoilModel) { if (!segmentPointReader.MoveToStochasticSoilModel(currentStochasticSoilModelId)) { throw new StochasticSoilModelException( string.Format(Resources.SegmentPointReader_ReadSegmentPoint_StochasticSoilModel_0_must_contain_geometry, ReadStochasticSoilModelName())); } stochasticSoilModel.Geometry.AddRange(segmentPointReader.ReadSegmentPoints()); } /// /// Moves the reader to the stochastic soil model with id . /// /// The id of the stochastic soil model. /// true if the reader was moved to the stochastic soil model with id /// successfully, false otherwise. private bool MoveToStochasticSoilModel(long stochasticSoilModelId) { while (HasNext && ReadStochasticSoilModelId() <= stochasticSoilModelId) { if (ReadStochasticSoilModelId() == stochasticSoilModelId) { currentStochasticSoilModelId = stochasticSoilModelId; return true; } MoveNext(); } return false; } /// /// Reads and returns objects that belong to soil model. /// /// The read stochastic soil profiles. /// Thrown when: /// /// No stochastic soil profiles could be read; /// The read failure mechanism type is not supported. /// /// private IEnumerable ReadStochasticSoilProfiles() { while (HasNext && ReadStochasticSoilModelId() == currentStochasticSoilModelId) { double? probability = ReadStochasticSoilProfileProbability(); if (!probability.HasValue) { string soilModelName = ReadStochasticSoilModelName(); throw new StochasticSoilModelException( string.Format(Resources.StochasticSoilModelReader_ReadStochasticSoilProfiles_No_profiles_found_in_stochastic_soil_model_Name_0_, soilModelName)); } long? soilProfile1D = ReadSoilProfile1DId(); long? soilProfile2D = ReadSoilProfile2DId(); if (soilProfile1D.HasValue && soilProfile1Ds.ContainsKey(soilProfile1D.Value)) { yield return new StochasticSoilProfile(probability.Value, soilProfile1Ds[soilProfile1D.Value]); } else if (soilProfile2D.HasValue && soilProfile2Ds.ContainsKey(soilProfile2D.Value)) { yield return new StochasticSoilProfile(probability.Value, soilProfile2Ds[soilProfile2D.Value]); } MoveNext(); } } /// /// Creates a new basic , based on the data read from the data reader. /// /// The newly created . /// Thrown when the read failure mechanism /// type is not supported. private StochasticSoilModel CreateStochasticSoilModel() { return new StochasticSoilModel(ReadStochasticSoilModelName(), ReadFailureMechanismType()); } /// /// Initializes a new . /// /// Thrown when failed to fetch stochastic soil models from the database. private void InitializeReaders() { CreateDataReader(); MoveNext(); segmentPointReader = new SegmentPointReader(Path); segmentPointReader.Initialize(); } /// /// Creates a new . /// /// Thrown when query to fetch stochastic soil /// models from the database failed. private void CreateDataReader() { string stochasticSoilModelCount = SoilDatabaseQueryBuilder.GetStochasticSoilModelOfMechanismCountQuery(); string stochasticSoilModelSegmentsQuery = SoilDatabaseQueryBuilder.GetStochasticSoilModelPerMechanismQuery(); try { dataReader = CreateDataReader(stochasticSoilModelCount + stochasticSoilModelSegmentsQuery); } catch (SQLiteException exception) { string message = new FileReaderErrorMessageBuilder(Path).Build(Resources.StochasticSoilModelDatabaseReader_Failed_to_read_database); throw new CriticalFileReadException(message, exception); } StochasticSoilModelCount = ReadStochasticSoilModelCount(); dataReader.NextResult(); } /// /// Verifies that the database at has the required version. /// /// The path of the database file to open. /// Thrown when: /// /// The database version could not be read; /// The database version is incorrect. /// /// private static void VerifyVersion(string databaseFilePath) { using (var reader = new SoilDatabaseVersionReader(databaseFilePath)) { reader.VerifyVersion(); } } /// /// Verifies that the database at meets required constraints. /// /// The path of the database file to open. /// Thrown when: /// /// Required information for constraint evaluation could not be read; /// The database segment names are not unique. /// /// private static void VerifyConstraints(string databaseFilePath) { using (var reader = new SoilDatabaseConstraintsReader(databaseFilePath)) { reader.VerifyConstraints(); } } #region Read columns /// /// Reads the stochastic soil profile probability from the data reader. /// /// The 1D soil profile id. /// The read value is not in an appropriate format. /// The read value represents a number that is less /// than or greater than . private double? ReadStochasticSoilProfileProbability() { object probability = dataReader[StochasticSoilProfileTableDefinitions.Probability]; return probability == Convert.DBNull ? (double?) null : Convert.ToDouble(probability); } /// /// Reads the 1D soil profile id from the data reader. /// /// The 1D soil profile id. /// The read value is not in an appropriate format. /// The read value represents a number that is less /// than or greater than . private long? ReadSoilProfile1DId() { object soilProfileId = dataReader[StochasticSoilProfileTableDefinitions.SoilProfile1DId]; return soilProfileId == Convert.DBNull ? (long?) null : Convert.ToInt64(soilProfileId); } /// /// Reads the 2D soil profile id from the data reader. /// /// The 2D soil profile id. /// The read value is not in an appropriate format. /// The read value represents a number that is less /// than or greater than . private long? ReadSoilProfile2DId() { object soilProfileId = dataReader[StochasticSoilProfileTableDefinitions.SoilProfile2DId]; return soilProfileId == Convert.DBNull ? (long?) null : Convert.ToInt64(soilProfileId); } private int ReadStochasticSoilModelCount() { return !dataReader.Read() ? 0 : Convert.ToInt32(dataReader[StochasticSoilModelTableDefinitions.Count]); } /// /// Reads the stochastic soil model id from the data reader. /// /// The stochastic soil model id. /// The read value is not in an appropriate format. /// The read value represents a number that is less /// than or greater than . private long ReadStochasticSoilModelId() { return Convert.ToInt64(dataReader[StochasticSoilModelTableDefinitions.StochasticSoilModelId]); } private string ReadStochasticSoilModelName() { return Convert.ToString(dataReader[StochasticSoilModelTableDefinitions.StochasticSoilModelName]); } private string ReadMechanismName() { return Convert.ToString(dataReader[MechanismTableDefinitions.MechanismName]); } /// /// Reads the failure mechanism type from the data reader. /// /// The failure mechanism type. /// Thrown when the read failure mechanism type is not supported. private FailureMechanismType ReadFailureMechanismType() { long mechanismId = Convert.ToInt64(dataReader[MechanismTableDefinitions.MechanismId]); if (Enum.IsDefined(typeof(FailureMechanismType), mechanismId)) { return (FailureMechanismType) mechanismId; } string message = string.Format(Resources.StochasticSoilModelReader_ReadFailureMechanismType_Failure_mechanism_0_not_supported, ReadMechanismName()); throw new StochasticSoilModelException(message); } #endregion } }