Support optimized surface export from grid model layers

* #7885 Update opm-common with optimized coordinate import
* #7885 Allow null as default result from a script method
* #7885 Propagate default parameter values to generated Python code
* #7885 Add CommandRouter as hub for worker methods
* #7885 Add support for use of CommadRouter from Python
This commit is contained in:
Magne Sjaastad 2021-08-23 11:58:32 +02:00 committed by GitHub
parent 2ef22f518c
commit 3a94078867
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1587 additions and 863 deletions

View File

@ -37,6 +37,7 @@
#include "RicfCommandFileExecutor.h"
#include "RicfCommandObject.h"
#include "CommandRouter/RimCommandRouter.h"
#include "Rim2dIntersectionViewCollection.h"
#include "RimAnnotationCollection.h"
#include "RimAnnotationInViewCollection.h"
@ -149,6 +150,8 @@ RiaApplication::RiaApplication()
#endif
setLastUsedDialogDirectory( "MULTICASEIMPORT", "/" );
m_commandRouter = std::make_unique<RimCommandRouter>();
}
//--------------------------------------------------------------------------------------------------
@ -301,6 +304,14 @@ RimProject* RiaApplication::project()
return m_project.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCommandRouter* RiaApplication::commandRouter()
{
return m_commandRouter.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -52,6 +52,7 @@ class RiaSocketServer;
class RigEclipseCaseData;
class RimCommandObject;
class RimCommandRouter;
class RimEclipseCase;
class RimEclipseView;
class RimWellPath;
@ -115,7 +116,8 @@ public:
RimGridView* activeMainOrComparisonGridView();
int currentScriptCaseId() const;
RimProject* project();
RimProject* project();
RimCommandRouter* commandRouter();
void createMockModel();
void createResultsMockModel();
@ -234,6 +236,8 @@ protected:
caf::PdmPointer<Rim3dView> m_activeReservoirView;
std::unique_ptr<RimProject> m_project;
std::unique_ptr<RimCommandRouter> m_commandRouter;
QPointer<RiaSocketServer> m_socketServer;
std::unique_ptr<caf::UiProcess> m_workerProcess;

View File

@ -184,6 +184,7 @@ list(
ProjectDataModel/WellMeasurement/CMakeLists_files.cmake
ProjectDataModel/WellPath/CMakeLists_files.cmake
ProjectDataModelCommands/CMakeLists_files.cmake
ProjectDataModelCommands/CommandRouter/CMakeLists_files.cmake
GeoMech/GeoMechVisualization/CMakeLists_files.cmake
ModelVisualization/CMakeLists_files.cmake
ModelVisualization/GridBox/CMakeLists_files.cmake
@ -400,7 +401,8 @@ target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARIES}
target_include_directories(
${PROJECT_NAME}
PRIVATE ${CMAKE_BINARY_DIR}/Generated
PUBLIC ${CMAKE_SOURCE_DIR}/ApplicationLibCode/Application
PUBLIC ${CMAKE_SOURCE_DIR}/ApplicationLibCode
${CMAKE_SOURCE_DIR}/ApplicationLibCode/Application
${CMAKE_SOURCE_DIR}/ApplicationLibCode/Application/Tools
${CMAKE_SOURCE_DIR}/ApplicationLibCode/CommandFileInterface
${CMAKE_SOURCE_DIR}/ApplicationLibCode/CommandFileInterface/Core

View File

@ -0,0 +1,20 @@
set (SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCommandRouter.h
${CMAKE_CURRENT_LIST_DIR}/RimcExtractSurfaces.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCommandRouter.cpp
${CMAKE_CURRENT_LIST_DIR}/RimcExtractSurfaces.cpp
)
list(APPEND CODE_HEADER_FILES
${SOURCE_GROUP_HEADER_FILES}
)
list(APPEND CODE_SOURCE_FILES
${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "ProjectDataModelCommands\\CommandRouter" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@ -0,0 +1,74 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimCommandRouter.h"
#include "cafPdmObjectScriptingCapability.h"
CAF_PDM_SOURCE_INIT( RimCommandRouter, "RimCommandRouter" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCommandRouter::RimCommandRouter()
{
CAF_PDM_InitScriptableObjectWithNameAndComment( "CommandRouter",
"",
"",
"",
"CommandRouter",
"The CommandRouter is used to call code independent to the "
"project" );
}
//--------------------------------------------------------------------------------------------------
///
/// RimCommandRouterMethod
///
///
///
///
//--------------------------------------------------------------------------------------------------
RimCommandRouterMethod::RimCommandRouterMethod( PdmObjectHandle* self )
: caf::PdmObjectMethod( self )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCommandRouterMethod::isNullptrValidResult() const
{
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimCommandRouterMethod::resultIsPersistent() const
{
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<caf::PdmObjectHandle> RimCommandRouterMethod::defaultResult() const
{
return nullptr;
}

View File

@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmObject.h"
#include "cafPdmObjectMethod.h"
//--------------------------------------------------------------------------------------------------
/// Usually, command router classes will require only the execute() method. Derive from RimCommandRouterMethod to get
/// default values for the other required virtual functions
//--------------------------------------------------------------------------------------------------
class RimCommandRouterMethod : public caf::PdmObjectMethod
{
public:
RimCommandRouterMethod( PdmObjectHandle* self );
bool isNullptrValidResult() const override;
bool resultIsPersistent() const override;
std::unique_ptr<PdmObjectHandle> defaultResult() const override;
};
//==================================================================================================
/// The command router object is used as a hub for data processing commands independent to a ResInsight project
/// (RimProject). The intention for this object is to have a hub to connect to when using ResInsight as a data
/// processing server. Avoid dependency on a GUI, and make sure the execute() commands works in headless mode.
///
/// The router object is made available from Python using
///
/// resinsight = rips.Instance.find()
/// command_router = resinsight.command_router
///
/// Steps to add a new processing function
/// 1) Create a new class deriving from RimCommandRouterMethod
/// 2) Add Pdm fields to this class. These fields will be made available as parameters from Python
/// 2) Implement data processing in execute() method using the input values specified in the Pdm fields
///
/// Example : RimcCommandRouter_extractSurfaces
///
//==================================================================================================
class RimCommandRouter : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimCommandRouter();
};

View File

@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimcExtractSurfaces.h"
#include "RiaLogging.h"
#include "RifSurfaceExporter.h"
#include "RimCommandRouter.h"
#include "opm/io/eclipse/EGrid.hpp"
#include "cafPdmAbstractFieldScriptingCapability.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectHandle.h"
#include <QDir>
#include <QFileInfo>
#include <memory>
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimCommandRouter, RimcCommandRouter_extractSurfaces, "ExtractSurfaces" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimcCommandRouter_extractSurfaces::RimcCommandRouter_extractSurfaces( caf::PdmObjectHandle* self )
: RimCommandRouterMethod( self )
{
CAF_PDM_InitObject( "Extract Layer Surface", "", "", "Extract Layer Surface" );
CAF_PDM_InitScriptableField( &m_gridModelFilename, "GridModelFilename", QString(), "Grid Model Case Filename", "", "", "" );
CAF_PDM_InitScriptableField( &m_layers, "Layers", std::vector<int>(), "Layers", "", "", "" );
CAF_PDM_InitScriptableField( &m_minimumI, "MinimumI", -1, "Minimum I", "", "", "" );
CAF_PDM_InitScriptableField( &m_maximumI, "MaximumI", -1, "Maximum I", "", "", "" );
CAF_PDM_InitScriptableField( &m_minimumJ, "MinimumJ", -1, "Minimum J", "", "", "" );
CAF_PDM_InitScriptableField( &m_maximumJ, "MaximumJ", -1, "Maximum J", "", "", "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmObjectHandle* RimcCommandRouter_extractSurfaces::execute()
{
try
{
std::string filename = m_gridModelFilename().toStdString();
Opm::EclIO::EGrid grid1( filename );
auto dims = grid1.dimension();
int minI = m_minimumI() == -1 ? 0 : m_minimumI();
int maxI = m_maximumJ() == -1 ? dims[0] - 1 : m_maximumI();
int minJ = m_minimumI() == -1 ? 0 : m_minimumJ();
int maxJ = m_minimumI() == -1 ? dims[1] - 1 : m_maximumJ();
std::array<int, 4> range = { minI, maxI, minJ, maxJ };
for ( auto layer : m_layers() )
{
bool bottom = false;
auto xyz_data = grid1.getXYZ_layer( layer, range, bottom );
auto mapAxis = grid1.get_mapaxes();
// Create surface from coords
std::vector<unsigned> triangleIndices;
std::vector<cvf::Vec3d> vertices;
unsigned startOfCellCoordIndex = 0;
while ( startOfCellCoordIndex + 4 < xyz_data.size() )
{
for ( size_t cornerIdx = 0; cornerIdx < 4; cornerIdx++ )
{
auto coord1 = xyz_data[startOfCellCoordIndex + cornerIdx];
auto cvfCoord = cvf::Vec3d( coord1[0], coord1[1], -coord1[2] );
if ( !mapAxis.empty() )
{
cvfCoord[0] += mapAxis[2];
cvfCoord[1] += mapAxis[3];
}
vertices.push_back( cvfCoord );
}
triangleIndices.push_back( startOfCellCoordIndex );
triangleIndices.push_back( startOfCellCoordIndex + 3 );
triangleIndices.push_back( startOfCellCoordIndex + 2 );
triangleIndices.push_back( startOfCellCoordIndex );
triangleIndices.push_back( startOfCellCoordIndex + 1 );
triangleIndices.push_back( startOfCellCoordIndex + 3 );
// Coordinates are given for each four corners for each cell of the surface
startOfCellCoordIndex += 4;
}
// Write to TS file on disk
QFileInfo fi( m_gridModelFilename );
QString surfaceFilename = fi.absoluteDir().absolutePath() +
QString( "/surfaceexport/layer-%1.ts" ).arg( layer );
// TODO: Add more info in surface comment
if ( !RifSurfaceExporter::writeGocadTSurfFile( surfaceFilename, "Surface comment", vertices, triangleIndices ) )
{
RiaLogging::error( "Failed to export surface data to " + surfaceFilename );
}
else
{
RiaLogging::error( "Successfully exported surface data to " + surfaceFilename );
}
}
}
catch ( ... )
{
RiaLogging::error( "Error during creation of surface data for model " + m_gridModelFilename() );
}
return nullptr;
}

View File

@ -0,0 +1,50 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimCommandRouter.h"
#include "cafPdmField.h"
#include "cvfVector3.h"
#include <QString>
#include <memory>
//==================================================================================================
///
//==================================================================================================
class RimcCommandRouter_extractSurfaces : public RimCommandRouterMethod
{
CAF_PDM_HEADER_INIT;
public:
RimcCommandRouter_extractSurfaces( caf::PdmObjectHandle* self );
caf::PdmObjectHandle* execute() override;
private:
caf::PdmField<QString> m_gridModelFilename;
caf::PdmField<std::vector<int>> m_layers;
caf::PdmField<int> m_minimumI;
caf::PdmField<int> m_maximumI;
caf::PdmField<int> m_minimumJ;
caf::PdmField<int> m_maximumJ;
};

View File

@ -182,16 +182,7 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
}
else
{
QString valueString;
// Always make sure the default value for a ptrField is empty string
if ( !field->hasPtrReferencedObjects() )
{
QTextStream valueStream( &valueString );
scriptability->readFromField( valueStream, true, true );
}
if ( valueString.isEmpty() ) valueString = QString( "\"\"" );
valueString = pythonifyDataValue( valueString );
QString valueString = getDefaultValue( field );
QString fieldCode =
QString( " self.%1 = %2\n" ).arg( snake_field_name ).arg( valueString );
@ -264,16 +255,20 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
QStringList argumentComments;
outputArgumentStrings.push_back( QString( "\"%1\"" ).arg( methodName ) );
QString returnComment = method->defaultResult()->xmlCapability()->classKeyword();
QString returnComment;
if ( method->defaultResult() ) returnComment = method->defaultResult()->xmlCapability()->classKeyword();
for ( auto field : arguments )
{
bool isList = field->xmlCapability()->isVectorField();
QString defaultValue = isList ? "[]" : "None";
auto scriptability = field->capability<PdmAbstractFieldScriptingCapability>();
auto argumentName = camelToSnakeCase( scriptability->scriptFieldName() );
auto dataType = dataTypeString( field, false );
auto scriptability = field->capability<PdmAbstractFieldScriptingCapability>();
auto argumentName = camelToSnakeCase( scriptability->scriptFieldName() );
auto dataType = dataTypeString( field, false );
bool isList = field->xmlCapability()->isVectorField();
if ( isList ) dataType = "List of " + dataType;
QString defaultValue = getDefaultValue( field );
inputArgumentStrings.push_back( QString( "%1=%2" ).arg( argumentName ).arg( defaultValue ) );
outputArgumentStrings.push_back( QString( "%1=%1" ).arg( argumentName ) );
argumentComments.push_back(
@ -406,6 +401,39 @@ QString caf::PdmPythonGenerator::generate( PdmObjectFactory* factory, std::vecto
return generatedCode;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString PdmPythonGenerator::getDefaultValue( PdmFieldHandle* field )
{
QString defaultValue = "None";
bool isList = field->xmlCapability()->isVectorField();
if ( isList )
{
defaultValue = "[]";
}
else
{
QString valueString;
// Always make sure the default value for a ptrField is empty string
if ( !field->hasPtrReferencedObjects() )
{
auto scriptability = field->template capability<PdmAbstractFieldScriptingCapability>();
QTextStream valueStream( &valueString );
scriptability->readFromField( valueStream, true, true );
}
if ( valueString.isEmpty() ) valueString = QString( "\"\"" );
valueString = pythonifyDataValue( valueString );
defaultValue = valueString;
}
return defaultValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -54,6 +54,9 @@ public:
static QString dataTypeString( const PdmFieldHandle* field, bool useStrForUnknownDataTypes );
static QString pythonifyDataValue( const QString& dataValue );
private:
static QString getDefaultValue( PdmFieldHandle* field );
};
} // namespace caf

View File

@ -3,11 +3,13 @@ syntax = "proto3";
package rips;
import "Definitions.proto";
import "PdmObject.proto";
service App {
rpc GetVersion(Empty) returns (Version) {}
rpc Exit(Empty) returns (Empty) {}
rpc GetRuntimeInfo(Empty) returns (RuntimeInfo) {}
rpc GetPdmObject(Empty) returns (PdmObject) {}
}
message Version {

View File

@ -13,6 +13,7 @@ home_dir = expanduser("~")
export_folder = tempfile.mkdtemp()
directory_path = "resprojects/webviz-subsurface-testdata/reek_history_match/"
# directory_path = "e:/gitroot/webviz-subsurface-testdata/reek_history_match"
case_file_paths = []

View File

@ -0,0 +1,41 @@
# Load ResInsight Processing Server Client Library
import rips
import tempfile
from os.path import expanduser
from pathlib import Path
# Connect to ResInsight instance
resinsight = rips.Instance.find()
home_dir = expanduser("~")
export_folder = tempfile.mkdtemp()
directory_path = "resprojects/webviz-subsurface-testdata/reek_history_match/"
# directory_path = "e:/gitroot/webviz-subsurface-testdata/reek_history_match"
case_file_paths = []
num_realizations = 9
num_iterations = 4
for realization in range(0, num_realizations):
for iteration in range(0, num_iterations):
realization_dir = "realization-" + str(realization)
iteration_dir = "iter-" + str(iteration)
egrid_name = "eclipse/model/5_R001_REEK-" + str(realization) + ".EGRID"
path = Path(
home_dir, directory_path, realization_dir, iteration_dir, egrid_name
)
case_file_paths.append(path)
k_indexes = [4, 10]
command_router = resinsight.command_router
for path in case_file_paths:
path_name = path.as_posix()
command_router.extract_surfaces(path_name, k_indexes)

View File

@ -23,6 +23,7 @@ import RiaVersionInfo
from .project import Project
from .retry_policy import ExponentialBackoffRetryPolicy
from .grpc_retry_interceptor import RetryOnRpcErrorClientInterceptor
from .generated.generated_classes import CommandRouter
class Instance:
@ -202,12 +203,17 @@ class Instance:
intercepted_channel = grpc.intercept_channel(self.channel, *interceptors)
# Recreate ommand stubs with the retry policy
# Recreate command stubs with the retry policy
self.commands = Commands_pb2_grpc.CommandsStub(intercepted_channel)
# Service packages
self.project = Project.create(intercepted_channel)
# Command Router object used as entry point for independent processing functions
self.command_router = CommandRouter(
self.app.GetPdmObject(Empty()), intercepted_channel
)
path = os.getcwd()
self.set_start_dir(path=path)

View File

@ -22,6 +22,8 @@
#include "RiaGrpcServer.h"
#include "RiaVersionInfo.h"
#include "ProjectDataModelCommands/CommandRouter/RimCommandRouter.h"
#include <QApplication>
//--------------------------------------------------------------------------------------------------
@ -51,7 +53,7 @@ grpc::Status
RiaGrpcAppService::GetRuntimeInfo( grpc::ServerContext* context, const rips::Empty* request, rips::RuntimeInfo* reply )
{
rips::ApplicationTypeEnum appType = rips::CONSOLE_APPLICATION;
if ( dynamic_cast<QApplication*>(RiaApplication::instance()))
if ( dynamic_cast<QApplication*>( RiaApplication::instance() ) )
{
appType = rips::GUI_APPLICATION;
}
@ -70,7 +72,24 @@ std::vector<RiaGrpcCallbackInterface*> RiaGrpcAppService::createCallbacks()
new RiaGrpcUnaryCallback<Self, rips::Empty, rips::Empty>( this, &Self::Exit, &Self::RequestExit ),
new RiaGrpcUnaryCallback<Self, rips::Empty, rips::RuntimeInfo>( this,
&Self::GetRuntimeInfo,
&Self::RequestGetRuntimeInfo ) };
&Self::RequestGetRuntimeInfo ),
new RiaGrpcUnaryCallback<Self, rips::Empty, rips::PdmObject>( this,
&Self::GetPdmObject,
&Self::RequestGetPdmObject ) };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcAppService::GetPdmObject( grpc::ServerContext* context, const rips::Empty* request, rips::PdmObject* reply )
{
auto* commandRouter = RiaApplication::instance()->commandRouter();
if ( commandRouter )
{
copyPdmObjectFromCafToRips( commandRouter, reply );
}
return grpc::Status::OK;
}
static bool RiaGrpcAppInfoService_init =

View File

@ -46,4 +46,5 @@ public:
grpc::Status Exit( grpc::ServerContext* context, const rips::Empty* request, rips::Empty* reply ) override;
grpc::Status GetRuntimeInfo( grpc::ServerContext* context, const rips::Empty* request, rips::RuntimeInfo* reply ) override;
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
grpc::Status GetPdmObject( grpc::ServerContext* context, const rips::Empty* request, rips::PdmObject* reply ) override;
};

View File

@ -17,7 +17,10 @@
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcPdmObjectService.h"
#include "RiaApplication.h"
#include "RiaGrpcCallbacks.h"
#include "ProjectDataModelCommands/CommandRouter/RimCommandRouter.h"
#include "Rim3dView.h"
#include "RimEclipseResultDefinition.h"
#include "RimProject.h"
@ -613,11 +616,13 @@ caf::PdmObject* RiaGrpcPdmObjectService::findCafObjectFromRipsObject( const rips
caf::PdmObject* RiaGrpcPdmObjectService::findCafObjectFromScriptNameAndAddress( const QString& scriptClassName,
uint64_t address )
{
QString classKeyword = caf::PdmObjectScriptingCapabilityRegister::classKeywordFromScriptClassName( scriptClassName );
if ( classKeyword == RimCommandRouter::classKeywordStatic() ) return RiaApplication::instance()->commandRouter();
RimProject* project = RimProject::current();
std::vector<caf::PdmObject*> objectsOfCurrentClass;
QString classKeyword = caf::PdmObjectScriptingCapabilityRegister::classKeywordFromScriptClassName( scriptClassName );
project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass );
caf::PdmObject* matchingObject = nullptr;

View File

@ -34,7 +34,9 @@
#include <grpcpp/grpcpp.h>
#include <PdmObject.pb.h>
#include <QDebug>
#include <QXmlStreamReader>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -137,6 +139,16 @@ void RiaGrpcServiceInterface::copyPdmObjectFromRipsToCaf( const rips::PdmObject*
destination->fields( fields );
auto parametersMap = source->parameters();
bool printContent = false; // Flag to control debug output to debugger
if ( printContent )
{
for ( const auto& p : parametersMap )
{
qDebug() << QString::fromStdString( p.first ) << " : " << QString::fromStdString( p.second );
}
}
for ( auto field : fields )
{
auto scriptability = field->template capability<caf::PdmAbstractFieldScriptingCapability>();

View File

@ -48,6 +48,9 @@ public:
void getCellCorners(int globindex, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z);
void getCellCorners(const std::array<int, 3>& ijk, std::array<double,8>& X, std::array<double,8>& Y, std::array<double,8>& Z);
std::vector<std::array<float, 3>> getXYZ_layer(int layer, bool bottom=false);
std::vector<std::array<float, 3>> getXYZ_layer(int layer, std::array<int, 4>& box, bool bottom=false);
int activeCells() const { return nactive; }
int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; }
@ -64,11 +67,17 @@ public:
const std::vector<std::string>& list_of_lgrs() const { return lgr_names; }
std::vector<float> get_mapaxes() const { return m_mapaxes; }
std::string get_mapunits() const { return m_mapunits; }
private:
Opm::filesystem::path inputFileName, initFileName;
std::string m_grid_name;
bool m_radial;
std::vector<float> m_mapaxes;
std::string m_mapunits;
std::array<int, 3> nijk;
std::array<int, 3> host_nijk;
@ -93,6 +102,12 @@ private:
int actnum_array_index;
int nnc1_array_index;
int nnc2_array_index;
std::vector<float> get_zcorn_from_disk(int layer, bool bottom);
void getCellCorners(const std::array<int, 3>& ijk, const std::vector<float>& zcorn_layer,
std::array<double,4>& X, std::array<double,4>& Y, std::array<double,4>& Z);
};
}} // namespace Opm::EclIO

View File

@ -51,35 +51,7 @@ public:
protected:
template <typename T>
const std::vector<T>& ImplgetInitData(const std::string& name, const std::string& grid_name = "global")
{
int arr_ind = get_array_index(name, grid_name);
if constexpr (std::is_same_v<T, int>)
return getImpl(arr_ind, INTE, inte_array, "integer");
if constexpr (std::is_same_v<T, float>)
return getImpl(arr_ind, REAL, real_array, "float");
if constexpr (std::is_same_v<T, double>)
return getImpl(arr_ind, DOUB, doub_array, "double");
if constexpr (std::is_same_v<T, bool>)
return getImpl(arr_ind, LOGI, logi_array, "bool");
if constexpr (std::is_same_v<T, std::string>)
{
if (array_type[arr_ind] == Opm::EclIO::CHAR)
return getImpl(arr_ind, array_type[arr_ind], char_array, "char");
if (array_type[arr_ind] == Opm::EclIO::C0NN)
return getImpl(arr_ind, array_type[arr_ind], char_array, "c0nn");
OPM_THROW(std::runtime_error, "Array not of type CHAR or C0nn");
}
OPM_THROW(std::runtime_error, "type not supported");
}
const std::vector<T>& ImplgetInitData(const std::string& name, const std::string& grid_name = "global");
private:
std::array<int, 3> global_nijk;

View File

@ -53,9 +53,6 @@ public:
template <typename T>
const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber, int occurrence);
template <typename T>
const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber, const std::string& lgr_name);
template <typename T>
const std::vector<T>& getRestartData(int index, int reportStepNumber)
{
@ -64,16 +61,10 @@ public:
}
template <typename T>
const std::vector<T>& getRestartData(int index, int reportStepNumber, const std::string& lgr_name)
{
auto indRange = this->getIndexRange(reportStepNumber);
const std::vector<T>& getRestartData(const std::string& name, int reportStepNumber, const std::string& lgr_name);
if ((std::get<0>(indRange) + index) > std::get<1>(indRange))
OPM_THROW(std::invalid_argument, "getRestartData, index out of range");
int start_ind = get_start_index_lgrname(reportStepNumber, lgr_name);
return this->get<T>(index + start_ind);
}
template <typename T>
const std::vector<T>& getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
int occurrence_count(const std::string& name, int reportStepNumber) const;
size_t numberOfReportSteps() const { return seqnum.size(); };

View File

@ -19,11 +19,10 @@
#ifndef OPM_IO_ECLFILE_HPP
#define OPM_IO_ECLFILE_HPP
#include <opm/common/ErrorMacros.hpp>
#include <opm/io/eclipse/EclIOdata.hpp>
#include <ios>
#include <map>
#include <string>
#include <stdexcept>
#include <tuple>
@ -97,19 +96,7 @@ protected:
template<class T>
const std::vector<T>& getImpl(int arrIndex, eclArrType type,
const std::unordered_map<int, std::vector<T>>& array,
const std::string& typeStr)
{
if (array_type[arrIndex] != type) {
std::string message = "Array with index " + std::to_string(arrIndex) + " is not of type " + typeStr;
OPM_THROW(std::runtime_error, message);
}
if (!arrayLoaded[arrIndex]) {
loadData(arrIndex);
}
return array.at(arrIndex);
}
const std::string& typeStr);
std::streampos
seekPosition(const std::vector<std::string>::size_type arrIndex) const;

View File

@ -3,9 +3,8 @@
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -24,336 +23,549 @@
#include <algorithm>
#include <cstring>
#include <iterator>
#include <iomanip>
#include <iterator>
#include <numeric>
#include <string>
#include <sstream>
#include <stdexcept>
#include <string>
#define _USE_MATH_DEFINES
#include <math.h>
namespace Opm { namespace EclIO {
using NNCentry = std::tuple<int, int, int, int, int,int, float>;
EGrid::EGrid(const std::string &filename, std::string grid_name) :
EclFile(filename), inputFileName { filename }, m_grid_name {grid_name}
namespace Opm
{
initFileName = inputFileName.parent_path() / inputFileName.stem();
if (this->formattedInput())
initFileName += ".FINIT";
else
initFileName += ".INIT";
std::string lgrname = "global";
m_nncs_loaded = false;
actnum_array_index = -1;
nnc1_array_index = -1;
nnc2_array_index = -1;
m_radial = false;
int hostnum_index = -1;
for (size_t n = 0; n < array_name.size(); n++) {
if (array_name[n] == "ENDLGR")
lgrname = "global";
if (array_name[n] == "LGR") {
auto lgr = this->get<std::string>(n);
lgrname = lgr[0];
lgr_names.push_back(lgr[0]);
}
if (array_name[n] == "NNCHEAD"){
auto nnchead = this->get<int>(n);
if (nnchead[1] == 0)
lgrname = "global";
else
lgrname = lgr_names[nnchead[1] - 1];
}
if (lgrname == grid_name) {
if (array_name[n] == "GRIDHEAD") {
auto gridhead = get<int>(n);
nijk[0] = gridhead[1];
nijk[1] = gridhead[2];
nijk[2] = gridhead[3];
if (gridhead.size() > 26)
m_radial = gridhead[26] > 0 ? true: false;
}
if (array_name[n] == "COORD")
coord_array_index= n;
else if (array_name[n] == "ZCORN")
zcorn_array_index= n;
else if (array_name[n] == "ACTNUM")
actnum_array_index= n;
else if (array_name[n] == "NNC1")
nnc1_array_index= n;
else if (array_name[n] == "NNC2")
nnc2_array_index= n;
else if (array_name[n] == "HOSTNUM")
hostnum_index= n;
}
if ((lgrname == "global") && (array_name[n] == "GRIDHEAD")) {
auto gridhead = get<int>(n);
host_nijk[0] = gridhead[1];
host_nijk[1] = gridhead[2];
host_nijk[2] = gridhead[3];
}
}
if (actnum_array_index != -1) {
auto actnum = this->get<int>(actnum_array_index);
nactive = 0;
for (size_t i = 0; i < actnum.size(); i++) {
if (actnum[i] > 0) {
act_index.push_back(nactive);
glob_index.push_back(i);
nactive++;
} else {
act_index.push_back(-1);
}
}
} else {
int nCells = nijk[0] * nijk[1] * nijk[2];
act_index.resize(nCells);
glob_index.resize(nCells);
std::iota(act_index.begin(), act_index.end(), 0);
std::iota(glob_index.begin(), glob_index.end(), 0);
}
if (hostnum_index > -1){
auto hostnum = getImpl(hostnum_index, INTE, inte_array, "integer");
host_cells.reserve(hostnum.size());
for (auto val : hostnum)
host_cells.push_back(val -1);
}
}
std::vector<std::array<int, 3>> EGrid::hostCellsIJK()
namespace EclIO
{
std::vector<std::array<int, 3>> res_vect;
res_vect.reserve(host_cells.size());
for (auto val : host_cells){
std::array<int, 3> tmp;
tmp[2] = val / (host_nijk[0] * host_nijk[1]);
int rest = val % (host_nijk[0] * host_nijk[1]);
using NNCentry = std::tuple<int, int, int, int, int, int, float>;
tmp[1] = rest / host_nijk[0];
tmp[0] = rest % host_nijk[0];
EGrid::EGrid(const std::string& filename, std::string grid_name)
: EclFile(filename)
, inputFileName {filename}
, m_grid_name {grid_name}
{
initFileName = inputFileName.parent_path() / inputFileName.stem();
res_vect.push_back(tmp);
}
return res_vect;
}
std::vector<NNCentry> EGrid::get_nnc_ijk()
{
if (!m_nncs_loaded)
load_nnc_data();
std::vector<NNCentry> res_vect;
res_vect.reserve(nnc1_array.size());
for (size_t n=0; n< nnc1_array.size(); n++){
auto ijk1 = ijk_from_global_index(nnc1_array[n] - 1);
auto ijk2 = ijk_from_global_index(nnc2_array[n] - 1);
if (transnnc_array.size() > 0)
res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], transnnc_array[n]});
if (this->formattedInput())
initFileName += ".FINIT";
else
res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], -1.0 });
}
initFileName += ".INIT";
return res_vect;
}
std::string lgrname = "global";
m_nncs_loaded = false;
actnum_array_index = -1;
nnc1_array_index = -1;
nnc2_array_index = -1;
m_radial = false;
m_mapunits = "";
void EGrid::load_grid_data()
{
coord_array = getImpl(coord_array_index, REAL, real_array, "float");
zcorn_array = getImpl(zcorn_array_index, REAL, real_array, "float");
}
int hostnum_index = -1;
void EGrid::load_nnc_data()
{
if ((nnc1_array_index > -1) && (nnc2_array_index > -1)) {
for (size_t n = 0; n < array_name.size(); n++) {
nnc1_array = getImpl(nnc1_array_index, Opm::EclIO::INTE, inte_array, "inte");
nnc2_array = getImpl(nnc2_array_index, Opm::EclIO::INTE, inte_array, "inte");
if (array_name[n] == "ENDLGR")
lgrname = "global";
if ((Opm::filesystem::exists(initFileName)) && (nnc1_array.size() > 0)){
Opm::EclIO::EInit init(initFileName.string());
auto init_dims = init.grid_dimension(m_grid_name);
int init_nactive = init.activeCells(m_grid_name);
if (init_dims != nijk){
std::string message = "Dimensions of Egrid differ from dimensions found in init file. ";
std::string grid_str = std::to_string(nijk[0]) + "x" + std::to_string(nijk[1]) + "x" + std::to_string(nijk[2]);
std::string init_str = std::to_string(init_dims[0]) + "x" + std::to_string(init_dims[1]) + "x" + std::to_string(init_dims[2]);
message = message + "Egrid: " + grid_str + ". INIT file: " + init_str;
OPM_THROW(std::invalid_argument, message);
if (array_name[n] == "LGR") {
auto lgr = this->get<std::string>(n);
lgrname = lgr[0];
lgr_names.push_back(lgr[0]);
}
if (init_nactive != nactive){
std::string message = "Number of active cells are different in Egrid and Init file.";
message = message + " Egrid: " + std::to_string(nactive) + ". INIT file: " + std::to_string(init_nactive);
OPM_THROW(std::invalid_argument, message);
if (array_name[n] == "NNCHEAD") {
auto nnchead = this->get<int>(n);
if (nnchead[1] == 0)
lgrname = "global";
else
lgrname = lgr_names[nnchead[1] - 1];
}
auto trans_data = init.getInitData<float>("TRANNNC", m_grid_name);
if (trans_data.size() != nnc1_array.size()){
std::string message = "inconsistent size of array TRANNNC in init file. ";
message = message + " Size of NNC1 and NNC2: " + std::to_string(nnc1_array.size());
message = message + " Size of TRANNNC: " + std::to_string(trans_data.size());
OPM_THROW(std::invalid_argument, message);
if (array_name[n] == "MAPUNITS") {
auto mapunits = this->get<std::string>(n);
m_mapunits = mapunits[0];
}
transnnc_array = trans_data;
if (array_name[n] == "MAPAXES")
m_mapaxes = this->get<float>(n);
if (lgrname == grid_name) {
if (array_name[n] == "GRIDHEAD") {
auto gridhead = get<int>(n);
nijk[0] = gridhead[1];
nijk[1] = gridhead[2];
nijk[2] = gridhead[3];
if (gridhead.size() > 26)
m_radial = gridhead[26] > 0 ? true : false;
}
if (array_name[n] == "COORD")
coord_array_index = n;
else if (array_name[n] == "ZCORN")
zcorn_array_index = n;
else if (array_name[n] == "ACTNUM")
actnum_array_index = n;
else if (array_name[n] == "NNC1")
nnc1_array_index = n;
else if (array_name[n] == "NNC2")
nnc2_array_index = n;
else if (array_name[n] == "HOSTNUM")
hostnum_index = n;
}
if ((lgrname == "global") && (array_name[n] == "GRIDHEAD")) {
auto gridhead = get<int>(n);
host_nijk[0] = gridhead[1];
host_nijk[1] = gridhead[2];
host_nijk[2] = gridhead[3];
}
}
m_nncs_loaded = true;
}
}
int EGrid::global_index(int i, int j, int k) const
{
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
}
return i + j * nijk[0] + k * nijk[0] * nijk[1];
}
int EGrid::active_index(int i, int j, int k) const
{
int n = i + j * nijk[0] + k * nijk[0] * nijk[1];
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
}
return act_index[n];
}
std::array<int, 3> EGrid::ijk_from_active_index(int actInd) const
{
if (actInd < 0 || actInd >= nactive) {
OPM_THROW(std::invalid_argument, "active index out of range");
}
int _glob = glob_index[actInd];
std::array<int, 3> result;
result[2] = _glob / (nijk[0] * nijk[1]);
int rest = _glob % (nijk[0] * nijk[1]);
result[1] = rest / nijk[0];
result[0] = rest % nijk[0];
return result;
}
std::array<int, 3> EGrid::ijk_from_global_index(int globInd) const
{
if (globInd < 0 || globInd >= nijk[0] * nijk[1] * nijk[2]) {
OPM_THROW(std::invalid_argument, "global index out of range");
}
std::array<int, 3> result;
result[2] = globInd / (nijk[0] * nijk[1]);
int rest = globInd % (nijk[0] * nijk[1]);
result[1] = rest / nijk[0];
result[0] = rest % nijk[0];
return result;
}
void EGrid::getCellCorners(const std::array<int, 3>& ijk,
std::array<double,8>& X,
std::array<double,8>& Y,
std::array<double,8>& Z)
{
if (coord_array.empty())
load_grid_data();
std::vector<int> zind;
std::vector<int> pind;
// calculate indices for grid pillars in COORD arrray
pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6);
pind.push_back(pind[0] + 6);
pind.push_back(pind[0] + (nijk[0]+1)*6);
pind.push_back(pind[2] + 6);
// get depths from zcorn array in ZCORN array
zind.push_back(ijk[2]*nijk[0]*nijk[1]*8 + ijk[1]*nijk[0]*4 + ijk[0]*2);
zind.push_back(zind[0] + 1);
zind.push_back(zind[0] + nijk[0]*2);
zind.push_back(zind[2] + 1);
for (int n = 0; n < 4; n++)
zind.push_back(zind[n] + nijk[0]*nijk[1]*4);
for (int n = 0; n< 8; n++)
Z[n] = zcorn_array[zind[n]];
for (int n = 0; n < 4; n++) {
double xt;
double yt;
double xb;
double yb;
double zt = coord_array[pind[n] + 2];
double zb = coord_array[pind[n] + 5];
if (m_radial) {
xt = coord_array[pind[n]] * cos(coord_array[pind[n] + 1] / 180.0 * M_PI);
yt = coord_array[pind[n]] * sin(coord_array[pind[n] + 1] / 180.0 * M_PI);
xb = coord_array[pind[n]+3] * cos(coord_array[pind[n] + 4] / 180.0 * M_PI);
yb = coord_array[pind[n]+3] * sin(coord_array[pind[n] + 4] / 180.0 * M_PI);
if (actnum_array_index != -1) {
auto actnum = this->get<int>(actnum_array_index);
nactive = 0;
for (size_t i = 0; i < actnum.size(); i++) {
if (actnum[i] > 0) {
act_index.push_back(nactive);
glob_index.push_back(i);
nactive++;
} else {
act_index.push_back(-1);
}
}
} else {
int nCells = nijk[0] * nijk[1] * nijk[2];
act_index.resize(nCells);
glob_index.resize(nCells);
std::iota(act_index.begin(), act_index.end(), 0);
std::iota(glob_index.begin(), glob_index.end(), 0);
}
if (hostnum_index > -1) {
auto hostnum = getImpl(hostnum_index, INTE, inte_array, "integer");
host_cells.reserve(hostnum.size());
for (auto val : hostnum)
host_cells.push_back(val - 1);
}
}
std::vector<std::array<int, 3>> EGrid::hostCellsIJK()
{
std::vector<std::array<int, 3>> res_vect;
res_vect.reserve(host_cells.size());
for (auto val : host_cells) {
std::array<int, 3> tmp;
tmp[2] = val / (host_nijk[0] * host_nijk[1]);
int rest = val % (host_nijk[0] * host_nijk[1]);
tmp[1] = rest / host_nijk[0];
tmp[0] = rest % host_nijk[0];
res_vect.push_back(tmp);
}
return res_vect;
}
std::vector<NNCentry> EGrid::get_nnc_ijk()
{
if (!m_nncs_loaded)
load_nnc_data();
std::vector<NNCentry> res_vect;
res_vect.reserve(nnc1_array.size());
for (size_t n = 0; n < nnc1_array.size(); n++) {
auto ijk1 = ijk_from_global_index(nnc1_array[n] - 1);
auto ijk2 = ijk_from_global_index(nnc2_array[n] - 1);
if (transnnc_array.size() > 0)
res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], transnnc_array[n]});
else
res_vect.push_back({ijk1[0], ijk1[1], ijk1[2], ijk2[0], ijk2[1], ijk2[2], -1.0});
}
return res_vect;
}
void EGrid::load_grid_data()
{
coord_array = getImpl(coord_array_index, REAL, real_array, "float");
zcorn_array = getImpl(zcorn_array_index, REAL, real_array, "float");
}
void EGrid::load_nnc_data()
{
if ((nnc1_array_index > -1) && (nnc2_array_index > -1)) {
nnc1_array = getImpl(nnc1_array_index, Opm::EclIO::INTE, inte_array, "inte");
nnc2_array = getImpl(nnc2_array_index, Opm::EclIO::INTE, inte_array, "inte");
if ((Opm::filesystem::exists(initFileName)) && (nnc1_array.size() > 0)) {
Opm::EclIO::EInit init(initFileName.string());
auto init_dims = init.grid_dimension(m_grid_name);
int init_nactive = init.activeCells(m_grid_name);
if (init_dims != nijk) {
std::string message = "Dimensions of Egrid differ from dimensions found in init file. ";
std::string grid_str
= std::to_string(nijk[0]) + "x" + std::to_string(nijk[1]) + "x" + std::to_string(nijk[2]);
std::string init_str = std::to_string(init_dims[0]) + "x" + std::to_string(init_dims[1]) + "x"
+ std::to_string(init_dims[2]);
message = message + "Egrid: " + grid_str + ". INIT file: " + init_str;
OPM_THROW(std::invalid_argument, message);
}
if (init_nactive != nactive) {
std::string message = "Number of active cells are different in Egrid and Init file.";
message = message + " Egrid: " + std::to_string(nactive)
+ ". INIT file: " + std::to_string(init_nactive);
OPM_THROW(std::invalid_argument, message);
}
auto trans_data = init.getInitData<float>("TRANNNC", m_grid_name);
if (trans_data.size() != nnc1_array.size()) {
std::string message = "inconsistent size of array TRANNNC in init file. ";
message = message + " Size of NNC1 and NNC2: " + std::to_string(nnc1_array.size());
message = message + " Size of TRANNNC: " + std::to_string(trans_data.size());
OPM_THROW(std::invalid_argument, message);
}
transnnc_array = trans_data;
}
m_nncs_loaded = true;
}
}
int EGrid::global_index(int i, int j, int k) const
{
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
}
return i + j * nijk[0] + k * nijk[0] * nijk[1];
}
int EGrid::active_index(int i, int j, int k) const
{
int n = i + j * nijk[0] + k * nijk[0] * nijk[1];
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
}
return act_index[n];
}
std::array<int, 3> EGrid::ijk_from_active_index(int actInd) const
{
if (actInd < 0 || actInd >= nactive) {
OPM_THROW(std::invalid_argument, "active index out of range");
}
int _glob = glob_index[actInd];
std::array<int, 3> result;
result[2] = _glob / (nijk[0] * nijk[1]);
int rest = _glob % (nijk[0] * nijk[1]);
result[1] = rest / nijk[0];
result[0] = rest % nijk[0];
return result;
}
std::array<int, 3> EGrid::ijk_from_global_index(int globInd) const
{
if (globInd < 0 || globInd >= nijk[0] * nijk[1] * nijk[2]) {
OPM_THROW(std::invalid_argument, "global index out of range");
}
std::array<int, 3> result;
result[2] = globInd / (nijk[0] * nijk[1]);
int rest = globInd % (nijk[0] * nijk[1]);
result[1] = rest / nijk[0];
result[0] = rest % nijk[0];
return result;
}
void EGrid::getCellCorners(const std::array<int, 3>& ijk,
std::array<double, 8>& X,
std::array<double, 8>& Y,
std::array<double, 8>& Z)
{
if (coord_array.empty())
load_grid_data();
std::vector<int> zind;
std::vector<int> pind;
// calculate indices for grid pillars in COORD arrray
pind.push_back(ijk[1] * (nijk[0] + 1) * 6 + ijk[0] * 6);
pind.push_back(pind[0] + 6);
pind.push_back(pind[0] + (nijk[0] + 1) * 6);
pind.push_back(pind[2] + 6);
// get depths from zcorn array in ZCORN array
zind.push_back(ijk[2] * nijk[0] * nijk[1] * 8 + ijk[1] * nijk[0] * 4 + ijk[0] * 2);
zind.push_back(zind[0] + 1);
zind.push_back(zind[0] + nijk[0] * 2);
zind.push_back(zind[2] + 1);
for (int n = 0; n < 4; n++)
zind.push_back(zind[n] + nijk[0] * nijk[1] * 4);
for (int n = 0; n < 8; n++)
Z[n] = zcorn_array[zind[n]];
for (int n = 0; n < 4; n++) {
double xt;
double yt;
double xb;
double yb;
double zt = coord_array[pind[n] + 2];
double zb = coord_array[pind[n] + 5];
if (m_radial) {
xt = coord_array[pind[n]] * cos(coord_array[pind[n] + 1] / 180.0 * M_PI);
yt = coord_array[pind[n]] * sin(coord_array[pind[n] + 1] / 180.0 * M_PI);
xb = coord_array[pind[n] + 3] * cos(coord_array[pind[n] + 4] / 180.0 * M_PI);
yb = coord_array[pind[n] + 3] * sin(coord_array[pind[n] + 4] / 180.0 * M_PI);
} else {
xt = coord_array[pind[n]];
yt = coord_array[pind[n] + 1];
xb = coord_array[pind[n] + 3];
yb = coord_array[pind[n] + 4];
}
X[n] = xt + (xb - xt) / (zt - zb) * (zt - Z[n]);
X[n + 4] = xt + (xb - xt) / (zt - zb) * (zt - Z[n + 4]);
Y[n] = yt + (yb - yt) / (zt - zb) * (zt - Z[n]);
Y[n + 4] = yt + (yb - yt) / (zt - zb) * (zt - Z[n + 4]);
}
}
void
EGrid::getCellCorners(int globindex, std::array<double, 8>& X, std::array<double, 8>& Y, std::array<double, 8>& Z)
{
return getCellCorners(ijk_from_global_index(globindex), X, Y, Z);
}
std::vector<std::array<float, 3>> EGrid::getXYZ_layer(int layer, std::array<int, 4>& box, bool bottom)
{
// layer is layer index, zero based. The box array is i and j range (i1,i2,j1,j2), also zero based
if ((layer < 0) || (layer > (nijk[2] - 1))) {
std::string message = "invalid layer index " + std::to_string(layer) + ". Valied range [0, ";
message = message + std::to_string(nijk[2] - 1) + "]";
throw std::invalid_argument(message);
}
if ((box[0] < 0) || (box[0] + 1 > nijk[0]) || (box[1] < 0) || (box[1] + 1 > nijk[0]) || (box[2] < 0)
|| (box[2] + 1 > nijk[1]) || (box[3] < 0) || (box[3] + 1 > nijk[1]) || (box[0] > box[1])
|| (box[2] > box[3])) {
throw std::invalid_argument("invalid box input, i1,i2,j1 or j2 out of valied range ");
}
int nodes_pr_surf = nijk[0] * nijk[1] * 4;
int zcorn_offset = nodes_pr_surf * layer * 2;
if (bottom)
zcorn_offset += nodes_pr_surf;
std::vector<float> layer_zcorn;
layer_zcorn.reserve(nodes_pr_surf);
std::vector<std::array<float, 3>> xyz_vector;
if (coord_array.size() == 0)
coord_array = getImpl(coord_array_index, REAL, real_array, "float");
if (zcorn_array.size() > 0) {
for (size_t n = 0; n < static_cast<size_t>(nodes_pr_surf); n++)
layer_zcorn.push_back(zcorn_array[zcorn_offset + n]);
} else {
layer_zcorn = get_zcorn_from_disk(layer, bottom);
}
std::array<double, 4> X;
std::array<double, 4> Y;
std::array<double, 4> Z;
std::array<int, 3> ijk;
ijk[2] = 0;
for (int j = box[2]; j < (box[3] + 1); j++) {
for (int i = box[0]; i < (box[1] + 1); i++) {
ijk[0] = i;
ijk[1] = j;
this->getCellCorners(ijk, layer_zcorn, X, Y, Z);
for (size_t n = 0; n < 4; n++) {
std::array<float, 3> xyz;
xyz[0] = X[n];
xyz[1] = Y[n];
xyz[2] = Z[n];
xyz_vector.push_back(xyz);
}
}
}
return xyz_vector;
}
std::vector<std::array<float, 3>> EGrid::getXYZ_layer(int layer, bool bottom)
{
std::array<int, 4> box = {0, nijk[0] - 1, 0, nijk[1] - 1};
return this->getXYZ_layer(layer, box, bottom);
}
std::vector<float> EGrid::get_zcorn_from_disk(int layer, bool bottom)
{
if (formatted)
throw std::invalid_argument("partial loading of zcorn arrays not possible when using formatted input");
std::vector<float> zcorn_layer;
std::fstream fileH;
int nodes_pr_surf = nijk[0] * nijk[1] * 4;
int zcorn_offset = nodes_pr_surf * layer * 2;
if (bottom)
zcorn_offset += nodes_pr_surf;
fileH.open(inputFileName, std::ios::in | std::ios::binary);
if (!fileH)
throw std::runtime_error("Can not open EGrid file" + this->inputFilename);
std::string arrName(8, ' ');
eclArrType arrType;
int64_t num;
int sizeOfElement;
uint64_t zcorn_pos = 0;
while (!isEOF(&fileH)) {
readBinaryHeader(fileH, arrName, num, arrType, sizeOfElement);
if (arrName == "ZCORN ") {
zcorn_pos = fileH.tellg();
break;
}
uint64_t sizeOfNextArray = sizeOnDiskBinary(num, arrType, sizeOfElement);
fileH.seekg(static_cast<std::streamoff>(sizeOfNextArray), std::ios_base::cur);
}
int elements_pr_block = Opm::EclIO::MaxBlockSizeReal / Opm::EclIO::sizeOfReal;
int num_blocks_start = zcorn_offset / elements_pr_block;
// adding size of zcorn real data before to ignored
uint64_t start_pos = zcorn_pos + Opm::EclIO::sizeOfReal * zcorn_offset;
// adding size of blocks (head and tail flags)
start_pos = start_pos + (1 + num_blocks_start * 2) * Opm::EclIO::sizeOfInte;
fileH.seekg(start_pos, std::ios_base::beg);
float value;
int zcorn_to = zcorn_offset + nodes_pr_surf;
for (int ind = zcorn_offset; ind < zcorn_to; ind++) {
if ((ind > 0) && ((ind % elements_pr_block) == 0))
fileH.seekg(static_cast<std::streamoff>(2 * Opm::EclIO::sizeOfInte), std::ios_base::cur);
fileH.read(reinterpret_cast<char*>(&value), Opm::EclIO::sizeOfReal);
value = Opm::EclIO::flipEndianFloat(value);
zcorn_layer.push_back(value);
}
fileH.close();
return zcorn_layer;
}
void EGrid::getCellCorners(const std::array<int, 3>& ijk,
const std::vector<float>& zcorn_layer,
std::array<double, 4>& X,
std::array<double, 4>& Y,
std::array<double, 4>& Z)
{
std::vector<int> zind;
std::vector<int> pind;
// calculate indices for grid pillars in COORD arrray
pind.push_back(ijk[1] * (nijk[0] + 1) * 6 + ijk[0] * 6);
pind.push_back(pind[0] + 6);
pind.push_back(pind[0] + (nijk[0] + 1) * 6);
pind.push_back(pind[2] + 6);
// get depths from zcorn array in ZCORN array
zind.push_back(ijk[2] * nijk[0] * nijk[1] * 8 + ijk[1] * nijk[0] * 4 + ijk[0] * 2);
zind.push_back(zind[0] + 1);
zind.push_back(zind[0] + nijk[0] * 2);
zind.push_back(zind[2] + 1);
for (int n = 0; n < 4; n++)
Z[n] = zcorn_layer[zind[n]];
for (int n = 0; n < 4; n++) {
double xt;
double yt;
double xb;
double yb;
double zt = coord_array[pind[n] + 2];
double zb = coord_array[pind[n] + 5];
xt = coord_array[pind[n]];
yt = coord_array[pind[n] + 1];
xb = coord_array[pind[n] + 3];
yb = coord_array[pind[n] + 4];
if (zt == zb) {
X[n] = xt;
Y[n] = yt;
} else {
X[n] = xt + (xb - xt) / (zt - zb) * (zt - Z[n]);
Y[n] = yt + (yb - yt) / (zt - zb) * (zt - Z[n]);
}
}
X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]);
X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]);
Y[n] = yt+(yb-yt)/(zt-zb)*(zt-Z[n]);
Y[n+4] = yt+(yb-yt)/(zt-zb)*(zt-Z[n+4]);
}
}
void EGrid::getCellCorners(int globindex, std::array<double,8>& X,
std::array<double,8>& Y, std::array<double,8>& Z)
{
return getCellCorners(ijk_from_global_index(globindex),X,Y,Z);
}
}} // namespace Opm::ecl
} // namespace EclIO
} // namespace Opm

