Files
ResInsight/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.cpp
Magne Sjaastad 5e791353b2 #14470 Do not truncate folder names containing a dot when removing file extension
The ensemble file set removed the file extension by searching for the last dot in the complete path. When the path pattern was already without extension, the last dot was found in a folder name, truncating the path pattern and causing the search for SMSPEC files to fail.

Add RiaFilePathTools::removeFileExtension based on std::filesystem::path::replace_extension, and use it both in RimEnsembleFileSet and in the grid and summary ensemble import, replacing a duplicated lambda doing the same operation.
2026-08-06 14:10:49 +02:00

235 lines
9.8 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026- 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 "RicImportGridAndSummaryEnsembleFeature.h"
#include "RiaApplication.h"
#include "RiaDefines.h"
#include "RiaFilePathTools.h"
#include "RiaFileSearchTools.h"
#include "RiaGuiApplication.h"
#include "Summary/RiaSummaryPlotTools.h"
#include "RicImportGridAndSummaryEnsembleDialog.h"
#include "RicNewViewFeature.h"
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
#include "Rim3dView.h"
#include "RimReservoirGridEnsemble.h"
#include "RimSummaryEnsemble.h"
#include "RimViewNameConfig.h"
#include "RiuPlotMainWindow.h"
#include "RiuPlotMainWindowTools.h"
#include <QAction>
#include <QIcon>
#include <QPointer>
#include <QSet>
#include <QSettings>
#include <QTimer>
CAF_CMD_SOURCE_INIT( RicImportGridAndSummaryEnsembleFeature, "RicImportGridAndSummaryEnsembleFeature" );
namespace
{
const QString k_settingsKey = "EnsembleImportParams";
const QChar k_sep = '\t';
void storeEnsembleImportParams( const RicImportGridAndSummaryEnsembleDialogResult& result )
{
QString rootDir = result.rootDir;
if ( rootDir.endsWith( '/' ) || rootDir.endsWith( '\\' ) ) rootDir.chop( 1 );
QString record = rootDir + k_sep + result.pathFilter + k_sep + QString::number( static_cast<int>( result.groupingMode ) ) + k_sep +
( result.createGridEnsemble ? QChar( '1' ) : QChar( '0' ) ) + k_sep +
( result.createSummaryEnsemble ? QChar( '1' ) : QChar( '0' ) ) + k_sep + result.filePattern;
QSettings settings;
QStringList stored = settings.value( k_settingsKey ).toStringList();
stored.erase( std::remove_if( stored.begin(), stored.end(), [&]( const QString& r ) { return r.section( k_sep, 0, 0 ) == rootDir; } ),
stored.end() );
stored.prepend( record );
while ( stored.size() > 20 )
stored.removeLast();
settings.setValue( k_settingsKey, stored );
}
bool loadEnsembleImportParams( const QString& rootDir,
QString& pathFilter,
RiaDefines::EnsembleGroupingMode& groupingMode,
bool& createGrid,
bool& createSummary,
QString& filePattern )
{
QSettings settings;
QStringList stored = settings.value( k_settingsKey ).toStringList();
for ( const auto& r : stored )
{
if ( r.section( k_sep, 0, 0 ) == rootDir )
{
pathFilter = r.section( k_sep, 1, 1 );
groupingMode = static_cast<RiaDefines::EnsembleGroupingMode>( r.section( k_sep, 2, 2 ).toInt() );
createGrid = r.section( k_sep, 3, 3 ) == "1";
createSummary = r.section( k_sep, 4, 4 ) == "1";
filePattern = r.section( k_sep, 5, 5 );
if ( filePattern.isEmpty() ) filePattern = "*";
return true;
}
}
return false;
}
} // namespace
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
static void doImport( const RicImportGridAndSummaryEnsembleDialogResult& result, QPointer<QWidget> activeWindowBeforeImport )
{
// Build the union of base paths (extension-stripped) from both lists so every realization
// appears exactly once. findPathPattern requires each realization number to be unique across
// the input; duplicating paths with different extensions breaks the pattern detection.
QStringList strippedPaths;
for ( const auto& f : result.gridFiles )
strippedPaths << RiaFilePathTools::removeFileExtension( f );
for ( const auto& f : result.summaryFiles )
strippedPaths << RiaFilePathTools::removeFileExtension( f );
strippedPaths.removeDuplicates();
if ( strippedPaths.isEmpty() ) return;
auto fileSets = RimEnsembleFileSetTools::createEnsembleFileSets( strippedPaths, result.groupingMode );
if ( fileSets.empty() ) return;
bool gridEnsemblesCreated = false;
if ( result.createGridEnsemble && !result.gridFiles.isEmpty() )
{
auto gridEnsembles = RimEnsembleFileSetTools::createGridEnsemblesFromFileSets( fileSets );
if ( !gridEnsembles.empty() )
{
gridEnsemblesCreated = true;
auto firstEnsemble = gridEnsembles.front();
auto cases = firstEnsemble->cases();
if ( !cases.empty() )
{
auto view = RicNewViewFeature::addReservoirView( cases.front(), nullptr, firstEnsemble->viewCollection() );
if ( view ) view->nameConfig()->setAddCaseName( true );
}
}
}
if ( result.createSummaryEnsemble && !result.summaryFiles.isEmpty() )
{
auto summaryEnsembles = RimEnsembleFileSetTools::createSummaryEnsemblesFromFileSets( fileSets );
for ( auto ensemble : summaryEnsembles )
{
RiaSummaryPlotTools::createAndAppendDefaultSummaryMultiPlot( {}, { ensemble } );
}
if ( !summaryEnsembles.empty() ) RiuPlotMainWindowTools::showPlotMainWindow();
}
if ( gridEnsemblesCreated && activeWindowBeforeImport )
{
QTimer::singleShot( 500,
activeWindowBeforeImport,
[activeWindowBeforeImport]()
{
activeWindowBeforeImport->raise();
activeWindowBeforeImport->activateWindow();
} );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicImportGridAndSummaryEnsembleFeature::importFromDirectory( const QString& dirPath )
{
if ( !RiaGuiApplication::instance() ) return false;
QString pathFilter;
RiaDefines::EnsembleGroupingMode groupingMode;
bool createGrid;
bool createSummary;
QString filePattern;
if ( !loadEnsembleImportParams( dirPath, pathFilter, groupingMode, createGrid, createSummary, filePattern ) ) return false;
QString rootDir = dirPath;
if ( rootDir.size() > 1 && ( rootDir.endsWith( '/' ) || rootDir.endsWith( '\\' ) ) ) rootDir.chop( 1 );
QStringList matchingFolders;
RiaFileSearchTools::findMatchingFoldersRecursively( rootDir, pathFilter, matchingFolders );
QStringList gridFiles = RiaFileSearchTools::findFilesInFolders( matchingFolders, { filePattern + ".EGRID" } );
QStringList summaryFiles = RiaFileSearchTools::findFilesInFolders( matchingFolders, { filePattern + ".SMSPEC", filePattern + ".ESMRY" } );
std::sort( summaryFiles.begin(), summaryFiles.end() );
if ( gridFiles.isEmpty() && summaryFiles.isEmpty() ) return false;
RicImportGridAndSummaryEnsembleDialogResult result;
result.ok = true;
result.rootDir = rootDir + RiaFilePathTools::separator();
result.pathFilter = pathFilter;
result.filePattern = filePattern;
result.groupingMode = groupingMode;
result.createGridEnsemble = createGrid;
result.createSummaryEnsemble = createSummary;
result.gridFiles = gridFiles;
result.summaryFiles = summaryFiles;
QPointer<QWidget> activeWindowBeforeImport = RiaGuiApplication::widgetToUseAsParent();
doImport( result, activeWindowBeforeImport );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportGridAndSummaryEnsembleFeature::onActionTriggered( bool isChecked )
{
QPointer<QWidget> activeWindowBeforeImport = RiaGuiApplication::widgetToUseAsParent();
bool startedFromPlotWindow = ( RiaGuiApplication::activeMainWindow() == RiaGuiApplication::instance()->mainPlotWindow() );
auto result = RicImportGridAndSummaryEnsembleDialog::runDialog( activeWindowBeforeImport, !startedFromPlotWindow, startedFromPlotWindow );
if ( !result.ok ) return;
if ( !result.createGridEnsemble && !result.createSummaryEnsemble ) return;
doImport( result, activeWindowBeforeImport );
storeEnsembleImportParams( result );
QString rootDir = result.rootDir;
if ( rootDir.endsWith( '/' ) || rootDir.endsWith( '\\' ) ) rootDir.chop( 1 );
RiaApplication::instance()->addToRecentFiles( rootDir );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicImportGridAndSummaryEnsembleFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setIcon( QIcon( ":/GridAndSummaryEnsemble.svg" ) );
actionToSetup->setText( "Import Grid and Summary Ensemble" );
}