Add action for downloading and parsing well log from OSDU Wellbore DDMS.

This commit is contained in:
Kristian Bendiksen
2024-05-27 11:24:00 +02:00
parent 5be47b3d2c
commit 23d716754e
20 changed files with 1094 additions and 46 deletions

View File

@@ -194,6 +194,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicExportSummaryCalculationExpressionsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportSummaryCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogOsduFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomVfpPlotFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewCustomVfpPlotFeature.cpp

View File

@@ -120,7 +120,7 @@ void RiaOsduConnector::requestFieldsByName( const QString& server, const QString
params["limit"] = "10000"; params["limit"] = "10000";
params["query"] = "data.FieldName:" + fieldName; params["query"] = "data.FieldName:" + fieldName;
auto reply = makeRequest( params, server, dataPartitionId, token ); auto reply = makeSearchRequest( params, server, dataPartitionId, token );
connect( reply, connect( reply,
&QNetworkReply::finished, &QNetworkReply::finished,
[this, reply]() [this, reply]()
@@ -150,7 +150,7 @@ void RiaOsduConnector::requestWellsByFieldId( const QString& server, const QStri
params["limit"] = "10000"; params["limit"] = "10000";
params["query"] = QString( "nested(data.GeoContexts, (FieldID:\"%1\"))" ).arg( fieldId ); 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, connect( reply,
&QNetworkReply::finished, &QNetworkReply::finished,
[this, reply, fieldId]() [this, reply, fieldId]()
@@ -180,7 +180,7 @@ void RiaOsduConnector::requestWellboresByWellId( const QString& server, const QS
params["limit"] = "10000"; params["limit"] = "10000";
params["query"] = "data.WellID: \"" + wellId + "\""; params["query"] = "data.WellID: \"" + wellId + "\"";
auto reply = makeRequest( params, server, dataPartitionId, token ); auto reply = makeSearchRequest( params, server, dataPartitionId, token );
connect( reply, connect( reply,
&QNetworkReply::finished, &QNetworkReply::finished,
[this, reply, wellId]() [this, reply, wellId]()
@@ -221,7 +221,7 @@ void RiaOsduConnector::requestWellboreTrajectoryByWellboreId( const QString& ser
params["limit"] = "10000"; params["limit"] = "10000";
params["query"] = "data.WellboreID: \"" + wellboreId + "\""; params["query"] = "data.WellboreID: \"" + wellboreId + "\"";
auto reply = makeRequest( params, server, dataPartitionId, token ); auto reply = makeSearchRequest( params, server, dataPartitionId, token );
connect( reply, connect( reply,
&QNetworkReply::finished, &QNetworkReply::finished,
[this, reply, wellboreId]() [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 ) void RiaOsduConnector::requestFileDownloadByFileId( const QString& server, const QString& dataPartitionId, const QString& token, const QString& fileId )
{ {
RiaLogging::info( "Requesting download of file id: " + 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, connect( reply,
&QNetworkReply::finished, &QNetworkReply::finished,
[this, reply, fileId]() [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"; 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, QString RiaOsduConnector::constructWellLogDownloadUrl( const QString& server, const QString& wellLogId )
const QString& server, {
const QString& dataPartitionId, return server + "/api/os-wellbore-ddms/ddms/v3/welllogs/" + wellLogId + "/data";
const QString& token ) }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QNetworkReply* RiaOsduConnector::makeSearchRequest( const std::map<QString, QString>& parameters,
const QString& server,
const QString& dataPartitionId,
const QString& token )
{ {
QNetworkRequest m_networkRequest; QNetworkRequest m_networkRequest;
m_networkRequest.setUrl( QUrl( constructSearchUrl( server ) ) ); m_networkRequest.setUrl( QUrl( constructSearchUrl( server ) ) );
addStandardHeader( m_networkRequest, token, dataPartitionId ); addStandardHeader( m_networkRequest, token, dataPartitionId, CONTENT_TYPE_JSON );
QJsonObject obj; QJsonObject obj;
for ( auto [key, value] : parameters ) 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( "Authorization", "Bearer " + token.toUtf8() );
networkRequest.setRawHeader( QByteArray( "Data-Partition-Id" ), dataPartitionId.toUtf8() ); networkRequest.setRawHeader( QByteArray( "Data-Partition-Id" ), dataPartitionId.toUtf8() );
} }
@@ -495,17 +508,14 @@ void RiaOsduConnector::addStandardHeader( QNetworkRequest& networkRequest, const
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
QNetworkReply* 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 ) ); auto reply = m_networkAccessManager->get( networkRequest );
addStandardHeader( m_networkRequest, token, dataPartitionId );
auto reply = m_networkAccessManager->get( m_networkRequest );
return reply; return reply;
} }
@@ -635,6 +645,7 @@ std::pair<QString, QString> RiaOsduConnector::requestFileContentsById( const QSt
this, this,
SLOT( fileDownloadComplete( const QString&, const QString& ) ) ); SLOT( fileDownloadComplete( const QString&, const QString& ) ) );
connect( this, SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), &loop2, SLOT( quit() ) ); connect( this, SIGNAL( fileDownloadFinished( const QString&, const QString& ) ), &loop2, SLOT( quit() ) );
requestFileDownloadByFileId( m_server, m_dataPartitionId, m_token, fileId ); requestFileDownloadByFileId( m_server, m_dataPartitionId, m_token, fileId );
loop2.exec(); loop2.exec();
@@ -650,3 +661,66 @@ std::pair<QString, QString> RiaOsduConnector::requestFileContentsById( const QSt
return { fileContent, "" }; 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;
}

View File

@@ -59,9 +59,12 @@ public:
void requestWellboresByWellId( const QString& wellId ); void requestWellboresByWellId( const QString& wellId );
void requestWellboreTrajectoryByWellboreId( const QString& wellboreId ); void requestWellboreTrajectoryByWellboreId( const QString& wellboreId );
void requestFileDownloadByFileId( const QString& fileId ); 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<QString, QString> requestFileContentsById( const QString& fileId );
std::pair<QByteArray, QString> requestWellLogParquetDataById( const QString& wellLogId );
QString wellIdForWellboreId( const QString& wellboreId ) const; QString wellIdForWellboreId( const QString& wellboreId ) const;
QString server() const; QString server() const;
@@ -81,9 +84,11 @@ public slots:
void saveFile( QNetworkReply* reply, const QString& fileId ); void saveFile( QNetworkReply* reply, const QString& fileId );
void accessGranted(); void accessGranted();
void fileDownloadComplete( const QString& fileId, const QString& filePath ); void fileDownloadComplete( const QString& fileId, const QString& filePath );
void wellLogDownloadComplete( const QByteArray&, const QString& url );
signals: signals:
void fileDownloadFinished( const QString& fileId, const QString& filePath ); void fileDownloadFinished( const QString& fileId, const QString& filePath );
void wellLogDownloadFinished( const QByteArray& contents, const QString& url );
void fieldsFinished(); void fieldsFinished();
void wellsFinished(); void wellsFinished();
void wellboresFinished( const QString& wellId ); void wellboresFinished( const QString& wellId );
@@ -91,12 +96,14 @@ signals:
void tokenReady( const QString& token ); void tokenReady( const QString& token );
private: 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* QNetworkReply* makeSearchRequest( const std::map<QString, QString>& parameters,
makeRequest( const std::map<QString, QString>& parameters, const QString& server, const QString& dataPartitionId, const QString& token ); 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 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 ); 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 generateRandomString( int length = 20 );
static QString constructSearchUrl( const QString& server ); 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 constructAuthUrl( const QString& authority );
static QString constructTokenUrl( const QString& authority ); static QString constructTokenUrl( const QString& authority );
static QString constructWellLogDownloadUrl( const QString& server, const QString& wellLogId );
QOAuth2AuthorizationCodeFlow* m_osdu; QOAuth2AuthorizationCodeFlow* m_osdu;
QNetworkAccessManager* m_networkAccessManager; QNetworkAccessManager* m_networkAccessManager;
@@ -128,9 +136,13 @@ private:
std::map<QString, std::vector<OsduWellbore>> m_wellbores; std::map<QString, std::vector<OsduWellbore>> m_wellbores;
std::map<QString, std::vector<OsduWellboreTrajectory>> m_wellboreTrajectories; std::map<QString, std::vector<OsduWellboreTrajectory>> m_wellboreTrajectories;
QString m_filePath; QString m_filePath;
QByteArray m_wellLogContents;
static inline const QString FIELD_KIND = "osdu:wks:master-data--Field:1.0.0"; 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 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_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 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";
}; };

View 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" );
}

View 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;
};

View File

@@ -98,6 +98,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.h ${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.h
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.h ${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.h
${CMAKE_CURRENT_LIST_DIR}/RifAsciiDataParseOptions.h ${CMAKE_CURRENT_LIST_DIR}/RifAsciiDataParseOptions.h
${CMAKE_CURRENT_LIST_DIR}/RifByteArrayArrowRandomAccessFile.h
) )
set(SOURCE_GROUP_SOURCE_FILES set(SOURCE_GROUP_SOURCE_FILES
@@ -194,6 +195,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RifSummaryCalculationExporter.cpp
${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader.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}) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@@ -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;
}

View File

@@ -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;
};

View 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, "" };
}

View 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 );
};

View File

@@ -102,6 +102,7 @@
#include "RimMultiPlot.h" #include "RimMultiPlot.h"
#include "RimMultiPlotCollection.h" #include "RimMultiPlotCollection.h"
#include "RimObservedSummaryData.h" #include "RimObservedSummaryData.h"
#include "RimOsduWellPath.h"
#include "RimParameterResultCrossPlot.h" #include "RimParameterResultCrossPlot.h"
#include "RimPerforationCollection.h" #include "RimPerforationCollection.h"
#include "RimPerforationInterval.h" #include "RimPerforationInterval.h"
@@ -409,7 +410,9 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
appendCreateCompletions( menuBuilder ); appendCreateCompletions( menuBuilder );
menuBuilder.addSeparator(); menuBuilder.addSeparator();
appendImportMenu( menuBuilder ); bool addSeparatorBeforeMenu = false;
bool addOsduImportMenuItem = dynamic_cast<RimOsduWellPath*>( firstUiItem ) != nullptr;
appendImportMenu( menuBuilder, addSeparatorBeforeMenu, addOsduImportMenuItem );
menuBuilder.addSeparator(); menuBuilder.addSeparator();
appendExportCompletions( menuBuilder ); appendExportCompletions( menuBuilder );
menuBuilder.addSeparator(); 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; QStringList candidates;
candidates << "RicWellPathsImportFileFeature"; candidates << "RicWellPathsImportFileFeature";
@@ -1507,6 +1510,8 @@ int RimContextCommandBuilder::appendImportMenu( caf::CmdFeatureMenuBuilder& menu
candidates << "RicImportWellLogCsvFileFeature"; candidates << "RicImportWellLogCsvFileFeature";
candidates << "RicReloadWellPathFormationNamesFeature"; candidates << "RicReloadWellPathFormationNamesFeature";
if ( addOsduImportMenuItem ) candidates << "RicImportWellLogOsduFeature";
return appendSubMenuWithCommands( menuBuilder, candidates, "Import", QIcon(), addSeparatorBeforeMenu ); return appendSubMenuWithCommands( menuBuilder, candidates, "Import", QIcon(), addSeparatorBeforeMenu );
} }