View File

@ -157,5 +157,40 @@ std::vector<EclFile::EclEntry> EInit::list_arrays() const
return array_list;
}
template <typename T>
const std::vector<T>& EInit::ImplgetInitData(const std::string& name, const std::string& grid_name)
{
int arr_ind = get_array_index(name, grid_name);
if constexpr (std::is_same_v<T, int>)
return getImpl(arr_ind, INTE, inte_array, "integer");
if constexpr (std::is_same_v<T, float>)
return getImpl(arr_ind, REAL, real_array, "float");
if constexpr (std::is_same_v<T, double>)
return getImpl(arr_ind, DOUB, doub_array, "double");
if constexpr (std::is_same_v<T, bool>)
return getImpl(arr_ind, LOGI, logi_array, "bool");
if constexpr (std::is_same_v<T, std::string>)
{
if (array_type[arr_ind] == Opm::EclIO::CHAR)
return getImpl(arr_ind, array_type[arr_ind], char_array, "char");
if (array_type[arr_ind] == Opm::EclIO::C0NN)
return getImpl(arr_ind, array_type[arr_ind], char_array, "c0nn");
OPM_THROW(std::runtime_error, "Array not of type CHAR or C0nn");
}
OPM_THROW(std::runtime_error, "type not supported");
}
template const std::vector<int>& EInit::ImplgetInitData(const std::string& name, const std::string& grid_name);
template const std::vector<float>& EInit::ImplgetInitData(const std::string& name, const std::string& grid_name);
template const std::vector<double>& EInit::ImplgetInitData(const std::string& name, const std::string& grid_name);
template const std::vector<bool>& EInit::ImplgetInitData(const std::string& name, const std::string& grid_name);
}} // namespace Opm::EclIO

