From 8f5beb88510990fa6cb9fa13a3576318a9787d6f Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 6 Sep 2021 09:32:24 +0200 Subject: [PATCH] #7928 Add user interface for exporting multiple well logs. --- .../Commands/CMakeLists_files.cmake | 4 + .../RicCreateEnsembleWellLogFeature.cpp | 281 ++++++++++++++++++ .../RicCreateEnsembleWellLogFeature.h | 44 +++ .../Commands/RicCreateEnsembleWellLogUi.cpp | 231 ++++++++++++++ .../Commands/RicCreateEnsembleWellLogUi.h | 68 +++++ .../RicImportEnsembleWellLogsFeature.cpp | 21 +- .../RicImportEnsembleWellLogsFeature.h | 4 + .../WellPathCommands/RicImportWellPaths.h | 5 +- .../RimContextCommandBuilder.cpp | 1 + .../ProjectDataModel/RimDialogData.cpp | 12 + .../ProjectDataModel/RimDialogData.h | 3 + .../WellLog/RimEnsembleWellLogCurveSet.cpp | 17 ++ .../WellLog/RimEnsembleWellLogCurveSet.h | 3 + .../RimcWellLogPlot.cpp | 17 +- .../RimcWellLogPlot.h | 6 + .../RimcWellLogPlotCollection.cpp | 30 +- .../RimcWellLogPlotCollection.h | 4 + .../RimcWellLogTrack.cpp | 64 ++-- .../RimcWellLogTrack.h | 10 + 19 files changed, 782 insertions(+), 43 deletions(-) create mode 100644 ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.cpp create mode 100644 ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.h create mode 100644 ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.cpp create mode 100644 ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.h diff --git a/ApplicationLibCode/Commands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CMakeLists_files.cmake index fb06ed6d76..c044253652 100644 --- a/ApplicationLibCode/Commands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CMakeLists_files.cmake @@ -75,6 +75,8 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicImportGridModelFromSummaryCurveFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicGenerateMultipleSurfacesFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicGenerateMultipleSurfacesUi.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleWellLogFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleWellLogUi.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -153,6 +155,8 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicImportGridModelFromSummaryCurveFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicGenerateMultipleSurfacesFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicGenerateMultipleSurfacesUi.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleWellLogFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateEnsembleWellLogUi.cpp ) if(Qt5Charts_FOUND) diff --git a/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.cpp b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.cpp new file mode 100644 index 0000000000..056137f4cb --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.cpp @@ -0,0 +1,281 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- Equinor 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 "RicCreateEnsembleWellLogFeature.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" +#include "RiaImportEclipseCaseTools.h" +#include "RiaLogging.h" + +#include "ExportCommands/RicExportToLasFileFeature.h" +#include "RicCreateEnsembleWellLogUi.h" +#include "RicImportEnsembleWellLogsFeature.h" +#include "RicRecursiveFileSearchDialog.h" +#include "WellPathCommands/RicImportWellPaths.h" + +#include "RimDialogData.h" +#include "RimEclipseCase.h" +#include "RimEnsembleWellLogCurveSet.h" +#include "RimMainPlotCollection.h" +#include "RimProject.h" +#include "RimWellLogTrack.h" +#include "RimcWellLogPlot.h" +#include "RimcWellLogPlotCollection.h" +#include "RimcWellLogTrack.h" + +#include "Riu3DMainWindowTools.h" +#include "RiuPlotMainWindowTools.h" +#include "RiuPropertyViewTabWidget.h" + +#include "cafCmdFeatureManager.h" +#include "cafPdmSettings.h" +#include "cafPdmUiPropertyViewDialog.h" +#include "cafProgressInfo.h" +#include "cafSelectionManager.h" + +#include +#include +#include + +CAF_CMD_SOURCE_INIT( RicCreateEnsembleWellLogFeature, "RicCreateEnsembleWellLogFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogFeature::openDialogAndExecuteCommand() +{ + // Get the list of egrid files + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory( "BINARY_GRID" ); + + QString pathFilter( "*" ); + QString fileNameFilter( "*" ); + + RicRecursiveFileSearchDialogResult result = + RicRecursiveFileSearchDialog::runRecursiveSearchDialog( nullptr, + "Choose Eclipse Cases", + defaultDir, + pathFilter, + fileNameFilter, + QStringList( ".EGRID" ) ); + + if ( !result.ok || result.files.isEmpty() ) + { + return; + } + + // Use case data from first case + RimEclipseCase* eclipseCase = loadEclipseCase( result.files[0] ); + + RicCreateEnsembleWellLogUi* ui = RimProject::current()->dialogData()->createEnsembleWellLogUi(); + ui->setCaseData( eclipseCase->eclipseCaseData() ); + + RiuPropertyViewTabWidget propertyDialog( Riu3DMainWindowTools::mainWindowWidget(), + ui, + "Create Ensemble Well Log", + ui->tabNames() ); + + if ( propertyDialog.exec() == QDialog::Accepted && !ui->properties().empty() && !ui->wellPathFilePath().isEmpty() ) + { + executeCommand( *ui, result.files.toStdList() ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogFeature::executeCommand( const RicCreateEnsembleWellLogUi& ui, + const std::list& fileNames ) +{ + caf::ProgressInfo progress( fileNames.size(), "Creating ensemble well log" ); + + std::vector> properties = ui.properties(); + + RimWellLogPlotCollection* plotCollection = RimProject::current()->mainPlotCollection()->wellLogPlotCollection(); + + // Load well path from file + QStringList wellPathFilePaths; + wellPathFilePaths << ui.wellPathFilePath(); + bool importGrouped = false; + QStringList errorMessages; + std::vector wellPaths = + RicImportWellPaths::importWellPaths( wellPathFilePaths, importGrouped, &errorMessages ); + if ( wellPaths.empty() ) return; + + RimWellPath* wellPath = wellPaths[0]; + + QStringList allLasFileNames; + for ( auto fileName : fileNames ) + { + auto task = progress.task( QString( "Extracting well log for %1" ).arg( fileName ) ); + + // Load eclipse case + RimEclipseCase* eclipseCase = loadEclipseCase( fileName ); + if ( !eclipseCase ) + { + RiaLogging::error( QString( "Failed to load model from file: " ).arg( fileName ) ); + return; + } + + // Create the well log plot + RimWellLogPlot* wellLogPlot = + RimcWellLogPlotCollection_newWellLogPlot::createWellLogPlot( plotCollection, wellPath, eclipseCase ); + + // Create well log track + QString title = "Track"; + RimWellLogTrack* wellLogTrack = + RimcWellLogPlot_newWellLogTrack::createWellLogTrack( wellLogPlot, eclipseCase, wellPath, title ); + + // Create a well log curve for each property + for ( auto property : properties ) + { + QString propertyName = property.first; + RiaDefines::ResultCatType resultCategoryType = property.second; + int timeStep = ui.timeStep(); + RimcWellLogTrack_addExtractionCurve::addExtractionCurve( wellLogTrack, + eclipseCase, + wellPath, + propertyName, + resultCategoryType, + timeStep ); + } + + { + // Create missing directories + QString wellLogExportDirName = "lasexport"; + QFileInfo fi( fileName ); + QString exportFolder = fi.absoluteDir().absolutePath() + QString( "/%1/" ).arg( wellLogExportDirName ); + + if ( !fi.absoluteDir().exists( wellLogExportDirName ) ) + { + if ( !fi.absoluteDir().mkpath( wellLogExportDirName ) ) + { + RiaLogging::error( QString( "Unable to create directory for well log export: " ).arg( exportFolder ) ); + return; + } + } + + // Export to las file + QString filePrefix = ""; + bool exportTvdRkb = false; + bool capitalizeFileNames = false; + bool alwaysOverwrite = true; + double resampleInterval = 0.0; + bool convertCurveUnits = false; + + std::vector lasFiles = RicExportToLasFileFeature::exportToLasFiles( exportFolder, + filePrefix, + wellLogPlot, + exportTvdRkb, + capitalizeFileNames, + alwaysOverwrite, + resampleInterval, + convertCurveUnits ); + for ( auto lasFile : lasFiles ) + allLasFileNames << lasFile; + } + + // Remove the temporary plots after export + plotCollection->removePlot( wellLogPlot ); + } + + if ( ui.autoCreateEnsembleWellLogs() ) + { + RimEnsembleWellLogs* ensembleWellLogs = + RicImportEnsembleWellLogsFeature::createEnsembleWellLogsFromFiles( allLasFileNames ); + if ( ensembleWellLogs ) + { + RimEclipseCase* eclipseCase = nullptr; + + // Create the well log plot + RimWellLogPlot* wellLogPlot = + RimcWellLogPlotCollection_newWellLogPlot::createWellLogPlot( plotCollection, wellPath, eclipseCase ); + + // Create a track per property + for ( auto property : properties ) + { + // Create well log track + cvf::Color3f color = RiaColorTables::normalPaletteColors().cycledColor3f( wellLogPlot->plotCount() ); + QString title = QString( "Track %1" ).arg( wellLogPlot->plotCount() ); + RimWellLogTrack* wellLogTrack = + RimcWellLogPlot_newWellLogTrack::createWellLogTrack( wellLogPlot, eclipseCase, wellPath, title ); + RimEnsembleWellLogCurveSet* ensembleWellLogCurveSet = new RimEnsembleWellLogCurveSet(); + ensembleWellLogCurveSet->setEnsembleWellLogs( ensembleWellLogs ); + ensembleWellLogCurveSet->setColor( color ); + ensembleWellLogCurveSet->setWellLogChannelName( property.first ); + wellLogTrack->setEnsembleWellLogCurveSet( ensembleWellLogCurveSet ); + ensembleWellLogCurveSet->loadDataAndUpdate( true ); + } + + wellLogPlot->updateConnectedEditors(); + + RiuPlotMainWindowTools::showPlotMainWindow(); + RiuPlotMainWindowTools::selectAsCurrentItem( wellLogPlot ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseCase* RicCreateEnsembleWellLogFeature::loadEclipseCase( const QString& fileName ) +{ + QString absolutePath = fileName; + QFileInfo projectPathInfo( absolutePath ); + if ( !projectPathInfo.exists() ) + { + QDir startDir( RiaApplication::instance()->startDir() ); + absolutePath = startDir.absoluteFilePath( fileName ); + } + + RiaImportEclipseCaseTools::FileCaseIdMap fileCaseIdMap; + bool createView = false; + bool doNotShowDialog = true; + bool ok = RiaImportEclipseCaseTools::openEclipseCasesFromFile( QStringList( { absolutePath } ), + createView, + &fileCaseIdMap, + doNotShowDialog ); + if ( !ok || fileCaseIdMap.empty() ) return nullptr; + + return RimProject::current()->eclipseCaseFromCaseId( fileCaseIdMap.begin()->second ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateEnsembleWellLogFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogFeature::onActionTriggered( bool isChecked ) +{ + openDialogAndExecuteCommand(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setText( "Create Ensemble Well Log..." ); +} diff --git a/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.h b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.h new file mode 100644 index 0000000000..125e135765 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogFeature.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- Equinor 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +#include + +class RicCreateEnsembleWellLogUi; +class RimEclipseCase; + +//================================================================================================== +/// +//================================================================================================== +class RicCreateEnsembleWellLogFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + static void openDialogAndExecuteCommand(); + static void executeCommand( const RicCreateEnsembleWellLogUi& ui, const std::list& fileNames ); + static RimEclipseCase* loadEclipseCase( const QString& fileName ); + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.cpp b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.cpp new file mode 100644 index 0000000000..d4ef95ee90 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.cpp @@ -0,0 +1,231 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- Equinor 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 "RicCreateEnsembleWellLogUi.h" + +#include "RiaApplication.h" + +#include "RiaDefines.h" +#include "RigEclipseCaseData.h" + +#include "RigEclipseResultAddress.h" +#include "RimEclipseCase.h" +#include "RimEclipseResultDefinition.h" +#include "RimTools.h" + +#include "cafPdmObject.h" +#include "cafPdmUiCheckBoxEditor.h" +#include "cafPdmUiListEditor.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmUiTreeSelectionEditor.h" + +CAF_PDM_SOURCE_INIT( RicCreateEnsembleWellLogUi, "RicCreateEnsembleWellLogUi" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCreateEnsembleWellLogUi::RicCreateEnsembleWellLogUi() +{ + CAF_PDM_InitObject( "Create Ensemble Well Log", "", "", "" ); + + CAF_PDM_InitField( &m_autoCreateEnsembleWellLogs, + "AutoCreateEnsembleWellLogs", + false, + "Create Ensemble Well Logs From Exported Files", + "", + "", + "" ); + caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_autoCreateEnsembleWellLogs ); + + CAF_PDM_InitField( &m_timeStep, "TimeStep", 0, "Time Step", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_well, "Well", "Well", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_selectedKeywords, "SelectedProperties", "Selected Properties", "", "", "" ); + m_selectedKeywords.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); + + m_tabNames << "Well" + << "Properties"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCreateEnsembleWellLogUi::~RicCreateEnsembleWellLogUi() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QStringList& RicCreateEnsembleWellLogUi::tabNames() const +{ + return m_tabNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogUi::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + if ( uiConfigName == m_tabNames[0] ) + { + uiOrdering.add( &m_well ); + uiOrdering.add( &m_autoCreateEnsembleWellLogs ); + } + else if ( uiConfigName == m_tabNames[1] ) + { + uiOrdering.add( &m_selectedKeywords ); + uiOrdering.add( &m_timeStep ); + } + uiOrdering.skipRemainingFields( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RicCreateEnsembleWellLogUi::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) +{ + QList options; + + if ( fieldNeedingOptions == &m_selectedKeywords ) + { + RigCaseCellResultsData* resultData = m_caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL ); + + std::vector resultCategories = validResultCategories(); + for ( auto catType : resultCategories ) + { + QList allOptions = + RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard( catType, resultData ); + + bool isFirstOfCategory = true; + for ( caf::PdmOptionItemInfo option : allOptions ) + { + if ( resultData->hasResultEntry( RigEclipseResultAddress( catType, option.optionUiText() ) ) ) + { + if ( isFirstOfCategory ) + { + // Add the category title only when there is at least one valid result + options.push_back( + caf::PdmOptionItemInfo::createHeader( caf::AppEnum::uiText( catType ), + true ) ); + isFirstOfCategory = false; + } + + options.push_back( option ); + } + } + } + } + else if ( fieldNeedingOptions == &m_timeStep ) + { + RimTools::timeStepsForCase( m_caseData->ownerCase(), &options ); + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateEnsembleWellLogUi::autoCreateEnsembleWellLogs() const +{ + return m_autoCreateEnsembleWellLogs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RicCreateEnsembleWellLogUi::properties() const +{ + std::vector selectedKeyWords = m_selectedKeywords(); + + auto findResultCategory = []( const QString& keyword, + const std::vector& categories, + RigEclipseCaseData* caseData ) { + // Find the result category for a given keyword + RigCaseCellResultsData* resultData = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL ); + for ( auto category : categories ) + if ( resultData->hasResultEntry( RigEclipseResultAddress( category, keyword ) ) ) return category; + + return RiaDefines::ResultCatType::UNDEFINED; + }; + + std::vector resultCategories = validResultCategories(); + + std::vector> props; + for ( auto keyword : selectedKeyWords ) + { + auto resultCategory = findResultCategory( keyword, resultCategories, m_caseData ); + props.push_back( std::make_pair( keyword, resultCategory ) ); + } + + return props; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicCreateEnsembleWellLogUi::validResultCategories() const +{ + return { RiaDefines::ResultCatType::STATIC_NATIVE, + RiaDefines::ResultCatType::DYNAMIC_NATIVE, + RiaDefines::ResultCatType::INPUT_PROPERTY }; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RicCreateEnsembleWellLogUi::timeStep() const +{ + return m_timeStep; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicCreateEnsembleWellLogUi::wellPathFilePath() const +{ + return m_well().path(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateEnsembleWellLogUi::setCaseData( RigEclipseCaseData* caseData ) +{ + m_caseData = caseData; + + if ( m_selectedKeywords().empty() ) + { + RigCaseCellResultsData* resultData = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL ); + std::vector defaultKeywords = { "INDEX_K", "PORO", "PERMZ", "PRESSURE" }; + std::vector categories = validResultCategories(); + + for ( auto keyword : defaultKeywords ) + { + for ( auto category : categories ) + { + if ( resultData->hasResultEntry( RigEclipseResultAddress( category, keyword ) ) ) + { + m_selectedKeywords.v().push_back( keyword ); + break; + } + } + } + } +} diff --git a/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.h b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.h new file mode 100644 index 0000000000..ffb747e1b5 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateEnsembleWellLogUi.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2021- Equinor 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include + +class RigEclipseCaseData; + +//================================================================================================== +/// +//================================================================================================== +class RicCreateEnsembleWellLogUi : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RicCreateEnsembleWellLogUi(); + ~RicCreateEnsembleWellLogUi() override; + const QStringList& tabNames() const; + + bool autoCreateEnsembleWellLogs() const; + + int timeStep() const; + QString wellPathFilePath() const; + std::vector> properties() const; + + void setCaseData( RigEclipseCaseData* caseData ); + +protected: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly ) override; + + std::vector validResultCategories() const; + +private: + caf::PdmField m_well; + caf::PdmField m_autoCreateEnsembleWellLogs; + + caf::PdmField> m_selectedKeywords; + caf::PdmField m_timeStep; + + QStringList m_tabNames; + RigEclipseCaseData* m_caseData; +}; diff --git a/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.cpp b/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.cpp index 87a9af67e2..dbd8f83175 100644 --- a/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.cpp +++ b/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.cpp @@ -19,10 +19,9 @@ #include "RicImportEnsembleWellLogsFeature.h" #include "RiaApplication.h" +#include "RiaEnsembleNameTools.h" #include "RiaLogging.h" -#include "WellLogCommands/RicWellLogsImportFileFeature.h" - #include "RimEnsembleWellLogs.h" #include "RimEnsembleWellLogsCollection.h" #include "RimOilField.h" @@ -30,6 +29,7 @@ #include "RimWellLogFile.h" #include "RicRecursiveFileSearchDialog.h" +#include "WellLogCommands/RicWellLogsImportFileFeature.h" #include #include @@ -63,8 +63,15 @@ void RicImportEnsembleWellLogsFeature::onActionTriggered( bool isChecked ) QStringList fileNames = runRecursiveFileSearchDialog( "Import Ensemble Well Logs", pathCacheName ); if ( fileNames.isEmpty() ) return; - QString ensembleName = "Ensemble Well Logs"; - if ( ensembleName.isEmpty() ) return; + createEnsembleWellLogsFromFiles( fileNames ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEnsembleWellLogs* RicImportEnsembleWellLogsFeature::createEnsembleWellLogsFromFiles( const QStringList& fileNames ) +{ + if ( fileNames.isEmpty() ) return nullptr; std::vector cases; for ( QString fileNames : fileNames ) @@ -78,15 +85,19 @@ void RicImportEnsembleWellLogsFeature::onActionTriggered( bool isChecked ) } } - if ( cases.empty() ) return; + if ( cases.empty() ) return nullptr; RimEnsembleWellLogs* ensemble = new RimEnsembleWellLogs; + + QString ensembleName = RiaEnsembleNameTools::findSuitableEnsembleName( fileNames ); ensemble->setName( ensembleName ); for ( auto wellLogFile : cases ) ensemble->addWellLogFile( wellLogFile ); RimProject::current()->activeOilField()->ensembleWellLogsCollection->addEnsembleWellLogs( ensemble ); RimProject::current()->activeOilField()->ensembleWellLogsCollection->updateConnectedEditors(); + + return ensemble; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.h b/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.h index e5d025c2cf..3d5650f23d 100644 --- a/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.h +++ b/ApplicationLibCode/Commands/RicImportEnsembleWellLogsFeature.h @@ -22,6 +22,8 @@ #include +class RimEnsembleWellLogs; + //================================================================================================== /// //================================================================================================== @@ -31,6 +33,8 @@ class RicImportEnsembleWellLogsFeature : public caf::CmdFeature RicImportEnsembleWellLogsFeature(); + static RimEnsembleWellLogs* createEnsembleWellLogsFromFiles( const QStringList& fileNames ); + protected: // Overrides bool isCommandEnabled() override; diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h index 0c53f1dbe1..8d2378ad6a 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h +++ b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h @@ -42,9 +42,10 @@ public: RicImportWellPaths(); caf::PdmScriptResponse execute() override; -protected: static std::vector - importWellPaths( const QStringList& wellPathFilePaths, bool importGrouped, QStringList* errorMessages ); + importWellPaths( const QStringList& wellPathFilePaths, bool importGrouped, QStringList* errorMessages ); + +protected: static QStringList wellPathNameFilters(); bool isCommandEnabled() override; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 9eea87b6ab..48b69fc1cd 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -340,6 +340,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() { menuBuilder << "RicNewEditableWellPathFeature"; menuBuilder << "RicPasteModeledWellPathFeature"; + menuBuilder << "RicCreateEnsembleWellLogFeature"; menuBuilder.addSeparator(); menuBuilder.subMenuStart( "Import" ); menuBuilder << "RicWellPathsImportFileFeature"; diff --git a/ApplicationLibCode/ProjectDataModel/RimDialogData.cpp b/ApplicationLibCode/ProjectDataModel/RimDialogData.cpp index c711a1a068..5dd734969e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimDialogData.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimDialogData.cpp @@ -27,6 +27,7 @@ #include "ExportCommands/RicExportWellPathsUi.h" #include "FractureCommands/RicCreateMultipleFracturesUi.h" #include "HoloLensCommands/RicHoloLensExportToFolderUi.h" +#include "RicCreateEnsembleWellLogUi.h" #include "RicGenerateMultipleSurfacesUi.h" CAF_PDM_SOURCE_INIT( RimDialogData, "RimDialogData" ); @@ -74,6 +75,9 @@ RimDialogData::RimDialogData() "", "" ); m_generateEnsembleSurfacesUi = new RicGenerateMultipleSurfacesUi(); + + CAF_PDM_InitFieldNoDefault( &m_createEnsembleWellLogUi, "CreateEnsembleWellLogUi", "Create Ensemble Well Log Ui", "", "", "" ); + m_createEnsembleWellLogUi = new RicCreateEnsembleWellLogUi(); } //-------------------------------------------------------------------------------------------------- @@ -172,3 +176,11 @@ RicGenerateMultipleSurfacesUi* RimDialogData::generateEnsembleSurfacesUi() const { return m_generateEnsembleSurfacesUi; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCreateEnsembleWellLogUi* RimDialogData::createEnsembleWellLogUi() const +{ + return m_createEnsembleWellLogUi; +} diff --git a/ApplicationLibCode/ProjectDataModel/RimDialogData.h b/ApplicationLibCode/ProjectDataModel/RimDialogData.h index c8c83386ec..b4738beefe 100644 --- a/ApplicationLibCode/ProjectDataModel/RimDialogData.h +++ b/ApplicationLibCode/ProjectDataModel/RimDialogData.h @@ -30,6 +30,7 @@ class RicExportWellPathsUi; class RicExportLgrUi; class RimMockModelSettings; class RicGenerateMultipleSurfacesUi; +class RicCreateEnsembleWellLogUi; //================================================================================================== /// @@ -63,6 +64,7 @@ public: RicExportEclipseSectorModelUi* exportSectorModelUi() const; RimMockModelSettings* mockModelSettings() const; RicGenerateMultipleSurfacesUi* generateEnsembleSurfacesUi() const; + RicCreateEnsembleWellLogUi* createEnsembleWellLogUi() const; private: caf::PdmChildField m_exportCarfin; @@ -74,4 +76,5 @@ private: caf::PdmChildField m_exportSectorModelData; caf::PdmChildField m_mockModelSettings; caf::PdmChildField m_generateEnsembleSurfacesUi; + caf::PdmChildField m_createEnsembleWellLogUi; }; diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.cpp b/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.cpp index 9019a605cb..0c19ccb6ce 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.cpp @@ -764,6 +764,7 @@ void RimEnsembleWellLogCurveSet::updateEnsembleCurves( const std::vectoraddCurve( curve ); + curve->setUiTreeHidden( true ); QString errorMessage; if ( wellLogFile->readFile( &errorMessage ) ) @@ -1153,3 +1154,19 @@ void RimEnsembleWellLogCurveSet::initAfterRead() { connectEnsembleCurveSetFilterSignals(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEnsembleWellLogCurveSet::setEnsembleWellLogs( RimEnsembleWellLogs* ensembleWellLogs ) +{ + m_ensembleWellLogs = ensembleWellLogs; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEnsembleWellLogCurveSet::setWellLogChannelName( const QString& wellLogChannelName ) +{ + m_wellLogChannelName = wellLogChannelName; +} diff --git a/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.h b/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.h index 6d572a4af8..6912ff52b2 100644 --- a/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.h +++ b/ApplicationLibCode/ProjectDataModel/WellLog/RimEnsembleWellLogCurveSet.h @@ -117,6 +117,9 @@ public: void updateStatistics(); + void setEnsembleWellLogs( RimEnsembleWellLogs* ensembleWellLogs ); + void setWellLogChannelName( const QString& wellLogChannelName ); + private: void updateEnsembleCurves( const std::vector& curves ); void updateStatisticsCurves( const std::vector& curves ); diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.cpp index a65c3ea1f5..9914021ca4 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.cpp @@ -60,9 +60,20 @@ caf::PdmObjectHandle* RimcWellLogPlot_newWellLogTrack::execute() if ( !wellLogPlot ) return nullptr; - RimWellLogTrack* plotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( false, m_title, wellLogPlot ); - if ( m_case() ) plotTrack->setFormationCase( m_case ); - if ( m_wellPath() ) plotTrack->setFormationWellPath( m_wellPath ); + return createWellLogTrack( wellLogPlot, m_case(), m_wellPath(), m_title() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellLogTrack* RimcWellLogPlot_newWellLogTrack::createWellLogTrack( RimWellLogPlot* wellLogPlot, + RimEclipseCase* eclipseCase, + RimWellPath* wellPath, + const QString& title ) +{ + RimWellLogTrack* plotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack( false, title, wellLogPlot ); + if ( eclipseCase ) plotTrack->setFormationCase( eclipseCase ); + if ( wellPath ) plotTrack->setFormationWellPath( wellPath ); plotTrack->setColSpan( RimPlot::TWO ); plotTrack->setLegendsVisible( true ); plotTrack->setPlotTitleVisible( true ); diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.h b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.h index b480a1c653..4c38a9da9b 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlot.h @@ -28,6 +28,7 @@ class RimEclipseCase; class RimWellPath; +class RimWellLogTrack; //================================================================================================== /// @@ -43,6 +44,11 @@ public: bool resultIsPersistent() const override; std::unique_ptr defaultResult() const override; + static RimWellLogTrack* createWellLogTrack( RimWellLogPlot* wellLogPlot, + RimEclipseCase* eclipseCase, + RimWellPath* wellPath, + const QString& title ); + private: caf::PdmField m_title; caf::PdmPtrField m_case; diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.cpp index 58c9c6c96d..202393ec67 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.cpp @@ -20,6 +20,7 @@ #include "RiaApplication.h" #include "RiaGuiApplication.h" +#include "RimcWellLogPlot.h" #include "WellLogCommands/RicNewWellLogPlotFeatureImpl.h" #include "RimEclipseCase.h" @@ -64,20 +65,31 @@ caf::PdmObjectHandle* RimcWellLogPlotCollection_newWellLogPlot::execute() if ( m_case && m_wellPath && wellLogPlotCollection ) { - newWellLogPlot = new RimWellLogPlot; - newWellLogPlot->setAsPlotMdiWindow(); - - wellLogPlotCollection->addWellLogPlot( newWellLogPlot ); - - newWellLogPlot->commonDataSource()->setCaseToApply( m_case ); - newWellLogPlot->commonDataSource()->setWellPathToApply( m_wellPath ); - newWellLogPlot->loadDataAndUpdate(); - newWellLogPlot->updateConnectedEditors(); + newWellLogPlot = createWellLogPlot( wellLogPlotCollection, m_wellPath, m_case ); } return newWellLogPlot; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellLogPlot* RimcWellLogPlotCollection_newWellLogPlot::createWellLogPlot( RimWellLogPlotCollection* wellLogPlotCollection, + RimWellPath* wellPath, + RimEclipseCase* eclipseCase ) +{ + RimWellLogPlot* newWellLogPlot = new RimWellLogPlot; + newWellLogPlot->setAsPlotMdiWindow(); + + wellLogPlotCollection->addWellLogPlot( newWellLogPlot ); + + newWellLogPlot->commonDataSource()->setCaseToApply( eclipseCase ); + newWellLogPlot->commonDataSource()->setWellPathToApply( wellPath ); + newWellLogPlot->loadDataAndUpdate(); + newWellLogPlot->updateConnectedEditors(); + return newWellLogPlot; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.h b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.h index 0480c13300..f31c3cc2c5 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogPlotCollection.h @@ -42,6 +42,10 @@ public: bool resultIsPersistent() const override; std::unique_ptr defaultResult() const override; + static RimWellLogPlot* createWellLogPlot( RimWellLogPlotCollection* wellLogPlotCollection, + RimWellPath* wellPath, + RimEclipseCase* eclipseCase ); + private: caf::PdmPtrField m_case; caf::PdmPtrField m_wellPath; diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.cpp index 21378e5ce3..c27ab775f5 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.cpp @@ -18,6 +18,7 @@ #include "RimcWellLogTrack.h" #include "RiaApplication.h" +#include "RiaDefines.h" #include "RiaGuiApplication.h" #include "WellLogCommands/RicNewWellLogPlotFeatureImpl.h" @@ -61,37 +62,52 @@ caf::PdmObjectHandle* RimcWellLogTrack_addExtractionCurve::execute() if ( m_case && m_wellPath && wellLogTrack ) { - RimWellLogExtractionCurve* curve = new RimWellLogExtractionCurve; - curve->setWellPath( m_wellPath ); - curve->setCase( m_case ); - curve->setCurrentTimeStep( m_timeStep ); - curve->setEclipseResultVariable( m_propertyName ); - RiaDefines::ResultCatType resultCategoryType = caf::AppEnum::fromText( m_propertyType ); - curve->setEclipseResultCategory( resultCategoryType ); - wellLogTrack->addCurve( curve ); - curve->loadDataAndUpdate( true ); - - curve->updateConnectedEditors(); - - wellLogTrack->setXAxisGridVisibility( RimWellLogPlot::AXIS_GRID_MAJOR ); - wellLogTrack->setShowRegionLabels( true ); - wellLogTrack->setAutoScaleXEnabled( true ); - wellLogTrack->updateConnectedEditors(); - wellLogTrack->setShowWindow( true ); - - RiaApplication::instance()->project()->updateConnectedEditors(); - - RimWellLogPlot* wellLogPlot = dynamic_cast( wellLogTrack->parentField() ); - if ( wellLogPlot ) wellLogPlot->loadDataAndUpdate(); - - return curve; + return addExtractionCurve( wellLogTrack, m_case, m_wellPath, m_propertyName, resultCategoryType, m_timeStep ); } return nullptr; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellLogExtractionCurve* + RimcWellLogTrack_addExtractionCurve::addExtractionCurve( RimWellLogTrack* wellLogTrack, + RimEclipseCase* eclipseCase, + RimWellPath* wellPath, + const QString& propertyName, + RiaDefines::ResultCatType resultCategoryType, + int timeStep ) +{ + RimWellLogExtractionCurve* curve = new RimWellLogExtractionCurve; + curve->setWellPath( wellPath ); + curve->setCase( eclipseCase ); + curve->setCurrentTimeStep( timeStep ); + curve->setEclipseResultVariable( propertyName ); + + curve->setEclipseResultCategory( resultCategoryType ); + + wellLogTrack->addCurve( curve ); + curve->loadDataAndUpdate( true ); + + curve->updateConnectedEditors(); + + wellLogTrack->setXAxisGridVisibility( RimWellLogPlot::AXIS_GRID_MAJOR ); + wellLogTrack->setShowRegionLabels( true ); + wellLogTrack->setAutoScaleXEnabled( true ); + wellLogTrack->updateConnectedEditors(); + wellLogTrack->setShowWindow( true ); + + RiaApplication::instance()->project()->updateConnectedEditors(); + + RimWellLogPlot* wellLogPlot = dynamic_cast( wellLogTrack->parentField() ); + if ( wellLogPlot ) wellLogPlot->loadDataAndUpdate(); + + return curve; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.h b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.h index 70dc049952..b7cead3bee 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellLogTrack.h @@ -18,6 +18,8 @@ #pragma once +#include "RiaDefines.h" + #include "cafPdmField.h" #include "cafPdmObjectHandle.h" #include "cafPdmObjectMethod.h" @@ -27,6 +29,7 @@ class RimEclipseCase; class RimWellPath; class RimWellLogTrack; +class RimWellLogExtractionCurve; //================================================================================================== /// @@ -42,6 +45,13 @@ public: bool resultIsPersistent() const override; std::unique_ptr defaultResult() const override; + static RimWellLogExtractionCurve* addExtractionCurve( RimWellLogTrack* wellLogTrack, + RimEclipseCase* eclipseCase, + RimWellPath* wellPath, + const QString& propertyName, + RiaDefines::ResultCatType resultCategoryType, + int timeStep ); + private: caf::PdmPtrField m_case; caf::PdmPtrField m_wellPath;