2026-05-27 12:14:08 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// 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 <http://www.gnu.org/licenses/gpl.html>
|
|
|
|
|
// for more details.
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2026-06-05 14:35:21 +02:00
|
|
|
#include "RimFaultDistance.h"
|
2026-05-27 12:14:08 +02:00
|
|
|
|
|
|
|
|
#include "RiaDefines.h"
|
|
|
|
|
|
|
|
|
|
#include "RigCaseCellResultsData.h"
|
|
|
|
|
#include "RigEclipseCaseData.h"
|
|
|
|
|
#include "RigEclipseResultAddress.h"
|
|
|
|
|
#include "RigFault.h"
|
|
|
|
|
#include "RigSelectedFaultDistanceResultCalculator.h"
|
|
|
|
|
|
|
|
|
|
#include "RimEclipseCase.h"
|
2026-06-05 14:07:00 +02:00
|
|
|
#include "RimEclipseCellColors.h"
|
2026-05-27 12:14:08 +02:00
|
|
|
#include "RimEclipseView.h"
|
|
|
|
|
#include "RimFaultInView.h"
|
|
|
|
|
#include "RimFaultInViewCollection.h"
|
|
|
|
|
|
2026-06-01 08:41:36 +02:00
|
|
|
#include "cafCmdFeatureMenuBuilder.h"
|
2026-05-27 12:59:19 +02:00
|
|
|
#include "cafPdmFieldScriptingCapability.h"
|
|
|
|
|
#include "cafPdmObjectScriptingCapability.h"
|
2026-06-05 14:07:00 +02:00
|
|
|
#include "cafPdmUiPushButtonEditor.h"
|
2026-05-27 12:14:08 +02:00
|
|
|
#include "cafPdmUiTreeSelectionEditor.h"
|
|
|
|
|
|
2026-06-05 14:35:21 +02:00
|
|
|
CAF_PDM_SOURCE_INIT( RimFaultDistance, "RimFaultDistance" );
|
2026-05-27 12:14:08 +02:00
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
RimFaultDistance::RimFaultDistance()
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
2026-06-05 13:57:24 +02:00
|
|
|
CAF_PDM_InitScriptableObjectWithNameAndComment( "Fault Distance",
|
2026-05-27 12:59:19 +02:00
|
|
|
":/draw_style_faults_24x24.png",
|
|
|
|
|
"",
|
|
|
|
|
"",
|
2026-06-05 14:35:21 +02:00
|
|
|
"FaultDistance",
|
2026-05-27 12:59:19 +02:00
|
|
|
"Per-cell distance to a selected subset of faults" );
|
2026-05-27 12:14:08 +02:00
|
|
|
|
2026-05-27 12:59:19 +02:00
|
|
|
CAF_PDM_InitScriptableFieldNoDefault( &m_resultName, "ResultName", "Name" );
|
2026-05-27 12:14:08 +02:00
|
|
|
|
2026-05-27 12:59:19 +02:00
|
|
|
CAF_PDM_InitScriptableFieldNoDefault( &m_faults, "SelectedFaults", "Faults" );
|
2026-05-27 12:14:08 +02:00
|
|
|
m_faults.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
|
2026-06-05 14:07:00 +02:00
|
|
|
|
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_generateButton, "Generate", "" );
|
|
|
|
|
caf::PdmUiPushButtonEditor::configureEditorLabelLeft( &m_generateButton );
|
2026-06-08 15:50:26 +02:00
|
|
|
|
|
|
|
|
setDeletable( true );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
/// Remove the generated result from the case when the object is deleted. The object is still
|
|
|
|
|
/// attached to the project tree while this destructor body runs, so the owner case is reachable.
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RimFaultDistance::~RimFaultDistance()
|
|
|
|
|
{
|
|
|
|
|
removeGeneratedResult( m_resultName() );
|
2026-05-27 12:14:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
QString RimFaultDistance::resultName() const
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
return m_resultName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::setResultName( const QString& name )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
m_resultName = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::setSelectedFaults( const std::vector<RimFaultInView*>& faults )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
m_faults.setValue( faults );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
std::vector<const RigFault*> RimFaultDistance::selectedRigFaults() const
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
std::vector<const RigFault*> rigFaults;
|
|
|
|
|
for ( RimFaultInView* fault : m_faults )
|
|
|
|
|
{
|
|
|
|
|
if ( fault && fault->faultGeometry() ) rigFaults.push_back( fault->faultGeometry() );
|
|
|
|
|
}
|
|
|
|
|
return rigFaults;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::compute()
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
if ( m_resultName().isEmpty() ) return;
|
|
|
|
|
|
2026-06-05 14:04:21 +02:00
|
|
|
RimEclipseCase* eclipseCase = firstAncestorOrThisOfType<RimEclipseCase>();
|
2026-05-27 12:14:08 +02:00
|
|
|
if ( !eclipseCase ) return;
|
|
|
|
|
|
|
|
|
|
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
|
|
|
|
|
if ( !caseData ) return;
|
|
|
|
|
|
|
|
|
|
RigSelectedFaultDistanceResultCalculator::compute( caseData, m_resultName(), selectedRigFaults() );
|
|
|
|
|
|
2026-06-05 14:04:21 +02:00
|
|
|
const auto views = eclipseCase->reservoirViews();
|
2026-06-05 14:07:00 +02:00
|
|
|
if ( !views.empty() && views.front() )
|
|
|
|
|
{
|
|
|
|
|
RimEclipseView* firstView = views.front();
|
|
|
|
|
|
|
|
|
|
// Select the generated result in the first view so the computation result is visible.
|
|
|
|
|
if ( RimEclipseCellColors* cellResult = firstView->cellResult() )
|
|
|
|
|
{
|
|
|
|
|
cellResult->setResultType( RiaDefines::ResultCatType::GENERATED );
|
|
|
|
|
cellResult->setResultVariable( m_resultName() );
|
|
|
|
|
cellResult->loadResult();
|
|
|
|
|
cellResult->updateConnectedEditors();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
firstView->scheduleCreateDisplayModelAndRedraw();
|
|
|
|
|
}
|
2026-05-27 12:14:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
if ( changedField == &m_resultName )
|
|
|
|
|
{
|
|
|
|
|
const QString previousName = oldValue.toString();
|
|
|
|
|
if ( !previousName.isEmpty() && previousName != m_resultName() )
|
|
|
|
|
{
|
|
|
|
|
removeGeneratedResult( previousName );
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-05 14:07:00 +02:00
|
|
|
else if ( changedField == &m_generateButton )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
2026-06-05 14:07:00 +02:00
|
|
|
m_generateButton = false;
|
2026-05-27 12:14:08 +02:00
|
|
|
compute();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
QList<caf::PdmOptionItemInfo> RimFaultDistance::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
|
|
|
|
|
|
|
|
if ( fieldNeedingOptions == &m_faults )
|
|
|
|
|
{
|
2026-06-05 14:04:21 +02:00
|
|
|
RimEclipseCase* eclipseCase = firstAncestorOrThisOfType<RimEclipseCase>();
|
|
|
|
|
const auto views = eclipseCase ? eclipseCase->reservoirViews() : std::vector<RimEclipseView*>();
|
|
|
|
|
auto faultCollection = ( !views.empty() && views.front() ) ? views.front()->faultCollection() : nullptr;
|
2026-05-27 12:14:08 +02:00
|
|
|
if ( faultCollection )
|
|
|
|
|
{
|
|
|
|
|
for ( RimFaultInView* fault : faultCollection->faults() )
|
|
|
|
|
{
|
|
|
|
|
if ( fault ) options.push_back( caf::PdmOptionItemInfo( fault->name(), fault ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
caf::PdmFieldHandle* RimFaultDistance::userDescriptionField()
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
return &m_resultName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
uiOrdering.add( &m_resultName );
|
|
|
|
|
uiOrdering.add( &m_faults );
|
2026-06-05 14:07:00 +02:00
|
|
|
uiOrdering.add( &m_generateButton );
|
2026-05-27 12:14:08 +02:00
|
|
|
uiOrdering.skipRemainingFields( true );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:07:00 +02:00
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
2026-06-05 14:07:00 +02:00
|
|
|
{
|
|
|
|
|
if ( field == &m_generateButton )
|
|
|
|
|
{
|
|
|
|
|
if ( auto* attrib = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute ) )
|
|
|
|
|
{
|
|
|
|
|
attrib->m_buttonText = "Generate";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-05-27 12:14:08 +02:00
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::removeGeneratedResult( const QString& name )
|
2026-05-27 12:14:08 +02:00
|
|
|
{
|
|
|
|
|
if ( name.isEmpty() ) return;
|
|
|
|
|
|
2026-06-05 14:04:21 +02:00
|
|
|
RimEclipseCase* eclipseCase = firstAncestorOrThisOfType<RimEclipseCase>();
|
2026-05-27 12:14:08 +02:00
|
|
|
if ( !eclipseCase ) return;
|
|
|
|
|
|
|
|
|
|
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
|
|
|
|
|
if ( !caseData ) return;
|
|
|
|
|
|
|
|
|
|
RigCaseCellResultsData* resultsData = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
|
|
|
|
if ( !resultsData ) return;
|
|
|
|
|
|
2026-06-10 11:25:05 +02:00
|
|
|
RigEclipseResultAddress resultAddress( RiaDefines::ResultCatType::GENERATED, name );
|
|
|
|
|
|
|
|
|
|
// Select "None" result in any view currently displaying the result being removed.
|
|
|
|
|
for ( RimEclipseView* view : eclipseCase->reservoirViews() )
|
|
|
|
|
{
|
|
|
|
|
if ( !view ) continue;
|
|
|
|
|
|
|
|
|
|
RimEclipseCellColors* cellResult = view->cellResult();
|
|
|
|
|
if ( cellResult && cellResult->resultType() == RiaDefines::ResultCatType::GENERATED && cellResult->resultVariable() == name )
|
|
|
|
|
{
|
|
|
|
|
cellResult->setResultVariable( "None" );
|
|
|
|
|
cellResult->updateConnectedEditors();
|
|
|
|
|
view->scheduleCreateDisplayModelAndRedraw();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resultsData->clearScalarResult( resultAddress );
|
|
|
|
|
resultsData->setRemovedTagOnGeneratedResult( resultAddress );
|
2026-05-27 12:14:08 +02:00
|
|
|
}
|
2026-06-01 08:41:36 +02:00
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2026-06-05 14:35:21 +02:00
|
|
|
void RimFaultDistance::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
|
2026-06-01 08:41:36 +02:00
|
|
|
{
|
|
|
|
|
menuBuilder << "RicNewFaultDistanceResultFeature";
|
|
|
|
|
}
|