diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechCellColors.cpp b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechCellColors.cpp index 4219273eea..d03d6fde4e 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechCellColors.cpp +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechCellColors.cpp @@ -24,6 +24,8 @@ #include "RimViewController.h" #include "RimViewLinker.h" +#include "cafPdmObjectScriptingCapability.h" + CAF_PDM_SOURCE_INIT( RimGeoMechCellColors, "GeoMechResultSlot" ); //-------------------------------------------------------------------------------------------------- @@ -32,6 +34,8 @@ CAF_PDM_SOURCE_INIT( RimGeoMechCellColors, "GeoMechResultSlot" ); RimGeoMechCellColors::RimGeoMechCellColors() : legendConfigChanged( this ) { + CAF_PDM_InitScriptableObjectWithNameAndComment( "Color Result", ":/CellResult.png", "", "", "GeoMechCellColors", "Geomechanical cell colors" ); + CAF_PDM_InitFieldNoDefault( &legendConfig, "LegendDefinition", "Color Legend" ); legendConfig = new RimRegularLegendConfig(); legendConfig->changed.connect( this, &RimGeoMechCellColors::onLegendConfigChanged ); diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.cpp b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.cpp index ae773d48ad..4b4a93aadc 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.cpp +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.cpp @@ -48,6 +48,8 @@ #include "RimViewLinker.h" #include "RimWellPath.h" +#include "cafPdmFieldScriptingCapability.h" +#include "cafPdmObjectScriptingCapability.h" #include "cafPdmUiDoubleValueEditor.h" #include "cafPdmUiTreeSelectionEditor.h" @@ -77,15 +79,15 @@ CAF_PDM_SOURCE_INIT( RimGeoMechResultDefinition, "GeoMechResultDefinition" ); //-------------------------------------------------------------------------------------------------- RimGeoMechResultDefinition::RimGeoMechResultDefinition() { - CAF_PDM_InitObject( "Color Result", ":/CellResult.png" ); + CAF_PDM_InitScriptableObjectWithNameAndComment( "Color Result", ":/CellResult.png", "", "", "GeoMechResult", "A geomechanical result definition" ); - CAF_PDM_InitFieldNoDefault( &m_resultPositionType, "ResultPositionType", "Result Position" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_resultPositionType, "ResultPositionType", "Result Position" ); m_resultPositionType.uiCapability()->setUiHidden( true ); - CAF_PDM_InitField( &m_resultFieldName, "ResultFieldName", QString( "" ), "Field Name" ); + CAF_PDM_InitScriptableField( &m_resultFieldName, "ResultFieldName", QString( "" ), "Field Name" ); m_resultFieldName.uiCapability()->setUiHidden( true ); - CAF_PDM_InitField( &m_resultComponentName, "ResultComponentName", QString( "" ), "Component" ); + CAF_PDM_InitScriptableField( &m_resultComponentName, "ResultComponentName", QString( "" ), "Component" ); m_resultComponentName.uiCapability()->setUiHidden( true ); CAF_PDM_InitField( &m_timeLapseBaseTimestep, "TimeLapseBaseTimeStep", RigFemResultAddress::noTimeLapseValue(), "Base Time Step" ); @@ -541,6 +543,14 @@ void RimGeoMechResultDefinition::initAfterRead() { if ( m_resultComponentName() == "STM" || m_resultComponentName() == "SEM" ) m_resultComponentName = "SM"; + updateUiFieldsFromActiveResult(); +} + +//-------------------------------------------------------------------------------------------------- +/// Sync the UI fields after the result fields are set directly, e.g. from scripting +//-------------------------------------------------------------------------------------------------- +void RimGeoMechResultDefinition::updateUiFieldsFromActiveResult() +{ m_resultPositionTypeUiField = m_resultPositionType; m_resultVariableUiField = composeFieldCompString( m_resultFieldName(), m_resultComponentName() ); m_compactionRefLayerUiField = m_compactionRefLayer; diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.h b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.h index 3398acdb0e..4841007af9 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.h +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechResultDefinition.h @@ -22,6 +22,7 @@ #include "RimCheckableObject.h" #include "RimFemResultObserver.h" +#include "RimResultDefinitionInterface.h" #include "RigFemResultPosEnum.h" @@ -41,7 +42,7 @@ class RimRegularLegendConfig; /// /// //================================================================================================== -class RimGeoMechResultDefinition : public RimFemResultObserver, public RimCheckableObject +class RimGeoMechResultDefinition : public RimFemResultObserver, public RimCheckableObject, public RimResultDefinitionInterface { CAF_PDM_HEADER_INIT; @@ -54,7 +55,8 @@ public: RigGeoMechCaseData* ownerCaseData() const; bool hasResult(); - void loadResult(); + void loadResult() override; + void updateUiFieldsFromActiveResult() override; void setAddWellPathDerivedResults( bool addWellPathDerivedResults ); RigFemResultAddress resultAddress() const; diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp index ff7e1e16af..4ef233d189 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp @@ -76,6 +76,7 @@ #include "cafDisplayCoordTransform.h" #include "cafFrameAnimationControl.h" #include "cafOverlayScalarMapperLegend.h" +#include "cafPdmFieldScriptingCapability.h" #include "cafPdmUiTreeOrdering.h" #include "cafProgressInfo.h" @@ -96,7 +97,7 @@ RimGeoMechView::RimGeoMechView() { CAF_PDM_InitScriptableObject( "Geomechanical View", ":/3DViewGeoMech16x16.png", "", "The Geomechanical 3d View" ); - CAF_PDM_InitFieldNoDefault( &cellResult, "GridCellResult", "Color Result", ":/CellResult.png" ); + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &cellResult, "GridCellResult", "CellResult", "Color Result", ":/CellResult.png" ); cellResult = new RimGeoMechCellColors(); CAF_PDM_InitFieldNoDefault( &m_tensorResults, "TensorResults", "Tensor Results" ); diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.h b/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.h index 24289c39de..a3cd6bf88f 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.h +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseResultDefinition.h @@ -27,6 +27,7 @@ #include "RimCheckableObject.h" #include "RimFlowDiagSolution.h" +#include "RimResultDefinitionInterface.h" #include "cafAppEnum.h" #include "cafPdmField.h" @@ -49,7 +50,7 @@ class RigEclipseResultAddress; /// /// //================================================================================================== -class RimEclipseResultDefinition : public RimCheckableObject +class RimEclipseResultDefinition : public RimCheckableObject, public RimResultDefinitionInterface { CAF_PDM_HEADER_INIT; @@ -102,7 +103,7 @@ public: int caseDiffIndex() const; QString additionalResultText() const; - virtual void loadResult(); + void loadResult() override; void setEagerResultLoadingEnabled( bool enabled ); RigEclipseResultAddress eclipseResultAddress() const; void setFromEclipseResultAddress( const RigEclipseResultAddress& resultAddress ); @@ -125,7 +126,7 @@ public: void setSelectedProducerTracers( const std::vector& selectedTracers ); void setSelectedSouringTracers( const std::vector& selectedTracers ); - void updateUiFieldsFromActiveResult(); + void updateUiFieldsFromActiveResult() override; bool showDualPorosityLabel() const; diff --git a/ApplicationLibCode/ProjectDataModel/RimResultDefinitionInterface.h b/ApplicationLibCode/ProjectDataModel/RimResultDefinitionInterface.h new file mode 100644 index 0000000000..f546be9983 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/RimResultDefinitionInterface.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2026- 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 + +//================================================================================================== +// Interface implemented by result definitions (e.g. RimEclipseResultDefinition and +// RimGeoMechResultDefinition) that can be updated after their active result has been changed +// programmatically, e.g. from the scripting/gRPC interface. +//================================================================================================== +class RimResultDefinitionInterface +{ +public: + virtual ~RimResultDefinitionInterface() = default; + + virtual void updateUiFieldsFromActiveResult() = 0; + virtual void loadResult() = 0; +}; diff --git a/GrpcInterface/Python/rips/PythonExamples/case_and_grid_operations/set_geomech_cell_result.py b/GrpcInterface/Python/rips/PythonExamples/case_and_grid_operations/set_geomech_cell_result.py new file mode 100644 index 0000000000..caac488518 --- /dev/null +++ b/GrpcInterface/Python/rips/PythonExamples/case_and_grid_operations/set_geomech_cell_result.py @@ -0,0 +1,22 @@ +###################################################################### +# This script applies a geomechanical cell result to the first view +# of the first GeoMech case in the project +###################################################################### +import sys + +import rips + +resinsight = rips.Instance.find() + +cases = resinsight.project.descendants(rips.GeoMechCase) +if not cases: + print("No GeoMech cases in project") + sys.exit(1) + +view = cases[0].views()[0] + +cell_result = view.cell_result() +cell_result.result_position_type = "ELEMENT_NODAL" +cell_result.result_field_name = "SE" +cell_result.result_component_name = "S33" +cell_result.update() diff --git a/GrpcInterface/Python/rips/pdmobject.py b/GrpcInterface/Python/rips/pdmobject.py index 56638267e3..a1cf54e9df 100644 --- a/GrpcInterface/Python/rips/pdmobject.py +++ b/GrpcInterface/Python/rips/pdmobject.py @@ -521,6 +521,11 @@ class PdmObjectBase: ) try: pb2_object = self._pdm_object_stub.GetAncestorPdmObject(request) + from .generated.generated_classes import class_from_keyword + + actual_class = class_from_keyword(pb2_object.class_keyword) + if actual_class is not None and issubclass(actual_class, class_definition): + class_definition = actual_class pdm_object = class_definition(pb2_object=pb2_object, channel=self.channel()) return pdm_object except grpc.RpcError as e: diff --git a/GrpcInterface/Python/rips/view.py b/GrpcInterface/Python/rips/view.py index b7cbd59920..bd614d4aee 100644 --- a/GrpcInterface/Python/rips/view.py +++ b/GrpcInterface/Python/rips/view.py @@ -115,6 +115,10 @@ def extract_address(address) -> int: @add_method(View) def case(self): """Get the case the view belongs to""" + if isinstance(self, GeoMechView): + # Geomechanical views are children of their case + return self.ancestor(rips.case.Case) + project = self.ancestor(rips.project.Project) eclipse_case_addr = extract_address(self.eclipse_case) diff --git a/GrpcInterface/RiaGrpcPdmObjectService.cpp b/GrpcInterface/RiaGrpcPdmObjectService.cpp index 853a5114bd..10da38fb4d 100644 --- a/GrpcInterface/RiaGrpcPdmObjectService.cpp +++ b/GrpcInterface/RiaGrpcPdmObjectService.cpp @@ -24,8 +24,8 @@ #include "RiaLogging.h" #include "RiaOpenTelemetryManager.h" -#include "RimEclipseResultDefinition.h" #include "RimProject.h" +#include "RimResultDefinitionInterface.h" #include "cafPdmAbstractFieldScriptingCapability.h" #include "cafPdmObject.h" @@ -451,9 +451,7 @@ grpc::Status RiaGrpcPdmObjectService::UpdateExistingPdmObject( grpc::ServerConte } // Validation succeeded - update UI and views - RimEclipseResultDefinition* resultDefinition = dynamic_cast( matchingObject ); - // TODO: Make this more general. Perhaps we need an interface method for updating UI fields - if ( resultDefinition ) + if ( auto resultDefinition = dynamic_cast( matchingObject ) ) { resultDefinition->updateUiFieldsFromActiveResult(); resultDefinition->loadResult();