Files
ResInsight/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp
T
Kristian Bendiksen e85137db6e #14345 Recompute calculated results when data for a time step has been released
The grid calculator releases result data per time step to reduce memory
usage when calculating for many cases. If only some time steps are
released, findOrLoadKnownScalarResult() returned early because data was
present for other time steps, leaving the released time steps empty.
Results computed by ResInsight, like riOILVOLUME, then appeared as
undefined in the 3d view after running a calculation for a selected
time step.

Recompute results computed by ResInsight when data is missing for any
time step. Skip the delegation from the single time step variant when
the requested time step already has data, to avoid repeated
recomputation while the calculator releases other time steps.
2026-09-07 11:18:09 +02:00

3431 lines
152 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011- Statoil ASA
// Copyright (C) 2013- Ceetron Solutions AS
// Copyright (C) 2011-2012 Ceetron AS
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RigCaseCellResultsData.h"
#include "RiaDefines.h"
#include "RiaEclipseUnitTools.h"
#include "RiaLogging.h"
#include "RiaPreferencesGrid.h"
#include "RiaPreferencesSystem.h"
#include "RiaResultNames.h"
#include "RifReaderEclipseOutput.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 <QDateTime>
#include <algorithm>
#include <array>
#include <cmath>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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<size_t>& RigCaseCellResultsData::cellScalarValuesHistogram( const RigEclipseResultAddress& resVarAddr )
{
return statistics( resVarAddr )->cellScalarValuesHistogram();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& 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<int>& 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<std::string, size_t> RigCaseCellResultsData::resultValueCount() const
{
std::map<std::string, size_t> 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<std::vector<double>>& RigCaseCellResultsData::cellScalarResults( const RigEclipseResultAddress& resVarAddr ) const
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
CAF_ASSERT( scalarResultIndex < resultCount() );
return m_cellScalarResults[scalarResultIndex];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<double>>* RigCaseCellResultsData::modifiableCellScalarResultTimesteps( const RigEclipseResultAddress& resVarAddr )
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
CAF_ASSERT( scalarResultIndex < resultCount() );
return &( m_cellScalarResults[scalarResultIndex] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double>* 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<double>& 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<std::vector<double>>() );
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<RigStatisticsCalculator> statisticsCalculator;
if ( resultName == RiaResultNames::combinedTransmissibilityResultName() )
{
cvf::ref<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseMultiPropertyStatCalc> 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<RigEclipseAllanFaultsStatCalc> calc = new RigEclipseAllanFaultsStatCalc( m_ownerMainGrid->nncData(), resVarAddr );
statisticsCalculator = calc;
}
else
{
statisticsCalculator = new RigEclipseNativeStatCalc( this, resVarAddr );
}
cvf::ref<RigStatisticsDataCache> 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<RigEclipseResultInfo>::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<int>& 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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RigCaseCellResultsData::allTimeStepDatesFromEclipseReader() const
{
const RifReaderEclipseOutput* rifReaderOutput = dynamic_cast<const RifReaderEclipseOutput*>( m_readerInterface.p() );
if ( rifReaderOutput )
{
return rifReaderOutput->allTimeSteps();
}
else
{
return std::vector<QDateTime>();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RigCaseCellResultsData::timeStepDates( const RigEclipseResultAddress& resVarAddr ) const
{
if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() )
{
return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].dates();
}
else
return std::vector<QDateTime>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RigCaseCellResultsData::timeStepDates() const
{
RigEclipseResultAddress scalarResWithMostTimeSteps;
maxTimeStepCount( &scalarResWithMostTimeSteps );
return timeStepDates( scalarResWithMostTimeSteps );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigCaseCellResultsData::daysSinceSimulationStart() const
{
RigEclipseResultAddress scalarResWithMostTimeSteps;
maxTimeStepCount( &scalarResWithMostTimeSteps );
return daysSinceSimulationStart( scalarResWithMostTimeSteps );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigCaseCellResultsData::daysSinceSimulationStart( const RigEclipseResultAddress& resVarAddr ) const
{
if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() )
{
return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].daysSinceSimulationStarts();
}
else
{
return std::vector<double>();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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<RigEclipseTimeStepInfo> RigCaseCellResultsData::timeStepInfos( const RigEclipseResultAddress& resVarAddr ) const
{
if ( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() )
return m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].timeStepInfos();
else
return std::vector<RigEclipseTimeStepInfo>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::setTimeStepInfos( const RigEclipseResultAddress& resVarAddr,
const std::vector<RigEclipseTimeStepInfo>& timeStepInfos )
{
CAF_ASSERT( findScalarResultIndexFromAddress( resVarAddr ) < m_resultInfos.size() );
m_resultInfos[findScalarResultIndexFromAddress( resVarAddr )].setTimeStepInfos( timeStepInfos );
std::vector<std::vector<double>>* 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<double> 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<RiaDefines::ResultCatType>& categoriesToExclude,
std::optional<size_t> 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<double> 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<double>() );
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<double>* RigCaseCellResultsData::getResultIndexableStaticResult( RigActiveCellInfo* actCellInfo,
RigCaseCellResultsData* gridCellResults,
QString resultName,
std::vector<double>& 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<double>* 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<RigEclipseResultInfo>& RigCaseCellResultsData::infoForEachResultIndex() const
{
return m_resultInfos;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigCaseCellResultsData::mustBeCalculated( size_t scalarResultIndex ) const
{
std::vector<RigEclipseResultInfo>::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<RigEclipseResultInfo>::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<RigEclipseResultAddress> RigCaseCellResultsData::existingResults() const
{
std::vector<RigEclipseResultAddress> 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<RiaDefines::ResultCatType>& 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<RiaDefines::ResultCatType> 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<double>& 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<double>& 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<double>::infinity() );
assignValuesToTemporaryLgrs( resultName, values );
}
RigNestedHybridGridResultTools::assignValuesToLgrs( this, values );
}
}
}
else if ( type == RiaDefines::ResultCatType::STATIC_NATIVE )
{
m_cellScalarResults[scalarResultIndex].resize( 1 );
std::vector<double>& 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<double>::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<RifReaderEclipseOutput*>( 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<double>& values = m_cellScalarResults[scalarResultIndex][i];
eclReader->sourSimRlResult( resultName, i, &values );
}
}
}
return scalarResultIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigCaseCellResultsData::findOrLoadKnownScalarResultByResultTypeOrder( const RigEclipseResultAddress& resVarAddr,
const std::vector<RiaDefines::ResultCatType>& resultCategorySearchOrder )
{
std::set<RiaDefines::ResultCatType> 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<RiaDefines::ResultCatType> 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<double>& 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 && timeStepCount > 0 )
{
// A case in an ensemble can have fewer time steps than the case defining the time step axis
if ( timeStepIndex >= timeStepCount ) return cvf::UNDEFINED_SIZE_T;
m_cellScalarResults[scalarResultIndex].resize( timeStepCount );
std::vector<double>& 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<double>& 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<RifReaderEclipseOutput*>( m_readerInterface.p() );
if ( eclReader )
{
size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size();
m_cellScalarResults[scalarResultIndex].resize( timeStepCount );
std::vector<double>& 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<std::vector<double>>& depth = m_cellScalarResults[depthResultIndex];
std::vector<std::vector<double>>& dx = m_cellScalarResults[dxResultIndex];
std::vector<std::vector<double>>& dy = m_cellScalarResults[dyResultIndex];
std::vector<std::vector<double>>& dz = m_cellScalarResults[dzResultIndex];
std::vector<std::vector<double>>& tops = m_cellScalarResults[topsResultIndex];
std::vector<std::vector<double>>& 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<double>::max() );
buffers.computeDepth = true;
}
if ( dx[0].size() < actCellCount )
{
dx[0].resize( actCellCount, std::numeric_limits<double>::max() );
buffers.computeDx = true;
}
if ( dy[0].size() < actCellCount )
{
dy[0].resize( actCellCount, std::numeric_limits<double>::max() );
buffers.computeDy = true;
}
if ( dz[0].size() < actCellCount )
{
dz[0].resize( actCellCount, std::numeric_limits<double>::max() );
buffers.computeDz = true;
}
if ( tops[0].size() < actCellCount )
{
tops[0].resize( actCellCount, std::numeric_limits<double>::max() );
buffers.computeTops = true;
}
if ( bottom[0].size() < actCellCount )
{
bottom[0].resize( actCellCount, std::numeric_limits<double>::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<DepthResultBuffers> 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<long>( 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<size_t, 2> 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<double>* 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<cvf::Vec3d>& nodes,
cvf::StructGridInterface::FaceType faceId,
cvf::Vec3d* faceAreaVec )
{
CAF_ASSERT( faceAreaVec );
*faceAreaVec = cvf::Vec3d::ZERO;
std::vector<size_t> polygon;
std::vector<cvf::Vec3d> intersections;
std::array<size_t, 4> face1;
std::array<size_t, 4> face2;
c1.faceIndices( faceId, &face1 );
c2.faceIndices( cvf::StructGridInterface::oppositeFace( faceId ), &face2 );
bool foundOverlap = cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( polygon,
intersections,
(cvf::EdgeIntersectStorage<size_t>*)nullptr,
cvf::wrapArrayConst( &nodes ),
face1.data(),
face2.data(),
1e-6 );
if ( foundOverlap )
{
std::vector<cvf::Vec3d> 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<double>& permResults = m_cellScalarResults[permResultIdx][0];
std::vector<double>& riTransResults = m_cellScalarResults[riTransResultIdx][0];
std::vector<double>* 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<cvf::Vec3d>& 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<double>& permXResults = m_cellScalarResults[permXResultIdx][0];
std::vector<double>& permYResults = m_cellScalarResults[permYResultIdx][0];
std::vector<double>& permZResults = m_cellScalarResults[permZResultIdx][0];
std::vector<double>& riCombTransResults =
m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult( RiaDefines::propertyNameRiCombTrans() );
m_ownerMainGrid->nncData()->setEclResultAddress( RiaDefines::propertyNameRiCombTrans(), riCombTransEclResAddr );
std::vector<double>* 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<cvf::StructGridInterface::FaceType>( nncConnections[connIdx].face() );
ResultIndexFunction permIdxFunc = nullptr;
std::vector<double>* 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<cvf::Vec3f>& 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<double>& riTransResults = m_cellScalarResults[riTransResultIdx][0];
const std::vector<double>& transResults = m_cellScalarResults[transResultIdx][0];
std::vector<double>& 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<double>* riTransResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombTransEclResAddr );
const std::vector<double>* transResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( combTransEclResAddr );
if ( riTransResults && transResults && ( riTransResults->size() == transResults->size() ) )
{
std::vector<double>& 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<double>& transResults = m_cellScalarResults[tranCompScResIdx][0];
std::vector<double>& 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<cvf::Vec3d>& 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<double>* transResults = m_ownerMainGrid->nncData()->staticConnectionScalarResult( combTransEclResAddr );
if ( !transResults ) return;
std::vector<double>& 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<cvf::Vec3f>& 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<double>& 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<RimGridCalculation*>( 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<QString> 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<RifReaderEclipseOutput*>( 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<double>* 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<std::vector<double>>& 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<std::vector<double>>& 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<double>& valuesForAllReservoirCells )
{
CAF_ASSERT( m_activeCellInfo );
static std::vector<QString> 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<RimEclipseCase*> destinationCases )
{
std::vector<RigEclipseResultAddress> resAddresses = mainCaseResultsData->results( poroModel )->existingResults();
std::vector<RigEclipseTimeStepInfo> timeStepInfos = mainCaseResultsData->results( poroModel )->timeStepInfos( resAddresses[0] );
const std::vector<RigEclipseResultInfo> resultInfos = mainCaseResultsData->results( poroModel )->infoForEachResultIndex();
for ( size_t i = 0; i < destinationCases.size(); i++ )
{
RimEclipseResultCase* rimReservoir = dynamic_cast<RimEclipseResultCase*>( 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<std::vector<double>>* 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();
}