mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-13 09:37:29 -06:00
Merge identical nodes when grid geometry is finalized and remap cell corner indices. Partial shared node indices in the quad overlap calculation are now resolved geometrically, keeping fault and NNC geometry unchanged. Log the node count reduction with thousand grouping and the removed share of nodes.
1540 lines
59 KiB
C++
1540 lines
59 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2011- Statoil ASA
|
|
// Copyright (C) 2013- Ceetron Solutions AS
|
|
// Copyright (C) 2011-2012 Ceetron AS
|
|
//
|
|
// 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 "RimEclipseCase.h"
|
|
|
|
#include "RiaApplication.h"
|
|
#include "RiaColorTables.h"
|
|
#include "RiaDefines.h"
|
|
#include "RiaFieldHandleTools.h"
|
|
#include "RiaLogging.h"
|
|
#include "RiaPreferencesGrid.h"
|
|
#include "RiaQDateTimeTools.h"
|
|
#include "RiaResultNames.h"
|
|
#include "RiaStdStringTools.h"
|
|
|
|
#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h"
|
|
|
|
#include "RicfCommandObject.h"
|
|
#include "RifInputPropertyLoader.h"
|
|
|
|
#include "RigActiveCellInfo.h"
|
|
#include "RigCaseCellResultsData.h"
|
|
#include "RigEclipseCaseData.h"
|
|
#include "RigGridManager.h"
|
|
#include "RigMainGrid.h"
|
|
#include "RigNNCData.h"
|
|
#include "RigVirtualPerforationTransmissibilities.h"
|
|
#include "Well/RigSimWellData.h"
|
|
#include "Well/RigWellResultFrame.h"
|
|
|
|
#include "ContourMap/RimEclipseContourMapView.h"
|
|
#include "ContourMap/RimEclipseContourMapViewCollection.h"
|
|
#include "Formations/RimFormationNames.h"
|
|
#include "Rim2dIntersectionViewCollection.h"
|
|
#include "RimCaseCollection.h"
|
|
#include "RimCellEdgeColors.h"
|
|
#include "RimDataAnalyticsCollection.h"
|
|
#include "RimDataFilterCollection.h"
|
|
#include "RimEclipseCellColors.h"
|
|
#include "RimEclipseInputProperty.h"
|
|
#include "RimEclipseInputPropertyCollection.h"
|
|
#include "RimEclipsePropertyFilter.h"
|
|
#include "RimEclipsePropertyFilterCollection.h"
|
|
#include "RimEclipseResultAddress.h"
|
|
#include "RimEclipseResultAddressCollection.h"
|
|
#include "RimEclipseStatisticsCase.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimEclipseViewCollection.h"
|
|
#include "RimFaultDistance.h"
|
|
#include "RimFaultDistanceCollection.h"
|
|
#include "RimFaultInViewCollection.h"
|
|
#include "RimGenericViewCollection.h"
|
|
#include "RimGridCollection.h"
|
|
#include "RimIntersectionCollection.h"
|
|
#include "RimMainPlotCollection.h"
|
|
#include "RimOilField.h"
|
|
#include "RimPerforationCollection.h"
|
|
#include "RimProject.h"
|
|
#include "RimReloadCaseTools.h"
|
|
#include "RimReservoirCellResultsStorage.h"
|
|
#include "RimReservoirGridEnsemble.h"
|
|
#include "RimReservoirGridEnsembleBase.h"
|
|
#include "RimResultNameAlias.h"
|
|
#include "RimStimPlanColors.h"
|
|
#include "RimWellLogPlotCollection.h"
|
|
#include "RimWellPath.h"
|
|
#include "RimWellPathCollection.h"
|
|
#include "RimWellTargetMapping.h"
|
|
|
|
#include "cafCmdFeatureMenuBuilder.h"
|
|
#include "cafPdmDocument.h"
|
|
#include "cafPdmFieldScriptingCapability.h"
|
|
#include "cafPdmObjectScriptingCapability.h"
|
|
#include "cafPdmUiTableViewEditor.h"
|
|
#include "cafPdmUiTreeOrdering.h"
|
|
#include "cafProgressInfo.h"
|
|
|
|
#include "cafUtils.h"
|
|
#include <QFileInfo>
|
|
|
|
#include <format>
|
|
|
|
CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimEclipseCase, "RimReservoir" );
|
|
|
|
//------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseCase::RimEclipseCase()
|
|
{
|
|
CAF_PDM_InitScriptableObjectWithNameAndComment( "EclipseCase", ":/Case48x48.png", "", "", "Reservoir", "Abstract base class for Eclipse Cases" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_reservoirViews_OBSOLETE, "ReservoirViews", "Views", "", "", "", "All Eclipse Views in the case" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_matrixModelResults, "MatrixModelResults", "" );
|
|
CAF_PDM_InitFieldNoDefault( &m_fractureModelResults, "FractureModelResults", "" );
|
|
|
|
CAF_PDM_InitField( &m_flipXAxis, "FlipXAxis", false, "Flip X Axis" );
|
|
CAF_PDM_InitField( &m_flipYAxis, "FlipYAxis", false, "Flip Y Axis" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_filesContainingFaults, "CachedFileNamesContainingFaults", "" );
|
|
m_filesContainingFaults.uiCapability()->setUiHidden( true );
|
|
// Caching of file names causes issues when using the project file as template, do not save to disk
|
|
// https://github.com/OPM/ResInsight/issues/7308
|
|
m_filesContainingFaults.xmlCapability()->disableIO();
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_contourMapCollection_OBSOLETE, "ContourMaps", "2d Contour Maps" );
|
|
m_contourMapCollection_OBSOLETE = new RimEclipseContourMapViewCollection;
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_inputPropertyCollection, "InputPropertyCollection", "" );
|
|
m_inputPropertyCollection = new RimEclipseInputPropertyCollection;
|
|
m_inputPropertyCollection->parentField()->uiCapability()->setUiTreeHidden( true );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_resultAddressCollections, "ResultAddressCollections", "Result Addresses" );
|
|
m_resultAddressCollections.uiCapability()->setUiHidden( true );
|
|
m_resultAddressCollections.xmlCapability()->disableIO();
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_viewCollection, "ViewCollection", "Views" );
|
|
m_viewCollection = new RimEclipseViewCollection;
|
|
|
|
CAF_PDM_InitScriptableFieldNoDefault( &m_dataFilterCollection, "DataFilterCollection", "Data Filters" );
|
|
m_dataFilterCollection = new RimDataFilterCollection;
|
|
m_dataFilterCollection->setCase( this );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_dataAnalyticsCollection, "DataAnalyticsCollection", "Data Analytics" );
|
|
m_dataAnalyticsCollection = new RimDataAnalyticsCollection;
|
|
|
|
// Obsolete: well target mappings used to be stored directly on the case. They are migrated into
|
|
// the Data Analytics collection in initAfterRead().
|
|
CAF_PDM_InitFieldNoDefault( &m_wellTargetMappings_OBSOLETE, "WellTargetMappings", "Well Target Mappings" );
|
|
m_wellTargetMappings_OBSOLETE.xmlCapability()->setIOWritable( false );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_resultAliasList, "ResultAliasNames", "Result Name Aliases" );
|
|
m_resultAliasList.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() );
|
|
m_resultAliasList.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::HIDDEN );
|
|
|
|
// Init
|
|
|
|
m_matrixModelResults = new RimReservoirCellResultsStorage;
|
|
m_matrixModelResults.uiCapability()->setUiTreeChildrenHidden( true );
|
|
|
|
m_fractureModelResults = new RimReservoirCellResultsStorage;
|
|
m_fractureModelResults.uiCapability()->setUiTreeChildrenHidden( true );
|
|
setReservoirData( nullptr );
|
|
|
|
m_readerSettings = RiaPreferencesGrid::current()->readerSettings();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseCase::~RimEclipseCase()
|
|
{
|
|
delete m_matrixModelResults();
|
|
delete m_fractureModelResults();
|
|
delete m_inputPropertyCollection;
|
|
delete m_viewCollection;
|
|
delete m_dataFilterCollection;
|
|
|
|
RimProject* project = RimProject::current();
|
|
if ( project )
|
|
{
|
|
if ( project->mainPlotCollection() )
|
|
{
|
|
RimWellLogPlotCollection* plotCollection = project->mainPlotCollection()->wellLogPlotCollection();
|
|
if ( plotCollection )
|
|
{
|
|
plotCollection->removeExtractors( eclipseCaseData() );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( eclipseCaseData() )
|
|
{
|
|
// At this point, we assume that memory should be released
|
|
CAF_ASSERT( eclipseCaseData()->refCount() == 1 );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RigEclipseCaseData* RimEclipseCase::eclipseCaseData()
|
|
{
|
|
return m_rigEclipseCase.p();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigEclipseCaseData* RimEclipseCase::eclipseCaseData() const
|
|
{
|
|
return m_rigEclipseCase.p();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::ensureDeckIsParsedForEquilData()
|
|
{
|
|
if ( m_rigEclipseCase.notNull() )
|
|
{
|
|
QString dataDeckFile;
|
|
{
|
|
QFileInfo fi( gridFileName() );
|
|
|
|
dataDeckFile = caf::Utils::constructFullFileName( fi.absolutePath(), fi.baseName(), ".DATA" );
|
|
}
|
|
|
|
m_rigEclipseCase->ensureDeckIsParsedForEquilData( dataDeckFile, m_readerSettings.includeFileAbsolutePathPrefix );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Color3f RimEclipseCase::defaultWellColor( const QString& wellName )
|
|
{
|
|
if ( m_wellToColorMap.empty() )
|
|
{
|
|
const caf::ColorTable& colorTable = RiaColorTables::wellsPaletteColors();
|
|
cvf::Color3ubArray wellColors = colorTable.color3ubArray();
|
|
cvf::Color3ubArray interpolatedWellColors = wellColors;
|
|
|
|
const cvf::Collection<RigSimWellData>& simWellData = eclipseCaseData()->wellResults();
|
|
if ( simWellData.size() > 1 )
|
|
{
|
|
interpolatedWellColors = caf::ColorTable::interpolateColorArray( wellColors, simWellData.size() );
|
|
}
|
|
|
|
for ( size_t wIdx = 0; wIdx < simWellData.size(); ++wIdx )
|
|
{
|
|
m_wellToColorMap[simWellData[wIdx]->m_wellName] = cvf::Color3f::BLACK;
|
|
}
|
|
|
|
size_t wIdx = 0;
|
|
for ( auto& wNameColorPair : m_wellToColorMap )
|
|
{
|
|
wNameColorPair.second = cvf::Color3f( interpolatedWellColors[wIdx] );
|
|
|
|
++wIdx;
|
|
}
|
|
}
|
|
|
|
auto nmColor = m_wellToColorMap.find( wellName );
|
|
if ( nmColor != m_wellToColorMap.end() )
|
|
{
|
|
return nmColor->second;
|
|
}
|
|
else
|
|
{
|
|
return cvf::Color3f::LIGHT_GRAY;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigMainGrid* RimEclipseCase::mainGrid() const
|
|
{
|
|
if ( eclipseCaseData() )
|
|
{
|
|
return eclipseCaseData()->mainGrid();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::isGridSizeEqualTo( const RimEclipseCase* otherCase ) const
|
|
{
|
|
if ( !mainGrid() || !otherCase || !otherCase->mainGrid() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return RigGridManager::isMainGridDimensionsEqual( mainGrid(), otherCase->mainGrid() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::initAfterRead()
|
|
{
|
|
RimCase::initAfterRead();
|
|
|
|
// Move views to view collection.
|
|
RimEclipseViewCollection* viewColl = viewCollection();
|
|
for ( RimEclipseView* riv : m_reservoirViews_OBSOLETE.childrenByType() )
|
|
{
|
|
CAF_ASSERT( riv );
|
|
riv->setEclipseCase( this );
|
|
m_reservoirViews_OBSOLETE.removeChild( riv );
|
|
viewColl->addView( riv );
|
|
}
|
|
|
|
m_reservoirViews_OBSOLETE.clearWithoutDelete();
|
|
|
|
// Move contour maps
|
|
auto mapViewColl = contourMapCollection();
|
|
for ( RimEclipseContourMapView* contourMap : m_contourMapCollection_OBSOLETE->views() )
|
|
{
|
|
contourMap->setEclipseCase( this );
|
|
m_contourMapCollection_OBSOLETE->removeChild( contourMap );
|
|
mapViewColl->addView( contourMap );
|
|
}
|
|
|
|
m_contourMapCollection_OBSOLETE->clearWithoutDelete();
|
|
|
|
// Move case-level well target mappings into the Data Analytics collection.
|
|
for ( RimWellTargetMapping* wellTargetMapping : m_wellTargetMappings_OBSOLETE.childrenByType() )
|
|
{
|
|
m_wellTargetMappings_OBSOLETE.removeChild( wellTargetMapping );
|
|
m_dataAnalyticsCollection->addWellTargetMapping( wellTargetMapping );
|
|
}
|
|
m_wellTargetMappings_OBSOLETE.clearWithoutDelete();
|
|
|
|
m_dataFilterCollection()->setCase( this );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::syncResultAliases()
|
|
{
|
|
if ( auto ecData = eclipseCaseData() )
|
|
{
|
|
if ( auto results = ecData->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) )
|
|
{
|
|
results->clearAllResultAliases();
|
|
for ( const auto& alias : m_resultAliasList )
|
|
{
|
|
results->addResultAlias( alias->resultName(), alias->aliasName() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::addResultAlias( const QString& resultName, const QString& aliasName )
|
|
{
|
|
if ( resultName.trimmed().isEmpty() ) return;
|
|
if ( aliasName.trimmed().isEmpty() ) return;
|
|
|
|
auto resultAlias = new RimResultNameAlias();
|
|
resultAlias->setResultNameAndAlias( resultName, aliasName );
|
|
m_resultAliasList.push_back( resultAlias );
|
|
syncResultAliases();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::clearResultAliases()
|
|
{
|
|
m_resultAliasList.deleteChildren();
|
|
syncResultAliases();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseView* RimEclipseCase::createAndAddReservoirView( bool useGlobalViewCollection )
|
|
{
|
|
if ( useGlobalViewCollection )
|
|
{
|
|
return createAndAddReservoirView( globalViewCollection() );
|
|
}
|
|
|
|
return createAndAddReservoirView( viewCollection() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseView* RimEclipseCase::createAndAddReservoirView( RimEclipseViewCollection* viewColl )
|
|
{
|
|
if ( !viewColl ) return nullptr;
|
|
|
|
return viewColl->addView( this );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseView* RimEclipseCase::createAndAddReservoirView( RimGenericViewCollection* viewColl )
|
|
{
|
|
if ( !viewColl ) return nullptr;
|
|
|
|
return viewColl->addView( this );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseView* RimEclipseCase::createCopyAndAddView( const RimEclipseView* sourceView )
|
|
{
|
|
CAF_ASSERT( sourceView );
|
|
|
|
auto rimEclipseView = sourceView->copyObject<RimEclipseView>();
|
|
CAF_ASSERT( rimEclipseView );
|
|
rimEclipseView->resetDockWindowId();
|
|
rimEclipseView->setEclipseCase( this );
|
|
|
|
caf::PdmDocument::updateUiIconStateRecursively( rimEclipseView );
|
|
|
|
RimEclipseViewCollection* viewColl = viewCollection();
|
|
if ( !viewColl ) return nullptr;
|
|
|
|
viewColl->addView( rimEclipseView );
|
|
|
|
rimEclipseView->initAfterInsert();
|
|
|
|
return rimEclipseView;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigVirtualPerforationTransmissibilities* RimEclipseCase::computeAndGetVirtualPerforationTransmissibilities()
|
|
{
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( !rigEclipseCase ) return nullptr;
|
|
|
|
if ( rigEclipseCase->virtualPerforationTransmissibilities() == nullptr )
|
|
{
|
|
cvf::ref<RigVirtualPerforationTransmissibilities> perfTrans = new RigVirtualPerforationTransmissibilities;
|
|
|
|
std::vector<RimWellPath*> visibleWellPaths;
|
|
bool anyPerforationsPresent = false;
|
|
{
|
|
RimProject* proj = RimProject::current();
|
|
std::vector<RimWellPath*> wellPaths = proj->allWellPaths();
|
|
for ( auto w : wellPaths )
|
|
{
|
|
if ( w->showWellPath() )
|
|
{
|
|
visibleWellPaths.push_back( w );
|
|
|
|
if ( !w->perforationIntervalCollection()->perforations().empty() )
|
|
{
|
|
anyPerforationsPresent = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( auto w : visibleWellPaths )
|
|
{
|
|
std::vector<RigCompletionData> staticCompletionData =
|
|
RicWellPathExportCompletionDataFeatureImpl::computeStaticCompletionsForWellPath( w, this );
|
|
|
|
if ( anyPerforationsPresent )
|
|
{
|
|
std::vector<std::vector<RigCompletionData>> allCompletionData;
|
|
|
|
size_t maxIndexCount = 1;
|
|
if ( !timeStepDates().empty() )
|
|
{
|
|
maxIndexCount = timeStepDates().size();
|
|
}
|
|
for ( size_t i = 0; i < maxIndexCount; i++ )
|
|
{
|
|
std::vector<RigCompletionData> dynamicCompletionDataOneTimeStep =
|
|
RicWellPathExportCompletionDataFeatureImpl::computeDynamicCompletionsForWellPath( w, this, i );
|
|
|
|
std::copy( staticCompletionData.begin(), staticCompletionData.end(), std::back_inserter( dynamicCompletionDataOneTimeStep ) );
|
|
|
|
allCompletionData.push_back( dynamicCompletionDataOneTimeStep );
|
|
}
|
|
|
|
perfTrans->setCompletionDataForWellPath( w, allCompletionData );
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::vector<RigCompletionData>> allCompletionData;
|
|
allCompletionData.push_back( staticCompletionData );
|
|
|
|
perfTrans->setCompletionDataForWellPath( w, allCompletionData );
|
|
}
|
|
}
|
|
|
|
for ( const auto& wellRes : rigEclipseCase->wellResults() )
|
|
{
|
|
std::vector<std::vector<RigCompletionData>> completionsPerTimeStep;
|
|
for ( size_t i = 0; i < timeStepDates().size(); i++ )
|
|
{
|
|
std::vector<RigCompletionData> completionData;
|
|
|
|
if ( wellRes->hasWellResult( i ) )
|
|
{
|
|
for ( const auto& wellResultBranch : wellRes->wellResultFrame( i )->wellResultBranches() )
|
|
{
|
|
for ( const auto& r : wellResultBranch.branchResultPoints() )
|
|
{
|
|
if ( r.isCell() )
|
|
{
|
|
RigCompletionData compData( wellRes->m_wellName,
|
|
RigCompletionDataGridCell( r.cellIndex(), rigEclipseCase->mainGrid() ),
|
|
0 );
|
|
compData.setTransmissibility( r.connectionFactor() );
|
|
|
|
completionData.push_back( compData );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
completionsPerTimeStep.push_back( completionData );
|
|
|
|
perfTrans->setCompletionDataForSimWell( wellRes.p(), completionsPerTimeStep );
|
|
}
|
|
}
|
|
|
|
rigEclipseCase->setVirtualPerforationTransmissibilities( perfTrans.p() );
|
|
}
|
|
|
|
return rigEclipseCase->virtualPerforationTransmissibilities();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
{
|
|
RimCase::fieldChangedByUi( changedField, oldValue, newValue );
|
|
if ( changedField == &m_releaseResultMemory )
|
|
{
|
|
RimReloadCaseTools::reloadEclipseGrid( this );
|
|
|
|
m_releaseResultMemory = oldValue.toBool();
|
|
}
|
|
else if ( changedField == &m_flipXAxis || changedField == &m_flipYAxis )
|
|
{
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase )
|
|
{
|
|
rigEclipseCase->mainGrid()->setFlipAxis( m_flipXAxis, m_flipYAxis );
|
|
|
|
computeCachedData();
|
|
|
|
for ( RimEclipseView* reservoirView : reservoirViews() )
|
|
{
|
|
reservoirView->scheduleReservoirGridGeometryRegen();
|
|
reservoirView->scheduleSimWellGeometryRegen();
|
|
reservoirView->createDisplayModelAndRedraw();
|
|
}
|
|
}
|
|
}
|
|
else if ( changedField == &m_activeFormationNames )
|
|
{
|
|
updateFormationNamesData();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
|
|
{
|
|
if ( changedChildField == &m_resultAliasList )
|
|
{
|
|
syncResultAliases();
|
|
for ( auto resView : reservoirViews() )
|
|
{
|
|
resView->scheduleCreateDisplayModelAndRedraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the formation names data for the case, falling back to the parent ensemble's
|
|
/// shared formation names if the case has none of its own.
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigFormationNames* RimEclipseCase::effectiveFormationNames() const
|
|
{
|
|
auto resolve = [&]( RimFormationNames* rim ) -> const RigFormationNames* { return rim ? rim->formationNamesData() : nullptr; };
|
|
|
|
if ( auto* formationNames = resolve( activeFormationNames() ) ) return formationNames;
|
|
|
|
if ( auto* coll = const_cast<RimEclipseCase*>( this )->parentCaseCollection() )
|
|
{
|
|
if ( auto* ensembleBase = coll->parentGridEnsembleBase() )
|
|
{
|
|
return resolve( ensembleBase->activeFormationNames() );
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::updateFormationNamesData()
|
|
{
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase )
|
|
{
|
|
auto* formationNames = effectiveFormationNames();
|
|
rigEclipseCase->setActiveFormationNames( formationNames );
|
|
|
|
// Update plots based on formations
|
|
RimMainPlotCollection::current()->updatePlotsWithFormations();
|
|
|
|
std::vector<Rim3dView*> views = this->views();
|
|
for ( Rim3dView* view : views )
|
|
{
|
|
RimEclipseView* eclView = dynamic_cast<RimEclipseView*>( view );
|
|
|
|
if ( eclView && eclView->isUsingFormationNames() )
|
|
{
|
|
if ( !formationNames )
|
|
{
|
|
if ( eclView->cellResult()->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
|
|
{
|
|
eclView->cellResult()->setResultVariable( RiaResultNames::undefinedResultName() );
|
|
eclView->cellResult()->updateConnectedEditors();
|
|
}
|
|
|
|
RimEclipsePropertyFilterCollection* eclFilColl = eclView->eclipsePropertyFilterCollection();
|
|
for ( RimEclipsePropertyFilter* propFilter : eclFilColl->propertyFilters() )
|
|
{
|
|
if ( propFilter->resultDefinition()->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
|
|
{
|
|
propFilter->resultDefinition()->setResultVariable( RiaResultNames::undefinedResultName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
RimEclipsePropertyFilterCollection* eclFilColl = eclView->eclipsePropertyFilterCollection();
|
|
for ( RimEclipsePropertyFilter* propFilter : eclFilColl->propertyFilters() )
|
|
{
|
|
if ( propFilter->resultDefinition()->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
|
|
{
|
|
propFilter->setToDefaultValues();
|
|
propFilter->updateConnectedEditors();
|
|
}
|
|
}
|
|
|
|
view->scheduleGeometryRegen( PROPERTY_FILTERED );
|
|
view->scheduleCreateDisplayModelAndRedraw();
|
|
eclView->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::resultAliasUiOrdering( caf::PdmUiOrdering& uiOrdering )
|
|
{
|
|
auto aGrp = uiOrdering.addNewGroup( "Result Name Aliases" );
|
|
aGrp->setCollapsedByDefault();
|
|
aGrp->add( &m_resultAliasList );
|
|
|
|
aGrp->addNewButton( "Add Result Alias",
|
|
[this]()
|
|
{
|
|
m_resultAliasList.push_back( new RimResultNameAlias() );
|
|
updateConnectedEditors();
|
|
} );
|
|
aGrp->addNewButton( "Reset Result Aliases",
|
|
[this]()
|
|
{
|
|
m_resultAliasList.deleteChildren();
|
|
syncResultAliases();
|
|
updateConnectedEditors();
|
|
for ( auto resView : reservoirViews() )
|
|
{
|
|
resView->scheduleCreateDisplayModelAndRedraw();
|
|
}
|
|
},
|
|
{ .newRow = false, .totalColumnSpan = 1 } );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
|
|
{
|
|
if ( uiConfigName == "MainWindow.ProjectTree" )
|
|
{
|
|
if ( m_dataAnalyticsCollection() && !m_dataAnalyticsCollection()->isEmpty() )
|
|
{
|
|
uiTreeOrdering.add( m_dataAnalyticsCollection() );
|
|
}
|
|
|
|
for ( auto view : m_viewCollection->views() )
|
|
{
|
|
uiTreeOrdering.add( view );
|
|
}
|
|
|
|
// For a case in a grid ensemble, the 2D intersection views are displayed as a child of the ensemble, as the
|
|
// 3D views are located in the ensemble and not in the case
|
|
if ( !m_2dIntersectionViewCollection->views().empty() && !firstAncestorOfType<RimReservoirGridEnsemble>() )
|
|
{
|
|
uiTreeOrdering.add( &m_2dIntersectionViewCollection );
|
|
}
|
|
|
|
if ( m_dataFilterCollection() && m_dataFilterCollection()->shouldBeVisibleInTree() )
|
|
{
|
|
uiTreeOrdering.add( m_dataFilterCollection() );
|
|
}
|
|
}
|
|
else if ( uiConfigName == "MainWindow.DataSources" )
|
|
{
|
|
if ( m_resultAddressCollections.empty() ) buildResultChildNodes();
|
|
uiTreeOrdering.add( &m_resultAddressCollections );
|
|
}
|
|
|
|
uiTreeOrdering.skipRemainingChildren( true );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Expose the case-level data-filter creation commands directly on the case node. The "Data Filters"
|
|
/// collection node is hidden while empty, so this lets the user create the first filter from here.
|
|
/// Delegates to RimDataFilterCollection::appendMenuItems, wrapped in a single "Data Filters" submenu.
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
|
|
{
|
|
menuBuilder.subMenuStart( "Data Filters", QIcon( ":/CellFilter.png" ) );
|
|
m_dataFilterCollection->appendMenuItems( menuBuilder );
|
|
menuBuilder.subMenuEnd();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::buildResultChildNodes()
|
|
{
|
|
m_resultAddressCollections.deleteChildren();
|
|
|
|
auto cellResultData = results( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
|
if ( !cellResultData ) return;
|
|
|
|
std::vector<RiaDefines::ResultCatType> resultTypes = { RiaDefines::ResultCatType::STATIC_NATIVE,
|
|
RiaDefines::ResultCatType::DYNAMIC_NATIVE,
|
|
RiaDefines::ResultCatType::INPUT_PROPERTY,
|
|
RiaDefines::ResultCatType::GENERATED };
|
|
for ( auto resultType : resultTypes )
|
|
{
|
|
auto resultAddressCollection = new RimEclipseResultAddressCollection;
|
|
resultAddressCollection->setResultType( resultType );
|
|
QString name = caf::AppEnum<RiaDefines::ResultCatType>::uiText( resultType );
|
|
resultAddressCollection->setName( name );
|
|
|
|
QStringList resultNames = cellResultData->resultNames( resultType );
|
|
for ( auto resultName : resultNames )
|
|
{
|
|
resultAddressCollection->addAddress( resultName, resultType, this );
|
|
}
|
|
|
|
m_resultAddressCollections.push_back( resultAddressCollection );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::computeCachedData()
|
|
{
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase )
|
|
{
|
|
caf::ProgressInfo pInf( 32, "" );
|
|
|
|
{
|
|
auto task = pInf.task( "Removing Duplicate Grid Nodes", 2 );
|
|
|
|
RigMainGrid* mainGrid = rigEclipseCase->mainGrid();
|
|
const size_t oldNodeCount = mainGrid->nodes().size();
|
|
const size_t removedNodes = mainGrid->removeDuplicateNodes();
|
|
if ( removedNodes > 0 )
|
|
{
|
|
const double removedPercentage = 100.0 * static_cast<double>( removedNodes ) / static_cast<double>( oldNodeCount );
|
|
RiaLogging::debug( std::format( "Removed duplicate grid nodes: {} -> {} nodes ({} removed, {:.1f} %)",
|
|
RiaStdStringTools::formatThousandGrouping( static_cast<int64_t>( oldNodeCount ) ),
|
|
RiaStdStringTools::formatThousandGrouping( static_cast<int64_t>( mainGrid->nodes().size() ) ),
|
|
RiaStdStringTools::formatThousandGrouping( static_cast<int64_t>( removedNodes ) ),
|
|
removedPercentage ) );
|
|
}
|
|
}
|
|
|
|
{
|
|
// NB! Call computeCachedData() first, as this function also computes the bounding box used in other functions, specifically
|
|
// computeActiveCellsBoundingBox()
|
|
|
|
auto task = pInf.task( "Calculating Cell Search Tree", 10 );
|
|
|
|
std::string aabbTreeInfo;
|
|
rigEclipseCase->mainGrid()->computeCachedData( &aabbTreeInfo );
|
|
|
|
// Debug output of the content of the AABB tree
|
|
// RiaLogging::debug( QString::fromStdString( aabbTreeInfo ) );
|
|
}
|
|
|
|
{
|
|
auto task = pInf.task( "", 1 );
|
|
computeActiveCellsBoundingBox();
|
|
}
|
|
|
|
{
|
|
auto task = pInf.task( "Calculating faults", 17 );
|
|
|
|
ensureFaultDataIsComputed();
|
|
}
|
|
|
|
{
|
|
auto task = pInf.task( "Calculating Formation Names Result", 2 );
|
|
|
|
rigEclipseCase->setActiveFormationNames( effectiveFormationNames() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimCaseCollection* RimEclipseCase::parentCaseCollection()
|
|
{
|
|
auto* field = parentField();
|
|
if ( !field ) return nullptr;
|
|
return dynamic_cast<RimCaseCollection*>( field->ownerObject() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseContourMapViewCollection* RimEclipseCase::contourMapCollection() const
|
|
{
|
|
RimProject* project = RimProject::current();
|
|
if ( !project ) return nullptr;
|
|
|
|
RimOilField* oilField = project->activeOilField();
|
|
if ( !oilField ) return nullptr;
|
|
|
|
return oilField->eclipseContourMapCollection();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseInputPropertyCollection* RimEclipseCase::inputPropertyCollection() const
|
|
{
|
|
return m_inputPropertyCollection();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimDataFilterCollection* RimEclipseCase::dataFilterCollection() const
|
|
{
|
|
return m_dataFilterCollection();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QString> RimEclipseCase::additionalFiles() const
|
|
{
|
|
std::vector<QString> additionalFiles;
|
|
for ( const RimEclipseInputProperty* inputProperty : m_inputPropertyCollection()->items() )
|
|
{
|
|
if ( inputProperty->fileName == gridFileName() ) continue;
|
|
|
|
additionalFiles.push_back( inputProperty->fileName().path() );
|
|
}
|
|
|
|
return additionalFiles;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Loads input property data from the gridFile and additional files
|
|
/// Creates new InputProperties if necessary, and flags the unused ones as obsolete
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::loadAndSynchronizeInputProperties( bool importGridOrFaultData )
|
|
{
|
|
// Make sure we actually have reservoir data
|
|
|
|
if ( !eclipseCaseData() || !eclipseCaseData()->mainGrid() || ( eclipseCaseData()->mainGrid()->cellCount() == 0 ) ) return;
|
|
|
|
RifInputPropertyLoader::loadAndSynchronizeInputProperties( inputPropertyCollection(),
|
|
eclipseCaseData(),
|
|
additionalFiles(),
|
|
importGridOrFaultData );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::ensureFaultDataIsComputed()
|
|
{
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase )
|
|
{
|
|
if ( m_readerSettings.importFaults )
|
|
{
|
|
RigActiveCellInfo* actCellInfo = rigEclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
|
rigEclipseCase->mainGrid()->calculateFaults( actCellInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::ensureNncDataIsComputed()
|
|
{
|
|
bool computedData = false;
|
|
RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase && rigEclipseCase->mainGrid() )
|
|
{
|
|
computedData = rigEclipseCase->mainGrid()->nncData()->ensureAllConnectionDataIsProcessed();
|
|
}
|
|
|
|
return computedData;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::createDisplayModelAndUpdateAllViews()
|
|
{
|
|
for ( const auto& v : views() )
|
|
{
|
|
RimEclipseView* eclipseView = dynamic_cast<RimEclipseView*>( v );
|
|
if ( eclipseView )
|
|
{
|
|
eclipseView->scheduleReservoirGridGeometryRegen();
|
|
}
|
|
|
|
v->loadDataAndUpdate();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::computeActiveCellsBoundingBox()
|
|
{
|
|
if ( !eclipseCaseData() ) return;
|
|
|
|
bool useOptimizedVersion = true;
|
|
|
|
const auto gridPref = RiaPreferencesGrid::current();
|
|
if ( ( gridPref != nullptr ) && ( gridPref->gridModelReader() == RiaDefines::GridModelReader::OPM_COMMON ) )
|
|
{
|
|
useOptimizedVersion = !gridPref->onlyLoadActiveCells();
|
|
}
|
|
|
|
if ( auto proj = RimProject::current() )
|
|
{
|
|
if ( proj->isProjectFileVersionEqualOrOlderThan( "2023.12.0" ) )
|
|
{
|
|
useOptimizedVersion = false;
|
|
}
|
|
}
|
|
|
|
eclipseCaseData()->computeActiveCellBoundingBoxes( useOptimizedVersion );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::setReservoirData( RigEclipseCaseData* eclipseCase )
|
|
{
|
|
m_rigEclipseCase = eclipseCase;
|
|
if ( eclipseCaseData() )
|
|
{
|
|
m_fractureModelResults()->setCellResults( eclipseCaseData()->results( RiaDefines::PorosityModelType::FRACTURE_MODEL ) );
|
|
m_matrixModelResults()->setCellResults( eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) );
|
|
syncResultAliases();
|
|
}
|
|
else
|
|
{
|
|
m_fractureModelResults()->setCellResults( nullptr );
|
|
m_matrixModelResults()->setCellResults( nullptr );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::createTimeStepFormatString()
|
|
{
|
|
std::vector<QDateTime> timeStepDates = this->timeStepDates();
|
|
|
|
m_timeStepFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates( timeStepDates );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::BoundingBox RimEclipseCase::reservoirBoundingBox()
|
|
{
|
|
return activeCellsBoundingBox();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::BoundingBox RimEclipseCase::activeCellsBoundingBox() const
|
|
{
|
|
if ( m_rigEclipseCase.notNull() && m_rigEclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ) )
|
|
{
|
|
return m_rigEclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL )->geometryBoundingBox();
|
|
}
|
|
else
|
|
{
|
|
return cvf::BoundingBox();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::BoundingBox RimEclipseCase::allCellsBoundingBox() const
|
|
{
|
|
if ( m_rigEclipseCase.notNull() && m_rigEclipseCase->mainGrid() )
|
|
{
|
|
return m_rigEclipseCase->mainGrid()->boundingBox();
|
|
}
|
|
else
|
|
{
|
|
return cvf::BoundingBox();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Vec3d RimEclipseCase::displayModelOffset() const
|
|
{
|
|
if ( m_rigEclipseCase.notNull() && m_rigEclipseCase->mainGrid() )
|
|
{
|
|
return m_rigEclipseCase->mainGrid()->displayModelOffset();
|
|
}
|
|
else
|
|
{
|
|
return cvf::Vec3d::ZERO;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RigCaseCellResultsData* RimEclipseCase::results( RiaDefines::PorosityModelType porosityModel )
|
|
{
|
|
if ( m_rigEclipseCase.notNull() )
|
|
{
|
|
return m_rigEclipseCase->results( porosityModel );
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RigCaseCellResultsData* RimEclipseCase::results( RiaDefines::PorosityModelType porosityModel ) const
|
|
{
|
|
if ( m_rigEclipseCase.notNull() )
|
|
{
|
|
return m_rigEclipseCase->results( porosityModel );
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimReservoirCellResultsStorage* RimEclipseCase::resultsStorage( RiaDefines::PorosityModelType porosityModel )
|
|
{
|
|
if ( porosityModel == RiaDefines::PorosityModelType::MATRIX_MODEL )
|
|
{
|
|
return m_matrixModelResults();
|
|
}
|
|
|
|
return m_fractureModelResults();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const RimReservoirCellResultsStorage* RimEclipseCase::resultsStorage( RiaDefines::PorosityModelType porosityModel ) const
|
|
{
|
|
if ( porosityModel == RiaDefines::PorosityModelType::MATRIX_MODEL )
|
|
{
|
|
return m_matrixModelResults();
|
|
}
|
|
|
|
return m_fractureModelResults();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QString> RimEclipseCase::filesContainingFaults() const
|
|
{
|
|
std::vector<QString> stdPathList;
|
|
|
|
for ( auto& filePath : m_filesContainingFaults() )
|
|
{
|
|
stdPathList.push_back( filePath.path() );
|
|
}
|
|
|
|
return stdPathList;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::setFilesContainingFaults( const std::vector<QString>& pathStrings )
|
|
{
|
|
std::vector<caf::FilePath> filePaths;
|
|
for ( const auto& pathString : pathStrings )
|
|
{
|
|
filePaths.push_back( pathString );
|
|
}
|
|
|
|
m_filesContainingFaults = filePaths;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::ensureReservoirCaseIsOpen()
|
|
{
|
|
// Call openReservoirCase, as this is a cheap method to call multiple times
|
|
// Add extra testing here if performance issues are seen
|
|
|
|
return openReservoirCase();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::isReservoirCaseOpen() const
|
|
{
|
|
// for most grid case types, this is a sufficient test
|
|
return eclipseCaseData() != nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::openReservoirCase()
|
|
{
|
|
if ( !openEclipseGridFile() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( eclipseCaseData() && eclipseCaseData()->mainGrid() && !eclipseCaseData()->mainGrid()->hasValidCharacteristicCellSizes() )
|
|
{
|
|
RigMainGrid* mainGrid = eclipseCaseData()->mainGrid();
|
|
|
|
auto activeCellInfo = eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
|
if ( activeCellInfo )
|
|
{
|
|
std::vector<size_t> reservoirCellIndices;
|
|
for ( size_t i = 0; i < mainGrid->cellCount(); i++ )
|
|
{
|
|
if ( activeCellInfo->isActive( ReservoirCellIndex( i ) ) )
|
|
{
|
|
reservoirCellIndices.push_back( i );
|
|
}
|
|
}
|
|
mainGrid->computeCharacteristicCellSize( reservoirCellIndices );
|
|
mainGrid->computeFaceNormalsDirection( reservoirCellIndices );
|
|
}
|
|
}
|
|
|
|
bool createPlaceholderEntries = true;
|
|
if ( dynamic_cast<RimEclipseStatisticsCase*>( this ) )
|
|
{
|
|
// Never create placeholder entries for statistical cases. This does not make sense, and breaks the
|
|
// logic for testing if data is present in RimEclipseStatisticsCase::hasComputedStatistics()
|
|
createPlaceholderEntries = false;
|
|
}
|
|
|
|
if ( createPlaceholderEntries )
|
|
{
|
|
if ( RigCaseCellResultsData* results = this->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) )
|
|
{
|
|
results->createPlaceholderResultEntries();
|
|
// After the placeholder result for combined transmissibility is created,
|
|
// make sure the nnc transmissibilities can be addressed by this scalarResultIndex as well
|
|
|
|
RigEclipseResultAddress combinedTransmissibilityResAddr( RiaDefines::ResultCatType::STATIC_NATIVE,
|
|
RiaResultNames::combinedTransmissibilityResultName() );
|
|
if ( results->hasResultEntry( combinedTransmissibilityResAddr ) )
|
|
{
|
|
eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress( RiaDefines::propertyNameCombTrans(),
|
|
combinedTransmissibilityResAddr );
|
|
}
|
|
|
|
RigEclipseResultAddress combinedWaterFluxResAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
|
|
RiaResultNames::combinedWaterFluxResultName() );
|
|
if ( results->hasResultEntry( combinedWaterFluxResAddr ) )
|
|
{
|
|
eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress( RiaDefines::propertyNameFluxWat(), combinedWaterFluxResAddr );
|
|
}
|
|
|
|
RigEclipseResultAddress combinedOilFluxResAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
|
|
RiaResultNames::combinedOilFluxResultName() );
|
|
if ( results->hasResultEntry( combinedOilFluxResAddr ) )
|
|
{
|
|
eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress( RiaDefines::propertyNameFluxOil(), combinedOilFluxResAddr );
|
|
}
|
|
RigEclipseResultAddress combinedGasFluxResAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
|
|
RiaResultNames::combinedGasFluxResultName() );
|
|
|
|
if ( results->hasResultEntry( combinedGasFluxResAddr ) )
|
|
{
|
|
eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress( RiaDefines::propertyNameFluxGas(), combinedGasFluxResAddr );
|
|
}
|
|
}
|
|
|
|
if ( RigCaseCellResultsData* results = this->results( RiaDefines::PorosityModelType::FRACTURE_MODEL ) )
|
|
{
|
|
results->createPlaceholderResultEntries();
|
|
}
|
|
}
|
|
|
|
// Build result child nodes after the placeholder entries have been created
|
|
if ( m_resultAddressCollections.empty() ) buildResultChildNodes();
|
|
|
|
createTimeStepFormatString();
|
|
|
|
if ( !m_readerSettings.skipWellData )
|
|
{
|
|
// Associate existing well paths with simulation wells
|
|
RimProject* proj = RimProject::current();
|
|
for ( const auto& oilField : proj->oilFields() )
|
|
{
|
|
for ( const auto& wellPath : oilField->wellPathCollection()->allWellPaths() )
|
|
{
|
|
if ( !wellPath->isAssociatedWithSimulationWell() )
|
|
{
|
|
wellPath->tryAssociateWithSimulationWell();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::reloadEclipseGridFile()
|
|
{
|
|
closeReservoirCase();
|
|
openReservoirCase();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::closeReservoirCase()
|
|
{
|
|
setReservoirData( nullptr );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<Rim3dView*> RimEclipseCase::allSpecialViews() const
|
|
{
|
|
std::vector<Rim3dView*> views;
|
|
for ( RimEclipseView* view : reservoirViews() )
|
|
{
|
|
views.push_back( view );
|
|
}
|
|
|
|
for ( RimEclipseContourMapView* view : contourMapViews() )
|
|
{
|
|
views.push_back( view );
|
|
}
|
|
|
|
return views;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QStringList RimEclipseCase::timeStepStrings() const
|
|
{
|
|
QStringList stringList;
|
|
|
|
const RigCaseCellResultsData* cellResultData = results( RiaDefines::PorosityModelType::MATRIX_MODEL );
|
|
if ( cellResultData )
|
|
{
|
|
int timeStepCount = static_cast<int>( cellResultData->maxTimeStepCount() );
|
|
for ( int i = 0; i < timeStepCount; i++ )
|
|
{
|
|
stringList += timeStepName( i );
|
|
}
|
|
}
|
|
|
|
return stringList;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimEclipseCase::timeStepName( int frameIdx ) const
|
|
{
|
|
std::vector<QDateTime> timeStepDates = this->timeStepDates();
|
|
if ( frameIdx < static_cast<int>( timeStepDates.size() ) )
|
|
{
|
|
QDateTime date = timeStepDates.at( frameIdx );
|
|
|
|
return RiaQDateTimeTools::toStringUsingApplicationLocale( date, m_timeStepFormatString );
|
|
}
|
|
|
|
return QString( "" );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimEclipseCase::characteristicCellSize() const
|
|
{
|
|
const RigEclipseCaseData* rigEclipseCase = eclipseCaseData();
|
|
if ( rigEclipseCase && rigEclipseCase->mainGrid() )
|
|
{
|
|
double maxSize = 200.0;
|
|
return std::min( rigEclipseCase->mainGrid()->characteristicIJCellSize(), maxSize );
|
|
}
|
|
|
|
return 10.0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::set<QString> RimEclipseCase::sortedSimWellNames() const
|
|
{
|
|
std::set<QString> sortedWellNames;
|
|
if ( eclipseCaseData() )
|
|
{
|
|
const cvf::Collection<RigSimWellData>& simWellData = eclipseCaseData()->wellResults();
|
|
|
|
for ( size_t wIdx = 0; wIdx < simWellData.size(); ++wIdx )
|
|
{
|
|
sortedWellNames.insert( simWellData[wIdx]->m_wellName );
|
|
}
|
|
}
|
|
return sortedWellNames;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QDateTime> RimEclipseCase::timeStepDates() const
|
|
{
|
|
if ( results( RiaDefines::PorosityModelType::MATRIX_MODEL ) )
|
|
{
|
|
return results( RiaDefines::PorosityModelType::MATRIX_MODEL )->timeStepDates();
|
|
}
|
|
return std::vector<QDateTime>();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseCase::importAsciiInputProperties( const QStringList& fileNames )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::setReaderSettings( RifReaderSettings& readerSettings )
|
|
{
|
|
m_readerSettings = readerSettings;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RifReaderSettings RimEclipseCase::readerSettings() const
|
|
{
|
|
return m_readerSettings;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::updateResultAddressCollection()
|
|
{
|
|
m_resultAddressCollections.deleteChildren();
|
|
updateConnectedEditors();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimEclipseViewCollection* RimEclipseCase::viewCollection() const
|
|
{
|
|
return m_viewCollection;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimGenericViewCollection* RimEclipseCase::globalViewCollection() const
|
|
{
|
|
RimProject* project = RimProject::current();
|
|
if ( !project ) return nullptr;
|
|
|
|
RimOilField* oilField = project->activeOilField();
|
|
if ( !oilField ) return nullptr;
|
|
|
|
return oilField->genericViewCollection();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimEclipseView*> RimEclipseCase::reservoirViews() const
|
|
{
|
|
std::vector<RimEclipseView*> views;
|
|
|
|
addViewsFromViewCollection( views, viewCollection() );
|
|
addViewsFromViewCollection( views, globalViewCollection() );
|
|
|
|
// A case in a grid ensemble is displayed by views in the view collection of the grid ensemble
|
|
if ( auto gridEnsemble = firstAncestorOrThisOfType<RimReservoirGridEnsemble>() )
|
|
{
|
|
addViewsFromViewCollection( views, gridEnsemble->viewCollection() );
|
|
}
|
|
|
|
return views;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::addViewsFromViewCollection( std::vector<RimEclipseView*>& views, const RimEclipseViewCollection* viewColl ) const
|
|
{
|
|
if ( viewColl )
|
|
{
|
|
for ( auto view : viewColl->views() )
|
|
{
|
|
if ( view && view->eclipseCase() && view->eclipseCase() == this )
|
|
{
|
|
views.push_back( view );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::addViewsFromViewCollection( std::vector<RimEclipseView*>& views, const RimGenericViewCollection* viewColl ) const
|
|
{
|
|
if ( viewColl )
|
|
{
|
|
for ( auto view : viewColl->views() )
|
|
{
|
|
if ( view && view->eclipseCase() && view->eclipseCase() == this )
|
|
{
|
|
views.push_back( view );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RimEclipseContourMapView*> RimEclipseCase::contourMapViews() const
|
|
{
|
|
std::vector<RimEclipseContourMapView*> views;
|
|
if ( RimEclipseContourMapViewCollection* viewColl = contourMapCollection() )
|
|
{
|
|
for ( auto view : viewColl->views() )
|
|
{
|
|
if ( view && view->eclipseCase() && view->eclipseCase() == this )
|
|
{
|
|
views.push_back( view );
|
|
}
|
|
}
|
|
}
|
|
|
|
return views;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseCase::addWellTargetMapping( RimWellTargetMapping* generator )
|
|
{
|
|
m_dataAnalyticsCollection->addWellTargetMapping( generator );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimFaultDistanceCollection* RimEclipseCase::faultDistanceCollection() const
|
|
{
|
|
return m_dataAnalyticsCollection ? m_dataAnalyticsCollection->faultDistanceCollection() : nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimReservoirGridEnsemble* RimEclipseCase::ensemble() const
|
|
{
|
|
return firstAncestorOrThisOfType<RimReservoirGridEnsemble>();
|
|
}
|