View File

@ -18,6 +18,8 @@
#include <opm/io/eclipse/ERst.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
#include <cstring>
#include <exception>
@ -407,5 +409,22 @@ const std::vector<std::string>& ERst::getRestartData<std::string>(const std::str
return getImpl(ind, CHAR, char_array, "char");
}
template <typename T>
const std::vector<T>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name)
{
auto indRange = this->getIndexRange(reportStepNumber);
if ((std::get<0>(indRange) + index) > std::get<1>(indRange))
OPM_THROW(std::invalid_argument, "getRestartData, index out of range");
int start_ind = get_start_index_lgrname(reportStepNumber, lgr_name);
return this->get<T>(index + start_ind);
}
template const std::vector<int>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
template const std::vector<std::string>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
template const std::vector<float>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
template const std::vector<double>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
template const std::vector<bool>& ERst::getRestartData(int index, int reportStepNumber, const std::string& lgr_name);
}} // namespace Opm::ecl

View File

@ -23,6 +23,7 @@
#include <opm/io/eclipse/EclUtil.hpp>
#include <opm/io/eclipse/EclOutput.hpp>
#include <opm/common/utility/TimeService.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <algorithm>
#include <chrono>

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/utility/numeric/calculateCellVol.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/io/eclipse/EclFile.hpp>
#include <opm/io/eclipse/EclOutput.hpp>