mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Add action for downloading and parsing well log from OSDU Wellbore DDMS.
This commit is contained in:
@@ -194,6 +194,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicExportSummaryCalculationExpressionsFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogOsduFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomVfpPlotFeature.cpp
|
||||
|
||||
@@ -120,7 +120,7 @@ void RiaOsduConnector::requestFieldsByName( const QString& server, const QString
|
||||
params["limit"] = "10000";
|
||||
params["query"] = "data.FieldName:" + fieldName;
|
||||
|
||||
auto reply = makeRequest( params, server, dataPartitionId, token );
|
||||
auto reply = makeSearchRequest( params, server, dataPartitionId, token );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply]()
|
||||
@@ -150,7 +150,7 @@ void RiaOsduConnector::requestWellsByFieldId( const QString& server, const QStri
|
||||
params["limit"] = "10000";
|
||||
params["query"] = QString( "nested(data.GeoContexts, (FieldID:\"%1\"))" ).arg( fieldId );
|
||||
|
||||
auto reply = makeRequest( params, server, dataPartitionId, token );
|
||||
auto reply = makeSearchRequest( params, server, dataPartitionId, token );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply, fieldId]()
|
||||
@@ -180,7 +180,7 @@ void RiaOsduConnector::requestWellboresByWellId( const QString& server, const QS
|
||||
params["limit"] = "10000";
|
||||
params["query"] = "data.WellID: \"" + wellId + "\"";
|
||||
|
||||
auto reply = makeRequest( params, server, dataPartitionId, token );
|
||||
auto reply = makeSearchRequest( params, server, dataPartitionId, token );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply, wellId]()
|
||||
@@ -221,7 +221,7 @@ void RiaOsduConnector::requestWellboreTrajectoryByWellboreId( const QString& ser
|
||||
params["limit"] = "10000";
|
||||
params["query"] = "data.WellboreID: \"" + wellboreId + "\"";
|
||||
|
||||
auto reply = makeRequest( params, server, dataPartitionId, token );
|
||||
auto reply = makeSearchRequest( params, server, dataPartitionId, token );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply, wellboreId]()
|
||||
@@ -239,7 +239,9 @@ void RiaOsduConnector::requestWellboreTrajectoryByWellboreId( const QString& ser
|
||||
void RiaOsduConnector::requestFileDownloadByFileId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fileId )
|
||||
{
|
||||
RiaLogging::info( "Requesting download of file id: " + fileId );
|
||||
auto reply = makeDownloadRequest( server, dataPartitionId, fileId, token );
|
||||
QString url = constructFileDownloadUrl( server, fileId );
|
||||
|
||||
auto reply = makeDownloadRequest( url, dataPartitionId, token, CONTENT_TYPE_JSON );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply, fileId]()
|
||||
@@ -266,7 +268,7 @@ QString RiaOsduConnector::constructSearchUrl( const QString& server )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaOsduConnector::constructDownloadUrl( const QString& server, const QString& fileId )
|
||||
QString RiaOsduConnector::constructFileDownloadUrl( const QString& server, const QString& fileId )
|
||||
{
|
||||
return server + "/api/file/v2/files/" + fileId + "/downloadURL";
|
||||
}
|
||||
@@ -290,15 +292,23 @@ QString RiaOsduConnector::constructTokenUrl( const QString& authority )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QNetworkReply* RiaOsduConnector::makeRequest( const std::map<QString, QString>& parameters,
|
||||
const QString& server,
|
||||
const QString& dataPartitionId,
|
||||
const QString& token )
|
||||
QString RiaOsduConnector::constructWellLogDownloadUrl( const QString& server, const QString& wellLogId )
|
||||
{
|
||||
return server + "/api/os-wellbore-ddms/ddms/v3/welllogs/" + wellLogId + "/data";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QNetworkReply* RiaOsduConnector::makeSearchRequest( const std::map<QString, QString>& parameters,
|
||||
const QString& server,
|
||||
const QString& dataPartitionId,
|
||||
const QString& token )
|
||||
{
|
||||
QNetworkRequest m_networkRequest;
|
||||
m_networkRequest.setUrl( QUrl( constructSearchUrl( server ) ) );
|
||||
|
||||
addStandardHeader( m_networkRequest, token, dataPartitionId );
|
||||
addStandardHeader( m_networkRequest, token, dataPartitionId, CONTENT_TYPE_JSON );
|
||||
|
||||
QJsonObject obj;
|
||||
for ( auto [key, value] : parameters )
|
||||
@@ -484,9 +494,12 @@ void RiaOsduConnector::saveFile( QNetworkReply* reply, const QString& fileId )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaOsduConnector::addStandardHeader( QNetworkRequest& networkRequest, const QString& token, const QString& dataPartitionId )
|
||||
void RiaOsduConnector::addStandardHeader( QNetworkRequest& networkRequest,
|
||||
const QString& token,
|
||||
const QString& dataPartitionId,
|
||||
const QString& contentType )
|
||||
{
|
||||
networkRequest.setHeader( QNetworkRequest::ContentTypeHeader, "application/json" );
|
||||
networkRequest.setHeader( QNetworkRequest::ContentTypeHeader, contentType );
|
||||
networkRequest.setRawHeader( "Authorization", "Bearer " + token.toUtf8() );
|
||||
networkRequest.setRawHeader( QByteArray( "Data-Partition-Id" ), dataPartitionId.toUtf8() );
|
||||
}
|
||||
@@ -495,17 +508,14 @@ void RiaOsduConnector::addStandardHeader( QNetworkRequest& networkRequest, const
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QNetworkReply*
|
||||
RiaOsduConnector::makeDownloadRequest( const QString& server, const QString& dataPartitionId, const QString& id, const QString& token )
|
||||
RiaOsduConnector::makeDownloadRequest( const QString& url, const QString& dataPartitionId, const QString& token, const QString& contentType )
|
||||
{
|
||||
QNetworkRequest m_networkRequest;
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setUrl( QUrl( url ) );
|
||||
|
||||
QString url = constructDownloadUrl( server, id );
|
||||
addStandardHeader( networkRequest, token, dataPartitionId, contentType );
|
||||
|
||||
m_networkRequest.setUrl( QUrl( url ) );
|
||||
|
||||
addStandardHeader( m_networkRequest, token, dataPartitionId );
|
||||
|
||||
auto reply = m_networkAccessManager->get( m_networkRequest );
|
||||
auto reply = m_networkAccessManager->get( networkRequest );
|
||||
return reply;
|
||||
}
|
||||
|
||||
@@ -635,6 +645,7 @@ std::pair<QString, QString> RiaOsduConnector::requestFileContentsById( const QSt
|
||||
this,
|
||||
SLOT( fileDownloadComplete( const QString&, const QString& ) ) );
|
||||
connect( this, SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), &loop2, SLOT( quit() ) );
|
||||
|
||||
requestFileDownloadByFileId( m_server, m_dataPartitionId, m_token, fileId );
|
||||
loop2.exec();
|
||||
|
||||
@@ -650,3 +661,66 @@ std::pair<QString, QString> RiaOsduConnector::requestFileContentsById( const QSt
|
||||
|
||||
return { fileContent, "" };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<QByteArray, QString> RiaOsduConnector::requestWellLogParquetDataById( const QString& wellLogId )
|
||||
{
|
||||
if ( m_token.isEmpty() )
|
||||
{
|
||||
// TODO: improve this..
|
||||
QEventLoop loop;
|
||||
connect( this, SIGNAL( tokenReady( const QString& ) ), &loop, SLOT( quit() ) );
|
||||
requestToken();
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
QEventLoop loop2;
|
||||
connect( this,
|
||||
SIGNAL( wellLogDownloadFinished( const QByteArray&, const QString& ) ),
|
||||
this,
|
||||
SLOT( wellLogDownloadComplete( const QByteArray&, const QString& ) ) );
|
||||
connect( this, SIGNAL( wellLogDownloadFinished( const QByteArray&, const QString& ) ), &loop2, SLOT( quit() ) );
|
||||
|
||||
QString url = constructWellLogDownloadUrl( m_server, wellLogId );
|
||||
RiaLogging::debug( "Well log URL: " + url );
|
||||
|
||||
requestWellLog( url, m_dataPartitionId, m_token );
|
||||
loop2.exec();
|
||||
|
||||
return { m_wellLogContents, "" };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaOsduConnector::requestWellLog( const QString& url, const QString& dataPartitionId, const QString& token )
|
||||
{
|
||||
RiaLogging::info( "Requesting download of well log from: " + url );
|
||||
|
||||
auto reply = makeDownloadRequest( url, dataPartitionId, token, CONTENT_TYPE_PARQUET );
|
||||
connect( reply,
|
||||
&QNetworkReply::finished,
|
||||
[this, reply, url]()
|
||||
{
|
||||
if ( reply->error() == QNetworkReply::NoError )
|
||||
{
|
||||
QByteArray contents = reply->readAll();
|
||||
RiaLogging::info( QString( "Download succeeded: %1 bytes." ).arg( contents.length() ) );
|
||||
emit wellLogDownloadFinished( contents, "" );
|
||||
}
|
||||
else
|
||||
{
|
||||
RiaLogging::error( "Download failed: " + url + " failed." + reply->errorString() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiaOsduConnector::wellLogDownloadComplete( const QByteArray& contents, const QString& url )
|
||||
{
|
||||
m_wellLogContents = contents;
|
||||
}
|
||||
|
||||
@@ -59,9 +59,12 @@ public:
|
||||
void requestWellboresByWellId( const QString& wellId );
|
||||
void requestWellboreTrajectoryByWellboreId( const QString& wellboreId );
|
||||
void requestFileDownloadByFileId( const QString& fileId );
|
||||
void requestWellLog( const QString& url, const QString& dataPartitionId, const QString& token );
|
||||
|
||||
std::pair<QString, QString> requestFileContentsById( const QString& fileId );
|
||||
|
||||
std::pair<QByteArray, QString> requestWellLogParquetDataById( const QString& wellLogId );
|
||||
|
||||
QString wellIdForWellboreId( const QString& wellboreId ) const;
|
||||
|
||||
QString server() const;
|
||||
@@ -81,9 +84,11 @@ public slots:
|
||||
void saveFile( QNetworkReply* reply, const QString& fileId );
|
||||
void accessGranted();
|
||||
void fileDownloadComplete( const QString& fileId, const QString& filePath );
|
||||
void wellLogDownloadComplete( const QByteArray&, const QString& url );
|
||||
|
||||
signals:
|
||||
void fileDownloadFinished( const QString& fileId, const QString& filePath );
|
||||
void wellLogDownloadFinished( const QByteArray& contents, const QString& url );
|
||||
void fieldsFinished();
|
||||
void wellsFinished();
|
||||
void wellboresFinished( const QString& wellId );
|
||||
@@ -91,12 +96,14 @@ signals:
|
||||
void tokenReady( const QString& token );
|
||||
|
||||
private:
|
||||
void addStandardHeader( QNetworkRequest& networkRequest, const QString& token, const QString& dataPartitionId );
|
||||
void addStandardHeader( QNetworkRequest& networkRequest, const QString& token, const QString& dataPartitionId, const QString& contentType );
|
||||
|
||||
QNetworkReply*
|
||||
makeRequest( const std::map<QString, QString>& parameters, const QString& server, const QString& dataPartitionId, const QString& token );
|
||||
QNetworkReply* makeSearchRequest( const std::map<QString, QString>& parameters,
|
||||
const QString& server,
|
||||
const QString& dataPartitionId,
|
||||
const QString& token );
|
||||
|
||||
QNetworkReply* makeDownloadRequest( const QString& server, const QString& dataPartitionId, const QString& id, const QString& token );
|
||||
QNetworkReply* makeDownloadRequest( const QString& url, const QString& dataPartitionId, const QString& token, const QString& contentType );
|
||||
|
||||
void requestFieldsByName( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldName );
|
||||
void requestWellsByFieldId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fieldId );
|
||||
@@ -109,9 +116,10 @@ private:
|
||||
|
||||
static QString generateRandomString( int length = 20 );
|
||||
static QString constructSearchUrl( const QString& server );
|
||||
static QString constructDownloadUrl( const QString& server, const QString& fileId );
|
||||
static QString constructFileDownloadUrl( const QString& server, const QString& fileId );
|
||||
static QString constructAuthUrl( const QString& authority );
|
||||
static QString constructTokenUrl( const QString& authority );
|
||||
static QString constructWellLogDownloadUrl( const QString& server, const QString& wellLogId );
|
||||
|
||||
QOAuth2AuthorizationCodeFlow* m_osdu;
|
||||
QNetworkAccessManager* m_networkAccessManager;
|
||||
@@ -128,9 +136,13 @@ private:
|
||||
std::map<QString, std::vector<OsduWellbore>> m_wellbores;
|
||||
std::map<QString, std::vector<OsduWellboreTrajectory>> m_wellboreTrajectories;
|
||||
QString m_filePath;
|
||||
QByteArray m_wellLogContents;
|
||||
|
||||
static inline const QString FIELD_KIND = "osdu:wks:master-data--Field:1.0.0";
|
||||
static inline const QString WELL_KIND = "osdu:wks:master-data--Well:1.2.0";
|
||||
static inline const QString WELLBORE_KIND = "osdu:wks:master-data--Wellbore:1.1.0";
|
||||
static inline const QString WELLBORE_TRAJECTORY_KIND = "osdu:wks:work-product-component--WellboreTrajectory:1.1.0";
|
||||
|
||||
static inline const QString CONTENT_TYPE_JSON = "application/json";
|
||||
static inline const QString CONTENT_TYPE_PARQUET = "application/x-parquet";
|
||||
};
|
||||
|
||||
103
ApplicationLibCode/Commands/RicImportWellLogOsduFeature.cpp
Normal file
103
ApplicationLibCode/Commands/RicImportWellLogOsduFeature.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicImportWellLogOsduFeature.h"
|
||||
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RimOilField.h"
|
||||
#include "RimOsduWellLog.h"
|
||||
#include "RimOsduWellPath.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
|
||||
#include "RiuMainWindow.h"
|
||||
|
||||
#include "OsduImportCommands/RiaOsduConnector.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPreferences.h"
|
||||
|
||||
#include "cafSelectionManager.h"
|
||||
|
||||
#include <QAction>
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicImportWellLogOsduFeature, "RicImportWellLogOsduFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicImportWellLogOsduFeature::isCommandEnabled() const
|
||||
{
|
||||
return caf::SelectionManager::instance()->selectedItemOfType<RimOsduWellPath>() != nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicImportWellLogOsduFeature::onActionTriggered( bool isChecked )
|
||||
{
|
||||
auto makeOsduConnector = []( auto app )
|
||||
{
|
||||
RiaPreferencesOsdu* osduPreferences = app->preferences()->osduPreferences();
|
||||
const QString server = osduPreferences->server();
|
||||
const QString dataPartitionId = osduPreferences->dataPartitionId();
|
||||
const QString authority = osduPreferences->authority();
|
||||
const QString scopes = osduPreferences->scopes();
|
||||
const QString clientId = osduPreferences->clientId();
|
||||
return std::make_unique<RiaOsduConnector>( RiuMainWindow::instance(), server, dataPartitionId, authority, scopes, clientId );
|
||||
};
|
||||
|
||||
if ( auto wellPath = caf::SelectionManager::instance()->selectedItemOfType<RimOsduWellPath>() )
|
||||
{
|
||||
RiaGuiApplication* app = RiaGuiApplication::instance();
|
||||
|
||||
RimOilField* oilField = RimProject::current()->activeOilField();
|
||||
if ( oilField == nullptr ) return;
|
||||
|
||||
if ( !oilField->wellPathCollection ) oilField->wellPathCollection = std::make_unique<RimWellPathCollection>();
|
||||
|
||||
RimOsduWellLog* osduWellLog = new RimOsduWellLog;
|
||||
// TODO: get from OSDU...
|
||||
osduWellLog->setWellLogId( "npequinor-dev:work-product-component--WellLog:aeb5bd8b1de14138afe9f23cacbc7fe7" );
|
||||
oilField->wellPathCollection->addWellLog( osduWellLog, wellPath );
|
||||
|
||||
auto osduConnector = makeOsduConnector( app );
|
||||
|
||||
auto [wellLogData, errorMessage] = RimWellPathCollection::loadWellLogFromOsdu( osduConnector.get(), osduWellLog->wellLogId() );
|
||||
if ( wellLogData.notNull() )
|
||||
{
|
||||
osduWellLog->setWellLogData( wellLogData.p() );
|
||||
}
|
||||
else
|
||||
{
|
||||
RiaLogging::error( "Importing OSDU well log failed: " + errorMessage );
|
||||
}
|
||||
|
||||
osduWellLog->updateConnectedEditors();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RicImportWellLogOsduFeature::setupActionLook( QAction* actionToSetup )
|
||||
{
|
||||
actionToSetup->setIcon( QIcon( ":/LasFile16x16.png" ) );
|
||||
actionToSetup->setText( "Import Well Log From OSDU" );
|
||||
}
|
||||
34
ApplicationLibCode/Commands/RicImportWellLogOsduFeature.h
Normal file
34
ApplicationLibCode/Commands/RicImportWellLogOsduFeature.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafCmdFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicImportWellLogOsduFeature : public caf::CmdFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
bool isCommandEnabled() const override;
|
||||
void onActionTriggered( bool isChecked ) override;
|
||||
void setupActionLook( QAction* actionToSetup ) override;
|
||||
};
|
||||
@@ -98,6 +98,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifAsciiDataParseOptions.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifByteArrayArrowRandomAccessFile.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@@ -194,6 +195,8 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellLogReader.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RifByteArrayArrowRandomAccessFile.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RifByteArrayArrowRandomAccessFile.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RifByteArrayArrowRandomAccessFile::RifByteArrayArrowRandomAccessFile( const QByteArray& data )
|
||||
: m_data( data )
|
||||
, m_position( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<int64_t> RifByteArrayArrowRandomAccessFile::ReadAt( int64_t position, int64_t nbytes, void* out )
|
||||
{
|
||||
if ( nbytes > 0 )
|
||||
{
|
||||
memcpy( out, m_data.data() + position, static_cast<size_t>( nbytes ) );
|
||||
m_position += nbytes;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<std::shared_ptr<arrow::Buffer>> RifByteArrayArrowRandomAccessFile::ReadAt( int64_t position, int64_t nbytes )
|
||||
{
|
||||
return std::make_shared<arrow::Buffer>( (const uint8_t*)m_data.data() + position, nbytes );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<int64_t> RifByteArrayArrowRandomAccessFile::Read( int64_t nbytes, void* out )
|
||||
{
|
||||
return ReadAt( m_position, nbytes, out );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<std::shared_ptr<arrow::Buffer>> RifByteArrayArrowRandomAccessFile::Read( int64_t nbytes )
|
||||
{
|
||||
return ReadAt( m_position, nbytes );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<int64_t> RifByteArrayArrowRandomAccessFile::GetSize()
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Result<int64_t> RifByteArrayArrowRandomAccessFile::Tell() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Status RifByteArrayArrowRandomAccessFile::Seek( int64_t position )
|
||||
{
|
||||
m_position = position;
|
||||
return arrow::Status::OK();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
arrow::Status RifByteArrayArrowRandomAccessFile::Close()
|
||||
{
|
||||
m_closed = true;
|
||||
return arrow::Status::OK();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RifByteArrayArrowRandomAccessFile::closed() const
|
||||
{
|
||||
return m_closed;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <arrow/csv/api.h>
|
||||
#include <arrow/io/api.h>
|
||||
#include <arrow/scalar.h>
|
||||
#include <arrow/util/cancel.h>
|
||||
#include <parquet/arrow/reader.h>
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include <memory>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RifByteArrayArrowRandomAccessFile : public arrow::io::RandomAccessFile
|
||||
{
|
||||
public:
|
||||
RifByteArrayArrowRandomAccessFile( const QByteArray& data );
|
||||
|
||||
arrow::Result<int64_t> ReadAt( int64_t position, int64_t nbytes, void* out ) override;
|
||||
|
||||
arrow::Result<std::shared_ptr<arrow::Buffer>> ReadAt( int64_t position, int64_t nbytes ) override;
|
||||
|
||||
arrow::Result<int64_t> Read( int64_t nbytes, void* out ) override;
|
||||
|
||||
arrow::Result<std::shared_ptr<arrow::Buffer>> Read( int64_t nbytes ) override;
|
||||
|
||||
arrow::Result<int64_t> GetSize() override;
|
||||
|
||||
arrow::Result<int64_t> Tell() const override;
|
||||
|
||||
arrow::Status Seek( int64_t position ) override;
|
||||
|
||||
arrow::Status Close() override;
|
||||
|
||||
bool closed() const override;
|
||||
|
||||
private:
|
||||
const QByteArray& m_data;
|
||||
bool m_closed;
|
||||
int64_t m_position;
|
||||
};
|
||||
105
ApplicationLibCode/FileInterface/RifOsduWellLogReader.cpp
Normal file
105
ApplicationLibCode/FileInterface/RifOsduWellLogReader.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RifOsduWellLogReader.h"
|
||||
|
||||
#include "RifByteArrayArrowRandomAccessFile.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <arrow/array/array_primitive.h>
|
||||
#include <arrow/csv/api.h>
|
||||
#include <arrow/io/api.h>
|
||||
#include <arrow/scalar.h>
|
||||
#include <arrow/util/cancel.h>
|
||||
#include <parquet/arrow/reader.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<cvf::ref<RigOsduWellLogData>, QString> RifOsduWellLogReader::readWellLogData( const QByteArray& contents )
|
||||
{
|
||||
// Function to convert an entire column to std::vector<double>
|
||||
auto convertColumnToVector = []( const std::shared_ptr<arrow::ChunkedArray>& column ) -> std::vector<double>
|
||||
{
|
||||
auto convertChunkToVector = []( const std::shared_ptr<arrow::Array>& array ) -> std::vector<double>
|
||||
{
|
||||
std::vector<double> result;
|
||||
|
||||
auto double_array = std::static_pointer_cast<arrow::DoubleArray>( array );
|
||||
result.resize( double_array->length() );
|
||||
for ( int64_t i = 0; i < double_array->length(); ++i )
|
||||
{
|
||||
result[i] = double_array->Value( i );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
CAF_ASSERT( column->type()->id() == arrow::Type::DOUBLE );
|
||||
|
||||
std::vector<double> result;
|
||||
|
||||
// Iterate over each chunk in the column
|
||||
for ( int i = 0; i < column->num_chunks(); ++i )
|
||||
{
|
||||
std::shared_ptr<arrow::Array> chunk = column->chunk( i );
|
||||
std::vector<double> chunk_vector = convertChunkToVector( chunk );
|
||||
result.insert( result.end(), chunk_vector.begin(), chunk_vector.end() );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
arrow::MemoryPool* pool = arrow::default_memory_pool();
|
||||
|
||||
std::shared_ptr<arrow::io::RandomAccessFile> input = std::make_shared<RifByteArrayArrowRandomAccessFile>( contents );
|
||||
|
||||
// Open Parquet file reader
|
||||
std::unique_ptr<parquet::arrow::FileReader> arrow_reader;
|
||||
if ( !parquet::arrow::OpenFile( input, pool, &arrow_reader ).ok() )
|
||||
{
|
||||
return { nullptr, "Unable to read parquet data." };
|
||||
}
|
||||
|
||||
// Read entire file as a single Arrow table
|
||||
std::shared_ptr<arrow::Table> table;
|
||||
if ( !arrow_reader->ReadTable( &table ).ok() )
|
||||
{
|
||||
return { nullptr, "Unable to read parquet table." };
|
||||
}
|
||||
|
||||
auto logData = cvf::make_ref<RigOsduWellLogData>();
|
||||
for ( std::string columnName : table->ColumnNames() )
|
||||
{
|
||||
std::shared_ptr<arrow::ChunkedArray> column = table->GetColumnByName( columnName );
|
||||
|
||||
if ( column->type()->id() == arrow::Type::DOUBLE )
|
||||
{
|
||||
std::vector<double> columnVector = convertColumnToVector( column );
|
||||
logData->setValues( QString::fromStdString( columnName ), columnVector );
|
||||
}
|
||||
}
|
||||
|
||||
logData->finalizeData();
|
||||
|
||||
return { logData, "" };
|
||||
}
|
||||
36
ApplicationLibCode/FileInterface/RifOsduWellLogReader.h
Normal file
36
ApplicationLibCode/FileInterface/RifOsduWellLogReader.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RigOsduWellLogData.h"
|
||||
|
||||
#include "cvfObject.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class RifOsduWellLogReader
|
||||
{
|
||||
public:
|
||||
static std::pair<cvf::ref<RigOsduWellLogData>, QString> readWellLogData( const QByteArray& contents );
|
||||
};
|
||||
@@ -102,6 +102,7 @@
|
||||
#include "RimMultiPlot.h"
|
||||
#include "RimMultiPlotCollection.h"
|
||||
#include "RimObservedSummaryData.h"
|
||||
#include "RimOsduWellPath.h"
|
||||
#include "RimParameterResultCrossPlot.h"
|
||||
#include "RimPerforationCollection.h"
|
||||
#include "RimPerforationInterval.h"
|
||||
@@ -409,7 +410,9 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
|
||||
appendCreateCompletions( menuBuilder );
|
||||
menuBuilder.addSeparator();
|
||||
appendImportMenu( menuBuilder );
|
||||
bool addSeparatorBeforeMenu = false;
|
||||
bool addOsduImportMenuItem = dynamic_cast<RimOsduWellPath*>( firstUiItem ) != nullptr;
|
||||
appendImportMenu( menuBuilder, addSeparatorBeforeMenu, addOsduImportMenuItem );
|
||||
menuBuilder.addSeparator();
|
||||
appendExportCompletions( menuBuilder );
|
||||
menuBuilder.addSeparator();
|
||||
@@ -1498,7 +1501,7 @@ void RimContextCommandBuilder::appendScriptItems( caf::CmdFeatureMenuBuilder& me
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RimContextCommandBuilder::appendImportMenu( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu )
|
||||
int RimContextCommandBuilder::appendImportMenu( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu, bool addOsduImportMenuItem )
|
||||
{
|
||||
QStringList candidates;
|
||||
candidates << "RicWellPathsImportFileFeature";
|
||||
@@ -1507,6 +1510,8 @@ int RimContextCommandBuilder::appendImportMenu( caf::CmdFeatureMenuBuilder& menu
|
||||
candidates << "RicImportWellLogCsvFileFeature";
|
||||
candidates << "RicReloadWellPathFormationNamesFeature";
|
||||
|
||||
if ( addOsduImportMenuItem ) candidates << "RicImportWellLogOsduFeature";
|
||||
|
||||
return appendSubMenuWithCommands( menuBuilder, candidates, "Import", QIcon(), addSeparatorBeforeMenu );
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ private:
|
||||
static void appendScriptItems( caf::CmdFeatureMenuBuilder& menuBuilder, RimScriptCollection* scriptCollection );
|
||||
static void appendPlotTemplateItems( caf::CmdFeatureMenuBuilder& menuBuilder, RimPlotTemplateFolderItem* plotTemplateRoot );
|
||||
|
||||
static int appendImportMenu( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
|
||||
static int appendImportMenu( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false, bool addOsduMenuItem = false );
|
||||
static int appendCreateCompletions( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
|
||||
static int appendExportCompletions( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
|
||||
static int appendExportWellPaths( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
|
||||
|
||||
@@ -41,6 +41,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogExtractionCurve.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogLasFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCsvFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimOsduWellLog.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLog.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogFile.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellLogFileUtil.cpp
|
||||
|
||||
176
ApplicationLibCode/ProjectDataModel/WellLog/RimOsduWellLog.cpp
Normal file
176
ApplicationLibCode/ProjectDataModel/WellLog/RimOsduWellLog.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RimOsduWellLog.h"
|
||||
|
||||
#include "RiaGuiApplication.h"
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "RiaDateStringParser.h"
|
||||
#include "RiaFieldHandleTools.h"
|
||||
#include "RiaQDateTimeTools.h"
|
||||
|
||||
#include "RimFileWellPath.h"
|
||||
#include "RimTools.h"
|
||||
#include "RimWellLogChannel.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
#include "RimWellPlotTools.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimOsduWellLog, "OsduWellLog" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimOsduWellLog::RimOsduWellLog()
|
||||
{
|
||||
CAF_PDM_InitObject( "OSDU Well Log", ":/LasFile16x16.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_name, "Name", "" );
|
||||
m_name.uiCapability()->setUiReadOnly( true );
|
||||
RiaFieldHandleTools::disableWriteAndSetFieldHidden( &m_name );
|
||||
|
||||
m_date.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_wellLogId, "WellLogId", "Well Log Id" );
|
||||
m_wellLogId.uiCapability()->setUiReadOnly( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimOsduWellLog::~RimOsduWellLog()
|
||||
{
|
||||
m_wellLogChannelNames.deleteChildren();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOsduWellLog::wellName() const
|
||||
{
|
||||
return m_wellName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimOsduWellLog::hasFlowData() const
|
||||
{
|
||||
return RimWellPlotTools::hasFlowData( this );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<std::pair<double, double>>
|
||||
RimOsduWellLog::findMdAndChannelValuesForWellPath( const RimWellPath& wellPath, const QString& channelName, QString* unitString )
|
||||
{
|
||||
std::vector<RimOsduWellLog*> wellLogFiles = wellPath.descendantsIncludingThisOfType<RimOsduWellLog>();
|
||||
for ( RimOsduWellLog* wellLogFile : wellLogFiles )
|
||||
{
|
||||
RigOsduWellLogData* fileData = wellLogFile->wellLogData();
|
||||
std::vector<double> channelValues = fileData->values( channelName );
|
||||
if ( !channelValues.empty() )
|
||||
{
|
||||
if ( unitString )
|
||||
{
|
||||
*unitString = fileData->wellLogChannelUnitString( channelName );
|
||||
}
|
||||
std::vector<double> depthValues = fileData->depthValues();
|
||||
CVF_ASSERT( depthValues.size() == channelValues.size() );
|
||||
std::vector<std::pair<double, double>> depthValuePairs;
|
||||
for ( size_t i = 0; i < depthValues.size(); ++i )
|
||||
{
|
||||
depthValuePairs.push_back( std::make_pair( depthValues[i], channelValues[i] ) );
|
||||
}
|
||||
return depthValuePairs;
|
||||
}
|
||||
}
|
||||
return std::vector<std::pair<double, double>>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimOsduWellLog::isDateValid( const QDateTime dateTime )
|
||||
{
|
||||
return dateTime.isValid() && dateTime != DEFAULT_DATE_TIME;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
caf::PdmFieldHandle* RimOsduWellLog::userDescriptionField()
|
||||
{
|
||||
return &m_name;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOsduWellLog::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigOsduWellLogData* RimOsduWellLog::wellLogData()
|
||||
{
|
||||
return m_wellLogData.p();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOsduWellLog::setWellLogData( RigOsduWellLogData* wellLogData )
|
||||
{
|
||||
m_wellLogData = wellLogData;
|
||||
|
||||
m_wellLogChannelNames.deleteChildren();
|
||||
|
||||
for ( const QString& wellLogName : wellLogData->wellLogChannelNames() )
|
||||
{
|
||||
RimWellLogChannel* wellLog = new RimWellLogChannel();
|
||||
wellLog->setName( wellLogName );
|
||||
m_wellLogChannelNames.push_back( wellLog );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOsduWellLog::setWellLogId( const QString& wellLogId )
|
||||
{
|
||||
m_wellLogId = wellLogId;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOsduWellLog::wellLogId() const
|
||||
{
|
||||
return m_wellLogId;
|
||||
}
|
||||
74
ApplicationLibCode/ProjectDataModel/WellLog/RimOsduWellLog.h
Normal file
74
ApplicationLibCode/ProjectDataModel/WellLog/RimOsduWellLog.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimWellLog.h"
|
||||
|
||||
#include "RigOsduWellLogData.h"
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafPdmProxyValueField.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
class RimWellLogChannel;
|
||||
class RimWellPath;
|
||||
|
||||
class QString;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimOsduWellLog : public RimWellLog
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimOsduWellLog();
|
||||
~RimOsduWellLog() override;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
QString wellName() const override;
|
||||
|
||||
RigOsduWellLogData* wellLogData() override;
|
||||
void setWellLogData( RigOsduWellLogData* wellLogData );
|
||||
|
||||
void setWellLogId( const QString& wellLogId );
|
||||
QString wellLogId() const;
|
||||
|
||||
bool hasFlowData() const;
|
||||
|
||||
std::vector<std::pair<double, double>>
|
||||
findMdAndChannelValuesForWellPath( const RimWellPath& wellPath, const QString& channelName, QString* unitString = nullptr ) override;
|
||||
|
||||
private:
|
||||
caf::PdmFieldHandle* userDescriptionField() override;
|
||||
|
||||
static bool isDateValid( const QDateTime dateTime );
|
||||
|
||||
private:
|
||||
cvf::ref<RigOsduWellLogData> m_wellLogData;
|
||||
caf::PdmField<QString> m_wellName;
|
||||
caf::PdmField<QString> m_name;
|
||||
caf::PdmField<QString> m_wellLogId;
|
||||
};
|
||||
@@ -28,12 +28,14 @@
|
||||
#include "RiaTextStringTools.h"
|
||||
#include "RiaWellNameComparer.h"
|
||||
|
||||
#include "RifOsduWellLogReader.h"
|
||||
#include "RifOsduWellPathReader.h"
|
||||
#include "RifWellPathFormationsImporter.h"
|
||||
#include "RifWellPathImporter.h"
|
||||
|
||||
#include "RigEclipseCaseData.h"
|
||||
#include "RigMainGrid.h"
|
||||
#include "RigOsduWellLogData.h"
|
||||
#include "RigWellPath.h"
|
||||
|
||||
#include "RimEclipseCase.h"
|
||||
@@ -42,6 +44,7 @@
|
||||
#include "RimFileWellPath.h"
|
||||
#include "RimModeledWellPath.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimOsduWellLog.h"
|
||||
#include "RimOsduWellPath.h"
|
||||
#include "RimPerforationCollection.h"
|
||||
#include "RimProject.h"
|
||||
@@ -147,6 +150,17 @@ void RimWellPathCollection::loadDataAndUpdate()
|
||||
{
|
||||
caf::ProgressInfo progress( m_wellPaths.size(), "Reading well paths from file" );
|
||||
|
||||
auto makeOsduConnector = []( auto app )
|
||||
{
|
||||
RiaPreferencesOsdu* osduPreferences = app->preferences()->osduPreferences();
|
||||
const QString server = osduPreferences->server();
|
||||
const QString dataPartitionId = osduPreferences->dataPartitionId();
|
||||
const QString authority = osduPreferences->authority();
|
||||
const QString scopes = osduPreferences->scopes();
|
||||
const QString clientId = osduPreferences->clientId();
|
||||
return std::make_unique<RiaOsduConnector>( RiuMainWindow::instance(), server, dataPartitionId, authority, scopes, clientId );
|
||||
};
|
||||
|
||||
readWellPathFormationFiles();
|
||||
|
||||
for ( RimWellPath* wellPath : allWellPaths() )
|
||||
@@ -173,18 +187,8 @@ void RimWellPathCollection::loadDataAndUpdate()
|
||||
}
|
||||
else if ( oWPath )
|
||||
{
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
|
||||
RiaPreferencesOsdu* osduPreferences = app->preferences()->osduPreferences();
|
||||
|
||||
const QString server = osduPreferences->server();
|
||||
const QString dataParitionId = osduPreferences->dataPartitionId();
|
||||
const QString authority = osduPreferences->authority();
|
||||
const QString scopes = osduPreferences->scopes();
|
||||
const QString clientId = osduPreferences->clientId();
|
||||
|
||||
auto osduConnector =
|
||||
std::make_unique<RiaOsduConnector>( RiuMainWindow::instance(), server, dataParitionId, authority, scopes, clientId );
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
auto osduConnector = makeOsduConnector( app );
|
||||
|
||||
auto [wellPathGeometry, errorMessage] = loadWellPathGeometryFromOsdu( osduConnector.get(), oWPath->fileId() );
|
||||
if ( wellPathGeometry.notNull() )
|
||||
@@ -199,9 +203,9 @@ void RimWellPathCollection::loadDataAndUpdate()
|
||||
|
||||
if ( wellPath )
|
||||
{
|
||||
for ( RimWellLogFile* const wellLogFile : wellPath->wellLogFiles() )
|
||||
for ( RimWellLog* wellLog : wellPath->wellLogs() )
|
||||
{
|
||||
if ( wellLogFile )
|
||||
if ( RimWellLogFile* wellLogFile = dynamic_cast<RimWellLogFile*>( wellLog ) )
|
||||
{
|
||||
QString errorMessage;
|
||||
if ( !wellLogFile->readFile( &errorMessage ) )
|
||||
@@ -209,6 +213,16 @@ void RimWellPathCollection::loadDataAndUpdate()
|
||||
RiaLogging::warning( errorMessage );
|
||||
}
|
||||
}
|
||||
else if ( RimOsduWellLog* osduWellLog = dynamic_cast<RimOsduWellLog*>( wellLog ) )
|
||||
{
|
||||
RiaApplication* app = RiaApplication::instance();
|
||||
auto osduConnector = makeOsduConnector( app );
|
||||
auto [wellLogData, errorMessage] = loadWellLogFromOsdu( osduConnector.get(), osduWellLog->wellLogId() );
|
||||
if ( wellLogData.notNull() )
|
||||
{
|
||||
osduWellLog->setWellLogData( wellLogData.p() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RimStimPlanModelCollection* stimPlanModelCollection = wellPath->stimPlanModelCollection();
|
||||
@@ -419,9 +433,9 @@ std::vector<RimWellLogLasFile*> RimWellPathCollection::addWellLogs( const QStrin
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellPathCollection::addWellLog( RimWellLogFile* wellLogFile, RimWellPath* wellPath )
|
||||
void RimWellPathCollection::addWellLog( RimWellLog* wellLog, RimWellPath* wellPath )
|
||||
{
|
||||
wellPath->addWellLog( wellLogFile );
|
||||
wellPath->addWellLog( wellLog );
|
||||
sortWellsByName();
|
||||
updateAllRequiredEditors();
|
||||
}
|
||||
@@ -1060,3 +1074,18 @@ std::pair<cvf::ref<RigWellPath>, QString> RimWellPathCollection::loadWellPathGeo
|
||||
|
||||
return RifOsduWellPathReader::parseCsv( fileContents );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::pair<cvf::ref<RigOsduWellLogData>, QString> RimWellPathCollection::loadWellLogFromOsdu( RiaOsduConnector* osduConnector,
|
||||
const QString& wellLogId )
|
||||
{
|
||||
auto [fileContents, errorMessage] = osduConnector->requestWellLogParquetDataById( wellLogId );
|
||||
if ( !errorMessage.isEmpty() )
|
||||
{
|
||||
return { nullptr, errorMessage };
|
||||
}
|
||||
|
||||
return RifOsduWellLogReader::readWellLogData( fileContents );
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include "RigOsduWellLogData.h"
|
||||
#include "cafAppEnum.h"
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmField.h"
|
||||
@@ -41,6 +42,7 @@
|
||||
class RiaOsduConnector;
|
||||
class RifWellPathImporter;
|
||||
class RigWellPath;
|
||||
class RigOsduWellLogData;
|
||||
class RimFileWellPath;
|
||||
class RimEclipseView;
|
||||
class RimProject;
|
||||
@@ -49,6 +51,7 @@ class RimWellLogFile;
|
||||
class RimWellPath;
|
||||
class RifWellPathFormationsImporter;
|
||||
class RimWellMeasurementCollection;
|
||||
class RimWellLog;
|
||||
class cafTreeNode;
|
||||
class QString;
|
||||
|
||||
@@ -118,7 +121,7 @@ public:
|
||||
|
||||
std::vector<RimWellLogLasFile*> addWellLogs( const QStringList& filePaths, QStringList* errorMessages );
|
||||
void addWellPathFormations( const QStringList& filePaths );
|
||||
void addWellLog( RimWellLogFile* wellLogFile, RimWellPath* wellPath );
|
||||
void addWellLog( RimWellLog* wellLog, RimWellPath* wellPath );
|
||||
|
||||
void scheduleRedrawAffectedViews();
|
||||
|
||||
@@ -134,6 +137,8 @@ public:
|
||||
|
||||
static std::pair<cvf::ref<RigWellPath>, QString> loadWellPathGeometryFromOsdu( RiaOsduConnector* osduConnector, const QString& fileId );
|
||||
|
||||
static std::pair<cvf::ref<RigOsduWellLogData>, QString> loadWellLogFromOsdu( RiaOsduConnector* osduConnector, const QString& wellLogId );
|
||||
|
||||
protected:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellResultFrame.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigOsduWellLogData.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@@ -196,6 +197,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigDeclineCurveCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigOsduWellLogData.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
||||
152
ApplicationLibCode/ReservoirDataModel/RigOsduWellLogData.cpp
Normal file
152
ApplicationLibCode/ReservoirDataModel/RigOsduWellLogData.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RigOsduWellLogData.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigOsduWellLogData::RigOsduWellLogData()
|
||||
: RigWellLogData()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RigOsduWellLogData::~RigOsduWellLogData()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RigOsduWellLogData::wellLogChannelNames() const
|
||||
{
|
||||
QStringList channelNames;
|
||||
for ( const auto& channelPair : m_values )
|
||||
{
|
||||
channelNames << channelPair.first;
|
||||
}
|
||||
|
||||
return channelNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RigOsduWellLogData::depthValues() const
|
||||
{
|
||||
return values( m_depthLogName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RigOsduWellLogData::tvdMslValues() const
|
||||
{
|
||||
return values( m_tvdMslLogName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RigOsduWellLogData::tvdRkbValues() const
|
||||
{
|
||||
// Not supported
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigOsduWellLogData::setValues( const QString& name, const std::vector<double>& values )
|
||||
{
|
||||
m_values[name] = values;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<double> RigOsduWellLogData::values( const QString& name ) const
|
||||
{
|
||||
if ( auto it = m_values.find( name ); it != m_values.end() ) return it->second;
|
||||
return std::vector<double>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigOsduWellLogData::hasTvdMslChannel() const
|
||||
{
|
||||
return !m_tvdMslLogName.isEmpty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigOsduWellLogData::hasTvdRkbChannel() const
|
||||
{
|
||||
return !m_tvdRkbLogName.isEmpty();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RigOsduWellLogData::depthUnitString() const
|
||||
{
|
||||
return wellLogChannelUnitString( m_tvdMslLogName );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RigOsduWellLogData::wellLogChannelUnitString( const QString& wellLogChannelName ) const
|
||||
{
|
||||
auto unit = m_units.find( wellLogChannelName );
|
||||
if ( unit != m_units.end() )
|
||||
return unit->second;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
double RigOsduWellLogData::getMissingValue() const
|
||||
{
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigOsduWellLogData::finalizeData()
|
||||
{
|
||||
for ( auto [columnName, values] : m_values )
|
||||
{
|
||||
if ( columnName.toUpper() == "TVDMSL" || columnName.toUpper().contains( "TVD" ) )
|
||||
{
|
||||
m_tvdMslLogName = columnName;
|
||||
}
|
||||
else if ( columnName.toUpper() == "DEPTH" )
|
||||
{
|
||||
m_depthLogName = "DEPTH";
|
||||
}
|
||||
}
|
||||
}
|
||||
68
ApplicationLibCode/ReservoirDataModel/RigOsduWellLogData.h
Normal file
68
ApplicationLibCode/ReservoirDataModel/RigOsduWellLogData.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2024- 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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RigWellLogData.h"
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class RimWellLogCurve;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RigOsduWellLogData : public RigWellLogData
|
||||
{
|
||||
public:
|
||||
RigOsduWellLogData();
|
||||
~RigOsduWellLogData() override;
|
||||
|
||||
QStringList wellLogChannelNames() const override;
|
||||
|
||||
std::vector<double> depthValues() const override;
|
||||
std::vector<double> tvdMslValues() const override;
|
||||
std::vector<double> tvdRkbValues() const override;
|
||||
|
||||
void setValues( const QString& name, const std::vector<double>& values );
|
||||
std::vector<double> values( const QString& name ) const override;
|
||||
|
||||
QString wellLogChannelUnitString( const QString& wellLogChannelName ) const override;
|
||||
|
||||
bool hasTvdMslChannel() const override;
|
||||
bool hasTvdRkbChannel() const override;
|
||||
|
||||
double getMissingValue() const override;
|
||||
|
||||
void finalizeData();
|
||||
|
||||
private:
|
||||
QString depthUnitString() const override;
|
||||
|
||||
QString m_depthLogName;
|
||||
QString m_tvdMslLogName;
|
||||
QString m_tvdRkbLogName;
|
||||
|
||||
std::map<QString, std::vector<double>> m_values;
|
||||
std::map<QString, QString> m_units;
|
||||
};
|
||||
Reference in New Issue
Block a user