Producer/Injector Connectivity Table (#9928)

- Crated new RimMatrixPlotWidget to show table data
- Create RimWellConnectivityTable for showing Producer/Injector connectivity table data
- Rename RimWellAllocationOverTimeCollection to RigWellAllocationOverTime for well allocation over time data storage
- Created heatmap color palette
- Move utils from RimWellAllocationOverTimePlot to RiaQDateTimeTools
- Create RimFlowDiagnosticsTools for producer/injector well utility functions


---------

Co-authored-by: jorgenherje <jorgenherje@users.noreply.github.com>
This commit is contained in:
Jørgen Herje
2023-03-21 08:32:38 +01:00
committed by GitHub
parent 37abe17582
commit 535811cc4f
36 changed files with 2692 additions and 294 deletions

View File

@@ -28,6 +28,7 @@
#include "RigEclipseCaseData.h"
#include "RigSimWellData.h"
#include "RigSimulationWellCenterLineCalculator.h"
#include "RigWellAllocationOverTime.h"
#include "RigWellResultPoint.h"
#include "RimEclipseCaseTools.h"
@@ -37,7 +38,6 @@
#include "RimFlowDiagSolution.h"
#include "RimSimWellInView.h"
#include "RimStackablePlotCurve.h"
#include "RimWellAllocationOverTimeCollection.h"
#include "RimWellAllocationTools.h"
#include "RimWellLogFile.h"
#include "RimWellPlotTools.h"
@@ -108,7 +108,7 @@ RimWellAllocationOverTimePlot::RimWellAllocationOverTimePlot()
m_selectedFromTimeStep.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_selectedToTimeStep, "ToTimeStep", "To Time Step" );
m_selectedToTimeStep.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_timeStepFilterMode, "TimeStepFilterMode", "Filter" );
CAF_PDM_InitFieldNoDefault( &m_timeStepFilterMode, "TimeStepRangeFilterMode", "Filter" );
m_timeStepFilterMode.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_timeStepCount, "TimeStepCount", m_initialNumberOfTimeSteps, "Number of Time Steps" );
CAF_PDM_InitFieldNoDefault( &m_excludeTimeSteps, "ExcludeTimeSteps", "" );
@@ -186,23 +186,23 @@ RiuPlotWidget* RimWellAllocationOverTimePlot::plotWidget()
//--------------------------------------------------------------------------------------------------
QString RimWellAllocationOverTimePlot::asciiDataForPlotExport() const
{
// Retrieve collection of allocation over time data for wells
RimWellAllocationOverTimeCollection allocationOverTimeCollection = createWellAllocationOverTimeCollection();
// Retrieve allocation over time data for wells
RigWellAllocationOverTime allocationOverTime = createWellAllocationOverTime();
QString titleText = m_userName + "\n\n";
QString dataText = "Time Step\t";
for ( auto& [wellName, wellValues] : allocationOverTimeCollection.wellValuesMap() )
for ( auto& [wellName, wellValues] : allocationOverTime.wellValuesMap() )
{
dataText += wellName + "\t";
}
dataText += "\n";
const QString dateFormatStr = dateFormatString();
for ( const auto& timeStep : allocationOverTimeCollection.timeStepDates() )
for ( const auto& timeStep : allocationOverTime.timeStepDates() )
{
dataText += timeStep.toString( dateFormatStr ) + "\t";
for ( auto& [wellName, wellValues] : allocationOverTimeCollection.wellValuesMap() )
for ( auto& [wellName, wellValues] : allocationOverTime.wellValuesMap() )
{
dataText += wellValues.count( timeStep ) == 0 ? QString::number( 0.0 ) : QString::number( wellValues.at( timeStep ) );
dataText += "\t";
@@ -350,18 +350,18 @@ void RimWellAllocationOverTimePlot::updateFromWell()
}
m_plotWidget->detachItems( RiuPlotWidget::PlotItemType::CURVE );
// Retrieve collection of total fraction data for wells
RimWellAllocationOverTimeCollection allocationOverTimeCollection = createWellAllocationOverTimeCollection();
std::vector<double> allStackedValues( allocationOverTimeCollection.timeStepDates().size(), 0.0 );
// Retrieve total fraction data for wells
RigWellAllocationOverTime allocationOverTime = createWellAllocationOverTime();
std::vector<double> allStackedValues( allocationOverTime.timeStepDates().size(), 0.0 );
// Negative z-position to show grid lines
int zPos = -10000;
for ( auto& [wellName, wellValues] : allocationOverTimeCollection.wellValuesMap() )
for ( auto& [wellName, wellValues] : allocationOverTime.wellValuesMap() )
{
cvf::Color3f color = m_flowDiagSolution ? m_flowDiagSolution->tracerColor( wellName ) : getTracerColor( wellName );
for ( size_t i = 0; i < allocationOverTimeCollection.timeStepDates().size(); ++i )
for ( size_t i = 0; i < allocationOverTime.timeStepDates().size(); ++i )
{
const auto value = wellValues.at( allocationOverTimeCollection.timeStepDates()[i] );
const auto value = wellValues.at( allocationOverTime.timeStepDates()[i] );
allStackedValues[i] += value;
}
@@ -375,7 +375,7 @@ void RimWellAllocationOverTimePlot::updateFromWell()
RiuPlotCurve* curve = m_plotWidget->createPlotCurve( nullptr, wellName );
curve->setAppearance( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID, interpolationType, 2, qColor, fillBrush );
curve->setSamplesFromDatesAndYValues( allocationOverTimeCollection.timeStepDates(), allStackedValues, false );
curve->setSamplesFromDatesAndYValues( allocationOverTime.timeStepDates(), allStackedValues, false );
curve->attachToPlot( m_plotWidget );
curve->showInPlot();
curve->setZ( zPos-- );
@@ -412,23 +412,23 @@ void RimWellAllocationOverTimePlot::updateFromWell()
/// well data for all time steps. If well does not exist for specific time step date - value is
/// set to 0.
//--------------------------------------------------------------------------------------------------
RimWellAllocationOverTimeCollection RimWellAllocationOverTimePlot::createWellAllocationOverTimeCollection() const
RigWellAllocationOverTime RimWellAllocationOverTimePlot::createWellAllocationOverTime() const
{
if ( !m_case )
{
return RimWellAllocationOverTimeCollection( {}, {} );
return RigWellAllocationOverTime( {}, {} );
}
if ( m_selectedFromTimeStep() > m_selectedToTimeStep() )
{
RiaLogging::error( QString( "Selected 'From Time Step' (%1) must be prior to selected 'To Time Step' (%2)" )
.arg( m_selectedFromTimeStep().toString( dateFormatString() ) )
.arg( m_selectedToTimeStep().toString( dateFormatString() ) ) );
return RimWellAllocationOverTimeCollection( {}, {} );
return RigWellAllocationOverTime( {}, {} );
}
const RigSimWellData* simWellData = m_case->eclipseCaseData()->findSimWellData( m_wellName );
if ( !simWellData )
{
return RimWellAllocationOverTimeCollection( {}, {} );
return RigWellAllocationOverTime( {}, {} );
}
// Note: Threshold per calculator does not work for accumulated data - use no threshold for each calculator
@@ -470,7 +470,8 @@ RimWellAllocationOverTimeCollection RimWellAllocationOverTimePlot::createWellAll
bool isProducer = ( simWellData->wellProductionType( i ) == RiaDefines::WellProductionType::PRODUCER ||
simWellData->wellProductionType( i ) == RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE );
RigEclCellIndexCalculator cellIdxCalc( m_case->eclipseCaseData()->mainGrid(),
m_case->eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ) );
m_case->eclipseCaseData()->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ),
nullptr );
const auto calculator = RigAccWellFlowCalculator( pipeBranchesCLCoords,
pipeBranchesCellIds,
tracerFractionCellValues,
@@ -491,41 +492,41 @@ RimWellAllocationOverTimeCollection RimWellAllocationOverTimePlot::createWellAll
}
}
// Create collection
const auto selectedTimeStepsVector = std::vector( selectedTimeSteps.begin(), selectedTimeSteps.end() );
RimWellAllocationOverTimeCollection collection( selectedTimeStepsVector, timeStepAndCalculatorPairs );
// Create well allocation over time data
const auto selectedTimeStepsVector = std::vector( selectedTimeSteps.begin(), selectedTimeSteps.end() );
RigWellAllocationOverTime wellAllocationOverTime( selectedTimeStepsVector, timeStepAndCalculatorPairs );
if ( m_flowValueType == FlowValueType::FLOW_RATE_PERCENTAGE )
{
collection.fillWithFlowRatePercentageValues();
wellAllocationOverTime.fillWithFlowRatePercentageValues();
}
else if ( m_flowValueType == FlowValueType::FLOW_RATE )
{
collection.fillWithFlowRateValues();
wellAllocationOverTime.fillWithFlowRateValues();
}
else if ( m_flowValueType == FlowValueType::FLOW_VOLUME )
{
collection.fillWithFlowVolumeValues();
wellAllocationOverTime.fillWithFlowVolumeValues();
}
else if ( m_flowValueType == FlowValueType::ACCUMULATED_FLOW_VOLUME )
{
// Accumulated flow volume without threshold, and filter according to threshold after accumulating volumes
const double actualSmallContributionThreshold = m_groupSmallContributions() ? m_smallContributionsThreshold : 0.0;
collection.fillWithAccumulatedFlowVolumeValues( actualSmallContributionThreshold );
wellAllocationOverTime.fillWithAccumulatedFlowVolumeValues( actualSmallContributionThreshold );
}
else if ( m_flowValueType == FlowValueType::ACCUMULATED_FLOW_VOLUME_PERCENTAGE )
{
// Accumulate flow volume percentages without threshold, and filter according to threshold after accumulating
// values
const double actualSmallContributionThreshold = m_groupSmallContributions() ? m_smallContributionsThreshold : 0.0;
collection.fillWithAccumulatedFlowVolumePercentageValues( actualSmallContributionThreshold );
wellAllocationOverTime.fillWithAccumulatedFlowVolumePercentageValues( actualSmallContributionThreshold );
}
else
{
CAF_ASSERT( "Not handled FlowValue type!" );
}
return collection;
return wellAllocationOverTime;
}
//--------------------------------------------------------------------------------------------------
@@ -782,8 +783,8 @@ QString RimWellAllocationOverTimePlot::dateFormatString() const
//--------------------------------------------------------------------------------------------------
/// Update selected "From Time Step" and "To Time Step" according to selected case.
/// If both selected time steps exist for case, keep as is. Otherwise set the 10 first time steps
/// for case. If less than 10 time steps exist, all are selected.
/// If both selected time steps exist for case, keep as is, otherwise select first and last time
/// step in case.
//--------------------------------------------------------------------------------------------------
void RimWellAllocationOverTimePlot::setValidTimeStepRangeForCase()
{
@@ -821,77 +822,14 @@ int RimWellAllocationOverTimePlot::axisValueFontSize() const
return caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_axisValueFontSize() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RimWellAllocationOverTimePlot::getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps ) const
{
std::vector<QDateTime> selectedTimeSteps;
auto isTimeStepInSelectedRange = [&]( const QDateTime& timeStep ) -> bool {
return m_selectedFromTimeStep() <= timeStep && timeStep <= m_selectedToTimeStep();
};
std::copy_if( timeSteps.begin(), timeSteps.end(), std::back_inserter( selectedTimeSteps ), isTimeStepInSelectedRange );
return selectedTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RimWellAllocationOverTimePlot::getSelectedTimeSteps( const std::vector<QDateTime>& timeSteps ) const
{
const auto timeStepsInRange = getTimeStepsWithinSelectedRange( timeSteps );
return m_timeStepFilterMode == TimeStepFilterMode::TIME_STEP_COUNT ? createEvenlyDistributedDates( timeStepsInRange, m_timeStepCount )
: std::set( timeStepsInRange.begin(), timeStepsInRange.end() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RimWellAllocationOverTimePlot::createEvenlyDistributedDates( const std::vector<QDateTime>& inputDates, int numDates )
{
std::set<QDateTime> outputDates;
if ( inputDates.empty() || numDates <= 0 )
{
return outputDates;
}
if ( static_cast<size_t>( numDates ) > inputDates.size() )
{
outputDates = std::set( inputDates.begin(), inputDates.end() );
return outputDates;
}
if ( numDates == 1 )
{
outputDates = { inputDates.front() };
return outputDates;
}
// Find the minimum and maximum dates in the input vector
QDateTime minDate = *std::min_element( inputDates.begin(), inputDates.end() );
QDateTime maxDate = *std::max_element( inputDates.begin(), inputDates.end() );
// Calculate the time step between each selected date
qint64 timeStep = ( maxDate.toMSecsSinceEpoch() - minDate.toMSecsSinceEpoch() ) / ( static_cast<qint64>( numDates ) - 1 );
// Find the index of the input date that is closest to each new date
for ( int i = 0; i < numDates; ++i )
{
qint64 targetTime = minDate.toMSecsSinceEpoch() + i * timeStep;
int closestIndex = 0;
qint64 closestTimeDiff = std::numeric_limits<qint64>::max();
for ( size_t j = 0; j < inputDates.size(); ++j )
{
qint64 timeDiff = std::abs( inputDates[j].toMSecsSinceEpoch() - targetTime );
if ( timeDiff < closestTimeDiff )
{
closestIndex = j;
closestTimeDiff = timeDiff;
}
}
// Add the closest date to the output vector
outputDates.insert( inputDates[closestIndex] );
}
return outputDates;
const auto timeStepsInRange =
RiaQDateTimeTools::getTimeStepsWithinSelectedRange( timeSteps, m_selectedFromTimeStep(), m_selectedToTimeStep() );
return m_timeStepFilterMode == TimeStepFilterMode::TIME_STEP_COUNT
? RiaQDateTimeTools::createEvenlyDistributedDates( timeStepsInRange, m_timeStepCount )
: std::set( timeStepsInRange.begin(), timeStepsInRange.end() );
}