Support setting Wbs-parameters from Python.

This commit is contained in:
Gaute Lindkvist 2020-01-21 08:48:56 +01:00
parent 954bf1e02e
commit 56d141d4c3
20 changed files with 323 additions and 70 deletions

View File

@ -88,6 +88,14 @@ RicfCommandResponse RicfCreateWellBoreStabilityPlotFeature::execute()
if ( chosenCase && chosenWellPath && m_timeStep() >= 0 )
{
if ( !chosenWellPath->wellPathGeometry() )
{
QString error = QString( "The well path %1 has no geometry. Cannot create a Well Bore Stability Plot" )
.arg( chosenWellPath->name() );
RiaLogging::error( error );
return RicfCommandResponse( RicfCommandResponse::COMMAND_ERROR, error );
}
RimWellBoreStabilityPlot* wbsPlot = RicNewWellBoreStabilityPlotFeature::createPlot( chosenCase,
chosenWellPath,
m_timeStep(),

View File

@ -19,6 +19,7 @@
#include "RicNewWellBoreStabilityPlotFeature.h"
#include "RiaColorTables.h"
#include "RiaLogging.h"
#include "RicNewWellLogCurveExtractionFeature.h"
#include "RicNewWellLogFileCurveFeature.h"
@ -175,6 +176,13 @@ void RicNewWellBoreStabilityPlotFeature::onActionTriggered( bool isChecked )
return;
}
if ( !wellPath->wellPathGeometry() )
{
RiaLogging::warning( QString( "The well path %1 has no geometry. Cannot create a Well Bore Stability Plot" )
.arg( wellPath->name() ) );
return;
}
createPlot( geoMechCase, wellPath, view->currentTimeStep() );
}

View File

