mirror of
https://github.com/OPM/ResInsight.git
synced 2026-09-03 20:53:13 -05:00
Well target updates (#14619)
Support well target mapping calculations for ensembles.
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
#include "RimCellFilterCollection.h"
|
||||
#include "RimCommandRouter.h"
|
||||
#include "RimCompletionTemplateCollection.h"
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipseCaseCollection.h"
|
||||
#include "RimEclipseCaseEnsemble.h"
|
||||
#include "RimEclipseView.h"
|
||||
@@ -115,6 +116,7 @@
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCollection.h"
|
||||
#include "RimWellPathFracture.h"
|
||||
#include "RimWellTargetMapping.h"
|
||||
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
|
||||
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
|
||||
|
||||
@@ -865,6 +867,15 @@ bool RiaApplication::loadProject( const QString& projectFileName, ProjectLoadAct
|
||||
{
|
||||
view->loadDataAndUpdate();
|
||||
}
|
||||
|
||||
for ( auto wellTargetMapping : gridEnsemble->wellTargetMappings() )
|
||||
{
|
||||
if ( !wellTargetMapping->ensembleStatisticsCase() ) continue;
|
||||
for ( auto view : wellTargetMapping->ensembleStatisticsCase()->views() )
|
||||
{
|
||||
view->loadDataAndUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,16 @@ CAF_CMD_SOURCE_INIT( RicCloseCaseFeature, "RicCloseCaseFeature" );
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicCloseCaseFeature::isCommandEnabled() const
|
||||
{
|
||||
return !selectedCases().empty();
|
||||
if ( !selectedCases().empty() )
|
||||
{
|
||||
for ( auto ecase : selectedCases() )
|
||||
{
|
||||
if ( !ecase->isDeletable() ) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -39,16 +39,11 @@ bool RicNewWellTargetMappingFeature::isCommandEnabled() const
|
||||
{
|
||||
if ( auto gridEnsembles = caf::selectedObjectsByTypeStrict<RimReservoirGridEnsemble*>(); !gridEnsembles.empty() )
|
||||
{
|
||||
// Computation of well target mappings for individual grids is implemented in RimWellTargetMapping::generateEnsembleStatistics().
|
||||
//
|
||||
// If there is a future need to support well target mappings for ensembles with individual grids, the implementation in
|
||||
// RimWellTargetMapping::generateEnsembleStatistics() will need to be updated, and this check can be removed.
|
||||
//
|
||||
// The main performance reason is the memory consumption of loading all grids in the ensemble into memory at the same time, which is
|
||||
// currently needed in order to compute the well target mapping for ensembles with individual grids. For ensembles with shared grid,
|
||||
// only the shared grid needs to be loaded, which is much more memory efficient.
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if ( auto cases = caf::selectedObjectsByType<RimEclipseCase*>(); !cases.empty() )
|
||||
{
|
||||
return ( cases.front()->ensemble() == nullptr );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -614,6 +614,11 @@ void RimStatisticsContourMap::onComputeStatisticsClicked()
|
||||
void RimStatisticsContourMap::computeStatistics()
|
||||
{
|
||||
computeStatisticsForMaps( { this } );
|
||||
|
||||
if ( auto ensemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>() )
|
||||
{
|
||||
ensemble->reloadMetaDataIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -682,7 +687,7 @@ void RimStatisticsContourMap::computeStatisticsForMaps( const std::vector<RimSta
|
||||
|
||||
// The bounding box is empty unless the primary case is open with active cell info
|
||||
cvf::BoundingBox gridBoundingBox = primaryCase->activeCellsBoundingBox();
|
||||
gridBoundingBox.expandPercent( map->m_boundingBoxExpPercent() );
|
||||
gridBoundingBox.expandPercent( map->m_boundingBoxExpPercent(), map->m_boundingBoxExpPercent() );
|
||||
|
||||
double sampleSpacing = 1.0;
|
||||
if ( auto mainGrid = primaryCase->mainGrid() ) sampleSpacing = map->sampleSpacingFactor() * mainGrid->characteristicIJCellSize();
|
||||
@@ -722,12 +727,7 @@ void RimStatisticsContourMap::computeStatisticsForMaps( const std::vector<RimSta
|
||||
RiaLogging::info( std::format( "Computing statistics for {} ensemble contour map(s)", contexts.size() ) );
|
||||
|
||||
// All maps belong to the same ensemble, so the realization cases are shared
|
||||
auto cases = contexts.front().map->ensembleCases();
|
||||
auto casesInViews = contexts.front().map->ensembleCasesInViews();
|
||||
|
||||
std::set<RimEclipseCase*> primaryCases;
|
||||
for ( const auto& ctx : contexts )
|
||||
primaryCases.insert( ctx.map->eclipseCase() );
|
||||
auto cases = contexts.front().map->ensembleCases();
|
||||
|
||||
const size_t nCases = cases.size();
|
||||
caf::ProgressInfo progInfo( nCases, QString( "Reading Eclipse Ensemble" ) );
|
||||
@@ -739,6 +739,8 @@ void RimStatisticsContourMap::computeStatisticsForMaps( const std::vector<RimSta
|
||||
{
|
||||
auto task = progInfo.task( QString( "Processing Case %1 of %2" ).arg( i++ ).arg( nCases ) );
|
||||
|
||||
bool closeCase = !eCase->isReservoirCaseOpen();
|
||||
|
||||
RifReaderSettings oldSettings = eCase->readerSettings();
|
||||
eCase->setReaderSettings( readerSettings );
|
||||
|
||||
@@ -796,7 +798,7 @@ void RimStatisticsContourMap::computeStatisticsForMaps( const std::vector<RimSta
|
||||
// Release the grid data for cases that were opened only to compute statistics. A case is kept open if it has
|
||||
// its own views, if it is the primary case of one of the contour maps, or if it is displayed in one of the
|
||||
// ensemble views.
|
||||
if ( eCase->views().empty() && !primaryCases.contains( eCase ) && !casesInViews.contains( eCase ) )
|
||||
if ( closeCase )
|
||||
{
|
||||
eCase->closeReservoirCase();
|
||||
}
|
||||
@@ -981,6 +983,12 @@ void RimStatisticsContourMap::ensureResultsComputed()
|
||||
}
|
||||
|
||||
computeStatisticsForMaps( maps );
|
||||
|
||||
// contour map calculations on shared grids clears the ensemble meta data, reload it
|
||||
if ( auto ensemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>() )
|
||||
{
|
||||
ensemble->reloadMetaDataIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1119,6 +1119,15 @@ bool RimEclipseCase::ensureReservoirCaseIsOpen()
|
||||
return openReservoirCase();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimEclipseCase::isReservoirCaseOpen() const
|
||||
{
|
||||
// for most grid case types, this is a sufficient test
|
||||
return eclipseCaseData() != nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1468,3 +1477,11 @@ RimFaultDistanceCollection* RimEclipseCase::faultDistanceCollection() const
|
||||
{
|
||||
return m_dataAnalyticsCollection ? m_dataAnalyticsCollection->faultDistanceCollection() : nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimReservoirGridEnsemble* RimEclipseCase::ensemble() const
|
||||
{
|
||||
return firstAncestorOrThisOfType<RimReservoirGridEnsemble>();
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ class RimReservoirCellResultsStorage;
|
||||
class RimEclipseResultAddressCollection;
|
||||
class RimEclipseViewCollection;
|
||||
class RimResultNameAlias;
|
||||
class RimReservoirGridEnsemble;
|
||||
|
||||
namespace caf
|
||||
{
|
||||
@@ -87,6 +88,7 @@ public:
|
||||
|
||||
bool ensureReservoirCaseIsOpen();
|
||||
bool openReservoirCase();
|
||||
virtual bool isReservoirCaseOpen() const;
|
||||
virtual void closeReservoirCase();
|
||||
virtual bool openEclipseGridFile() = 0;
|
||||
virtual void reloadEclipseGridFile();
|
||||
@@ -155,6 +157,8 @@ public:
|
||||
|
||||
void updateFormationNamesData() override;
|
||||
|
||||
RimReservoirGridEnsemble* ensemble() const;
|
||||
|
||||
protected:
|
||||
void initAfterRead() override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
|
||||
@@ -415,6 +415,14 @@ void RimEclipseResultCase::closeReservoirCase()
|
||||
m_activeCellInfoIsReadFromFile = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimEclipseResultCase::isReservoirCaseOpen() const
|
||||
{
|
||||
return RimEclipseCase::isReservoirCaseOpen() && m_gridAndWellDataIsReadFromFile && m_activeCellInfoIsReadFromFile;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -58,6 +58,8 @@ public:
|
||||
bool hasSourSimFile();
|
||||
|
||||
bool openEclipseGridFile() override;
|
||||
|
||||
bool isReservoirCaseOpen() const override;
|
||||
void closeReservoirCase() override;
|
||||
|
||||
bool importGridAndResultMetaData( bool showTimeStepFilter );
|
||||
|
||||
@@ -141,6 +141,8 @@ RimEclipseStatisticsCase::RimEclipseStatisticsCase()
|
||||
m_activeFormationNames.uiCapability()->setUiHidden( true );
|
||||
|
||||
m_displayNameOption = RimCaseDisplayNameTools::DisplayName::CUSTOM;
|
||||
|
||||
setDeletable( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -405,10 +405,9 @@ void RimGridView::onCreatePartCollectionFromSelection( cvf::Collection<cvf::Part
|
||||
{
|
||||
RiuEclipseSelectionItem* eclipseSelItem = static_cast<RiuEclipseSelectionItem*>( items[i] );
|
||||
|
||||
if ( eclipseSelItem && eclipseSelItem->m_view == this && eclipseSelItem->m_resultDefinition->eclipseCase() )
|
||||
if ( eclipseSelItem && eclipseSelItem->m_view == this && eclipseSelItem->m_resultDefinition->eclipseCase() &&
|
||||
eclipseSelItem->m_resultDefinition->eclipseCase()->eclipseCaseData() )
|
||||
{
|
||||
CAF_ASSERT( eclipseSelItem->m_resultDefinition->eclipseCase()->eclipseCaseData() );
|
||||
|
||||
RivSingleCellPartGenerator partGen( eclipseSelItem->m_resultDefinition->eclipseCase()->eclipseCaseData(),
|
||||
eclipseSelItem->m_gridIndex,
|
||||
eclipseSelItem->m_gridLocalCellIndex,
|
||||
|
||||
@@ -108,6 +108,9 @@ RimReservoirGridEnsemble::RimReservoirGridEnsemble()
|
||||
m_statisticsCaseCollection->uiCapability()->setUiName( "Derived Statistics" );
|
||||
m_statisticsCaseCollection->uiCapability()->setUiIconFromResourceString( ":/Histograms16x16.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_ensembleCase, "EnsembleCase", "Ensemble Grid" );
|
||||
m_ensembleCase = nullptr;
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_viewCollection, "ViewCollection", "Views" );
|
||||
m_viewCollection = new RimEclipseViewCollection;
|
||||
m_viewCollection->setEclipseCaseProvider( [this]() { return this->cases(); } );
|
||||
@@ -563,6 +566,7 @@ std::set<RimEclipseCase*> RimReservoirGridEnsemble::casesInViews() const
|
||||
void RimReservoirGridEnsemble::addWellTargetMapping( RimWellTargetMapping* wellTargetMapping )
|
||||
{
|
||||
m_wellTargetMappings.push_back( wellTargetMapping );
|
||||
wellTargetMapping->setName( QString( "Well Target Mapping #%1" ).arg( m_wellTargetMappings.size() ) );
|
||||
wellTargetMapping->updateResultDefinition();
|
||||
}
|
||||
|
||||
@@ -927,6 +931,17 @@ void RimReservoirGridEnsemble::loadGridDataFromFiles()
|
||||
updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimReservoirGridEnsemble::reloadMetaDataIfNeeded()
|
||||
{
|
||||
if ( gridMode() == GridModeType::INDIVIDUAL_GRIDS ) return;
|
||||
|
||||
m_mainGrid = nullptr;
|
||||
loadGridDataFromFiles();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
// Deferred loading control
|
||||
void loadGridDataFromFiles();
|
||||
bool isGridDataLoaded() const;
|
||||
void reloadMetaDataIfNeeded();
|
||||
|
||||
// Helper methods
|
||||
bool hasSharedGrid() const;
|
||||
@@ -157,6 +158,7 @@ private:
|
||||
// Cases
|
||||
caf::PdmChildField<RimCaseCollection*> m_caseCollection;
|
||||
caf::PdmChildField<RimCaseCollection*> m_statisticsCaseCollection;
|
||||
caf::PdmChildField<RimEclipseCase*> m_ensembleCase;
|
||||
|
||||
// Grid mode
|
||||
caf::PdmField<bool> m_autoDetectGridType;
|
||||
|
||||
@@ -41,12 +41,14 @@
|
||||
#include "RimEclipsePropertyFilterCollection.h"
|
||||
#include "RimEclipseResultDefinition.h"
|
||||
#include "RimEclipseView.h"
|
||||
#include "RimEclipseViewCollection.h"
|
||||
#include "RimRegularGridCase.h"
|
||||
#include "RimReservoirGridEnsemble.h"
|
||||
#include "RimTools.h"
|
||||
|
||||
#include "cafPdmUiDoubleSliderEditor.h"
|
||||
#include "cafPdmUiSliderTools.h"
|
||||
#include "cafPdmUiTreeOrdering.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -93,6 +95,8 @@ RimWellTargetMapping::RimWellTargetMapping()
|
||||
{
|
||||
CAF_PDM_InitObject( "Well Target Mapping", ":/WellTargets.png" );
|
||||
|
||||
setName( "Well Target Mapping" );
|
||||
|
||||
CAF_PDM_InitField( &m_timeStep, "TimeStep", 0, "Time Step" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_volumeType, "VolumeType", "Volume" );
|
||||
@@ -141,6 +145,21 @@ RimWellTargetMapping::RimWellTargetMapping()
|
||||
CAF_PDM_InitField( &m_cellCountJ, "CellCountJ", 100, "Cell Count J" );
|
||||
CAF_PDM_InitField( &m_cellCountK, "CellCountK", 10, "Cell Count K" );
|
||||
|
||||
CAF_PDM_InitField( &m_expandBoundingBoxXYPercent,
|
||||
"ExpandBoundingBoxXYPercent",
|
||||
5.0,
|
||||
"Expand Bounding Box XY [%]",
|
||||
"",
|
||||
"How much to increase the bounding box of the first case to cover for any grid size differences across the "
|
||||
"ensemble." );
|
||||
CAF_PDM_InitField( &m_expandBoundingBoxZPercent,
|
||||
"ExpandBoundingBoxZPercent",
|
||||
10.0,
|
||||
"Expand Bounding Box Z [%]",
|
||||
"",
|
||||
"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_filterView, "FilterView", "Filter By View" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_ensembleStatisticsCase, "EnsembleStatisticsCase", "Ensemble Statistics Case" );
|
||||
@@ -180,7 +199,10 @@ RimWellTargetMapping::~RimWellTargetMapping()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
updateAllBoundaries();
|
||||
if ( changedField != nameField() )
|
||||
{
|
||||
updateAllBoundaries();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -384,15 +406,16 @@ void RimWellTargetMapping::generateCandidates( RimEclipseCase* eclipseCase, bool
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::generateEnsembleStatistics()
|
||||
{
|
||||
// See RicNewWellTargetMappingFeature::isCommandEnabled() for comment on future support for ensembles with varying geometry.
|
||||
|
||||
auto ensemble = firstAncestorOrThisOfType<RimEclipseCaseEnsemble>();
|
||||
auto ensemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>();
|
||||
if ( !ensemble ) return;
|
||||
|
||||
const cvf::Vec3st& resultGridCellCount = getResultGridCellCount();
|
||||
RigWellTargetMapping::ClusteringLimits limits = getClusteringLimits();
|
||||
RigFloodingSettings floodingSettings( m_oilFloodingType(), m_userDefinedFloodingOil(), m_gasFloodingType(), m_userDefinedFloodingGas() );
|
||||
|
||||
double expandXY = ensemble->hasSharedGrid() ? 0.0 : m_expandBoundingBoxXYPercent();
|
||||
double expandZ = ensemble->hasSharedGrid() ? 0.0 : m_expandBoundingBoxZPercent();
|
||||
|
||||
RimRegularGridCase* regularGridCase = RigWellTargetMapping::generateEnsembleCandidates( ensemble->cases(),
|
||||
m_timeStep(),
|
||||
resultGridCellCount,
|
||||
@@ -400,9 +423,17 @@ void RimWellTargetMapping::generateEnsembleStatistics()
|
||||
m_volumesType(),
|
||||
m_volumeResultType(),
|
||||
floodingSettings,
|
||||
limits );
|
||||
limits,
|
||||
expandXY,
|
||||
expandZ );
|
||||
|
||||
regularGridCase->setCustomCaseName( "Ensemble Grid" );
|
||||
regularGridCase->setDeletable( false );
|
||||
|
||||
if ( m_ensembleStatisticsCase() != nullptr )
|
||||
{
|
||||
delete m_ensembleStatisticsCase();
|
||||
}
|
||||
|
||||
m_ensembleStatisticsCase = regularGridCase;
|
||||
|
||||
@@ -411,14 +442,17 @@ void RimWellTargetMapping::generateEnsembleStatistics()
|
||||
eclipseView->cellResult()->setResultType( RiaDefines::ResultCatType::GENERATED );
|
||||
eclipseView->cellResult()->setResultVariable( "TOTAL_PORV_SOIL_P10" );
|
||||
|
||||
eclipseView->loadDataAndUpdate();
|
||||
|
||||
updateConnectedEditors();
|
||||
m_ensembleStatisticsCase->updateConnectedEditors();
|
||||
|
||||
ensemble->reloadMetaDataIfNeeded();
|
||||
|
||||
if ( RiaGuiApplication::isRunning() || RiuMainWindow::instance() )
|
||||
{
|
||||
RiuMainWindow::instance()->selectAsCurrentItem( eclipseView->cellResult() );
|
||||
}
|
||||
|
||||
eclipseView->loadDataAndUpdate();
|
||||
|
||||
m_ensembleStatisticsCase->updateConnectedEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -426,6 +460,9 @@ void RimWellTargetMapping::generateEnsembleStatistics()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
uiOrdering.add( nameField() );
|
||||
uiOrdering.addNewButton( "Compute", [this]() { onGenerateButtonClicked(); } );
|
||||
|
||||
caf::PdmUiGroup* resultGroup = uiOrdering.addNewGroup( "Result" );
|
||||
resultGroup->add( &m_timeStep );
|
||||
resultGroup->add( &m_volumeType );
|
||||
@@ -458,8 +495,9 @@ void RimWellTargetMapping::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
|
||||
|
||||
resultGroup->add( &m_volumesType );
|
||||
|
||||
auto hasEnsembleParent = firstAncestorOrThisOfType<RimEclipseCaseEnsemble>() != nullptr ||
|
||||
firstAncestorOrThisOfType<RimReservoirGridEnsemble>() != nullptr;
|
||||
auto gridEnsemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>();
|
||||
|
||||
auto hasEnsembleParent = firstAncestorOrThisOfType<RimEclipseCaseEnsemble>() != nullptr || gridEnsemble != nullptr;
|
||||
if ( !hasEnsembleParent ) uiOrdering.add( &m_filterView );
|
||||
|
||||
caf::PdmUiGroup* minimumCellValuesGroup = uiOrdering.addNewGroup( "Minimum Cell Values" );
|
||||
@@ -476,14 +514,18 @@ void RimWellTargetMapping::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
|
||||
ensembleGridGroup->add( &m_cellCountI );
|
||||
ensembleGridGroup->add( &m_cellCountJ );
|
||||
ensembleGridGroup->add( &m_cellCountK );
|
||||
|
||||
if ( gridEnsemble && !gridEnsemble->hasSharedGrid() )
|
||||
{
|
||||
ensembleGridGroup->add( &m_expandBoundingBoxXYPercent );
|
||||
ensembleGridGroup->add( &m_expandBoundingBoxZPercent );
|
||||
}
|
||||
}
|
||||
|
||||
caf::PdmUiGroup* advancedGroup = uiOrdering.addNewGroup( "Advanced" );
|
||||
advancedGroup->add( &m_maxNumTargets );
|
||||
advancedGroup->setCollapsedByDefault();
|
||||
|
||||
uiOrdering.addNewButton( "Generate", [this]() { onGenerateButtonClicked(); } );
|
||||
|
||||
uiOrdering.skipRemainingFields();
|
||||
|
||||
if ( m_minimumPressure == cvf::UNDEFINED_DOUBLE || m_maximumPressure == cvf::UNDEFINED_DOUBLE )
|
||||
@@ -492,6 +534,19 @@ void RimWellTargetMapping::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
||||
{
|
||||
if ( ensembleStatisticsCase() )
|
||||
{
|
||||
uiTreeOrdering.add( &m_ensembleStatisticsCase );
|
||||
}
|
||||
|
||||
uiTreeOrdering.skipRemainingChildren();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -563,12 +618,15 @@ RimEclipseCase* RimWellTargetMapping::firstCase() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::initAfterRead()
|
||||
{
|
||||
if ( RimEclipseCase* eclipseCase = firstCase() )
|
||||
if ( firstAncestorOrThisOfType<RimReservoirGridEnsemble>() )
|
||||
{
|
||||
return; // no need to to do anything for ensembles, as the data have been cached
|
||||
}
|
||||
else if ( RimEclipseCase* eclipseCase = firstCase() )
|
||||
{
|
||||
// Automatically generate results on project load
|
||||
m_resultDefinition->setEclipseCase( eclipseCase );
|
||||
|
||||
// Automatically generate results on project load
|
||||
// Consider to also do this for ensemble cases, but this will be more expensive
|
||||
bool setTimeStepInView = false;
|
||||
generateCandidates( eclipseCase, setTimeStepInView );
|
||||
}
|
||||
@@ -641,20 +699,10 @@ void RimWellTargetMapping::resetMinimumCellValuesToDefault()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellTargetMapping::onGenerateButtonClicked()
|
||||
{
|
||||
auto hasEclipseCaseEnsembleParent = firstAncestorOrThisOfType<RimEclipseCaseEnsemble>() != nullptr;
|
||||
auto hasGridEnsembleParent = firstAncestorOrThisOfType<RimReservoirGridEnsemble>() != nullptr;
|
||||
if ( hasEclipseCaseEnsembleParent )
|
||||
if ( firstAncestorOrThisOfType<RimReservoirGridEnsemble>() != nullptr )
|
||||
{
|
||||
generateEnsembleStatistics();
|
||||
}
|
||||
else if ( hasGridEnsembleParent )
|
||||
{
|
||||
// For RimReservoirGridEnsemble implement two variants, shared grid and individual grids. Individual grids variant will require more
|
||||
// work, and is not currently prioritized, so for now just show a warning if user tries to generate candidates for a
|
||||
// RimReservoirGridEnsemble
|
||||
//
|
||||
// See RicNewWellTargetMappingFeature::isCommandEnabled() for comment on future support for ensembles with varying geometry.
|
||||
}
|
||||
else if ( auto eclipseCase = firstCase() )
|
||||
{
|
||||
generateCandidates( eclipseCase );
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimNamedObject.h"
|
||||
|
||||
#include "cafAppEnum.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
@@ -34,7 +36,7 @@ class RimEclipseView;
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimWellTargetMapping : public caf::PdmObject
|
||||
class RimWellTargetMapping : public RimNamedObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
@@ -53,9 +55,11 @@ public:
|
||||
protected:
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override;
|
||||
void initAfterRead() override;
|
||||
|
||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void initAfterRead() override;
|
||||
|
||||
private:
|
||||
void generateCandidates( RimEclipseCase* eclipseCase, bool setTimeStepInView = true );
|
||||
@@ -90,6 +94,9 @@ private:
|
||||
caf::PdmField<double> m_permeability;
|
||||
caf::PdmField<double> m_transmissibility;
|
||||
|
||||
caf::PdmField<double> m_expandBoundingBoxXYPercent;
|
||||
caf::PdmField<double> m_expandBoundingBoxZPercent;
|
||||
|
||||
caf::PdmField<int> m_maxIterations;
|
||||
caf::PdmField<int> m_maxNumTargets;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "RiaEclipseUnitTools.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPorosityModel.h"
|
||||
#include "RiaPreferencesGrid.h"
|
||||
#include "RiaQStringFormatter.h"
|
||||
#include "RiaResultNames.h"
|
||||
#include "RiaWeightedMeanCalculator.h"
|
||||
@@ -364,27 +365,32 @@ RimRegularGridCase* RigWellTargetMapping::generateEnsembleCandidates( const std:
|
||||
VolumesType volumesType,
|
||||
VolumeResultType volumeResultType,
|
||||
const RigFloodingSettings& floodingSettings,
|
||||
const ClusteringLimits& limits )
|
||||
const ClusteringLimits& limits,
|
||||
double expandBoundingBoxXYPercent,
|
||||
double expandBoundingBoxZPercent )
|
||||
{
|
||||
RiaLogging::debug( "Generating ensemble statistics" );
|
||||
|
||||
caf::ProgressInfo progInfo( cases.size() * 2, "Generating ensemble statistics" );
|
||||
|
||||
for ( auto eclipseCase : cases )
|
||||
{
|
||||
auto task = progInfo.task( "Generating realization statistics.", 1 );
|
||||
|
||||
generateCandidates( eclipseCase, timeStepIdx, volumeType, volumesType, volumeResultType, floodingSettings, limits, false );
|
||||
}
|
||||
caf::ProgressInfo progInfo( cases.size(), "Generating ensemble statistics" );
|
||||
|
||||
cvf::BoundingBox boundingBox;
|
||||
for ( auto eclipseCase : cases )
|
||||
{
|
||||
cvf::BoundingBox bb =
|
||||
RigWellTargetMappingTools::computeBoundingBoxForResult( *eclipseCase, RigWellTargetMapping::wellTargetResultName(), timeStepIdx );
|
||||
boundingBox.add( bb );
|
||||
if ( eclipseCase->eclipseCaseData() != nullptr )
|
||||
{
|
||||
boundingBox.add( eclipseCase->activeCellsBoundingBox() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !boundingBox.isValid() )
|
||||
{
|
||||
RiaLogging::error( "Failed to compute valid bounding box for ensemble statistics. At least one view must be opened" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
boundingBox.expandPercent( expandBoundingBoxXYPercent, expandBoundingBoxZPercent );
|
||||
|
||||
RiaLogging::debug( QString( "Clusters bounding box min: [%1 %2 %3]" )
|
||||
.arg( boundingBox.min().x() )
|
||||
.arg( boundingBox.min().y() )
|
||||
@@ -414,13 +420,44 @@ RimRegularGridCase* RigWellTargetMapping::generateEnsembleCandidates( const std:
|
||||
resultNamesAndSamples["TOTAL_SFIPOIL"] = {};
|
||||
resultNamesAndSamples["TOTAL_SFIPGAS"] = {};
|
||||
|
||||
auto readerSettings = RiaPreferencesGrid::gridOnlyReaderSettings();
|
||||
readerSettings.onlyLoadActiveCells = true;
|
||||
|
||||
auto oldReaderType = RiaPreferencesGrid::current()->gridModelReaderOverride();
|
||||
RiaPreferencesGrid::current()->setGridModelReaderOverride( RiaDefines::GridModelReader::OPM_COMMON );
|
||||
|
||||
for ( auto eclipseCase : cases )
|
||||
{
|
||||
auto task = progInfo.task( "Accumulating results.", 1 );
|
||||
auto task = progInfo.task( "Generating realization statistics.", 1 );
|
||||
|
||||
RigWellTargetMappingTools::accumulateResultsForSingleCase( *eclipseCase, *targetCase, resultNamesAndSamples, occurrence, timeStepIdx );
|
||||
bool closeGrid = ( !eclipseCase->isReservoirCaseOpen() );
|
||||
|
||||
if ( closeGrid )
|
||||
{
|
||||
RiaLogging::debug( QString( "Opening grid for case: %1" ).arg( eclipseCase->gridFileName() ).toStdString() );
|
||||
}
|
||||
|
||||
auto oldReaderSettings = eclipseCase->readerSettings();
|
||||
if ( closeGrid )
|
||||
{
|
||||
eclipseCase->setReaderSettings( readerSettings );
|
||||
}
|
||||
|
||||
if ( eclipseCase->ensureReservoirCaseIsOpen() )
|
||||
{
|
||||
generateCandidates( eclipseCase, timeStepIdx, volumeType, volumesType, volumeResultType, floodingSettings, limits, false );
|
||||
RigWellTargetMappingTools::accumulateResultsForSingleCase( *eclipseCase, *targetCase, resultNamesAndSamples, occurrence, timeStepIdx );
|
||||
}
|
||||
if ( closeGrid )
|
||||
{
|
||||
eclipseCase->closeReservoirCase();
|
||||
eclipseCase->setReaderSettings( oldReaderSettings );
|
||||
RiaLogging::debug( QString( "Closing grid for case: %1" ).arg( eclipseCase->gridFileName() ).toStdString() );
|
||||
}
|
||||
}
|
||||
|
||||
RiaPreferencesGrid::current()->setGridModelReaderOverride( oldReaderType );
|
||||
|
||||
auto createFractionVector = []( const std::vector<int>& occurrence, int maxRealizationCount ) -> std::vector<double>
|
||||
{
|
||||
std::vector<double> fractions( occurrence.size() );
|
||||
|
||||
@@ -95,7 +95,9 @@ public:
|
||||
VolumesType volumesType,
|
||||
VolumeResultType volumeResultType,
|
||||
const RigFloodingSettings& floodingSettings,
|
||||
const ClusteringLimits& limits );
|
||||
const ClusteringLimits& limits,
|
||||
double expandBoundingBoxXYPercent,
|
||||
double expandBoundingBoxZPercent );
|
||||
|
||||
static QString wellTargetResultName();
|
||||
};
|
||||
|
||||
@@ -474,6 +474,7 @@ std::vector<ReservoirCellIndex> RigWellTargetMappingTools::findCandidates( RimEc
|
||||
double transmissibility = data.transmissibilityNNC->at( nncResultIdx );
|
||||
|
||||
ActiveCellIndex otherResultIndex = resultsData->activeCellInfo()->cellResultIndex( otherCellIdx );
|
||||
if ( otherResultIndex.value() == cvf::UNDEFINED_SIZE_T ) continue;
|
||||
|
||||
double permeability = data.permeabilityX[otherResultIndex.value()];
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace cvf {
|
||||
namespace cvf
|
||||
{
|
||||
|
||||
|
||||
|
||||
@@ -68,8 +69,7 @@ namespace cvf {
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
BoundingBox::BoundingBox(const Vec3d& min, const Vec3d& max)
|
||||
: m_min(min), m_max(max)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -77,8 +77,7 @@ namespace cvf {
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
BoundingBox::BoundingBox(const Vec3f& min, const Vec3f& max)
|
||||
: m_min(min), m_max(max)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -87,8 +86,7 @@ namespace cvf {
|
||||
BoundingBox::BoundingBox(const BoundingBox& other)
|
||||
: m_min(other.m_min),
|
||||
m_max(other.m_max)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -359,14 +357,15 @@ namespace cvf {
|
||||
///
|
||||
/// If a bounding box is expanded by 10%, the bounding box's size will increase by 5% in each direction
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void BoundingBox::expandPercent(double percent)
|
||||
void BoundingBox::expandPercent(double percentXY, double percentZ)
|
||||
{
|
||||
const auto ext = extent();
|
||||
const double factor = percent / 100.0;
|
||||
const double factorXY = percentXY / 100.0;
|
||||
const double factorZ = percentZ / 100.0;
|
||||
|
||||
const double xHalf = (ext.x() / 2) * factor;
|
||||
const double yHalf = (ext.y() / 2) * factor;
|
||||
const double zHalf = (ext.z() / 2) * factor;
|
||||
const double xHalf = (ext.x() / 2) * factorXY;
|
||||
const double yHalf = (ext.y() / 2) * factorXY;
|
||||
const double zHalf = (ext.z() / 2) * factorZ;
|
||||
|
||||
m_min.x() -= xHalf;
|
||||
m_min.y() -= yHalf;
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
#include "cvfMatrix4.h"
|
||||
#include "cvfString.h"
|
||||
|
||||
namespace cvf {
|
||||
namespace cvf
|
||||
{
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
@@ -83,7 +84,7 @@ namespace cvf {
|
||||
void cornerVertices(Vec3d corners[8]) const;
|
||||
|
||||
void expand(double amount);
|
||||
void expandPercent(double percent);
|
||||
void expandPercent(double percentXY, double percentZ);
|
||||
void transform(const Mat4d& matrix);
|
||||
const BoundingBox getTransformed(const Mat4d& matrix) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user