mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-23 23:13:39 -06:00
ee724633b5
* Show text after value in category legend * Use integer slider for category results * Do not allow min larger than max and max lower than min
779 lines
34 KiB
C++
779 lines
34 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "RimEclipseResultDefinitionTools.h"
|
|
|
|
#include "RiaColorTables.h"
|
|
#include "RiaColorTools.h"
|
|
|
|
#include "RigAllanDiagramData.h"
|
|
#include "RigCaseCellResultsData.h"
|
|
#include "RigEclipseCaseData.h"
|
|
#include "RigEclipseResultAddress.h"
|
|
#include "RigFlowDiagResults.h"
|
|
#include "RigVisibleCategoriesCalculator.h"
|
|
|
|
#include "RimColorLegend.h"
|
|
#include "RimColorLegendItem.h"
|
|
#include "RimEclipseCase.h"
|
|
#include "RimEclipseCellColors.h"
|
|
#include "RimEclipseInputProperty.h"
|
|
#include "RimEclipseInputPropertyCollection.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimFlowDiagnosticsTools.h"
|
|
#include "RimRegularLegendConfig.h"
|
|
#include "RimSimWellInView.h"
|
|
#include "RimSimWellInViewCollection.h"
|
|
#include "RimTernaryLegendConfig.h"
|
|
|
|
#include <QString>
|
|
|
|
#include "cafCategoryMapper.h"
|
|
#include "cvfColor3.h"
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimEclipseResultDefinitionTools::isDivideByCellFaceAreaPossible( const QString& resultName )
|
|
{
|
|
if ( resultName == "FLRWATI+" ) return true;
|
|
if ( resultName == "FLRWATJ+" ) return true;
|
|
if ( resultName == "FLRWATK+" ) return true;
|
|
|
|
if ( resultName == "FLROILI+" ) return true;
|
|
if ( resultName == "FLROILJ+" ) return true;
|
|
if ( resultName == "FLROILK+" ) return true;
|
|
|
|
if ( resultName == "FLRGASI+" ) return true;
|
|
if ( resultName == "FLRGASJ+" ) return true;
|
|
if ( resultName == "FLRGASK+" ) return true;
|
|
|
|
if ( resultName == "TRANX" ) return true;
|
|
if ( resultName == "TRANY" ) return true;
|
|
if ( resultName == "TRANZ" ) return true;
|
|
|
|
if ( resultName == "riTRANX" ) return true;
|
|
if ( resultName == "riTRANY" ) return true;
|
|
if ( resultName == "riTRANZ" ) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RD::FlowTracerSelectionState RimEclipseResultDefinitionTools::getFlowTracerSelectionState( bool isInjector,
|
|
RD::FlowTracerSelectionType tracerSelectionType,
|
|
const RimFlowDiagSolution* flowDiagSolution,
|
|
size_t selectedTracerCount )
|
|
{
|
|
if ( isInjector && ( tracerSelectionType == RD::FlowTracerSelectionType::FLOW_TR_INJECTORS ||
|
|
tracerSelectionType == RD::FlowTracerSelectionType::FLOW_TR_INJ_AND_PROD ) )
|
|
{
|
|
return RD::FlowTracerSelectionState::ALL_SELECTED;
|
|
}
|
|
|
|
if ( !isInjector && ( tracerSelectionType == RD::FlowTracerSelectionType::FLOW_TR_PRODUCERS ||
|
|
tracerSelectionType == RD::FlowTracerSelectionType::FLOW_TR_INJ_AND_PROD ) )
|
|
{
|
|
return RD::FlowTracerSelectionState::ALL_SELECTED;
|
|
}
|
|
|
|
if ( tracerSelectionType == RD::FlowTracerSelectionType::FLOW_TR_BY_SELECTION )
|
|
{
|
|
if ( selectedTracerCount == RimFlowDiagnosticsTools::setOfTracersOfType( flowDiagSolution, isInjector ).size() )
|
|
{
|
|
return RD::FlowTracerSelectionState::ALL_SELECTED;
|
|
}
|
|
if ( selectedTracerCount == 1 )
|
|
{
|
|
return RD::FlowTracerSelectionState::ONE_SELECTED;
|
|
}
|
|
if ( selectedTracerCount > 1 )
|
|
{
|
|
return RD::FlowTracerSelectionState::MULTIPLE_SELECTED;
|
|
}
|
|
}
|
|
|
|
return RD::FlowTracerSelectionState::NONE_SELECTED;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QStringList RimEclipseResultDefinitionTools::getResultNamesForResultType( RiaDefines::ResultCatType resultCatType,
|
|
const RigCaseCellResultsData* results )
|
|
{
|
|
if ( resultCatType != RiaDefines::ResultCatType::FLOW_DIAGNOSTICS )
|
|
{
|
|
if ( !results ) return {};
|
|
|
|
return results->resultNames( resultCatType );
|
|
}
|
|
|
|
QStringList flowVars;
|
|
flowVars.push_back( RIG_FLD_TOF_RESNAME );
|
|
flowVars.push_back( RIG_FLD_CELL_FRACTION_RESNAME );
|
|
flowVars.push_back( RIG_FLD_MAX_FRACTION_TRACER_RESNAME );
|
|
flowVars.push_back( RIG_FLD_COMMUNICATION_RESNAME );
|
|
return flowVars;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimEclipseResultDefinitionTools::timeOfFlightString( RD::FlowTracerSelectionState injectorState,
|
|
RD::FlowTracerSelectionState producerState,
|
|
bool shorter )
|
|
{
|
|
QString tofString;
|
|
bool multipleSelected = false;
|
|
if ( injectorState != RD::FlowTracerSelectionState::NONE_SELECTED && producerState != RD::FlowTracerSelectionState::NONE_SELECTED )
|
|
{
|
|
tofString = shorter ? "Res.Time" : "Residence Time";
|
|
multipleSelected = true;
|
|
}
|
|
else if ( injectorState != RD::FlowTracerSelectionState::NONE_SELECTED )
|
|
{
|
|
tofString = shorter ? "Fwd.TOF" : "Forward Time of Flight";
|
|
}
|
|
else if ( producerState != RD::FlowTracerSelectionState::NONE_SELECTED )
|
|
{
|
|
tofString = shorter ? "Rev.TOF" : "Reverse Time of Flight";
|
|
}
|
|
else
|
|
{
|
|
tofString = shorter ? "TOF" : "Time of Flight";
|
|
}
|
|
|
|
multipleSelected = multipleSelected || injectorState >= RD::FlowTracerSelectionState::MULTIPLE_SELECTED ||
|
|
producerState >= RD::FlowTracerSelectionState::MULTIPLE_SELECTED;
|
|
|
|
if ( multipleSelected && !shorter )
|
|
{
|
|
tofString += " (Average)";
|
|
}
|
|
|
|
tofString += " [days]";
|
|
// Conversion from seconds in flow module to days is done in RigFlowDiagTimeStepResult::setTracerTOF()
|
|
|
|
return tofString;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimEclipseResultDefinitionTools::maxFractionTracerString( RD::FlowTracerSelectionState injectorState,
|
|
RD::FlowTracerSelectionState producerState,
|
|
bool shorter )
|
|
{
|
|
QString mfString;
|
|
if ( injectorState >= RD::FlowTracerSelectionState::ONE_SELECTED && producerState == RD::FlowTracerSelectionState::NONE_SELECTED )
|
|
{
|
|
mfString = shorter ? "FloodReg" : "Flooding Region";
|
|
if ( injectorState >= RD::FlowTracerSelectionState::MULTIPLE_SELECTED ) mfString += "s";
|
|
}
|
|
else if ( injectorState == RD::FlowTracerSelectionState::NONE_SELECTED && producerState >= RD::FlowTracerSelectionState::ONE_SELECTED )
|
|
{
|
|
mfString = shorter ? "DrainReg" : "Drainage Region";
|
|
if ( producerState >= RD::FlowTracerSelectionState::MULTIPLE_SELECTED ) mfString += "s";
|
|
}
|
|
else
|
|
{
|
|
mfString = shorter ? "Drain&FloodReg" : "Drainage/Flooding Regions";
|
|
}
|
|
return mfString;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimEclipseResultDefinitionTools::selectedTracersString( RD::FlowTracerSelectionState injectorState,
|
|
RD::FlowTracerSelectionState producerState,
|
|
const std::vector<QString>& selectedInjectors,
|
|
const std::vector<QString>& selectedProducers,
|
|
int maxTracerStringLength )
|
|
{
|
|
QStringList fullTracersList;
|
|
|
|
if ( injectorState == RD::FlowTracerSelectionState::ALL_SELECTED && producerState == RD::FlowTracerSelectionState::ALL_SELECTED )
|
|
{
|
|
fullTracersList += caf::AppEnum<RD::FlowTracerSelectionType>::uiText( RD::FlowTracerSelectionType::FLOW_TR_INJ_AND_PROD );
|
|
}
|
|
else
|
|
{
|
|
if ( injectorState == RD::FlowTracerSelectionState::ALL_SELECTED )
|
|
{
|
|
fullTracersList += caf::AppEnum<RD::FlowTracerSelectionType>::uiText( RD::FlowTracerSelectionType::FLOW_TR_INJECTORS );
|
|
}
|
|
|
|
if ( producerState == RD::FlowTracerSelectionState::ALL_SELECTED )
|
|
{
|
|
fullTracersList += caf::AppEnum<RD::FlowTracerSelectionType>::uiText( RD::FlowTracerSelectionType::FLOW_TR_PRODUCERS );
|
|
}
|
|
|
|
if ( injectorState == RD::FlowTracerSelectionState::ONE_SELECTED || injectorState == RD::FlowTracerSelectionState::MULTIPLE_SELECTED )
|
|
{
|
|
QStringList listOfSelectedInjectors;
|
|
for ( const QString& injector : selectedInjectors )
|
|
{
|
|
listOfSelectedInjectors.push_back( injector );
|
|
}
|
|
if ( !listOfSelectedInjectors.empty() )
|
|
{
|
|
fullTracersList += listOfSelectedInjectors.join( ", " );
|
|
}
|
|
}
|
|
|
|
if ( producerState == RD::FlowTracerSelectionState::ONE_SELECTED || producerState == RD::FlowTracerSelectionState::MULTIPLE_SELECTED )
|
|
{
|
|
QStringList listOfSelectedProducers;
|
|
for ( const QString& producer : selectedProducers )
|
|
{
|
|
listOfSelectedProducers.push_back( producer );
|
|
}
|
|
if ( !listOfSelectedProducers.empty() )
|
|
{
|
|
fullTracersList.push_back( listOfSelectedProducers.join( ", " ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
QString tracersText;
|
|
if ( !fullTracersList.empty() )
|
|
{
|
|
tracersText = fullTracersList.join( ", " );
|
|
}
|
|
|
|
if ( !tracersText.isEmpty() )
|
|
{
|
|
const QString postfix = "...";
|
|
|
|
if ( tracersText.size() > maxTracerStringLength + postfix.size() )
|
|
{
|
|
tracersText = tracersText.left( maxTracerStringLength );
|
|
tracersText += postfix;
|
|
}
|
|
}
|
|
|
|
return tracersText;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimEclipseResultDefinitionTools::getInputPropertyFileName( const RimEclipseCase* eclipseCase, const QString& resultName )
|
|
{
|
|
if ( eclipseCase )
|
|
{
|
|
RimEclipseInputPropertyCollection* inputPropertyCollection = eclipseCase->inputPropertyCollection();
|
|
if ( inputPropertyCollection )
|
|
{
|
|
RimEclipseInputProperty* inputProperty = inputPropertyCollection->findInputProperty( resultName );
|
|
if ( inputProperty )
|
|
{
|
|
return inputProperty->fileName.v().path();
|
|
}
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseResultDefinitionTools::updateTernaryLegend( RigCaseCellResultsData* cellResultsData,
|
|
RimTernaryLegendConfig* ternaryLegendConfigToUpdate,
|
|
int timeStep )
|
|
{
|
|
if ( !cellResultsData ) return;
|
|
|
|
size_t maxTimeStepCount = cellResultsData->maxTimeStepCount();
|
|
if ( maxTimeStepCount > 1 )
|
|
{
|
|
{
|
|
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::soil() );
|
|
|
|
if ( cellResultsData->ensureKnownResultLoaded( resAddr ) )
|
|
{
|
|
double globalMin = 0.0;
|
|
double globalMax = 1.0;
|
|
double localMin = 0.0;
|
|
double localMax = 1.0;
|
|
|
|
cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax );
|
|
cellResultsData->minMaxCellScalarValues( resAddr, timeStep, localMin, localMax );
|
|
|
|
ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SOIL_IDX, globalMin, globalMax, localMin, localMax );
|
|
}
|
|
}
|
|
|
|
{
|
|
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::sgas() );
|
|
|
|
if ( cellResultsData->ensureKnownResultLoaded( resAddr ) )
|
|
{
|
|
double globalMin = 0.0;
|
|
double globalMax = 1.0;
|
|
double localMin = 0.0;
|
|
double localMax = 1.0;
|
|
|
|
cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax );
|
|
cellResultsData->minMaxCellScalarValues( resAddr, timeStep, localMin, localMax );
|
|
|
|
ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SGAS_IDX, globalMin, globalMax, localMin, localMax );
|
|
}
|
|
}
|
|
|
|
{
|
|
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::DYNAMIC_NATIVE, RiaResultNames::swat() );
|
|
|
|
if ( cellResultsData->ensureKnownResultLoaded( resAddr ) )
|
|
{
|
|
double globalMin = 0.0;
|
|
double globalMax = 1.0;
|
|
double localMin = 0.0;
|
|
double localMax = 1.0;
|
|
|
|
cellResultsData->minMaxCellScalarValues( resAddr, globalMin, globalMax );
|
|
cellResultsData->minMaxCellScalarValues( resAddr, timeStep, localMin, localMax );
|
|
|
|
ternaryLegendConfigToUpdate->setAutomaticRanges( RimTernaryLegendConfig::TERNARY_SWAT_IDX, globalMin, globalMax, localMin, localMax );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace RimEclipseResultDefinitionTools
|
|
{
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool operator<( const cvf::Color3ub first, const cvf::Color3ub second )
|
|
{
|
|
if ( first.r() != second.r() ) return first.r() < second.r();
|
|
if ( first.g() != second.g() ) return first.g() < second.g();
|
|
if ( first.b() != second.b() ) return first.b() < second.b();
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
class TupleCompare
|
|
{
|
|
public:
|
|
bool operator()( const std::tuple<QString, int, cvf::Color3ub>& t1, const std::tuple<QString, int, cvf::Color3ub>& t2 ) const
|
|
{
|
|
using namespace std;
|
|
if ( get<0>( t1 ) != get<0>( t2 ) ) return get<0>( t1 ) < get<0>( t2 );
|
|
if ( get<1>( t1 ) != get<1>( t2 ) ) return get<1>( t1 ) < get<1>( t2 );
|
|
if ( get<2>( t1 ) != get<2>( t2 ) ) return get<2>( t1 ) < get<2>( t2 );
|
|
|
|
return false;
|
|
}
|
|
};
|
|
} // namespace RimEclipseResultDefinitionTools
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseResultDefinitionTools::updateLegendForFlowDiagnostics( const RimEclipseResultDefinition* resultDefinition,
|
|
RimRegularLegendConfig* legendConfigToUpdate,
|
|
int timeStep )
|
|
{
|
|
if ( timeStep < 0 ) return;
|
|
if ( !resultDefinition || !legendConfigToUpdate ) return;
|
|
|
|
auto flowDiagSolution = resultDefinition->flowDiagSolution();
|
|
if ( !flowDiagSolution ) return;
|
|
|
|
RigFlowDiagResults* flowResultsData = flowDiagSolution->flowDiagResults();
|
|
if ( !flowResultsData ) return;
|
|
|
|
RigFlowDiagResultAddress resAddr = resultDefinition->flowDiagResAddress();
|
|
|
|
double globalMin, globalMax;
|
|
double globalPosClosestToZero, globalNegClosestToZero;
|
|
|
|
flowResultsData->minMaxScalarValues( resAddr, timeStep, &globalMin, &globalMax );
|
|
flowResultsData->posNegClosestToZero( resAddr, timeStep, &globalPosClosestToZero, &globalNegClosestToZero );
|
|
|
|
double localMin, localMax;
|
|
double localPosClosestToZero, localNegClosestToZero;
|
|
if ( resultDefinition->hasDynamicResult() )
|
|
{
|
|
flowResultsData->minMaxScalarValues( resAddr, timeStep, &localMin, &localMax );
|
|
flowResultsData->posNegClosestToZero( resAddr, timeStep, &localPosClosestToZero, &localNegClosestToZero );
|
|
}
|
|
else
|
|
{
|
|
localMin = globalMin;
|
|
localMax = globalMax;
|
|
|
|
localPosClosestToZero = globalPosClosestToZero;
|
|
localNegClosestToZero = globalNegClosestToZero;
|
|
}
|
|
|
|
CVF_ASSERT( legendConfigToUpdate );
|
|
|
|
legendConfigToUpdate->disableAllTimeStepsRange( true );
|
|
legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero );
|
|
legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax );
|
|
|
|
if ( resultDefinition->hasCategoryResult() )
|
|
{
|
|
auto eclView = resultDefinition->firstAncestorOrThisOfType<RimEclipseView>();
|
|
if ( eclView )
|
|
{
|
|
std::set<std::tuple<QString, int, cvf::Color3ub>, TupleCompare> categories;
|
|
|
|
std::vector<QString> tracerNames = flowDiagSolution->tracerNames();
|
|
int tracerIndex = 0;
|
|
|
|
for ( const auto& tracerName : tracerNames )
|
|
{
|
|
cvf::Color3ub color( cvf::Color3::GRAY );
|
|
|
|
RimSimWellInView* well = eclView->wellCollection()->findWell( RimFlowDiagSolution::removeCrossFlowEnding( tracerName ) );
|
|
|
|
if ( well ) color = cvf::Color3ub( well->wellPipeColor() );
|
|
|
|
categories.insert( std::make_tuple( tracerName, tracerIndex, color ) );
|
|
++tracerIndex;
|
|
}
|
|
|
|
std::vector<std::tuple<QString, int, cvf::Color3ub>> categoryVector;
|
|
|
|
if ( resultDefinition->showOnlyVisibleCategoriesInLegend() )
|
|
{
|
|
std::set<int> visibleTracers =
|
|
RigVisibleCategoriesCalculator::visibleFlowDiagCategories( *eclView, *flowResultsData, resAddr, timeStep );
|
|
for ( auto tupIt : categories )
|
|
{
|
|
int tracerIndex = std::get<1>( tupIt );
|
|
if ( visibleTracers.count( tracerIndex ) ) categoryVector.push_back( tupIt );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for ( const auto& tupIt : categories )
|
|
{
|
|
categoryVector.push_back( tupIt );
|
|
}
|
|
}
|
|
|
|
legendConfigToUpdate->setCategoryItems( categoryVector );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimEclipseResultDefinitionTools::updateCellResultLegend( const RimEclipseResultDefinition* resultDefinition,
|
|
RimRegularLegendConfig* legendConfigToUpdate,
|
|
int timeStep )
|
|
{
|
|
if ( !resultDefinition || !legendConfigToUpdate ) return;
|
|
|
|
auto cellResultsData = resultDefinition->currentGridCellResults();
|
|
if ( !cellResultsData ) return;
|
|
|
|
auto eclipseCaseData = resultDefinition->eclipseCase()->eclipseCaseData();
|
|
if ( !eclipseCaseData ) return;
|
|
|
|
cellResultsData->ensureKnownResultLoaded( resultDefinition->eclipseResultAddress() );
|
|
|
|
double globalMin, globalMax;
|
|
double globalPosClosestToZero, globalNegClosestToZero;
|
|
|
|
cellResultsData->minMaxCellScalarValues( resultDefinition->eclipseResultAddress(), globalMin, globalMax );
|
|
cellResultsData->posNegClosestToZero( resultDefinition->eclipseResultAddress(), globalPosClosestToZero, globalNegClosestToZero );
|
|
|
|
double localMin, localMax;
|
|
double localPosClosestToZero, localNegClosestToZero;
|
|
if ( resultDefinition->hasDynamicResult() && timeStep >= 0 )
|
|
{
|
|
cellResultsData->minMaxCellScalarValues( resultDefinition->eclipseResultAddress(), timeStep, localMin, localMax );
|
|
cellResultsData->posNegClosestToZero( resultDefinition->eclipseResultAddress(), timeStep, localPosClosestToZero, localNegClosestToZero );
|
|
}
|
|
else
|
|
{
|
|
localMin = globalMin;
|
|
localMax = globalMax;
|
|
|
|
localPosClosestToZero = globalPosClosestToZero;
|
|
localNegClosestToZero = globalNegClosestToZero;
|
|
}
|
|
|
|
CVF_ASSERT( legendConfigToUpdate );
|
|
|
|
legendConfigToUpdate->disableAllTimeStepsRange( false );
|
|
legendConfigToUpdate->setClosestToZeroValues( globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero );
|
|
legendConfigToUpdate->setAutomaticRanges( globalMin, globalMax, localMin, localMax );
|
|
|
|
if ( resultDefinition->hasCategoryResult() )
|
|
{
|
|
if ( resultDefinition->resultType() == RiaDefines::ResultCatType::ALLAN_DIAGRAMS )
|
|
{
|
|
if ( resultDefinition->resultVariable() == RiaResultNames::formationAllanResultName() )
|
|
{
|
|
const std::vector<QString> fnVector = eclipseCaseData->formationNames();
|
|
std::vector<int> fnameIdxes;
|
|
for ( int i = 0; i < static_cast<int>( fnVector.size() ); i++ )
|
|
{
|
|
fnameIdxes.push_back( i );
|
|
}
|
|
|
|
cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray();
|
|
|
|
cvf::ref<caf::CategoryMapper> formationColorMapper = new caf::CategoryMapper;
|
|
formationColorMapper->setCategories( fnameIdxes );
|
|
formationColorMapper->setInterpolateColors( legendBaseColors );
|
|
|
|
const std::map<std::pair<int, int>, int>& formationCombToCategory =
|
|
eclipseCaseData->allanDiagramData()->formationCombinationToCategory();
|
|
|
|
std::vector<std::tuple<QString, int, cvf::Color3ub>> categories;
|
|
for ( int frmNameIdx : fnameIdxes )
|
|
{
|
|
cvf::Color3ub formationColor = formationColorMapper->mapToColor( frmNameIdx );
|
|
categories.emplace_back( std::make_tuple( fnVector[frmNameIdx], frmNameIdx, formationColor ) );
|
|
}
|
|
|
|
std::set<size_t> visibleAllanCategories;
|
|
{
|
|
auto eclView = resultDefinition->firstAncestorOrThisOfType<RimEclipseView>();
|
|
|
|
visibleAllanCategories = RigVisibleCategoriesCalculator::visibleAllanCategories( eclView );
|
|
}
|
|
|
|
for ( auto [formationPair, categoryIndex] : formationCombToCategory )
|
|
{
|
|
int frmIdx1 = formationPair.first;
|
|
int frmIdx2 = formationPair.second;
|
|
|
|
if ( visibleAllanCategories.count( categoryIndex ) == 0 ) continue;
|
|
|
|
auto fnVectorSize = static_cast<int>( fnVector.size() );
|
|
if ( frmIdx1 >= fnVectorSize || frmIdx2 >= fnVectorSize ) continue;
|
|
|
|
QString frmName1 = fnVector[frmIdx1];
|
|
QString frmName2 = fnVector[frmIdx2];
|
|
|
|
cvf::Color3f formationColor1 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx1 ) );
|
|
cvf::Color3f formationColor2 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx2 ) );
|
|
|
|
cvf::Color3ub blendColor = cvf::Color3ub( RiaColorTools::blendCvfColors( formationColor1, formationColor2 ) );
|
|
|
|
categories.emplace_back( std::make_tuple( frmName1 + "-" + frmName2, categoryIndex, blendColor ) );
|
|
}
|
|
|
|
legendConfigToUpdate->setCategoryItems( categories );
|
|
}
|
|
else if ( resultDefinition->resultVariable() == RiaResultNames::formationBinaryAllanResultName() )
|
|
{
|
|
std::vector<std::tuple<QString, int, cvf::Color3ub>> categories;
|
|
categories.emplace_back( std::make_tuple( "Same formation", 0, cvf::Color3ub::BROWN ) );
|
|
categories.emplace_back( std::make_tuple( "Different formation", 1, cvf::Color3ub::ORANGE ) );
|
|
|
|
legendConfigToUpdate->setCategoryItems( categories );
|
|
}
|
|
}
|
|
else if ( resultDefinition->resultType() == RiaDefines::ResultCatType::DYNAMIC_NATIVE &&
|
|
resultDefinition->resultVariable() == RiaResultNames::completionTypeResultName() )
|
|
{
|
|
const std::vector<int>& visibleCategories = cellResultsData->uniqueCellScalarValues( resultDefinition->eclipseResultAddress() );
|
|
|
|
std::vector<RiaDefines::WellPathComponentType> supportedCompletionTypes = { RiaDefines::WellPathComponentType::WELL_PATH,
|
|
RiaDefines::WellPathComponentType::FISHBONES,
|
|
RiaDefines::WellPathComponentType::PERFORATION_INTERVAL,
|
|
RiaDefines::WellPathComponentType::FRACTURE };
|
|
|
|
RiaColorTables::WellPathComponentColors colors = RiaColorTables::wellPathComponentColors();
|
|
|
|
std::vector<std::tuple<QString, int, cvf::Color3ub>> categories;
|
|
for ( auto completionType : supportedCompletionTypes )
|
|
{
|
|
if ( std::find( visibleCategories.begin(), visibleCategories.end(), static_cast<int>( completionType ) ) !=
|
|
visibleCategories.end() )
|
|
{
|
|
QString categoryText = caf::AppEnum<RiaDefines::WellPathComponentType>::uiText( completionType );
|
|
categories.emplace_back( categoryText, static_cast<int>( completionType ), colors[completionType] );
|
|
}
|
|
}
|
|
|
|
legendConfigToUpdate->setCategoryItems( categories );
|
|
}
|
|
else
|
|
{
|
|
auto uniqueValues = cellResultsData->uniqueCellScalarValues( resultDefinition->eclipseResultAddress() );
|
|
if ( resultDefinition->eclipseResultAddress().resultCatType() == RiaDefines::ResultCatType::FORMATION_NAMES )
|
|
{
|
|
std::vector<QString> fnVector = eclipseCaseData->formationNames();
|
|
uniqueValues.resize( fnVector.size() );
|
|
std::iota( uniqueValues.begin(), uniqueValues.end(), 0 );
|
|
}
|
|
|
|
cvf::Color3ubArray legendBaseColors = legendConfigToUpdate->colorLegend()->colorArray();
|
|
|
|
cvf::ref<caf::CategoryMapper> categoryMapper = new caf::CategoryMapper;
|
|
categoryMapper->setCategories( uniqueValues );
|
|
categoryMapper->setInterpolateColors( legendBaseColors );
|
|
|
|
std::vector<int> visibleCategoryValues = uniqueValues;
|
|
|
|
if ( resultDefinition->showOnlyVisibleCategoriesInLegend() )
|
|
{
|
|
auto eclView = resultDefinition->firstAncestorOrThisOfType<RimEclipseView>();
|
|
if ( eclView && eclView->showWindow() )
|
|
{
|
|
// Check if current result is cell result, and update the visible set of values
|
|
// TODO: Can be extended to the separate geometry results (separate fault result, separate
|
|
// intersection results), but this requires some refactoring
|
|
if ( eclView->cellResult() == resultDefinition )
|
|
{
|
|
std::set<int> visibleCategorySet = RigVisibleCategoriesCalculator::visibleCategories( eclView );
|
|
|
|
visibleCategoryValues.clear();
|
|
visibleCategoryValues.insert( visibleCategoryValues.begin(), visibleCategorySet.begin(), visibleCategorySet.end() );
|
|
}
|
|
}
|
|
}
|
|
std::vector<std::tuple<QString, int, cvf::Color3ub>> categoryVector;
|
|
|
|
for ( auto value : visibleCategoryValues )
|
|
{
|
|
cvf::Color3ub categoryColor = categoryMapper->mapToColor( value );
|
|
|
|
QString valueTxt;
|
|
if ( resultDefinition->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
|
|
{
|
|
std::vector<QString> fnVector = eclipseCaseData->formationNames();
|
|
|
|
if ( value < static_cast<int>( fnVector.size() ) )
|
|
{
|
|
valueTxt = fnVector[value];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto items = legendConfigToUpdate->colorLegend()->colorLegendItems();
|
|
auto it = std::find_if( items.begin(),
|
|
items.end(),
|
|
[value]( const RimColorLegendItem* const item ) { return item->categoryValue() == value; } );
|
|
if ( it != items.end() && !( *it )->categoryName().isEmpty() )
|
|
{
|
|
valueTxt = QString( "%1 %2" ).arg( value ).arg( ( *it )->categoryName() );
|
|
}
|
|
else
|
|
{
|
|
valueTxt = QString( "%1" ).arg( value );
|
|
}
|
|
}
|
|
|
|
categoryVector.emplace_back( valueTxt, value, categoryColor );
|
|
}
|
|
legendConfigToUpdate->setCategoryItems( categoryVector );
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QList<caf::PdmOptionItemInfo> RimEclipseResultDefinitionTools::calcOptionsForVariableUiFieldStandard( RiaDefines::ResultCatType resultCatType,
|
|
const RigCaseCellResultsData* results,
|
|
bool showDerivedResultsFirst,
|
|
bool addPerCellFaceOptionItems,
|
|
bool enableTernary )
|
|
{
|
|
if ( !results ) return {};
|
|
|
|
QList<caf::PdmOptionItemInfo> optionList;
|
|
|
|
QStringList cellCenterResultNames;
|
|
QStringList cellFaceResultNames;
|
|
|
|
for ( const QString& s : RimEclipseResultDefinitionTools::getResultNamesForResultType( resultCatType, results ) )
|
|
{
|
|
if ( s == RiaResultNames::completionTypeResultName() )
|
|
{
|
|
if ( results->timeStepDates().empty() ) continue;
|
|
}
|
|
|
|
if ( RiaResultNames::isPerCellFaceResult( s ) )
|
|
{
|
|
cellFaceResultNames.push_back( s );
|
|
}
|
|
else
|
|
{
|
|
cellCenterResultNames.push_back( s );
|
|
}
|
|
}
|
|
|
|
cellCenterResultNames.sort();
|
|
cellFaceResultNames.sort();
|
|
|
|
// Cell Center result names
|
|
for ( const QString& s : cellCenterResultNames )
|
|
{
|
|
optionList.push_back( caf::PdmOptionItemInfo( s, s ) );
|
|
}
|
|
|
|
if ( addPerCellFaceOptionItems )
|
|
{
|
|
for ( const QString& s : cellFaceResultNames )
|
|
{
|
|
if ( showDerivedResultsFirst )
|
|
{
|
|
optionList.push_front( caf::PdmOptionItemInfo( s, s ) );
|
|
}
|
|
else
|
|
{
|
|
optionList.push_back( caf::PdmOptionItemInfo( s, s ) );
|
|
}
|
|
}
|
|
|
|
// Ternary Result
|
|
if ( enableTernary )
|
|
{
|
|
bool hasAtLeastOneTernaryComponent = false;
|
|
if ( cellCenterResultNames.contains( RiaResultNames::soil() ) )
|
|
hasAtLeastOneTernaryComponent = true;
|
|
else if ( cellCenterResultNames.contains( RiaResultNames::sgas() ) )
|
|
hasAtLeastOneTernaryComponent = true;
|
|
else if ( cellCenterResultNames.contains( RiaResultNames::swat() ) )
|
|
hasAtLeastOneTernaryComponent = true;
|
|
|
|
if ( resultCatType == RiaDefines::ResultCatType::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent )
|
|
{
|
|
optionList.push_front( caf::PdmOptionItemInfo( RiaResultNames::ternarySaturationResultName(),
|
|
RiaResultNames::ternarySaturationResultName() ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
optionList.push_front( caf::PdmOptionItemInfo( RiaResultNames::undefinedResultName(), RiaResultNames::undefinedResultName() ) );
|
|
|
|
return optionList;
|
|
}
|