Scripting: read GeoMech time steps, result names and values

This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-10-23 09:28:19 +02:00
1 parent 9613251e9a
commit 7222d6360e
10 files changed
+495 -1

No files matched your search

@@ -20,12 +20,31 @@
#include "WellLogCommands/RicNewWellBoreStabilityPlotFeature.h"
#include "KeyValueStore/RiaKeyValueStoreUtil.h"
#include "RiaApplication.h"
#include "RigFemPartResultsCollection.h"
#include "RigGeoMechCaseData.h"
#include "RimGeoMechCase.h"
#include "RimWbsParameters.h"
#include "RimWellBoreStabilityPlot.h"
#include "RimWellPath.h"
#include "RimcDataContainerString.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmScriptEnumNameRegistry.h"
#include <algorithm>
namespace
{
struct RegisterScriptEnumNames
{
RegisterScriptEnumNames() { caf::PdmScriptEnumNameRegistry::registerName<RigFemResultPosEnum>( "GeoMechResultPosition" ); }
};
const RegisterScriptEnumNames s_registerScriptEnumNames;
} // namespace
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimGeoMechCase, RimGeoMechCase_createWellBoreStabilityPlot, "createWellBoreStabilityPlot" );
@@ -97,3 +116,191 @@ QString RimGeoMechCase_createWellBoreStabilityPlot::classKeywordReturnedType() c
{
return RimWellBoreStabilityPlot::classKeywordStatic();
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimGeoMechCase, RimGeoMechCase_timeStepStrings, "TimeStepStringsInternal" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechCase_timeStepStrings::RimGeoMechCase_timeStepStrings( caf::PdmObjectHandle* self )
: PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE )
{
CAF_PDM_InitObject( "Time Step Strings", "", "", "Time step strings for this case." );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimGeoMechCase_timeStepStrings::execute()
{
auto* geoMechCase = self<RimGeoMechCase>();
if ( !geoMechCase ) return std::unexpected( "No GeoMech case is available." );
auto* container = new RimcDataContainerString();
if ( geoMechCase->geoMechData() && geoMechCase->geoMechData()->femPartResults() )
{
// Filtered time step names match the time step index used by result_values()
std::vector<QString> names;
for ( const auto& name : geoMechCase->geoMechData()->femPartResults()->filteredTimeStepNames() )
{
names.push_back( QString::fromStdString( name ) );
}
container->m_stringValues = names;
}
return container;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechCase_timeStepStrings::classKeywordReturnedType() const
{
return RimcDataContainerString::classKeywordStatic();
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimGeoMechCase, RimGeoMechCase_resultNames, "ResultNamesInternal" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechCase_resultNames::RimGeoMechCase_resultNames( caf::PdmObjectHandle* self )
: PdmObjectMethod( self, PdmObjectMethod::NullPointerType::NULL_IS_INVALID, PdmObjectMethod::ResultType::PERSISTENT_FALSE )
{
CAF_PDM_InitObject( "Result Names", "", "", "Result names for this case." );
CAF_PDM_InitScriptableField( &m_resultPosition,
"ResultPosition",
caf::AppEnum<RigFemResultPosEnum>( RIG_ELEMENT_NODAL ),
"Result Position",
"",
"",
"Result position, for example NODAL or ELEMENT_NODAL" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimGeoMechCase_resultNames::execute()
{
auto* geoMechCase = self<RimGeoMechCase>();
if ( !geoMechCase ) return std::unexpected( "No GeoMech case is available." );
if ( !geoMechCase->geoMechData() || !geoMechCase->geoMechData()->femPartResults() )
{
return std::unexpected( "The GeoMech case has no result data. Open the case first." );
}
const auto fieldsWithComponents = geoMechCase->geoMechData()->femPartResults()->scalarFieldAndComponentNames( m_resultPosition() );
std::vector<QString> names;
for ( const auto& [field, components] : fieldsWithComponents )
{
const QString fieldName = QString::fromStdString( field );
if ( components.empty() )
{
names.push_back( fieldName );
continue;
}
for ( const auto& component : components )
{
names.push_back( fieldName + ":" + QString::fromStdString( component ) );
}
}
auto* container = new RimcDataContainerString();
container->m_stringValues = std::move( names );
return container;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechCase_resultNames::classKeywordReturnedType() const
{
return RimcDataContainerString::classKeywordStatic();
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimGeoMechCase, RimGeoMechCase_readResultValuesInternal, "ReadResultValuesInternal" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGeoMechCase_readResultValuesInternal::RimGeoMechCase_readResultValuesInternal( caf::PdmObjectHandle* self )
: caf::PdmVoidObjectMethod( self )
{
CAF_PDM_InitObject( "Read Result Values", "", "", "Read GeoMech result values" );
CAF_PDM_InitScriptableField( &m_resultPosition,
"ResultPosition",
caf::AppEnum<RigFemResultPosEnum>( RIG_ELEMENT_NODAL ),
"Result Position",
"",
"",
"Result position, for example NODAL or ELEMENT_NODAL" );
CAF_PDM_InitScriptableField( &m_fieldName, "FieldName", QString(), "Field Name" );
CAF_PDM_InitScriptableField( &m_componentName, "ComponentName", QString(), "Component Name" );
CAF_PDM_InitScriptableField( &m_timeStep, "TimeStep", 0, "Time Step", "", "", "Zero-based time step index" );
CAF_PDM_InitScriptableField( &m_frameIndex, "FrameIndex", -1, "Frame Index", "", "", "Zero-based frame index. Negative selects the last frame" );
CAF_PDM_InitScriptableField( &m_key, "Key", QString(), "Key" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimGeoMechCase_readResultValuesInternal::execute()
{
auto* geoMechCase = self<RimGeoMechCase>();
if ( !geoMechCase ) return std::unexpected( "No GeoMech case is available." );
if ( m_key().isEmpty() ) return std::unexpected( "No key specified." );
if ( m_fieldName().isEmpty() ) return std::unexpected( "No result field name specified." );
if ( !geoMechCase->geoMechData() || !geoMechCase->geoMechData()->femPartResults() )
{
return std::unexpected( "The GeoMech case has no result data. Open the case first." );
}
auto* results = geoMechCase->geoMechData()->femPartResults();
if ( m_timeStep() < 0 || m_timeStep() >= results->timeStepCount() )
{
return std::unexpected( QString( "Time step %1 is out of range [0, %2)." ).arg( m_timeStep() ).arg( results->timeStepCount() ) );
}
const int frameCount = results->frameCount( m_timeStep() );
const int frameIndex = m_frameIndex() < 0 ? frameCount - 1 : m_frameIndex();
if ( frameIndex < 0 || frameIndex >= frameCount )
{
return std::unexpected(
QString( "Frame %1 (resolved to %2) is out of range [0, %3)." ).arg( m_frameIndex() ).arg( frameIndex ).arg( frameCount ) );
}
const RigFemResultAddress address( m_resultPosition(), m_fieldName().toStdString(), m_componentName().toStdString() );
if ( !address.isValid() ) return std::unexpected( QString( "Invalid result %1 %2." ).arg( m_fieldName(), m_componentName() ) );
const auto fieldsWithComponents = results->scalarFieldAndComponentNames( m_resultPosition() );
const auto fieldIt = fieldsWithComponents.find( address.fieldName );
if ( fieldIt == fieldsWithComponents.end() )
{
return std::unexpected( QString( "Unknown result field '%1'." ).arg( m_fieldName() ) );
}
const auto& components = fieldIt->second;
const bool componentOk = components.empty()
? address.componentName.empty()
: std::find( components.begin(), components.end(), address.componentName ) != components.end();
if ( !componentOk )
{
return std::unexpected( QString( "Unknown component '%1' for result field '%2'." ).arg( m_componentName(), m_fieldName() ) );
}
std::vector<float> values;
results->globalResultValues( address, m_timeStep(), frameIndex, values );
RiaApplication::instance()->keyValueStore()->set( m_key().toStdString(), RiaKeyValueStoreUtil::convertToByteVector( values ) );
return nullptr;
}