@ -171,6 +171,8 @@ if (RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
"rips/pdmobject.py"
"rips/plot.py"
"rips/view.py"
"rips/well_log_plot.py"
"rips/well_bore_stability_plot.py"
"rips/PythonExamples/instance_example.py"
"rips/PythonExamples/command_example.py"
"rips/PythonExamples/case_grid_group.py"

View File

@ -1,4 +1,6 @@
import os
import grpc
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
@ -9,11 +11,20 @@ cases = resInsight.project.cases()
well_paths = resInsight.project.import_well_paths(well_path_folder='D:/Projects/ResInsight-regression-test/ModelData/Norne_LessWellPaths')
well_log_files = resInsight.project.import_well_log_files(well_log_folder='D:/Projects/ResInsight-regression-test/ModelData/Norne_PLT_LAS')
well_paths = resInsight.project.well_paths()
if len(well_paths) < 1:
print("No well paths in project")
exit(1)
print(well_paths)
wbs_parameters = rips.WbsParameters()
wbs_parameters.user_poisson_ratio = 0.412347
wbs_parameters.pore_pressure_outside_reservoir_source = "USER_DEFINED"
wbs_parameters.user_pp_outside_reservoir = 1.1
wbs_parameters.fg_shale_source = "PROPORTIONAL_TO_SH"
wbs_parameters.user_fg_shale = 1.13
for case in cases:
if case.type == "GeoMechCase":
print (case.case_id)
@ -26,5 +37,13 @@ for case in cases:
print("Exporting to: " + dirname)
for well_path in well_paths:
wbsplot = case.create_well_bore_stability_plot(well_path=well_path, time_step=0)
wbsplot.export_snapshot(export_folder=dirname)
try:
wbsplot = case.create_well_bore_stability_plot(well_path=well_path, time_step=0, wbs_parameters=wbs_parameters)
replace_params = wbsplot.parameters()
replace_params.user_poisson_ratio = 0.654321
replace_params.user_fg_shale = 1.0321
wbsplot.set_parameters(replace_params)
wbsplot.export_snapshot(export_folder=dirname)
except grpc.RpcError as e:
print("Error: ", e.details())

View File

@ -15,13 +15,13 @@ case = None
try:
case = resinsight.project.load_case("Nonsense")
except grpc.RpcError as e:
print("Expected Server Exception Received while loading case: ", e)
print("Expected Server Exception Received while loading case: ", e.code(), e.details())
# Try loading well paths from a non-existing folder. We should get a grpc.RpcError exception from the server
try:
well_path_files = resinsight.project.import_well_paths(well_path_folder="NONSENSE/NONSENSE")
except grpc.RpcError as e:
print("Expected Server Exception Received while loading wellpaths: ", e)
print("Expected Server Exception Received while loading wellpaths: ", e.code(), e.details())
# Try loading well paths from an existing but empty folder. We should get a warning.
try:

View File

@ -14,5 +14,7 @@ print("Exporting to: " + export_folder)
for plot in plots:
plot.export_snapshot(export_folder=export_folder)
plot.export_data_as_las(export_folder=export_folder)
plot.export_data_as_ascii(export_folder=export_folder)
well_log_plot = rips.WellLogPlot.from_pdm_object(plot)
if well_log_plot is not None:
well_log_plot.export_data_as_las(export_folder=export_folder)
well_log_plot.export_data_as_ascii(export_folder=export_folder)

View File

@ -34,10 +34,11 @@ for case in cases:
time_steps = case.time_steps()
print('Number of time_steps: ' + str(len(time_steps)))
view = case.views()[0]
for property in property_list:
view.apply_cell_result(result_type='DYNAMIC_NATIVE', result_variable=property)
for view in case.views():
if view.is_eclipse_view():
for property in property_list:
view.apply_cell_result(result_type='DYNAMIC_NATIVE', result_variable=property)
for time_step in range(0, len(time_steps), 10):
view.set_time_step(time_step = time_step)
view.export_snapshot()

View File

@ -12,3 +12,5 @@ from rips.view import View
from rips.project import Project
from rips.plot import Plot
from rips.contour_map import ContourMap, ContourMapType
from rips.well_log_plot import WellLogPlot
from rips.well_bore_stability_plot import WellBoreStabilityPlot, WbsParameters

View File

@ -12,13 +12,17 @@ import grpc
import rips.generated.Case_pb2 as Case_pb2
import rips.generated.Case_pb2_grpc as Case_pb2_grpc
import rips.generated.Commands_pb2 as Cmd
import rips.generated.PdmObject_pb2 as PdmObject_pb2
import rips.generated.Properties_pb2 as Properties_pb2
import rips.generated.Properties_pb2_grpc as Properties_pb2_grpc
from rips.grid import Grid
from rips.pdmobject import PdmObject
from rips.view import View
from rips.contour_map import ContourMap, ContourMapType
from rips.well_bore_stability_plot import WellBoreStabilityPlot, WbsParameters
class Case(PdmObject):
"""ResInsight case class
@ -224,10 +228,15 @@ class Case(PdmObject):
def views(self):
"""Get a list of views belonging to a case"""
pdm_objects = self.children("ReservoirViews")
eclipse_pdm_objects = self.children("ReservoirViews")
geomech_pdm_objects = self.children("GeoMechViews")
view_list = []
for pdm_object in pdm_objects:
for pdm_object in eclipse_pdm_objects:
view_list.append(View(pdm_object, self._project))
for pdm_object in geomech_pdm_objects:
view_list.append(View(pdm_object, self._project))
return view_list
def view(self, view_id):
@ -750,7 +759,7 @@ class Case(PdmObject):
exportFile=export_file,
))
def create_well_bore_stability_plot(self, well_path, time_step, wbsParameters=None):
def create_well_bore_stability_plot(self, well_path, time_step, wbs_parameters=None):
""" Create a new well bore stability plot
Arguments:
@ -760,11 +769,17 @@ class Case(PdmObject):
Returns:
A new plot object
"""
pdm_parameters = None
if wbs_parameters is not None:
assert(isinstance(wbs_parameters, WbsParameters))
pdm_parameters = PdmObject.create("WbsParameters", self.__channel, self._project)
wbs_parameters.to_pdm_object(pdm_parameters)
plot_result = self._execute_command(createWellBoreStabilityPlot=Cmd.CreateWbsPlotRequest(caseId=self.case_id,
wellPath=well_path,
timeStep=time_step,
wbsParameters=wbsParameters))
return self._project.plot(view_id=plot_result.createWbsPlotResult.viewId)
wbsParameters=pdm_parameters.pb2_object()))
return WellBoreStabilityPlot(self._project.plot(view_id=plot_result.createWbsPlotResult.viewId))
def import_formation_names(self, formation_files=None):
""" Import formation names into project and apply it to the current case

View File

@ -2,12 +2,14 @@
"""
ResInsight caf::PdmObject connection module
"""
import grpc
import rips.generated.PdmObject_pb2 as PdmObject_pb2
import rips.generated.PdmObject_pb2_grpc as PdmObject_pb2_grpc
import rips.generated.Commands_pb2 as Cmd
import rips.generated.Commands_pb2_grpc as CmdRpc
class PdmObject:
"""
Generic ResInsight object. Corresponds to items in the Project Tree
@ -31,6 +33,11 @@ class PdmObject:
self._project = project
self.__warnings = []
@classmethod
def create(cls, class_keyword, channel, project):
pb2_object = PdmObject_pb2.PdmObject(class_keyword=class_keyword)
return cls(pb2_object, channel, project)
def warnings(self):
return self.__warnings
@ -166,11 +173,16 @@ class PdmObject:
"""
request = PdmObject_pb2.PdmChildObjectRequest(object=self._pb2_object,
child_field=child_field)
object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects
child_list = []
for pdm_object in object_list:
child_list.append(PdmObject(pdm_object, self._channel, self._project))
return child_list
try:
object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects
child_list = []
for pdm_object in object_list:
child_list.append(PdmObject(pdm_object, self._channel, self._project))
return child_list
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return []
raise e
def ancestor(self, class_keyword):
"""Find the first ancestor that matches the provided class_keyword
@ -179,8 +191,13 @@ class PdmObject:
"""
request = PdmObject_pb2.PdmParentObjectRequest(
object=self._pb2_object, parent_keyword=class_keyword)
return PdmObject(self._pdm_object_stub.GetAncestorPdmObject(request),
self._channel, self._project)
try:
return PdmObject(self._pdm_object_stub.GetAncestorPdmObject(request),
self._channel, self._project)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return None
raise e
def update(self):
"""Sync all fields from the Python Object to ResInsight"""

View File

@ -30,44 +30,4 @@ class Plot(PdmObject):
viewId=self.view_id,
exportFolder=export_folder))
def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
export_tvdrkb(bool): Export in TVD-RKB format
capitalize_file_names(bool): Make all file names upper case
resample_interval(double): if > 0.0 the files will be resampled
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Cmd.ExportWellLogPlotDataRequest(exportFormat='LAS',
viewId=self.view_id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=export_tvdrkb,
capitalizeFileNames=capitalize_file_names,
resampleInterval=resample_interval))
return res.exportWellLogPlotDataResult.exportedFiles
def export_data_as_ascii(self, export_folder, file_prefix='', capitalize_file_names=False):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
capitalize_file_names(bool): Make all file names upper case
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Cmd.ExportWellLogPlotDataRequest(exportFormat='ASCII',
viewId=self.view_id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=False,
capitalizeFileNames=capitalize_file_names,
resampleInterval=0.0))
return res.exportWellLogPlotDataResult.exportedFiles

