Roff: support import of N grid files and 1 grid file with N property files

* Add utility to check is roff file contains grid data

* Import of multiple grid files or 1 grid file with N property files

* Fix build errors for using RifRoffFileTools from Commands
- Move template implementation to cpp-file
- Add roffcpp to link libraries in CMake for Commands

* Improve/fix import of single grid file with N property files

* Fix missing add of roff case Id
This commit is contained in:
Jørgen Herje 2023-04-19 15:52:57 +02:00 committed by GitHub
parent 643ccd67b8
commit 67264da0a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 219 additions and 51 deletions

View File

@ -24,7 +24,6 @@
#include "SummaryPlotCommands/RicNewSummaryCurveFeature.h"
#include "SummaryPlotCommands/RicSummaryPlotFeatureImpl.h"
#include "RiaApplication.h"
#include "RiaGuiApplication.h"
#include "RiaLogging.h"
@ -74,8 +73,8 @@ bool RiaImportEclipseCaseTools::openEclipseCasesFromFile( const QStringList&
bool noDialog,
std::shared_ptr<RifReaderSettings> readerSettings )
{
RiaApplication* app = RiaApplication::instance();
RimProject* project = app->project();
RimProject* project = RimProject::current();
if ( !project ) return false;
// Get list of files to import
RifSummaryCaseRestartSelector selector;
@ -258,8 +257,8 @@ int RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames( const QStringL
{
auto* rimInputReservoir = new RimEclipseInputCase();
RiaApplication* app = RiaApplication::instance();
RimProject* project = app->project();
RimProject* project = RimProject::current();
if ( !project ) return -1;
project->assignCaseIdToCase( rimInputReservoir );
@ -325,8 +324,8 @@ int RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl( const QStr
rimResultReservoir->setCaseInfo( caseName, fileName );
rimResultReservoir->setReaderSettings( readerSettings );
RiaApplication* app = RiaApplication::instance();
RimProject* project = app->project();
RimProject* project = RimProject::current();
if ( !project ) return -1;
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr;
if ( analysisModels == nullptr )
@ -395,8 +394,8 @@ bool RiaImportEclipseCaseTools::addEclipseCases( const QStringList& fileNames, R
std::vector<std::vector<int>> mainCaseGridDimensions;
RimIdenticalGridCaseGroup* gridCaseGroup = nullptr;
RiaApplication* app = RiaApplication::instance();
RimProject* project = app->project();
RimProject* project = RimProject::current();
if ( !project ) return false;
{
QString firstFileName = fileNames[0];
@ -487,27 +486,77 @@ bool RiaImportEclipseCaseTools::addEclipseCases( const QStringList& fileNames, R
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RiaImportEclipseCaseTools::openRoffCaseFromFileNames( const QStringList& fileNames, bool createDefaultView )
std::vector<int> RiaImportEclipseCaseTools::openRoffCasesFromFileNames( const QStringList& fileNames, bool createDefaultView )
{
CAF_ASSERT( !fileNames.empty() );
auto* roffCase = new RimRoffCase();
RimProject* project = RimProject::current();
if ( !project ) return {};
RiaApplication* app = RiaApplication::instance();
RimProject* project = app->project();
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr;
if ( !analysisModels ) return {};
std::vector<int> roffCaseIds;
for ( const auto& fileName : fileNames )
{
auto* roffCase = new RimRoffCase();
project->assignCaseIdToCase( roffCase );
roffCase->setGridFileName( fileName );
bool gridImportSuccess = roffCase->openEclipseGridFile();
if ( !gridImportSuccess )
{
const auto errMsg = "Failed to import grid from file: " + fileName.toStdString();
RiaLogging::error( errMsg.c_str() );
continue;
}
analysisModels->cases.push_back( roffCase );
RimEclipseView* eclipseView = nullptr;
if ( createDefaultView )
{
eclipseView = roffCase->createAndAddReservoirView();
eclipseView->cellResult()->setResultType( RiaDefines::ResultCatType::INPUT_PROPERTY );
if ( RiaGuiApplication::isRunning() )
{
if ( RiuMainWindow::instance() ) RiuMainWindow::instance()->selectAsCurrentItem( eclipseView->cellResult() );
}
eclipseView->loadDataAndUpdate();
}
analysisModels->updateConnectedEditors();
roffCaseIds.push_back( roffCase->caseId() );
}
return roffCaseIds;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimRoffCase* RiaImportEclipseCaseTools::openRoffCaseFromFileName( const QString& fileName, bool createDefaultView )
{
RimProject* project = RimProject::current();
if ( !project ) return nullptr;
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr;
if ( !analysisModels ) return nullptr;
auto* roffCase = new RimRoffCase();
project->assignCaseIdToCase( roffCase );
roffCase->setGridFileName( fileNames[0] );
roffCase->setGridFileName( fileName );
bool gridImportSuccess = roffCase->openEclipseGridFile();
if ( !gridImportSuccess )
{
RiaLogging::error( "Failed to import grid" );
return -1;
const auto errMsg = "Failed to import grid from file: " + fileName.toStdString();
RiaLogging::error( errMsg.c_str() );
return nullptr;
}
RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr;
if ( !analysisModels ) return -1;
analysisModels->cases.push_back( roffCase );
RimEclipseView* eclipseView = nullptr;
@ -527,5 +576,5 @@ int RiaImportEclipseCaseTools::openRoffCaseFromFileNames( const QStringList& fil
analysisModels->updateConnectedEditors();
return roffCase->caseId();
return roffCase;
}

View File

@ -20,11 +20,13 @@
#include <map>
#include <memory>
#include <vector>
class QString;
class QStringList;
class RimIdenticalGridCaseGroup;
class RimRoffCase;
class RifReaderSettings;
//==================================================================================================
@ -50,7 +52,8 @@ public:
static int openEclipseCaseFromFile( const QString& fileName, bool createView, std::shared_ptr<RifReaderSettings> readerSettings = nullptr );
static int openRoffCaseFromFileNames( const QStringList& fileNames, bool createDefaultView );
static std::vector<int> openRoffCasesFromFileNames( const QStringList& fileNames, bool createDefaultView );
static RimRoffCase* openRoffCaseFromFileName( const QString& fileName, bool createDefaultView );
private:
static int openEclipseCaseShowTimeStepFilterImpl( const QString& fileName,

View File

@ -129,6 +129,7 @@ set(LINK_LIBRARIES
qwt
${QT_LIBRARIES}
Eigen3::Eigen
roffcpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE ${LINK_LIBRARIES})

View File

@ -25,6 +25,9 @@
#include "RicImportSummaryCasesFeature.h"
#include "RifRoffFileTools.h"
#include "RimRoffCase.h"
#include "RimSummaryCase.h"
#include "Riu3DMainWindowTools.h"
@ -108,7 +111,7 @@ RicImportGeneralDataFeature::OpenCaseResults
}
if ( !roffFiles.empty() )
{
if ( !openRoffCaseFromFileNames( roffFiles, createDefaultView, results.createdCaseIds ) )
if ( !openRoffFilesFromFileNames( roffFiles, createDefaultView, results.createdCaseIds ) )
{
return OpenCaseResults();
}
@ -366,16 +369,88 @@ bool RicImportGeneralDataFeature::openSummaryCaseFromFileNames( const QStringLis
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicImportGeneralDataFeature::openRoffCaseFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds )
bool RicImportGeneralDataFeature::openRoffFilesFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds )
{
CAF_ASSERT( !fileNames.empty() );
auto generatedCaseId = RiaImportEclipseCaseTools::openRoffCaseFromFileNames( fileNames, createDefaultView );
if ( generatedCaseId >= 0 )
auto numGridCases = static_cast<int>(
std::count_if( fileNames.begin(), fileNames.end(), []( const auto& fileName ) { return RifRoffFileTools::hasGridData( fileName ); } ) );
if ( numGridCases != fileNames.size() && numGridCases != 1 )
{
RiaApplication::instance()->addToRecentFiles( fileNames[0] );
createdCaseIds.push_back( generatedCaseId );
return true;
RiaLogging::error( "Select only grid case files or 1 grid case file with N property files!" );
return false;
}
if ( numGridCases == 1 )
{
// Open single grid case and connected property files
return openRoffCaseAndPropertiesFromFileNames( fileNames, createDefaultView, createdCaseIds );
}
else
{
// Open multiple grid cases
return openRoffCasesFromFileNames( fileNames, createDefaultView, createdCaseIds );
}
return false;
}
//--------------------------------------------------------------------------------------------------
/// Assumes N files containing grid info - each file must be grid case
//--------------------------------------------------------------------------------------------------
bool RicImportGeneralDataFeature::openRoffCasesFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds )
{
CAF_ASSERT( !fileNames.empty() );
const size_t initialNumCases = createdCaseIds.size();
auto generatedCaseIds = RiaImportEclipseCaseTools::openRoffCasesFromFileNames( fileNames, createDefaultView );
CAF_ASSERT( fileNames.size() == static_cast<int>( generatedCaseIds.size() ) && "Expected to create one roff case per file provided" );
for ( int i = 0; i < fileNames.size(); ++i )
{
const auto caseId = generatedCaseIds[static_cast<size_t>( i )];
if ( caseId >= 0 )
{
RiaApplication::instance()->addToRecentFiles( fileNames[i] );
createdCaseIds.push_back( caseId );
}
}
return initialNumCases != createdCaseIds.size();
}
//--------------------------------------------------------------------------------------------------
/// Assuming 1 roff file with grid data and N roff files with property info for respective grid file
//--------------------------------------------------------------------------------------------------
bool RicImportGeneralDataFeature::openRoffCaseAndPropertiesFromFileNames( const QStringList& fileNames,
bool createDefaultView,
std::vector<int>& createdCaseIds )
{
CAF_ASSERT( !fileNames.empty() );
auto gridCaseItr =
std::find_if( fileNames.begin(), fileNames.end(), []( const auto& fileName ) { return RifRoffFileTools::hasGridData( fileName ); } );
if ( gridCaseItr == fileNames.end() )
{
RiaLogging::error( "Provided file names must contain one grid file" );
return false;
}
auto* generatedRoffCase = RiaImportEclipseCaseTools::openRoffCaseFromFileName( *gridCaseItr, createDefaultView );
if ( !generatedRoffCase ) return false;
createdCaseIds.push_back( generatedRoffCase->caseId() );
QStringList propertyFileNames;
for ( auto fileNameItr = fileNames.begin(); fileNameItr != fileNames.end(); ++fileNameItr )
{
if ( fileNameItr == gridCaseItr ) continue;
propertyFileNames.push_back( *fileNameItr );
}
generatedRoffCase->importAsciiInputProperties( propertyFileNames );
return true;
}

View File

@ -76,5 +76,8 @@ protected:
std::shared_ptr<RifReaderSettings> readerSettings );
static bool openInputEclipseCaseFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds );
static bool openSummaryCaseFromFileNames( const QStringList& fileNames, bool doCreateDefaultPlot = true );
static bool openRoffCaseFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds );
static bool openRoffFilesFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds );
static bool openRoffCasesFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds );
static bool openRoffCaseAndPropertiesFromFileNames( const QStringList& fileNames, bool createDefaultView, std::vector<int>& createdCaseIds );
};

View File

@ -42,6 +42,32 @@
using namespace std::chrono;
//--------------------------------------------------------------------------------------------------
/// NOTE: Moved from header file due to compile header when using RifRoffFileTools from
/// ApplicationLibCode/Commands
//--------------------------------------------------------------------------------------------------
template <typename IN, typename OUT>
static void convertToReservoirIndexOrder( int nx, int ny, int nz, const std::vector<IN>& in, std::vector<OUT>& out )
{
CAF_ASSERT( static_cast<size_t>( nx * ny * nz ) == in.size() );
out.resize( in.size(), -1 );
int outIdx = 0;
for ( int k = 0; k < nz; k++ )
{
for ( int j = 0; j < ny; j++ )
{
for ( int i = 0; i < nx; i++ )
{
int inIdx = i * ny * nz + j * nz + ( nz - k - 1 );
out[outIdx] = static_cast<OUT>( in[inIdx] );
outIdx++;
}
}
}
}
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
@ -520,6 +546,37 @@ std::pair<bool, std::map<QString, QString>> RifRoffFileTools::createInputPropert
return std::make_pair( true, keywordMapping );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifRoffFileTools::hasGridData( const QString& filename )
{
// Check if arrayTypes contains grid info
// - Alt 1. Look for tag "cornerLines" and its data with keyword "cornerLines.data" - actual representation of grid data
// - Alt 2. Look for tag "filedata" and its filetype with keyword "filedata.filetype" - should be equal "grid" (not as robust, rather
// look for "cornerLines" which is grid representation)
std::ifstream stream( filename.toStdString(), std::ios::binary );
if ( !stream.good() )
{
RiaLogging::error( "Unable to open roff file" );
return false;
}
roff::Reader reader( stream );
reader.parse();
const std::vector<std::pair<std::string, roff::Token::Kind>> arrayTypes = reader.getNamedArrayTypes();
const std::string cornerLinesDataKeyword = "cornerLines.data";
auto cornerLinesDataItr = std::find_if( arrayTypes.begin(),
arrayTypes.end(),
[&cornerLinesDataKeyword]( const auto& arrayType )
{ return arrayType.first == cornerLinesDataKeyword; } );
return cornerLinesDataItr != arrayTypes.end();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -53,6 +53,8 @@ public:
static std::pair<bool, std::map<QString, QString>> createInputProperties( const QString& fileName, RigEclipseCaseData* eclipseCase );
static bool hasGridData( const QString& filename );
private:
static void interpretSplitenzData( int nz,
float zoffset,
@ -81,26 +83,4 @@ private:
const std::string& keyword,
roff::Token::Kind token,
roff::Reader& reader );
template <typename IN, typename OUT>
static void convertToReservoirIndexOrder( int nx, int ny, int nz, const std::vector<IN>& in, std::vector<OUT>& out )
{
CAF_ASSERT( static_cast<size_t>( nx ) * ny * nz == in.size() );
out.resize( in.size(), -1 );
int outIdx = 0;
for ( int k = 0; k < nz; k++ )
{
for ( int j = 0; j < ny; j++ )
{
for ( int i = 0; i < nx; i++ )
{
int inIdx = i * ny * nz + j * nz + ( nz - k - 1 );
out[outIdx] = static_cast<OUT>( in[inIdx] );
outIdx++;
}
}
}
}
};