///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) Statoil ASA // // ResInsight 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. // // ResInsight 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 at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RifCaseRealizationParametersReader.h" #include "RiaLogging.h" #include "RiaStdStringTools.h" #include "RiaTextStringTools.h" #include "RifFileParseTools.h" #include "RifOpmSummaryTools.h" #include #include #include #include #include #include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationReader::RifCaseRealizationReader( const QString& fileName ) { m_parameters = std::make_shared(); m_fileName = fileName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationReader::~RifCaseRealizationReader() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::shared_ptr RifCaseRealizationReader::parameters() const { return m_parameters; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::shared_ptr RifCaseRealizationReader::createReaderFromFileName( const QString& fileName ) { std::shared_ptr reader; if ( fileName.endsWith( parametersFileName() ) ) { reader = std::make_shared( fileName ); } else if ( fileName.endsWith( runSpecificationFileName() ) ) { reader = std::make_shared( fileName ); } return reader; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RifCaseRealizationReader::parametersFileName() { return "parameters.txt"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RifCaseRealizationReader::runSpecificationFileName() { return "runspecification.xml"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationParametersReader::RifCaseRealizationParametersReader( const QString& fileName ) : RifCaseRealizationReader( fileName ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationParametersReader::~RifCaseRealizationParametersReader() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RifCaseRealizationParametersReader::parse() { QFile file( m_fileName ); if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) return; QTextStream dataStream( &file ); int lineNo = 0; QStringList errors; const auto decimalPoint = RiaStdStringTools::decimalPoint(); while ( !dataStream.atEnd() ) { QString line = dataStream.readLine(); lineNo++; const auto stdLine = line.toStdString(); const auto trimmedLine = RiaStdStringTools::trimString( stdLine ); const auto [name, parameterValue] = RiaStdStringTools::splitAtWhitespace( trimmedLine ); if ( name.empty() || parameterValue.empty() ) { errors << QString( "RifCaseRealizationParametersReader: Invalid file format in line %1" ).arg( lineNo ); continue; } if ( RiaStdStringTools::isNumber( parameterValue, decimalPoint ) ) { double doubleValue = 0.0; if ( RiaStdStringTools::toDouble( parameterValue, doubleValue ) ) { m_parameters->addParameter( QString::fromStdString( std::string( name ) ), doubleValue ); } else { errors << QString( "RifCaseRealizationParametersReader: Invalid number format in line %1" ).arg( lineNo ); } } else { m_parameters->addParameter( QString::fromStdString( std::string( name ) ), QString::fromStdString( std::string( parameterValue ) ) ); } } for ( const auto& s : errors ) { RiaLogging::warning( s.toStdString() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationRunspecificationReader::RifCaseRealizationRunspecificationReader( const QString& fileName ) : RifCaseRealizationReader( fileName ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RifCaseRealizationRunspecificationReader::~RifCaseRealizationRunspecificationReader() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RifCaseRealizationRunspecificationReader::parse() { QFile file( m_fileName ); if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) return; QXmlStreamReader xml( &file ); QStringList errors; QString paramName; while ( !xml.atEnd() ) { xml.readNext(); if ( xml.isStartElement() ) { if ( RiaTextStringTools::isTextEqual( xml.name(), QString( "modifier" ) ) ) { paramName = ""; } if ( RiaTextStringTools::isTextEqual( xml.name(), QString( "id" ) ) ) { paramName = xml.readElementText(); } if ( RiaTextStringTools::isTextEqual( xml.name(), QString( "value" ) ) ) { QString paramStrValue = xml.readElementText(); if ( paramName.isEmpty() ) continue; if ( RiaTextStringTools::isNumber( paramStrValue, QLocale::c().decimalPoint() ) ) { bool parseOk = true; double value = QLocale::c().toDouble( paramStrValue, &parseOk ); if ( parseOk ) { m_parameters->addParameter( paramName, value ); } else { errors << QString( "RifCaseRealizationRunspecificationReader: Invalid number format in line %1" ).arg( xml.lineNumber() ); } } else { m_parameters->addParameter( paramName, paramStrValue ); } } } else if ( xml.isEndElement() ) { if ( RiaTextStringTools::isTextEqual( xml.name(), QString( "modifier" ) ) ) { paramName = ""; } } } for ( const auto& s : errors ) { RiaLogging::warning( s.toStdString() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RifCaseRealizationParametersFileLocator::locate( const QString& modelPath ) { // Chosen to find parameters file for StimPlan ensembles. int MAX_LEVELS_UP = 5; int dirLevel = 0; QDir qdir( modelPath ); const QFileInfo dir( modelPath ); if ( dir.isFile() ) qdir.cdUp(); else if ( !dir.isDir() ) return ""; do { QStringList files = qdir.entryList( QDir::Files | QDir::NoDotAndDotDot ); for ( const QString& file : files ) { if ( QString::compare( file, RifCaseRealizationReader::parametersFileName(), Qt::CaseInsensitive ) == 0 || QString::compare( file, RifCaseRealizationReader::runSpecificationFileName(), Qt::CaseInsensitive ) == 0 ) { return qdir.absoluteFilePath( file ); } } qdir.cdUp(); } while ( dirLevel++ < MAX_LEVELS_UP ); return ""; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RifRmsSeedFileReader::fileName() { return "RMS_SEED_USED"; } //-------------------------------------------------------------------------------------------------- /// Locate the RMS seed file "rms/model/RMS_SEED_USED" relative to one of the parent directories of /// the given model file or folder, i.e. "/realization-N/iter-M/rms/model/RMS_SEED_USED" //-------------------------------------------------------------------------------------------------- QString RifRmsSeedFileReader::locate( const QString& modelPath ) { int MAX_LEVELS_UP = 5; int dirLevel = 0; QDir qdir( modelPath ); const QFileInfo dir( modelPath ); if ( dir.isFile() ) qdir.cdUp(); else if ( !dir.isDir() ) return ""; do { QString candidate = qdir.absoluteFilePath( "rms/model/" + fileName() ); if ( QFileInfo::exists( candidate ) ) return candidate; qdir.cdUp(); } while ( dirLevel++ < MAX_LEVELS_UP ); return ""; } //-------------------------------------------------------------------------------------------------- /// Read the RMS seed value from the last token of the last non-empty line, allowing the value to be /// preceded by a timestamp or other text: "25-07-2025 10:33:06 ... 81472369" //-------------------------------------------------------------------------------------------------- std::optional RifRmsSeedFileReader::readSeedValue( const QString& filePath ) { QFile file( filePath ); if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) return std::nullopt; QTextStream dataStream( &file ); QString lastNonEmptyLine; while ( !dataStream.atEnd() ) { QString line = dataStream.readLine().trimmed(); if ( !line.isEmpty() ) lastNonEmptyLine = line; } if ( lastNonEmptyLine.isEmpty() ) return std::nullopt; const QStringList tokens = RiaTextStringTools::splitSkipEmptyParts( lastNonEmptyLine, QRegularExpression( "\\s+" ) ); if ( tokens.isEmpty() ) return std::nullopt; const auto valueText = tokens.back().toStdString(); if ( !RiaStdStringTools::isNumber( valueText, RiaStdStringTools::decimalPoint() ) ) return std::nullopt; double value = 0.0; if ( !RiaStdStringTools::toDouble( valueText, value ) ) return std::nullopt; return value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RifCaseRealizationParametersFileLocator::realizationNumber( const QString& modelPath ) { QDir dir( modelPath ); QString absolutePath = dir.absolutePath(); auto realizationNumber = RifOpmSummaryTools::extractRealizationNumber( absolutePath ); if ( realizationNumber.has_value() ) { return realizationNumber.value(); } return -1; }