View File

@ -18,6 +18,12 @@ class View(PdmObject):
PdmObject.__init__(self, pdm_object.pb2_object(), pdm_object.channel(), project)
self.view_id = pdm_object.get_value("ViewId")
def is_eclipse_view(self):
return self.class_keyword() == "ReservoirView"
def is_geomech_view(self):
return self.class_keyword() == "GeoMechView"
def show_grid_box(self):
"""Check if the grid box is meant to be shown in the view"""
return self.get_value("ShowGridBox")

View File

@ -0,0 +1,125 @@
"""
ResInsight Well Bore Stability Plot module
"""
from rips.pdmobject import PdmObject
from rips.well_log_plot import WellLogPlot
class WbsParameters:
"""Well Bore Stability parameters
Note that any parameter sources left at "UNDEFINED" will get ResInsight defaults
which depends on the available data.
Attributes:
pore_pressure_in_reservoir_source(enum string): can be "GRID", "LAS_FILE" and "ELEMENT_PROPERTY_TABLE".
pore_pressure_outside_reservoir_source(enum string): can be "HYDROSTATIC" and "USER_DEFINED".
poisson_ratio_source(enum string): can be "LAS_FILE", "ELEMENT_PROPERTY_TABLE" or "USER_DEFINED".
ucs_source(enum string): can be "LAS_FILE", "ELEMENT_PROPERTY_TABLE" or "USER_DEFINED".
obg0_source(enum string): can be "GRID" or "LAS_FILE".
df_source(enum string): can be "LAS_FILE", "ELEMENT_PROPERTY_TABLE" or "USER_DEFINED".
fg_shale_source(enum string): can be "DERIVED_FROM_K0FG" or "PROPORTIONAL_TO_SH".
k0fg_source(enum string): can be "LAS_FILE" or "USER_DEFINED"". Only relevant if fg_shale_source is "DERIVED_FROM_K0FG".
user_pp_outside_reservoir(double): Used if pore_pressure_outside_reservoir_source is "USED_DEFINED". Default 1.05.
user_poission_ratio(double): Used if poisson_ratio_source is "USER_DEFINED", default 0.35.
user_ucs(double): Used if ucs_soruce is "USER_DEFINED", default 100.
user_df(double): Used if df is "USER_DEFINED", default 0.7.
user_k0sh(double): Used if k0sh_source is "USER_DEFINED", default 0.65.
fg_shale_sh_multiplier(double): Used if fg_shale_source is "PROPORTIONAL_TO_SH", default 1.05.
user_k0fg(double): Used if fg_shale_source is "DERIVED_FROM_K0FG" and k0fg_source is "USER_DEFINED", default 0.75.
"""
def __init__(self):
self.pore_pressure_in_reservoir_source = "UNDEFINED"
self.pore_pressure_outside_reservoir_source = "UNDEFINED"
self.poisson_ratio_source = "UNDEFINED"
self.ucs_source = "UNDEFINED"
self.obg0_source = "UNDEFINED"
self.df_source = "UNDEFINED"
self.k0sh_source = "UNDEFINED"
self.fg_shale_source = "UNDEFINED"
self.k0fg_source = "UNDEFINED"
self.user_pp_outside_reservoir = 1.05
self.user_poission_ratio = 0.35
self.user_ucs = 100
self.user_df = 0.7
self.user_k0sh = 0.65
self.fg_shale_multiplier = 1.05
self.user_k0fg = 0.75
@classmethod
def from_pdm_object(cls, pdm_object):
params = cls()
params.pore_pressure_in_reservoir_source = pdm_object.get_value("PorePressureReservoirSource")
params.pore_pressure_outside_reservoir_source = pdm_object.get_value("PorePressureNonReservoirSource")
params.poisson_ratio_source = pdm_object.get_value("PoissonRatioSource")
params.ucs_source = pdm_object.get_value("UcsSource")
params.obg0_source = pdm_object.get_value("OBG0Source")
params.df_source = pdm_object.get_value("DFSource")
params.k0sh_source = pdm_object.get_value("K0SHSource")
params.fg_shale_source = pdm_object.get_value("FGShaleSource")
params.k0fg_source = pdm_object.get_value("K0FGSource")
params.user_pp_outside_reservoir = pdm_object.get_value("UserPPNonReservoir")
params.user_poisson_ratio = pdm_object.get_value("UserPoissonRatio")
params.user_ucs = pdm_object.get_value("UserUcs")
params.user_df = pdm_object.get_value("UserDF")
params.user_k0fg = pdm_object.get_value("UserK0FG")
params.user_k0sh = pdm_object.get_value("UserK0SH")
params.user_fg_shale = pdm_object.get_value("FGMultiplier")
return params
def to_pdm_object(self, pdm_object):
pdm_object.set_value("PorePressureReservoirSource", self.pore_pressure_in_reservoir_source)
pdm_object.set_value("PorePressureNonReservoirSource", self.pore_pressure_outside_reservoir_source)
pdm_object.set_value("UserPPNonReservoir", self.user_pp_outside_reservoir)
pdm_object.set_value("PoissonRatioSource", self.poisson_ratio_source)
pdm_object.set_value("UcsSource", self.ucs_source)
pdm_object.set_value("OBG0Source", self.obg0_source)
pdm_object.set_value("DFSource", self.df_source)
pdm_object.set_value("K0SHSource", self.k0sh_source)
pdm_object.set_value("FGShaleSource", self.fg_shale_source)
pdm_object.set_value("K0FGSource", self.k0fg_source)
pdm_object.set_value("UserPoissonRatio", self.user_poisson_ratio)
pdm_object.set_value("UserUcs", self.user_ucs)
pdm_object.set_value("UserDF", self.user_df)
pdm_object.set_value("UserK0FG", self.user_k0fg)
pdm_object.set_value("UserK0SH", self.user_k0sh)
pdm_object.set_value("FGMultiplier", self.user_fg_shale)
class WellBoreStabilityPlot(WellLogPlot):
"""ResInsight Well Bore Stability Plot
"""
def __init__(self, pdm_object):
WellLogPlot.__init__(self, pdm_object)
@classmethod
def from_pdm_object(cls, pdm_object):
if isinstance(pdm_object, PdmObject):
if pdm_object.class_keyword() == "WellBoreStabilityPlot":
return cls(pdm_object)
return None
def parameters(self):
"""Retrieve the parameters of the Plot
"""
children = self.children("WbsParameters")
if len(children) == 1:
child = children[0]
return WbsParameters.from_pdm_object(child)
return None
def set_parameters(self, wbs_parameters):
children = self.children("WbsParameters")
if len(children) == 1:
pdm_params = children[0]
wbs_parameters.to_pdm_object(pdm_params)
pdm_params.update()

