///////////////////////////////////////////////////////////////////////////////// // // 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 // 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 CAF_CMD_SOURCE_INIT( RicAppendSummaryPlotsForObjectsFeature, "RicAppendSummaryPlotsForObjectsFeature" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicAppendSummaryPlotsForObjectsFeature::isCommandEnabled() const { return !selectedCollections().empty(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicAppendSummaryPlotsForObjectsFeature::appendPlots( RimSummaryMultiPlot* summaryMultiPlot, const std::vector& 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(); } summaryMultiPlot->updatePlotTitles(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicAppendSummaryPlotsForObjectsFeature::appendPlots( RimSummaryMultiPlot* summaryMultiPlot, const std::vector& cases, const std::vector& ensembles ) { auto addressCollectionsToBeDeleted = RicAppendSummaryPlotsForObjectsFeature::createAddressCollections( cases, ensembles ); RicAppendSummaryPlotsForObjectsFeature::appendPlots( summaryMultiPlot, addressCollectionsToBeDeleted ); for ( auto obj : addressCollectionsToBeDeleted ) { delete obj; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicAppendSummaryPlotsForObjectsFeature::createAddressCollections( const std::vector& cases, const std::vector& ensembles ) { std::vector 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( 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::uiText( firstAdr->contentType() ); } auto text = QString( "Append Plots For " ) + objectType; actionToSetup->setText( text ); actionToSetup->setIcon( QIcon( ":/SummaryPlotLight16x16.png" ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicAppendSummaryPlotsForObjectsFeature::selectedCollections() { std::vector 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& 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 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 RicAppendSummaryPlotsForObjectsFeature::plotsForOneInstanceOfObjectType( const std::vector& sourcePlots, RimSummaryAddressCollection::CollectionContentType objectType ) { std::vector 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; }