diff --git a/ApplicationCode/GrpcInterface/CMakeLists.cmake b/ApplicationCode/GrpcInterface/CMakeLists.cmake index 29e41cb87a..ecee06a030 100644 --- a/ApplicationCode/GrpcInterface/CMakeLists.cmake +++ b/ApplicationCode/GrpcInterface/CMakeLists.cmake @@ -13,6 +13,7 @@ set ( SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcAppService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPropertiesService.h + ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcNNCPropertiesService.h ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPdmObjectService.h ) @@ -27,6 +28,7 @@ set ( SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcAppService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPropertiesService.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcNNCPropertiesService.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPdmObjectService.cpp ) @@ -88,6 +90,7 @@ set(PROTO_FILES "SimulationWell" "Project" "Commands" + "NNCProperties" "App" "Properties" "Grid" diff --git a/ApplicationCode/GrpcInterface/GrpcProtos/NNCProperties.proto b/ApplicationCode/GrpcInterface/GrpcProtos/NNCProperties.proto new file mode 100644 index 0000000000..6475115854 --- /dev/null +++ b/ApplicationCode/GrpcInterface/GrpcProtos/NNCProperties.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +import "Case.proto"; +import "Definitions.proto"; + +package rips; + +service NNCProperties +{ + rpc GetAvailableNNCProperties(CaseRequest) returns (AvailableNNCProperties) {} + rpc GetNNCConnections(CaseRequest) returns (stream NNCConnections) {} +} + +enum NNCPropertyType +{ + NNC_DYNAMIC = 0; + NNC_STATIC = 1; + NNC_GENERATED = 2; +} + +message AvailableNNCProperty +{ + string name = 1; + NNCPropertyType property_type = 2; +} + +message AvailableNNCProperties +{ + repeated AvailableNNCProperty properties = 1; +} + +message NNCConnection +{ + int32 cell_grid_index1 = 1; + int32 cell_grid_index2 = 2; + Vec3i cell1 = 3; + Vec3i cell2 = 4; +} + +message NNCConnections +{ + repeated NNCConnection connections = 1; +} diff --git a/ApplicationCode/GrpcInterface/Python/rips/case.py b/ApplicationCode/GrpcInterface/Python/rips/case.py index 0099118b34..a61b2bd185 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/case.py +++ b/ApplicationCode/GrpcInterface/Python/rips/case.py @@ -17,6 +17,9 @@ 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 +import rips.generated.NNCProperties_pb2 as NNCProperties_pb2 +import rips.generated.NNCProperties_pb2_grpc as NNCProperties_pb2_grpc + from rips.grid import Grid from rips.pdmobject import PdmObject from rips.view import View @@ -50,6 +53,8 @@ class Case(PdmObject): info = self.__case_stub.GetCaseInfo(self.__request) self.__properties_stub = Properties_pb2_grpc.PropertiesStub( self.__channel) + self.__nnc_properties_stub = NNCProperties_pb2_grpc.NNCPropertiesStub( + self.__channel) PdmObject.__init__(self, self.__case_stub.GetPdmObject(self.__request), self.__channel, project) @@ -980,3 +985,31 @@ class Case(PdmObject): for each entry. """ return self.__case_stub.GetCoarseningInfoArray(self.__request).data + + + def available_nnc_properties(self): + """Get a list of available NNC properties + """ + return self.__nnc_properties_stub.GetAvailableNNCProperties(self.__request).properties + + + def nnc_connections_async(self): + """Get the NNC connections. Async, so returns an iterator. + Returns: + An iterator to a chunk object containing an array NNCConnection objects. + Loop through the chunks and then the connection within the chunk to get all connections. + """ + return self.__nnc_properties_stub.GetNNCConnections(self.__request) + + def nnc_connections(self): + """Get the NNC connection. Synchronous, so returns a list. + + Returns: + A list of NNCConnection objects. + """ + connections = [] + generator = self.nnc_connections_async() + for chunk in generator: + for value in chunk.connections: + connections.append(value) + return connections diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_nnc_properties.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_nnc_properties.py new file mode 100644 index 0000000000..59ca06e259 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_nnc_properties.py @@ -0,0 +1,35 @@ +import sys +import os +import grpc +import pytest + +import rips.generated.NNCProperties_pb2 as NNCProperties_pb2 + +sys.path.insert(1, os.path.join(sys.path[0], '../../')) +import rips + +import dataroot + + +def test_10kSync(rips_instance, initialize_test): + casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" + case = rips_instance.project.load_case(path=casePath) + + properties = case.available_nnc_properties() + assert(len(properties) == 3) + + assert("TRAN" == properties[0].name) + assert(NNCProperties_pb2.NNCPropertyType.NNC_STATIC == properties[0].property_type) + assert("Binary Formation Allen" == properties[1].name) + assert(NNCProperties_pb2.NNCPropertyType.NNC_GENERATED == properties[1].property_type) + assert("Formation Allen" == properties[2].name) + assert(NNCProperties_pb2.NNCPropertyType.NNC_GENERATED == properties[2].property_type) + + nnc_connections = case.nnc_connections() + assert(len(nnc_connections) == 84759) + + connection = nnc_connections[0] + assert(connection.cell1.i == 33) + assert(connection.cell1.j == 40) + assert(connection.cell1.k == 14) + assert(connection.cell_grid_index1 == 0) diff --git a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp new file mode 100644 index 0000000000..3528aef124 --- /dev/null +++ b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp @@ -0,0 +1,181 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 +// for more details. +// +////////////////////////////////////////////////////////////////////////////////// +#include "RiaGrpcNNCPropertiesService.h" + +#include "RiaGrpcCallbacks.h" +#include "RiaGrpcCaseService.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigEclipseResultInfo.h" +#include "RigMainGrid.h" +#include "RimEclipseCase.h" + +using namespace rips; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaNNCConnectionsStateHandler::RiaNNCConnectionsStateHandler() + : m_request( nullptr ) + , m_eclipseCase( nullptr ) + , m_currentIdx( 0u ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaNNCConnectionsStateHandler::init( const rips::CaseRequest* request ) +{ + CAF_ASSERT( request ); + m_request = request; + + RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->id() ); + m_eclipseCase = dynamic_cast( rimCase ); + + if ( !( m_eclipseCase && m_eclipseCase->eclipseCaseData() && m_eclipseCase->eclipseCaseData()->mainGrid() ) ) + { + return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" ); + } + + return grpc::Status::OK; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +rips::Vec3i* createConnectionVec3i( const RigCell& cell ) +{ + RigGridBase* hostGrid = cell.hostGrid(); + size_t gridLocalCellIndex = cell.gridLocalCellIndex(); + size_t i, j, k; + hostGrid->ijkFromCellIndex( gridLocalCellIndex, &i, &j, &k ); + + rips::Vec3i* vec = new rips::Vec3i; + vec->set_i( i ); + vec->set_j( j ); + vec->set_k( k ); + + return vec; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaNNCConnectionsStateHandler::assignReply( rips::NNCConnections* reply ) +{ + RigMainGrid* mainGrid = m_eclipseCase->eclipseCaseData()->mainGrid(); + std::vector connections = mainGrid->nncData()->connections(); + + size_t connectionCount = connections.size(); + const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::NNCConnection ) ); + size_t indexInPackage = 0u; + reply->mutable_connections()->Reserve( (int)packageSize ); + for ( ; indexInPackage < packageSize && m_currentIdx < connectionCount; ++indexInPackage ) + { + RigConnection& connection = connections[m_currentIdx]; + const RigCell& cell1 = mainGrid->globalCellArray()[connection.m_c1GlobIdx]; + const RigCell& cell2 = mainGrid->globalCellArray()[connection.m_c2GlobIdx]; + + NNCConnection* nncConnection = reply->add_connections(); + nncConnection->set_allocated_cell1( createConnectionVec3i( cell1 ) ); + nncConnection->set_allocated_cell2( createConnectionVec3i( cell2 ) ); + nncConnection->set_cell_grid_index1( cell1.hostGrid()->gridIndex() ); + nncConnection->set_cell_grid_index2( cell2.hostGrid()->gridIndex() ); + + m_currentIdx++; + } + + if ( indexInPackage > 0u ) + { + return Status::OK; + } + return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcNNCPropertiesService::GetNNCConnections( grpc::ServerContext* context, + const rips::CaseRequest* request, + rips::NNCConnections* reply, + RiaNNCConnectionsStateHandler* stateHandler ) +{ + return stateHandler->assignReply( reply ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcNNCPropertiesService::GetAvailableNNCProperties( grpc::ServerContext* context, + const CaseRequest* request, + AvailableNNCProperties* reply ) +{ + RimEclipseCase* eclipseCase = dynamic_cast( RiaGrpcServiceInterface::findCase( request->id() ) ); + if ( eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid() ) + { + RigNNCData* nncData = eclipseCase->eclipseCaseData()->mainGrid()->nncData(); + + std::vector resultTypes; + resultTypes.push_back( RigNNCData::NNC_DYNAMIC ); + resultTypes.push_back( RigNNCData::NNC_STATIC ); + resultTypes.push_back( RigNNCData::NNC_GENERATED ); + + for ( size_t rtIdx = 0; rtIdx < resultTypes.size(); ++rtIdx ) + { + std::vector availableParameters = nncData->availableProperties( resultTypes[rtIdx] ); + + for ( const QString& parameter : availableParameters ) + { + AvailableNNCProperty* property = reply->add_properties(); + property->set_name( parameter.toStdString() ); + property->set_property_type( static_cast( resultTypes[rtIdx] ) ); + } + } + + return grpc::Status::OK; + } + return grpc::Status( grpc::NOT_FOUND, "No such case" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaGrpcNNCPropertiesService::createCallbacks() +{ + typedef RiaGrpcNNCPropertiesService Self; + + std::vector callbacks; + callbacks = {new RiaGrpcUnaryCallback( this, + &Self::GetAvailableNNCProperties, + &Self::RequestGetAvailableNNCProperties ), + new RiaGrpcServerToClientStreamCallback( this, + &Self::GetNNCConnections, + &Self::RequestGetNNCConnections, + new RiaNNCConnectionsStateHandler )}; + return callbacks; +} + +static bool RiaGrpcNNCPropertiesService_init = + RiaGrpcServiceFactory::instance()->registerCreator( + typeid( RiaGrpcNNCPropertiesService ).hash_code() ); diff --git a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h new file mode 100644 index 0000000000..ce42ccc56d --- /dev/null +++ b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 +// for more details. +// +////////////////////////////////////////////////////////////////////////////////// +#pragma once +#include "RiaGrpcServiceInterface.h" + +#include "NNCProperties.grpc.pb.h" + +#include +#include + +class RimEclipseCase; + +//================================================================================================== +// +// State handler for streaming of NNC connections +// +//================================================================================================== +class RiaNNCConnectionsStateHandler +{ + typedef grpc::Status Status; + +public: + RiaNNCConnectionsStateHandler(); + grpc::Status init( const rips::CaseRequest* request ); + grpc::Status assignReply( rips::NNCConnections* reply ); + +protected: + const rips::CaseRequest* m_request; + RimEclipseCase* m_eclipseCase; + size_t m_currentIdx; +}; + +//================================================================================================== +// +// gRPC-service answering requests about NNC property information for a given case and time step +// +//================================================================================================== +class RiaGrpcNNCPropertiesService final : public rips::NNCProperties::AsyncService, public RiaGrpcServiceInterface +{ +public: + grpc::Status GetAvailableNNCProperties( grpc::ServerContext* context, + const rips::CaseRequest* request, + rips::AvailableNNCProperties* reply ) override; + grpc::Status GetNNCConnections( grpc::ServerContext* context, + const rips::CaseRequest* request, + rips::NNCConnections* reply, + RiaNNCConnectionsStateHandler* stateHandler ); + + std::vector createCallbacks() override; +};