View File

@ -0,0 +1,81 @@
"""
ResInsight Well Log Plot plot module
"""
import rips.generated.Commands_pb2 as Cmd
from rips.plot import Plot
from rips.pdmobject import PdmObject
class WellLogPlot(Plot):
"""ResInsight well log plot class
"""
def __init__(self, pdm_object):
Plot.__init__(self, pdm_object)
@classmethod
def from_pdm_object(cls, pdm_object):
if isinstance(pdm_object, PdmObject):
if pdm_object.class_keyword() == "WellLogPlot":
return cls(pdm_object)
return None
def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
export_tvdrkb(bool): Export in TVD-RKB format
capitalize_file_names(bool): Make all file names upper case
resample_interval(double): if > 0.0 the files will be resampled
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Cmd.ExportWellLogPlotDataRequest(exportFormat='LAS',
viewId=self.view_id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=export_tvdrkb,
capitalizeFileNames=capitalize_file_names,
resampleInterval=resample_interval))
return res.exportWellLogPlotDataResult.exportedFiles
def export_data_as_ascii(self, export_folder, file_prefix='', capitalize_file_names=False):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
capitalize_file_names(bool): Make all file names upper case
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Cmd.ExportWellLogPlotDataRequest(exportFormat='ASCII',
viewId=self.view_id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=False,
capitalizeFileNames=capitalize_file_names,
resampleInterval=0.0))
return res.exportWellLogPlotDataResult.exportedFiles
def depth_range(self):
"""Get the depth range of the Plot
"""
return self.get_value("MinimumDepth"), self.get_value("MaximumDepth")
def set_depth_range(self, min_depth, max_depth):
""" Set the visible depth range minimum
Arguments:
min_depth(double): The new minimum depth
max_depth(double): The new maximum depth
"""
self.set_value("MinimumDepth", min_depth)
self.set_value("MaximumDepth", max_depth)
self.update()

