mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
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:
@@ -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() );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user