Files
ResInsight/ApplicationLibCode/Commands/PlotBuilderCommands/RicAppendSummaryPlotsForObjectsFeature.cpp
Magne Sjaastad a91afff937 Make sure axis is set correctly when appending plots
The plots are duplicated, and the axis objects are referenced using ptrField. Make sure resolveReferencesRecursively() is called after the plot is inserted into the project tree.
2023-10-30 11:20:21 +01:00

425 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 "RimSummaryCase.h"
#include "RimSummaryCaseCollection.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() const
{
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 );
duplicatedPlot->resolveReferencesRecursively();
auto summaryCase = RiaSummaryTools::summaryCaseById( summaryAdrCollection->caseId() );
if ( summaryCase )
{
for ( auto c : duplicatedPlot->summaryCurves() )
{
c->setSummaryCaseY( summaryCase );
c->setSummaryCaseX( 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();
}
summaryMultiPlot->updatePlotTitles();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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;
}