View File

@ -239,6 +239,13 @@ void RiaGrpcCommandService::assignPdmObjectValues( caf::PdmObjectHandle*
const Message& subMessage = reflection->GetMessage( params, paramDescriptor );
const rips::PdmObject* ripsPdmObject = dynamic_cast<const rips::PdmObject*>( &subMessage );
if ( ripsPdmObject )
{
copyPdmObjectFromRipsToCaf( ripsPdmObject, pdmObjectHandle );
return;
}
auto messageDescriptor = paramDescriptor->message_type();
int numParameters = messageDescriptor->field_count();
for ( int i = 0; i < numParameters; ++i )

View File

@ -103,7 +103,6 @@ void RiaGrpcServiceInterface::copyPdmObjectFromRipsToCaf( const rips::PdmObject*
{
CAF_ASSERT( source && destination && destination->xmlCapability() );
CAF_ASSERT( source->class_keyword() == destination->xmlCapability()->classKeyword().toStdString() );
CAF_ASSERT( source->address() == reinterpret_cast<uint64_t>( destination ) );
std::vector<caf::PdmFieldHandle*> fields;
destination->fields( fields );

View File

@ -79,7 +79,7 @@ RimWbsParameters::RimWbsParameters()
"" );
RICF_InitField( &m_userDefinedPoissionRatio,
"UserPoissionRatio",
"UserPoissonRatio",
0.35,
"User Defined Poisson Ratio",
"",

View File

@ -2374,11 +2374,11 @@ void RimWellLogTrack::updateWellPathAttributesOnPlot()
{
m_wellPathAttributePlotObjects.clear();
if ( wellPathAttributeSource() )
if ( wellPathAttributeSource())
{
std::vector<const RimWellPathComponentInterface*> allWellPathComponents;
if ( m_showWellPathAttributes || m_showWellPathCompletions )
if ( wellPathAttributeSource()->wellPathGeometry() && (m_showWellPathAttributes || m_showWellPathCompletions ))
{
m_wellPathAttributePlotObjects.push_back( std::unique_ptr<RiuWellPathComponentPlotItem>(
new RiuWellPathComponentPlotItem( wellPathAttributeSource() ) ) );

View File

@ -227,7 +227,8 @@ RigWbsParameter RigWbsParameter::OBG()
//--------------------------------------------------------------------------------------------------
RigWbsParameter RigWbsParameter::OBG0()
{
std::vector<std::pair<Source, SourceAddress>> sources = {{GRID, SourceAddress( "ST", "S33" )}};
std::vector<std::pair<Source, SourceAddress>> sources = {{GRID, SourceAddress( "ST", "S33" )},
{LAS_FILE, SourceAddress( "POR" )}};
return RigWbsParameter( "OBG0", true, sources );
}

View File

@ -52,7 +52,7 @@ RiuWellPathComponentPlotItem::RiuWellPathComponentPlotItem( const RimWellPath* w
, m_maxColumnOffset( 0.0 )
, m_showLabel( false )
{
CVF_ASSERT( wellPath );
CVF_ASSERT( wellPath && wellPath->wellPathGeometry() );
double wellStart = wellPath->wellPathGeometry()->measureDepths().front();
double wellEnd = wellPath->wellPathGeometry()->measureDepths().back();
m_startMD = wellStart;