///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RigCaseCellResultsData.h" #include "RiaDefines.h" #include "RiaEclipseUnitTools.h" #include "RiaLogging.h" #include "RiaPreferencesGrid.h" #include "RiaPreferencesSystem.h" #include "RiaResultNames.h" #include "RifReaderEclipseOutput.h" #include "RifReaderOpmCommon.h" #include "RigAllanDiagramData.h" #include "RigAllanUtil.h" #include "RigCaseCellResultCalculator.h" #include "RigCell.h" #include "RigCellVolumeResultCalculator.h" #include "RigCellsWithNncsCalculator.h" #include "RigEclipseAllanFaultsStatCalc.h" #include "RigEclipseCaseData.h" #include "RigEclipseMultiPropertyStatCalc.h" #include "RigEclipseNativeStatCalc.h" #include "RigEclipseResultInfo.h" #include "RigFaultDistanceResultCalculator.h" #include "RigFormationNames.h" #include "RigIndexIjkResultCalculator.h" #include "RigLocalGrid.h" #include "RigMainGrid.h" #include "RigMobilePoreVolumeResultCalculator.h" #include "RigNestedHybridGridResultTools.h" #include "RigOilVolumeResultCalculator.h" #include "RigPorvSoilSgasResultCalculator.h" #include "RigSgasResultCalculator.h" #include "RigSoilResultCalculator.h" #include "RigStatisticsDataCache.h" #include "RigStatisticsMath.h" #include "RigSwatResultCalculator.h" #include "RigTypeSafeIndex.h" #include "RimCompletionCellIntersectionCalc.h" #include "RimEclipseCase.h" #include "RimGridCalculation.h" #include "RimGridCalculationCollection.h" #include "RimProject.h" #include "cafAssert.h" #include "cafProgressInfo.h" #include "cvfGeometryTools.h" #include #include #include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigCaseCellResultsData::RigCaseCellResultsData( RigEclipseCaseData* ownerCaseData, RiaDefines::PorosityModelType porosityModel ) : m_activeCellInfo( nullptr ) , m_porosityModel( porosityModel ) { CAF_ASSERT( ownerCaseData != nullptr ); CAF_ASSERT( ownerCaseData->mainGrid() != nullptr ); m_ownerCaseData = ownerCaseData; m_ownerMainGrid = ownerCaseData->mainGrid(); m_allanDiagramData = new RigAllanDiagramData; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setMainGrid( RigMainGrid* ownerGrid ) { m_ownerMainGrid = ownerGrid; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigMainGrid* RigCaseCellResultsData::mainGrid() { return m_ownerMainGrid; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setActiveCellInfo( RigActiveCellInfo* activeCellInfo ) { m_activeCellInfo = activeCellInfo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::minMaxCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& min, double& max ) { statistics( resVarAddr )->minMaxCellScalarValues( min, max ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::minMaxCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& min, double& max ) { statistics( resVarAddr )->minMaxCellScalarValues( timeStepIndex, min, max ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::posNegClosestToZero( const RigEclipseResultAddress& resVarAddr, double& pos, double& neg ) { statistics( resVarAddr )->posNegClosestToZero( pos, neg ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::posNegClosestToZero( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& pos, double& neg ) { statistics( resVarAddr )->posNegClosestToZero( timeStepIndex, pos, neg ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram( const RigEclipseResultAddress& resVarAddr ) { return statistics( resVarAddr )->cellScalarValuesHistogram(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) { return statistics( resVarAddr )->cellScalarValuesHistogram( timeStepIndex ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::p10p90CellScalarValues( const RigEclipseResultAddress& resVarAddr, double& p10, double& p90 ) { statistics( resVarAddr )->p10p90CellScalarValues( p10, p90 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::p10p90CellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& p10, double& p90 ) { statistics( resVarAddr )->p10p90CellScalarValues( timeStepIndex, p10, p90 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::meanCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& meanValue ) { statistics( resVarAddr )->meanCellScalarValues( meanValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::meanCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue ) { statistics( resVarAddr )->meanCellScalarValues( timeStepIndex, meanValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigCaseCellResultsData::uniqueCellScalarValues( const RigEclipseResultAddress& resVarAddr ) { return statistics( resVarAddr )->uniqueCellScalarValues(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::sumCellScalarValues( const RigEclipseResultAddress& resVarAddr, double& sumValue ) { statistics( resVarAddr )->sumCellScalarValues( sumValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::sumCellScalarValues( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& sumValue ) { statistics( resVarAddr )->sumCellScalarValues( timeStepIndex, sumValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::mobileVolumeWeightedMean( const RigEclipseResultAddress& resVarAddr, double& meanValue ) { statistics( resVarAddr )->mobileVolumeWeightedMean( meanValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::mobileVolumeWeightedMean( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue ) { statistics( resVarAddr )->mobileVolumeWeightedMean( timeStepIndex, meanValue ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map RigCaseCellResultsData::resultValueCount() const { std::map memoryUse; for ( size_t i = 0; i < m_cellScalarResults.size(); i++ ) { if ( allocatedValueCount( i ) > 0 ) { memoryUse[m_resultInfos[i].resultName().toStdString()] = allocatedValueCount( i ); } } return memoryUse; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::resultCount() const { return m_cellScalarResults.size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::timeStepCount( const RigEclipseResultAddress& resVarAddr ) const { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < resultCount() ); return m_cellScalarResults[scalarResultIndex].size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector>& RigCaseCellResultsData::cellScalarResults( const RigEclipseResultAddress& resVarAddr ) const { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < resultCount() ); return m_cellScalarResults[scalarResultIndex]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector>* RigCaseCellResultsData::modifiableCellScalarResultTimesteps( const RigEclipseResultAddress& resVarAddr ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < resultCount() ); return &( m_cellScalarResults[scalarResultIndex] ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector* RigCaseCellResultsData::modifiableCellScalarResult( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < resultCount() ); CAF_ASSERT( timeStepIndex < m_cellScalarResults[scalarResultIndex].size() ); return &( m_cellScalarResults[scalarResultIndex][timeStepIndex] ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigCaseCellResultsData::cellScalarResults( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) const { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < resultCount() ); CAF_ASSERT( timeStepIndex < m_cellScalarResults[scalarResultIndex].size() ); return m_cellScalarResults[scalarResultIndex][timeStepIndex]; } //-------------------------------------------------------------------------------------------------- /// Adds an empty scalar set, and returns the scalarResultIndex to it. /// if resultName already exists, it just returns the scalarResultIndex to the existing result. //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findOrCreateScalarResultIndex( const RigEclipseResultAddress& resVarAddrOrg, bool needsToBeStored ) { auto resVarAddr( resVarAddrOrg ); if ( m_resultAliasMap.contains( resVarAddrOrg.resultName() ) ) { resVarAddr.setResultName( m_resultAliasMap[resVarAddrOrg.resultName()] ); } size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); // If the result exists, do nothing if ( scalarResultIndex != cvf::UNDEFINED_SIZE_T ) { return scalarResultIndex; } // Create the new empty result with metadata scalarResultIndex = resultCount(); m_cellScalarResults.push_back( std::vector>() ); RigEclipseResultInfo resInfo( resVarAddr, needsToBeStored, false, scalarResultIndex ); m_resultInfos.push_back( resInfo ); m_addressToResultIndexMap[resVarAddr] = scalarResultIndex; // Create statistics calculator and add statistics cache object // Todo: Move to a "factory" method QString resultName = resVarAddr.resultName(); cvf::ref statisticsCalculator; if ( resultName == RiaResultNames::combinedTransmissibilityResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANX" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANY" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANZ" ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedMultResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTX" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTX-" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTY" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTY-" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTZ" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTZ-" ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedRiTranResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranXResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranYResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranZResultName() ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedRiMultResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultXResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultYResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultZResultName() ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedRiAreaNormTranResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranXResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranYResultName() ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranZResultName() ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedWaterFluxResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATI+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATJ+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATK+" ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedOilFluxResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILI+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILJ+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILK+" ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::combinedGasFluxResultName() ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASI+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASJ+" ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASK+" ) ); statisticsCalculator = calc; } else if ( resultName.endsWith( "IJK" ) ) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); QString baseName = resultName.left( resultName.size() - 3 ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::GENERATED, QString( "%1I" ).arg( baseName ) ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::GENERATED, QString( "%1J" ).arg( baseName ) ) ); calc->addNativeStatisticsCalculator( this, RigEclipseResultAddress( RiaDefines::ResultCatType::GENERATED, QString( "%1K" ).arg( baseName ) ) ); statisticsCalculator = calc; } else if ( resultName == RiaResultNames::formationAllanResultName() || resultName == RiaResultNames::formationBinaryAllanResultName() ) { cvf::ref calc = new RigEclipseAllanFaultsStatCalc( m_ownerMainGrid->nncData(), resVarAddr ); statisticsCalculator = calc; } else { statisticsCalculator = new RigEclipseNativeStatCalc( this, resVarAddr ); } cvf::ref dataCache = new RigStatisticsDataCache( statisticsCalculator.p() ); m_statisticsDataCache.push_back( dataCache.p() ); return scalarResultIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QStringList RigCaseCellResultsData::resultNames( RiaDefines::ResultCatType resType, bool includeAliases ) const { QStringList varList; std::vector::const_iterator it; for ( it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it ) { auto resultAddress = it->eclipseResultAddress(); if ( resultAddress.isDeltaTimeStepActive() || resultAddress.isDeltaCaseActive() || resultAddress.isDivideByCellFaceAreaActive() ) continue; if ( isRadialModel() && ( it->resultName() == "DX" || it->resultName() == "DY" ) ) continue; if ( it->resultType() == resType ) { varList.push_back( it->resultName() ); if ( !includeAliases ) continue; for ( auto& [alias, real] : m_resultAliasMap ) { if ( real == it->resultName() ) { varList.push_back( alias ); } } } } return varList; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigActiveCellInfo* RigCaseCellResultsData::activeCellInfo() { return m_activeCellInfo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RigActiveCellInfo* RigCaseCellResultsData::activeCellInfo() const { return m_activeCellInfo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::recalculateStatistics( const RigEclipseResultAddress& resVarAddr, const std::set& uniqueValuesOverride ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); if ( scalarResultIndex < m_cellScalarResults.size() ) { m_statisticsDataCache[scalarResultIndex]->clearAllStatistics(); if ( !uniqueValuesOverride.empty() ) { m_statisticsDataCache[scalarResultIndex]->setUniqueCellScalarValues( uniqueValuesOverride ); } } } //-------------------------------------------------------------------------------------------------- /// Returns whether the result data in question is addressed by Active Cell Index //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::isUsingGlobalActiveIndex( const RigEclipseResultAddress& resVarAddr ) const { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < m_cellScalarResults.size() ); if ( m_cellScalarResults[scalarResultIndex].empty() ) return true; size_t firstTimeStepResultValueCount = m_cellScalarResults[scalarResultIndex][0].size(); return firstTimeStepResultValueCount != m_ownerMainGrid->totalCellCount(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::hasFlowDiagUsableFluxes() const { QStringList dynResVarNames = resultNames( RiaDefines::ResultCatType::DYNAMIC_NATIVE ); bool hasFlowFluxes = true; hasFlowFluxes = dynResVarNames.contains( "FLRWATI+" ); hasFlowFluxes = hasFlowFluxes && ( dynResVarNames.contains( "FLROILI+" ) || dynResVarNames.contains( "FLRGASI+" ) ); return hasFlowFluxes; } //-------------------------------------------------------------------------------------------------- /// Time steps reported by the file reader itself, independent of which results (if any) have been /// loaded so far. gridFileName is only needed for the opm-common reader, which requires it to locate /// the matching restart file. //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::allTimeStepDatesFromEclipseReader( const QString& gridFileName ) const { if ( const RifReaderEclipseOutput* rifReaderOutput = dynamic_cast( m_readerInterface.p() ) ) { return rifReaderOutput->allTimeSteps(); } if ( auto* rifReaderOpmCommon = dynamic_cast( m_readerInterface.p() ) ) { if ( !gridFileName.isEmpty() ) return const_cast( rifReaderOpmCommon )->timeStepsOnFile( gridFileName ); } return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::timeStepDates( const RigEclipseResultAddress& resVarAddr ) const { if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() ) { return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].dates(); } else return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::timeStepDates() const { RigEclipseResultAddress scalarResWithMostTimeSteps; maxTimeStepCount( &scalarResWithMostTimeSteps ); return timeStepDates( scalarResWithMostTimeSteps ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::daysSinceSimulationStart() const { RigEclipseResultAddress scalarResWithMostTimeSteps; maxTimeStepCount( &scalarResWithMostTimeSteps ); return daysSinceSimulationStart( scalarResWithMostTimeSteps ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::daysSinceSimulationStart( const RigEclipseResultAddress& resVarAddr ) const { if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() ) { return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].daysSinceSimulationStarts(); } else { return std::vector(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RigCaseCellResultsData::reportStepNumber( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) const { if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() && m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].timeStepInfos().size() > timeStepIndex ) return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].timeStepInfos()[timeStepIndex].m_reportNumber; else return -1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::timeStepInfos( const RigEclipseResultAddress& resVarAddr ) const { if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() ) return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].timeStepInfos(); else return std::vector(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setTimeStepInfos( const RigEclipseResultAddress& resVarAddr, const std::vector& timeStepInfos ) { CAF_ASSERT( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() ); m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].setTimeStepInfos( timeStepInfos ); std::vector>* dataValues = modifiableCellScalarResultTimesteps( resVarAddr ); dataValues->resize( timeStepInfos.size() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::maxTimeStepCount( RigEclipseResultAddress* resultAddressWithMostTimeSteps ) const { size_t maxTsCount = 0; RigEclipseResultAddress scalarResultIndexWithMaxTsCount; for ( size_t i = 0; i < m_resultInfos.size(); i++ ) { if ( m_resultInfos[i].timeStepInfos().size() > maxTsCount ) { maxTsCount = m_resultInfos[i].timeStepInfos().size(); if ( resultAddressWithMostTimeSteps ) { *resultAddressWithMostTimeSteps = m_resultInfos[i].eclipseResultAddress(); } } } return maxTsCount; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RigCaseCellResultsData::makeResultNameUnique( const QString& resultNameProposal ) const { QString newResultName = resultNameProposal; int nameNum = 1; int stringLength = newResultName.size(); while ( true ) { if ( !hasResultEntry( RigEclipseResultAddress( newResultName ) ) ) break; newResultName.truncate( stringLength ); newResultName += "_" + QString::number( nameNum ); ++nameNum; } return newResultName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::clearScalarResult( RiaDefines::ResultCatType type, const QString& resultName ) { clearScalarResult( RigEclipseResultAddress( type, resultName ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::clearScalarResult( const RigEclipseResultAddress& resultAddress ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resultAddress ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) return; for ( size_t tsIdx = 0; tsIdx < m_cellScalarResults[scalarResultIndex].size(); ++tsIdx ) { std::vector empty; m_cellScalarResults[scalarResultIndex][tsIdx].swap( empty ); } recalculateStatistics( resultAddress ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::clearAllResults() { m_cellScalarResults.clear(); m_resultInfos.clear(); m_addressToResultIndexMap.clear(); m_statisticsDataCache.clear(); } //-------------------------------------------------------------------------------------------------- /// Removes all the actual numbers put into this object, and frees up the memory. /// Does not touch the metadata in any way //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::freeAllocatedResultsData( const std::vector& categoriesToExclude, std::optional timeStepIndexToRelease ) { for ( size_t resultIdx = 0; resultIdx < m_cellScalarResults.size(); ++resultIdx ) { if ( resultIdx < m_resultInfos.size() ) { auto resultCategory = m_resultInfos[resultIdx].eclipseResultAddress().resultCatType(); if ( std::find( categoriesToExclude.begin(), categoriesToExclude.end(), resultCategory ) != categoriesToExclude.end() ) { // Keep generated results for these categories continue; } } for ( size_t index = 0; index < m_cellScalarResults[resultIdx].size(); index++ ) { if ( timeStepIndexToRelease.has_value() && index != timeStepIndexToRelease.value() ) { // Keep generated results for these time steps continue; } auto& dataForTimeStep = m_cellScalarResults[resultIdx][index]; if ( !dataForTimeStep.empty() ) { // Using swap with an empty vector as that is the safest way to really get rid of the allocated data in a // vector std::vector empty; dataForTimeStep.swap( empty ); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::isResultLoaded( const RigEclipseResultAddress& resultAddr ) const { size_t scalarResultIndex = findScalarResultIndexFromAddress( resultAddr ); CAF_ASSERT( scalarResultIndex != cvf::UNDEFINED_SIZE_T ); if ( scalarResultIndex != cvf::UNDEFINED_SIZE_T ) { return isDataPresent( scalarResultIndex ); } return false; } //-------------------------------------------------------------------------------------------------- /// Make sure we have a result with given type and name, and make sure one "timestep" result vector // for the static result values are allocated //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::addStaticScalarResult( RiaDefines::ResultCatType type, const QString& resultName, bool needsToBeStored, size_t resultValueCount ) { size_t resultIdx = findOrCreateScalarResultIndex( RigEclipseResultAddress( type, resultName ), needsToBeStored ); m_cellScalarResults[resultIdx].resize( 1, std::vector() ); m_cellScalarResults[resultIdx][0].resize( resultValueCount, HUGE_VAL ); return resultIdx; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigEclipseResultAddress RigCaseCellResultsData::defaultResult() const { auto allResults = existingResults(); // Completion Type is a category result, and is not useful as a default result. See issue #14486. auto isCandidateResult = []( const RigEclipseResultAddress& adr, RiaDefines::ResultCatType category ) { return adr.resultCatType() == category && adr.resultName() != RiaResultNames::completionTypeResultName(); }; if ( maxTimeStepCount() > 0 ) { auto prefs = RiaPreferencesGrid::current(); if ( prefs->loadAndShowSoil() && m_ownerCaseData ) { // Use the saturation result matching the available phases, but only if the result exists or can be // computed, i.e. a result entry is present. See issue #10122. const auto phases = m_ownerCaseData->availablePhases(); const RigEclipseResultAddress soilAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ); if ( phases.contains( RiaDefines::PhaseType::OIL_PHASE ) && hasResultEntry( soilAddress ) ) { return soilAddress; } const RigEclipseResultAddress sgasAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ); if ( phases.contains( RiaDefines::PhaseType::GAS_PHASE ) && hasResultEntry( sgasAddress ) ) { return sgasAddress; } const RigEclipseResultAddress swatAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ); if ( hasResultEntry( swatAddress ) ) { return swatAddress; } } auto dynamicResult = std::find_if( allResults.begin(), allResults.end(), [&isCandidateResult]( const RigEclipseResultAddress& adr ) { return isCandidateResult( adr, RiaDefines::ResultCatType::DYNAMIC_NATIVE ); } ); if ( dynamicResult != allResults.end() ) return *dynamicResult; } // If any input property exists, use that auto inputProperty = std::find_if( allResults.begin(), allResults.end(), [&isCandidateResult]( const RigEclipseResultAddress& adr ) { return isCandidateResult( adr, RiaDefines::ResultCatType::INPUT_PROPERTY ); } ); if ( inputProperty != allResults.end() ) return *inputProperty; // If any static property exists, use that auto staticResult = std::find_if( allResults.begin(), allResults.end(), [&isCandidateResult]( const RigEclipseResultAddress& adr ) { return isCandidateResult( adr, RiaDefines::ResultCatType::STATIC_NATIVE ); } ); if ( staticResult != allResults.end() ) return *staticResult; // No results available, use "None" return RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::undefinedResultName() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::updateResultName( RiaDefines::ResultCatType resultType, const QString& oldName, const QString& newName ) { bool anyNameUpdated = false; for ( auto& it : m_resultInfos ) { if ( it.resultType() == resultType && it.resultName() == oldName ) { anyNameUpdated = true; it.setResultName( newName ); } } return anyNameUpdated; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector* RigCaseCellResultsData::getResultIndexableStaticResult( RigActiveCellInfo* actCellInfo, RigCaseCellResultsData* gridCellResults, QString resultName, std::vector& activeCellsResultsTempContainer ) { size_t resultCellCount = actCellInfo->reservoirActiveCellCount(); size_t reservoirCellCount = actCellInfo->reservoirCellCount(); RigEclipseResultAddress resVarAddr( RiaDefines::ResultCatType::STATIC_NATIVE, resultName ); size_t scalarResultIndexPorv = gridCellResults->findOrLoadKnownScalarResult( resVarAddr ); if ( scalarResultIndexPorv == cvf::UNDEFINED_SIZE_T ) return nullptr; const std::vector* porvResults = &( gridCellResults->cellScalarResults( resVarAddr, 0 ) ); if ( !gridCellResults->isUsingGlobalActiveIndex( resVarAddr ) ) { // PORV is given for all cells activeCellsResultsTempContainer.resize( resultCellCount, HUGE_VAL ); for ( size_t globalCellIndex = 0; globalCellIndex < reservoirCellCount; globalCellIndex++ ) { size_t resultIdx = actCellInfo->cellResultIndex( ReservoirCellIndex( globalCellIndex ) ).value(); if ( resultIdx != cvf::UNDEFINED_SIZE_T ) { activeCellsResultsTempContainer[resultIdx] = porvResults->at( globalCellIndex ); } } return &activeCellsResultsTempContainer; } else { return porvResults; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RigCaseCellResultsData::infoForEachResultIndex() const { return m_resultInfos; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::mustBeCalculated( size_t scalarResultIndex ) const { std::vector::const_iterator it; for ( it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it ) { if ( it->gridScalarResultIndex() == scalarResultIndex ) { return it->mustBeCalculated(); } } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setMustBeCalculated( size_t scalarResultIndex ) { std::vector::iterator it; for ( it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it ) { if ( it->gridScalarResultIndex() == scalarResultIndex ) { it->setMustBeCalculated( true ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::eraseAllSourSimData() { for ( size_t i = 0; i < m_resultInfos.size(); i++ ) { RigEclipseResultInfo& ri = m_resultInfos[i]; if ( ri.resultType() == RiaDefines::ResultCatType::SOURSIMRL ) { ri.setResultType( RiaDefines::ResultCatType::REMOVED ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setRemovedTagOnGeneratedResult( const RigEclipseResultAddress& resultAddress ) { CAF_ASSERT( resultAddress.resultCatType() == RiaDefines::ResultCatType::GENERATED ); for ( auto& it : m_resultInfos ) { if ( it.resultType() == RiaDefines::ResultCatType::GENERATED && it.resultName() == resultAddress.resultName() ) { it.setResultType( RiaDefines::ResultCatType::REMOVED ); return; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::createPlaceholderResultEntries() { bool needsToBeStored = false; // SOIL { RigSoilResultCalculator soilCalculator( *this ); soilCalculator.checkAndCreatePlaceholderEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ) ); } // SWAT { RigSwatResultCalculator swatCalculator( *this ); swatCalculator.checkAndCreatePlaceholderEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ) ); } // SGAS { RigSgasResultCalculator sgasCalculator( *this ); sgasCalculator.checkAndCreatePlaceholderEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) ); } // Oil Volume if ( RiaPreferencesSystem::current()->isFeatureEnabled( "oil-volume-result" ) ) { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ) ) ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::riOilVolumeResultName() ), needsToBeStored ); } } // Completion type { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::completionTypeResultName() ), needsToBeStored ); // Also register a static variant so completion type can be computed/viewed when only grid // geometry is loaded (no restart / no simulation time steps). See issue #14127. findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::completionTypeResultName() ), needsToBeStored ); } // Fault results { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::ALLAN_DIAGRAMS, RiaResultNames::formationBinaryAllanResultName() ), needsToBeStored ); findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::ALLAN_DIAGRAMS, RiaResultNames::formationAllanResultName() ), needsToBeStored ); } // FLUX { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATI+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATJ+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRWATK+" ) ) ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::combinedWaterFluxResultName() ), needsToBeStored ); } if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILI+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILJ+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLROILK+" ) ) ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::combinedOilFluxResultName() ), needsToBeStored ); } if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASI+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASJ+" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "FLRGASK+" ) ) ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::combinedGasFluxResultName() ), needsToBeStored ); } } // TRANSXYZ { if ( hasCompleteTransmissibilityResults() ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedTransmissibilityResultName(), needsToBeStored, 0 ); } } // MULTXYZ { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTX" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTX-" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTY" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTY-" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTZ" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "MULTZ-" ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedMultResultName(), needsToBeStored, 0 ); } } // riTRANSXYZ and X,Y,Z { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMX" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMY" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMZ" ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranXResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranYResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranZResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiTranResultName(), needsToBeStored, 0 ); } } // riMULTXYZ and X, Y, Z { if ( hasCompleteTransmissibilityResults() && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranXResultName() ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranYResultName() ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riTranZResultName() ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultXResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultYResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riMultZResultName(), needsToBeStored, 0 ); addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiMultResultName(), needsToBeStored, 0 ); } } // riTRANS X,Y,Z byArea { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANX" ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranXResultName(), needsToBeStored, 0 ); } if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANY" ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranYResultName(), needsToBeStored, 0 ); } if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANZ" ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riAreaNormTranZResultName(), needsToBeStored, 0 ); } } // riTRANSXYZbyArea { if ( hasCompleteTransmissibilityResults() ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiAreaNormTranResultName(), needsToBeStored, 0 ); } } // Cell Volume { if ( !hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riCellVolumeResultName() ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riCellVolumeResultName(), needsToBeStored, 0 ); } } // Mobile Pore Volume { if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::porv() ) ) ) { if ( !hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::mobilePoreVolumeName() ) ) ) { addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::mobilePoreVolumeName(), needsToBeStored, 0 ); } } } // I/J/K indexes { findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexIResultName( isRadialModel() ) ), needsToBeStored ); findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexJResultName( isRadialModel() ) ), needsToBeStored ); findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexKResultName() ), needsToBeStored ); } if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::porv() ) ) ) { bool hasSgas = hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) ); bool hasSoil = hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ) ); if ( hasSoil ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::riPorvSoil() ), needsToBeStored ); } if ( hasSgas ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::riPorvSgas() ), needsToBeStored ); } if ( hasSoil && hasSgas ) { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::riPorvSoilSgas() ), needsToBeStored ); } } // Fault distance { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::faultDistanceName() ), needsToBeStored ); } // NNC cells, 1 for cells with NNC and 0 for other cells { findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultDataType::INTEGER, RiaResultNames::riNncCells() ), needsToBeStored ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::hasCompleteTransmissibilityResults() const { return hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANX" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANY" ) ) && hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANZ" ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::existingResults() const { std::vector addresses; for ( const auto& ri : m_resultInfos ) { addresses.emplace_back( ri.eclipseResultAddress() ); } return addresses; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RigEclipseResultInfo* RigCaseCellResultsData::resultInfo( const RigEclipseResultAddress& resVarAddr ) const { size_t index = findScalarResultIndexFromAddress( resVarAddr ); if ( index < m_resultInfos.size() ) { return &( m_resultInfos[index] ); } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::ensureKnownResultLoaded( const RigEclipseResultAddress& resultAddress ) { size_t resultIndex = findOrLoadKnownScalarResult( resultAddress ); return ( resultIndex != cvf::UNDEFINED_SIZE_T ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::findAndLoadResultByName( const QString& resultName, const std::vector& resultCategorySearchOrder ) { RigEclipseResultAddress adr( resultName ); size_t resultIndex = findOrLoadKnownScalarResultByResultTypeOrder( adr, resultCategorySearchOrder ); return ( resultIndex != cvf::UNDEFINED_SIZE_T ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::hasResultEntry( const RigEclipseResultAddress& resultAddress ) const { size_t resultIndex = findScalarResultIndexFromAddress( resultAddress ); return ( resultIndex != cvf::UNDEFINED_SIZE_T ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::createResultEntry( const RigEclipseResultAddress& resultAddress, bool needsToBeStored ) { findOrCreateScalarResultIndex( resultAddress, needsToBeStored ); } //-------------------------------------------------------------------------------------------------- /// Update the data type of an existing result entry. Equality/ordering on RigEclipseResultAddress /// ignores dataType, so overwriting a property with a different dataType does not update the /// persisted metadata unless we explicitly patch it here. //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::updateResultDataType( const RigEclipseResultAddress& resultAddress, RiaDefines::ResultDataType dataType ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resultAddress ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) return false; m_resultInfos[scalarResultIndex].m_resultAddress.setDataType( dataType ); return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findOrLoadKnownScalarResult( const RigEclipseResultAddress& resVarAddrOrg ) { auto resVarAddr( resVarAddrOrg ); if ( m_resultAliasMap.contains( resVarAddrOrg.resultName() ) ) { resVarAddr.setResultName( m_resultAliasMap[resVarAddrOrg.resultName()] ); } if ( !resVarAddr.isValid() ) { return cvf::UNDEFINED_SIZE_T; } else if ( resVarAddr.resultCatType() == RiaDefines::ResultCatType::UNDEFINED ) { std::vector searchOrder = { RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaDefines::ResultCatType::SOURSIMRL, RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultCatType::INPUT_PROPERTY, RiaDefines::ResultCatType::FORMATION_NAMES }; size_t scalarResultIndex = findOrLoadKnownScalarResultByResultTypeOrder( resVarAddr, searchOrder ); return scalarResultIndex; } size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) return cvf::UNDEFINED_SIZE_T; RiaDefines::ResultCatType type = resVarAddr.resultCatType(); QString resultName = resVarAddr.resultName(); if ( resVarAddr.isDeltaCaseActive() || resVarAddr.isDeltaTimeStepActive() ) { if ( !RigCaseCellResultCalculator::computeDifference( m_ownerCaseData, m_porosityModel, resVarAddr ) ) { return cvf::UNDEFINED_SIZE_T; } return scalarResultIndex; } if ( resVarAddr.isDivideByCellFaceAreaActive() ) { if ( !isDataPresent( scalarResultIndex ) ) { if ( !RigCaseCellResultCalculator::computeDivideByCellFaceArea( m_ownerMainGrid, m_ownerCaseData, m_porosityModel, resVarAddr ) ) { return cvf::UNDEFINED_SIZE_T; } } return scalarResultIndex; } // Load dependency data sets if ( type == RiaDefines::ResultCatType::STATIC_NATIVE ) { if ( resultName == RiaResultNames::combinedTransmissibilityResultName() ) { findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "TRANX" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "TRANY" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "TRANZ" ) ); } else if ( resultName == RiaResultNames::combinedMultResultName() ) { findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTX" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTX-" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTY" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTY-" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTZ" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "MULTZ-" ) ); } else if ( resultName == RiaResultNames::combinedRiTranResultName() ) { computeRiTransComponent( RiaResultNames::riTranXResultName() ); computeRiTransComponent( RiaResultNames::riTranYResultName() ); computeRiTransComponent( RiaResultNames::riTranZResultName() ); computeNncCombRiTrans(); } else if ( resultName == RiaResultNames::riTranXResultName() || resultName == RiaResultNames::riTranYResultName() || resultName == RiaResultNames::riTranZResultName() ) { computeRiTransComponent( resultName ); } else if ( resultName == RiaResultNames::combinedRiMultResultName() ) { computeRiMULTComponent( RiaResultNames::riMultXResultName() ); computeRiMULTComponent( RiaResultNames::riMultYResultName() ); computeRiMULTComponent( RiaResultNames::riMultZResultName() ); computeNncCombRiTrans(); computeNncCombRiMULT(); } else if ( resultName == RiaResultNames::riMultXResultName() || resultName == RiaResultNames::riMultYResultName() || resultName == RiaResultNames::riMultZResultName() ) { computeRiMULTComponent( resultName ); } else if ( resultName == RiaResultNames::combinedRiAreaNormTranResultName() ) { computeRiTRANSbyAreaComponent( RiaResultNames::riAreaNormTranXResultName() ); computeRiTRANSbyAreaComponent( RiaResultNames::riAreaNormTranYResultName() ); computeRiTRANSbyAreaComponent( RiaResultNames::riAreaNormTranZResultName() ); computeNncCombRiTRANSbyArea(); } else if ( resultName == RiaResultNames::riAreaNormTranXResultName() || resultName == RiaResultNames::riAreaNormTranYResultName() || resultName == RiaResultNames::riAreaNormTranZResultName() ) { computeRiTRANSbyAreaComponent( resultName ); } else if ( resultName == RiaResultNames::formationAllanResultName() || resultName == RiaResultNames::formationBinaryAllanResultName() ) { bool includeInactiveCells = false; if ( m_readerInterface.notNull() ) { includeInactiveCells = m_readerInterface->includeInactiveCellsInFaultGeometry(); } RigAllanUtil::computeAllanResults( this, m_ownerMainGrid, includeInactiveCells ); } else if ( resultName == RiaResultNames::indexIResultName( isRadialModel() ) || resultName == RiaResultNames::indexJResultName( isRadialModel() ) || resultName == RiaResultNames::indexKResultName() ) { computeIndexResults(); } else if ( resultName == RiaResultNames::faultDistanceName() ) { computeFaultDistance(); } else if ( resultName == RiaResultNames::riNncCells() ) { computeNncsCells(); } } else if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) { if ( resultName == RiaResultNames::combinedWaterFluxResultName() ) { findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRWATI+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRWATJ+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRWATK+" ) ); } else if ( resultName == RiaResultNames::combinedOilFluxResultName() ) { findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLROILI+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLROILJ+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLROILK+" ) ); } else if ( resultName == RiaResultNames::combinedGasFluxResultName() ) { findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRGASI+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRGASJ+" ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( type, "FLRGASK+" ) ); } } if ( isDataPresent( scalarResultIndex ) ) { // Data for some time steps can have been released to reduce memory usage, see // RimGridCalculation::getActiveCellValues(). Results computed by ResInsight can not be reloaded from // file, so continue to recompute them if data is missing for any time step. const bool mustRecompute = isResultComputedByResInsight( resultName, scalarResultIndex ) && hasEmptyDataForAnyTimeStep( scalarResultIndex ); if ( !mustRecompute ) { return scalarResultIndex; } } if ( resultName == RiaResultNames::soil() ) { if ( mustBeCalculated( scalarResultIndex ) ) { // Trigger loading of SWAT, SGAS to establish time step count if no data has been loaded from file at // this point findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ) ); findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) ); m_cellScalarResults[scalarResultIndex].resize( maxTimeStepCount() ); for ( size_t timeStepIdx = 0; timeStepIdx < maxTimeStepCount(); timeStepIdx++ ) { std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIdx]; if ( values.empty() ) { computeSOILForTimeStep( timeStepIdx ); } } return scalarResultIndex; } } else if ( resultName == RiaResultNames::swat() ) { if ( mustBeCalculated( scalarResultIndex ) ) { RigSwatResultCalculator swatCalculator( *this ); for ( size_t timeStepIdx = 0; timeStepIdx < maxTimeStepCount(); timeStepIdx++ ) { swatCalculator.calculate( resVarAddr, timeStepIdx ); } return scalarResultIndex; } } else if ( resultName == RiaResultNames::sgas() ) { if ( mustBeCalculated( scalarResultIndex ) ) { // Trigger loading of SWAT to establish time step count if no data has been loaded from file at this point findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ) ); m_cellScalarResults[scalarResultIndex].resize( maxTimeStepCount() ); for ( size_t timeStepIdx = 0; timeStepIdx < maxTimeStepCount(); timeStepIdx++ ) { if ( m_cellScalarResults[scalarResultIndex][timeStepIdx].empty() ) { computeSgasForTimeStep( timeStepIdx ); } } return scalarResultIndex; } } else if ( resultName == RiaResultNames::completionTypeResultName() ) { if ( type == RiaDefines::ResultCatType::STATIC_NATIVE ) { // Single time-step-independent frame, computed even when no restart data is loaded. caf::ProgressInfo progressInfo( 1, "Calculate Completion Type Results" ); computeStaticCompletionType(); progressInfo.incrementProgress(); return scalarResultIndex; } caf::ProgressInfo progressInfo( maxTimeStepCount(), "Calculate Completion Type Results" ); m_cellScalarResults[scalarResultIndex].resize( maxTimeStepCount() ); for ( size_t timeStepIdx = 0; timeStepIdx < maxTimeStepCount(); ++timeStepIdx ) { computeCompletionTypeForTimeStep( timeStepIdx ); progressInfo.incrementProgress(); } } else if ( resultName == RiaResultNames::mobilePoreVolumeName() ) { computeMobilePV(); } if ( type == RiaDefines::ResultCatType::GENERATED ) { return cvf::UNDEFINED_SIZE_T; } if ( m_readerInterface.notNull() ) { // Add one more result to result container size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); size_t tempGridCellCount = m_ownerMainGrid->totalTemporaryGridCellCount(); if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && timeStepCount > 0 ) { m_cellScalarResults[scalarResultIndex].resize( timeStepCount ); size_t i; for ( i = 0; i < timeStepCount; i++ ) { std::vector& values = m_cellScalarResults[scalarResultIndex][i]; if ( !m_readerInterface->dynamicResult( resultName, m_porosityModel, i, &values ) ) { values.clear(); } else { if ( tempGridCellCount > 0 && !values.empty() ) { values.resize( values.size() + tempGridCellCount, std::numeric_limits::infinity() ); assignValuesToTemporaryLgrs( resultName, values ); } RigNestedHybridGridResultTools::assignValuesToLgrs( this, values ); } } } else if ( type == RiaDefines::ResultCatType::STATIC_NATIVE ) { m_cellScalarResults[scalarResultIndex].resize( 1 ); std::vector& values = m_cellScalarResults[scalarResultIndex][0]; if ( !m_readerInterface->staticResult( resultName, m_porosityModel, &values ) ) { values.clear(); } else { if ( tempGridCellCount > 0 && !values.empty() ) { values.resize( values.size() + tempGridCellCount, std::numeric_limits::infinity() ); assignValuesToTemporaryLgrs( resultName, values ); } RigNestedHybridGridResultTools::assignValuesToLgrs( this, values ); } } } if ( resultName == RiaResultNames::riCellVolumeResultName() ) { computeCellVolumes(); } else if ( resultName == RiaResultNames::riOilVolumeResultName() ) { computeCellVolumes(); computeOilVolumes(); } else if ( resultName == RiaResultNames::riPorvSoil() || resultName == RiaResultNames::riPorvSgas() || resultName == RiaResultNames::riPorvSoilSgas() ) { computePorvSoilSgas(); } // Allan results if ( resultName == RiaResultNames::formationAllanResultName() || resultName == RiaResultNames::formationBinaryAllanResultName() ) { bool includeInactiveCells = false; if ( m_readerInterface.notNull() ) { includeInactiveCells = m_readerInterface->includeInactiveCellsInFaultGeometry(); } RigAllanUtil::computeAllanResults( this, m_ownerMainGrid, includeInactiveCells ); } // Handle SourSimRL reading if ( type == RiaDefines::ResultCatType::SOURSIMRL ) { RifReaderEclipseOutput* eclReader = dynamic_cast( m_readerInterface.p() ); if ( eclReader ) { size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); m_cellScalarResults[scalarResultIndex].resize( timeStepCount ); size_t i; for ( i = 0; i < timeStepCount; i++ ) { std::vector& values = m_cellScalarResults[scalarResultIndex][i]; eclReader->sourSimRlResult( resultName, i, &values ); } } } return scalarResultIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findOrLoadKnownScalarResultByResultTypeOrder( const RigEclipseResultAddress& resVarAddr, const std::vector& resultCategorySearchOrder ) { std::set otherResultTypesToSearch = { RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaDefines::ResultCatType::SOURSIMRL, RiaDefines::ResultCatType::INPUT_PROPERTY, RiaDefines::ResultCatType::GENERATED, RiaDefines::ResultCatType::FORMATION_NAMES }; for ( const auto& resultType : resultCategorySearchOrder ) { otherResultTypesToSearch.erase( resultType ); } std::vector resultTypesOrdered = resultCategorySearchOrder; for ( const auto& resultType : otherResultTypesToSearch ) { resultTypesOrdered.push_back( resultType ); } for ( const auto& resultType : resultTypesOrdered ) { RigEclipseResultAddress resVarAddressWithType = resVarAddr; resVarAddressWithType.setResultCatType( resultType ); size_t scalarResultIndex = findOrLoadKnownScalarResult( resVarAddressWithType ); if ( scalarResultIndex != cvf::UNDEFINED_SIZE_T ) { return scalarResultIndex; } } return cvf::UNDEFINED_SIZE_T; } //-------------------------------------------------------------------------------------------------- /// This method is intended to be used for multicase cross statistical calculations, when /// we need process one timestep at a time, freeing memory as we go. //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findOrLoadKnownScalarResultForTimeStep( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex ) { RiaDefines::ResultCatType type = resVarAddr.resultCatType(); QString resultName = resVarAddr.resultName(); // Special handling for SOIL if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && resultName.toUpper() == RiaResultNames::soil() ) { size_t soilScalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); if ( mustBeCalculated( soilScalarResultIndex ) ) { // A case in an ensemble can have fewer time steps than the case defining the time step axis const size_t timeStepCount = maxTimeStepCount(); if ( timeStepIndex >= timeStepCount ) return cvf::UNDEFINED_SIZE_T; m_cellScalarResults[soilScalarResultIndex].resize( timeStepCount ); std::vector& values = m_cellScalarResults[soilScalarResultIndex][timeStepIndex]; if ( values.empty() ) { computeSOILForTimeStep( timeStepIndex ); } return soilScalarResultIndex; } } else if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && resultName.toUpper() == RiaResultNames::sgas() ) { size_t sgasScalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); if ( mustBeCalculated( sgasScalarResultIndex ) ) { // A case in an ensemble can have fewer time steps than the case defining the time step axis const size_t timeStepCount = maxTimeStepCount(); if ( timeStepIndex >= timeStepCount ) return cvf::UNDEFINED_SIZE_T; m_cellScalarResults[sgasScalarResultIndex].resize( timeStepCount ); if ( m_cellScalarResults[sgasScalarResultIndex][timeStepIndex].empty() ) { computeSgasForTimeStep( timeStepIndex ); } return sgasScalarResultIndex; } } else if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && resultName == RiaResultNames::completionTypeResultName() ) { size_t completionTypeScalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); computeCompletionTypeForTimeStep( timeStepIndex ); return completionTypeScalarResultIndex; } else if ( type == RiaDefines::ResultCatType::STATIC_NATIVE && resultName == RiaResultNames::completionTypeResultName() ) { size_t completionTypeScalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); computeStaticCompletionType(); return completionTypeScalarResultIndex; } size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) return cvf::UNDEFINED_SIZE_T; if ( type == RiaDefines::ResultCatType::GENERATED ) return scalarResultIndex; // Results computed by ResInsight (e.g. riOILVOLUME) can not be read from file for a single time step. // Delegate to findOrLoadKnownScalarResult(), which computes all time steps using the result // calculators. Skip the delegation if data is already present for the requested time step, to avoid // repeated recomputation when data for other time steps is released during a calculation. if ( isResultComputedByResInsight( resultName, scalarResultIndex ) ) { const auto& valuesAllTimeSteps = m_cellScalarResults[scalarResultIndex]; if ( timeStepIndex < valuesAllTimeSteps.size() && !valuesAllTimeSteps[timeStepIndex].empty() ) { return scalarResultIndex; } return findOrLoadKnownScalarResult( resVarAddr ); } if ( m_readerInterface.notNull() ) { size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); bool resultLoadingSuccess = true; if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) { // A case in an ensemble can have fewer time steps than the case defining the time step axis. // This also catches the case where timeStepCount is zero, i.e. no time steps are known for // this result on this case, which previously fell through and returned scalarResultIndex as // if it were valid without ever resizing m_cellScalarResults for it. if ( timeStepIndex >= timeStepCount ) return cvf::UNDEFINED_SIZE_T; m_cellScalarResults[scalarResultIndex].resize( timeStepCount ); std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIndex]; if ( values.empty() ) { if ( !m_readerInterface->dynamicResult( resultName, m_porosityModel, timeStepIndex, &values ) ) { resultLoadingSuccess = false; } else { RigNestedHybridGridResultTools::assignValuesToLgrs( this, values ); } } } else if ( type == RiaDefines::ResultCatType::STATIC_NATIVE ) { m_cellScalarResults[scalarResultIndex].resize( 1 ); std::vector& values = m_cellScalarResults[scalarResultIndex][0]; if ( values.empty() ) { if ( !m_readerInterface->staticResult( resultName, m_porosityModel, &values ) ) { resultLoadingSuccess = false; } else { RigNestedHybridGridResultTools::assignValuesToLgrs( this, values ); } } } if ( !resultLoadingSuccess ) { // A result present in the meta data can still fail to load from file. This is a run-time condition, not a // programming error, so report it instead of asserting. RiaLogging::error( QString( "Failed to load result '%1' for time step %2" ).arg( resultName ).arg( timeStepIndex ).toStdString() ); } } // Handle SourSimRL reading if ( type == RiaDefines::ResultCatType::SOURSIMRL ) { RifReaderEclipseOutput* eclReader = dynamic_cast( m_readerInterface.p() ); if ( eclReader ) { size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); m_cellScalarResults[scalarResultIndex].resize( timeStepCount ); std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIndex]; if ( values.empty() ) { eclReader->sourSimRlResult( resultName, timeStepIndex, &values ); } } } return scalarResultIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeSOILForTimeStep( size_t timeStepIndex ) { RigEclipseResultAddress SOILAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ); RigSoilResultCalculator calculator( *this ); calculator.calculate( SOILAddr, timeStepIndex ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeSgasForTimeStep( size_t timeStepIndex ) { RigEclipseResultAddress SGASAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ); RigSgasResultCalculator calculator( *this ); calculator.calculate( SGASAddr, timeStepIndex ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigCaseCellResultsData::DepthResultBuffers RigCaseCellResultsData::prepareDepthRelatedResultArrays() { DepthResultBuffers buffers; buffers.activeCellInfo = activeCellInfo(); buffers.actCellCount = activeCellInfo()->reservoirActiveCellCount(); // A porosity model with no active cells is left disabled. if ( buffers.actCellCount == 0 ) return buffers; const size_t actCellCount = buffers.actCellCount; size_t depthResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "DEPTH" ) ); size_t dxResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "DX" ) ); size_t dyResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "DY" ) ); size_t dzResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "DZ" ) ); size_t topsResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TOPS" ) ); size_t bottomResultIndex = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "BOTTOM" ) ); if ( depthResultIndex == cvf::UNDEFINED_SIZE_T ) { depthResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DEPTH", false, actCellCount ); buffers.computeDepth = true; } if ( dxResultIndex == cvf::UNDEFINED_SIZE_T ) { dxResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DX", false, actCellCount ); buffers.computeDx = true; } if ( dyResultIndex == cvf::UNDEFINED_SIZE_T ) { dyResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DY", false, actCellCount ); buffers.computeDy = true; } if ( dzResultIndex == cvf::UNDEFINED_SIZE_T ) { dzResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DZ", false, actCellCount ); buffers.computeDz = true; } if ( topsResultIndex == cvf::UNDEFINED_SIZE_T ) { topsResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "TOPS", false, actCellCount ); buffers.computeTops = true; } if ( bottomResultIndex == cvf::UNDEFINED_SIZE_T ) { bottomResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "BOTTOM", false, actCellCount ); buffers.computeBottom = true; } std::vector>& depth = m_cellScalarResults[depthResultIndex]; std::vector>& dx = m_cellScalarResults[dxResultIndex]; std::vector>& dy = m_cellScalarResults[dyResultIndex]; std::vector>& dz = m_cellScalarResults[dzResultIndex]; std::vector>& tops = m_cellScalarResults[topsResultIndex]; std::vector>& bottom = m_cellScalarResults[bottomResultIndex]; // Make sure the size is at least active cells { if ( depth[0].size() < actCellCount ) { depth[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeDepth = true; } if ( dx[0].size() < actCellCount ) { dx[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeDx = true; } if ( dy[0].size() < actCellCount ) { dy[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeDy = true; } if ( dz[0].size() < actCellCount ) { dz[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeDz = true; } if ( tops[0].size() < actCellCount ) { tops[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeTops = true; } if ( bottom[0].size() < actCellCount ) { bottom[0].resize( actCellCount, std::numeric_limits::max() ); buffers.computeBottom = true; } } buffers.depth = &depth[0]; buffers.dx = &dx[0]; buffers.dy = &dy[0]; buffers.dz = &dz[0]; buffers.tops = &tops[0]; buffers.bottom = &bottom[0]; return buffers; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeDepthRelatedResults( RigCaseCellResultsData* matrixResults, RigCaseCellResultsData* fractureResults ) { RigMainGrid* mainGrid = nullptr; if ( matrixResults ) mainGrid = matrixResults->m_ownerMainGrid; if ( !mainGrid && fractureResults ) mainGrid = fractureResults->m_ownerMainGrid; if ( !mainGrid ) return; // Collect the enabled (non-empty) porosity models. Both share the same main grid, so the // geometry of each cell only needs to be computed once and is written to every model in which // the cell is active. std::vector buffers; for ( RigCaseCellResultsData* results : { matrixResults, fractureResults } ) { if ( !results ) continue; DepthResultBuffers b = results->prepareDepthRelatedResultArrays(); if ( b.actCellCount == 0 ) continue; buffers.push_back( b ); } if ( buffers.empty() ) return; #pragma omp parallel for for ( long cellIdx = 0; cellIdx < static_cast( mainGrid->totalCellCount() ); cellIdx++ ) { const RigCell& cell = mainGrid->cell( cellIdx ); if ( cell.isInvalid() ) continue; const bool isTemporaryGrid = cell.hostGrid()->isTempGrid(); // Resolve this cell's result index in each enabled model, and gather which properties any // active model still needs (temporary grids are always recomputed). Skip the cell entirely // if it is inactive in every model. At most two porosity models (matrix and fracture) are // present. std::array resultIndices; bool anyActive = false; bool needDepth = isTemporaryGrid; bool needDx = isTemporaryGrid; bool needDy = isTemporaryGrid; bool needDz = isTemporaryGrid; bool needTops = isTemporaryGrid; bool needBottom = isTemporaryGrid; for ( size_t i = 0; i < buffers.size(); i++ ) { size_t resultIndex = buffers[i].activeCellInfo->cellResultIndex( ReservoirCellIndex( cellIdx ) ).value(); if ( resultIndex == cvf::UNDEFINED_SIZE_T || resultIndex >= buffers[i].actCellCount ) { resultIndices[i] = cvf::UNDEFINED_SIZE_T; continue; } resultIndices[i] = resultIndex; anyActive = true; needDepth = needDepth || buffers[i].computeDepth; needDx = needDx || buffers[i].computeDx; needDy = needDy || buffers[i].computeDy; needDz = needDz || buffers[i].computeDz; needTops = needTops || buffers[i].computeTops; needBottom = needBottom || buffers[i].computeBottom; } if ( !anyActive ) continue; // The geometry is shared between the porosity models, so each value is computed at most once // (only if some active model needs it) and then written to every active model that needs it. double depthValue = needDepth ? -cell.center().z() : 0.0; double dxValue = needDx ? ( cell.faceCenter( cvf::StructGridInterface::NEG_I ) - cell.faceCenter( cvf::StructGridInterface::POS_I ) ).length() : 0.0; double dyValue = needDy ? ( cell.faceCenter( cvf::StructGridInterface::NEG_J ) - cell.faceCenter( cvf::StructGridInterface::POS_J ) ).length() : 0.0; double dzValue = needDz ? ( cell.faceCenter( cvf::StructGridInterface::NEG_K ) - cell.faceCenter( cvf::StructGridInterface::POS_K ) ).length() : 0.0; double topsValue = needTops ? -cell.faceCenter( cvf::StructGridInterface::NEG_K ).z() : 0.0; double bottomValue = needBottom ? -cell.faceCenter( cvf::StructGridInterface::POS_K ).z() : 0.0; // Write a value into one model's result row, honoring its per-property compute flag. auto assign = [&]( std::vector* row, bool compute, size_t resultIndex, double value ) { if ( resultIndex != cvf::UNDEFINED_SIZE_T && ( compute || isTemporaryGrid ) ) { ( *row )[resultIndex] = value; } }; for ( size_t i = 0; i < buffers.size(); i++ ) { const DepthResultBuffers& b = buffers[i]; assign( b.depth, b.computeDepth, resultIndices[i], depthValue ); assign( b.dx, b.computeDx, resultIndices[i], dxValue ); assign( b.dy, b.computeDy, resultIndices[i], dyValue ); assign( b.dz, b.computeDz, resultIndices[i], dzValue ); assign( b.tops, b.computeTops, resultIndices[i], topsValue ); assign( b.bottom, b.computeBottom, resultIndices[i], bottomValue ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeIndexResults() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::indexIResultName( isRadialModel() ) ); RigIndexIjkResultCalculator calculator( *this ); calculator.calculate( addr, 0 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeFaultDistance() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::faultDistanceName() ); RigFaultDistanceResultCalculator calculator( *this ); calculator.calculate( addr, 0 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncsCells() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riNncCells() ); RigCellsWithNncsCalculator calculator( *this ); calculator.calculate( addr, 0 ); } namespace RigTransmissibilityCalcTools { void calculateConnectionGeometry( const RigCell& c1, const RigCell& c2, const std::vector& nodes, cvf::StructGridInterface::FaceType faceId, cvf::Vec3d* faceAreaVec ) { CAF_ASSERT( faceAreaVec ); *faceAreaVec = cvf::Vec3d::ZERO; std::vector polygon; std::vector intersections; std::array face1; std::array face2; c1.faceIndices( faceId, &face1 ); c2.faceIndices( cvf::StructGridInterface::oppositeFace( faceId ), &face2 ); bool foundOverlap = cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( polygon, intersections, (cvf::EdgeIntersectStorage*)nullptr, cvf::wrapArrayConst( &nodes ), face1.data(), face2.data(), 1e-6 ); if ( foundOverlap ) { std::vector realPolygon; for ( size_t pIdx = 0; pIdx < polygon.size(); ++pIdx ) { if ( polygon[pIdx] < nodes.size() ) realPolygon.push_back( nodes[polygon[pIdx]] ); else realPolygon.push_back( intersections[polygon[pIdx] - nodes.size()] ); } // Polygon area vector *faceAreaVec = cvf::GeometryTools::polygonAreaNormal3D( realPolygon ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double halfCellTransmissibility( double perm, double ntg, const cvf::Vec3d& centerToFace, const cvf::Vec3d& faceAreaVec ) { return perm * ntg * ( faceAreaVec * centerToFace ) / ( centerToFace * centerToFace ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double newtran( double cdarchy, double mult, double halfCellTrans, double neighborHalfCellTrans ) { if ( cvf::Math::abs( halfCellTrans ) < 1e-15 || cvf::Math::abs( neighborHalfCellTrans ) < 1e-15 ) { return 0.0; } double result = cdarchy * mult / ( ( 1 / halfCellTrans ) + ( 1 / neighborHalfCellTrans ) ); CAF_ASSERT( result == result ); return result; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- using ResultIndexFunction = size_t ( * )( const RigActiveCellInfo*, size_t ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t directReservoirCellIndex( const RigActiveCellInfo* activeCellinfo, size_t reservoirCellIndex ) { return reservoirCellIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t reservoirActiveCellIndex( const RigActiveCellInfo* activeCellinfo, size_t reservoirCellIndex ) { return activeCellinfo->cellResultIndex( ReservoirCellIndex( reservoirCellIndex ) ).value(); } } // namespace RigTransmissibilityCalcTools using namespace RigTransmissibilityCalcTools; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeRiTransComponent( const QString& riTransComponentResultName ) { // Set up which component to compute cvf::StructGridInterface::FaceType faceId = cvf::StructGridInterface::NO_FACE; QString permCompName; if ( riTransComponentResultName == RiaResultNames::riTranXResultName() ) { permCompName = "PERMX"; faceId = cvf::StructGridInterface::POS_I; } else if ( riTransComponentResultName == RiaResultNames::riTranYResultName() ) { permCompName = "PERMY"; faceId = cvf::StructGridInterface::POS_J; } else if ( riTransComponentResultName == RiaResultNames::riTranZResultName() ) { permCompName = "PERMZ"; faceId = cvf::StructGridInterface::POS_K; } else { CAF_ASSERT( false ); } double cdarchy = darchysValue(); // Get the needed result indices we depend on size_t permResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, permCompName ) ); size_t ntgResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "NTG" ) ); bool hasNTGResults = ntgResultIdx != cvf::UNDEFINED_SIZE_T; // Get the result index of the output size_t riTransResultIdx = findScalarResultIndexFromAddress( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, riTransComponentResultName ) ); CAF_ASSERT( riTransResultIdx != cvf::UNDEFINED_SIZE_T ); // Get the result count, to handle that one of them might be globally defined size_t permxResultValueCount = m_cellScalarResults[permResultIdx][0].size(); size_t resultValueCount = permxResultValueCount; if ( hasNTGResults ) { size_t ntgResultValueCount = m_cellScalarResults[ntgResultIdx][0].size(); resultValueCount = std::min( permxResultValueCount, ntgResultValueCount ); } // Get all the actual result values const std::vector& permResults = m_cellScalarResults[permResultIdx][0]; std::vector& riTransResults = m_cellScalarResults[riTransResultIdx][0]; std::vector* ntgResults = nullptr; if ( hasNTGResults ) { ntgResults = &( m_cellScalarResults[ntgResultIdx][0] ); } // Set up output container to correct number of results riTransResults.resize( resultValueCount ); // Prepare how to index the result values: ResultIndexFunction riTranIdxFunc = nullptr; ResultIndexFunction permIdxFunc = nullptr; ResultIndexFunction ntgIdxFunc = nullptr; { bool isPermUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, permCompName ) ); bool isTransUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, riTransComponentResultName ) ); bool isNtgUsingResIdx = false; if ( hasNTGResults ) { isNtgUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "NTG" ) ); } // Set up result index function pointers riTranIdxFunc = isTransUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; permIdxFunc = isPermUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; if ( hasNTGResults ) { ntgIdxFunc = isNtgUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; } } const RigActiveCellInfo* activeCellInfo = this->activeCellInfo(); const std::vector& nodes = m_ownerMainGrid->nodes(); bool isFaceNormalsOutwards = m_ownerMainGrid->isFaceNormalsOutwards(); for ( size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->totalCellCount(); nativeResvCellIndex++ ) { // Do nothing if we are only dealing with active cells, and this cell is not active: size_t tranResIdx = ( *riTranIdxFunc )( activeCellInfo, nativeResvCellIndex ); if ( tranResIdx == cvf::UNDEFINED_SIZE_T ) continue; const RigCell& nativeCell = m_ownerMainGrid->cell( nativeResvCellIndex ); RigGridBase* grid = nativeCell.hostGrid(); size_t gridLocalNativeCellIndex = nativeCell.gridLocalCellIndex(); size_t i, j, k, gridLocalNeighborCellIdx; grid->ijkFromCellIndex( gridLocalNativeCellIndex, &i, &j, &k ); if ( grid->cellIJKNeighbor( i, j, k, faceId, &gridLocalNeighborCellIdx ) ) { size_t neighborResvCellIdx = grid->reservoirCellIndex( gridLocalNeighborCellIdx ); const RigCell& neighborCell = m_ownerMainGrid->cell( neighborResvCellIdx ); // Do nothing if this cell has no permeability result. The transmissibility and the permeability results can use // different indexing, so a defined transmissibility index does not imply a defined permeability index. size_t nativeCellPermResIdx = ( *permIdxFunc )( activeCellInfo, nativeResvCellIndex ); if ( nativeCellPermResIdx == cvf::UNDEFINED_SIZE_T ) continue; // Do nothing if neighbor cell has no results size_t neighborCellPermResIdx = ( *permIdxFunc )( activeCellInfo, neighborResvCellIdx ); if ( neighborCellPermResIdx == cvf::UNDEFINED_SIZE_T ) continue; // Connection geometry const RigFault* fault = grid->mainGrid()->findFaultFromCellIndexAndCellFace( nativeResvCellIndex, faceId ); bool isOnFault = fault; cvf::Vec3d faceAreaVec; cvf::Vec3d faceCenter; if ( isOnFault ) { calculateConnectionGeometry( nativeCell, neighborCell, nodes, faceId, &faceAreaVec ); } else { faceAreaVec = nativeCell.faceNormalWithAreaLength( faceId ); } if ( !isFaceNormalsOutwards ) faceAreaVec = -faceAreaVec; double halfCellTrans = 0; double neighborHalfCellTrans = 0; // Native cell half cell transm { cvf::Vec3d centerToFace = nativeCell.faceCenter( faceId ) - nativeCell.center(); double perm = permResults[nativeCellPermResIdx]; double ntg = 1.0; if ( hasNTGResults && faceId != cvf::StructGridInterface::POS_K ) { size_t ntgResIdx = ( *ntgIdxFunc )( activeCellInfo, nativeResvCellIndex ); ntg = ( *ntgResults )[ntgResIdx]; } halfCellTrans = halfCellTransmissibility( perm, ntg, centerToFace, faceAreaVec ); } // Neighbor cell half cell transm { cvf::Vec3d centerToFace = neighborCell.faceCenter( cvf::StructGridInterface::oppositeFace( faceId ) ) - neighborCell.center(); double perm = permResults[neighborCellPermResIdx]; double ntg = 1.0; if ( hasNTGResults && faceId != cvf::StructGridInterface::POS_K ) { size_t ntgResIdx = ( *ntgIdxFunc )( activeCellInfo, neighborResvCellIdx ); ntg = ( *ntgResults )[ntgResIdx]; } neighborHalfCellTrans = halfCellTransmissibility( perm, ntg, centerToFace, -faceAreaVec ); } riTransResults[tranResIdx] = newtran( cdarchy, 1.0, halfCellTrans, neighborHalfCellTrans ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiTrans() { RigEclipseResultAddress riCombTransEclResAddr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiTranResultName() ); if ( m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombTransEclResAddr ) ) return; double cdarchy = darchysValue(); // Get the needed result indices we depend on size_t permXResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMX" ) ); size_t permYResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMY" ) ); size_t permZResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMZ" ) ); size_t ntgResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "NTG" ) ); bool hasNTGResults = ntgResultIdx != cvf::UNDEFINED_SIZE_T; // Get all the actual result values std::vector& permXResults = m_cellScalarResults[permXResultIdx][0]; std::vector& permYResults = m_cellScalarResults[permYResultIdx][0]; std::vector& permZResults = m_cellScalarResults[permZResultIdx][0]; std::vector& riCombTransResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult( RiaDefines::propertyNameRiCombTrans() ); m_ownerMainGrid->nncData()->setEclResultAddress( RiaDefines::propertyNameRiCombTrans(), riCombTransEclResAddr ); std::vector* ntgResults = nullptr; if ( hasNTGResults ) { ntgResults = &( m_cellScalarResults[ntgResultIdx][0] ); } // Prepare how to index the result values: ResultIndexFunction permXIdxFunc = nullptr; ResultIndexFunction permYIdxFunc = nullptr; ResultIndexFunction permZIdxFunc = nullptr; ResultIndexFunction ntgIdxFunc = nullptr; { bool isPermXUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMX" ) ); bool isPermYUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMY" ) ); bool isPermZUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMZ" ) ); bool isNtgUsingResIdx = false; if ( hasNTGResults ) { isNtgUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "NTG" ) ); } // Set up result index function pointers permXIdxFunc = isPermXUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; permYIdxFunc = isPermYUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; permZIdxFunc = isPermZUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; if ( hasNTGResults ) { ntgIdxFunc = isNtgUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; } } const RigActiveCellInfo* activeCellInfo = this->activeCellInfo(); bool isFaceNormalsOutwards = m_ownerMainGrid->isFaceNormalsOutwards(); // NNC calculation const RigConnectionContainer& nncConnections = m_ownerMainGrid->nncData()->allConnections(); for ( size_t connIdx = 0; connIdx < nncConnections.size(); connIdx++ ) { size_t nativeResvCellIndex = nncConnections[connIdx].c1GlobIdx(); size_t neighborResvCellIdx = nncConnections[connIdx].c2GlobIdx(); cvf::StructGridInterface::FaceType faceId = static_cast( nncConnections[connIdx].face() ); ResultIndexFunction permIdxFunc = nullptr; std::vector* permResults = nullptr; switch ( faceId ) { case cvf::StructGridInterface::POS_I: case cvf::StructGridInterface::NEG_I: permIdxFunc = permXIdxFunc; permResults = &permXResults; break; case cvf::StructGridInterface::POS_J: case cvf::StructGridInterface::NEG_J: permIdxFunc = permYIdxFunc; permResults = &permYResults; break; case cvf::StructGridInterface::POS_K: case cvf::StructGridInterface::NEG_K: permIdxFunc = permZIdxFunc; permResults = &permZResults; break; default: break; } if ( !permIdxFunc ) continue; // Do nothing if we are only dealing with active cells, and this cell is not active: size_t nativeCellPermResIdx = ( *permIdxFunc )( activeCellInfo, nativeResvCellIndex ); if ( nativeCellPermResIdx == cvf::UNDEFINED_SIZE_T ) continue; // Do nothing if neighbor cell has no results size_t neighborCellPermResIdx = ( *permIdxFunc )( activeCellInfo, neighborResvCellIdx ); if ( neighborCellPermResIdx == cvf::UNDEFINED_SIZE_T ) continue; const RigCell& nativeCell = m_ownerMainGrid->cell( nativeResvCellIndex ); const RigCell& neighborCell = m_ownerMainGrid->cell( neighborResvCellIdx ); // Connection geometry cvf::Vec3f faceAreaVec = cvf::Vec3f::ZERO; cvf::Vec3f faceCenter = cvf::Vec3f::ZERO; // Polygon center const std::vector& realPolygon = nncConnections[connIdx].polygon(); for ( size_t pIdx = 0; pIdx < realPolygon.size(); ++pIdx ) { faceCenter += realPolygon[pIdx]; } faceCenter *= 1.0 / realPolygon.size(); // Polygon area vector faceAreaVec = cvf::GeometryTools::polygonAreaNormal3D( realPolygon ); if ( !isFaceNormalsOutwards ) faceAreaVec = -faceAreaVec; double halfCellTrans = 0; double neighborHalfCellTrans = 0; // Native cell half cell transm { cvf::Vec3d centerToFace = nativeCell.faceCenter( faceId ) - nativeCell.center(); double perm = ( *permResults )[nativeCellPermResIdx]; double ntg = 1.0; if ( hasNTGResults && faceId != cvf::StructGridInterface::POS_K ) { size_t ntgResIdx = ( *ntgIdxFunc )( activeCellInfo, nativeResvCellIndex ); ntg = ( *ntgResults )[ntgResIdx]; } halfCellTrans = halfCellTransmissibility( perm, ntg, centerToFace, cvf::Vec3d( faceAreaVec ) ); } // Neighbor cell half cell transm { cvf::Vec3d centerToFace = neighborCell.faceCenter( cvf::StructGridInterface::oppositeFace( faceId ) ) - neighborCell.center(); double perm = ( *permResults )[neighborCellPermResIdx]; double ntg = 1.0; if ( hasNTGResults && faceId != cvf::StructGridInterface::POS_K ) { size_t ntgResIdx = ( *ntgIdxFunc )( activeCellInfo, neighborResvCellIdx ); ntg = ( *ntgResults )[ntgResIdx]; } neighborHalfCellTrans = halfCellTransmissibility( perm, ntg, centerToFace, -cvf::Vec3d( faceAreaVec ) ); } double newtranTemp = newtran( cdarchy, 1.0, halfCellTrans, neighborHalfCellTrans ); riCombTransResults[connIdx] = newtranTemp; } } double riMult( double transResults, double riTransResults ) { if ( transResults == HUGE_VAL || riTransResults == HUGE_VAL ) return HUGE_VAL; const double epsilon = 1e-9; if ( cvf::Math::abs( riTransResults ) < epsilon ) { if ( cvf::Math::abs( transResults ) < epsilon ) { return 0.0; } return HUGE_VAL; } double result = transResults / riTransResults; return result; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeRiMULTComponent( const QString& riMultCompName ) { // Set up which component to compute QString riTransCompName; QString transCompName; if ( riMultCompName == RiaResultNames::riMultXResultName() ) { riTransCompName = RiaResultNames::riTranXResultName(); transCompName = "TRANX"; } else if ( riMultCompName == RiaResultNames::riMultYResultName() ) { riTransCompName = RiaResultNames::riTranYResultName(); transCompName = "TRANY"; } else if ( riMultCompName == RiaResultNames::riMultZResultName() ) { riTransCompName = RiaResultNames::riTranZResultName(); transCompName = "TRANZ"; } else { CAF_ASSERT( false ); } // Get the needed result indices we depend on size_t transResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, transCompName ) ); size_t riTransResultIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, riTransCompName ) ); // Get the result index of the output size_t riMultResultIdx = findScalarResultIndexFromAddress( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, riMultCompName ) ); CAF_ASSERT( riMultResultIdx != cvf::UNDEFINED_SIZE_T ); // Get the result count, to handle that one of them might be globally defined CAF_ASSERT( m_cellScalarResults[riTransResultIdx][0].size() == m_cellScalarResults[transResultIdx][0].size() ); size_t resultValueCount = m_cellScalarResults[transResultIdx][0].size(); // Get all the actual result values const std::vector& riTransResults = m_cellScalarResults[riTransResultIdx][0]; const std::vector& transResults = m_cellScalarResults[transResultIdx][0]; std::vector& riMultResults = m_cellScalarResults[riMultResultIdx][0]; // Set up output container to correct number of results riMultResults.resize( resultValueCount ); for ( size_t vIdx = 0; vIdx < transResults.size(); ++vIdx ) { riMultResults[vIdx] = riMult( transResults[vIdx], riTransResults[vIdx] ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiMULT() { auto riCombMultEclResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiMultResultName() ); auto riCombTransEclResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiTranResultName() ); auto combTransEclResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedTransmissibilityResultName() ); if ( m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombMultEclResAddr ) ) return; const std::vector* riTransResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombTransEclResAddr ); const std::vector* transResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( combTransEclResAddr ); if ( riTransResults && transResults && ( riTransResults->size() == transResults->size() ) ) { std::vector& riMultResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult( RiaDefines::propertyNameRiCombMult() ); m_ownerMainGrid->nncData()->setEclResultAddress( RiaDefines::propertyNameRiCombMult(), riCombMultEclResAddr ); for ( size_t nncConIdx = 0; nncConIdx < riMultResults.size(); ++nncConIdx ) { riMultResults[nncConIdx] = riMult( ( *transResults )[nncConIdx], ( *riTransResults )[nncConIdx] ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeRiTRANSbyAreaComponent( const QString& riTransByAreaCompResultName ) { // Set up which component to compute cvf::StructGridInterface::FaceType faceId = cvf::StructGridInterface::NO_FACE; QString transCompName; if ( riTransByAreaCompResultName == RiaResultNames::riAreaNormTranXResultName() ) { transCompName = "TRANX"; faceId = cvf::StructGridInterface::POS_I; } else if ( riTransByAreaCompResultName == RiaResultNames::riAreaNormTranYResultName() ) { transCompName = "TRANY"; faceId = cvf::StructGridInterface::POS_J; } else if ( riTransByAreaCompResultName == RiaResultNames::riAreaNormTranZResultName() ) { transCompName = "TRANZ"; faceId = cvf::StructGridInterface::POS_K; } else { CAF_ASSERT( false ); } // Get the needed result indices we depend on size_t tranCompScResIdx = findOrLoadKnownScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, transCompName ) ); // Get the result index of the output size_t riTranByAreaScResIdx = findScalarResultIndexFromAddress( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, riTransByAreaCompResultName ) ); CAF_ASSERT( riTranByAreaScResIdx != cvf::UNDEFINED_SIZE_T ); // Get the result count, to handle that one of them might be globally defined size_t resultValueCount = m_cellScalarResults[tranCompScResIdx][0].size(); // Get all the actual result values const std::vector& transResults = m_cellScalarResults[tranCompScResIdx][0]; std::vector& riTransByAreaResults = m_cellScalarResults[riTranByAreaScResIdx][0]; // Set up output container to correct number of results riTransByAreaResults.resize( resultValueCount ); // Prepare how to index the result values: bool isUsingResIdx = isUsingGlobalActiveIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, transCompName ) ); // Set up result index function pointers ResultIndexFunction resValIdxFunc = isUsingResIdx ? &reservoirActiveCellIndex : &directReservoirCellIndex; const RigActiveCellInfo* activeCellInfo = this->activeCellInfo(); const std::vector& nodes = m_ownerMainGrid->nodes(); for ( size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->totalCellCount(); nativeResvCellIndex++ ) { // Do nothing if we are only dealing with active cells, and this cell is not active: size_t nativeCellResValIdx = ( *resValIdxFunc )( activeCellInfo, nativeResvCellIndex ); if ( nativeCellResValIdx == cvf::UNDEFINED_SIZE_T ) continue; const RigCell& nativeCell = m_ownerMainGrid->cell( nativeResvCellIndex ); RigGridBase* grid = nativeCell.hostGrid(); size_t gridLocalNativeCellIndex = nativeCell.gridLocalCellIndex(); size_t i, j, k, gridLocalNeighborCellIdx; grid->ijkFromCellIndex( gridLocalNativeCellIndex, &i, &j, &k ); if ( grid->cellIJKNeighbor( i, j, k, faceId, &gridLocalNeighborCellIdx ) ) { size_t neighborResvCellIdx = grid->reservoirCellIndex( gridLocalNeighborCellIdx ); const RigCell& neighborCell = m_ownerMainGrid->cell( neighborResvCellIdx ); // Connection geometry const RigFault* fault = grid->mainGrid()->findFaultFromCellIndexAndCellFace( nativeResvCellIndex, faceId ); bool isOnFault = fault; cvf::Vec3d faceAreaVec; if ( isOnFault ) { calculateConnectionGeometry( nativeCell, neighborCell, nodes, faceId, &faceAreaVec ); } else { faceAreaVec = nativeCell.faceNormalWithAreaLength( faceId ); } double areaOfOverlap = faceAreaVec.length(); double transCompValue = transResults[nativeCellResValIdx]; riTransByAreaResults[nativeCellResValIdx] = transCompValue / areaOfOverlap; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiTRANSbyArea() { auto riCombTransByAreaEclResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedRiAreaNormTranResultName() ); auto combTransEclResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::combinedTransmissibilityResultName() ); if ( m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombTransByAreaEclResAddr ) ) return; const std::vector* transResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( combTransEclResAddr ); if ( !transResults ) return; std::vector& riAreaNormTransResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult( RiaDefines::propertyNameRiCombTransByArea() ); m_ownerMainGrid->nncData()->setEclResultAddress( RiaDefines::propertyNameRiCombTransByArea(), riCombTransByAreaEclResAddr ); if ( transResults->size() != riAreaNormTransResults.size() ) return; const RigConnectionContainer& connections = m_ownerMainGrid->nncData()->allConnections(); for ( size_t nncConIdx = 0; nncConIdx < riAreaNormTransResults.size(); ++nncConIdx ) { const std::vector& realPolygon = connections[nncConIdx].polygon(); cvf::Vec3f faceAreaVec = cvf::GeometryTools::polygonAreaNormal3D( realPolygon ); double areaOfOverlap = faceAreaVec.length(); riAreaNormTransResults[nncConIdx] = ( *transResults )[nncConIdx] / areaOfOverlap; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeCompletionTypeForTimeStep( size_t timeStep ) { size_t completionTypeResultIndex = findScalarResultIndexFromAddress( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::completionTypeResultName() ) ); if ( m_cellScalarResults[completionTypeResultIndex].size() < maxTimeStepCount() ) { m_cellScalarResults[completionTypeResultIndex].resize( maxTimeStepCount() ); } computeCompletionTypeForFrame( m_cellScalarResults[completionTypeResultIndex][timeStep], timeStep ); } //-------------------------------------------------------------------------------------------------- /// Static completion type: a single frame, computed independent of simulation time steps. Used when /// only grid geometry is loaded (no restart). See issue #14127. //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeStaticCompletionType() { size_t completionTypeResultIndex = findScalarResultIndexFromAddress( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::completionTypeResultName() ) ); if ( completionTypeResultIndex == cvf::UNDEFINED_SIZE_T ) return; if ( m_cellScalarResults[completionTypeResultIndex].empty() ) { m_cellScalarResults[completionTypeResultIndex].resize( 1 ); } // calcTimeStep 0: RigVirtualPerforationTransmissibilities::multipleCompletionsPerEclipseCell clamps to the single // available frame, and RimEclipseCase::computeAndGetVirtualPerforationTransmissibilities builds exactly one frame // when timeStepDates() is empty. computeCompletionTypeForFrame( m_cellScalarResults[completionTypeResultIndex][0], 0 ); } //-------------------------------------------------------------------------------------------------- /// Core computation populating a single completion-type frame. calcTimeStep is the time step passed to /// calculateCompletionTypeResult; it is clamped to a valid virtual-perforation frame downstream. //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeCompletionTypeForFrame( std::vector& frameValues, size_t calcTimeStep ) { size_t resultValues = m_ownerMainGrid->totalCellCount(); if ( frameValues.size() == resultValues ) { return; } frameValues.resize( resultValues ); std::fill( frameValues.begin(), frameValues.end(), HUGE_VAL ); RimEclipseCase* eclipseCase = m_ownerCaseData->ownerCase(); if ( !eclipseCase ) return; triggerGeneratedPermeabilityCalculations( eclipseCase ); RimCompletionCellIntersectionCalc::calculateCompletionTypeResult( eclipseCase, frameValues, calcTimeStep ); } //-------------------------------------------------------------------------------------------------- /// If permeabilities are generated by calculations, make sure that generated data is calculated. /// See RicExportFractureCompletionsImpl::generateCompdatValues() //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::triggerGeneratedPermeabilityCalculations( RimEclipseCase* eclipseCase ) { for ( const QString propertyName : { "PERMX", "PERMY", "PERMZ" } ) { for ( auto userCalculation : RimProject::current()->gridCalculationCollection()->calculations() ) { if ( auto gridCalculation = dynamic_cast( userCalculation ) ) { auto outputCases = gridCalculation->outputEclipseCases(); if ( std::find( outputCases.begin(), outputCases.end(), eclipseCase ) == outputCases.end() ) continue; } QString generatedPropertyName = RimUserDefinedCalculation::findLeftHandSide( userCalculation->expression() ); if ( generatedPropertyName == propertyName ) { userCalculation->calculate(); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RigCaseCellResultsData::darchysValue() { return RiaEclipseUnitTools::darcysConstant( m_ownerCaseData->unitsType() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeCellVolumes() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riCellVolumeResultName() ); RigCellVolumeResultCalculator calculator( *this ); calculator.calculate( addr, 0 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeOilVolumes() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::riOilVolumeResultName() ); RigOilVolumeResultCalculator calculator( *this ); // Computes for all time steps calculator.calculate( addr, -1 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computePorvSoilSgas() { std::vector results = { RiaResultNames::riPorvSoil(), RiaResultNames::riPorvSgas(), RiaResultNames::riPorvSoilSgas() }; RigPorvSoilSgasResultCalculator calculator( *this ); for ( QString resultName : results ) { RigEclipseResultAddress addr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, resultName ); // Computes for all time steps calculator.calculate( addr, -1 ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeMobilePV() { RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::mobilePoreVolumeName() ); RigMobilePoreVolumeResultCalculator calculator( *this ); calculator.calculate( addr, 0 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setReaderInterface( RifReaderInterface* readerInterface ) { m_readerInterface = readerInterface; if ( m_ownerMainGrid ) { m_readerInterface->updateFromGridCount( m_ownerMainGrid->gridCount() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RifReaderInterface* RigCaseCellResultsData::readerInterface() const { return m_readerInterface.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setHdf5Filename( const QString& hdf5SourSimFilename ) { RifReaderEclipseOutput* rifReaderOutput = dynamic_cast( m_readerInterface.p() ); if ( rifReaderOutput ) { rifReaderOutput->setHdf5FileName( hdf5SourSimFilename ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setActiveFormationNames( const RigFormationNames* activeFormationNames ) { // Store a copy, as the owning RimFormationNames can be reloaded or deleted while this data is in use m_activeFormationNamesData = activeFormationNames ? *activeFormationNames : RigFormationNames(); if ( !activeFormationNames ) { clearScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::FORMATION_NAMES, RiaResultNames::activeFormationNamesResultName() ) ); return; } size_t totalGlobCellCount = m_ownerMainGrid->totalCellCount(); addStaticScalarResult( RiaDefines::ResultCatType::FORMATION_NAMES, RiaResultNames::activeFormationNamesResultName(), false, totalGlobCellCount ); std::vector* fnData = modifiableCellScalarResult( RigEclipseResultAddress( RiaDefines::ResultCatType::FORMATION_NAMES, RiaResultNames::activeFormationNamesResultName() ), 0 ); if ( m_activeFormationNamesData.isEmpty() ) { for ( size_t cIdx = 0; cIdx < totalGlobCellCount; ++cIdx ) { fnData->at( cIdx ) = HUGE_VAL; } } else { size_t localCellCount = m_ownerMainGrid->cellCount(); for ( size_t cIdx = 0; cIdx < localCellCount; ++cIdx ) { size_t i( cvf::UNDEFINED_SIZE_T ), j( cvf::UNDEFINED_SIZE_T ), k( cvf::UNDEFINED_SIZE_T ); if ( !m_ownerMainGrid->ijkFromCellIndex( cIdx, &i, &j, &k ) ) continue; int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx( k ); if ( formNameIdx != -1 ) { fnData->at( cIdx ) = formNameIdx; } else { fnData->at( cIdx ) = HUGE_VAL; } } for ( size_t cIdx = localCellCount; cIdx < totalGlobCellCount; ++cIdx ) { size_t mgrdCellIdx = m_ownerMainGrid->cell( cIdx ).mainGridCellIndex(); size_t i( cvf::UNDEFINED_SIZE_T ), j( cvf::UNDEFINED_SIZE_T ), k( cvf::UNDEFINED_SIZE_T ); if ( !m_ownerMainGrid->ijkFromCellIndex( mgrdCellIdx, &i, &j, &k ) ) continue; int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx( k ); if ( formNameIdx != -1 ) { fnData->at( cIdx ) = formNameIdx; } else { fnData->at( cIdx ) = HUGE_VAL; } } } // As the Allan formation diagram is depending on formation results, we need to clear the data set // Will be recomputed when required auto fnNamesResAddr = RigEclipseResultAddress( RiaDefines::ResultCatType::ALLAN_DIAGRAMS, RiaResultNames::formationAllanResultName() ); clearScalarResult( fnNamesResAddr ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RigFormationNames* RigCaseCellResultsData::activeFormationNames() const { return m_activeFormationNamesData.isEmpty() ? nullptr : &m_activeFormationNamesData; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigAllanDiagramData* RigCaseCellResultsData::allanDiagramData() { return m_allanDiagramData.p(); } //-------------------------------------------------------------------------------------------------- /// If we have any results on any time step, assume we have loaded results //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::isDataPresent( size_t scalarResultIndex ) const { return allocatedValueCount( scalarResultIndex ) > 0; } //-------------------------------------------------------------------------------------------------- /// Returns true for results that are computed by ResInsight and can not be read from file //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::isResultComputedByResInsight( const QString& resultName, size_t scalarResultIndex ) const { return mustBeCalculated( scalarResultIndex ) || resultName == RiaResultNames::riCellVolumeResultName() || resultName == RiaResultNames::riOilVolumeResultName() || resultName == RiaResultNames::riPorvSoil() || resultName == RiaResultNames::riPorvSgas() || resultName == RiaResultNames::riPorvSoilSgas(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::hasEmptyDataForAnyTimeStep( size_t scalarResultIndex ) const { if ( scalarResultIndex >= resultCount() ) return false; const std::vector>& valuesAllTimeSteps = m_cellScalarResults[scalarResultIndex]; return std::any_of( valuesAllTimeSteps.begin(), valuesAllTimeSteps.end(), []( const auto& values ) { return values.empty(); } ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::allocatedValueCount( size_t scalarResultIndex ) const { if ( scalarResultIndex >= resultCount() ) return 0; const std::vector>& valuesAllTimeSteps = m_cellScalarResults[scalarResultIndex]; size_t valueCount = 0; for ( const auto& values : valuesAllTimeSteps ) { valueCount += values.size(); } return valueCount; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::assignValuesToTemporaryLgrs( const QString& resultName, std::vector& valuesForAllReservoirCells ) { CAF_ASSERT( m_activeCellInfo ); static std::vector excludedProperties = { "MOBPROV", "PORV", "FIPOIL", "FIPGAS", "FIPWAT", "FLROILI+", "FLROILJ+", "FLROILK+", "FLRGASI+", "FLRGASJ+", "FLRGASK+", "FLRWATI+", "FLRWATJ+", "FLRWATK+", "FLOOILI+", "FLOWATI+", "FLOGASI+", "FLOOILJ+", "FLOWATJ+", "FLOGASJ+", "FLOOILK+", "FLOWATK+", "FLOGASK+", "SFIPGAS", "SFIPOIL", "SFIPWAT", "AREAX", "AREAY", "AREAZ", "DIFFX", "DIFFY", "DIFFZ", "DZNET", "HEATTX", "HEATTY", "HEATTZ", "LX", "LY", "LZ", "MINPVV", "TRANX", "TRANY", "TRANZ", }; if ( std::find( excludedProperties.begin(), excludedProperties.end(), resultName ) != excludedProperties.end() ) { return; } if ( m_resultAliasMap.contains( resultName ) ) { return; } bool invalidCellsDetected = false; for ( size_t gridIdx = 0; gridIdx < m_ownerMainGrid->gridCount(); gridIdx++ ) { const auto& grid = m_ownerMainGrid->gridByIndex( gridIdx ); if ( grid->isTempGrid() ) { for ( size_t localCellIdx = 0; localCellIdx < grid->cellCount(); localCellIdx++ ) { const RigCell& cell = grid->cell( localCellIdx ); size_t mainGridCellIndex = cell.mainGridCellIndex(); size_t reservoirCellIndex = grid->reservoirCellIndex( localCellIdx ); size_t mainGridCellResultIndex = m_activeCellInfo->cellResultIndex( ReservoirCellIndex( mainGridCellIndex ) ).value(); size_t cellResultIndex = m_activeCellInfo->cellResultIndex( ReservoirCellIndex( reservoirCellIndex ) ).value(); if ( mainGridCellResultIndex != cvf::UNDEFINED_SIZE_T && cellResultIndex != cvf::UNDEFINED_SIZE_T ) { double mainGridValue = valuesForAllReservoirCells[mainGridCellResultIndex]; valuesForAllReservoirCells[cellResultIndex] = mainGridValue; } else { invalidCellsDetected = true; } } } } if ( invalidCellsDetected ) { RiaLogging::warning( "Detected invalid/undefined cells when assigning result values to temporary LGRs" ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigStatisticsDataCache* RigCaseCellResultsData::statistics( const RigEclipseResultAddress& resVarAddr ) { size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr ); CAF_ASSERT( scalarResultIndex < m_statisticsDataCache.size() ); return m_statisticsDataCache[scalarResultIndex].p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RigCaseCellResultsData::isRadialModel() const { if ( !m_ownerMainGrid ) return false; return m_ownerMainGrid->isRadial(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findScalarResultIndexFromAddress( const RigEclipseResultAddress& resVarAddrOrg ) const { auto resVarAddr( resVarAddrOrg ); if ( m_resultAliasMap.contains( resVarAddrOrg.resultName() ) ) { resVarAddr.setResultName( m_resultAliasMap.at( resVarAddrOrg.resultName() ) ); } if ( !resVarAddrOrg.isValid() ) { return cvf::UNDEFINED_SIZE_T; } else if ( resVarAddr.resultCatType() == RiaDefines::ResultCatType::UNDEFINED ) { RigEclipseResultAddress resVarAddressWithType = resVarAddr; resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::STATIC_NATIVE ); size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::DYNAMIC_NATIVE ); scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); } if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::SOURSIMRL ); scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); } if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::GENERATED ); scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); } if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::INPUT_PROPERTY ); scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); } if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { resVarAddressWithType.setResultCatType( RiaDefines::ResultCatType::FORMATION_NAMES ); scalarResultIndex = findScalarResultIndexFromAddress( resVarAddressWithType ); } return scalarResultIndex; } else { auto index = m_addressToResultIndexMap.find( resVarAddr ); if ( index != m_addressToResultIndexMap.end() ) { return index->second; } return cvf::UNDEFINED_SIZE_T; } } #include "RimEclipseResultCase.h" //-------------------------------------------------------------------------------------------------- /// Copy result meta data from main case to all other cases in grid case group /// This code was originally part of RimStatisticsCaseEvaluator, but moved here to be a general solution /// for all cases //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::copyResultsMetaDataFromMainCase( RigEclipseCaseData* mainCaseResultsData, RiaDefines::PorosityModelType poroModel, std::vector destinationCases ) { std::vector resAddresses = mainCaseResultsData->results( poroModel )->existingResults(); std::vector timeStepInfos; if ( !resAddresses.empty() ) { timeStepInfos = mainCaseResultsData->results( poroModel )->timeStepInfos( resAddresses[0] ); } const std::vector resultInfos = mainCaseResultsData->results( poroModel )->infoForEachResultIndex(); for ( size_t i = 0; i < destinationCases.size(); i++ ) { RimEclipseResultCase* rimReservoir = dynamic_cast( destinationCases[i] ); if ( !rimReservoir ) continue; // Input reservoir if ( mainCaseResultsData == rimReservoir->eclipseCaseData() ) continue; // Do not copy on top of itself RigCaseCellResultsData* cellResultsStorage = rimReservoir->results( poroModel ); for ( size_t resIdx = 0; resIdx < resultInfos.size(); resIdx++ ) { RigEclipseResultAddress resVarAddr = resultInfos[resIdx].eclipseResultAddress(); bool needsToBeStored = resultInfos[resIdx].needsToBeStored(); bool mustBeCalculated = resultInfos[resIdx].mustBeCalculated(); size_t scalarResultIndex = cellResultsStorage->findScalarResultIndexFromAddress( resVarAddr ); if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) { cellResultsStorage->createResultEntry( resVarAddr, needsToBeStored ); if ( mustBeCalculated ) { scalarResultIndex = cellResultsStorage->findScalarResultIndexFromAddress( resVarAddr ); cellResultsStorage->setMustBeCalculated( scalarResultIndex ); } cellResultsStorage->setTimeStepInfos( resVarAddr, timeStepInfos ); std::vector>* dataValues = cellResultsStorage->modifiableCellScalarResultTimesteps( resVarAddr ); dataValues->resize( timeStepInfos.size() ); } } cellResultsStorage->createPlaceholderResultEntries(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::setStatisticsDataCacheNumBins( const RigEclipseResultAddress& resultAddress, size_t numBins ) { statistics( resultAddress )->setNumBins( numBins ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::addResultAlias( QString originalResultName, QString aliasResultName ) { m_resultAliasMap[aliasResultName] = originalResultName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::clearAllResultAliases() { m_resultAliasMap.clear(); }