View File

@@ -51,7 +51,7 @@ private:
static void appendScriptItems( caf::CmdFeatureMenuBuilder& menuBuilder, RimScriptCollection* scriptCollection ); static void appendScriptItems( caf::CmdFeatureMenuBuilder& menuBuilder, RimScriptCollection* scriptCollection );
static void appendPlotTemplateItems( caf::CmdFeatureMenuBuilder& menuBuilder, RimPlotTemplateFolderItem* plotTemplateRoot ); 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 appendCreateCompletions( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
static int appendExportCompletions( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false ); static int appendExportCompletions( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );
static int appendExportWellPaths( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false ); static int appendExportWellPaths( caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false );

View File

@@ -41,6 +41,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimWellLogExtractionCurve.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogExtractionCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellLogLasFile.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogLasFile.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCsvFile.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogCsvFile.cpp
${CMAKE_CURRENT_LIST_DIR}/RimOsduWellLog.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellLog.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLog.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellLogFile.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogFile.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellLogFileUtil.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogFileUtil.cpp

View 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;
}

View 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;
};

View File

@@ -28,12 +28,14 @@
#include "RiaTextStringTools.h" #include "RiaTextStringTools.h"
#include "RiaWellNameComparer.h" #include "RiaWellNameComparer.h"
#include "RifOsduWellLogReader.h"
#include "RifOsduWellPathReader.h" #include "RifOsduWellPathReader.h"
#include "RifWellPathFormationsImporter.h" #include "RifWellPathFormationsImporter.h"
#include "RifWellPathImporter.h" #include "RifWellPathImporter.h"
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigOsduWellLogData.h"
#include "RigWellPath.h" #include "RigWellPath.h"
#include "RimEclipseCase.h" #include "RimEclipseCase.h"
@@ -42,6 +44,7 @@
#include "RimFileWellPath.h" #include "RimFileWellPath.h"
#include "RimModeledWellPath.h" #include "RimModeledWellPath.h"
#include "RimOilField.h" #include "RimOilField.h"
#include "RimOsduWellLog.h"
#include "RimOsduWellPath.h" #include "RimOsduWellPath.h"
#include "RimPerforationCollection.h" #include "RimPerforationCollection.h"
#include "RimProject.h" #include "RimProject.h"
@@ -147,6 +150,17 @@ void RimWellPathCollection::loadDataAndUpdate()
{ {
caf::ProgressInfo progress( m_wellPaths.size(), "Reading well paths from file" ); 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(); readWellPathFormationFiles();
for ( RimWellPath* wellPath : allWellPaths() ) for ( RimWellPath* wellPath : allWellPaths() )
@@ -173,18 +187,8 @@ void RimWellPathCollection::loadDataAndUpdate()
} }
else if ( oWPath ) else if ( oWPath )
{ {
RiaApplication* app = RiaApplication::instance(); RiaApplication* app = RiaApplication::instance();
auto osduConnector = makeOsduConnector( app );
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 );
auto [wellPathGeometry, errorMessage] = loadWellPathGeometryFromOsdu( osduConnector.get(), oWPath->fileId() ); auto [wellPathGeometry, errorMessage] = loadWellPathGeometryFromOsdu( osduConnector.get(), oWPath->fileId() );
if ( wellPathGeometry.notNull() ) if ( wellPathGeometry.notNull() )
@@ -199,9 +203,9 @@ void RimWellPathCollection::loadDataAndUpdate()
if ( wellPath ) if ( wellPath )
{ {
for ( RimWellLogFile* const wellLogFile : wellPath->wellLogFiles() ) for ( RimWellLog* wellLog : wellPath->wellLogs() )
{ {
if ( wellLogFile ) if ( RimWellLogFile* wellLogFile = dynamic_cast<RimWellLogFile*>( wellLog ) )
{ {
QString errorMessage; QString errorMessage;
if ( !wellLogFile->readFile( &errorMessage ) ) if ( !wellLogFile->readFile( &errorMessage ) )
@@ -209,6 +213,16 @@ void RimWellPathCollection::loadDataAndUpdate()
RiaLogging::warning( errorMessage ); 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(); 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(); sortWellsByName();
updateAllRequiredEditors(); updateAllRequiredEditors();
} }
@@ -1060,3 +1074,18 @@ std::pair<cvf::ref<RigWellPath>, QString> RimWellPathCollection::loadWellPathGeo
return RifOsduWellPathReader::parseCsv( fileContents ); 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 );
}

View File

@@ -22,6 +22,7 @@
#include "RiaDefines.h" #include "RiaDefines.h"
#include "RigOsduWellLogData.h"
#include "cafAppEnum.h" #include "cafAppEnum.h"
#include "cafPdmChildArrayField.h" #include "cafPdmChildArrayField.h"
#include "cafPdmField.h" #include "cafPdmField.h"
@@ -41,6 +42,7 @@
class RiaOsduConnector; class RiaOsduConnector;
class RifWellPathImporter; class RifWellPathImporter;
class RigWellPath; class RigWellPath;
class RigOsduWellLogData;
class RimFileWellPath; class RimFileWellPath;
class RimEclipseView; class RimEclipseView;
class RimProject; class RimProject;
@@ -49,6 +51,7 @@ class RimWellLogFile;
class RimWellPath; class RimWellPath;
class RifWellPathFormationsImporter; class RifWellPathFormationsImporter;
class RimWellMeasurementCollection; class RimWellMeasurementCollection;
class RimWellLog;
class cafTreeNode; class cafTreeNode;
class QString; class QString;
@@ -118,7 +121,7 @@ public:
std::vector<RimWellLogLasFile*> addWellLogs( const QStringList& filePaths, QStringList* errorMessages ); std::vector<RimWellLogLasFile*> addWellLogs( const QStringList& filePaths, QStringList* errorMessages );
void addWellPathFormations( const QStringList& filePaths ); void addWellPathFormations( const QStringList& filePaths );
void addWellLog( RimWellLogFile* wellLogFile, RimWellPath* wellPath ); void addWellLog( RimWellLog* wellLog, RimWellPath* wellPath );
void scheduleRedrawAffectedViews(); 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<RigWellPath>, QString> loadWellPathGeometryFromOsdu( RiaOsduConnector* osduConnector, const QString& fileId );
static std::pair<cvf::ref<RigOsduWellLogData>, QString> loadWellLogFromOsdu( RiaOsduConnector* osduConnector, const QString& wellLogId );
protected: protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;

View File

@@ -99,6 +99,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigWellResultFrame.h ${CMAKE_CURRENT_LIST_DIR}/RigWellResultFrame.h
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.h ${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.h
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.h ${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.h
${CMAKE_CURRENT_LIST_DIR}/RigOsduWellLogData.h
) )
set(SOURCE_GROUP_SOURCE_FILES set(SOURCE_GROUP_SOURCE_FILES
@@ -196,6 +197,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigDeclineCurveCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RigDeclineCurveCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.cpp
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.cpp ${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.cpp
${CMAKE_CURRENT_LIST_DIR}/RigOsduWellLogData.cpp
) )
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View 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";
}
}
}

View 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;
};