#4550 Add python method to get simulation wells with status and cells info.

This commit is contained in:
Kristian Bendiksen 2020-02-11 21:20:53 +01:00
parent 2788c7a6c1
commit f7af2ed83e
12 changed files with 426 additions and 9 deletions

View File

@ -6,6 +6,7 @@ set ( SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.inl ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.inl
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcSimulationWellService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.h
@ -18,6 +19,7 @@ set ( SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcSimulationWellService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.cpp
@ -81,6 +83,7 @@ set(PROTO_FILES
"Definitions" "Definitions"
"PdmObject" "PdmObject"
"Case" "Case"
"SimulationWell"
"Project" "Project"
"Commands" "Commands"
"App" "App"

View File

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "PdmObject.proto"; import "PdmObject.proto";
import "Definitions.proto";
package rips; package rips;
@ -60,12 +61,6 @@ message GridCount
int32 count = 1; int32 count = 1;
} }
message Vec3i {
int32 i = 1;
int32 j = 2;
int32 k = 3;
}
message CellCount message CellCount
{ {
int32 active_cell_count = 1; int32 active_cell_count = 1;

View File

@ -9,4 +9,11 @@ message Empty
message ClientToServerStreamReply message ClientToServerStreamReply
{ {
int64 accepted_value_count = 1; int64 accepted_value_count = 1;
} }
message Vec3i {
int32 i = 1;
int32 j = 2;
int32 k = 3;
}

View File

@ -2,6 +2,7 @@ syntax = "proto3";
package rips; package rips;
import "Definitions.proto";
import "Case.proto"; import "Case.proto";
service Grid service Grid

View File

@ -0,0 +1,37 @@
syntax = "proto3";
import "Definitions.proto";
package rips;
service SimulationWell
{
rpc GetSimulationWellStatus(SimulationWellRequest) returns (SimulationWellStatus) {}
rpc GetSimulationWellCells(SimulationWellRequest) returns (SimulationWellCellInfoArray) {}
}
message SimulationWellRequest {
int32 case_id = 1;
string well_name = 2;
int32 timestep = 3;
}
message SimulationWellStatus
{
string well_type = 1;
bool is_open = 2;
}
message SimulationWellCellInfo {
Vec3i ijk = 1;
int32 grid_index = 2;
bool is_open = 3;
int32 branch_id = 4;
int32 segment_id = 5;
}
message SimulationWellCellInfoArray
{
repeated SimulationWellCellInfo data = 1;
}

View File

@ -0,0 +1,27 @@
###################################################################################
# This example will connect to ResInsight, retrieve a list of
# simulation wells and print info
###################################################################################
# Import the ResInsight Processing Server Module
import rips
# Connect to ResInsight
resinsight = rips.Instance.find()
if resinsight is not None:
# Get a list of all wells
cases = resinsight.project.cases()
for case in cases:
print("Case id: " + str(case.case_id))
print("Case name: " + case.name)
timesteps = case.time_steps()
sim_wells = case.simulation_wells()
for sim_well in sim_wells:
print("Simulation well: " + sim_well.name)
for (tidx, timestep) in enumerate(timesteps):
status = sim_well.status(tidx)
cells = sim_well.cells(tidx)
print("timestep: " + str(tidx) + " type: " + status.well_type + " open: " + str(status.is_open) + " cells:" + str(len(cells)))

View File

@ -17,12 +17,12 @@ import rips.generated.PdmObject_pb2 as PdmObject_pb2
import rips.generated.Properties_pb2 as Properties_pb2 import rips.generated.Properties_pb2 as Properties_pb2
import rips.generated.Properties_pb2_grpc as Properties_pb2_grpc import rips.generated.Properties_pb2_grpc as Properties_pb2_grpc
from rips.grid import Grid from rips.grid import Grid
from rips.pdmobject import PdmObject from rips.pdmobject import PdmObject
from rips.view import View from rips.view import View
from rips.contour_map import ContourMap, ContourMapType from rips.contour_map import ContourMap, ContourMapType
from rips.well_bore_stability_plot import WellBoreStabilityPlot, WbsParameters from rips.well_bore_stability_plot import WellBoreStabilityPlot, WbsParameters
from rips.simulation_well import SimulationWell
class Case(PdmObject): class Case(PdmObject):
"""ResInsight case class """ResInsight case class
@ -808,3 +808,15 @@ class Case(PdmObject):
res = self._execute_command(importFormationNames=Cmd.ImportFormationNamesRequest(formationFiles=formation_files, res = self._execute_command(importFormationNames=Cmd.ImportFormationNamesRequest(formationFiles=formation_files,
applyToCaseId=self.case_id)) applyToCaseId=self.case_id))
def simulation_wells(self):
"""Get a list of all simulation wells for a case
Returns:
A list of rips SimulationWell objects
"""
pdm_objects = self.descendants("Well")
wells = []
for pdm_object in pdm_objects:
wells.append(SimulationWell(pdm_object.get_value("WellName"), self.case_id, pdm_object))
return wells

View File

@ -0,0 +1,39 @@
"""
ResInsight SimulationWell
"""
import grpc
import rips.generated.SimulationWell_pb2 as SimulationWell_pb2
import rips.generated.SimulationWell_pb2_grpc as SimulationWell_pb2_grpc
import rips.generated.Properties_pb2 as Properties_pb2
import rips.generated.Properties_pb2_grpc as Properties_pb2_grpc
import rips.generated.Commands_pb2 as Cmd
from rips.pdmobject import PdmObject
class SimulationWell(PdmObject):
"""ResInsight simulation well class
Attributes:
name(string): Name of the well.
"""
def __init__(self, name, case_id, pdm_object):
PdmObject.__init__(self, pdm_object.pb2_object(), pdm_object.channel(), pdm_object.project())
self._simulation_well_stub = SimulationWell_pb2_grpc.SimulationWellStub(pdm_object.channel())
self.name = name
self.case_id = case_id
def status(self, timestep):
sim_well_request = SimulationWell_pb2.SimulationWellRequest(case_id=self.case_id,
well_name=self.name,
timestep=timestep)
return self._simulation_well_stub.GetSimulationWellStatus(sim_well_request)
def cells(self, timestep):
sim_well_request = SimulationWell_pb2.SimulationWellRequest(case_id=self.case_id,
well_name=self.name,
timestep=timestep)
return self._simulation_well_stub.GetSimulationWellCells(sim_well_request).data

View File

@ -0,0 +1,49 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def test_10k(rips_instance, initialize_test):
case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID"
case = rips_instance.project.load_case(path=case_path)
assert(len(case.grids()) == 2)
cell_count_info = case.cell_count()
sim_wells = case.simulation_wells()
assert(len(sim_wells) == 3)
assert(sim_wells[0].name == "GI1")
assert(sim_wells[1].name == "GP1")
assert(sim_wells[2].name == "GP2")
timesteps = case.time_steps()
# On time step 0 all simulation wells are undefined
for sim_well in sim_wells:
status = sim_well.status(0)
assert(status.well_type == "NotDefined")
# On time step 3 all wells are producing
for sim_well in sim_wells:
status = sim_well.status(3)
assert(status.well_type == "Producer")
# On time step 0 all simulation wells have no cells
for sim_well in sim_wells:
cells = sim_well.cells(0)
assert(len(cells) == 0)
# On the other time steps there should be cells
expected_cell_count = {}
expected_cell_count["GP1"] = 105
expected_cell_count["GI1"] = 38
expected_cell_count["GP2"] = 18
for sim_well in sim_wells:
for (tidx, timestep) in enumerate(timesteps):
if (tidx > 0):
cells = sim_well.cells(tidx)
print("well: " + sim_well.name + " timestep: " + str(tidx) + " cells:" + str(len(cells)))
assert(len(cells) == expected_cell_count[sim_well.name])

View File

@ -0,0 +1,185 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "RiaGrpcSimulationWellService.h"
#include "RiaGrpcCallbacks.h"
#include "RigEclipseCaseData.h"
#include "RigGridBase.h"
#include "RigSimWellData.h"
#include "RimCase.h"
#include "RimEclipseCase.h"
#include "cvfCollection.h"
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcSimulationWellService::GetSimulationWellStatus( grpc::ServerContext* context,
const rips::SimulationWellRequest* request,
rips::SimulationWellStatus* reply )
{
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( findCase( request->case_id() ) );
if ( !eclipseCase )
{
return grpc::Status( grpc::NOT_FOUND, "Case not found" );
}
// First find the well result for the correct well
cvf::ref<RigSimWellData> currentWellResult = findWellResult( eclipseCase, request->well_name() );
if ( currentWellResult.isNull() )
{
return grpc::Status( grpc::NOT_FOUND, "Well not found" );
}
size_t tsIdx = static_cast<size_t>( request->timestep() );
QString wellType = "NotDefined";
bool wellStatus = false;
if ( currentWellResult->hasWellResult( tsIdx ) )
{
switch ( currentWellResult->wellResultFrame( tsIdx ).m_productionType )
{
case RigWellResultFrame::PRODUCER:
wellType = "Producer";
break;
case RigWellResultFrame::OIL_INJECTOR:
wellType = "OilInjector";
break;
case RigWellResultFrame::WATER_INJECTOR:
wellType = "WaterInjector";
break;
case RigWellResultFrame::GAS_INJECTOR:
wellType = "GasInjector";
break;
}
wellStatus = currentWellResult->wellResultFrame( tsIdx ).m_isOpen;
}
reply->set_well_type( wellType.toStdString() );
reply->set_is_open( wellStatus );
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcSimulationWellService::GetSimulationWellCells( grpc::ServerContext* context,
const rips::SimulationWellRequest* request,
rips::SimulationWellCellInfoArray* reply )
{
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( findCase( request->case_id() ) );
if ( !eclipseCase )
{
return grpc::Status( grpc::NOT_FOUND, "Case not found" );
}
// First find the well result for the correct well
cvf::ref<RigSimWellData> currentWellResult = findWellResult( eclipseCase, request->well_name() );
if ( currentWellResult.isNull() )
{
return grpc::Status( grpc::NOT_FOUND, "Well not found" );
}
size_t tsIdx = static_cast<size_t>( request->timestep() );
if ( currentWellResult->hasWellResult( tsIdx ) )
{
// Fetch results
const RigWellResultFrame& wellResFrame = currentWellResult->wellResultFrame( tsIdx );
std::vector<RigGridBase*> grids;
eclipseCase->eclipseCaseData()->allGrids( &grids );
for ( size_t bIdx = 0; bIdx < wellResFrame.m_wellResultBranches.size(); ++bIdx )
{
const std::vector<RigWellResultPoint>& branchResPoints =
wellResFrame.m_wellResultBranches[bIdx].m_branchResultPoints;
for ( size_t rpIdx = 0; rpIdx < branchResPoints.size(); ++rpIdx )
{
const RigWellResultPoint& resPoint = branchResPoints[rpIdx];
if ( resPoint.isCell() )
{
rips::SimulationWellCellInfo* cellInfo = reply->add_data();
size_t i;
size_t j;
size_t k;
size_t gridIdx = resPoint.m_gridIndex;
grids[gridIdx]->ijkFromCellIndex( resPoint.m_gridCellIndex, &i, &j, &k );
Vec3i* ijk = new Vec3i;
ijk->set_i( i );
ijk->set_j( j );
ijk->set_k( k );
cellInfo->set_allocated_ijk( ijk );
cellInfo->set_grid_index( gridIdx );
cellInfo->set_is_open( resPoint.m_isOpen );
cellInfo->set_branch_id( resPoint.m_ertBranchId );
cellInfo->set_segment_id( resPoint.m_ertSegmentId );
}
}
}
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigSimWellData> RiaGrpcSimulationWellService::findWellResult( const RimEclipseCase* eclipseCase,
const std::string& wellName )
{
const cvf::Collection<RigSimWellData>& allWellRes = eclipseCase->eclipseCaseData()->wellResults();
for ( size_t tsIdx = 0; tsIdx < allWellRes.size(); ++tsIdx )
{
if ( allWellRes[tsIdx]->m_wellName.toStdString() == wellName )
{
return allWellRes[tsIdx];
}
}
return cvf::ref<RigSimWellData>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcSimulationWellService::createCallbacks()
{
typedef RiaGrpcSimulationWellService Self;
return {
new RiaGrpcUnaryCallback<Self, SimulationWellRequest, SimulationWellStatus>( this,
&Self::GetSimulationWellStatus,
&Self::RequestGetSimulationWellStatus ),
new RiaGrpcUnaryCallback<Self, SimulationWellRequest, SimulationWellCellInfoArray>( this,
&Self::GetSimulationWellCells,
&Self::RequestGetSimulationWellCells ),
};
}
static bool RiaGrpcSimulationWellService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcSimulationWellService>(
typeid( RiaGrpcSimulationWellService ).hash_code() );

View File

@ -0,0 +1,60 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- 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 "SimulationWell.grpc.pb.h"
#include "RiaGrpcServiceInterface.h"
#include "cvfObject.h"
#include <string>
#include <vector>
namespace rips
{
class SimulationWellRequest;
class SimulationWellStatus;
} // namespace rips
class RiaGrpcCallbackInterface;
class RimEclipseCase;
class RigSimWellData;
//==================================================================================================
//
// gRPC-service answering requests about grid information for a simulation wells
//
//==================================================================================================
class RiaGrpcSimulationWellService final : public rips::SimulationWell::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status GetSimulationWellStatus( grpc::ServerContext* context,
const rips::SimulationWellRequest* request,
rips::SimulationWellStatus* reply );
grpc::Status GetSimulationWellCells( grpc::ServerContext* context,
const rips::SimulationWellRequest* request,
rips::SimulationWellCellInfoArray* reply );
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
private:
static cvf::ref<RigSimWellData> findWellResult( const RimEclipseCase* eclipseCase, const std::string& wellName );
};

View File

@ -20,6 +20,8 @@
#include "RimSimWellInView.h" #include "RimSimWellInView.h"
#include "RicfCommandObject.h"
#include "RigActiveCellInfo.h" #include "RigActiveCellInfo.h"
#include "RigCell.h" #include "RigCell.h"
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
@ -62,7 +64,7 @@ RimSimWellInView::RimSimWellInView()
{ {
CAF_PDM_InitObject( "Well", ":/Well.png", "", "" ); CAF_PDM_InitObject( "Well", ":/Well.png", "", "" );
CAF_PDM_InitFieldNoDefault( &name, "WellName", "Name", "", "", "" ); RICF_InitFieldNoDefault( &name, "WellName", "Name", "", "", "" );
CAF_PDM_InitField( &showWell, "ShowWell", true, "Show well ", "", "", "" ); CAF_PDM_InitField( &showWell, "ShowWell", true, "Show well ", "", "", "" );