#7739 Show only visible categories in legend

For the main Cell Result Legend, add an option to only show visible categories
This commit is contained in:
Magne Sjaastad 2021-05-31 08:19:12 +02:00
parent 6e0dadbdaa
commit b3467a2fca
6 changed files with 374 additions and 85 deletions

View File

@ -21,6 +21,7 @@
#include "RimEclipseResultDefinition.h"
#include "RiaColorTables.h"
#include "RiaColorTools.h"
#include "RiaLogging.h"
#include "RiaNncDefines.h"
#include "RiaQDateTimeTools.h"
@ -35,7 +36,7 @@
#include "RigFlowDiagResultAddress.h"
#include "RigFlowDiagResults.h"
#include "RigFormationNames.h"
#include "RigVisibleTracerFilter.h"
#include "RigVisibleCategoriesCalculator.h"
#include "Rim3dView.h"
#include "Rim3dWellLogCurve.h"
@ -150,10 +151,10 @@ RimEclipseResultDefinition::RimEclipseResultDefinition( caf::PdmUiItemInfo::Labe
CAF_PDM_InitScriptableFieldNoDefault( &m_phaseSelection, "PhaseSelection", "Phases", "", "", "" );
m_phaseSelection.uiCapability()->setUiLabelPosition( m_labelPosition );
CAF_PDM_InitScriptableField( &m_showOnlyVisibleTracersInLegend,
"ShowOnlyVisibleTracersInLegend",
CAF_PDM_InitScriptableField( &m_showOnlyVisibleCategoriesInLegend,
"ShowOnlyVisibleCategoriesInLegend",
true,
"Show Only Visible Tracers In Legend",
"Show Only Visible Categories In Legend",
"",
"",
"" );
@ -426,6 +427,11 @@ void RimEclipseResultDefinition::fieldChangedByUi( const caf::PdmFieldHandle* ch
loadDataAndUpdate();
}
if ( &m_showOnlyVisibleCategoriesInLegend == changedField )
{
loadDataAndUpdate();
}
updateAnyFieldHasChanged();
}
@ -1577,12 +1583,28 @@ void RimEclipseResultDefinition::defineUiOrdering( QString uiConfigName, caf::Pd
m_resultVariableUiField.uiCapability()->setUiName( resultPropertyLabel );
}
caf::PdmUiGroup* legendGroup = uiOrdering.addNewGroup( "Legend" );
legendGroup->add( &m_showOnlyVisibleTracersInLegend );
{
caf::PdmUiGroup* legendGroup = uiOrdering.addNewGroup( "Legend" );
legendGroup->add( &m_showOnlyVisibleCategoriesInLegend );
bool showOnlyVisibleTracesOption = ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS &&
m_resultVariableUiField() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME );
legendGroup->setUiHidden( !showOnlyVisibleTracesOption );
bool showOnlyVisibleCategoriesOption = false;
RimEclipseView* eclView = nullptr;
this->firstAncestorOrThisOfType( eclView );
if ( eclView )
{
if ( eclView->cellResult() == this && this->hasCategoryResult() ) showOnlyVisibleCategoriesOption = true;
}
if ( m_resultTypeUiField() == RiaDefines::ResultCatType::FLOW_DIAGNOSTICS &&
m_resultVariableUiField() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME )
{
showOnlyVisibleCategoriesOption = true;
}
legendGroup->setUiHidden( !showOnlyVisibleCategoriesOption );
}
if ( isDeltaCasePossible() || isDeltaTimeStepPossible() )
{
@ -1924,14 +1946,13 @@ void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegen
std::vector<std::tuple<QString, int, cvf::Color3ub>> categoryVector;
if ( m_showOnlyVisibleTracersInLegend )
if ( m_showOnlyVisibleCategoriesInLegend )
{
std::set<int> visibleTracers;
RigVisibleTracerFilter::filterByVisibility( *eclView,
*flowResultsData,
resAddr,
currentTimeStep,
visibleTracers );
std::set<int> visibleTracers =
RigVisibleCategoriesCalculator::visibleFlowDiagCategories( *eclView,
*flowResultsData,
resAddr,
currentTimeStep );
for ( auto tupIt : categories )
{
int tracerIndex = std::get<1>( tupIt );
@ -1998,12 +2019,7 @@ void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegen
if ( this->hasCategoryResult() )
{
if ( this->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
{
std::vector<QString> fnVector = eclipseCaseData->formationNames();
legendConfigToUpdate->setNamedCategories( fnVector );
}
else if ( this->resultType() == RiaDefines::ResultCatType::ALLAN_DIAGRAMS )
if ( this->resultType() == RiaDefines::ResultCatType::ALLAN_DIAGRAMS )
{
if ( this->resultVariable() == RiaResultNames::formationAllanResultName() )
{
@ -2030,11 +2046,20 @@ void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegen
categories.emplace_back( std::make_tuple( fnVector[frmNameIdx], frmNameIdx, formationColor ) );
}
for ( auto it : formationCombToCategory )
std::set<size_t> visibleAllanCategories;
{
int frmIdx1 = it.first.first;
int frmIdx2 = it.first.second;
int combIndex = it.second;
RimEclipseView* eclView = nullptr;
this->firstAncestorOrThisOfType( eclView );
visibleAllanCategories = RigVisibleCategoriesCalculator::visibleAllanCategories( eclView );
}
for ( auto [formationPair, categoryIndex] : formationCombToCategory )
{
int frmIdx1 = formationPair.first;
int frmIdx2 = formationPair.second;
if ( visibleAllanCategories.count( categoryIndex ) == 0 ) continue;
int fnVectorSize = static_cast<int>( fnVector.size() );
if ( frmIdx1 >= fnVectorSize || frmIdx2 >= fnVectorSize ) continue;
@ -2046,10 +2071,10 @@ void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegen
cvf::Color3f formationColor2 = cvf::Color3f( formationColorMapper->mapToColor( frmIdx2 ) );
cvf::Color3ub blendColor =
cvf::Color3ub( cvf::Color3f( 0.5f * ( formationColor1.r() + formationColor2.r() ),
0.5f * ( formationColor1.g() + formationColor2.g() ),
0.5f * ( formationColor1.b() + formationColor2.b() ) ) );
categories.emplace_back( std::make_tuple( frmName1 + "-" + frmName2, combIndex, blendColor ) );
cvf::Color3ub( RiaColorTools::blendCvfColors( formationColor1, formationColor2 ) );
categories.emplace_back(
std::make_tuple( frmName1 + "-" + frmName2, categoryIndex, blendColor ) );
}
legendConfigToUpdate->setCategoryItems( categories );
@ -2096,8 +2121,56 @@ void RimEclipseResultDefinition::updateRangesForExplicitLegends( RimRegularLegen
}
else
{
legendConfigToUpdate->setIntegerCategories(
cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() ) );
auto uniqueValues = cellResultsData->uniqueCellScalarValues( this->eclipseResultAddress() );
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 ( m_showOnlyVisibleCategoriesInLegend )
{
RimEclipseView* eclView = nullptr;
this->firstAncestorOrThisOfType( eclView );
if ( eclView )
{
// 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() == this )
{
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;
std::vector<QString> fnVector = eclipseCaseData->formationNames();
for ( auto value : visibleCategoryValues )
{
cvf::Color3ub categoryColor = categoryMapper->mapToColor( value );
QString valueTxt;
if ( this->resultType() == RiaDefines::ResultCatType::FORMATION_NAMES )
{
valueTxt = fnVector[value];
}
else
valueTxt = QString( "%1" ).arg( value );
categoryVector.push_back( std::make_tuple( valueTxt, value, categoryColor ) );
}
legendConfigToUpdate->setCategoryItems( categoryVector );
}
}
}

View File

@ -180,7 +180,7 @@ protected:
caf::PdmField<caf::AppEnum<FlowTracerSelectionType>> m_flowTracerSelectionMode;
caf::PdmPtrField<RimFlowDiagSolution*> m_flowSolutionUiField;
caf::PdmField<RigFlowDiagResultAddress::PhaseSelectionEnum> m_phaseSelection;
caf::PdmField<bool> m_showOnlyVisibleTracersInLegend;
caf::PdmField<bool> m_showOnlyVisibleCategoriesInLegend;
caf::PdmField<bool> m_syncInjectorToProducerSelection;
caf::PdmField<bool> m_syncProducerToInjectorSelection;

View File

@ -83,7 +83,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigGocadData.h
${CMAKE_CURRENT_LIST_DIR}/RigElasticProperties.h
${CMAKE_CURRENT_LIST_DIR}/RigEnsembleFractureStatisticsCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigHistogramData.h
${CMAKE_CURRENT_LIST_DIR}/RigVisibleTracerFilter.h
${CMAKE_CURRENT_LIST_DIR}/RigVisibleCategoriesCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigTracerPoint.h
${CMAKE_CURRENT_LIST_DIR}/RigTracer.h
${CMAKE_CURRENT_LIST_DIR}/RigStimPlanModelTools.h
@ -168,7 +168,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigGocadData.cpp
${CMAKE_CURRENT_LIST_DIR}/RigElasticProperties.cpp
${CMAKE_CURRENT_LIST_DIR}/RigEnsembleFractureStatisticsCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigHistogramData.cpp
${CMAKE_CURRENT_LIST_DIR}/RigVisibleTracerFilter.cpp
${CMAKE_CURRENT_LIST_DIR}/RigVisibleCategoriesCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigTracerPoint.cpp
${CMAKE_CURRENT_LIST_DIR}/RigTracer.cpp
${CMAKE_CURRENT_LIST_DIR}/RigStimPlanModelTools.cpp

View File

@ -0,0 +1,252 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- 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 "RigVisibleCategoriesCalculator.h"
#include "RiaResultNames.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseNativeVisibleCellsStatCalc.h"
#include "RigFault.h"
#include "RigFlowDiagResults.h"
#include "RigFlowDiagVisibleCellsStatCalc.h"
#include "RigMainGrid.h"
#include "RigNNCData.h"
#include "RigResultAccessorFactory.h"
#include "RimBoxIntersection.h"
#include "RimEclipseCase.h"
#include "RimEclipseCellColors.h"
#include "RimEclipseFaultColors.h"
#include "RimEclipseView.h"
#include "RimExtrudedCurveIntersection.h"
#include "RimFaultInView.h"
#include "RimFaultInViewCollection.h"
#include "RimIntersection.h"
#include "RimIntersectionCollection.h"
#include "RimIntersectionResultsDefinitionCollection.h"
#include "RimSurface.h"
#include "RimSurfaceCollection.h"
#include "RimSurfaceInView.h"
#include "RimSurfaceInViewCollection.h"
#include "RivHexGridIntersectionTools.h"
#include <cmath>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<int> RigVisibleCategoriesCalculator::visibleFlowDiagCategories( RimEclipseView& eclView,
RigFlowDiagResults& flowDiagResults,
const RigFlowDiagResultAddress& resVarAddr,
size_t timeStepIndex )
{
cvf::ref<cvf::UByteArray> cellVisibilities = eclView.currentTotalCellVisibility();
cvf::ref<RigFlowDiagVisibleCellsStatCalc> calculator =
cvf::make_ref<RigFlowDiagVisibleCellsStatCalc>( &flowDiagResults, resVarAddr, cellVisibilities.p() );
std::set<int> visibleTracers;
calculator->uniqueValues( timeStepIndex, visibleTracers );
return visibleTracers;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<size_t> RigVisibleCategoriesCalculator::visibleAllanCategories( RimEclipseView* eclView )
{
if ( !( eclView && eclView->mainGrid() ) ) return {};
RigNNCData* nncData = eclView->mainGrid()->nncData();
std::set<size_t> usedAllanIndices;
auto fnAllanNncResults = nncData->staticConnectionScalarResultByName( RiaResultNames::formationAllanResultName() );
if ( fnAllanNncResults )
{
auto visibleConnectionIndices = visibleNncConnectionIndices( eclView );
for ( auto connIdx : visibleConnectionIndices )
{
auto allanValue = fnAllanNncResults->at( connIdx );
usedAllanIndices.insert( allanValue );
}
}
return usedAllanIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<int> RigVisibleCategoriesCalculator::visibleCategories( RimEclipseView* eclView )
{
std::set<int> visibleCategoryValues;
{
// Visible eclipse grid cells
RimEclipseResultDefinition* resDef = eclView->cellResult();
RigEclipseNativeVisibleCellsStatCalc calc( resDef->currentGridCellResults(),
resDef->eclipseResultAddress(),
eclView->currentTotalCellVisibility().p() );
calc.uniqueValues( eclView->currentTimeStep(), visibleCategoryValues );
}
{
// Visible cells in faults and intersections
std::set<size_t> visibleReservoirCells;
RigVisibleCategoriesCalculator::appendVisibleFaultCells( eclView, visibleReservoirCells );
RigVisibleCategoriesCalculator::appendVisibleIntersectionCells( eclView, visibleReservoirCells );
RimEclipseResultDefinition* resDef = eclView->cellResult();
cvf::ref<RigResultAccessor> resultAccessor =
RigResultAccessorFactory::createFromResultDefinition( eclView->eclipseCase()->eclipseCaseData(),
0,
eclView->currentTimeStep(),
resDef );
if ( resultAccessor.notNull() )
{
for ( auto cIdx : visibleReservoirCells )
{
const auto resultVal = resultAccessor->cellScalarGlobIdx( cIdx );
if ( resultVal != HUGE_VAL )
{
visibleCategoryValues.insert( resultVal );
}
}
}
}
return visibleCategoryValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<size_t> RigVisibleCategoriesCalculator::visibleNncConnectionIndices( RimEclipseView* eclView )
{
if ( !eclView->faultCollection() || !eclView->faultCollection()->showFaultCollection ) return {};
std::set<size_t> visibleConnectionIndices;
std::vector<RimFaultInView*> visibleFaults;
for ( auto f : eclView->faultCollection()->faults() )
{
if ( f->showFault() )
{
visibleFaults.push_back( f );
auto nncConnectionIndices = f->faultGeometry()->connectionIndices();
for ( const auto& c : nncConnectionIndices )
{
visibleConnectionIndices.insert( c );
}
}
}
return visibleConnectionIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVisibleCategoriesCalculator::appendVisibleFaultCells( RimEclipseView* eclView, std::set<size_t>& visibleCells )
{
if ( eclView->faultCollection() && eclView->faultCollection()->showFaultCollection &&
!eclView->faultResultSettings()->showCustomFaultResult() )
{
for ( const auto& f : eclView->faultCollection()->faults() )
{
if ( f->showFault() )
{
for ( const auto& faultFace : f->faultGeometry()->faultFaces() )
{
visibleCells.insert( faultFace.m_nativeReservoirCellIndex );
visibleCells.insert( faultFace.m_oppositeReservoirCellIndex );
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVisibleCategoriesCalculator::appendVisibleIntersectionCells( RimEclipseView* eclView, std::set<size_t>& visibleCells )
{
// Intersections
std::vector<const RivIntersectionGeometryGeneratorIF*> intersectionGeoGenerators;
if ( !eclView->separateIntersectionResultsCollection()->isActive() )
{
if ( eclView->intersectionCollection()->isActive() )
{
for ( auto intersection : eclView->intersectionCollection()->intersections() )
{
if ( intersection->isActive() )
{
auto geoGenerator = intersection->intersectionGeometryGenerator();
if ( geoGenerator )
{
intersectionGeoGenerators.push_back( geoGenerator );
}
}
}
for ( auto intersection : eclView->intersectionCollection()->intersectionBoxes() )
{
if ( intersection->isActive() )
{
auto geoGenerator = intersection->intersectionGeometryGenerator();
if ( geoGenerator )
{
intersectionGeoGenerators.push_back( geoGenerator );
}
}
}
}
}
if ( eclView->separateSurfaceResultsCollection()->isActive() )
{
// Surfaces in view
if ( eclView->surfaceInViewCollection() && eclView->surfaceInViewCollection()->isChecked() )
{
auto geoGenerators = eclView->surfaceInViewCollection()->intersectionGeometryGenerators();
intersectionGeoGenerators.insert( intersectionGeoGenerators.end(), geoGenerators.begin(), geoGenerators.end() );
}
}
for ( const auto geoGenerator : intersectionGeoGenerators )
{
for ( const auto& cIdx : geoGenerator->triangleToCellIndex() )
{
visibleCells.insert( cIdx );
}
}
}

View File

@ -28,12 +28,20 @@ class RigFlowDiagResultAddress;
//==================================================================================================
///
//==================================================================================================
class RigVisibleTracerFilter
class RigVisibleCategoriesCalculator
{
public:
static void filterByVisibility( RimEclipseView& eclView,
RigFlowDiagResults& flowDiagResults,
const RigFlowDiagResultAddress& resVarAddr,
size_t timeStepIndex,
std::set<int>& visibleTracers );
static std::set<int> visibleFlowDiagCategories( RimEclipseView& eclView,
RigFlowDiagResults& flowDiagResults,
const RigFlowDiagResultAddress& resVarAddr,
size_t timeStepIndex );
static std::set<size_t> visibleAllanCategories( RimEclipseView* eclView );
static std::set<int> visibleCategories( RimEclipseView* eclView );
private:
static std::set<size_t> visibleNncConnectionIndices( RimEclipseView* eclView );
static void appendVisibleFaultCells( RimEclipseView* eclView, std::set<size_t>& visibleCells );
static void appendVisibleIntersectionCells( RimEclipseView* eclView, std::set<size_t>& visibleCells );
};

View File

@ -1,44 +0,0 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2021- 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 "RigVisibleTracerFilter.h"
#include "RigFlowDiagResults.h"
#include "RigFlowDiagVisibleCellsStatCalc.h"
#include "RimEclipseView.h"
#include "cvfArray.h"
#include <cmath>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVisibleTracerFilter::filterByVisibility( RimEclipseView& eclView,
RigFlowDiagResults& flowDiagResults,
const RigFlowDiagResultAddress& resVarAddr,
size_t timeStepIndex,
std::set<int>& visibleTracers )
{
cvf::ref<cvf::UByteArray> cellVisibilities = eclView.currentTotalCellVisibility();
cvf::ref<RigFlowDiagVisibleCellsStatCalc> calculator =
cvf::make_ref<RigFlowDiagVisibleCellsStatCalc>( &flowDiagResults, resVarAddr, cellVisibilities.p() );
calculator->uniqueValues( timeStepIndex, visibleTracers );
}