diff --git a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp index 6eef13a527..e3adc65f1b 100644 --- a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp +++ b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp @@ -211,6 +211,21 @@ ref StructGridGeometryGenerator::generateSurface() return geo; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref StructGridGeometryGenerator::getOrCreateVertices() +{ + if ( m_vertices.isNull() || m_vertices->size() == 0 ) + { + computeArrays(); + } + + CVF_ASSERT( m_vertices.notNull() ); + + return m_vertices; +} + //-------------------------------------------------------------------------------------------------- /// Generates simplified mesh as line drawing /// Must call generateSurface first diff --git a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h index b5cb0ccc78..f8eb106d50 100644 --- a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h +++ b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h @@ -195,6 +195,8 @@ public: ref createMeshDrawable(); ref createOutlineMeshDrawable( double creaseAngle ); + cvf::ref getOrCreateVertices(); + static ref createMeshDrawableFromSingleCell( const StructGridInterface* grid, size_t cellIndex ); static ref createMeshDrawableFromSingleCell( const StructGridInterface* grid, diff --git a/GrpcInterface/CMakeLists.txt b/GrpcInterface/CMakeLists.txt index 64fcfc6f6c..8cc5a5ea45 100644 --- a/GrpcInterface/CMakeLists.txt +++ b/GrpcInterface/CMakeLists.txt @@ -49,6 +49,7 @@ set(SOURCE_GROUP_HEADER_FILES RiaGrpcNNCPropertiesService.h RiaGrpcPdmObjectService.h RiaGrpcApplicationInterface.h + RiaGrpcGridGeometryExtractionService.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -64,7 +65,9 @@ set(SOURCE_GROUP_SOURCE_FILES RiaGrpcPropertiesService.cpp RiaGrpcNNCPropertiesService.cpp RiaGrpcPdmObjectService.cpp - RiaGrpcApplicationInterface.cpp) + RiaGrpcApplicationInterface.cpp + RiaGrpcGridGeometryExtractionService.cpp +) # Find Protobuf installation Looks for protobuf-config.cmake file installed by # Protobuf's cmake installation. @@ -136,7 +139,20 @@ set(_LINK_LIBRARIES ApplicationLibCode) # Proto files -file(GLOB GRPC_PROTO_FILES GrpcProtos/*.proto) +set(GRPC_PROTO_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/App.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Case.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Commands.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Definitions.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Grid.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/GridGeometryExtraction.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/NNCProperties.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/PdmObject.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Project.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/Properties.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/SimulationWell.proto + ${CMAKE_CURRENT_SOURCE_DIR}/GrpcProtos/VectorDefines.proto +) set(GRPC_PYTHON_SOURCE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Python") diff --git a/GrpcInterface/GrpcProtos/Case.proto b/GrpcInterface/GrpcProtos/Case.proto index 61b3acc3bb..af99aa43a5 100644 --- a/GrpcInterface/GrpcProtos/Case.proto +++ b/GrpcInterface/GrpcProtos/Case.proto @@ -2,6 +2,7 @@ syntax = "proto3"; import "PdmObject.proto"; import "Definitions.proto"; +import "VectorDefines.proto"; package rips; diff --git a/GrpcInterface/GrpcProtos/Definitions.proto b/GrpcInterface/GrpcProtos/Definitions.proto index d6b6678d55..68e7defa97 100644 --- a/GrpcInterface/GrpcProtos/Definitions.proto +++ b/GrpcInterface/GrpcProtos/Definitions.proto @@ -1,5 +1,7 @@ syntax = "proto3"; +import "VectorDefines.proto"; + package rips; message Empty @@ -11,18 +13,6 @@ message ClientToServerStreamReply int64 accepted_value_count = 1; } -message Vec3i { - int32 i = 1; - int32 j = 2; - int32 k = 3; -} - -message Vec3d -{ - double x = 1; - double y = 2; - double z = 3; -} message CellCenters { diff --git a/GrpcInterface/GrpcProtos/Grid.proto b/GrpcInterface/GrpcProtos/Grid.proto index d501747d04..cc46e4bb81 100644 --- a/GrpcInterface/GrpcProtos/Grid.proto +++ b/GrpcInterface/GrpcProtos/Grid.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package rips; import "Definitions.proto"; +import "VectorDefines.proto"; import "Case.proto"; service Grid diff --git a/GrpcInterface/GrpcProtos/GridGeometryExtraction.proto b/GrpcInterface/GrpcProtos/GridGeometryExtraction.proto new file mode 100644 index 0000000000..569e31eddb --- /dev/null +++ b/GrpcInterface/GrpcProtos/GridGeometryExtraction.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +import "Grid.proto"; +import "VectorDefines.proto"; + +// Will this work if we import only part of the protos? +package rips; + +service GridGeometryExtraction +{ + rpc GetGridSurface(GetGridSurfaceRequest) returns (GetGridSurfaceResponse); + rpc CutAlongPolyline(CutAlongPolylineRequest) returns (CutAlongPolylineResponse); +} + +message IJKIndexFilter +{ + int32 iMin = 1; + int32 iMax = 2; + int32 jMin = 3; + int32 jMax = 4; + int32 kMin = 5; + int32 kMax = 6; +} + +message CellIndexFilter +{ + repeated fixed32 cellIndicesArr = 1; +} + +message PropertyFilter +{ + // Timestep ?? + string propertyFilename = 1; + float valueMin = 2; + float valueMax = 3; +} + +message GetGridSurfaceRequest +{ + string gridFilename = 1; + IJKIndexFilter ijkIndexFilter = 2; + CellIndexFilter cellIndexFilter = 3; + PropertyFilter propertyFilter = 4; +} + +message GetGridSurfaceResponse +{ + repeated float vertexArray = 1; + repeated fixed32 quadIndicesArr = 2; // 4*NumQuads long + repeated fixed32 sourceCellIndicesArr = 3; // The originating cell index per quad, longnumQuads long + GridDimensions gridDimensions = 5; + Vec3d originUtm = 6; +} + +message CutAlongPolylineRequest +{ + string gridFilename = 1; + repeated double fencePolylineUtmXY = 2; +} + +message FenceMeshSection +{ + // U-axis defined by vector from start to end, Z is global Z + repeated float vertexArrayUZ = 1; + repeated fixed32 polyIndicesArr = 2; + repeated fixed32 verticesPerPolygonArr = 3; // Number of vertices per polygon, numPolygons long + repeated fixed32 sourceCellIndicesArr = 4; // The originating cell index per polygon, numPolygons long + Vec2d startUtmXY = 6; + Vec2d endUtmXY = 7; +} + +message CutAlongPolylineResponse +{ + repeated FenceMeshSection feceMeshSections = 1; + GridDimensions gridDimensions = 2; +} diff --git a/GrpcInterface/GrpcProtos/GridWebviz.proto b/GrpcInterface/GrpcProtos/GridWebviz.proto deleted file mode 100644 index 7ba8f53e10..0000000000 --- a/GrpcInterface/GrpcProtos/GridWebviz.proto +++ /dev/null @@ -1,8 +0,0 @@ -syntax = "proto3"; - -// Will this work if we import only part of the protos? -package rips; - - - -// test \ No newline at end of file diff --git a/GrpcInterface/GrpcProtos/NNCProperties.proto b/GrpcInterface/GrpcProtos/NNCProperties.proto index 8fa510c220..eb7704eb87 100644 --- a/GrpcInterface/GrpcProtos/NNCProperties.proto +++ b/GrpcInterface/GrpcProtos/NNCProperties.proto @@ -2,6 +2,7 @@ syntax = "proto3"; import "Case.proto"; import "Definitions.proto"; +import "VectorDefines.proto"; package rips; diff --git a/GrpcInterface/GrpcProtos/SimulationWell.proto b/GrpcInterface/GrpcProtos/SimulationWell.proto index 65821e128a..4b1c8da4ca 100644 --- a/GrpcInterface/GrpcProtos/SimulationWell.proto +++ b/GrpcInterface/GrpcProtos/SimulationWell.proto @@ -1,6 +1,7 @@ syntax = "proto3"; import "Definitions.proto"; +import "VectorDefines.proto"; package rips; diff --git a/GrpcInterface/GrpcProtos/VectorDefines.proto b/GrpcInterface/GrpcProtos/VectorDefines.proto new file mode 100644 index 0000000000..2b46de83e0 --- /dev/null +++ b/GrpcInterface/GrpcProtos/VectorDefines.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package rips; + +message Vec3i { + int32 i = 1; + int32 j = 2; + int32 k = 3; +} + +message Vec2d +{ + double x = 1; + double y = 2; +} + +message Vec3d +{ + double x = 1; + double y = 2; + double z = 3; +} diff --git a/GrpcInterface/Python/rips/WebvizPythonExamples/grid_geometry_extraction_TEST.py b/GrpcInterface/Python/rips/WebvizPythonExamples/grid_geometry_extraction_TEST.py new file mode 100644 index 0000000000..d02aaea524 --- /dev/null +++ b/GrpcInterface/Python/rips/WebvizPythonExamples/grid_geometry_extraction_TEST.py @@ -0,0 +1,65 @@ +import sys +import os + +import numpy as np + +import plotly.graph_objects as go + +sys.path.insert(1, os.path.join(sys.path[0], "../")) + +from rips.instance import * +from rips.generated.GridGeometryExtraction_pb2_grpc import * +from rips.generated.GridGeometryExtraction_pb2 import * + +rips_instance = Instance.find() +grid_geometry_extraction_stub = GridGeometryExtractionStub(rips_instance.channel) + +get_grid_surface_request = GridGeometryExtraction__pb2.GetGridSurfaceRequest(gridFilename=None, ijkIndexFilter=None,cellIndexFilter=None,propertyFilter=None) +get_grid_surface_response: GridGeometryExtraction__pb2.GetGridSurfaceResponse = grid_geometry_extraction_stub.GetGridSurface(get_grid_surface_request) + +get_grid_surface_response.gridDimensions +vertex_array = get_grid_surface_response.vertexArray +quad_indices_array = get_grid_surface_response.quadIndicesArr + +num_vertex_coords = 3 # [x, y, z] +num_vertices_per_quad = 4 # [v1, v2, v3, v4] +num_quads = len(vertex_array) /(num_vertex_coords * num_vertices_per_quad) + +x_array = [] +y_array = [] +z_array = [] + +# Create x-, y-, and z-arrays +for i in range(0, len(vertex_array), num_vertex_coords): + x_array.append(vertex_array[i]) + y_array.append(vertex_array[i+1]) + z_array.append(vertex_array[i+2]) + +# Create triangular mesh +i_array = [] +j_array = [] +k_array = [] +for i in range(0, len(quad_indices_array), num_vertices_per_quad): + # Set the indices of the vertices of the triangles + i_array.extend([i, i]) + j_array.extend([i+1, i+2]) + k_array.extend([i+2, i+3]) + + + +fig = go.Figure(data=[go.Mesh3d( + x=x_array, + y=y_array, + z=z_array, + i=i_array, + j=j_array, + k=k_array, + intensity = np.linspace(-5, 5, 1000, endpoint=True), + showscale=True, + colorscale=[[0, 'gold'],[0.5, 'mediumturquoise'],[1.0, 'magenta']] +)]) + +print(fig.data) + +fig.show() + diff --git a/GrpcInterface/Python/rips/grid.py b/GrpcInterface/Python/rips/grid.py index e4f669f1e8..fd3f5c56c1 100644 --- a/GrpcInterface/Python/rips/grid.py +++ b/GrpcInterface/Python/rips/grid.py @@ -8,7 +8,7 @@ about Case grids. import Case_pb2 import Grid_pb2 import Grid_pb2_grpc -import Definitions_pb2 +import VectorDefines_pb2 from typing import Tuple, Optional, List from grpc import Channel @@ -30,7 +30,7 @@ class Grid: self.index: int = index self.cached_dimensions = None - def dimensions(self) -> Optional[Definitions_pb2.Vec3i]: + def dimensions(self) -> Optional[VectorDefines_pb2.Vec3i]: """The dimensions in i, j, k direction Returns: @@ -58,7 +58,7 @@ class Grid: for chunk in chunks: yield chunk - def cell_centers(self) -> List[Definitions_pb2.Vec3d]: + def cell_centers(self) -> List[VectorDefines_pb2.Vec3d]: """The cell center for all cells in given grid Returns: diff --git a/GrpcInterface/RiaGrpcGridGeometryExtractionService.cpp b/GrpcInterface/RiaGrpcGridGeometryExtractionService.cpp new file mode 100644 index 0000000000..a15944f49d --- /dev/null +++ b/GrpcInterface/RiaGrpcGridGeometryExtractionService.cpp @@ -0,0 +1,135 @@ +#include "RiaGrpcGridGeometryExtractionService.h" + +#include "qstring.h" + +#include "cvfStructGridGeometryGenerator.h" + +#include "RiaApplication.h" +#include "RiaGrpcCallbacks.h" +#include "RiaGrpcHelper.h" + +#include "RigEclipseCaseData.h" +#include "RigFemPartCollection.h" +#include "RigFemPartGrid.h" +#include "RigGeoMechCaseData.h" +#include "RigGridBase.h" +#include "RigMainGrid.h" +#include "RimCase.h" +#include "RimEclipseCase.h" +#include "RimEclipseView.h" +#include "RimGeoMechCase.h" +#include "RimGridView.h" +#include "RimProject.h" +#include "cvfArray.h" +#include "cvfDrawableGeo.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcGridGeometryExtractionService::GetGridSurface( grpc::ServerContext* context, + const rips::GetGridSurfaceRequest* request, + rips::GetGridSurfaceResponse* response ) +{ + // Get resinsight instance and open grid + RiaApplication* applicationInstance = RiaApplication::instance(); + + if ( applicationInstance == nullptr ) + { + return grpc::Status( grpc::StatusCode::NOT_FOUND, "ResInsight instance not found" ); + } + + applicationInstance->createMockModel(); + + RimProject* project = applicationInstance->project(); + if ( project == nullptr ) + { + return grpc::Status( grpc::StatusCode::NOT_FOUND, "No project found" ); + } + + // 1) + { + // 1. RimEclipseView + // 2. RivReservoirViewPartMgr using reservoirGridPartManager() + // 3. reservoirPartManager(RivCellSetEnum::RANGE_FILTERED, timeStepIndex); , timeStepIndex = 0 (make method + // public?) + // 4. ... ? + } + + // 2) + { + // Temporary code using mainGrid + auto eclipseCases = project->eclipseCases(); + if ( eclipseCases.empty() ) + { + return grpc::Status( grpc::StatusCode::NOT_FOUND, "No grid cases found" ); + } + auto* eclipseCase = eclipseCases.front(); + auto* mainGrid = eclipseCase->eclipseCaseData()->mainGrid(); + + // Get RigFemPartGrid object ? + cvf::StructGridGeometryGenerator gridGeometryGenerator( mainGrid, false ); + + cvf::UByteArray* cellVisibilities = new cvf::UByteArray( mainGrid->cellCount() ); + cellVisibilities->setAll( 1 ); + auto* faceVisibilityFilter = new RigGridCellFaceVisibilityFilter( mainGrid ); + + gridGeometryGenerator.setCellVisibility( cellVisibilities ); + gridGeometryGenerator.addFaceVisibilityFilter( faceVisibilityFilter ); + + auto gridSurfaceVertices = gridGeometryGenerator.getOrCreateVertices(); + if ( gridSurfaceVertices.p() == nullptr ) + { + return grpc::Status( grpc::StatusCode::NOT_FOUND, "No grid vertices found" ); + } + + // Set vertex_array and quadindicesarr response + const auto* verticesArray = gridSurfaceVertices.p(); + for ( int i = 0; i < verticesArray->size(); ++i ) + { + const auto& vertex = verticesArray->get( i ); + response->add_vertexarray( vertex.x() ); + response->add_vertexarray( vertex.y() ); + response->add_vertexarray( vertex.z() ); + + response->add_quadindicesarr( i ); + } + } + + // TODO: Add: + // - sourceCellIndicesArr + // - gridDimensions + // - originUtm + + applicationInstance->closeProject(); + + return grpc::Status::OK; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +grpc::Status RiaGrpcGridGeometryExtractionService::CutAlongPolyline( grpc::ServerContext* context, + const rips::CutAlongPolylineRequest* request, + rips::CutAlongPolylineResponse* response ) +{ + return grpc::Status( grpc::StatusCode::UNIMPLEMENTED, "Not implemented" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaGrpcGridGeometryExtractionService::createCallbacks() +{ + typedef RiaGrpcGridGeometryExtractionService Self; + + return { new RiaGrpcUnaryCallback( this, + &Self::GetGridSurface, + &Self::RequestGetGridSurface ), + new RiaGrpcUnaryCallback( this, + &Self::CutAlongPolyline, + &Self::RequestCutAlongPolyline ) }; +} + +static bool RiaGrpcGridGeometryExtractionService_init = + RiaGrpcServiceFactory::instance()->registerCreator( + typeid( RiaGrpcGridGeometryExtractionService ).hash_code() ); diff --git a/GrpcInterface/RiaGrpcGridGeometryExtractionService.h b/GrpcInterface/RiaGrpcGridGeometryExtractionService.h new file mode 100644 index 0000000000..80ec370499 --- /dev/null +++ b/GrpcInterface/RiaGrpcGridGeometryExtractionService.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- 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 "GridGeometryExtraction.grpc.pb.h" +#include "RiaGrpcServiceInterface.h" + +#include + +namespace rips +{ +class GetGridSurfaceRequest; +class GetGridSurfaceResponse; +class CutAlongPolylineRequest; +class CutAlongPolylineResponse; +} // namespace rips + +class RiaGrpcCallbackInterface; + +//================================================================================================== +// +// gRPC-service answering requests about grid geometry extraction +// +//================================================================================================== +class RiaGrpcGridGeometryExtractionService final : public rips::GridGeometryExtraction::AsyncService, + public RiaGrpcServiceInterface +{ +public: + grpc::Status GetGridSurface( grpc::ServerContext* context, + const rips::GetGridSurfaceRequest* request, + rips::GetGridSurfaceResponse* response ) override; + + grpc::Status CutAlongPolyline( grpc::ServerContext* context, + const rips::CutAlongPolylineRequest* request, + rips::CutAlongPolylineResponse* response ) override; + +public: + std::vector createCallbacks() override; +};