#13890 Faults: Add FAULTDIST result for a user-selected subset of faults

The existing FAULTDIST result always considered every fault in the main
grid. Users with many faults need to compute distance fields against a
named subset, so this adds a Fault Distance Results collection under
each view's Faults node. Each entry holds a multiselect of faults and a
name (FAULTDIST1, FAULTDIST2, ...) and publishes the result into the
Generated cell-result category.

The per-cell BVH-based distance loop was extracted from
RigFaultDistanceResultCalculator into a reusable utility that accepts
the subset of faults to include; the original all-faults entry point
delegates to the same utility and keeps the static-native FAULTDIST
behavior unchanged.
This commit is contained in:
Kristian Bendiksen
2026-06-01 11:28:46 +02:00
parent cb9274ecd6
commit b51dc28854
17 changed files with 833 additions and 89 deletions
@@ -18,6 +18,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicEclipsePropertyFilterNewInViewFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicEclipseHideFaultFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicEclipseShowOnlyFaultFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewFaultDistanceResultFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicRenameCaseFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicAddGridCalculationFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCreateGridCaseEnsemblesFromFilesFeature.cpp
@@ -0,0 +1,109 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewFaultDistanceResultFeature.h"
#include "RimFaultDistanceResult.h"
#include "RimFaultDistanceResultCollection.h"
#include "RimFaultInView.h"
#include "RimFaultInViewCollection.h"
#include "Riu3DMainWindowTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewFaultDistanceResultFeature, "RicNewFaultDistanceResultFeature" );
namespace
{
RimFaultInViewCollection* findHostCollection()
{
const auto faultCollections = caf::SelectionManager::instance()->objectsByType<RimFaultInViewCollection>();
if ( !faultCollections.empty() ) return faultCollections.front();
const auto distanceCollections = caf::SelectionManager::instance()->objectsByType<RimFaultDistanceResultCollection>();
if ( !distanceCollections.empty() )
{
return distanceCollections.front()->firstAncestorOrThisOfType<RimFaultInViewCollection>();
}
const auto distanceResults = caf::SelectionManager::instance()->objectsByType<RimFaultDistanceResult>();
if ( !distanceResults.empty() )
{
return distanceResults.front()->firstAncestorOrThisOfType<RimFaultInViewCollection>();
}
const auto faults = caf::SelectionManager::instance()->objectsByType<RimFaultInView>();
if ( !faults.empty() )
{
return faults.front()->firstAncestorOrThisOfType<RimFaultInViewCollection>();
}
return nullptr;
}
} // namespace
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewFaultDistanceResultFeature::isCommandEnabled() const
{
return findHostCollection() != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewFaultDistanceResultFeature::onActionTriggered( bool isChecked )
{
RimFaultInViewCollection* hostCollection = findHostCollection();
if ( !hostCollection ) return;
RimFaultDistanceResultCollection* distanceCollection = hostCollection->faultDistanceResults();
if ( !distanceCollection ) return;
const auto selectedFaultPointers = caf::SelectionManager::instance()->objectsByType<RimFaultInView>();
std::vector<RimFaultInView*> selectedFaults( selectedFaultPointers.begin(), selectedFaultPointers.end() );
RimFaultDistanceResult* newResult = distanceCollection->addResult();
if ( !newResult ) return;
if ( !selectedFaults.empty() )
{
newResult->setSelectedFaults( selectedFaults );
}
else
{
newResult->setSelectedFaults( hostCollection->faults() );
}
hostCollection->updateConnectedEditors();
distanceCollection->updateConnectedEditors();
Riu3DMainWindowTools::selectAsCurrentItem( newResult );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewFaultDistanceResultFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "New Fault Distance Result" );
actionToSetup->setIcon( QIcon( ":/draw_style_faults_24x24.png" ) );
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicNewFaultDistanceResultFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -1,4 +1,6 @@
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimFaultDistanceResult.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFaultDistanceResultCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFaultInView.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFaultInViewCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFaultReactivationModel.cpp
@@ -0,0 +1,190 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimFaultDistanceResult.h"
#include "RiaDefines.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigFault.h"
#include "RigSelectedFaultDistanceResultCalculator.h"
#include "RimEclipseCase.h"
#include "RimEclipseView.h"
#include "RimFaultInView.h"
#include "RimFaultInViewCollection.h"
#include "cafPdmUiTreeSelectionEditor.h"
CAF_PDM_SOURCE_INIT( RimFaultDistanceResult, "RimFaultDistanceResult" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultDistanceResult::RimFaultDistanceResult()
{
CAF_PDM_InitObject( "Fault Distance Result", ":/draw_style_faults_24x24.png" );
CAF_PDM_InitFieldNoDefault( &m_resultName, "ResultName", "Name" );
CAF_PDM_InitFieldNoDefault( &m_faults, "SelectedFaults", "Faults" );
m_faults.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimFaultDistanceResult::resultName() const
{
return m_resultName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::setResultName( const QString& name )
{
m_resultName = name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::setSelectedFaults( const std::vector<RimFaultInView*>& faults )
{
m_faults.setValue( faults );
compute();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<const RigFault*> RimFaultDistanceResult::selectedRigFaults() const
{
std::vector<const RigFault*> rigFaults;
for ( RimFaultInView* fault : m_faults )
{
if ( fault && fault->faultGeometry() ) rigFaults.push_back( fault->faultGeometry() );
}
return rigFaults;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::compute()
{
if ( m_resultName().isEmpty() ) return;
auto eclipseView = firstAncestorOrThisOfType<RimEclipseView>();
if ( !eclipseView ) return;
RimEclipseCase* eclipseCase = eclipseView->eclipseCase();
if ( !eclipseCase ) return;
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
if ( !caseData ) return;
RigSelectedFaultDistanceResultCalculator::compute( caseData, m_resultName(), selectedRigFaults() );
eclipseView->scheduleCreateDisplayModelAndRedraw();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_resultName )
{
const QString previousName = oldValue.toString();
if ( !previousName.isEmpty() && previousName != m_resultName() )
{
removeGeneratedResult( previousName );
}
compute();
}
else if ( changedField == &m_faults )
{
compute();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimFaultDistanceResult::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_faults )
{
auto faultCollection = firstAncestorOrThisOfType<RimFaultInViewCollection>();
if ( faultCollection )
{
for ( RimFaultInView* fault : faultCollection->faults() )
{
if ( fault ) options.push_back( caf::PdmOptionItemInfo( fault->name(), fault ) );
}
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimFaultDistanceResult::userDescriptionField()
{
return &m_resultName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_resultName );
uiOrdering.add( &m_faults );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResult::removeGeneratedResult( const QString& name )
{
if ( name.isEmpty() ) return;
auto eclipseView = firstAncestorOrThisOfType<RimEclipseView>();
if ( !eclipseView ) return;
RimEclipseCase* eclipseCase = eclipseView->eclipseCase();
if ( !eclipseCase ) return;
RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData();
if ( !caseData ) return;
RigCaseCellResultsData* resultsData = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
if ( !resultsData ) return;
resultsData->clearScalarResult( RiaDefines::ResultCatType::GENERATED, name );
}
@@ -0,0 +1,61 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmPtrArrayField.h"
#include <QString>
#include <vector>
class RigFault;
class RimFaultInView;
//==================================================================================================
///
//==================================================================================================
class RimFaultDistanceResult : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimFaultDistanceResult();
QString resultName() const;
void setResultName( const QString& name );
void setSelectedFaults( const std::vector<RimFaultInView*>& faults );
std::vector<const RigFault*> selectedRigFaults() const;
void compute();
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
caf::PdmFieldHandle* userDescriptionField() override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
private:
void removeGeneratedResult( const QString& name );
caf::PdmPtrArrayField<RimFaultInView*> m_faults;
caf::PdmField<QString> m_resultName;
};
@@ -0,0 +1,79 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimFaultDistanceResultCollection.h"
#include "RimFaultDistanceResult.h"
#include "cafPdmUiTreeOrdering.h"
#include <QRegularExpression>
CAF_PDM_SOURCE_INIT( RimFaultDistanceResultCollection, "RimFaultDistanceResultCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultDistanceResultCollection::RimFaultDistanceResultCollection()
{
CAF_PDM_InitObject( "Fault Distance Results", ":/draw_style_faults_24x24.png" );
CAF_PDM_InitFieldNoDefault( &m_items, "FaultDistanceResults", "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultDistanceResult* RimFaultDistanceResultCollection::addResult()
{
auto* newResult = new RimFaultDistanceResult();
newResult->setResultName( nextDefaultName() );
addItem( newResult );
return newResult;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimFaultDistanceResultCollection::nextDefaultName() const
{
QRegularExpression pattern( "^FAULTDIST(\\d+)$" );
int maxIndex = 0;
for ( RimFaultDistanceResult* result : items() )
{
if ( !result ) continue;
const QRegularExpressionMatch match = pattern.match( result->resultName() );
if ( match.hasMatch() )
{
maxIndex = std::max( maxIndex, match.captured( 1 ).toInt() );
}
}
return QString( "FAULTDIST%1" ).arg( maxIndex + 1 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimFaultDistanceResultCollection::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
{
for ( RimFaultDistanceResult* result : items() )
{
uiTreeOrdering.add( result );
}
uiTreeOrdering.skipRemainingChildren( true );
}
@@ -0,0 +1,42 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmObjectCollection.h"
#include <QString>
class RimFaultDistanceResult;
//==================================================================================================
///
//==================================================================================================
class RimFaultDistanceResultCollection : public caf::PdmObjectCollection<RimFaultDistanceResult>
{
CAF_PDM_HEADER_INIT;
public:
RimFaultDistanceResultCollection();
RimFaultDistanceResult* addResult();
QString nextDefaultName() const;
private:
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override;
};
@@ -27,6 +27,7 @@
#include "RimEclipseFaultColors.h"
#include "RimEclipseView.h"
#include "RimFaultDistanceResultCollection.h"
#include "RimFaultInView.h"
#include "RimIntersectionCollection.h"
#include "RimProject.h"
@@ -98,6 +99,9 @@ RimFaultInViewCollection::RimFaultInViewCollection()
CAF_PDM_InitFieldNoDefault( &m_faults, "Faults", "Faults" );
CAF_PDM_InitFieldNoDefault( &m_distanceResults, "FaultDistanceResults", "" );
m_distanceResults = new RimFaultDistanceResultCollection;
CAF_PDM_InitField( &m_showFaultsOutsideFilters_obsolete, "ShowFaultsOutsideFilters", true, "Show Faults Outside Filters" );
m_showFaultsOutsideFilters_obsolete.xmlCapability()->setIOWritable( false );
m_showFaultsOutsideFilters_obsolete.uiCapability()->setUiHidden( true );
@@ -391,6 +395,11 @@ void RimFaultInViewCollection::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiT
uiTreeOrdering.appendChild( uiTree );
}
if ( m_distanceResults() && !m_distanceResults()->isEmpty() )
{
uiTreeOrdering.add( m_distanceResults() );
}
for ( const auto& fault : m_faults )
{
uiTreeOrdering.add( fault );
@@ -407,6 +416,14 @@ RimEclipseView* RimFaultInViewCollection::parentView() const
return firstAncestorOrThisOfTypeAsserted<RimEclipseView>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFaultDistanceResultCollection* RimFaultInViewCollection::faultDistanceResults() const
{
return m_distanceResults();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -21,6 +21,7 @@
#include "cafAppEnum.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
@@ -32,6 +33,7 @@
#include <vector>
class RimEclipseView;
class RimFaultDistanceResultCollection;
class RimFaultInView;
//==================================================================================================
@@ -57,6 +59,7 @@ public:
void setActive( bool bActive );
std::vector<RimFaultInView*> faults() const;
RimFaultDistanceResultCollection* faultDistanceResults() const;
cvf::Color3f faultLabelColor() const;
caf::AppEnum<FaultFaceCullingMode> faultResult() const;
bool showFaultFaces() const;
@@ -105,7 +108,8 @@ private:
caf::PdmField<caf::AppEnum<FaultFaceCullingMode>> m_faultResult;
caf::PdmChildArrayField<RimFaultInView*> m_faults;
caf::PdmChildArrayField<RimFaultInView*> m_faults;
caf::PdmChildField<RimFaultDistanceResultCollection*> m_distanceResults;
caf::PdmField<bool> m_showFaultsOutsideFilters_obsolete;
};
@@ -68,7 +68,10 @@
#include "RimEnsembleCurveSetCollection.h"
#include "RimEnsembleFractureStatisticsCollection.h"
#include "RimExtrudedCurveIntersection.h"
#include "RimFaultDistanceResult.h"
#include "RimFaultDistanceResultCollection.h"
#include "RimFaultInView.h"
#include "RimFaultInViewCollection.h"
#include "RimFaultReactivationModel.h"
#include "RimFileWellPath.h"
#include "RimFishbones.h"
@@ -846,6 +849,12 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
else if ( dynamic_cast<RimFaultInView*>( firstUiItem ) )
{
menuBuilder << "RicExportFaultsFeature";
menuBuilder << "RicNewFaultDistanceResultFeature";
}
else if ( dynamic_cast<RimFaultInViewCollection*>( firstUiItem ) ||
dynamic_cast<RimFaultDistanceResultCollection*>( firstUiItem ) || dynamic_cast<RimFaultDistanceResult*>( firstUiItem ) )
{
menuBuilder << "RicNewFaultDistanceResultFeature";
}
else if ( dynamic_cast<RimWellAllocationPlot*>( firstUiItem ) )
{
@@ -1186,6 +1195,12 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
else if ( dynamic_cast<RimFaultInView*>( firstUiItem ) )
{
menuBuilder << "RicExportFaultsFeature";
menuBuilder << "RicNewFaultDistanceResultFeature";
}
else if ( dynamic_cast<RimFaultInViewCollection*>( firstUiItem ) ||
dynamic_cast<RimFaultDistanceResultCollection*>( firstUiItem ) || dynamic_cast<RimFaultDistanceResult*>( firstUiItem ) )
{
menuBuilder << "RicNewFaultDistanceResultFeature";
}
else if ( dynamic_cast<RimSimWellInView*>( firstUiItem ) )
{
@@ -2,7 +2,9 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigSoilResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigSwatResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigFaultDistanceCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigFaultDistanceResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigSelectedFaultDistanceResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigMobilePoreVolumeResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigIndexIjkResultCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigOilVolumeResultCalculator.cpp
@@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigFaultDistanceCalculator.h"
#include "RigActiveCellInfo.h"
#include "RigCell.h"
#include "RigFault.h"
#include "RigMainGrid.h"
#include "cvfBoundingBoxTree.h"
#include <limits>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFaultDistanceCalculator::computeFaultDistances( const RigMainGrid* mainGrid,
const RigActiveCellInfo* activeCellInfo,
const std::vector<const RigFault*>& faultsToInclude,
std::vector<double>& resultValues )
{
if ( !mainGrid || !activeCellInfo ) return;
const auto activeCells = activeCellInfo->activeReservoirCellIndices();
if ( activeCells.empty() ) return;
if ( resultValues.size() < activeCells.size() )
{
resultValues.resize( activeCells.size(), std::numeric_limits<double>::infinity() );
}
// Collect fault face centers from the requested subset of faults.
std::vector<cvf::Vec3d> faultFaceCenters;
for ( const RigFault* fault : faultsToInclude )
{
if ( !fault ) continue;
for ( const RigFault::FaultFace& faultFace : fault->faultFaces() )
{
if ( faultFace.m_nativeReservoirCellIndex >= mainGrid->cellCount() ) continue;
const RigCell& cell = mainGrid->cell( faultFace.m_nativeReservoirCellIndex );
if ( cell.isInvalid() ) continue;
faultFaceCenters.push_back( cell.faceCenter( faultFace.m_nativeFace ) );
}
}
if ( faultFaceCenters.empty() ) return;
// Create bounding box tree for all face centers
cvf::BoundingBoxTree searchTree;
{
std::vector<size_t> faceIndicesForBoundingBoxes;
std::vector<cvf::BoundingBox> faceBBs;
size_t faceCenterIndex = 0;
for ( const auto& faultFaceCenter : faultFaceCenters )
{
cvf::BoundingBox bb;
bb.add( faultFaceCenter );
faceBBs.push_back( bb );
faceIndicesForBoundingBoxes.push_back( faceCenterIndex++ );
}
searchTree.buildTreeFromBoundingBoxes( faceBBs, &faceIndicesForBoundingBoxes );
}
const auto nodes = mainGrid->nodes();
const auto mainGridBB = mainGrid->boundingBox();
#pragma omp parallel for
for ( int activeIndex = 0; activeIndex < static_cast<int>( activeCells.size() ); activeIndex++ )
{
auto cellIdx = activeCells[activeIndex];
if ( cellIdx.value() == cvf::UNDEFINED_SIZE_T ) continue;
const RigCell& cell = mainGrid->cell( cellIdx.value() );
if ( cell.isInvalid() ) continue;
std::vector<size_t> candidateFaceIndices;
{
cvf::BoundingBox bb;
const auto& cellIndices = cell.cornerIndices();
for ( const auto& i : cellIndices )
{
bb.add( nodes[i] );
}
searchTree.findIntersections( bb, &candidateFaceIndices );
bool bbIsBelowThreshold = true;
while ( candidateFaceIndices.empty() && bbIsBelowThreshold )
{
if ( bb.extent().x() > mainGridBB.extent().x() * 2 )
{
bbIsBelowThreshold = false;
break;
}
if ( bb.extent().y() > mainGridBB.extent().y() * 2 )
{
bbIsBelowThreshold = false;
break;
}
bb.expand( bb.extent().x() );
searchTree.findIntersections( bb, &candidateFaceIndices );
}
}
// Find closest fault face
double shortestDistance = std::numeric_limits<double>::infinity();
for ( const auto& faultFaceIndex : candidateFaceIndices )
{
const cvf::Vec3d& faultFaceCenter = faultFaceCenters[faultFaceIndex];
shortestDistance = std::min( cell.center().pointDistance( faultFaceCenter ), shortestDistance );
}
resultValues[activeIndex] = shortestDistance;
}
}
@@ -0,0 +1,36 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <vector>
class RigActiveCellInfo;
class RigFault;
class RigMainGrid;
//==================================================================================================
///
//==================================================================================================
namespace RigFaultDistanceCalculator
{
void computeFaultDistances( const RigMainGrid* mainGrid,
const RigActiveCellInfo* activeCellInfo,
const std::vector<const RigFault*>& faultsToInclude,
std::vector<double>& resultValues );
}
@@ -22,12 +22,11 @@
#include "RiaResultNames.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigCell.h"
#include "RigEclipseResultInfo.h"
#include "RigFault.h"
#include "RigFaultDistanceCalculator.h"
#include "RigMainGrid.h"
#include "cvfBoundingBoxTree.h"
//==================================================================================================
///
//==================================================================================================
@@ -80,92 +79,11 @@ void RigFaultDistanceResultCalculator::calculate( const RigEclipseResultAddress&
const auto mainGrid = m_resultsData->m_ownerMainGrid;
std::vector<cvf::StructGridInterface::FaceType> faceTypes = cvf::StructGridInterface::validFaceTypes();
// Preprocessing: create vector of all fault face centers.
std::vector<cvf::Vec3d> faultFaceCenters;
const auto activeCells = m_resultsData->activeCellInfo()->activeReservoirCellIndices();
for ( auto cellIdx : activeCells )
std::vector<const RigFault*> allFaults;
for ( size_t i = 0; i < mainGrid->faults().size(); ++i )
{
const RigCell& cell = mainGrid->cell( cellIdx.value() );
if ( cell.isInvalid() ) continue;
for ( auto faceType : faceTypes )
{
if ( m_resultsData->m_ownerMainGrid->findFaultFromCellIndexAndCellFace( cellIdx.value(), faceType ) )
faultFaceCenters.push_back( cell.faceCenter( faceType ) );
}
allFaults.push_back( mainGrid->faults().at( i ) );
}
if ( faultFaceCenters.empty() ) return;
// Create bounding box tree for all face centers
auto searchTree = new cvf::BoundingBoxTree;
{
std::vector<size_t> faceIndicesForBoundingBoxes;
std::vector<cvf::BoundingBox> faceBBs;
size_t faceCenterIndex = 0;
for ( const auto& faultFaceCenter : faultFaceCenters )
{
cvf::BoundingBox bb;
bb.add( faultFaceCenter );
faceBBs.push_back( bb );
faceIndicesForBoundingBoxes.push_back( faceCenterIndex++ );
}
searchTree->buildTreeFromBoundingBoxes( faceBBs, &faceIndicesForBoundingBoxes );
}
const auto nodes = m_resultsData->m_ownerMainGrid->nodes();
const auto mainGridBB = m_resultsData->m_ownerMainGrid->boundingBox();
#pragma omp parallel for
for ( int activeIndex = 0; activeIndex < static_cast<int>( activeCells.size() ); activeIndex++ )
{
auto cellIdx = activeCells[activeIndex];
if ( cellIdx.value() == cvf::UNDEFINED_SIZE_T ) continue;
const RigCell& cell = mainGrid->cell( cellIdx.value() );
if ( cell.isInvalid() ) continue;
std::vector<size_t> candidateFaceIndices;
{
cvf::BoundingBox bb;
const auto& cellIndices = cell.cornerIndices();
for ( const auto& i : cellIndices )
{
bb.add( nodes[i] );
}
searchTree->findIntersections( bb, &candidateFaceIndices );
bool bbIsBelowThreshold = true;
while ( candidateFaceIndices.empty() && bbIsBelowThreshold )
{
if ( bb.extent().x() > mainGridBB.extent().x() * 2 )
{
bbIsBelowThreshold = false;
break;
}
if ( bb.extent().y() > mainGridBB.extent().y() * 2 )
{
bbIsBelowThreshold = false;
break;
}
bb.expand( bb.extent().x() );
searchTree->findIntersections( bb, &candidateFaceIndices );
}
}
// Find closest fault face
double shortestDistance = std::numeric_limits<double>::infinity();
for ( const auto& faultFaceIndex : candidateFaceIndices )
{
const cvf::Vec3d& faultFaceCenter = faultFaceCenters[faultFaceIndex];
shortestDistance = std::min( cell.center().pointDistance( faultFaceCenter ), shortestDistance );
}
result[0][activeIndex] = shortestDistance;
}
RigFaultDistanceCalculator::computeFaultDistances( mainGrid, m_resultsData->activeCellInfo(), allFaults, result[0] );
}
@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigSelectedFaultDistanceResultCalculator.h"
#include "RiaDefines.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigFaultDistanceCalculator.h"
#include "RigMainGrid.h"
#include <limits>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigSelectedFaultDistanceResultCalculator::compute( RigEclipseCaseData* caseData,
const QString& resultName,
const std::vector<const RigFault*>& selectedFaults )
{
if ( !caseData || resultName.isEmpty() ) return;
RigCaseCellResultsData* resultsData = caseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
if ( !resultsData ) return;
const RigActiveCellInfo* activeCellInfo = resultsData->activeCellInfo();
if ( !activeCellInfo ) return;
const size_t activeCellCount = activeCellInfo->reservoirActiveCellCount();
if ( activeCellCount == 0 ) return;
RigEclipseResultAddress resultAddress( RiaDefines::ResultCatType::GENERATED, resultName );
if ( !resultsData->hasResultEntry( resultAddress ) )
{
resultsData->addStaticScalarResult( RiaDefines::ResultCatType::GENERATED, resultName, false, activeCellCount );
}
std::vector<double>* resultVector = resultsData->modifiableCellScalarResult( resultAddress, 0 );
if ( !resultVector ) return;
resultVector->assign( activeCellCount, std::numeric_limits<double>::infinity() );
RigFaultDistanceCalculator::computeFaultDistances( caseData->mainGrid(), activeCellInfo, selectedFaults, *resultVector );
resultsData->recalculateStatistics( resultAddress );
}
@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QString>
#include <vector>
class RigEclipseCaseData;
class RigFault;
//==================================================================================================
///
//==================================================================================================
class RigSelectedFaultDistanceResultCalculator
{
public:
static void compute( RigEclipseCaseData* caseData, const QString& resultName, const std::vector<const RigFault*>& selectedFaults );
};