mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
Well target mapping: separate start and grow data filters
Add a start data filter used when finding starting cells. If empty, the grow filter is used. An empty grow filter allows growing anywhere.
This commit is contained in:
1 parent
da4e6e15cd
commit
19f94395a7
5 files changed
+76
-41
No files matched your search
@@ -160,7 +160,17 @@ RimWellTargetMapping::RimWellTargetMapping()
|
||||
"How much to increase the bounding box of the first case to cover for any grid size differences across the "
|
||||
"ensemble." );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_dataFilter, "DataFilter", "Data Filter" );
|
||||
// "DataFilter" is the grow filter; keeping the keyword keeps old project files working (an empty start filter falls back to it).
|
||||
CAF_PDM_InitFieldNoDefault( &m_startDataFilter,
|
||||
"StartDataFilter",
|
||||
"Start Data Filter",
|
||||
"",
|
||||
"Limits where starting cells are searched for. If empty, the grow data filter is used." );
|
||||
CAF_PDM_InitFieldNoDefault( &m_dataFilter,
|
||||
"DataFilter",
|
||||
"Grow Data Filter",
|
||||
"",
|
||||
"Limits where clusters can grow. If empty, clusters can grow anywhere in the model." );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_ensembleStatisticsCase, "EnsembleStatisticsCase", "Ensemble Statistics Case" );
|
||||
|
||||
@@ -226,7 +236,7 @@ QList<caf::PdmOptionItemInfo> RimWellTargetMapping::calculateValueOptions( const
|
||||
caf::AppEnum<RigWellTargetMapping::VolumesType>::setEnumSubset( &m_volumesType, findAvailableVolumesTypes( fc ) );
|
||||
}
|
||||
}
|
||||
else if ( fieldNeedingOptions == &m_dataFilter )
|
||||
else if ( fieldNeedingOptions == &m_dataFilter || fieldNeedingOptions == &m_startDataFilter )
|
||||
{
|
||||
options.push_back( caf::PdmOptionItemInfo( "None", nullptr ) );
|
||||
|
||||
@@ -498,6 +508,7 @@ void RimWellTargetMapping::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
|
||||
auto gridEnsemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>();
|
||||
|
||||
auto hasEnsembleParent = firstAncestorOrThisOfType<RimEclipseCaseEnsemble>() != nullptr || gridEnsemble != nullptr;
|
||||
uiOrdering.add( &m_startDataFilter );
|
||||
uiOrdering.add( &m_dataFilter );
|
||||
|
||||
caf::PdmUiGroup* minimumCellValuesGroup = uiOrdering.addNewGroup( "Minimum Cell Values" );
|
||||
@@ -560,7 +571,8 @@ RigWellTargetMapping::ClusteringLimits RimWellTargetMapping::getClusteringLimits
|
||||
.maxNumTargets = m_maxNumTargets,
|
||||
.maxIterations = m_maxIterations,
|
||||
.filterAddress = m_resultDefinition->eclipseResultAddress(),
|
||||
.dataFilter = m_dataFilter() };
|
||||
.startDataFilter = m_startDataFilter(),
|
||||
.growDataFilter = m_dataFilter() };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -107,7 +107,8 @@ private:
|
||||
caf::PdmField<int> m_cellCountJ;
|
||||
caf::PdmField<int> m_cellCountK;
|
||||
|
||||
caf::PdmPtrField<RimCellFilter*> m_dataFilter;
|
||||
caf::PdmPtrField<RimCellFilter*> m_startDataFilter;
|
||||
caf::PdmPtrField<RimCellFilter*> m_dataFilter; // grow filter
|
||||
|
||||
caf::PdmChildField<RimEclipseCase*> m_ensembleStatisticsCase;
|
||||
|
||||
|
||||
@@ -146,45 +146,53 @@ void RigWellTargetMapping::generateCandidates( RimEclipseCase* eclips
|
||||
data.transmissibilityNNC = nullptr;
|
||||
}
|
||||
|
||||
std::vector<double> filterVector;
|
||||
if ( limits.dataFilter )
|
||||
// Evaluate for each realization after opening its grid, using the mapping's time step.
|
||||
auto computeFilterVector = [&]( RimCellFilter* dataFilter ) -> std::vector<double>
|
||||
{
|
||||
// Evaluate for each realization after opening its grid, using the mapping's time step.
|
||||
auto visibility = RimCellFilterTools::computeReservoirCellVisibility( limits.dataFilter, eclipseCase, timeStepIdx );
|
||||
if ( visibility.notNull() )
|
||||
std::vector<double> filterVector;
|
||||
if ( dataFilter )
|
||||
{
|
||||
auto activeReservoirCellIndices =
|
||||
caseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL )->activeReservoirCellIndices();
|
||||
const int numActiveCells = static_cast<int>( activeReservoirCellIndices.size() );
|
||||
filterVector.resize( numActiveCells );
|
||||
|
||||
// Convert reservoir visibility to the active-cell indexing used by clustering.
|
||||
#pragma omp parallel for
|
||||
for ( int i = 0; i < numActiveCells; i++ )
|
||||
auto visibility = RimCellFilterTools::computeReservoirCellVisibility( dataFilter, eclipseCase, timeStepIdx );
|
||||
if ( visibility.notNull() )
|
||||
{
|
||||
filterVector[i] = visibility->val( activeReservoirCellIndices[i].value() ) ? 1.0 : 0.0;
|
||||
auto activeReservoirCellIndices =
|
||||
caseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL )->activeReservoirCellIndices();
|
||||
const int numActiveCells = static_cast<int>( activeReservoirCellIndices.size() );
|
||||
filterVector.resize( numActiveCells );
|
||||
|
||||
// Convert reservoir visibility to the active-cell indexing used by clustering.
|
||||
#pragma omp parallel for
|
||||
for ( int i = 0; i < numActiveCells; i++ )
|
||||
{
|
||||
filterVector[i] = visibility->val( activeReservoirCellIndices[i].value() ) ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fall through to the unfiltered path below so all realizations in an ensemble get a result,
|
||||
// consistent with how an invalid filterAddress is handled.
|
||||
RiaLogging::warning(
|
||||
std::format( "Unable to evaluate well target mapping data filter for case '{}'. Continuing without filter.",
|
||||
eclipseCase->caseUserDescription().toStdString() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( limits.filterAddress.isValid() )
|
||||
{
|
||||
// Fall through to the unfiltered path below so all realizations in an ensemble get a result,
|
||||
// consistent with how an invalid filterAddress is handled.
|
||||
RiaLogging::warning(
|
||||
std::format( "Unable to evaluate well target mapping data filter for case '{}'. Continuing without filter.",
|
||||
eclipseCase->caseUserDescription().toStdString() ) );
|
||||
resultsData->ensureKnownResultLoaded( limits.filterAddress );
|
||||
filterVector = resultsData->cellScalarResults( limits.filterAddress, timeStepIdx );
|
||||
}
|
||||
}
|
||||
else if ( limits.filterAddress.isValid() )
|
||||
{
|
||||
resultsData->ensureKnownResultLoaded( limits.filterAddress );
|
||||
filterVector = resultsData->cellScalarResults( limits.filterAddress, timeStepIdx );
|
||||
}
|
||||
|
||||
// Disable filtering if not configured: set all items to 1 (which includes all cells).
|
||||
if ( filterVector.empty() || filterVector.size() != data.pressure.size() )
|
||||
{
|
||||
filterVector = std::vector<double>( data.pressure.size(), 1.0 );
|
||||
}
|
||||
// Disable filtering if not configured: set all items to 1 (which includes all cells).
|
||||
if ( filterVector.empty() || filterVector.size() != data.pressure.size() )
|
||||
{
|
||||
filterVector = std::vector<double>( data.pressure.size(), 1.0 );
|
||||
}
|
||||
return filterVector;
|
||||
};
|
||||
|
||||
const std::vector<double> growFilterVector = computeFilterVector( limits.growDataFilter );
|
||||
// Without a start filter, the grow filter is used to find the starting cells.
|
||||
const std::vector<double> startFilterVector = limits.startDataFilter ? computeFilterVector( limits.startDataFilter ) : growFilterVector;
|
||||
|
||||
const QString logKeyword = "RigWellTargetMapping";
|
||||
|
||||
@@ -196,7 +204,7 @@ void RigWellTargetMapping::generateCandidates( RimEclipseCase* eclips
|
||||
for ( int clusterId = 1; clusterId <= numClusters; clusterId++ )
|
||||
{
|
||||
std::optional<caf::VecIjk0> startCell =
|
||||
RigWellTargetMappingTools::findStartCell( eclipseCase, timeStepIdx, volumeType, limits, data, filterVector, clusters );
|
||||
RigWellTargetMappingTools::findStartCell( eclipseCase, timeStepIdx, volumeType, limits, data, startFilterVector, clusters );
|
||||
|
||||
if ( startCell.has_value() )
|
||||
{
|
||||
@@ -213,7 +221,7 @@ void RigWellTargetMapping::generateCandidates( RimEclipseCase* eclips
|
||||
volumeType,
|
||||
limits,
|
||||
data,
|
||||
filterVector,
|
||||
growFilterVector,
|
||||
clusters,
|
||||
clusterId,
|
||||
timeStepIdx,
|
||||
|
||||
@@ -68,7 +68,8 @@ public:
|
||||
int maxNumTargets;
|
||||
int maxIterations;
|
||||
RigEclipseResultAddress filterAddress;
|
||||
RimCellFilter* dataFilter = nullptr;
|
||||
RimCellFilter* startDataFilter = nullptr; // falls back to growDataFilter if null
|
||||
RimCellFilter* growDataFilter = nullptr;
|
||||
};
|
||||
|
||||
static void generateCandidates( RimEclipseCase* eclipseCase,
|
||||
|
||||
@@ -113,6 +113,19 @@ TEST( RimWellTargetMappingTest, FilterOptionsUseOwningCase )
|
||||
EXPECT_EQ( caf::PdmOptionItemInfo( "Case filter", filter ).value(), options[1].value() );
|
||||
}
|
||||
|
||||
TEST( RimWellTargetMappingTest, StartFilterOptionsUseOwningCase )
|
||||
{
|
||||
RimEclipseResultCase eclipseCase;
|
||||
auto mapping = new TestableWellTargetMapping;
|
||||
eclipseCase.addWellTargetMapping( mapping );
|
||||
auto filter = eclipseCase.dataFilterCollection()->addNewRangeFilter();
|
||||
filter->setName( "Case filter" );
|
||||
|
||||
auto options = mapping->calculateValueOptions( mapping->findField( "StartDataFilter" ) );
|
||||
ASSERT_EQ( 2, options.size() );
|
||||
EXPECT_EQ( caf::PdmOptionItemInfo( "Case filter", filter ).value(), options[1].value() );
|
||||
}
|
||||
|
||||
TEST( RimWellTargetMappingTest, FilterOptionsUseOwningEnsemble )
|
||||
{
|
||||
RimReservoirGridEnsemble ensemble;
|
||||
@@ -222,9 +235,9 @@ TEST_P( RimWellTargetMappingFilterTest, FiltersClustersWithoutViews )
|
||||
if ( useEnsemble )
|
||||
{
|
||||
RigWellTargetMapping::ClusteringLimits limits{};
|
||||
limits.maxNumTargets = 1;
|
||||
limits.maxIterations = 10;
|
||||
limits.dataFilter = filter;
|
||||
limits.maxNumTargets = 1;
|
||||
limits.maxIterations = 10;
|
||||
limits.growDataFilter = filter;
|
||||
RigFloodingSettings floodingSettings( RigFloodingSettings::FloodingType::WATER_FLOODING,
|
||||
0.0,
|
||||
RigFloodingSettings::FloodingType::GAS_FLOODING,
|
||||
|
||||
Reference in new issue
Block a user