ResInsight/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp
Magne Sjaastad 76edb49e89 #9126 Improve plot and curve handling for ensembles
Add append plots and append curves to context menu of ensembles
Make sure we create an unique color when adding multiple ensembles
2022-07-08 17:54:37 +02:00

422 lines
16 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2022 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 "RicAppendSummaryPlotsForObjectsFeature.h"
#include "RiaGuiApplication.h"
#include "RiaLogging.h"
#include "RiaStdStringTools.h"
#include "RiaSummaryAddressAnalyzer.h"
#include "RiaSummaryTools.h"
#include "RicSummaryPlotBuilder.h"
#include "RimEnsembleCurveSet.h"
#include "RimSummaryAddressCollection.h"
#include "RimSummaryAddressModifier.h"
#include "RimSummaryCurve.h"
#include "RimSummaryMultiPlot.h"
#include "RimSummaryMultiPlotCollection.h"
#include "RimSummaryPlot.h"
#include "cafAssert.h"
#include "cafProgressInfo.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicAppendSummaryPlotsForObjectsFeature, "RicAppendSummaryPlotsForObjectsFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicAppendSummaryPlotsForObjectsFeature::isCommandEnabled()
{
return !selectedCollections().empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicAppendSummaryPlotsForObjectsFeature::appendPlots( RimSummaryMultiPlot* summaryMultiPlot,
const std::vector<RimSummaryAddressCollection*>& sumAddressCollections )
{
if ( sumAddressCollections.empty() ) return;
isSelectionCompatibleWithPlot( sumAddressCollections, summaryMultiPlot );
auto selectionType = sumAddressCollections.front()->contentType();
auto sourcePlots = summaryMultiPlot->summaryPlots();
auto plotsForOneInstance = plotsForOneInstanceOfObjectType( sourcePlots, selectionType );
caf::ProgressInfo info( sumAddressCollections.size(), "Appending plots..." );
for ( auto summaryAdrCollection : sumAddressCollections )
{
auto duplicatedPlots = RicSummaryPlotBuilder::duplicateSummaryPlots( plotsForOneInstance );
for ( auto duplicatedPlot : duplicatedPlots )
{
if ( summaryAdrCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::SUMMARY_CASE )
{
summaryMultiPlot->addPlot( duplicatedPlot );
auto summaryCase = RiaSummaryTools::summaryCaseById( summaryAdrCollection->caseId() );
if ( summaryCase )
{
for ( auto c : duplicatedPlot->summaryCurves() )
{
c->setSummaryCaseY( summaryCase );
}
}
auto ensemble = RiaSummaryTools::ensembleById( summaryAdrCollection->ensembleId() );
if ( ensemble )
{
for ( auto c : duplicatedPlot->curveSets() )
{
c->setSummaryCaseCollection( ensemble );
}
}
}
else
{
auto adrMods = RimSummaryAddressModifier::createAddressModifiersForPlot( duplicatedPlot );
for ( auto adrMod : adrMods )
{
auto sourceAddress = adrMod.address();
auto modifiedAdr = modifyAddress( sourceAddress, summaryAdrCollection );
adrMod.setAddress( modifiedAdr );
}
summaryMultiPlot->addPlot( duplicatedPlot );
duplicatedPlot->resolveReferencesRecursively();
}
duplicatedPlot->loadDataAndUpdate();
}
info.incrementProgress();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicAppendSummaryPlotsForObjectsFeature::appendPlots( RimSummaryMultiPlot* summaryMultiPlot,
const std::vector<RimSummaryCase*>& cases,
const std::vector<RimSummaryCaseCollection*>& ensembles )
{
auto addressCollectionsToBeDeleted =
RicAppendSummaryPlotsForObjectsFeature::createAddressCollections( cases, ensembles );
RicAppendSummaryPlotsForObjectsFeature::appendPlots( summaryMultiPlot, addressCollectionsToBeDeleted );
for ( auto obj : addressCollectionsToBeDeleted )
{
delete obj;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryAddressCollection*>
RicAppendSummaryPlotsForObjectsFeature::createAddressCollections( const std::vector<RimSummaryCase*>& cases,
const std::vector<RimSummaryCaseCollection*>& ensembles )
{
std::vector<RimSummaryAddressCollection*> addresses;
for ( auto c : cases )
{
auto myColl = new RimSummaryAddressCollection;
myColl->setContentType( RimSummaryAddressCollection::CollectionContentType::SUMMARY_CASE );
myColl->setCaseId( c->caseId() );
addresses.push_back( myColl );
}
for ( auto c : ensembles )
{
auto myColl = new RimSummaryAddressCollection;
myColl->setContentType( RimSummaryAddressCollection::CollectionContentType::SUMMARY_CASE );
myColl->setEnsembleId( c->ensembleId() );
addresses.push_back( myColl );
}
return addresses;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicAppendSummaryPlotsForObjectsFeature::onActionTriggered( bool isChecked )
{
// - Select a set of objects in Data Source (wells, groups, regions, ..)
// - Use context menu to activate action
// - For each plot in the current active plot, create a duplicate plot and replace the object name
auto sumAddressCollections = selectedCollections();
if ( sumAddressCollections.empty() ) return;
RiaGuiApplication* app = RiaGuiApplication::instance();
auto summaryMultiPlot = dynamic_cast<RimSummaryMultiPlot*>( app->activePlotWindow() );
if ( !summaryMultiPlot ) return;
appendPlots( summaryMultiPlot, sumAddressCollections );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicAppendSummaryPlotsForObjectsFeature::setupActionLook( QAction* actionToSetup )
{
QString objectType = "Objects";
auto addresses = selectedCollections();
if ( !addresses.empty() )
{
auto firstAdr = addresses.front();
objectType = caf::AppEnum<RimSummaryAddressCollection::CollectionContentType>::uiText( firstAdr->contentType() );
}
auto text = QString( "Append Plots For " ) + objectType;
actionToSetup->setText( text );
actionToSetup->setIcon( QIcon( ":/SummaryPlotLight16x16.png" ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryAddressCollection*> RicAppendSummaryPlotsForObjectsFeature::selectedCollections()
{
std::vector<RimSummaryAddressCollection*> sumAddressCollections;
caf::SelectionManager::instance()->objectsByType( &sumAddressCollections );
if ( sumAddressCollections.size() == 1 )
{
auto coll = sumAddressCollections[0];
if ( coll->isFolder() )
{
// If a folder is selected, return all sub items in folder
auto childObjects = coll->subFolders();
return childObjects;
}
}
return sumAddressCollections;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicAppendSummaryPlotsForObjectsFeature::isSelectionCompatibleWithPlot(
const std::vector<RimSummaryAddressCollection*>& selection,
RimSummaryMultiPlot* summaryMultiPlot )
{
if ( !summaryMultiPlot ) return false;
if ( selection.empty() ) return false;
auto selectionType = selection.front()->contentType();
RiaSummaryAddressAnalyzer analyzer;
{
// Find all plots for one object type
auto sourcePlots = summaryMultiPlot->summaryPlots();
std::vector<RimSummaryPlot*> plotsForObjectType =
RicAppendSummaryPlotsForObjectsFeature::plotsForOneInstanceOfObjectType( sourcePlots, selectionType );
for ( auto plot : plotsForObjectType )
{
auto addresses = RimSummaryAddressModifier::createEclipseSummaryAddress( plot );
analyzer.appendAddresses( addresses );
}
}
QString errorText;
if ( selectionType == RimSummaryAddressCollection::CollectionContentType::WELL )
{
if ( analyzer.wellNames().empty() )
{
errorText = "Source plot must contain at least one well to be able to duplicate a selection of wells";
}
}
else if ( selectionType == RimSummaryAddressCollection::CollectionContentType::GROUP )
{
if ( analyzer.groupNames().empty() )
{
errorText = "Source plot must contain at least one group to be able to duplicate a selection of groups";
}
}
else if ( selectionType == RimSummaryAddressCollection::CollectionContentType::REGION )
{
if ( analyzer.regionNumbers().empty() )
{
errorText = "Source plot must contain at least one region to be able to duplicate a selection of regions";
}
}
if ( !errorText.isEmpty() )
{
RiaLogging::error( errorText );
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress
RicAppendSummaryPlotsForObjectsFeature::modifyAddress( const RifEclipseSummaryAddress& sourceAddress,
RimSummaryAddressCollection* summaryAddressCollection )
{
CAF_ASSERT( summaryAddressCollection );
auto adr = sourceAddress;
auto objectName = summaryAddressCollection->name().toStdString();
if ( summaryAddressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::WELL )
{
adr.setWellName( objectName );
}
else if ( summaryAddressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::GROUP )
{
adr.setGroupName( objectName );
}
else if ( summaryAddressCollection->contentType() == RimSummaryAddressCollection::CollectionContentType::REGION )
{
int intValue = RiaStdStringTools::toInt( objectName );
if ( intValue == -1 )
{
QString errorText = QString( "Failed to convert region text to region integer value "
"for region text : " ) +
summaryAddressCollection->name();
RiaLogging::error( errorText );
}
else
{
adr.setRegion( intValue );
}
}
return adr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryPlot*> RicAppendSummaryPlotsForObjectsFeature::plotsForOneInstanceOfObjectType(
const std::vector<RimSummaryPlot*>& sourcePlots,
RimSummaryAddressCollection::CollectionContentType objectType )
{
std::vector<RimSummaryPlot*> plotsForOneInstance;
std::string wellNameToMatch;
std::string groupNameToMatch;
int regionToMatch = -1;
int caseIdToMatch = -1;
int ensembleIdToMatch = -1;
RiaSummaryAddressAnalyzer myAnalyser;
for ( auto sourcePlot : sourcePlots )
{
auto addresses = RimSummaryAddressModifier::createEclipseSummaryAddress( sourcePlot );
myAnalyser.appendAddresses( addresses );
}
if ( objectType == RimSummaryAddressCollection::CollectionContentType::WELL )
{
if ( !myAnalyser.wellNames().empty() ) wellNameToMatch = *( myAnalyser.wellNames().begin() );
}
else if ( objectType == RimSummaryAddressCollection::CollectionContentType::GROUP )
{
if ( !myAnalyser.groupNames().empty() ) groupNameToMatch = *( myAnalyser.groupNames().begin() );
}
else if ( objectType == RimSummaryAddressCollection::CollectionContentType::REGION )
{
if ( !myAnalyser.regionNumbers().empty() ) regionToMatch = *( myAnalyser.regionNumbers().begin() );
}
else if ( objectType == RimSummaryAddressCollection::CollectionContentType::SUMMARY_CASE )
{
if ( !sourcePlots.empty() )
{
auto curves = sourcePlots.back()->summaryCurves();
if ( !curves.empty() )
{
caseIdToMatch = curves.front()->summaryCaseY()->caseId();
}
auto curveSets = sourcePlots.back()->curveSets();
if ( !curveSets.empty() )
{
ensembleIdToMatch = curveSets.front()->ensembleId();
}
}
}
for ( auto sourcePlot : sourcePlots )
{
bool isMatching = false;
if ( caseIdToMatch != -1 )
{
auto curves = sourcePlot->summaryCurves();
for ( auto c : curves )
{
if ( c->summaryCaseY()->caseId() == caseIdToMatch ) isMatching = true;
}
}
else if ( ensembleIdToMatch != -1 )
{
auto curveSets = sourcePlot->curveSets();
for ( auto c : curveSets )
{
if ( c->summaryCaseCollection()->ensembleId() == ensembleIdToMatch ) isMatching = true;
}
}
else
{
auto addresses = RimSummaryAddressModifier::createEclipseSummaryAddress( sourcePlot );
for ( const auto& a : addresses )
{
if ( !wellNameToMatch.empty() && a.wellName() == wellNameToMatch )
{
isMatching = true;
}
else if ( !groupNameToMatch.empty() && a.groupName() == groupNameToMatch )
{
isMatching = true;
}
else if ( regionToMatch != -1 && a.regionNumber() == regionToMatch )
{
isMatching = true;
}
}
}
if ( isMatching ) plotsForOneInstance.push_back( sourcePlot );
}
return plotsForOneInstance;
}