diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.cpp b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.cpp index 4430d6c983..3040855c53 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.cpp @@ -29,6 +29,8 @@ #include "RimProject.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" +#include "RimcDataContainerString.h" +#include "RimcWellPathCollection.h" #include "Riu3DMainWindowTools.h" #include "RiuFileDialogTools.h" @@ -74,83 +76,47 @@ RicImportWellPaths::RicImportWellPaths() //-------------------------------------------------------------------------------------------------- caf::PdmScriptResponse RicImportWellPaths::execute() { - QStringList errorMessages, warningMessages; - QStringList wellPathFiles; - - QDir wellPathDir; - if ( m_wellPathFolder().isEmpty() ) + RimProject* project = RimProject::current(); + if ( !project || !project->activeOilField() || !project->activeOilField()->wellPathCollection() ) { - wellPathDir = QDir( RiaApplication::instance()->startDir() ); - } - else - { - wellPathDir = QDir( m_wellPathFolder ); + return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, "importWellPaths: No well path collection available" ); } - if ( !m_wellPathFolder().isEmpty() ) - { - if ( wellPathDir.exists() ) - { - QStringList nameFilters; - nameFilters << RicImportWellPaths::wellPathNameFilters(); - QStringList relativePaths = wellPathDir.entryList( nameFilters, QDir::Files | QDir::NoDotAndDotDot ); - for ( const QString& relativePath : relativePaths ) - { - wellPathFiles.push_back( wellPathDir.absoluteFilePath( relativePath ) ); - } - } - else - { - errorMessages << ( wellPathDir.absolutePath() + " does not exist" ); - } - } + RimWellPathCollection_importWellPaths method( project->activeOilField()->wellPathCollection() ); + method.setWellPathFiles( m_wellPathFiles() ); + method.setWellPathFolder( m_wellPathFolder() ); - for ( const QString& wellPathFile : m_wellPathFiles() ) - { - if ( QFileInfo::exists( wellPathFile ) ) - { - wellPathFiles.push_back( wellPathFile ); - } - else if ( QFileInfo::exists( wellPathDir.absoluteFilePath( wellPathFile ) ) ) - { - wellPathFiles.push_back( wellPathDir.absoluteFilePath( wellPathFile ) ); - } - else - { - errorMessages << ( wellPathFile + " does not exist" ); - } - } + auto result = method.execute(); caf::PdmScriptResponse response; - if ( !wellPathFiles.empty() ) - { - std::vector importedWellPaths = importWellPaths( wellPathFiles, &warningMessages ); - if ( !importedWellPaths.empty() ) - { - RicImportWellPathsResult* wellPathsResult = new RicImportWellPathsResult; - for ( RimWellPath* wellPath : importedWellPaths ) - { - wellPathsResult->wellPathNames.v().push_back( wellPath->name() ); - } - - response.setResult( wellPathsResult ); - } - } - else - { - warningMessages << "No well paths found"; - } - - for ( const QString& warningMessage : warningMessages ) + for ( const QString& warningMessage : method.warnings() ) { response.updateStatus( caf::PdmScriptResponse::COMMAND_WARNING, warningMessage ); } - for ( const QString& errorMessage : errorMessages ) + if ( !result ) { - response.updateStatus( caf::PdmScriptResponse::COMMAND_ERROR, errorMessage ); + // Legacy behavior: "no files found" is a warning, missing files are errors + if ( result.error() == "No well path files found" ) + { + response.updateStatus( caf::PdmScriptResponse::COMMAND_WARNING, "No well paths found" ); + } + else + { + response.updateStatus( caf::PdmScriptResponse::COMMAND_ERROR, result.error() ); + } + return response; } + auto* names = dynamic_cast( result.value() ); + if ( names && !names->m_stringValues().empty() ) + { + auto* wellPathsResult = new RicImportWellPathsResult; + wellPathsResult->wellPathNames = names->m_stringValues(); + response.setResult( wellPathsResult ); + } + delete names; + return response; } diff --git a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h index 6747460dec..c32939a19a 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h +++ b/ApplicationLibCode/Commands/WellPathCommands/RicImportWellPaths.h @@ -43,10 +43,9 @@ public: caf::PdmScriptResponse execute() override; static std::vector importWellPaths( const QStringList& wellPathFilePaths, QStringList* errorMessages ); + static QStringList wellPathNameFilters(); protected: - static QStringList wellPathNameFilters(); - void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.cpp index ed82e07505..4589340bbe 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.cpp @@ -21,19 +21,25 @@ #include "RiaApplication.h" #include "RiaKeyValueStoreUtil.h" +#include "WellLogCommands/RicWellLogsImportFileFeature.h" #include "WellPathCommands/RicImportWellPaths.h" #include "RimEclipseCase.h" #include "RimModeledWellPath.h" #include "RimPointBasedWellPath.h" #include "RimProject.h" +#include "RimWellLogLasFile.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" +#include "RimcDataContainerString.h" #include "cafPdmFieldScriptingCapability.h" #include "cvfVector3.h" +#include +#include + CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellPathCollection, RimcWellPathCollection_importWellPath, "ImportWellPath" ); //-------------------------------------------------------------------------------------------------- @@ -209,3 +215,205 @@ std::expected RimcWellPathCollection_setMswNameG return nullptr; } + +namespace +{ +//-------------------------------------------------------------------------------------------------- +/// Resolve explicit file paths (absolute, or relative to the folder / start dir) and all files in the folder matching +/// the name filters. Missing files are reported as errors. +//-------------------------------------------------------------------------------------------------- +std::expected resolveImportFiles( const std::vector& files, const QString& folder, const QStringList& nameFilters ) +{ + QStringList errorMessages; + QStringList resolvedFiles; + + QDir baseDir = folder.isEmpty() ? QDir( RiaApplication::instance()->startDir() ) : QDir( folder ); + + if ( !folder.isEmpty() ) + { + if ( baseDir.exists() ) + { + for ( const QString& relativePath : baseDir.entryList( nameFilters, QDir::Files | QDir::NoDotAndDotDot ) ) + { + resolvedFiles.push_back( baseDir.absoluteFilePath( relativePath ) ); + } + } + else + { + errorMessages << ( baseDir.absolutePath() + " does not exist" ); + } + } + + for ( const QString& file : files ) + { + if ( QFileInfo::exists( file ) ) + { + resolvedFiles.push_back( file ); + } + else if ( QFileInfo::exists( baseDir.absoluteFilePath( file ) ) ) + { + resolvedFiles.push_back( baseDir.absoluteFilePath( file ) ); + } + else + { + errorMessages << ( file + " does not exist" ); + } + } + + if ( !errorMessages.empty() ) return std::unexpected( errorMessages.join( "\n" ) ); + + return resolvedFiles; +} +} // namespace + +CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellPathCollection, RimWellPathCollection_importWellPaths, "importWellPaths" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathCollection_importWellPaths::RimWellPathCollection_importWellPaths( caf::PdmObjectHandle* self ) + : caf::PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE ) +{ + CAF_PDM_InitObject( "Import Well Paths", "", "", "Import well paths from files and/or all well path files in a folder" ); + + CAF_PDM_InitScriptableField( &m_wellPathFiles, "WellPathFiles", std::vector(), "Well Path Files", "", "", "Well path files to import" ); + CAF_PDM_InitScriptableField( &m_wellPathFolder, + "WellPathFolder", + QString(), + "Well Path Folder", + "", + "", + "Folder to import all well path files from. Also used to resolve relative file paths." ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection_importWellPaths::setWellPathFiles( const std::vector& wellPathFiles ) +{ + m_wellPathFiles = wellPathFiles; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection_importWellPaths::setWellPathFolder( const QString& wellPathFolder ) +{ + m_wellPathFolder = wellPathFolder; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimWellPathCollection_importWellPaths::warnings() const +{ + return m_warnings; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::expected RimWellPathCollection_importWellPaths::execute() +{ + m_warnings.clear(); + + auto wellPathCollection = self(); + if ( !wellPathCollection ) return std::unexpected( "No well path collection is available." ); + + auto files = resolveImportFiles( m_wellPathFiles(), m_wellPathFolder(), RicImportWellPaths::wellPathNameFilters() ); + if ( !files ) return std::unexpected( files.error() ); + if ( files->empty() ) return std::unexpected( "No well path files found" ); + + std::vector importedWellPaths = RicImportWellPaths::importWellPaths( files.value(), &m_warnings ); + + auto* result = new RimcDataContainerString(); + for ( RimWellPath* wellPath : importedWellPaths ) + { + result->m_stringValues.v().push_back( wellPath->name() ); + } + return result; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCollection_importWellPaths::classKeywordReturnedType() const +{ + return RimcDataContainerString::classKeywordStatic(); +} + +CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellPathCollection, RimWellPathCollection_importWellLogFiles, "importWellLogFiles" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathCollection_importWellLogFiles::RimWellPathCollection_importWellLogFiles( caf::PdmObjectHandle* self ) + : caf::PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE ) +{ + CAF_PDM_InitObject( "Import Well Log Files", "", "", "Import LAS files and attach them to the well paths with matching names" ); + + CAF_PDM_InitScriptableField( &m_wellLogFiles, "WellLogFiles", std::vector(), "Well Log Files", "", "", "Well log files to import" ); + CAF_PDM_InitScriptableField( &m_wellLogFolder, + "WellLogFolder", + QString(), + "Well Log Folder", + "", + "", + "Folder to import all well log files from. Also used to resolve relative file paths." ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection_importWellLogFiles::setWellLogFiles( const std::vector& wellLogFiles ) +{ + m_wellLogFiles = wellLogFiles; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection_importWellLogFiles::setWellLogFolder( const QString& wellLogFolder ) +{ + m_wellLogFolder = wellLogFolder; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimWellPathCollection_importWellLogFiles::warnings() const +{ + return m_warnings; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::expected RimWellPathCollection_importWellLogFiles::execute() +{ + m_warnings.clear(); + + auto wellPathCollection = self(); + if ( !wellPathCollection ) return std::unexpected( "No well path collection is available." ); + + auto files = resolveImportFiles( m_wellLogFiles(), m_wellLogFolder(), RicWellLogsImportFileFeature::wellLogFileNameFilters() ); + if ( !files ) return std::unexpected( files.error() ); + if ( files->empty() ) return std::unexpected( "No well log files found" ); + + std::vector importedFiles = RicWellLogsImportFileFeature::importWellLogFiles( files.value(), &m_warnings ); + + auto* result = new RimcDataContainerString(); + for ( RimWellLogLasFile* wellLogFile : importedFiles ) + { + result->m_stringValues.v().push_back( wellLogFile->wellName() ); + } + return result; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCollection_importWellLogFiles::classKeywordReturnedType() const +{ + return RimcDataContainerString::classKeywordStatic(); +} diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.h b/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.h index 80d8341278..82994ca77a 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcWellPathCollection.h @@ -23,6 +23,7 @@ #include "cafPdmObjectMethod.h" #include +#include class RimEclipseResultCase; @@ -78,3 +79,57 @@ public: private: caf::PdmField m_mswNameGrouping; }; + +//================================================================================================== +/// Import well paths from a list of files and/or all well path files in a folder. +/// Returns the names of the imported well paths as a string container. +//================================================================================================== +class RimWellPathCollection_importWellPaths : public caf::PdmObjectMethod +{ + CAF_PDM_HEADER_INIT; + +public: + RimWellPathCollection_importWellPaths( caf::PdmObjectHandle* self ); + + void setWellPathFiles( const std::vector& wellPathFiles ); + void setWellPathFolder( const QString& wellPathFolder ); + + std::expected execute() override; + QString classKeywordReturnedType() const override; + + /// Warnings from the last execute(), e.g. files that could not be parsed + QStringList warnings() const; + +private: + caf::PdmField> m_wellPathFiles; + caf::PdmField m_wellPathFolder; + + QStringList m_warnings; +}; + +//================================================================================================== +/// Import well log files (LAS) from a list of files and/or all well log files in a folder, and attach +/// them to the well paths with matching names. Returns the names of the affected well paths. +//================================================================================================== +class RimWellPathCollection_importWellLogFiles : public caf::PdmObjectMethod +{ + CAF_PDM_HEADER_INIT; + +public: + RimWellPathCollection_importWellLogFiles( caf::PdmObjectHandle* self ); + + void setWellLogFiles( const std::vector& wellLogFiles ); + void setWellLogFolder( const QString& wellLogFolder ); + + std::expected execute() override; + QString classKeywordReturnedType() const override; + + /// Warnings from the last execute(), e.g. files that could not be parsed + QStringList warnings() const; + +private: + caf::PdmField> m_wellLogFiles; + caf::PdmField m_wellLogFolder; + + QStringList m_warnings; +};