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:
parent
37abe17582
commit
535811cc4f
@ -32,6 +32,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -68,6 +69,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
27
ApplicationLibCode/Application/RiaWellFlowDefines.cpp
Normal file
27
ApplicationLibCode/Application/RiaWellFlowDefines.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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 "RiaWellFlowDefines.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RiaDefines::reservoirTracerName()
|
||||
{
|
||||
return "Reservoir";
|
||||
}
|
26
ApplicationLibCode/Application/RiaWellFlowDefines.h
Normal file
26
ApplicationLibCode/Application/RiaWellFlowDefines.h
Normal file
@ -0,0 +1,26 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace RiaDefines
|
||||
{
|
||||
QString reservoirTracerName();
|
||||
}; // namespace RiaDefines
|
@ -531,6 +531,24 @@ const caf::ColorTable& RiaColorTables::correlationPaletteColors()
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const caf::ColorTable& RiaColorTables::heatMapPaletteColors()
|
||||
{
|
||||
static std::vector<cvf::Color3ub> colors{ cvf::Color3ub::DARK_BLUE,
|
||||
cvf::Color3ub( 0, 0, 240 ), // Medium Blue
|
||||
cvf::Color3ub( 0, 102, 204 ), // Transition Medium Blue to Cyan
|
||||
cvf::Color3ub::CYAN,
|
||||
cvf::Color3ub( 75, 255, 47 ), // Green/Yellow more green
|
||||
cvf::Color3ub::DARK_ORANGE,
|
||||
cvf::Color3ub::YELLOW };
|
||||
|
||||
static caf::ColorTable colorTable = caf::ColorTable( colors );
|
||||
|
||||
return colorTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
static const caf::ColorTable& wellPathsPaletteColors();
|
||||
static const caf::ColorTable& waterAndRockPaletteColors();
|
||||
static const caf::ColorTable& correlationPaletteColors();
|
||||
static const caf::ColorTable& heatMapPaletteColors();
|
||||
|
||||
static cvf::Color3f undefinedCellColor();
|
||||
|
||||
|
@ -499,3 +499,68 @@ QList<caf::PdmOptionItemInfo> RiaQDateTimeTools::createOptionItems( const std::v
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QDateTime> RiaQDateTimeTools::createEvenlyDistributedDates( const std::vector<QDateTime>& inputDates, int numDates )
|
||||
{
|
||||
std::set<QDateTime> outputDates;
|
||||
if ( inputDates.empty() || numDates <= 0 )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QDateTime> RiaQDateTimeTools::getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps,
|
||||
const QDateTime& fromTimeStep,
|
||||
const QDateTime& toTimeStep )
|
||||
{
|
||||
std::vector<QDateTime> selectedTimeSteps;
|
||||
auto isTimeStepInSelectedRange = [&]( const QDateTime& timeStep ) -> bool { return fromTimeStep <= timeStep && timeStep <= toTimeStep; };
|
||||
std::copy_if( timeSteps.begin(), timeSteps.end(), std::back_inserter( selectedTimeSteps ), isTimeStepInSelectedRange );
|
||||
|
||||
return selectedTimeSteps;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -93,6 +94,10 @@ public:
|
||||
|
||||
static QList<caf::PdmOptionItemInfo> createOptionItems( const std::vector<time_t>& timeSteps );
|
||||
|
||||
static std::set<QDateTime> createEvenlyDistributedDates( const std::vector<QDateTime>& inputDates, int numDates );
|
||||
static std::vector<QDateTime>
|
||||
getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps, const QDateTime& fromTimeStep, const QDateTime& toTimeStep );
|
||||
|
||||
private:
|
||||
static const DateTimeSpan TIMESPAN_DAY;
|
||||
static const DateTimeSpan TIMESPAN_WEEK;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "RimSimWellInViewCollection.h"
|
||||
#include "RimWellAllocationOverTimePlot.h"
|
||||
#include "RimWellAllocationPlot.h"
|
||||
#include "RimWellConnectivityTable.h"
|
||||
#include "RimWellPath.h"
|
||||
|
||||
#include "RiuPlotMainWindowTools.h"
|
||||
@ -111,6 +112,8 @@ void RicShowWellAllocationPlotFeature::onActionTriggered( bool isChecked )
|
||||
flowPlotColl->defaultWellAllocOverTimePlot()->setFromSimulationWell( simWell );
|
||||
flowPlotColl->defaultWellAllocOverTimePlot()->updateConnectedEditors();
|
||||
|
||||
flowPlotColl->defaultWellConnectivityTable()->setFromSimulationWell( simWell );
|
||||
|
||||
RiuPlotMainWindowTools::showPlotMainWindow();
|
||||
RiuPlotMainWindowTools::onObjectAppended( flowPlotColl->defaultWellAllocOverTimePlot() );
|
||||
RiuPlotMainWindowTools::onObjectAppended( flowPlotColl->defaultWellAllocPlot() );
|
||||
|
@ -38,6 +38,7 @@ CAF_PDM_SOURCE_INIT( RimCellFilterCollection, "CellFilterCollection", "RimCellFi
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimCellFilterCollection::RimCellFilterCollection()
|
||||
: filtersChanged( this )
|
||||
{
|
||||
CAF_PDM_InitScriptableObject( "Cell Filters", ":/CellFilter.png" );
|
||||
|
||||
@ -357,6 +358,8 @@ void RimCellFilterCollection::onFilterUpdated( const SignalEmitter* emitter )
|
||||
view->scheduleGeometryRegen( RANGE_FILTERED_INACTIVE );
|
||||
|
||||
view->scheduleCreateDisplayModelAndRedraw();
|
||||
|
||||
filtersChanged.send();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
class RimCellFilter;
|
||||
class RimCellRangeFilter;
|
||||
@ -45,6 +46,8 @@ public:
|
||||
RimCellFilterCollection();
|
||||
~RimCellFilterCollection() override;
|
||||
|
||||
caf::Signal<> filtersChanged;
|
||||
|
||||
RimPolygonFilter* addNewPolygonFilter( RimCase* srcCase );
|
||||
RimUserDefinedFilter* addNewUserDefinedFilter( RimCase* srcCase );
|
||||
RimCellRangeFilter* addNewCellRangeFilter( RimCase* srcCase, int gridIndex, int sliceDirection = -1, int defaultSlice = -1 );
|
||||
|
@ -16,7 +16,8 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellDistributionPlotCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationOverTimePlot.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationTools.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationOverTimeCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellConnectivityTable.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimFlowDiagnosticsTools.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -37,7 +38,8 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellDistributionPlotCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationOverTimePlot.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationTools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellAllocationOverTimeCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimWellConnectivityTable.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimFlowDiagnosticsTools.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
@ -0,0 +1,216 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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 "RimFlowDiagnosticsTools.h"
|
||||
|
||||
#include "RigFlowDiagResults.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimFlowDiagnosticsTools::TracerComp::operator()( const QString& lhs, const QString& rhs ) const
|
||||
{
|
||||
if ( !lhs.endsWith( "-XF" ) && rhs.endsWith( "-XF" ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ( lhs.endsWith( "-XF" ) && !rhs.endsWith( "-XF" ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RimFlowDiagnosticsTools::calcOptionsForSelectedTracerField( RimFlowDiagSolution* flowSol, bool isInjector )
|
||||
{
|
||||
if ( !flowSol ) return {};
|
||||
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
std::set<QString, TracerComp> sortedTracers = setOfTracersOfType( flowSol, isInjector );
|
||||
for ( const QString& tracerName : sortedTracers )
|
||||
{
|
||||
QString postfix;
|
||||
RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName );
|
||||
if ( status == RimFlowDiagSolution::TracerStatusType::VARYING )
|
||||
{
|
||||
postfix = " [I/P]";
|
||||
}
|
||||
else if ( status == RimFlowDiagSolution::TracerStatusType::UNDEFINED )
|
||||
{
|
||||
postfix = " [U]";
|
||||
}
|
||||
options.push_back( caf::PdmOptionItemInfo( tracerName + postfix, tracerName ) );
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp> RimFlowDiagnosticsTools::setOfTracersOfType( RimFlowDiagSolution* flowSol,
|
||||
bool isInjector )
|
||||
{
|
||||
if ( !flowSol ) return {};
|
||||
|
||||
std::set<QString, TracerComp> sortedTracers;
|
||||
std::vector<QString> tracerNames = flowSol->tracerNames();
|
||||
for ( const QString& tracerName : tracerNames )
|
||||
{
|
||||
RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName );
|
||||
bool includeTracer = status == RimFlowDiagSolution::TracerStatusType::VARYING ||
|
||||
status == RimFlowDiagSolution::TracerStatusType::UNDEFINED;
|
||||
includeTracer |= isInjector && status == RimFlowDiagSolution::TracerStatusType::INJECTOR;
|
||||
includeTracer |= !isInjector && status == RimFlowDiagSolution::TracerStatusType::PRODUCER;
|
||||
|
||||
if ( includeTracer )
|
||||
{
|
||||
sortedTracers.insert( tracerName );
|
||||
}
|
||||
}
|
||||
return sortedTracers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RimFlowDiagnosticsTools::producerTracersInTimeStep( RimFlowDiagSolution* flowSol, int timeStepIndex )
|
||||
{
|
||||
return tracersOfStatusInTimeStep( flowSol, RimFlowDiagSolution::TracerStatusType::PRODUCER, timeStepIndex );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RimFlowDiagnosticsTools::injectorTracersInTimeStep( RimFlowDiagSolution* flowSol, int timeStepIndex )
|
||||
{
|
||||
return tracersOfStatusInTimeStep( flowSol, RimFlowDiagSolution::TracerStatusType::INJECTOR, timeStepIndex );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RimFlowDiagnosticsTools::tracersOfStatusInTimeStep( RimFlowDiagSolution* flowSol,
|
||||
RimFlowDiagSolution::TracerStatusType status,
|
||||
int timeStepIndex )
|
||||
{
|
||||
if ( !flowSol || timeStepIndex < 0 ) return {};
|
||||
|
||||
std::vector<QString> tracers;
|
||||
for ( const auto& tracer : flowSol->tracerNames() )
|
||||
{
|
||||
if ( status == flowSol->tracerStatusInTimeStep( tracer, timeStepIndex ) )
|
||||
{
|
||||
tracers.push_back( tracer );
|
||||
}
|
||||
}
|
||||
return tracers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
RimFlowDiagnosticsTools::setOfInjectorTracersFromProducers( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& producerTracers,
|
||||
std::vector<int> timeStepIndices )
|
||||
{
|
||||
if ( !flowSol ) return {};
|
||||
|
||||
const double epsilon = 1.0e-8;
|
||||
const bool isInjector = true;
|
||||
std::set<QString, TracerComp> communicatingInjectors;
|
||||
std::set<QString, TracerComp> injectors = RimFlowDiagnosticsTools::setOfTracersOfType( flowSol, isInjector );
|
||||
for ( const QString& producer : producerTracers )
|
||||
{
|
||||
for ( const QString& injector : injectors )
|
||||
{
|
||||
for ( const auto& timeStepIndex : timeStepIndices )
|
||||
{
|
||||
std::pair<double, double> commFluxes =
|
||||
flowSol->flowDiagResults()->injectorProducerPairFluxes( injector.toStdString(), producer.toStdString(), timeStepIndex );
|
||||
if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon )
|
||||
{
|
||||
communicatingInjectors.insert( injector );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return communicatingInjectors;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
RimFlowDiagnosticsTools::setOfInjectorTracersFromProducers( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& producerTracers,
|
||||
int timeStepIndex )
|
||||
{
|
||||
const auto timeStepIndices = std::vector<int>( { timeStepIndex } );
|
||||
return setOfInjectorTracersFromProducers( flowSol, producerTracers, timeStepIndices );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
RimFlowDiagnosticsTools::setOfProducerTracersFromInjectors( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& injectorTracers,
|
||||
std::vector<int> timeStepIndices )
|
||||
{
|
||||
if ( !flowSol ) return {};
|
||||
|
||||
const double epsilon = 1.0e-8;
|
||||
const bool isInjector = false;
|
||||
std::set<QString, TracerComp> communicatingProducers;
|
||||
std::set<QString, TracerComp> producers = RimFlowDiagnosticsTools::setOfTracersOfType( flowSol, isInjector );
|
||||
for ( const QString& injector : injectorTracers )
|
||||
{
|
||||
for ( const QString& producer : producers )
|
||||
{
|
||||
for ( const auto& timeStepIndex : timeStepIndices )
|
||||
{
|
||||
std::pair<double, double> commFluxes =
|
||||
flowSol->flowDiagResults()->injectorProducerPairFluxes( injector.toStdString(), producer.toStdString(), timeStepIndex );
|
||||
if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon )
|
||||
{
|
||||
communicatingProducers.insert( producer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return communicatingProducers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
RimFlowDiagnosticsTools::setOfProducerTracersFromInjectors( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& injectorTracers,
|
||||
int timeStepIndex )
|
||||
{
|
||||
const auto timeStepIndices = std::vector<int>( { timeStepIndex } );
|
||||
return setOfProducerTracersFromInjectors( flowSol, injectorTracers, timeStepIndices );
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimFlowDiagSolution.h"
|
||||
#include "cafPdmUiItem.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
namespace RimFlowDiagnosticsTools
|
||||
{
|
||||
// --- Structures ---
|
||||
struct TracerComp
|
||||
{
|
||||
bool operator()( const QString& lhs, const QString& rhs ) const;
|
||||
};
|
||||
|
||||
// --- Methods ---
|
||||
QList<caf::PdmOptionItemInfo> calcOptionsForSelectedTracerField( RimFlowDiagSolution* flowSol, bool isInjector );
|
||||
std::set<QString, TracerComp> setOfTracersOfType( RimFlowDiagSolution* flowSol, bool isInjector );
|
||||
|
||||
std::vector<QString> producerTracersInTimeStep( RimFlowDiagSolution* flowSol, int timeStepIndex );
|
||||
std::vector<QString> injectorTracersInTimeStep( RimFlowDiagSolution* flowSol, int timeStepIndex );
|
||||
std::vector<QString> tracersOfStatusInTimeStep( RimFlowDiagSolution* flowSol, RimFlowDiagSolution::TracerStatusType status, int timeStepIndex );
|
||||
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp> setOfInjectorTracersFromProducers( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& producerTracers,
|
||||
std::vector<int> timeStepIndices );
|
||||
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
setOfInjectorTracersFromProducers( RimFlowDiagSolution* flowSol, const std::vector<QString>& producerTracers, int timeStepIndex );
|
||||
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp> setOfProducerTracersFromInjectors( RimFlowDiagSolution* flowSol,
|
||||
const std::vector<QString>& injectorTracers,
|
||||
std::vector<int> timeStepIndices );
|
||||
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp>
|
||||
setOfProducerTracersFromInjectors( RimFlowDiagSolution* flowSol, const std::vector<QString>& injectorTracers, int timeStepIndex );
|
||||
|
||||
}; // namespace RimFlowDiagnosticsTools
|
@ -22,6 +22,7 @@
|
||||
#include "RimProject.h"
|
||||
#include "RimWellAllocationOverTimePlot.h"
|
||||
#include "RimWellAllocationPlot.h"
|
||||
#include "RimWellConnectivityTable.h"
|
||||
#include "RimWellDistributionPlotCollection.h"
|
||||
|
||||
#include "cafProgressInfo.h"
|
||||
@ -39,6 +40,9 @@ RimFlowPlotCollection::RimFlowPlotCollection()
|
||||
CAF_PDM_InitFieldNoDefault( &m_flowCharacteristicsPlot, "FlowCharacteristicsPlot", "" );
|
||||
m_flowCharacteristicsPlot.uiCapability()->setUiTreeHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_defaultWellConnectivityTable, "DefaultWellConnectivityTable", "" );
|
||||
m_defaultWellConnectivityTable.uiCapability()->setUiTreeHidden( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_defaultWellAllocOverTimePlot, "DefaultWellAllocationOverTimePlot", "" );
|
||||
m_defaultWellAllocOverTimePlot.uiCapability()->setUiTreeHidden( true );
|
||||
|
||||
@ -72,6 +76,7 @@ void RimFlowPlotCollection::deleteAllPlots()
|
||||
m_defaultWellAllocPlot->removeFromMdiAreaAndDeleteViewWidget();
|
||||
delete m_defaultWellAllocPlot();
|
||||
}
|
||||
delete m_defaultWellConnectivityTable;
|
||||
delete m_defaultWellAllocOverTimePlot;
|
||||
delete m_flowCharacteristicsPlot;
|
||||
delete m_wellDistributionPlotCollection;
|
||||
@ -90,6 +95,9 @@ void RimFlowPlotCollection::loadDataAndUpdateAllPlots()
|
||||
if ( m_defaultWellAllocPlot ) m_defaultWellAllocPlot->loadDataAndUpdate();
|
||||
plotProgress.incrementProgress();
|
||||
|
||||
if ( m_defaultWellConnectivityTable ) m_defaultWellConnectivityTable->loadDataAndUpdate();
|
||||
plotProgress.incrementProgress();
|
||||
|
||||
if ( m_defaultWellAllocOverTimePlot ) m_defaultWellAllocOverTimePlot->loadDataAndUpdate();
|
||||
plotProgress.incrementProgress();
|
||||
|
||||
@ -123,6 +131,7 @@ size_t RimFlowPlotCollection::plotCount() const
|
||||
{
|
||||
size_t plotCount = 0;
|
||||
plotCount += m_defaultWellAllocPlot ? 1 : 0;
|
||||
plotCount += m_defaultWellConnectivityTable ? 1 : 0;
|
||||
plotCount += m_defaultWellAllocOverTimePlot ? 1 : 0;
|
||||
plotCount += m_storedWellAllocPlots.size();
|
||||
plotCount += m_storedFlowCharacteristicsPlots.size();
|
||||
@ -145,6 +154,21 @@ void RimFlowPlotCollection::addFlowCharacteristicsPlotToStoredPlots( RimFlowChar
|
||||
m_storedFlowCharacteristicsPlots.push_back( plot );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellConnectivityTable* RimFlowPlotCollection::defaultWellConnectivityTable()
|
||||
{
|
||||
if ( !m_defaultWellConnectivityTable )
|
||||
{
|
||||
m_defaultWellConnectivityTable = new RimWellConnectivityTable;
|
||||
}
|
||||
|
||||
this->updateConnectedEditors();
|
||||
|
||||
return m_defaultWellConnectivityTable;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -217,6 +241,11 @@ void RimFlowPlotCollection::ensureDefaultFlowPlotsAreCreated()
|
||||
m_defaultWellAllocOverTimePlot->setDescription( "Default Well Allocation Over Time Plot" );
|
||||
}
|
||||
|
||||
if ( !m_defaultWellConnectivityTable() )
|
||||
{
|
||||
m_defaultWellConnectivityTable = new RimWellConnectivityTable;
|
||||
}
|
||||
|
||||
if ( !m_flowCharacteristicsPlot() )
|
||||
{
|
||||
m_flowCharacteristicsPlot = new RimFlowCharacteristicsPlot;
|
||||
|
@ -29,6 +29,7 @@ class RimWellAllocationPlot;
|
||||
class RimFlowCharacteristicsPlot;
|
||||
class RimWellDistributionPlot;
|
||||
class RimWellDistributionPlotCollection;
|
||||
class RimWellConnectivityTable;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
@ -48,6 +49,7 @@ public:
|
||||
|
||||
void addWellAllocPlotToStoredPlots( RimWellAllocationPlot* plot );
|
||||
void addFlowCharacteristicsPlotToStoredPlots( RimFlowCharacteristicsPlot* plot );
|
||||
RimWellConnectivityTable* defaultWellConnectivityTable();
|
||||
RimWellAllocationOverTimePlot* defaultWellAllocOverTimePlot();
|
||||
RimWellAllocationPlot* defaultWellAllocPlot();
|
||||
RimFlowCharacteristicsPlot* defaultFlowCharacteristicsPlot();
|
||||
@ -56,6 +58,7 @@ public:
|
||||
|
||||
private:
|
||||
caf::PdmChildField<RimFlowCharacteristicsPlot*> m_flowCharacteristicsPlot;
|
||||
caf::PdmChildField<RimWellConnectivityTable*> m_defaultWellConnectivityTable;
|
||||
caf::PdmChildField<RimWellAllocationOverTimePlot*> m_defaultWellAllocOverTimePlot;
|
||||
caf::PdmChildField<RimWellAllocationPlot*> m_defaultWellAllocPlot;
|
||||
caf::PdmChildField<RimWellDistributionPlotCollection*> m_wellDistributionPlotCollection;
|
||||
|
@ -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
|
||||
// Create well allocation over time data
|
||||
const auto selectedTimeStepsVector = std::vector( selectedTimeSteps.begin(), selectedTimeSteps.end() );
|
||||
RimWellAllocationOverTimeCollection collection( selectedTimeStepsVector, timeStepAndCalculatorPairs );
|
||||
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 )
|
||||
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() );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
class RigAccWellFlowCalculator;
|
||||
class RimEclipseResultCase;
|
||||
class RimFlowDiagSolution;
|
||||
class RimWellAllocationOverTimeCollection;
|
||||
class RigWellAllocationOverTime;
|
||||
class RimSimWellInView;
|
||||
class RiuPlotWidget;
|
||||
class RiuQwtPlotWidget;
|
||||
@ -102,7 +102,7 @@ private:
|
||||
void doUpdateLayout() override;
|
||||
|
||||
void updateFromWell();
|
||||
RimWellAllocationOverTimeCollection createWellAllocationOverTimeCollection() const;
|
||||
RigWellAllocationOverTime createWellAllocationOverTime() const;
|
||||
std::set<QString> findSortedWellNames();
|
||||
cvf::Color3f getTracerColor( const QString& tracerName );
|
||||
|
||||
@ -118,9 +118,7 @@ private:
|
||||
int axisTitleFontSize() const;
|
||||
int axisValueFontSize() const;
|
||||
|
||||
std::vector<QDateTime> getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps ) const;
|
||||
std::set<QDateTime> getSelectedTimeSteps( const std::vector<QDateTime>& timeSteps ) const;
|
||||
static std::set<QDateTime> createEvenlyDistributedDates( const std::vector<QDateTime>& inputDates, int numDates );
|
||||
|
||||
private:
|
||||
caf::PdmField<QString> m_userName;
|
||||
|
@ -266,7 +266,8 @@ void RimWellAllocationPlot::updateFromWell()
|
||||
bool isProducer = ( simWellData->wellProductionType( m_timeStep ) == RiaDefines::WellProductionType::PRODUCER ||
|
||||
simWellData->wellProductionType( m_timeStep ) == 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 );
|
||||
wfCalculator.reset( new RigAccWellFlowCalculator( pipeBranchesCLCoords,
|
||||
pipeBranchesCellIds,
|
||||
tracerFractionCellValues,
|
||||
|
@ -20,16 +20,30 @@
|
||||
|
||||
#include "RiaDefines.h"
|
||||
|
||||
#include "RigFlowDiagResultAddress.h"
|
||||
#include "RigFlowDiagResults.h"
|
||||
#include "RigSimWellData.h"
|
||||
|
||||
#include "RimFlowDiagSolution.h"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<QString, const std::vector<double>*>
|
||||
RimWellAllocationTools::findOrCreateRelevantTracerCellFractions( const RigSimWellData* simWellData,
|
||||
RimFlowDiagSolution* flowDiagSolution,
|
||||
int timeStepIndex )
|
||||
{
|
||||
return findOrCreateRelevantTracerCellFractions( simWellData, flowDiagSolution, RigFlowDiagResultAddress::PHASE_ALL, timeStepIndex );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<QString, const std::vector<double>*>
|
||||
RimWellAllocationTools::findOrCreateRelevantTracerCellFractions( const RigSimWellData* simWellData,
|
||||
RimFlowDiagSolution* flowDiagSolution,
|
||||
RigFlowDiagResultAddress::PhaseSelection phaseSelection,
|
||||
int timeStepIndex )
|
||||
{
|
||||
std::map<QString, const std::vector<double>*> tracerCellFractionValues = {};
|
||||
if ( flowDiagSolution && simWellData->hasWellResult( timeStepIndex ) )
|
||||
@ -51,7 +65,7 @@ std::map<QString, const std::vector<double>*>
|
||||
{
|
||||
if ( flowDiagSolution->tracerStatusInTimeStep( tracerName, timeStepIndex ) == requestedTracerType )
|
||||
{
|
||||
RigFlowDiagResultAddress resAddr( RIG_FLD_CELL_FRACTION_RESNAME, RigFlowDiagResultAddress::PHASE_ALL, tracerName.toStdString() );
|
||||
RigFlowDiagResultAddress resAddr( RIG_FLD_CELL_FRACTION_RESNAME, phaseSelection, tracerName.toStdString() );
|
||||
const std::vector<double>* tracerCellFractions = flowDiagSolution->flowDiagResults()->resultValues( resAddr, timeStepIndex );
|
||||
if ( tracerCellFractions )
|
||||
{
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RigFlowDiagResultAddress.h"
|
||||
|
||||
#include <QString>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -32,4 +34,9 @@ namespace RimWellAllocationTools
|
||||
{
|
||||
std::map<QString, const std::vector<double>*>
|
||||
findOrCreateRelevantTracerCellFractions( const RigSimWellData* simWellData, RimFlowDiagSolution* flowDiagSolution, int timeStepIndex );
|
||||
}
|
||||
|
||||
std::map<QString, const std::vector<double>*> findOrCreateRelevantTracerCellFractions( const RigSimWellData* simWellData,
|
||||
RimFlowDiagSolution* flowDiagSolution,
|
||||
RigFlowDiagResultAddress::PhaseSelection phaseSelection,
|
||||
int timeStepIndex );
|
||||
} // namespace RimWellAllocationTools
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,183 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimPlotWindow.h"
|
||||
|
||||
#include "RigFlowDiagResultAddress.h"
|
||||
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmPtrField.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QPointer>
|
||||
#include <QString>
|
||||
|
||||
class RimEclipseResultCase;
|
||||
class RimEclipseView;
|
||||
class RimFlowDiagSolution;
|
||||
class RimRegularLegendConfig;
|
||||
class RimSimWellInView;
|
||||
class RigWellAllocationOverTime;
|
||||
class RiuMatrixPlotWidget;
|
||||
class RigSimWellData;
|
||||
class RigAccWellFlowCalculator;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimWellConnectivityTable : public RimPlotWindow
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
enum class TimeStepSelection
|
||||
{
|
||||
SINGLE_TIME_STEP,
|
||||
TIME_STEP_RANGE,
|
||||
};
|
||||
|
||||
enum class TimeSampleValueType
|
||||
{
|
||||
FLOW_RATE,
|
||||
FLOW_RATE_FRACTION,
|
||||
FLOW_RATE_PERCENTAGE,
|
||||
};
|
||||
enum class TimeRangeValueType
|
||||
{
|
||||
ACCUMULATED_FLOW_VOLUME,
|
||||
ACCUMULATED_FLOW_VOLUME_FRACTION,
|
||||
ACCUMULATED_FLOW_VOLUME_PERCENTAGE,
|
||||
};
|
||||
|
||||
enum class TimeStepRangeFilterMode
|
||||
{
|
||||
NONE,
|
||||
TIME_STEP_COUNT,
|
||||
};
|
||||
|
||||
public:
|
||||
RimWellConnectivityTable();
|
||||
~RimWellConnectivityTable() override;
|
||||
|
||||
void setFromSimulationWell( RimSimWellInView* simWell );
|
||||
|
||||
private:
|
||||
void cleanupBeforeClose();
|
||||
|
||||
void onLoadDataAndUpdate() override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||
|
||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||
|
||||
// Inherited via RimPlotWindow
|
||||
virtual QString description() const override;
|
||||
virtual void doRenderWindowContent( QPaintDevice* paintDevice ) override;
|
||||
|
||||
// Inherited via RimViewWindow
|
||||
virtual QWidget* viewWidget() override;
|
||||
virtual QImage snapshotWindowContent() override;
|
||||
virtual void zoomAll() override;
|
||||
virtual QWidget* createViewWidget( QWidget* mainWindowParent ) override;
|
||||
virtual void deleteViewWidget() override;
|
||||
|
||||
int axisTitleFontSize() const;
|
||||
int axisLabelFontSize() const;
|
||||
int valueLabelFontSize() const;
|
||||
|
||||
private:
|
||||
std::map<QString, RigWellAllocationOverTime>
|
||||
createProductionWellsAllocationOverTimeMap( const std::set<QString>& selectedProductionWells ) const;
|
||||
RigWellAllocationOverTime createWellAllocationOverTime( const RigSimWellData* simWellData ) const;
|
||||
|
||||
void createAndEmplaceTimeStepAndCalculatorPairInMap( std::map<QDateTime, RigAccWellFlowCalculator>& rTimeStepAndCalculatorPairs,
|
||||
const QDateTime timeStep,
|
||||
int timeStepIndex,
|
||||
const RigSimWellData* simWellData ) const;
|
||||
|
||||
std::set<QDateTime> getSelectedTimeSteps( const std::vector<QDateTime>& timeSteps ) const;
|
||||
QString dateFormatString() const;
|
||||
std::vector<QString> getProductionWellNames() const;
|
||||
std::vector<QString> getProductionWellNamesAtTimeSteps( const std::set<QDateTime>& timeSteps ) const;
|
||||
|
||||
QString createTableTitle() const;
|
||||
|
||||
std::pair<double, double> createLegendMinMaxValues( const double maxTableValue ) const;
|
||||
|
||||
void setValidTimeStepSelectionsForCase();
|
||||
void setValidSingleTimeStepForCase();
|
||||
void setValidTimeStepRangeForCase();
|
||||
bool isTimeStepInCase( const QDateTime& timeStep ) const;
|
||||
|
||||
int getTimeStepIndex( const QDateTime timeStep, const std::vector<QDateTime> timeSteps ) const;
|
||||
void setSelectedProducersAndInjectorsForSingleTimeStep();
|
||||
void setSelectedProducersAndInjectorsForTimeStepRange();
|
||||
|
||||
void syncSelectedInjectorsFromProducerSelection();
|
||||
void syncSelectedProducersFromInjectorSelection();
|
||||
|
||||
void onCellFiltersChanged( const SignalEmitter* emitter );
|
||||
void connectViewCellFiltersChangedToSlot( RimEclipseView* view );
|
||||
void disconnectViewCellFiltersChangedFromSlots( RimEclipseView* view );
|
||||
|
||||
private:
|
||||
// Matrix plot for visualizing table data
|
||||
QPointer<RiuMatrixPlotWidget> m_matrixPlotWidget;
|
||||
|
||||
caf::PdmPtrField<RimEclipseResultCase*> m_case;
|
||||
caf::PdmPtrField<RimEclipseView*> m_cellFilterView;
|
||||
caf::PdmPtrField<RimFlowDiagSolution*> m_flowDiagSolution;
|
||||
|
||||
caf::PdmField<caf::AppEnum<TimeStepSelection>> m_timeStepSelection;
|
||||
caf::PdmField<caf::AppEnum<TimeSampleValueType>> m_timeSampleValueType;
|
||||
caf::PdmField<caf::AppEnum<TimeRangeValueType>> m_timeRangeValueType;
|
||||
|
||||
caf::PdmField<bool> m_selectProducersAndInjectorsForTimeSteps;
|
||||
|
||||
caf::PdmField<double> m_thresholdValue;
|
||||
|
||||
// For single time sample
|
||||
caf::PdmField<QDateTime> m_selectedTimeStep;
|
||||
|
||||
// For time step range
|
||||
caf::PdmField<QDateTime> m_selectedFromTimeStep;
|
||||
caf::PdmField<QDateTime> m_selectedToTimeStep;
|
||||
caf::PdmField<caf::AppEnum<TimeStepRangeFilterMode>> m_timeStepFilterMode;
|
||||
caf::PdmField<int> m_timeStepCount;
|
||||
caf::PdmField<std::vector<QDateTime>> m_excludeTimeSteps;
|
||||
caf::PdmField<bool> m_applyTimeStepSelections;
|
||||
|
||||
caf::PdmChildField<RimRegularLegendConfig*> m_legendConfig;
|
||||
|
||||
caf::PdmField<std::vector<QString>> m_selectedInjectorTracersUiField;
|
||||
caf::PdmField<std::vector<QString>> m_selectedProducerTracersUiField;
|
||||
caf::PdmField<bool> m_syncSelectedProducersFromInjectorSelection;
|
||||
caf::PdmField<bool> m_syncSelectedInjectorsFromProducerSelection;
|
||||
caf::PdmField<bool> m_applySelectedInectorProducerTracers;
|
||||
|
||||
caf::PdmField<caf::FontTools::RelativeSizeEnum> m_axisTitleFontSize;
|
||||
caf::PdmField<caf::FontTools::RelativeSizeEnum> m_axisLabelFontSize;
|
||||
caf::PdmField<caf::FontTools::RelativeSizeEnum> m_valueLabelFontSize;
|
||||
caf::PdmField<bool> m_showValueLabels;
|
||||
|
||||
const int m_initialNumberOfTimeSteps = 10;
|
||||
};
|
@ -54,6 +54,7 @@
|
||||
#include "RimEclipseResultCase.h"
|
||||
#include "RimEclipseView.h"
|
||||
#include "RimFlowDiagSolution.h"
|
||||
#include "RimFlowDiagnosticsTools.h"
|
||||
#include "RimGridCrossPlot.h"
|
||||
#include "RimGridCrossPlotDataSet.h"
|
||||
#include "RimGridTimeHistoryCurve.h"
|
||||
@ -753,11 +754,13 @@ QList<caf::PdmOptionItemInfo> RimEclipseResultDefinition::calculateValueOptions(
|
||||
}
|
||||
else if ( fieldNeedingOptions == &m_selectedInjectorTracersUiField )
|
||||
{
|
||||
options = calcOptionsForSelectedTracerField( true );
|
||||
const bool isInjector = true;
|
||||
options = RimFlowDiagnosticsTools::calcOptionsForSelectedTracerField( m_flowSolutionUiField(), isInjector );
|
||||
}
|
||||
else if ( fieldNeedingOptions == &m_selectedProducerTracersUiField )
|
||||
{
|
||||
options = calcOptionsForSelectedTracerField( false );
|
||||
const bool isInjector = false;
|
||||
options = RimFlowDiagnosticsTools::calcOptionsForSelectedTracerField( m_flowSolutionUiField(), isInjector );
|
||||
}
|
||||
}
|
||||
else if ( m_resultTypeUiField() == RiaDefines::ResultCatType::INJECTION_FLOODING )
|
||||
@ -1644,25 +1647,6 @@ void RimEclipseResultDefinition::defineEditorAttribute( const caf::PdmFieldHandl
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimEclipseResultDefinition::TracerComp::operator()( const QString& lhs, const QString& rhs ) const
|
||||
{
|
||||
if ( !lhs.endsWith( "-XF" ) && rhs.endsWith( "-XF" ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ( lhs.endsWith( "-XF" ) && !rhs.endsWith( "-XF" ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -2243,36 +2227,6 @@ void RimEclipseResultDefinition::updateLegendTitle( RimRegularLegendConfig* lege
|
||||
legendConfig->setTitle( title );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RimEclipseResultDefinition::calcOptionsForSelectedTracerField( bool injector )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
RimFlowDiagSolution* flowSol = m_flowSolutionUiField();
|
||||
if ( flowSol )
|
||||
{
|
||||
std::set<QString, TracerComp> sortedTracers = setOfTracersOfType( injector );
|
||||
|
||||
for ( const QString& tracerName : sortedTracers )
|
||||
{
|
||||
QString postfix;
|
||||
RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName );
|
||||
if ( status == RimFlowDiagSolution::TracerStatusType::VARYING )
|
||||
{
|
||||
postfix = " [I/P]";
|
||||
}
|
||||
else if ( status == RimFlowDiagSolution::TracerStatusType::UNDEFINED )
|
||||
{
|
||||
postfix = " [U]";
|
||||
}
|
||||
options.push_back( caf::PdmOptionItemInfo( tracerName + postfix, tracerName ) );
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -2418,50 +2372,6 @@ QStringList RimEclipseResultDefinition::getResultNamesForResultType( RiaDefines:
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<QString> RimEclipseResultDefinition::allTracerNames() const
|
||||
{
|
||||
std::vector<QString> tracerNames;
|
||||
|
||||
RimFlowDiagSolution* flowSol = m_flowSolutionUiField();
|
||||
if ( flowSol )
|
||||
{
|
||||
tracerNames = flowSol->tracerNames();
|
||||
}
|
||||
|
||||
return tracerNames;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::set<QString, RimEclipseResultDefinition::TracerComp> RimEclipseResultDefinition::setOfTracersOfType( bool injector ) const
|
||||
{
|
||||
std::set<QString, TracerComp> sortedTracers;
|
||||
|
||||
RimFlowDiagSolution* flowSol = m_flowSolutionUiField();
|
||||
if ( flowSol )
|
||||
{
|
||||
std::vector<QString> tracerNames = allTracerNames();
|
||||
for ( const QString& tracerName : tracerNames )
|
||||
{
|
||||
RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall( tracerName );
|
||||
bool includeTracer = status == RimFlowDiagSolution::TracerStatusType::VARYING ||
|
||||
status == RimFlowDiagSolution::TracerStatusType::UNDEFINED;
|
||||
includeTracer |= injector && status == RimFlowDiagSolution::TracerStatusType::INJECTOR;
|
||||
includeTracer |= !injector && status == RimFlowDiagSolution::TracerStatusType::PRODUCER;
|
||||
|
||||
if ( includeTracer )
|
||||
{
|
||||
sortedTracers.insert( tracerName );
|
||||
}
|
||||
}
|
||||
}
|
||||
return sortedTracers;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -2473,7 +2383,8 @@ RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition:
|
||||
}
|
||||
else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION )
|
||||
{
|
||||
if ( m_selectedInjectorTracers().size() == setOfTracersOfType( true ).size() )
|
||||
const bool isInjector = true;
|
||||
if ( m_selectedInjectorTracers().size() == RimFlowDiagnosticsTools::setOfTracersOfType( m_flowSolutionUiField(), isInjector ).size() )
|
||||
{
|
||||
return ALL_SELECTED;
|
||||
}
|
||||
@ -2500,7 +2411,8 @@ RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition:
|
||||
}
|
||||
else if ( m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION )
|
||||
{
|
||||
if ( m_selectedProducerTracers().size() == setOfTracersOfType( false ).size() )
|
||||
const bool isInjector = false;
|
||||
if ( m_selectedProducerTracers().size() == RimFlowDiagnosticsTools::setOfTracersOfType( m_flowSolutionUiField(), isInjector ).size() )
|
||||
{
|
||||
return ALL_SELECTED;
|
||||
}
|
||||
@ -2521,8 +2433,6 @@ RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition:
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipseResultDefinition::syncInjectorToProducerSelection()
|
||||
{
|
||||
const double epsilon = 1.0e-8;
|
||||
|
||||
int timeStep = 0;
|
||||
|
||||
Rim3dView* rimView = nullptr;
|
||||
@ -2535,21 +2445,8 @@ void RimEclipseResultDefinition::syncInjectorToProducerSelection()
|
||||
RimFlowDiagSolution* flowSol = m_flowSolution();
|
||||
if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION )
|
||||
{
|
||||
std::set<QString, TracerComp> producers = setOfTracersOfType( false );
|
||||
|
||||
std::set<QString, TracerComp> newProducerSelection;
|
||||
for ( const QString& selectedInjector : m_selectedInjectorTracers() )
|
||||
{
|
||||
for ( const QString& producer : producers )
|
||||
{
|
||||
std::pair<double, double> commFluxes =
|
||||
flowSol->flowDiagResults()->injectorProducerPairFluxes( selectedInjector.toStdString(), producer.toStdString(), timeStep );
|
||||
if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon )
|
||||
{
|
||||
newProducerSelection.insert( producer );
|
||||
}
|
||||
}
|
||||
}
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp> newProducerSelection =
|
||||
RimFlowDiagnosticsTools::setOfProducerTracersFromInjectors( m_flowSolutionUiField(), m_selectedInjectorTracers(), timeStep );
|
||||
// Add all currently selected producers to set
|
||||
for ( const QString& selectedProducer : m_selectedProducerTracers() )
|
||||
{
|
||||
@ -2565,8 +2462,6 @@ void RimEclipseResultDefinition::syncInjectorToProducerSelection()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEclipseResultDefinition::syncProducerToInjectorSelection()
|
||||
{
|
||||
const double epsilon = 1.0e-8;
|
||||
|
||||
int timeStep = 0;
|
||||
|
||||
Rim3dView* rimView = nullptr;
|
||||
@ -2579,21 +2474,9 @@ void RimEclipseResultDefinition::syncProducerToInjectorSelection()
|
||||
RimFlowDiagSolution* flowSol = m_flowSolution();
|
||||
if ( flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION )
|
||||
{
|
||||
std::set<QString, TracerComp> injectors = setOfTracersOfType( true );
|
||||
std::set<QString, RimFlowDiagnosticsTools::TracerComp> newInjectorSelection =
|
||||
RimFlowDiagnosticsTools::setOfInjectorTracersFromProducers( m_flowSolutionUiField(), m_selectedProducerTracers(), timeStep );
|
||||
|
||||
std::set<QString, TracerComp> newInjectorSelection;
|
||||
for ( const QString& selectedProducer : m_selectedProducerTracers() )
|
||||
{
|
||||
for ( const QString& injector : injectors )
|
||||
{
|
||||
std::pair<double, double> commFluxes =
|
||||
flowSol->flowDiagResults()->injectorProducerPairFluxes( injector.toStdString(), selectedProducer.toStdString(), timeStep );
|
||||
if ( std::abs( commFluxes.first ) > epsilon || std::abs( commFluxes.second ) > epsilon )
|
||||
{
|
||||
newInjectorSelection.insert( injector );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add all currently selected injectors to set
|
||||
for ( const QString& selectedInjector : m_selectedInjectorTracers() )
|
||||
{
|
||||
|
@ -188,11 +188,6 @@ protected:
|
||||
caf::PdmPointer<RimEclipseCase> m_eclipseCase;
|
||||
|
||||
private:
|
||||
struct TracerComp
|
||||
{
|
||||
bool operator()( const QString& lhs, const QString& rhs ) const;
|
||||
};
|
||||
|
||||
caf::PdmField<int> m_timeLapseBaseTimestep;
|
||||
caf::PdmPtrField<RimEclipseCase*> m_differenceCase;
|
||||
caf::PdmField<bool> m_divideByCellFaceArea;
|
||||
@ -202,8 +197,6 @@ private:
|
||||
|
||||
QString flowDiagResUiText( bool shortLabel, int maxTracerStringLength = std::numeric_limits<int>::max() ) const;
|
||||
|
||||
QList<caf::PdmOptionItemInfo> calcOptionsForSelectedTracerField( bool injector );
|
||||
|
||||
QString timeOfFlightString( bool shorter ) const;
|
||||
QString maxFractionTracerString( bool shorter ) const;
|
||||
|
||||
@ -212,9 +205,6 @@ private:
|
||||
void changedTracerSelectionField( bool injector );
|
||||
static QStringList getResultNamesForResultType( RiaDefines::ResultCatType resultCatType, const RigCaseCellResultsData* results );
|
||||
|
||||
std::vector<QString> allTracerNames() const;
|
||||
std::set<QString, TracerComp> setOfTracersOfType( bool injector ) const;
|
||||
|
||||
FlowTracerSelectionState injectorSelectionState() const;
|
||||
FlowTracerSelectionState producerSelectionState() const;
|
||||
|
||||
|
@ -103,6 +103,7 @@ void RimRegularLegendConfig::ColorRangeEnum::setUp()
|
||||
addItem( RimRegularLegendConfig::ColorRangesType::GREEN_RED, "GREEN_RED", "Green to Red" );
|
||||
addItem( RimRegularLegendConfig::ColorRangesType::BLUE_MAGENTA, "BLUE_MAGENTA", "Blue to Magenta" );
|
||||
addItem( RimRegularLegendConfig::ColorRangesType::CORRELATION, "CORRELATION", "Correlation colors" );
|
||||
addItem( RimRegularLegendConfig::ColorRangesType::HEAT_MAP, "HEAT_MAP", "Heat map colors" );
|
||||
addItem( RimRegularLegendConfig::ColorRangesType::UNDEFINED, "UNDEFINED", "Undefined" );
|
||||
setDefault( RimRegularLegendConfig::ColorRangesType::UNDEFINED );
|
||||
}
|
||||
@ -392,6 +393,7 @@ void RimRegularLegendConfig::updateLegend()
|
||||
{
|
||||
m_significantDigitsInData = m_precision;
|
||||
|
||||
updateTickCountAndUserDefinedRange();
|
||||
if ( m_resetUserDefinedValues && m_globalAutoMax != cvf::UNDEFINED_DOUBLE )
|
||||
{
|
||||
updateTickCountAndUserDefinedRange();
|
||||
@ -1112,6 +1114,9 @@ cvf::Color3ubArray RimRegularLegendConfig::colorArrayFromColorType( ColorRangesT
|
||||
case RimRegularLegendConfig::ColorRangesType::CORRELATION:
|
||||
return RiaColorTables::correlationPaletteColors().color3ubArray();
|
||||
break;
|
||||
case RimRegularLegendConfig::ColorRangesType::HEAT_MAP:
|
||||
return RiaColorTables::heatMapPaletteColors().color3ubArray();
|
||||
break;
|
||||
default:
|
||||
if ( ColorManager::isEnsembleColorRange( colorType ) ) return ColorManager::EnsembleColorRanges().at( colorType );
|
||||
break;
|
||||
@ -1229,6 +1234,13 @@ void RimRegularLegendConfig::defineUiOrdering( QString uiConfigName, caf::PdmUiO
|
||||
uiOrdering.add( &m_colorLegend );
|
||||
uiOrdering.skipRemainingFields( true );
|
||||
}
|
||||
else if ( uiConfigName == "FlagColorsAndMappingModeOnly" )
|
||||
{
|
||||
uiOrdering.add( &m_showLegend );
|
||||
uiOrdering.add( &m_colorLegend );
|
||||
uiOrdering.add( &m_mappingMode );
|
||||
uiOrdering.skipRemainingFields( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
caf::PdmUiOrdering* formatGr = uiOrdering.addNewGroup( "Format" );
|
||||
|
@ -97,6 +97,8 @@ public:
|
||||
|
||||
CORRELATION,
|
||||
|
||||
HEAT_MAP,
|
||||
|
||||
UNDEFINED
|
||||
};
|
||||
|
||||
|
@ -88,6 +88,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellAllocationOverTime.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -173,6 +174,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RigWellAllocationOverTime.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include "RigAccWellFlowCalculator.h"
|
||||
|
||||
#include "RiaWellFlowDefines.h"
|
||||
|
||||
#include "RigActiveCellInfo.h"
|
||||
#include "RigFlowDiagResults.h"
|
||||
#include "RigMainGrid.h"
|
||||
@ -37,12 +39,23 @@
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RigEclCellIndexCalculator::resultCellIndex( size_t gridIndex, size_t gridCellIndex ) const
|
||||
{
|
||||
const RigGridBase* grid = m_mainGrid->gridByIndex( gridIndex );
|
||||
size_t reservoirCellIndex = grid->reservoirCellIndex( gridCellIndex );
|
||||
size_t reservoirCellIndex = m_mainGrid->reservoirCellIndexByGridAndGridLocalCellIndex( gridIndex, gridCellIndex );
|
||||
|
||||
return m_activeCellInfo->cellResultIndex( reservoirCellIndex );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RigEclCellIndexCalculator::isCellVisible( size_t gridIndex, size_t gridCellIndex ) const
|
||||
{
|
||||
if ( !m_cellVisibilities ) return true;
|
||||
|
||||
size_t reservoirCellIndex = m_mainGrid->reservoirCellIndexByGridAndGridLocalCellIndex( gridIndex, gridCellIndex );
|
||||
|
||||
return ( *m_cellVisibilities )[reservoirCellIndex];
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
@ -73,7 +86,7 @@ RigAccWellFlowCalculator::RigAccWellFlowCalculator( const std::vector<std::vecto
|
||||
for ( const auto& it : ( *m_tracerCellFractionValues ) )
|
||||
m_tracerNames.push_back( it.first );
|
||||
|
||||
m_tracerNames.push_back( RIG_RESERVOIR_TRACER_NAME );
|
||||
m_tracerNames.push_back( RiaDefines::reservoirTracerName() );
|
||||
|
||||
initializePipeBranchesMeasuredDepths();
|
||||
calculateFlowData();
|
||||
@ -90,7 +103,7 @@ RigAccWellFlowCalculator::RigAccWellFlowCalculator( const std::vector<std::vecto
|
||||
: m_pipeBranchesCLCoords( pipeBranchesCLCoords )
|
||||
, m_pipeBranchesWellResultPoints( pipeBranchesWellResultPoints )
|
||||
, m_tracerCellFractionValues( nullptr )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr ) )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr, nullptr ) )
|
||||
, m_smallContributionsThreshold( smallContribThreshold )
|
||||
, m_isProducer( true )
|
||||
, m_useTotalWellPhaseRateOnly( false )
|
||||
@ -123,7 +136,7 @@ RigAccWellFlowCalculator::RigAccWellFlowCalculator( const std::vector<cvf::Vec3d
|
||||
const std::vector<double>& pipeBranchMeasuredDepths,
|
||||
bool totalFlowOnly )
|
||||
: m_tracerCellFractionValues( nullptr )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr ) )
|
||||
, m_cellIndexCalculator( RigEclCellIndexCalculator( nullptr, nullptr, nullptr ) )
|
||||
, m_smallContributionsThreshold( 0.0 )
|
||||
, m_isProducer( true )
|
||||
, m_useTotalWellPhaseRateOnly( totalFlowOnly )
|
||||
@ -697,6 +710,8 @@ std::vector<double> RigAccWellFlowCalculator::calculateWellCellFlowPrTracer( con
|
||||
{
|
||||
std::vector<double> flowPrTracer( m_tracerNames.size(), 0.0 );
|
||||
|
||||
if ( wellCell.isCell() && !m_cellIndexCalculator.isCellVisible( wellCell.gridIndex(), wellCell.cellIndex() ) ) return flowPrTracer;
|
||||
|
||||
if ( !isConnectionFlowConsistent( wellCell ) )
|
||||
{
|
||||
double flowRate = wellCell.flowRate();
|
||||
@ -866,12 +881,16 @@ void RigAccWellFlowCalculator::groupSmallContributions()
|
||||
for ( const auto& tracerPair : totalTracerFractions )
|
||||
{
|
||||
if ( fabs( tracerPair.second ) <= m_smallContributionsThreshold &&
|
||||
( hasConsistentWellFlow || tracerPair.first != RIG_RESERVOIR_TRACER_NAME ) ) // Do not group the
|
||||
// Reservoir tracer if the
|
||||
( hasConsistentWellFlow || tracerPair.first != RiaDefines::reservoirTracerName() ) ) // Do not group
|
||||
// the Reservoir
|
||||
// tracer if the
|
||||
// well flow is
|
||||
// inconsistent, because
|
||||
// cross flow is shown as
|
||||
// the reservoir fraction
|
||||
// inconsistent,
|
||||
// because cross
|
||||
// flow is shown
|
||||
// as the
|
||||
// reservoir
|
||||
// fraction
|
||||
{
|
||||
tracersToGroup.push_back( tracerPair.first );
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cvfArray.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -33,17 +35,20 @@ class RigActiveCellInfo;
|
||||
class RigEclCellIndexCalculator
|
||||
{
|
||||
public:
|
||||
RigEclCellIndexCalculator( const RigMainGrid* mainGrid, const RigActiveCellInfo* activeCellInfo )
|
||||
RigEclCellIndexCalculator( const RigMainGrid* mainGrid, const RigActiveCellInfo* activeCellInfo, const cvf::UByteArray* cellVisibilities )
|
||||
: m_mainGrid( mainGrid )
|
||||
, m_activeCellInfo( activeCellInfo )
|
||||
, m_cellVisibilities( cellVisibilities )
|
||||
{
|
||||
}
|
||||
|
||||
size_t resultCellIndex( size_t gridIndex, size_t gridCellIndex ) const;
|
||||
bool isCellVisible( size_t gridIndex, size_t gridCellIndex ) const;
|
||||
|
||||
private:
|
||||
const RigMainGrid* m_mainGrid;
|
||||
const RigActiveCellInfo* m_activeCellInfo;
|
||||
const cvf::UByteArray* m_cellVisibilities;
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
@ -125,6 +130,9 @@ private:
|
||||
bool m_isProducer;
|
||||
bool m_useTotalWellPhaseRateOnly;
|
||||
|
||||
cvf::UByteArray* m_cellVisibilities = nullptr;
|
||||
RigMainGrid* m_mainGrid = nullptr;
|
||||
|
||||
struct BranchFlow
|
||||
{
|
||||
std::vector<double> depthValuesFromTop;
|
||||
|
@ -16,7 +16,7 @@
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RimWellAllocationOverTimeCollection.h"
|
||||
#include "RigWellAllocationOverTime.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimWellAllocationOverTimeCollection::RimWellAllocationOverTimeCollection( const std::vector<QDateTime>& timeStepDates,
|
||||
RigWellAllocationOverTime::RigWellAllocationOverTime( const std::vector<QDateTime>& timeStepDates,
|
||||
const std::map<QDateTime, RigAccWellFlowCalculator>& timeStepAndCalculatorPairs )
|
||||
: m_timeStepDates( timeStepDates )
|
||||
{
|
||||
@ -84,7 +84,23 @@ RimWellAllocationOverTimeCollection::RimWellAllocationOverTimeCollection( const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::fillWithFlowRatePercentageValues()
|
||||
void RigWellAllocationOverTime::fillWithFlowRateFractionValues()
|
||||
{
|
||||
m_wellValuesMap = m_defaultWellValuesMap;
|
||||
for ( auto& [timeStep, calculator] : m_timeStepAndCalculatorPairs )
|
||||
{
|
||||
const auto totalTracerFractions = calculator.totalTracerFractions();
|
||||
for ( const auto& [wellName, value] : totalTracerFractions )
|
||||
{
|
||||
m_wellValuesMap[wellName][timeStep] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigWellAllocationOverTime::fillWithFlowRatePercentageValues()
|
||||
{
|
||||
m_wellValuesMap = m_defaultWellValuesMap;
|
||||
for ( auto& [timeStep, calculator] : m_timeStepAndCalculatorPairs )
|
||||
@ -101,7 +117,7 @@ void RimWellAllocationOverTimeCollection::fillWithFlowRatePercentageValues()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::fillWithFlowRateValues()
|
||||
void RigWellAllocationOverTime::fillWithFlowRateValues()
|
||||
{
|
||||
m_wellValuesMap = m_defaultWellValuesMap;
|
||||
const size_t branchIdx = 0;
|
||||
@ -121,7 +137,7 @@ void RimWellAllocationOverTimeCollection::fillWithFlowRateValues()
|
||||
///
|
||||
/// Create volume by multiplying with number of days since last time step.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::fillWithFlowVolumeValues()
|
||||
void RigWellAllocationOverTime::fillWithFlowVolumeValues()
|
||||
{
|
||||
fillWithFlowRateValues();
|
||||
|
||||
@ -150,7 +166,7 @@ void RimWellAllocationOverTimeCollection::fillWithFlowVolumeValues()
|
||||
/// Group small contributors in "Others" if accumulated volume value at last time step is below
|
||||
/// threshold value.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::fillWithAccumulatedFlowVolumeValues( double smallContributionsThreshold )
|
||||
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeValues( double smallContributionsThreshold )
|
||||
{
|
||||
fillWithFlowRateValues();
|
||||
|
||||
@ -181,15 +197,34 @@ void RimWellAllocationOverTimeCollection::fillWithAccumulatedFlowVolumeValues( d
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Fill with accumulated well flow volumes in percent of total accumulated flow volume at each
|
||||
/// time step.
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeFractionValues( double smallContributionsThreshold )
|
||||
{
|
||||
fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage::FRACTION, smallContributionsThreshold );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumePercentageValues( double smallContributionsThreshold )
|
||||
{
|
||||
fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage::PERCENTAGE, smallContributionsThreshold );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Fill with accumulated well flow volumes in fraction/percent of total accumulated flow volume
|
||||
/// at each time step.
|
||||
///
|
||||
///
|
||||
/// Group small contributors in "Others" if percentage value for well is below threshold at every
|
||||
/// Group small contributors in "Others" if volume value for well is below threshold at every
|
||||
/// time step.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::fillWithAccumulatedFlowVolumePercentageValues( double smallContributionsThreshold )
|
||||
void RigWellAllocationOverTime::fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage selection,
|
||||
double smallContributionsThreshold )
|
||||
{
|
||||
const double scaling = selection == FractionOrPercentage::FRACTION ? 1.0 : 100.0;
|
||||
|
||||
// Handle threshold filtering afterwards
|
||||
const double nonFilteringThreshold = 0.0;
|
||||
fillWithAccumulatedFlowVolumeValues( nonFilteringThreshold );
|
||||
@ -213,14 +248,14 @@ void RimWellAllocationOverTimeCollection::fillWithAccumulatedFlowVolumePercentag
|
||||
// Create percentage value
|
||||
for ( auto& [well, value] : timeStepWellValues )
|
||||
{
|
||||
m_wellValuesMap[well][timeStep] = 100.0 * value / totalAccumulatedVolume;
|
||||
m_wellValuesMap[well][timeStep] = scaling * value / totalAccumulatedVolume;
|
||||
}
|
||||
}
|
||||
|
||||
if ( smallContributionsThreshold > 0.0 )
|
||||
{
|
||||
const auto percentageThreshold = 100.0 * smallContributionsThreshold;
|
||||
groupAccumulatedFlowVolumePercentages( m_wellValuesMap, percentageThreshold );
|
||||
const auto threshold = scaling * smallContributionsThreshold;
|
||||
groupAccumulatedFlowVolumeFractionsOrPercentages( m_wellValuesMap, threshold );
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,8 +264,7 @@ void RimWellAllocationOverTimeCollection::fillWithAccumulatedFlowVolumePercentag
|
||||
/// Group small contributors in "Others" if accumulated volume value at last time step is below
|
||||
/// threshold value.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::groupAccumulatedFlowVolumes( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap,
|
||||
double threshold )
|
||||
void RigWellAllocationOverTime::groupAccumulatedFlowVolumes( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap, double threshold )
|
||||
{
|
||||
if ( m_timeStepDates.empty() ) return;
|
||||
|
||||
@ -283,13 +317,13 @@ void RimWellAllocationOverTimeCollection::groupAccumulatedFlowVolumes( std::map<
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Handle grouping of small contributors in accumulated volume percentage based on threshold.
|
||||
/// Group small contributors in "Others" if percentage value for well is below threshold at every
|
||||
/// time step. If percentage value is above threshold for one time step or more, show data for well
|
||||
/// Handle grouping of small contributors in accumulated volume fraction/percentage based on threshold.
|
||||
/// Group small contributors in "Others" if fraction/percentage value for well is below threshold at every
|
||||
/// time step. If fraction/percentage value is above threshold for one time step or more, show data for well
|
||||
/// at every time step.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimWellAllocationOverTimeCollection::groupAccumulatedFlowVolumePercentages( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap,
|
||||
double thresholdPercent )
|
||||
void RigWellAllocationOverTime::groupAccumulatedFlowVolumeFractionsOrPercentages( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap,
|
||||
double threshold )
|
||||
{
|
||||
auto getMaxValue = []( const std::map<QDateTime, double>& valuesMap ) -> double {
|
||||
double maxValue = 0.0;
|
||||
@ -305,7 +339,7 @@ void RimWellAllocationOverTimeCollection::groupAccumulatedFlowVolumePercentages(
|
||||
for ( const auto& [well, values] : rWellValuesMap )
|
||||
{
|
||||
const double maxValue = getMaxValue( values );
|
||||
if ( maxValue > thresholdPercent )
|
||||
if ( maxValue > threshold )
|
||||
{
|
||||
contributingWells.push_back( well );
|
||||
}
|
@ -26,24 +26,34 @@
|
||||
|
||||
class RigAccWellFlowCalculator;
|
||||
|
||||
class RimWellAllocationOverTimeCollection
|
||||
class RigWellAllocationOverTime
|
||||
{
|
||||
public:
|
||||
RimWellAllocationOverTimeCollection( const std::vector<QDateTime>& timeStepDates,
|
||||
RigWellAllocationOverTime( const std::vector<QDateTime>& timeStepDates,
|
||||
const std::map<QDateTime, RigAccWellFlowCalculator>& timeStepAndCalculatorPairs );
|
||||
|
||||
const std::vector<QDateTime> timeStepDates() const { return m_timeStepDates; }
|
||||
const std::map<QString, std::map<QDateTime, double>> wellValuesMap() const { return m_wellValuesMap; }
|
||||
|
||||
void fillWithFlowRateFractionValues();
|
||||
void fillWithFlowRatePercentageValues();
|
||||
void fillWithFlowRateValues();
|
||||
void fillWithFlowVolumeValues();
|
||||
void fillWithAccumulatedFlowVolumeValues( double smallContributionsThreshold );
|
||||
void fillWithAccumulatedFlowVolumeFractionValues( double smallContributionsThreshold );
|
||||
void fillWithAccumulatedFlowVolumePercentageValues( double smallContributionsThreshold );
|
||||
|
||||
private:
|
||||
enum class FractionOrPercentage
|
||||
{
|
||||
FRACTION,
|
||||
PERCENTAGE
|
||||
};
|
||||
|
||||
void fillWithAccumulatedFlowVolumeFractionOrPercentageValues( FractionOrPercentage selection, double smallContributionsThreshold );
|
||||
|
||||
void groupAccumulatedFlowVolumes( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap, double threshold );
|
||||
void groupAccumulatedFlowVolumePercentages( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap, double threshold );
|
||||
void groupAccumulatedFlowVolumeFractionsOrPercentages( std::map<QString, std::map<QDateTime, double>>& rWellValuesMap, double threshold );
|
||||
|
||||
private:
|
||||
std::map<QDateTime, RigAccWellFlowCalculator> m_timeStepAndCalculatorPairs;
|
@ -105,6 +105,7 @@ set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuGuiTheme.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuQssSyntaxHighlighter.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
@ -211,6 +212,7 @@ set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuTextContentFrame.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtLegendOverlayContentFrame.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtDateScaleWrapper.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.cpp
|
||||
)
|
||||
|
||||
if(RESINSIGHT_USE_QT_CHARTS)
|
||||
@ -301,6 +303,7 @@ list(
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuTextEditWithCompletion.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuTextContentFrame.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuQwtLegendOverlayContentFrame.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RiuMatrixPlotWidget.h
|
||||
)
|
||||
|
||||
list(APPEND QT_UI_FILES)
|
||||
|
443
ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp
Normal file
443
ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.cpp
Normal file
@ -0,0 +1,443 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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 "RiuMatrixPlotWidget.h"
|
||||
|
||||
#include "RiaColorTools.h"
|
||||
#include "RiaPreferences.h"
|
||||
|
||||
#include "RimRegularLegendConfig.h"
|
||||
#include "RimViewWindow.h"
|
||||
|
||||
#include "RiuAbstractLegendFrame.h"
|
||||
#include "RiuQwtLinearScaleEngine.h"
|
||||
#include "RiuQwtPlotItem.h"
|
||||
#include "RiuQwtPlotTools.h"
|
||||
#include "RiuScalarMapperLegendFrame.h"
|
||||
|
||||
#include "cvfColor3.h"
|
||||
|
||||
#include "qwt_plot_marker.h"
|
||||
#include "qwt_scale_draw.h"
|
||||
#include "qwt_text.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
class MatrixShapeItem : public QwtPlotShapeItem
|
||||
{
|
||||
public:
|
||||
MatrixShapeItem( const QString& title = QString() )
|
||||
: QwtPlotShapeItem( title )
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
double value;
|
||||
size_t rowIndex;
|
||||
size_t columnIndex;
|
||||
};
|
||||
|
||||
class TextScaleDraw : public QwtScaleDraw
|
||||
{
|
||||
public:
|
||||
TextScaleDraw( const std::map<size_t, QString>& tickLabels )
|
||||
: m_tickLabels( tickLabels )
|
||||
{
|
||||
}
|
||||
|
||||
QwtText label( double value ) const override
|
||||
{
|
||||
size_t intValue = static_cast<size_t>( value + 0.25 );
|
||||
auto it = m_tickLabels.find( intValue );
|
||||
return it != m_tickLabels.end() ? it->second : "";
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<size_t, QString> m_tickLabels;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiuMatrixPlotWidget::RiuMatrixPlotWidget( RimViewWindow* ownerViewWindow, RimRegularLegendConfig* legendConfig, QWidget* parent )
|
||||
: matrixCellSelected( this )
|
||||
, m_ownerViewWindow( ownerViewWindow )
|
||||
, m_legendConfig( legendConfig )
|
||||
{
|
||||
// Configure main layout
|
||||
QHBoxLayout* mainLayout = new QHBoxLayout();
|
||||
mainLayout->setContentsMargins( 15, 15, 15, 15 );
|
||||
this->setLayout( mainLayout );
|
||||
|
||||
// White background
|
||||
QPalette palette = this->palette();
|
||||
palette.setColor( QPalette::Window, Qt::white );
|
||||
this->setAutoFillBackground( true );
|
||||
this->setPalette( palette );
|
||||
|
||||
// Add plot to main layout
|
||||
m_plotWidget = new RiuQwtPlotWidget( nullptr, parent );
|
||||
m_plotWidget->qwtPlot()->insertLegend( nullptr );
|
||||
mainLayout->addWidget( m_plotWidget );
|
||||
|
||||
// Add legend to main layout
|
||||
if ( m_legendConfig )
|
||||
{
|
||||
m_legendFrame = m_legendConfig->makeLegendFrame();
|
||||
mainLayout->addWidget( m_legendFrame );
|
||||
}
|
||||
|
||||
// Configure plot widget to be a matrix plot?
|
||||
m_plotWidget->enableGridLines( RiuPlotAxis::defaultTop(), false, false );
|
||||
m_plotWidget->enableGridLines( RiuPlotAxis::defaultBottom(), false, false );
|
||||
m_plotWidget->enableGridLines( RiuPlotAxis::defaultRight(), false, false );
|
||||
m_plotWidget->enableGridLines( RiuPlotAxis::defaultLeft(), false, false );
|
||||
|
||||
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultLeft(), true );
|
||||
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultBottom(), true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RiuMatrixPlotWidget::~RiuMatrixPlotWidget()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QwtPlot* RiuMatrixPlotWidget::qwtPlot() const
|
||||
{
|
||||
return m_plotWidget->qwtPlot();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::clearPlotData()
|
||||
{
|
||||
m_columnHeaders = {};
|
||||
m_rowHeaders = {};
|
||||
m_rowValues = {};
|
||||
m_plotWidget->qwtPlot()->detachItems();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setColumnHeaders( const std::vector<QString>& columnHeaders )
|
||||
{
|
||||
if ( m_columnHeaders.empty() )
|
||||
{
|
||||
m_columnHeaders = columnHeaders;
|
||||
}
|
||||
else if ( columnHeaders.size() == m_columnHeaders.size() )
|
||||
{
|
||||
m_columnHeaders = columnHeaders;
|
||||
}
|
||||
CAF_ASSERT( "Column headers must be assigned for an empty matrix or re-assigned with an equal number of columns!" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setRowValues( const QString& rowLabel, const std::vector<double>& values )
|
||||
{
|
||||
CAF_ASSERT( !m_columnHeaders.empty() && "Matrix column headers are not configured - headers are empty!" );
|
||||
CAF_ASSERT( values.size() == m_columnHeaders.size() && "Number of row values must be equal number of configured matrix columns" );
|
||||
|
||||
// Insert in front to get rows from bottom to top in plot
|
||||
m_rowHeaders.insert( m_rowHeaders.begin(), rowLabel );
|
||||
m_rowValues.insert( m_rowValues.begin(), values );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::createPlot()
|
||||
{
|
||||
updateAxes();
|
||||
createMatrixCells();
|
||||
scheduleReplot();
|
||||
|
||||
auto frame = dynamic_cast<RiuScalarMapperLegendFrame*>( m_legendFrame.data() );
|
||||
frame->updateTickValues();
|
||||
frame->update();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::scheduleReplot()
|
||||
{
|
||||
m_plotWidget->scheduleReplot();
|
||||
}
|
||||
|
||||
RimViewWindow* RiuMatrixPlotWidget::ownerViewWindow() const
|
||||
{
|
||||
return m_ownerViewWindow;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setPlotTitleEnabled( bool enabled )
|
||||
{
|
||||
m_plotWidget->setPlotTitleEnabled( enabled );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setLegendFontSize( int fontSize )
|
||||
{
|
||||
m_plotWidget->setLegendFontSize( fontSize );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setPlotTitle( const QString& title )
|
||||
{
|
||||
m_plotWidget->setPlotTitle( title );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setShowValueLabel( bool showValueLabel )
|
||||
{
|
||||
m_showValueLabel = showValueLabel;
|
||||
|
||||
// Due to few data points - clear plot and create matrix cells with new label flag
|
||||
m_plotWidget->qwtPlot()->detachItems();
|
||||
createMatrixCells();
|
||||
m_plotWidget->scheduleReplot();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setRowTitle( const QString& title )
|
||||
{
|
||||
m_rowTitle = title;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setInvalidValueColor( const cvf::Color3ub& color )
|
||||
{
|
||||
m_invalidValueColor = color;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setUseInvalidValueColor( bool useInvalidValueColor )
|
||||
{
|
||||
m_useInvalidValueColor = useInvalidValueColor;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setInvalidValueRange( double min, double max )
|
||||
{
|
||||
CAF_ASSERT( min <= max && "Min must be less or equal to max!" );
|
||||
|
||||
m_invalidValueRange = std::make_pair( min, max );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setColumnTitle( const QString& title )
|
||||
{
|
||||
m_columnTitle = title;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setPlotTitleFontSize( int fontSize )
|
||||
{
|
||||
m_plotWidget->setPlotTitleFontSize( fontSize );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setAxisTitleFontSize( int fontSize )
|
||||
{
|
||||
m_axisTitleFontSize = fontSize;
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultLeft(), m_axisTitleFontSize, m_axisLabelFontSize );
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultBottom(), m_axisTitleFontSize, m_axisLabelFontSize );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setAxisLabelFontSize( int fontSize )
|
||||
{
|
||||
m_axisLabelFontSize = fontSize;
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultLeft(), m_axisTitleFontSize, m_axisLabelFontSize );
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultBottom(), m_axisTitleFontSize, m_axisLabelFontSize );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::setValueFontSize( int fontSize )
|
||||
{
|
||||
m_valueFontSize = fontSize;
|
||||
|
||||
// Due to few data points - clear plot and create matrix cells with new font size
|
||||
m_plotWidget->qwtPlot()->detachItems();
|
||||
createMatrixCells();
|
||||
m_plotWidget->scheduleReplot();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::updateAxes()
|
||||
{
|
||||
if ( !m_plotWidget ) return;
|
||||
|
||||
// Labels on y-axis
|
||||
m_plotWidget->qwtPlot()->setAxisScaleDraw( QwtAxis::YLeft, new TextScaleDraw( createIndexLabelMap( m_rowHeaders ) ) );
|
||||
m_plotWidget->qwtPlot()->setAxisScaleEngine( QwtAxis::YLeft, new RiuQwtLinearScaleEngine );
|
||||
m_plotWidget->setAxisTitleText( RiuPlotAxis::defaultLeft(), m_rowTitle );
|
||||
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultLeft(), true );
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultLeft(), m_axisTitleFontSize, m_axisLabelFontSize, false, Qt::AlignCenter );
|
||||
m_plotWidget->setAxisLabelsAndTicksEnabled( RiuPlotAxis::defaultLeft(), true, false );
|
||||
m_plotWidget->setAxisRange( RiuPlotAxis::defaultLeft(), 0.0, static_cast<double>( m_rowHeaders.size() ) + 1 );
|
||||
m_plotWidget->setMajorAndMinorTickIntervalsAndRange( RiuPlotAxis::defaultLeft(),
|
||||
1.0,
|
||||
0.0,
|
||||
0.5,
|
||||
static_cast<double>( m_rowHeaders.size() ) - 0.5,
|
||||
0.0,
|
||||
static_cast<double>( m_rowHeaders.size() ) );
|
||||
|
||||
// Labels on column axis
|
||||
auto scaleDraw = new TextScaleDraw( createIndexLabelMap( m_columnHeaders ) );
|
||||
scaleDraw->setLabelRotation( 30.0 );
|
||||
m_plotWidget->qwtPlot()->setAxisScaleDraw( QwtAxis::XBottom, scaleDraw );
|
||||
m_plotWidget->qwtPlot()->setAxisScaleEngine( QwtAxis::XBottom, new RiuQwtLinearScaleEngine );
|
||||
m_plotWidget->setAxisTitleText( RiuPlotAxis::defaultBottom(), m_columnTitle );
|
||||
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultBottom(), true );
|
||||
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultBottom(),
|
||||
m_axisTitleFontSize,
|
||||
m_axisLabelFontSize,
|
||||
false,
|
||||
Qt::AlignCenter | Qt::AlignTop );
|
||||
m_plotWidget->setAxisLabelsAndTicksEnabled( RiuPlotAxis::defaultBottom(), true, false );
|
||||
m_plotWidget->setAxisRange( RiuPlotAxis::defaultBottom(), 0.0, static_cast<double>( m_columnHeaders.size() ) + 1 );
|
||||
m_plotWidget->setMajorAndMinorTickIntervalsAndRange( RiuPlotAxis::defaultBottom(),
|
||||
1.0,
|
||||
0.0,
|
||||
0.5,
|
||||
static_cast<double>( m_columnHeaders.size() ) - 0.5,
|
||||
0.0,
|
||||
static_cast<double>( m_columnHeaders.size() ) );
|
||||
|
||||
m_plotWidget->qwtPlot()->setAxisLabelAlignment( QwtAxis::XBottom, Qt::AlignRight );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::createMatrixCells()
|
||||
{
|
||||
CAF_ASSERT( m_legendConfig.notNull() && m_legendConfig->scalarMapper() && "Scalar mapper must be set for legend config!" );
|
||||
|
||||
for ( size_t rowIdx = 0u; rowIdx < m_rowValues.size(); ++rowIdx )
|
||||
{
|
||||
for ( size_t colIdx = 0u; colIdx < m_rowValues[rowIdx].size(); ++colIdx )
|
||||
{
|
||||
const double value = m_rowValues[rowIdx][colIdx];
|
||||
const auto label = QString( "%1" ).arg( value, 0, 'f', 2 );
|
||||
|
||||
cvf::Color3ub color = m_legendConfig->scalarMapper()->mapToColor( value );
|
||||
|
||||
if ( m_useInvalidValueColor && m_invalidValueRange.first <= value && value <= m_invalidValueRange.second )
|
||||
{
|
||||
color = m_invalidValueColor;
|
||||
}
|
||||
|
||||
QColor qColor( color.r(), color.g(), color.b() );
|
||||
auto rectangle = RiuQwtPlotTools::createBoxShapeT<MatrixShapeItem>( label,
|
||||
static_cast<double>( colIdx ),
|
||||
static_cast<double>( colIdx ) + 1.0,
|
||||
static_cast<double>( rowIdx ),
|
||||
static_cast<double>( rowIdx ) + 1,
|
||||
qColor );
|
||||
|
||||
rectangle->value = value;
|
||||
rectangle->rowIndex = rowIdx;
|
||||
rectangle->columnIndex = colIdx;
|
||||
rectangle->attach( m_plotWidget->qwtPlot() );
|
||||
|
||||
if ( m_showValueLabel )
|
||||
{
|
||||
QwtText textLabel( label );
|
||||
cvf::Color3f contrastColor = RiaColorTools::contrastColor( cvf::Color3f( color ) );
|
||||
textLabel.setColor( RiaColorTools::toQColor( contrastColor ) );
|
||||
QFont font = textLabel.font();
|
||||
font.setPixelSize( caf::FontTools::pointSizeToPixelSize( m_valueFontSize ) );
|
||||
textLabel.setFont( font );
|
||||
QwtPlotMarker* marker = new QwtPlotMarker();
|
||||
marker->setLabel( textLabel );
|
||||
marker->setXValue( colIdx + 0.5 );
|
||||
marker->setYValue( rowIdx + 0.5 );
|
||||
marker->attach( m_plotWidget->qwtPlot() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::map<size_t, QString> RiuMatrixPlotWidget::createIndexLabelMap( const std::vector<QString>& labels )
|
||||
{
|
||||
std::map<size_t, QString> indexLabelMap;
|
||||
for ( size_t i = 0; i < labels.size(); ++i )
|
||||
{
|
||||
indexLabelMap.emplace( i, labels[i] );
|
||||
}
|
||||
return indexLabelMap;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuMatrixPlotWidget::onPlotItemSelected( std::shared_ptr<RiuPlotItem> plotItem, bool toggle, int sampleIndex )
|
||||
{
|
||||
RiuQwtPlotItem* qwtPlotItem = dynamic_cast<RiuQwtPlotItem*>( plotItem.get() );
|
||||
if ( !qwtPlotItem ) return;
|
||||
|
||||
MatrixShapeItem* matrixItem = dynamic_cast<MatrixShapeItem*>( qwtPlotItem->qwtPlotItem() );
|
||||
if ( matrixItem )
|
||||
{
|
||||
matrixCellSelected.send( std::make_pair( matrixItem->rowIndex, matrixItem->columnIndex ) );
|
||||
}
|
||||
}
|
110
ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h
Normal file
110
ApplicationLibCode/UserInterface/RiuMatrixPlotWidget.h
Normal file
@ -0,0 +1,110 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2023- Equinor ASA
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RiuInterfaceToViewWindow.h"
|
||||
#include "RiuPlotItem.h"
|
||||
#include "RiuQwtPlotWidget.h"
|
||||
|
||||
#include "cafFontTools.h"
|
||||
#include "cafPdmPointer.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
#include "cvfScalarMapper.h"
|
||||
|
||||
#include "qwt_plot.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QWidget>
|
||||
|
||||
class RimViewWindow;
|
||||
class RimRegularLegendConfig;
|
||||
class RiuAbstractLegendFrame;
|
||||
|
||||
class RiuMatrixPlotWidget : public QWidget, public RiuInterfaceToViewWindow, public caf::SignalEmitter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
caf::Signal<std::pair<int, int>> matrixCellSelected;
|
||||
|
||||
public:
|
||||
RiuMatrixPlotWidget( RimViewWindow* ownerViewWindow, RimRegularLegendConfig* legendConfig, QWidget* parent = nullptr );
|
||||
~RiuMatrixPlotWidget();
|
||||
|
||||
QwtPlot* qwtPlot() const;
|
||||
|
||||
void createPlot();
|
||||
void clearPlotData();
|
||||
void setColumnHeaders( const std::vector<QString>& columnHeaders );
|
||||
void setRowValues( const QString& rowLabel, const std::vector<double>& values );
|
||||
|
||||
void setPlotTitle( const QString& title );
|
||||
void setColumnTitle( const QString& title );
|
||||
void setRowTitle( const QString& title );
|
||||
|
||||
void setInvalidValueColor( const cvf::Color3ub& color );
|
||||
void setUseInvalidValueColor( bool useInvalidValueColor );
|
||||
void setInvalidValueRange( double min, double max );
|
||||
|
||||
void setShowValueLabel( bool showValueLabel );
|
||||
|
||||
void setPlotTitleFontSize( int fontSize );
|
||||
void setPlotTitleEnabled( bool enabled );
|
||||
void setLegendFontSize( int fontSize );
|
||||
|
||||
void setAxisTitleFontSize( int fontSize );
|
||||
void setAxisLabelFontSize( int fontSize );
|
||||
void setValueFontSize( int fontSize );
|
||||
|
||||
void scheduleReplot();
|
||||
|
||||
virtual RimViewWindow* ownerViewWindow() const override;
|
||||
|
||||
private slots:
|
||||
void onPlotItemSelected( std::shared_ptr<RiuPlotItem> plotItem, bool toggle, int sampleIndex );
|
||||
|
||||
private:
|
||||
void updateAxes();
|
||||
void createMatrixCells();
|
||||
std::map<size_t, QString> createIndexLabelMap( const std::vector<QString>& labels );
|
||||
|
||||
private:
|
||||
QPointer<RiuQwtPlotWidget> m_plotWidget;
|
||||
QPointer<RiuAbstractLegendFrame> m_legendFrame;
|
||||
|
||||
caf::PdmPointer<RimViewWindow> m_ownerViewWindow; // Only intended to be used by ownerViewWindow()
|
||||
caf::PdmPointer<RimRegularLegendConfig> m_legendConfig;
|
||||
|
||||
std::vector<QString> m_columnHeaders;
|
||||
std::vector<QString> m_rowHeaders;
|
||||
std::vector<std::vector<double>> m_rowValues;
|
||||
|
||||
cvf::Color3ub m_invalidValueColor = cvf::Color3ub::WHITE;
|
||||
bool m_useInvalidValueColor = false;
|
||||
std::pair<double, double> m_invalidValueRange = { 0.0, 0.0 };
|
||||
|
||||
bool m_showValueLabel = true;
|
||||
|
||||
QString m_rowTitle;
|
||||
QString m_columnTitle;
|
||||
int m_axisTitleFontSize = 8;
|
||||
int m_axisLabelFontSize = 8;
|
||||
int m_valueFontSize = 8;
|
||||
};
|
@ -39,10 +39,7 @@ RiuScalarMapperLegendFrame::RiuScalarMapperLegendFrame( QWidget* parent, const Q
|
||||
, m_tickNumberPrecision( 4 )
|
||||
, m_numberFormat( RiaNumberFormat::NumberFormatType::AUTO )
|
||||
{
|
||||
if ( m_scalarMapper.notNull() )
|
||||
{
|
||||
m_scalarMapper->majorTickValues( &m_tickValues );
|
||||
}
|
||||
updateTickValues();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -68,6 +65,18 @@ void RiuScalarMapperLegendFrame::setTickFormat( NumberFormat format )
|
||||
m_numberFormat = format;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RiuScalarMapperLegendFrame::updateTickValues()
|
||||
{
|
||||
if ( m_scalarMapper.notNull() )
|
||||
{
|
||||
m_tickValues = {};
|
||||
m_scalarMapper->majorTickValues( &m_tickValues );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
|
||||
void setTickPrecision( int precision );
|
||||
void setTickFormat( NumberFormat format );
|
||||
void updateTickValues();
|
||||
|
||||
private:
|
||||
void layoutInfo( LayoutInfo* layout ) const override;
|
||||
|
Loading…
Reference in New Issue
Block a user