diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 16c11f7992..06425ce9ea 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1737,7 +1737,8 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) return lhs->classKeyword() < rhs->classKeyword(); } ); - std::map>> classesGenerated; + std::map>> classAttributesGenerated; + std::map> classMethodsGenerated; std::map classCommentsGenerated; // First generate all attributes and comments to go into each object @@ -1767,10 +1768,13 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) auto ricfHandle = field->template capability(); if ( ricfHandle != nullptr ) { - QString snake_field_name = RiaTextStringTools::camelToSnakeCase( ricfHandle->fieldName() ); - if ( classesGenerated[field->ownerClass()].count( snake_field_name ) ) continue; + bool shouldBeMethod = false; + auto proxyField = dynamic_cast( field ); + if ( proxyField && proxyField->isStreamingField() ) shouldBeMethod = true; - QString fieldPythonCode = QString( " self.%1 = None\n" ).arg( snake_field_name ); + QString snake_field_name = RiaTextStringTools::camelToSnakeCase( ricfHandle->fieldName() ); + if ( classAttributesGenerated[field->ownerClass()].count( snake_field_name ) ) continue; + if ( classMethodsGenerated[field->ownerClass()].count( snake_field_name ) ) continue; QString comment; { @@ -1784,9 +1788,47 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) QVariant valueVariant = pdmValueField->toQVariant(); QString dataTypeString = valueVariant.typeName(); - classesGenerated[field->ownerClass()][snake_field_name].first = fieldPythonCode; - classesGenerated[field->ownerClass()][snake_field_name].second = - QString( "%1 (%2): %3\n" ).arg( snake_field_name ).arg( dataTypeString ).arg( comment ); + if ( shouldBeMethod ) + { + if ( proxyField->hasGetter() ) + { + QString fullComment = + QString( " \"\"\"%1\n Returns:\n %2\n \"\"\"" ) + .arg( comment ) + .arg( dataTypeString ); + + QString fieldCode = QString( " def %1(self):\n%2\n return " + "self._call_get_method(\"%3\")\n" ) + .arg( snake_field_name ) + .arg( fullComment ) + .arg( ricfHandle->fieldName() ); + classMethodsGenerated[field->ownerClass()][snake_field_name] = fieldCode; + } + if ( proxyField->hasSetter() ) + { + QString fullComment = QString( " \"\"\"Set %1\n Attributes:\n" + " values (%2): data\n \"\"\"" ) + .arg( comment ) + .arg( dataTypeString ); + + QString fieldCode = QString( " def set_%1(self, values):\n%2\n " + "self._call_set_method(\"%3\", values)\n" ) + .arg( snake_field_name ) + .arg( fullComment ) + .arg( ricfHandle->fieldName() ); + classMethodsGenerated[field->ownerClass()][QString( "set_%1" ).arg( snake_field_name )] = + fieldCode; + } + } + else + { + QString fieldCode = QString( " self.%1 = None\n" ).arg( snake_field_name ); + QString fullComment = + QString( "%1 (%2): %3\n" ).arg( snake_field_name ).arg( dataTypeString ).arg( comment ); + + classAttributesGenerated[field->ownerClass()][snake_field_name].first = fieldCode; + classAttributesGenerated[field->ownerClass()][snake_field_name].second = fullComment; + } } } } @@ -1818,20 +1860,23 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) { classCode = QString( "class %1(%2):\n" ).arg( scriptClassName ).arg( scriptSuperClassNames.back() ); } - - if ( !classCommentsGenerated[classKeyword].isEmpty() || !classesGenerated[classKeyword].empty() ) + if ( !classCommentsGenerated[classKeyword].isEmpty() || !classAttributesGenerated[classKeyword].empty() ) { classCode += " \"\"\"\n"; if ( !classCommentsGenerated[classKeyword].isEmpty() ) { - classCode += QString( " %1\n\n" ).arg( classCommentsGenerated[classKeyword] ); + if ( !classCommentsGenerated[classKeyword].isEmpty() ) + { + classCode += QString( " %1\n\n" ).arg( classCommentsGenerated[classKeyword] ); + } } - - classCode += " Attributes\n"; - classCode += " class_keyword (string): the class keyword that uniquely defines a class\n"; - for ( auto keyWordValuePair : classesGenerated[classKeyword] ) + if ( !classAttributesGenerated[classKeyword].empty() ) { - classCode += " " + keyWordValuePair.second.second; + classCode += " Attributes\n"; + for ( auto keyWordValuePair : classAttributesGenerated[classKeyword] ) + { + classCode += " " + keyWordValuePair.second.second; + } } classCode += " \"\"\"\n"; } @@ -1844,7 +1889,7 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) { // Own attributes. This initializes a lot of attributes to None. // This means it has to be done before we set any values. - for ( auto keyWordValuePair : classesGenerated[classKeyword] ) + for ( auto keyWordValuePair : classAttributesGenerated[classKeyword] ) { classCode += keyWordValuePair.second.first; } @@ -1857,6 +1902,13 @@ void RiaApplication::generatePythonClasses( const QString& fileName ) classCode += QString( " %1.__custom_init__(self, pb2_object=pb2_object, channel=channel)\n" ) .arg( scriptClassName ); + for ( auto keyWordValuePair : classMethodsGenerated[classKeyword] ) + { + classCode += "\n"; + classCode += keyWordValuePair.second; + classCode += "\n"; + } + out << classCode << "\n"; classesWritten.insert( scriptClassName ); } diff --git a/ApplicationCode/GrpcInterface/GrpcProtos/PdmObject.proto b/ApplicationCode/GrpcInterface/GrpcProtos/PdmObject.proto index 601a2fc45b..e5ecf1976d 100644 --- a/ApplicationCode/GrpcInterface/GrpcProtos/PdmObject.proto +++ b/ApplicationCode/GrpcInterface/GrpcProtos/PdmObject.proto @@ -11,6 +11,8 @@ service PdmObjectService rpc GetAncestorPdmObject(PdmParentObjectRequest) returns (PdmObject) {} rpc CreateChildPdmObject(CreatePdmChildObjectRequest) returns (PdmObject) {} rpc UpdateExistingPdmObject(PdmObject) returns (Empty) {} + rpc CallPdmObjectGetMethod(PdmObjectMethodRequest) returns (stream PdmObjectGetMethodReply) {} + rpc CallPdmObjectSetMethod(stream PdmObjectSetMethodChunk) returns (ClientToServerStreamReply) {} } message PdmDescendantObjectRequest @@ -48,4 +50,53 @@ message PdmObject message PdmObjectArray { repeated PdmObject objects = 1; +} + +message PdmObjectMethodRequest +{ + PdmObject object = 1; + string method = 2; +} + +message PdmObjectSetMethodRequest +{ + PdmObjectMethodRequest request = 1; + int32 data_count = 2; +} + +message PdmObjectSetMethodChunk +{ + oneof data + { + PdmObjectSetMethodRequest set_request = 1; + DoubleArray doubles = 2; + IntArray ints = 3; + StringArray strings = 4; + } +} + + +message DoubleArray +{ + repeated double data = 1; +} + +message IntArray +{ + repeated int32 data = 1; +} + +message StringArray +{ + repeated string data = 1; +} + +message PdmObjectGetMethodReply +{ + oneof data + { + DoubleArray doubles = 1; + IntArray ints = 2; + StringArray strings = 3; + } } \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/cell_result_data.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/cell_result_data.py new file mode 100644 index 0000000000..b420f6f915 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/cell_result_data.py @@ -0,0 +1,17 @@ +###################################################################### +# This script retrieves cell result data and alters it +###################################################################### +import rips + +resinsight = rips.Instance.find() + +view = resinsight.project.views()[0] +results = view.cell_result_data() +print ("Number of result values: ", len(results)) + +newresults = [] +for i in range(0, len(results)): + newresults.append(results[i] * -1.0) +view.set_cell_result_data(newresults) + + \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py b/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py index 803e52b6d0..e6b2048a6d 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py +++ b/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py @@ -52,9 +52,12 @@ def _execute_command(self, **command_params): def __custom_init__(self, pb2_object, channel): self.__warnings = [] self.__keyword_translation = {} + self.__chunk_size = 8160 if pb2_object is not None: + assert(not isinstance(pb2_object, PdmObject)) self._pb2_object = pb2_object + else: self._pb2_object = PdmObject_pb2.PdmObject(class_keyword=self.__class__.__name__) self.class_keyword = self._pb2_object.class_keyword @@ -246,7 +249,7 @@ def children(self, child_field, class_definition=PdmObject): A list of PdmObjects inside the child_field """ request = PdmObject_pb2.PdmChildObjectRequest(object=self._pb2_object, - child_field=child_field) + child_field=child_field) try: object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects return self.__from_pb2_to_pdm_objects(object_list, class_definition) @@ -281,6 +284,61 @@ def ancestor(self, class_definition): return None raise e +@add_method(PdmObject) +def _call_get_method_async(self, method_name): + request = PdmObject_pb2.PdmObjectMethodRequest(object=self._pb2_object, method=method_name) + for chunk in self._pdm_object_stub.CallPdmObjectGetMethod(request): + yield chunk + +@add_method(PdmObject) +def _call_get_method(self, method_name): + all_values = [] + generator = self._call_get_method_async(method_name) + for chunk in generator: + data = getattr(chunk, chunk.WhichOneof('data')) + for value in data.data: + all_values.append(value) + return all_values + +@add_method(PdmObject) +def __generate_set_method_chunks(self, array, method_request): + index = -1 + + while index < len(array): + chunk = PdmObject_pb2.PdmObjectSetMethodChunk() + if index is -1: + chunk.set_request.CopyFrom(PdmObject_pb2.PdmObjectSetMethodRequest(request=method_request, data_count=len(array))) + index += 1 + else: + actual_chunk_size = min(len(array) - index + 1, self.__chunk_size) + if isinstance(array[0], float): + chunk.CopyFrom( + PdmObject_pb2.PdmObjectSetMethodChunk(doubles=PdmObject_pb2.DoubleArray(data=array[index:index + + actual_chunk_size]))) + elif isinstance(array[0], int): + chunk.CopyFrom( + PdmObject_pb2.PdmObjectSetMethodChunk(ints=PdmObject_pb2.IntArray(data=array[index:index + + actual_chunk_size]))) + elif isinstance(array[0], str): + chunk.CopyFrom( + PdmObject_pb2.PdmObjectSetMethodChunk(strings=PdmObject_pb2.StringArray(data=array[index:index + + actual_chunk_size]))) + else: + raise Exception("Wrong data type for set method") + index += actual_chunk_size + yield chunk + # Final empty message to signal completion + chunk = PdmObject_pb2.PdmObjectSetMethodChunk() + yield chunk + +@add_method(PdmObject) +def _call_set_method(self, method_name, values): + method_request = PdmObject_pb2.PdmObjectMethodRequest(object=self._pb2_object, method=method_name) + request_iterator = self.__generate_set_method_chunks(values, method_request) + reply = self._pdm_object_stub.CallPdmObjectSetMethod(request_iterator) + if reply.accepted_value_count < len(values): + raise IndexError + @add_method(PdmObject) def update(self): """Sync all fields from the Python Object to ResInsight""" diff --git a/ApplicationCode/GrpcInterface/RiaGrpcCallbacks.inl b/ApplicationCode/GrpcInterface/RiaGrpcCallbacks.inl index a803752725..b0a708ed0d 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcCallbacks.inl +++ b/ApplicationCode/GrpcInterface/RiaGrpcCallbacks.inl @@ -348,8 +348,8 @@ void RiaGrpcClientToServerStreamCallbackstreamedValueCount() <= m_stateHandler->cellCount() ); - if ( m_stateHandler->streamedValueCount() == m_stateHandler->cellCount() ) + CAF_ASSERT( m_stateHandler->streamedValueCount() <= m_stateHandler->totalValueCount() ); + if ( m_stateHandler->streamedValueCount() == m_stateHandler->totalValueCount() ) { this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST ); m_reader.Finish( this->m_reply, grpc::Status::OK, this ); diff --git a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp index bb92ca4ae4..6ec22178b4 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp +++ b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.cpp @@ -422,7 +422,7 @@ grpc::Status RiaNNCInputValuesStateHandler::receiveStreamRequest( const NNCValue //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RiaNNCInputValuesStateHandler::cellCount() const +size_t RiaNNCInputValuesStateHandler::totalValueCount() const { return m_cellCount; } diff --git a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h index ebdab76e00..fb76bc601d 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h +++ b/ApplicationCode/GrpcInterface/RiaGrpcNNCPropertiesService.h @@ -84,7 +84,7 @@ public: grpc::Status init( const rips::NNCValuesInputRequest* request ); grpc::Status receiveStreamRequest( const rips::NNCValuesChunk* request, rips::ClientToServerStreamReply* reply ); - size_t cellCount() const; + size_t totalValueCount() const; size_t streamedValueCount() const; void finish(); diff --git a/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.cpp b/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.cpp index 941d13e0d0..a23562192a 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.cpp +++ b/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.cpp @@ -28,6 +28,303 @@ using namespace rips; +template +struct DataHolder : public AbstractDataHolder +{ + DataHolder( const DataType& data ) + : data( data ) + { + } + + size_t dataCount() const override { return data.size(); } + size_t dataSizeOf() const override { return sizeof( typename DataType::value_type ); } + + void reserveReplyStorage( rips::PdmObjectGetMethodReply* reply ) const; + void addValueToReply( size_t valueIndex, rips::PdmObjectGetMethodReply* reply ) const; + size_t getValuesFromChunk( size_t startIndex, const rips::PdmObjectSetMethodChunk* chunk ); + void applyValuesToProxyField( caf::PdmProxyFieldHandle* proxyField ); + + DataType data; +}; + +template <> +void DataHolder>::reserveReplyStorage( rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_ints()->mutable_data()->Reserve( data.size() ); +} +template <> +void DataHolder>::addValueToReply( size_t valueIndex, rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_ints()->add_data( data[valueIndex] ); +} +template <> +size_t DataHolder>::getValuesFromChunk( size_t startIndex, const rips::PdmObjectSetMethodChunk* chunk ) +{ + size_t chunkSize = chunk->ints().data_size(); + size_t currentIndex = startIndex; + size_t chunkIndex = 0u; + for ( ; chunkIndex < chunkSize && currentIndex < data.size(); ++currentIndex, ++chunkIndex ) + { + data[currentIndex] = chunk->ints().data()[chunkIndex]; + } + return chunkSize; +} +template <> +void DataHolder>::applyValuesToProxyField( caf::PdmProxyFieldHandle* proxyField ) +{ + auto proxyValueField = dynamic_cast>*>( proxyField ); + CAF_ASSERT( proxyValueField ); + if ( proxyValueField ) + { + proxyValueField->setValue( data ); + } +} + +template <> +void DataHolder>::reserveReplyStorage( rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_doubles()->mutable_data()->Reserve( data.size() ); +} +template <> +void DataHolder>::addValueToReply( size_t valueIndex, rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_doubles()->add_data( data[valueIndex] ); +} +template <> +size_t DataHolder>::getValuesFromChunk( size_t startIndex, const rips::PdmObjectSetMethodChunk* chunk ) +{ + size_t chunkSize = chunk->doubles().data_size(); + size_t currentIndex = startIndex; + size_t chunkIndex = 0u; + for ( ; chunkIndex < chunkSize && currentIndex < data.size(); ++currentIndex, ++chunkIndex ) + { + data[currentIndex] = chunk->doubles().data()[chunkIndex]; + } + return chunkSize; +} +template <> +void DataHolder>::applyValuesToProxyField( caf::PdmProxyFieldHandle* proxyField ) +{ + auto proxyValueField = dynamic_cast>*>( proxyField ); + CAF_ASSERT( proxyValueField ); + if ( proxyValueField ) + { + proxyValueField->setValue( data ); + } +} + +template <> +void DataHolder>::reserveReplyStorage( rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_strings()->mutable_data()->Reserve( data.size() ); +} +template <> +void DataHolder>::addValueToReply( size_t valueIndex, rips::PdmObjectGetMethodReply* reply ) const +{ + reply->mutable_strings()->add_data( data[valueIndex].toStdString() ); +} +template <> +size_t DataHolder>::getValuesFromChunk( size_t startIndex, const rips::PdmObjectSetMethodChunk* chunk ) +{ + size_t chunkSize = chunk->strings().data_size(); + size_t currentIndex = startIndex; + size_t chunkIndex = 0u; + for ( ; chunkIndex < chunkSize && currentIndex < data.size(); ++currentIndex, ++chunkIndex ) + { + data[currentIndex] = QString::fromStdString( chunk->strings().data()[chunkIndex] ); + } + return chunkSize; +} +template <> +void DataHolder>::applyValuesToProxyField( caf::PdmProxyFieldHandle* proxyField ) +{ + auto proxyValueField = dynamic_cast>*>( proxyField ); + CAF_ASSERT( proxyValueField ); + if ( proxyValueField ) + { + proxyValueField->setValue( data ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaPdmObjectMethodStateHandler::RiaPdmObjectMethodStateHandler( bool clientToServerStreamer ) + : m_fieldOwner( nullptr ) + , m_proxyField( nullptr ) + , m_currentDataIndex( 0u ) + , m_clientToServerStreamer( clientToServerStreamer ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Status RiaPdmObjectMethodStateHandler::init( const rips::PdmObjectMethodRequest* request ) +{ + CAF_ASSERT( !m_clientToServerStreamer ); + m_fieldOwner = RiaGrpcPdmObjectService::findCafObjectFromRipsObject( request->object() ); + QString fieldName = QString::fromStdString( request->method() ); + + std::vector fields; + m_fieldOwner->fields( fields ); + for ( auto field : fields ) + { + if ( field->keyword() == fieldName ) + { + caf::PdmProxyFieldHandle* proxyField = dynamic_cast( field ); + if ( proxyField ) + { + m_proxyField = proxyField; + + if ( dynamic_cast>*>( field ) ) + { + auto dataField = dynamic_cast>*>( field ); + m_dataHolder.reset( new DataHolder>( dataField->value() ) ); + return grpc::Status::OK; + } + else if ( dynamic_cast>*>( field ) ) + { + auto dataField = dynamic_cast>*>( field ); + m_dataHolder.reset( new DataHolder>( dataField->value() ) ); + return grpc::Status::OK; + } + else if ( dynamic_cast>*>( field ) ) + { + auto dataField = dynamic_cast>*>( field ); + m_dataHolder.reset( new DataHolder>( dataField->value() ) ); + return grpc::Status::OK; + } + else + { + CAF_ASSERT( false && "The proxy field data type is not yet supported for streaming fields" ); + } + } + } + } + + return grpc::Status( grpc::NOT_FOUND, "Proxy field not found" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Status RiaPdmObjectMethodStateHandler::init( const rips::PdmObjectSetMethodChunk* chunk ) +{ + CAF_ASSERT( m_clientToServerStreamer ); + CAF_ASSERT( chunk->has_set_request() ); + auto setRequest = chunk->set_request(); + auto methodRequest = setRequest.request(); + m_fieldOwner = RiaGrpcPdmObjectService::findCafObjectFromRipsObject( methodRequest.object() ); + QString fieldName = QString::fromStdString( methodRequest.method() ); + int valueCount = setRequest.data_count(); + + std::vector fields; + m_fieldOwner->fields( fields ); + for ( auto field : fields ) + { + if ( field->keyword() == fieldName ) + { + caf::PdmProxyFieldHandle* proxyField = dynamic_cast( field ); + if ( proxyField ) + { + m_proxyField = proxyField; + + if ( dynamic_cast>*>( field ) ) + { + m_dataHolder.reset( new DataHolder>( std::vector( valueCount ) ) ); + return grpc::Status::OK; + } + else if ( dynamic_cast>*>( field ) ) + { + m_dataHolder.reset( new DataHolder>( std::vector( valueCount ) ) ); + return grpc::Status::OK; + } + else if ( dynamic_cast>*>( field ) ) + { + m_dataHolder.reset( new DataHolder>( std::vector( valueCount ) ) ); + return grpc::Status::OK; + } + else + { + CAF_ASSERT( false && "The proxy field data type is not yet supported for streaming fields" ); + } + } + } + } + return grpc::Status( grpc::NOT_FOUND, "Proxy field not found" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Status RiaPdmObjectMethodStateHandler::assignReply( rips::PdmObjectGetMethodReply* reply ) +{ + CAF_ASSERT( m_dataHolder ); + const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( m_dataHolder->dataSizeOf() ); + size_t indexInPackage = 0u; + m_dataHolder->reserveReplyStorage( reply ); + + for ( ; indexInPackage < packageSize && m_currentDataIndex < m_dataHolder->dataCount(); ++indexInPackage ) + { + m_dataHolder->addValueToReply( m_currentDataIndex, reply ); + m_currentDataIndex++; + } + if ( indexInPackage > 0u ) + { + return grpc::Status::OK; + } + return grpc::Status( grpc::OUT_OF_RANGE, + "We've reached the end. This is not an error but means transmission is finished" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Status RiaPdmObjectMethodStateHandler::receiveRequest( const rips::PdmObjectSetMethodChunk* chunk, + rips::ClientToServerStreamReply* reply ) +{ + size_t valuesWritten = m_dataHolder->getValuesFromChunk( m_currentDataIndex, chunk ); + m_currentDataIndex += valuesWritten; + + if ( m_currentDataIndex > totalValueCount() ) + { + return grpc::Status( grpc::OUT_OF_RANGE, "Attempting to write out of bounds" ); + } + reply->set_accepted_value_count( static_cast( m_currentDataIndex ) ); + return grpc::Status::OK; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RiaPdmObjectMethodStateHandler::streamedValueCount() const +{ + return m_currentDataIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RiaPdmObjectMethodStateHandler::totalValueCount() const +{ + return m_dataHolder->dataCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaPdmObjectMethodStateHandler::finish() +{ + if ( m_proxyField ) + { + QVariant before = m_proxyField->toQVariant(); + m_dataHolder->applyValuesToProxyField( m_proxyField ); + QVariant after = m_proxyField->toQVariant(); + m_fieldOwner->fieldChangedByUi( m_proxyField, before, after ); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -74,22 +371,7 @@ grpc::Status RiaGrpcPdmObjectService::GetDescendantPdmObjects( grpc::ServerConte const rips::PdmDescendantObjectRequest* request, rips::PdmObjectArray* reply ) { - RimProject* project = RiaApplication::instance()->project(); - std::vector objectsOfCurrentClass; - - QString scriptClassName = QString::fromStdString( request->object().class_keyword() ); - QString classKeyword = RicfObjectCapability::classKeywordFromScriptClassName( scriptClassName ); - - project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass ); - - caf::PdmObject* matchingObject = nullptr; - for ( caf::PdmObject* testObject : objectsOfCurrentClass ) - { - if ( reinterpret_cast( testObject ) == request->object().address() ) - { - matchingObject = testObject; - } - } + auto matchingObject = findCafObjectFromRipsObject( request->object() ); if ( matchingObject ) { @@ -114,23 +396,7 @@ grpc::Status RiaGrpcPdmObjectService::GetChildPdmObjects( grpc::ServerContext* const rips::PdmChildObjectRequest* request, rips::PdmObjectArray* reply ) { - RimProject* project = RiaApplication::instance()->project(); - std::vector objectsOfCurrentClass; - - QString scriptClassName = QString::fromStdString( request->object().class_keyword() ); - QString classKeyword = RicfObjectCapability::classKeywordFromScriptClassName( scriptClassName ); - - project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass ); - - caf::PdmObject* matchingObject = nullptr; - for ( caf::PdmObject* testObject : objectsOfCurrentClass ) - { - if ( reinterpret_cast( testObject ) == request->object().address() ) - { - matchingObject = testObject; - } - } - + auto matchingObject = findCafObjectFromRipsObject( request->object() ); if ( matchingObject ) { QString fieldName = QString::fromStdString( request->child_field() ); @@ -162,22 +428,7 @@ grpc::Status RiaGrpcPdmObjectService::UpdateExistingPdmObject( grpc::ServerConte const rips::PdmObject* request, rips::Empty* response ) { - RimProject* project = RiaApplication::instance()->project(); - std::vector objectsOfCurrentClass; - - QString scriptClassName = QString::fromStdString( request->class_keyword() ); - QString classKeyword = RicfObjectCapability::classKeywordFromScriptClassName( scriptClassName ); - - project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass ); - - caf::PdmObject* matchingObject = nullptr; - for ( caf::PdmObject* pdmObject : objectsOfCurrentClass ) - { - if ( reinterpret_cast( pdmObject ) == request->address() ) - { - matchingObject = pdmObject; - } - } + auto matchingObject = findCafObjectFromRipsObject( *request ); if ( matchingObject ) { @@ -191,7 +442,8 @@ grpc::Status RiaGrpcPdmObjectService::UpdateExistingPdmObject( grpc::ServerConte } matchingObject->updateAllRequiredEditors(); - project->scheduleCreateDisplayModelAndRedrawAllViews(); + RiaApplication::instance()->project()->scheduleCreateDisplayModelAndRedrawAllViews(); + Rim3dView* view = dynamic_cast( matchingObject ); if ( view ) { @@ -209,22 +461,7 @@ grpc::Status RiaGrpcPdmObjectService::CreateChildPdmObject( grpc::ServerContext* const rips::CreatePdmChildObjectRequest* request, rips::PdmObject* reply ) { - RimProject* project = RiaApplication::instance()->project(); - std::vector objectsOfCurrentClass; - - QString scriptClassName = QString::fromStdString( request->object().class_keyword() ); - QString classKeyword = RicfObjectCapability::classKeywordFromScriptClassName( scriptClassName ); - - project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass ); - - caf::PdmObject* matchingObject = nullptr; - for ( caf::PdmObject* testObject : objectsOfCurrentClass ) - { - if ( reinterpret_cast( testObject ) == request->object().address() ) - { - matchingObject = testObject; - } - } + auto matchingObject = findCafObjectFromRipsObject( request->object() ); if ( matchingObject ) { @@ -242,6 +479,28 @@ grpc::Status RiaGrpcPdmObjectService::CreateChildPdmObject( grpc::ServerContext* return grpc::Status( grpc::NOT_FOUND, "Could not find PdmObject" ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcPdmObjectService::CallPdmObjectGetMethod( grpc::ServerContext* context, + const rips::PdmObjectMethodRequest* request, + rips::PdmObjectGetMethodReply* reply, + RiaPdmObjectMethodStateHandler* stateHandler ) +{ + return stateHandler->assignReply( reply ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcPdmObjectService::CallPdmObjectSetMethod( grpc::ServerContext* context, + const rips::PdmObjectSetMethodChunk* chunk, + rips::ClientToServerStreamReply* reply, + RiaPdmObjectMethodStateHandler* stateHandler ) +{ + return stateHandler->receiveRequest( chunk, reply ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -262,7 +521,47 @@ std::vector RiaGrpcPdmObjectService::createCallbacks( &Self::RequestUpdateExistingPdmObject ), new RiaGrpcUnaryCallback( this, &Self::CreateChildPdmObject, - &Self::RequestCreateChildPdmObject )}; + &Self::RequestCreateChildPdmObject ), + new RiaGrpcServerToClientStreamCallback( this, + &Self::CallPdmObjectGetMethod, + &Self::RequestCallPdmObjectGetMethod, + new RiaPdmObjectMethodStateHandler ), + + new RiaGrpcClientToServerStreamCallback( this, + &Self::CallPdmObjectSetMethod, + &Self::RequestCallPdmObjectSetMethod, + new RiaPdmObjectMethodStateHandler( + true ) )}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmObject* RiaGrpcPdmObjectService::findCafObjectFromRipsObject( const rips::PdmObject& ripsObject ) +{ + RimProject* project = RiaApplication::instance()->project(); + std::vector objectsOfCurrentClass; + + QString scriptClassName = QString::fromStdString( ripsObject.class_keyword() ); + QString classKeyword = RicfObjectCapability::classKeywordFromScriptClassName( scriptClassName ); + + project->descendantsIncludingThisFromClassKeyword( classKeyword, objectsOfCurrentClass ); + + caf::PdmObject* matchingObject = nullptr; + for ( caf::PdmObject* testObject : objectsOfCurrentClass ) + { + if ( reinterpret_cast( testObject ) == ripsObject.address() ) + { + matchingObject = testObject; + } + } + return matchingObject; } static bool RiaGrpcPdmObjectService_init = RiaGrpcServiceFactory::instance()->registerCreator( diff --git a/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.h b/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.h index 4bb6de3bbd..1e18670331 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.h +++ b/ApplicationCode/GrpcInterface/RiaGrpcPdmObjectService.h @@ -23,6 +23,50 @@ #include #include +namespace caf +{ +class PdmProxyFieldHandle; +} + +struct AbstractDataHolder +{ + virtual size_t dataCount() const = 0; + virtual size_t dataSizeOf() const = 0; + virtual void reserveReplyStorage( rips::PdmObjectGetMethodReply* reply ) const = 0; + virtual void addValueToReply( size_t valueIndex, rips::PdmObjectGetMethodReply* reply ) const = 0; + + virtual size_t getValuesFromChunk( size_t startIndex, const rips::PdmObjectSetMethodChunk* chunk ) = 0; + virtual void applyValuesToProxyField( caf::PdmProxyFieldHandle* proxyField ) = 0; +}; + +//================================================================================================== +// +// State handler for streaming of active cell info +// +//================================================================================================== +class RiaPdmObjectMethodStateHandler +{ + typedef grpc::Status Status; + +public: + RiaPdmObjectMethodStateHandler( bool clientToServerStreamer = false ); + + Status init( const rips::PdmObjectMethodRequest* request ); + Status init( const rips::PdmObjectSetMethodChunk* chunk ); + Status assignReply( rips::PdmObjectGetMethodReply* reply ); + Status receiveRequest( const rips::PdmObjectSetMethodChunk* chunk, rips::ClientToServerStreamReply* reply ); + size_t streamedValueCount() const; + size_t totalValueCount() const; + void finish(); + +protected: + caf::PdmObject* m_fieldOwner; + caf::PdmProxyFieldHandle* m_proxyField; + std::unique_ptr m_dataHolder; + size_t m_currentDataIndex; + bool m_clientToServerStreamer; +}; + //================================================================================================== // // gRPC-service answering request searching for PdmObjects in property tree @@ -49,5 +93,16 @@ public: const rips::PdmObject* request, rips::Empty* response ) override; + grpc::Status CallPdmObjectGetMethod( grpc::ServerContext* context, + const rips::PdmObjectMethodRequest* request, + rips::PdmObjectGetMethodReply* reply, + RiaPdmObjectMethodStateHandler* stateHandler ); + grpc::Status CallPdmObjectSetMethod( grpc::ServerContext* context, + const rips::PdmObjectSetMethodChunk* chunk, + rips::ClientToServerStreamReply* reply, + RiaPdmObjectMethodStateHandler* stateHandler ); + std::vector createCallbacks() override; + + static caf::PdmObject* findCafObjectFromRipsObject( const rips::PdmObject& ripsObject ); }; diff --git a/ApplicationCode/GrpcInterface/RiaGrpcPropertiesService.cpp b/ApplicationCode/GrpcInterface/RiaGrpcPropertiesService.cpp index 158471b284..dcda32f210 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcPropertiesService.cpp +++ b/ApplicationCode/GrpcInterface/RiaGrpcPropertiesService.cpp @@ -70,7 +70,7 @@ public: //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- - size_t cellCount() const { return m_cellCount; } + size_t totalValueCount() const { return m_cellCount; } //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/GrpcInterface/RiaGrpcServiceInterface.cpp b/ApplicationCode/GrpcInterface/RiaGrpcServiceInterface.cpp index 4dfdda60e8..c19a6f2b2e 100644 --- a/ApplicationCode/GrpcInterface/RiaGrpcServiceInterface.cpp +++ b/ApplicationCode/GrpcInterface/RiaGrpcServiceInterface.cpp @@ -29,6 +29,7 @@ #include "cafPdmChildField.h" #include "cafPdmDataValueField.h" #include "cafPdmObject.h" +#include "cafPdmProxyValueField.h" #include "cafPdmXmlFieldHandle.h" #include @@ -100,10 +101,14 @@ void RiaGrpcServiceInterface::copyPdmObjectFromCafToRips( const caf::PdmObjectHa auto ricfHandle = field->template capability(); if ( ricfHandle != nullptr ) { - QString text; - QTextStream outStream( &text ); - ricfHandle->writeFieldData( outStream, false ); - ( *parametersMap )[ricfHandle->fieldName().toStdString()] = text.toStdString(); + auto pdmProxyField = dynamic_cast( field ); + if ( !( pdmProxyField && pdmProxyField->isStreamingField() ) ) + { + QString text; + QTextStream outStream( &text ); + ricfHandle->writeFieldData( outStream, false ); + ( *parametersMap )[ricfHandle->fieldName().toStdString()] = text.toStdString(); + } } } } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp index 609d0c1c87..50d1faf9d8 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp @@ -21,6 +21,7 @@ #include "RimEclipseCellColors.h" #include "RiaColorTables.h" +#include "RicfCommandObject.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigFlowDiagResults.h" @@ -50,7 +51,7 @@ CAF_PDM_SOURCE_INIT( RimEclipseCellColors, "ResultSlot" ); //-------------------------------------------------------------------------------------------------- RimEclipseCellColors::RimEclipseCellColors() { - CAF_PDM_InitObject( "Cell Result", ":/CellResult.png", "", "" ); + RICF_InitObjectWithScriptNameAndComment( "Cell Result", ":/CellResult.png", "", "", "CellColors", "Eclipse Cell Colors class" ); CAF_PDM_InitFieldNoDefault( &obsoleteField_legendConfig, "LegendDefinition", "Color Legend", "", "", "" ); this->obsoleteField_legendConfig.xmlCapability()->setIOWritable( false ); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp index 25b263866a..c0886ec5ae 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -95,7 +95,7 @@ RimEclipseResultDefinition::RimEclipseResultDefinition( caf::PdmUiItemInfo::Labe , m_labelPosition( labelPosition ) , m_ternaryEnabled( true ) { - CAF_PDM_InitObject( "Result Definition", "", "", "" ); + RICF_InitObjectWithScriptNameAndComment( "Result Definition", "", "", "", "EclipseResult", "An eclipse result definition" ); RICF_InitFieldNoDefault( &m_resultType, "ResultType", "Type", "", "", "" ); m_resultType.uiCapability()->setUiHidden( true ); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index a8713cec14..5556012414 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -172,8 +172,12 @@ RimEclipseView::RimEclipseView() CAF_PDM_InitField( &m_showInactiveCells, "ShowInactiveCells", false, "Show Inactive Cells", "", "", "" ); CAF_PDM_InitField( &m_showInvalidCells, "ShowInvalidCells", false, "Show Invalid Cells", "", "", "" ); - this->cellResult()->setReservoirView( this ); + RICF_InitFieldNoDefault( &m_cellResultData, "CellResultData", "", "", "", "Current Eclipse Cell Result" ); + m_cellResultData.xmlCapability()->disableIO(); + m_cellResultData.registerGetMethod( this, &RimEclipseView::currentCellResultData ); + m_cellResultData.registerSetMethod( this, &RimEclipseView::setCurrentCellResultData ); + this->cellResult()->setReservoirView( this ); this->cellEdgeResult()->setReservoirView( this ); this->cellEdgeResult()->legendConfig()->setColorRange( RimRegularLegendConfig::PINK_WHITE ); @@ -351,6 +355,12 @@ void RimEclipseView::fieldChangedByUi( const caf::PdmFieldHandle* changedField, scheduleCreateDisplayModelAndRedraw(); } + else if ( changedField == &m_cellResultData ) + { + currentGridCellResults()->recalculateStatistics( m_cellResult->eclipseResultAddress() ); + setCurrentTimeStepAndUpdate( currentTimeStep() ); + createDisplayModelAndRedraw(); + } } //-------------------------------------------------------------------------------------------------- @@ -1120,7 +1130,7 @@ void RimEclipseView::onUpdateDisplayModelVisibility() //-------------------------------------------------------------------------------------------------- /// Convenience for quick access to results //-------------------------------------------------------------------------------------------------- -RigCaseCellResultsData* RimEclipseView::currentGridCellResults() +RigCaseCellResultsData* RimEclipseView::currentGridCellResults() const { if ( m_eclipseCase ) { @@ -1894,6 +1904,45 @@ RimEclipseCellColors* RimEclipseView::currentFaultResultColors() return faultResultColors; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseView::currentCellResultData() const +{ + std::vector resultData; + if ( currentGridCellResults() && cellResult() ) + { + int timeStep = 0; + if ( cellResult()->hasDynamicResult() ) + { + timeStep = this->currentTimeStep(); + } + resultData = currentGridCellResults()->cellScalarResults( cellResult()->eclipseResultAddress() )[timeStep]; + } + return resultData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::setCurrentCellResultData( const std::vector& values ) +{ + if ( currentGridCellResults() && cellResult() ) + { + int timeStep = 0; + if ( cellResult()->hasDynamicResult() ) + { + timeStep = this->currentTimeStep(); + } + std::vector* modResult = + currentGridCellResults()->modifiableCellScalarResult( cellResult()->eclipseResultAddress(), timeStep ); + if ( modResult->size() == values.size() ) + { + *modResult = values; + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 9835a2d3f6..fca233d51e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -24,6 +24,7 @@ #include "cafPdmChildField.h" #include "cafPdmField.h" #include "cafPdmObject.h" +#include "cafPdmProxyValueField.h" #include "cvfArray.h" @@ -101,10 +102,13 @@ public: const RimEclipsePropertyFilterCollection* eclipsePropertyFilterCollection() const; void setOverridePropertyFilterCollection( RimEclipsePropertyFilterCollection* pfc ); - RigCaseCellResultsData* currentGridCellResults(); + RigCaseCellResultsData* currentGridCellResults() const; const RigActiveCellInfo* currentActiveCellInfo() const; RimEclipseCellColors* currentFaultResultColors(); + std::vector currentCellResultData() const; + void setCurrentCellResultData( const std::vector& values ); + void setEclipseCase( RimEclipseCase* reservoir ); RimEclipseCase* eclipseCase() const; RimCase* ownerCase() const override; @@ -206,6 +210,8 @@ private: caf::PdmChildField m_fractureColors; caf::PdmChildField m_virtualPerforationResult; + caf::PdmProxyValueField> m_cellResultData; + caf::PdmChildField m_wellCollection; caf::PdmChildField m_faultCollection; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h index 1e2b1f9a63..3a06644047 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h @@ -8,21 +8,42 @@ #include +#include +#include + namespace caf { +//================================================================================================== +/// Abstract non-templated base class for PdmProxyValueField +/// Exists only to be able to determine that a field is a proxy field +//================================================================================================== + +class PdmProxyFieldHandle : public PdmValueField +{ +public: + virtual bool isStreamingField() const = 0; + virtual bool hasGetter() const = 0; + virtual bool hasSetter() const = 0; +}; + +//================================================================================================== +/// Type traits magic to check if a template argument is a vector +//================================================================================================== +template struct is_vector : public std::false_type {}; +template struct is_vector> : public std::true_type{}; + //================================================================================================== /// Field class encapsulating data access through object setter/getter with input and output of this /// data to/from a QXmlStream /// read/write-FieldData is supposed to be specialized for types needing specialization //================================================================================================== - template -class PdmProxyValueField : public PdmValueField +class PdmProxyValueField : public PdmProxyFieldHandle { public: typedef DataType FieldDataType; - PdmProxyValueField() { m_valueSetter = NULL; m_valueGetter = NULL; } + PdmProxyValueField() { m_valueSetter = NULL; m_valueGetter = NULL; } ~PdmProxyValueField() override { if (m_valueSetter) delete m_valueSetter; if (m_valueGetter) delete m_valueGetter; } // Assignment @@ -34,6 +55,10 @@ public: void setValue(const DataType& fieldValue) { CAF_ASSERT(isInitializedByInitFieldMacro()); if (m_valueSetter) m_valueSetter->setValue(fieldValue); } DataType value() const { CAF_ASSERT(m_valueGetter); return m_valueGetter->getValue(); } + bool isStreamingField() const override { return is_vector(); } + bool hasGetter() const override { return m_valueGetter != nullptr; } + bool hasSetter() const override { return m_valueSetter != nullptr; } + // Implementation of PdmValueField interface QVariant toQVariant() const override { DataType val = value(); return PdmValueFieldSpecialization::convert(val); } @@ -130,6 +155,7 @@ private: SetValueInterface* m_valueSetter; GetValueInterface* m_valueGetter; + }; } // End of namespace caf