Files
ResInsight/ApplicationLibCode/Commands/RicDeleteSummaryCaseCollectionFeature.cpp
T
Magne Sjaastad 1660e333ff #14493 Delete curves for all cases in one pass when deleting a summary ensemble
deleteSummaryCaseCollection() looped over every case in the ensemble, and for each case scanned every summary plot and called updateConnectedEditors() on every multi plot. For an ensemble with many realizations this scanned each plot once per realization, and updated the connected editors once per realization and multi plot. This showed up as a hot spot in the profiler.

Replace deleteCurvesAssosiatedWithCase() with deleteCurvesAssosiatedWithCases(), which takes a set of cases and returns whether anything was deleted. Each plot is now scanned once, and the connected editors of a multi plot are updated only when that multi plot actually lost a curve.

RicCloseSummaryCaseFeature and RicCloseObservedDataFeature are updated to the new signature. RicCloseSummaryCaseFeature also scans each plot once instead of once per case.
2026-08-10 12:38:41 +02:00

173 lines
6.8 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil 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 "RicDeleteSummaryCaseCollectionFeature.h"
#include "Summary/RiaSummaryTools.h"
#include "RimDeltaSummaryEnsemble.h"
#include "RimDepthTrackPlot.h"
#include "RimMainPlotCollection.h"
#include "RimProject.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseMainCollection.h"
#include "RimSummaryEnsemble.h"
#include "RimSummaryMultiPlot.h"
#include "RimSummaryMultiPlotCollection.h"
#include "RimSummaryPlot.h"
#include "RimWellPlotTools.h"
#include "RiuPlotMainWindow.h"
#include "cafPdmObject.h"
#include "cafPdmObjectHandleTools.h"
#include "cafSelectionManager.h"
#include <QAction>
#include <QMessageBox>
#include <set>
CAF_CMD_SOURCE_INIT( RicDeleteSummaryCaseCollectionFeature, "RicDeleteSummaryCaseCollectionFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteSummaryCaseCollectionFeature::deleteSummaryCaseCollection( RimSummaryEnsemble* caseCollection )
{
auto cases = caseCollection->allSummaryCases();
if ( cases.empty() ) return;
// Delete the curves for all the cases in one pass per plot, and update each multi plot only if it actually lost a
// curve. Doing this per case meant scanning every plot once per realization and updating the connected editors
// once per realization and multi plot.
const std::set<RimSummaryCase*> casesToDelete( cases.begin(), cases.end() );
RimSummaryMultiPlotCollection* summaryPlotColl = RiaSummaryTools::summaryMultiPlotCollection();
for ( RimSummaryMultiPlot* multiPlot : summaryPlotColl->multiPlots() )
{
bool curvesDeleted = false;
for ( RimSummaryPlot* summaryPlot : multiPlot->summaryPlots() )
{
if ( summaryPlot->deleteCurvesAssosiatedWithCases( casesToDelete ) ) curvesDeleted = true;
}
if ( curvesDeleted ) multiPlot->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicDeleteSummaryCaseCollectionFeature::isCommandEnabled() const
{
auto selection = caf::SelectionManager::instance()->objectsByType<RimSummaryEnsemble>();
selection.erase( std::remove_if( selection.begin(),
selection.end(),
[]( RimSummaryEnsemble* coll ) { return dynamic_cast<RimDeltaSummaryEnsemble*>( coll ) != nullptr; } ),
selection.end() );
return ( !selection.empty() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteSummaryCaseCollectionFeature::onActionTriggered( bool isChecked )
{
const auto ensembles = caf::SelectionManager::instance()->objectsByType<RimSummaryEnsemble>();
if ( ensembles.empty() ) return;
QMessageBox msgBox( RiuPlotMainWindow::instance() );
msgBox.setIcon( QMessageBox::Question );
QString questionText;
questionText = QString( "Do you also want to close the summary cases in the group?" );
msgBox.setText( questionText );
msgBox.setStandardButtons( QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel );
int ret = msgBox.exec();
if ( ret == QMessageBox::Cancel )
{
return;
}
auto depthTrackPlots = caf::PdmObjectHandleTools::referringAncestorOfType<RimDepthTrackPlot, RimSummaryEnsemble>( ensembles );
for ( RimSummaryEnsemble* ensemble : ensembles )
{
if ( ret == QMessageBox::Yes )
{
RicDeleteSummaryCaseCollectionFeature::deleteSummaryCaseCollection( ensemble );
}
else if ( ret == QMessageBox::No )
{
RicDeleteSummaryCaseCollectionFeature::moveAllCasesToMainSummaryCollection( ensemble );
}
}
RimSummaryCaseMainCollection* summaryCaseMainCollection = ensembles[0]->firstAncestorOrThisOfTypeAsserted<RimSummaryCaseMainCollection>();
for ( RimSummaryEnsemble* ensemble : ensembles )
{
summaryCaseMainCollection->removeEnsemble( ensemble );
ensemble->cleanupBeforeDelete();
}
// Rebuild the tree and connected editors while the detached ensembles are still alive, so no tree item
// editor ends up referencing freed objects during the update (see caf::CmdDeleteItemExec for the same
// ordering). Deleting the ensembles before the tree update caused a use-after-free crash.
summaryCaseMainCollection->updateConnectedEditors();
for ( RimSummaryEnsemble* ensemble : ensembles )
{
delete ensemble;
}
RimWellPlotTools::loadDataAndUpdateDepthTrackPlots( depthTrackPlots );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteSummaryCaseCollectionFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Delete Summary Case Group/Ensemble" );
actionToSetup->setIcon( QIcon( ":/Erase.svg" ) );
applyShortcutWithHintToAction( actionToSetup, QKeySequence::Delete );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteSummaryCaseCollectionFeature::moveAllCasesToMainSummaryCollection( RimSummaryEnsemble* summaryCaseCollection )
{
std::vector<RimSummaryCase*> summaryCases = summaryCaseCollection->allSummaryCases();
if ( summaryCases.empty() ) return;
RimSummaryCaseMainCollection* summaryCaseMainCollection = summaryCaseCollection->firstAncestorOrThisOfType<RimSummaryCaseMainCollection>();
for ( RimSummaryCase* summaryCase : summaryCases )
{
summaryCaseCollection->removeCase( summaryCase );
summaryCaseMainCollection->addCase( summaryCase );
}
}