ResInsight/ApplicationLibCode/ReservoirDataModel/RigCaseCellResultsData.cpp

3009 lines
131 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 "RiaApplication.h"
#include "RiaDefines.h"
#include "RiaEclipseUnitTools.h"
#include "RiaLogging.h"
#include "RiaPreferences.h"
#include "RiaResultNames.h"
#include "RifReaderEclipseOutput.h"
#include "RigAllanDiagramData.h"
#include "RigAllanUtil.h"
#include "RigCaseCellResultCalculator.h"
#include "RigCellVolumeResultCalculator.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 "RigMainGrid.h"
#include "RigMobilePoreVolumeResultCalculator.h"
#include "RigOilVolumeResultCalculator.h"
#include "RigSoilResultCalculator.h"
#include "RigStatisticsDataCache.h"
#include "RigStatisticsMath.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 <cmath>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigCaseCellResultsData::RigCaseCellResultsData( RigEclipseCaseData* ownerCaseData, RiaDefines::PorosityModelType porosityModel )
: m_activeCellInfo( nullptr )
, m_porosityModel( porosityModel )
{
CVF_ASSERT( ownerCaseData != nullptr );
CVF_ASSERT( ownerCaseData->mainGrid() != nullptr );
m_ownerCaseData = ownerCaseData;
m_ownerMainGrid = ownerCaseData->mainGrid();
m_allanDiagramData = new RigAllanDiagramData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::setMainGrid( RigMainGrid* ownerGrid )
{
m_ownerMainGrid = ownerGrid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigCaseCellResultsData::resultCount() const
{
return m_cellScalarResults.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigCaseCellResultsData::timeStepCount( const RigEclipseResultAddress& resVarAddr ) const
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
CVF_TIGHT_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 );
CVF_TIGHT_ASSERT( scalarResultIndex < resultCount() );
return m_cellScalarResults[scalarResultIndex];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<double>>* RigCaseCellResultsData::modifiableCellScalarResultTimesteps( const RigEclipseResultAddress& resVarAddr )
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
CVF_TIGHT_ASSERT( scalarResultIndex < resultCount() );
return &( m_cellScalarResults[scalarResultIndex] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double>* RigCaseCellResultsData::modifiableCellScalarResult( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex )
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
CVF_TIGHT_ASSERT( scalarResultIndex < resultCount() );
CVF_TIGHT_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 );
CVF_TIGHT_ASSERT( scalarResultIndex < resultCount() );
CVF_TIGHT_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& resVarAddr, bool needsToBeStored )
{
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 ) 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 ( it->resultType() == resType )
{
varList.push_back( it->resultName() );
}
}
return varList;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigActiveCellInfo* RigCaseCellResultsData::activeCellInfo()
{
return m_activeCellInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigActiveCellInfo* RigCaseCellResultsData::activeCellInfo() const
{
return m_activeCellInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::recalculateStatistics( const RigEclipseResultAddress& resVarAddr )
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
if ( scalarResultIndex < m_cellScalarResults.size() )
{
m_statisticsDataCache[scalarResultIndex]->clearAllStatistics();
}
}
//--------------------------------------------------------------------------------------------------
/// 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 );
CVF_TIGHT_ASSERT( scalarResultIndex < m_cellScalarResults.size() );
if ( m_cellScalarResults[scalarResultIndex].empty() ) return true;
size_t firstTimeStepResultValueCount = m_cellScalarResults[scalarResultIndex][0].size();
return firstTimeStepResultValueCount != m_ownerMainGrid->globalCellArray().size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 )
{
CVF_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()
{
for ( size_t resultIdx = 0; resultIdx < m_cellScalarResults.size(); ++resultIdx )
{
if ( resultIdx < m_resultInfos.size() &&
m_resultInfos[resultIdx].eclipseResultAddress().resultCatType() == RiaDefines::ResultCatType::GENERATED )
{
// Not possible to recreate generated results, keep them
continue;
}
for ( auto& tsIdx : m_cellScalarResults[resultIdx] )
{
// 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;
tsIdx.swap( empty );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigCaseCellResultsData::isResultLoaded( const RigEclipseResultAddress& resultAddr ) const
{
size_t scalarResultIndex = findScalarResultIndexFromAddress( resultAddr );
CVF_TIGHT_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();
if ( maxTimeStepCount() > 0 )
{
auto prefs = RiaPreferences::current();
if ( prefs->loadAndShowSoil ) return RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() );
auto dynamicResult = std::find_if( allResults.begin(),
allResults.end(),
[]( const RigEclipseResultAddress& adr )
{ return adr.resultCatType() == 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(),
[]( const RigEclipseResultAddress& adr )
{ return adr.resultCatType() == 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(),
[]( const RigEclipseResultAddress& adr )
{ return adr.resultCatType() == RiaDefines::ResultCatType::STATIC_NATIVE; } );
if ( staticResult != allResults.end() ) return *staticResult;
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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( globalCellIndex );
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
{
if ( !hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() ) ) )
{
if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ) ) ||
hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ) ) )
{
size_t soilIndex = findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE,
RiaResultNames::soil() ),
needsToBeStored );
setMustBeCalculated( soilIndex );
}
}
}
// Oil Volume
if ( RiaApplication::enableDevelopmentFeatures() )
{
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 );
}
// 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
{
addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::riCellVolumeResultName(), needsToBeStored, 0 );
}
// Mobile Pore Volume
{
if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PORV" ) ) )
{
addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::mobilePoreVolumeName(), needsToBeStored, 0 );
}
}
// I/J/K indexes
{
findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexIResultName() ), needsToBeStored );
findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexJResultName() ), needsToBeStored );
findOrCreateScalarResultIndex( RiaResultNames::staticIntegerAddress( RiaResultNames::indexKResultName() ), needsToBeStored );
}
// Fault distance
{
findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::faultDistanceName() ),
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 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigCaseCellResultsData::findOrLoadKnownScalarResult( const RigEclipseResultAddress& resVarAddr )
{
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() || resultName == RiaResultNames::indexJResultName() ||
resultName == RiaResultNames::indexKResultName() )
{
computeIndexResults();
}
else if ( resultName == RiaResultNames::faultDistanceName() )
{
computeFaultDistance();
}
}
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 ) )
{
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::completionTypeResultName() )
{
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();
bool resultLoadingSuccess = true;
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 ) )
{
resultLoadingSuccess = false;
}
else if ( tempGridCellCount > 0 )
{
if ( !values.empty() )
{
values.resize( values.size() + tempGridCellCount, std::numeric_limits<double>::infinity() );
assignValuesToTemporaryLgrs( resultName, 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 ) )
{
resultLoadingSuccess = false;
}
else if ( tempGridCellCount > 0 )
{
if ( !values.empty() )
{
values.resize( values.size() + tempGridCellCount, std::numeric_limits<double>::infinity() );
assignValuesToTemporaryLgrs( resultName, values );
}
}
}
if ( !resultLoadingSuccess )
{
// Remove last scalar result because loading of result failed
m_cellScalarResults[scalarResultIndex].clear();
}
}
if ( resultName == RiaResultNames::riCellVolumeResultName() )
{
computeCellVolumes();
}
else if ( resultName == RiaResultNames::riOilVolumeResultName() )
{
computeCellVolumes();
computeOilVolumes();
}
// 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 ) )
{
m_cellScalarResults[soilScalarResultIndex].resize( maxTimeStepCount() );
std::vector<double>& values = m_cellScalarResults[soilScalarResultIndex][timeStepIndex];
if ( values.empty() )
{
computeSOILForTimeStep( timeStepIndex );
}
return soilScalarResultIndex;
}
}
else if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && resultName == RiaResultNames::completionTypeResultName() )
{
size_t completionTypeScalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
computeCompletionTypeForTimeStep( timeStepIndex );
return completionTypeScalarResultIndex;
}
size_t scalarResultIndex = findScalarResultIndexFromAddress( resVarAddr );
if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) return cvf::UNDEFINED_SIZE_T;
if ( type == RiaDefines::ResultCatType::GENERATED )
{
return cvf::UNDEFINED_SIZE_T;
}
if ( m_readerInterface.notNull() )
{
size_t timeStepCount = infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size();
bool resultLoadingSuccess = true;
if ( type == RiaDefines::ResultCatType::DYNAMIC_NATIVE && timeStepCount > 0 )
{
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 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 ) )
{
resultLoadingSuccess = false;
}
}
if ( !resultLoadingSuccess )
{
// Error logging
CVF_ASSERT( false );
}
}
// 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::testAndComputeSgasForTimeStep( size_t timeStepIndex )
{
size_t scalarIndexSWAT =
findOrLoadKnownScalarResultForTimeStep( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() ),
timeStepIndex );
if ( scalarIndexSWAT == cvf::UNDEFINED_SIZE_T )
{
return;
}
if ( m_readerInterface.isNull() ) return;
std::set<RiaDefines::PhaseType> phases = m_readerInterface->availablePhases();
if ( phases.count( RiaDefines::PhaseType::GAS_PHASE ) == 0 ) return;
if ( phases.count( RiaDefines::PhaseType::OIL_PHASE ) > 0 ) return;
// Simulation type is gas and water. No SGAS is present, compute SGAS based on SWAT
size_t scalarIndexSGAS =
findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() ), false );
if ( m_cellScalarResults[scalarIndexSGAS].size() > timeStepIndex )
{
std::vector<double>& values = m_cellScalarResults[scalarIndexSGAS][timeStepIndex];
if ( !values.empty() ) return;
}
size_t swatResultValueCount = 0;
size_t swatTimeStepCount = 0;
{
std::vector<double>& swatForTimeStep = m_cellScalarResults[scalarIndexSWAT][timeStepIndex];
if ( !swatForTimeStep.empty() )
{
swatResultValueCount = swatForTimeStep.size();
swatTimeStepCount = infoForEachResultIndex()[scalarIndexSWAT].timeStepInfos().size();
}
}
m_cellScalarResults[scalarIndexSGAS].resize( swatTimeStepCount );
if ( !m_cellScalarResults[scalarIndexSGAS][timeStepIndex].empty() )
{
return;
}
m_cellScalarResults[scalarIndexSGAS][timeStepIndex].resize( swatResultValueCount );
std::vector<double>* swatForTimeStep = nullptr;
{
swatForTimeStep = &( m_cellScalarResults[scalarIndexSWAT][timeStepIndex] );
if ( swatForTimeStep->empty() )
{
swatForTimeStep = nullptr;
}
}
std::vector<double>& sgasForTimeStep = m_cellScalarResults[scalarIndexSGAS][timeStepIndex];
#pragma omp parallel for
for ( int idx = 0; idx < static_cast<int>( swatResultValueCount ); idx++ )
{
double sgasValue = 1.0;
if ( swatForTimeStep )
{
sgasValue -= swatForTimeStep->at( idx );
}
sgasForTimeStep[idx] = sgasValue;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::computeDepthRelatedResults()
{
size_t actCellCount = activeCellInfo()->reservoirActiveCellCount();
if ( actCellCount == 0 ) return;
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" ) );
bool computeDepth = false;
bool computeDx = false;
bool computeDy = false;
bool computeDz = false;
bool computeTops = false;
bool computeBottom = false;
if ( depthResultIndex == cvf::UNDEFINED_SIZE_T )
{
depthResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DEPTH", false, actCellCount );
computeDepth = true;
}
if ( dxResultIndex == cvf::UNDEFINED_SIZE_T )
{
dxResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DX", false, actCellCount );
computeDx = true;
}
if ( dyResultIndex == cvf::UNDEFINED_SIZE_T )
{
dyResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DY", false, actCellCount );
computeDy = true;
}
if ( dzResultIndex == cvf::UNDEFINED_SIZE_T )
{
dzResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "DZ", false, actCellCount );
computeDz = true;
}
if ( topsResultIndex == cvf::UNDEFINED_SIZE_T )
{
topsResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "TOPS", false, actCellCount );
computeTops = true;
}
if ( bottomResultIndex == cvf::UNDEFINED_SIZE_T )
{
bottomResultIndex = addStaticScalarResult( RiaDefines::ResultCatType::STATIC_NATIVE, "BOTTOM", false, actCellCount );
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() );
computeDepth = true;
}
if ( dx[0].size() < actCellCount )
{
dx[0].resize( actCellCount, std::numeric_limits<double>::max() );
computeDx = true;
}
if ( dy[0].size() < actCellCount )
{
dy[0].resize( actCellCount, std::numeric_limits<double>::max() );
computeDy = true;
}
if ( dz[0].size() < actCellCount )
{
dz[0].resize( actCellCount, std::numeric_limits<double>::max() );
computeDz = true;
}
if ( tops[0].size() < actCellCount )
{
tops[0].resize( actCellCount, std::numeric_limits<double>::max() );
computeTops = true;
}
if ( bottom[0].size() < actCellCount )
{
bottom[0].resize( actCellCount, std::numeric_limits<double>::max() );
computeBottom = true;
}
}
for ( size_t cellIdx = 0; cellIdx < m_ownerMainGrid->globalCellArray().size(); cellIdx++ )
{
const RigCell& cell = m_ownerMainGrid->globalCellArray()[cellIdx];
size_t resultIndex = activeCellInfo()->cellResultIndex( cellIdx );
if ( resultIndex == cvf::UNDEFINED_SIZE_T ) continue;
bool isTemporaryGrid = cell.hostGrid()->isTempGrid();
if ( computeDepth || isTemporaryGrid )
{
depth[0][resultIndex] = cvf::Math::abs( cell.center().z() );
}
if ( computeDx || isTemporaryGrid )
{
cvf::Vec3d cellWidth = cell.faceCenter( cvf::StructGridInterface::NEG_I ) - cell.faceCenter( cvf::StructGridInterface::POS_I );
dx[0][resultIndex] = cellWidth.length();
}
if ( computeDy || isTemporaryGrid )
{
cvf::Vec3d cellWidth = cell.faceCenter( cvf::StructGridInterface::NEG_J ) - cell.faceCenter( cvf::StructGridInterface::POS_J );
dy[0][resultIndex] = cellWidth.length();
}
if ( computeDz || isTemporaryGrid )
{
cvf::Vec3d cellWidth = cell.faceCenter( cvf::StructGridInterface::NEG_K ) - cell.faceCenter( cvf::StructGridInterface::POS_K );
dz[0][resultIndex] = cellWidth.length();
}
if ( computeTops || isTemporaryGrid )
{
tops[0][resultIndex] = cvf::Math::abs( cell.faceCenter( cvf::StructGridInterface::NEG_K ).z() );
}
if ( computeBottom || isTemporaryGrid )
{
bottom[0][resultIndex] = cvf::Math::abs( cell.faceCenter( cvf::StructGridInterface::POS_K ).z() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::computeIndexResults()
{
RigEclipseResultAddress addr( RiaDefines::ResultCatType::STATIC_NATIVE, RiaResultNames::indexIResultName() );
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 );
}
namespace RigTransmissibilityCalcTools
{
void calculateConnectionGeometry( const RigCell& c1,
const RigCell& c2,
const std::vector<cvf::Vec3d>& nodes,
cvf::StructGridInterface::FaceType faceId,
cvf::Vec3d* faceAreaVec )
{
CVF_TIGHT_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 ) );
CVF_TIGHT_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 );
}
} // 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
{
CVF_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 ) );
CVF_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->globalCellArray().size(); 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->globalCellArray()[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->globalCellArray()[neighborResvCellIdx];
// 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();
size_t permResIdx = ( *permIdxFunc )( activeCellInfo, nativeResvCellIndex );
double perm = permResults[permResIdx];
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->globalCellArray()[nativeResvCellIndex];
const RigCell& neighborCell = m_ownerMainGrid->globalCellArray()[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
{
CVF_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 ) );
CVF_ASSERT( riMultResultIdx != cvf::UNDEFINED_SIZE_T );
// Get the result count, to handle that one of them might be globally defined
CVF_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
{
CVF_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 ) );
CVF_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->globalCellArray().size(); 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->globalCellArray()[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->globalCellArray()[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() );
}
std::vector<double>& completionTypeResult = m_cellScalarResults[completionTypeResultIndex][timeStep];
size_t resultValues = m_ownerMainGrid->globalCellArray().size();
if ( completionTypeResult.size() == resultValues )
{
return;
}
completionTypeResult.resize( resultValues );
std::fill( completionTypeResult.begin(), completionTypeResult.end(), HUGE_VAL );
RimEclipseCase* eclipseCase = m_ownerCaseData->ownerCase();
if ( !eclipseCase ) return;
// If permeabilities are generated by calculations, make sure that generated data is calculated
// See RicExportFractureCompletionsImpl::generateCompdatValues()
for ( const QString propertyName : { "PERMX", "PERMY", "PERMZ" } )
{
for ( auto userCalculation : RimProject::current()->gridCalculationCollection()->calculations() )
{
auto gridCalculation = dynamic_cast<RimGridCalculation*>( userCalculation );
if ( gridCalculation && gridCalculation->outputEclipseCase() != eclipseCase ) continue;
QString generatedPropertyName = RimUserDefinedCalculation::findLeftHandSide( userCalculation->expression() );
if ( generatedPropertyName == propertyName )
{
userCalculation->calculate();
}
}
}
RimCompletionCellIntersectionCalc::calculateCompletionTypeResult( eclipseCase, completionTypeResult, timeStep );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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::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( RigFormationNames* activeFormationNames )
{
m_activeFormationNamesData = activeFormationNames;
size_t totalGlobCellCount = m_ownerMainGrid->globalCellArray().size();
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.isNull() )
{
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->globalCellArray()[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.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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
{
if ( scalarResultIndex >= resultCount() )
{
return false;
}
const std::vector<std::vector<double>>& data = m_cellScalarResults[scalarResultIndex];
for ( size_t tsIdx = 0; tsIdx < data.size(); ++tsIdx )
{
if ( !data[tsIdx].empty() )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigCaseCellResultsData::assignValuesToTemporaryLgrs( const QString& resultName, std::vector<double>& valuesForAllReservoirCells )
{
CVF_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;
}
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( mainGridCellIndex );
size_t cellResultIndex = m_activeCellInfo->cellResultIndex( reservoirCellIndex );
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();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigCaseCellResultsData::findScalarResultIndexFromAddress( const RigEclipseResultAddress& resVarAddr ) const
{
if ( !resVarAddr.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 ontop 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 );
}