mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-06 22:26:44 -06:00
Run Opm Flow jobs from ResInsight (#12580)
This commit is contained in:
62 files changed
+3144
-62
No files matched your search
@@ -182,6 +182,22 @@ QString RimWellPathCompletionSettings::groupNameForExport() const
|
||||
return formatStringForExport( m_groupName, "1*" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellPathCompletionSettings::wellName() const
|
||||
{
|
||||
return m_wellNameForExport();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimWellPathCompletionSettings::groupName() const
|
||||
{
|
||||
return m_groupName();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -69,6 +69,9 @@ public:
|
||||
RimWellPathCompletionSettings( const RimWellPathCompletionSettings& rhs );
|
||||
RimWellPathCompletionSettings& operator=( const RimWellPathCompletionSettings& rhs );
|
||||
|
||||
QString groupName() const;
|
||||
QString wellName() const;
|
||||
|
||||
void setWellNameForExport( const QString& name );
|
||||
void updateWellPathNameHasChanged( const QString& newWellPathName, const QString& previousWellPathName );
|
||||
QString wellNameForExport() const;
|
||||
|
||||
@@ -97,7 +97,18 @@ QStringList RimEnsembleFileSet::createPaths( const QString& extension ) const
|
||||
{
|
||||
if ( m_realizationNumbersReadFromFiles.isEmpty() )
|
||||
{
|
||||
auto paths = RiaEnsembleImportTools::createPathsBySearchingFileSystem( pathPatternWithExtension, internal::placeholderString() );
|
||||
QStringList paths;
|
||||
if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::RESINSIGHT_OPMFLOW_STRUCTURE )
|
||||
{
|
||||
paths =
|
||||
RiaEnsembleImportTools::createPathsBySearchingFileSystem( pathPatternWithExtension, internal::placeholderString(), "run" );
|
||||
}
|
||||
else
|
||||
{
|
||||
paths = RiaEnsembleImportTools::createPathsBySearchingFileSystem( pathPatternWithExtension,
|
||||
internal::placeholderString(),
|
||||
"realization" );
|
||||
}
|
||||
const auto [pattern, range] = RiaEnsembleImportTools::findPathPattern( paths, internal::placeholderString() );
|
||||
m_realizationNumbersReadFromFiles = range;
|
||||
}
|
||||
@@ -238,6 +249,14 @@ void RimEnsembleFileSet::setUsePathKey2( bool useKey2 )
|
||||
m_useKey2 = useKey2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEnsembleFileSet::setAutoName( bool autoName )
|
||||
{
|
||||
m_autoName = autoName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -393,6 +412,20 @@ std::pair<std::string, std::string> RimEnsembleFileSet::nameKeys() const
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::RESINSIGHT_OPMFLOW_STRUCTURE )
|
||||
{
|
||||
auto pathPattern = m_pathPattern + ".SMSPEC";
|
||||
auto paths = RiaEnsembleImportTools::createPathsFromPattern( pathPattern, "0", internal::placeholderString() );
|
||||
if ( !paths.empty() )
|
||||
{
|
||||
auto fileNames = RiaEnsembleNameTools::groupFilePathsOpm( { paths.front().toStdString() } );
|
||||
if ( !fileNames.empty() )
|
||||
{
|
||||
key1 = fileNames.begin()->first.first;
|
||||
key2 = fileNames.begin()->first.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { key1, key2 };
|
||||
}
|
||||
@@ -424,7 +457,15 @@ void RimEnsembleFileSet::setGroupingMode( RiaDefines::EnsembleGroupingMode group
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEnsembleFileSet::sendFileSetChangedSignal()
|
||||
RiaDefines::EnsembleGroupingMode RimEnsembleFileSet::groupingMode() const
|
||||
{
|
||||
return m_groupingMode();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimEnsembleFileSet::sendFileSetChangedSignal() const
|
||||
{
|
||||
fileSetChanged.send();
|
||||
}
|
||||
|
||||
@@ -54,8 +54,11 @@ public:
|
||||
void setUsePathKey2( bool useKey2 );
|
||||
std::pair<std::string, std::string> nameKeys() const;
|
||||
QString nameTemplateText() const;
|
||||
void setAutoName( bool autoName );
|
||||
|
||||
void setGroupingMode( RiaDefines::EnsembleGroupingMode groupingMode );
|
||||
RiaDefines::EnsembleGroupingMode groupingMode() const;
|
||||
|
||||
void setGroupingMode( RiaDefines::EnsembleGroupingMode groupingMode );
|
||||
void reload();
|
||||
|
||||
private:
|
||||
@@ -68,7 +71,7 @@ private:
|
||||
|
||||
QString ensembleInfo() const;
|
||||
|
||||
void sendFileSetChangedSignal();
|
||||
void sendFileSetChangedSignal() const;
|
||||
|
||||
private:
|
||||
caf::PdmField<QString> m_pathPattern;
|
||||
|
||||
@@ -79,6 +79,25 @@ std::vector<RimEnsembleFileSet*> createEnsembleFileSets( const QStringList& file
|
||||
return fileSets;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimEnsembleFileSet* createEnsembleFileSetFromOpm( const QString& pathPattern, const QString& name )
|
||||
{
|
||||
auto collection = RimProject::current()->ensembleFileSetCollection();
|
||||
auto ensembleFileSet = new RimEnsembleFileSet();
|
||||
ensembleFileSet->setAutoName( false );
|
||||
ensembleFileSet->setName( name );
|
||||
ensembleFileSet->setGroupingMode( RiaDefines::EnsembleGroupingMode::RESINSIGHT_OPMFLOW_STRUCTURE );
|
||||
ensembleFileSet->setPathPattern( pathPattern );
|
||||
|
||||
collection->addFileSet( ensembleFileSet );
|
||||
collection->updateFileSetNames();
|
||||
collection->updateAllRequiredEditors();
|
||||
|
||||
return ensembleFileSet;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace RimEnsembleFileSetTools
|
||||
std::vector<RimSummaryEnsemble*> createSummaryEnsemblesFromFileSets( const std::vector<RimEnsembleFileSet*> fileSets );
|
||||
std::vector<RimEnsembleFileSet*> createEnsembleFileSets( const QStringList& fileNames, RiaDefines::EnsembleGroupingMode groupingMode );
|
||||
|
||||
RimEnsembleFileSet* createEnsembleFileSetFromOpm( const QString& pathPattern, const QString& name );
|
||||
|
||||
QList<caf::PdmOptionItemInfo> ensembleFileSetOptions();
|
||||
|
||||
}; // namespace RimEnsembleFileSetTools
|
||||
@@ -0,0 +1,17 @@
|
||||
set(SOURCE_GROUP_HEADER_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimGenericJob.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimOpmFlowJob.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimJobCollection.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDeckPositionDlg.h
|
||||
)
|
||||
|
||||
set(SOURCE_GROUP_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimGenericJob.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimOpmFlowJob.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimJobCollection.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/RimDeckPositionDlg.cpp
|
||||
)
|
||||
|
||||
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
|
||||
|
||||
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
|
||||
@@ -0,0 +1,187 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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 "RimDeckPositionDlg.h"
|
||||
|
||||
#include "RiuTools.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimDeckPositionDlg::RimDeckPositionDlg( QWidget* parent )
|
||||
: QDialog( parent, RiuTools::defaultDialogFlags() )
|
||||
, m_selectedPosition( -1 )
|
||||
{
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout();
|
||||
|
||||
QLabel* label = new QLabel( "Select position of open well keyword:" );
|
||||
mainLayout->addWidget( label );
|
||||
|
||||
QHBoxLayout* listLayout = new QHBoxLayout();
|
||||
|
||||
m_list = new QListWidget();
|
||||
listLayout->addWidget( m_list );
|
||||
|
||||
QVBoxLayout* upDownLayout = new QVBoxLayout();
|
||||
|
||||
QPushButton* moveUp = new QPushButton( "Up" );
|
||||
QPushButton* moveDown = new QPushButton( "Down" );
|
||||
|
||||
connect( moveUp, SIGNAL( clicked() ), this, SLOT( slotMoveUpClicked() ) );
|
||||
connect( moveDown, SIGNAL( clicked() ), this, SLOT( slotMoveDownClicked() ) );
|
||||
|
||||
upDownLayout->addStretch( 1 );
|
||||
upDownLayout->addWidget( moveUp );
|
||||
upDownLayout->addWidget( moveDown );
|
||||
upDownLayout->addStretch( 1 );
|
||||
|
||||
listLayout->addLayout( upDownLayout );
|
||||
|
||||
mainLayout->addLayout( listLayout );
|
||||
|
||||
m_buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
|
||||
connect( m_buttons, SIGNAL( accepted() ), this, SLOT( slotDialogOkClicked() ) );
|
||||
connect( m_buttons, SIGNAL( rejected() ), this, SLOT( slotDialogCancelClicked() ) );
|
||||
|
||||
mainLayout->addWidget( m_buttons );
|
||||
|
||||
setLayout( mainLayout );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimDeckPositionDlg::~RimDeckPositionDlg()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RimDeckPositionDlg::askForPosition( QWidget* parent, std::vector<std::pair<int, QString>> items, QString newItemName, int defPosition )
|
||||
{
|
||||
RimDeckPositionDlg dlg( parent );
|
||||
|
||||
dlg.setWindowTitle( "Open Well" );
|
||||
dlg.addItems( items );
|
||||
dlg.addNewItem( newItemName, defPosition );
|
||||
|
||||
dlg.resize( 300, 600 );
|
||||
if ( dlg.exec() == QDialog::Accepted )
|
||||
{
|
||||
return dlg.selectedPosition();
|
||||
}
|
||||
|
||||
return defPosition;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int RimDeckPositionDlg::selectedPosition() const
|
||||
{
|
||||
return m_selectedPosition;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::slotDialogOkClicked()
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::slotDialogCancelClicked()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::slotMoveUpClicked()
|
||||
{
|
||||
auto item = m_list->takeItem( m_selectedPosition );
|
||||
m_selectedPosition--;
|
||||
if ( m_selectedPosition < 0 ) m_selectedPosition = 0;
|
||||
m_list->insertItem( m_selectedPosition, item );
|
||||
m_list->setCurrentRow( m_selectedPosition );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::slotMoveDownClicked()
|
||||
{
|
||||
auto item = m_list->takeItem( m_selectedPosition );
|
||||
m_selectedPosition++;
|
||||
if ( m_selectedPosition >= m_list->count() ) m_selectedPosition = m_list->count() - 1;
|
||||
m_list->insertItem( m_selectedPosition, item );
|
||||
m_list->setCurrentRow( m_selectedPosition );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::addItems( std::vector<std::pair<int, QString>> items )
|
||||
{
|
||||
m_list->clear();
|
||||
|
||||
for ( auto& [index, name] : items )
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem( name, m_list );
|
||||
item->setData( Qt::UserRole, index );
|
||||
if ( m_selectedPosition < 0 )
|
||||
{
|
||||
if ( name == "WCONPROD" )
|
||||
{
|
||||
m_selectedPosition = index + 1;
|
||||
}
|
||||
else if ( name == "DATES" )
|
||||
{
|
||||
m_selectedPosition = index - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_selectedPosition < 0 )
|
||||
{
|
||||
m_selectedPosition = (int)items.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimDeckPositionDlg::addNewItem( QString text, int defPosition )
|
||||
{
|
||||
if ( defPosition >= 0 ) m_selectedPosition = defPosition;
|
||||
m_list->insertItem( m_selectedPosition, text );
|
||||
m_list->setCurrentRow( m_selectedPosition );
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class QListWidget;
|
||||
class QDialogButtonBox;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimDeckPositionDlg : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RimDeckPositionDlg( QWidget* parent );
|
||||
~RimDeckPositionDlg() override;
|
||||
|
||||
static int askForPosition( QWidget* parent, std::vector<std::pair<int, QString>> items, QString newItemName, int defPosition );
|
||||
|
||||
private:
|
||||
void addItems( std::vector<std::pair<int, QString>> items );
|
||||
void addNewItem( QString name, int defPosition );
|
||||
int selectedPosition() const;
|
||||
|
||||
private slots:
|
||||
void slotDialogOkClicked();
|
||||
void slotDialogCancelClicked();
|
||||
void slotMoveUpClicked();
|
||||
void slotMoveDownClicked();
|
||||
|
||||
private:
|
||||
QListWidget* m_list;
|
||||
QDialogButtonBox* m_buttons;
|
||||
int m_selectedPosition;
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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 "RimGenericJob.h"
|
||||
|
||||
#include "RimProcess.h"
|
||||
|
||||
#include "cafCmdFeatureMenuBuilder.h"
|
||||
#include "cafProgressInfo.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimGenericJob, "GenericJob" ); // Do not use. Abstract class
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimGenericJob::RimGenericJob()
|
||||
{
|
||||
CAF_PDM_InitObject( "Generic Job" );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimGenericJob::~RimGenericJob()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimGenericJob::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
|
||||
{
|
||||
menuBuilder << "RicRunJobFeature";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimGenericJob::workingDirectory() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimGenericJob::execute()
|
||||
{
|
||||
if ( !onPrepare() ) return false;
|
||||
|
||||
bool runOk = false;
|
||||
{
|
||||
caf::ProgressInfo runProgress( 1, title() );
|
||||
|
||||
auto taskRun = runProgress.task( "Running job, please wait..." );
|
||||
|
||||
QStringList cmdLine = command();
|
||||
if ( cmdLine.isEmpty() ) return false;
|
||||
|
||||
QString cmd = cmdLine.takeFirst();
|
||||
|
||||
RimProcess process;
|
||||
process.setCommand( cmd );
|
||||
if ( !cmdLine.isEmpty() ) process.addParameters( cmdLine );
|
||||
process.setWorkingDirectory( workingDirectory() );
|
||||
|
||||
runOk = process.execute();
|
||||
}
|
||||
|
||||
onCompleted( runOk );
|
||||
|
||||
if ( !runOk )
|
||||
{
|
||||
QMessageBox::critical( nullptr, title(), "Failed to run job. Check log window for additional information." );
|
||||
}
|
||||
return runOk;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimNamedObject.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimGenericJob : public RimNamedObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimGenericJob();
|
||||
~RimGenericJob() override;
|
||||
|
||||
bool execute();
|
||||
|
||||
protected:
|
||||
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
|
||||
|
||||
virtual QString title() = 0;
|
||||
virtual QStringList command() = 0;
|
||||
virtual QString workingDirectory() const;
|
||||
virtual bool onPrepare() = 0;
|
||||
virtual void onCompleted( bool success ) = 0;
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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 "RimJobCollection.h"
|
||||
|
||||
#include "RiaLogging.h"
|
||||
|
||||
#include "Rim3dView.h"
|
||||
#include "RimGenericJob.h"
|
||||
#include "RimGridView.h"
|
||||
#include "RimProject.h"
|
||||
|
||||
#include "cafCmdFeatureMenuBuilder.h"
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimJobCollection, "JobCollection" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimJobCollection::RimJobCollection()
|
||||
{
|
||||
CAF_PDM_InitObject( "Jobs", ":/gear.svg" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_jobs, "Jobs", "Jobs" );
|
||||
|
||||
setCustomContextMenuEnabled( true );
|
||||
setDeletable( false );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimJobCollection::~RimJobCollection()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<RimGenericJob*> RimJobCollection::jobs() const
|
||||
{
|
||||
return m_jobs.childrenByType();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimJobCollection::isEmpty()
|
||||
{
|
||||
return !m_jobs.hasChildren();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimJobCollection::addNewJob( RimGenericJob* newJob )
|
||||
{
|
||||
m_jobs.push_back( newJob );
|
||||
updateAllRequiredEditors();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimJobCollection::deleteAllJobs()
|
||||
{
|
||||
m_jobs.deleteChildren();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimJobCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
|
||||
{
|
||||
menuBuilder << "RicNewOpmFlowJobFeature";
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
|
||||
#include "cafPdmField.h"
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class RimGenericJob;
|
||||
|
||||
class RimJobCollection : public caf::PdmObject
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimJobCollection();
|
||||
~RimJobCollection() override;
|
||||
|
||||
void addNewJob( RimGenericJob* newJob );
|
||||
|
||||
bool isEmpty();
|
||||
|
||||
void deleteAllJobs();
|
||||
|
||||
std::vector<RimGenericJob*> jobs() const;
|
||||
|
||||
protected:
|
||||
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
|
||||
|
||||
private:
|
||||
caf::PdmChildArrayField<RimGenericJob*> m_jobs;
|
||||
};
|
||||
@@ -0,0 +1,924 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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 "RimOpmFlowJob.h"
|
||||
|
||||
#include "RiaImportEclipseCaseTools.h"
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaPreferencesOpm.h"
|
||||
#include "RiaWslTools.h"
|
||||
|
||||
#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h"
|
||||
#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h"
|
||||
#include "EclipseCommands/RicCreateGridCaseEnsemblesFromFilesFeature.h"
|
||||
#include "JobCommands/RicRunJobFeature.h"
|
||||
#include "RifOpmFlowDeckFile.h"
|
||||
|
||||
#include "Ensemble/RimSummaryFileSetEnsemble.h"
|
||||
#include "EnsembleFileSet/RimEnsembleFileSet.h"
|
||||
#include "EnsembleFileSet/RimEnsembleFileSetTools.h"
|
||||
#include "RimCase.h"
|
||||
#include "RimDeckPositionDlg.h"
|
||||
#include "RimEclipseCase.h"
|
||||
#include "RimEclipseCaseCollection.h"
|
||||
#include "RimEclipseCaseEnsemble.h"
|
||||
#include "RimFishbones.h"
|
||||
#include "RimOilField.h"
|
||||
#include "RimPerforationInterval.h"
|
||||
#include "RimProject.h"
|
||||
#include "RimReloadCaseTools.h"
|
||||
#include "RimSummaryEnsemble.h"
|
||||
#include "RimTools.h"
|
||||
#include "RimWellPath.h"
|
||||
#include "RimWellPathCompletionSettings.h"
|
||||
#include "RimWellPathFracture.h"
|
||||
|
||||
#include "Riu3DMainWindowTools.h"
|
||||
|
||||
#include "cafPdmUiCheckBoxEditor.h"
|
||||
#include "cafPdmUiComboBoxEditor.h"
|
||||
#include "cafPdmUiFilePathEditor.h"
|
||||
#include "cafPdmUiPushButtonEditor.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
|
||||
CAF_PDM_SOURCE_INIT( RimOpmFlowJob, "OpmFlowJob" );
|
||||
|
||||
namespace caf
|
||||
{
|
||||
template <>
|
||||
void caf::AppEnum<RimOpmFlowJob::WellOpenType>::setUp()
|
||||
{
|
||||
addItem( RimOpmFlowJob::WellOpenType::OPEN_BY_POSITION, "OpenByPosition", "Select Keyword Position in File" );
|
||||
addItem( RimOpmFlowJob::WellOpenType::OPEN_AT_DATE, "AtSelectedDate", "Select a Date" );
|
||||
|
||||
setDefault( RimOpmFlowJob::WellOpenType::OPEN_AT_DATE );
|
||||
}
|
||||
} // namespace caf
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimOpmFlowJob::RimOpmFlowJob()
|
||||
: m_fileDeckHasDates( false )
|
||||
{
|
||||
CAF_PDM_InitObject( "Opm Flow Simulation", ":/opm.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_deckFileName, "DeckFile", "Input Data File" );
|
||||
m_deckFileName.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_workDir, "WorkDirectory", "Working Folder" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_wellPath, "WellPath", "Well Path for New Well" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_eclipseCase, "EclipseCase", "Eclipse Case" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_gridEnsemble, "GridEnsemble", "Grid Ensemble" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_summaryEnsemble, "SummaryEnsemble", "Summary Ensemble" );
|
||||
|
||||
CAF_PDM_InitField( &m_pauseBeforeRun, "PauseBeforeRun", false, "Pause before running OPM Flow" );
|
||||
CAF_PDM_InitField( &m_addNewWell, "AddNewWell", true, "Add New Well" );
|
||||
CAF_PDM_InitField( &m_openWellDeckPosition, "OpenWellDeckPosition", -1, "Open Well at Keyword Index" );
|
||||
CAF_PDM_InitField( &m_includeMSWData, "IncludeMswData", false, "Add MSW Data" );
|
||||
CAF_PDM_InitField( &m_addToEnsemble, "AddToEnsemble", false, "Add Runs to Ensemble" );
|
||||
CAF_PDM_InitField( &m_useRestart, "UseRestart", false, "Restart Simulation at Well Open Date" );
|
||||
CAF_PDM_InitField( &m_currentRunId, "CurrentRunID", 0, "Current Run ID" );
|
||||
|
||||
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_addToEnsemble );
|
||||
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_pauseBeforeRun );
|
||||
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_useRestart );
|
||||
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_includeMSWData );
|
||||
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_addNewWell );
|
||||
|
||||
CAF_PDM_InitField( &m_wellOpenType, "WellOpenType", caf::AppEnum<WellOpenType>( WellOpenType::OPEN_AT_DATE ), "Open Well" );
|
||||
CAF_PDM_InitField( &m_wellOpenKeyword, "WellOpenKeyword", QString( "WCONPROD" ), "Open Well Keyword" );
|
||||
m_wellOpenKeyword.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
|
||||
m_wellOpenKeyword.xmlCapability()->disableIO();
|
||||
|
||||
CAF_PDM_InitField( &m_wellOpenText, "WellOpenText", QString( "'GRUP' 5000 4* 100 20 5" ), "Open Well Parameters" );
|
||||
|
||||
CAF_PDM_InitField( &m_openTimeStep, "OpenTimeStep", 0, " " );
|
||||
|
||||
CAF_PDM_InitField( &m_runButton, "runButton", false, "" );
|
||||
caf::PdmUiPushButtonEditor::configureEditorLabelHidden( &m_runButton );
|
||||
m_runButton.xmlCapability()->disableIO();
|
||||
|
||||
CAF_PDM_InitField( &m_resetRunIdButton, "resetRunIdButton", false, " " );
|
||||
caf::PdmUiPushButtonEditor::configureEditorLabelLeft( &m_resetRunIdButton );
|
||||
m_resetRunIdButton.xmlCapability()->disableIO();
|
||||
|
||||
CAF_PDM_InitField( &m_openSelectButton, "openSelectButton", false, " " );
|
||||
caf::PdmUiPushButtonEditor::configureEditorLabelLeft( &m_openSelectButton );
|
||||
m_openSelectButton.xmlCapability()->disableIO();
|
||||
|
||||
setDeletable( true );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimOpmFlowJob::~RimOpmFlowJob()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::initAfterRead()
|
||||
{
|
||||
openDeckFile();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
||||
{
|
||||
if ( field == &m_workDir )
|
||||
{
|
||||
if ( auto myAttr = dynamic_cast<caf::PdmUiFilePathEditorAttribute*>( attribute ) )
|
||||
{
|
||||
myAttr->m_selectDirectory = true;
|
||||
}
|
||||
}
|
||||
else if ( field == &m_runButton )
|
||||
{
|
||||
auto* pbAttribute = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
|
||||
if ( pbAttribute )
|
||||
{
|
||||
pbAttribute->m_buttonText = "Run Simulation";
|
||||
pbAttribute->m_buttonIcon = QIcon( ":/opm.png" );
|
||||
}
|
||||
}
|
||||
else if ( field == &m_openSelectButton )
|
||||
{
|
||||
auto* pbAttribute = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
|
||||
if ( pbAttribute )
|
||||
{
|
||||
pbAttribute->m_buttonText = "Select Open Keyword Position";
|
||||
}
|
||||
}
|
||||
else if ( field == &m_resetRunIdButton )
|
||||
{
|
||||
auto* pbAttribute = dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute );
|
||||
if ( pbAttribute )
|
||||
{
|
||||
pbAttribute->m_buttonText = "Reset Ensemble Run Id";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||
{
|
||||
auto genGrp = uiOrdering.addNewGroup( "General" );
|
||||
genGrp->add( nameField() );
|
||||
genGrp->add( &m_deckFileName );
|
||||
genGrp->add( &m_workDir );
|
||||
genGrp->add( &m_addNewWell );
|
||||
|
||||
if ( m_addNewWell() )
|
||||
{
|
||||
auto wellGrp = uiOrdering.addNewGroup( "New Well Settings" );
|
||||
|
||||
wellGrp->add( &m_wellPath );
|
||||
wellGrp->add( &m_wellOpenKeyword );
|
||||
wellGrp->add( &m_wellOpenText );
|
||||
|
||||
wellGrp->add( &m_wellOpenType );
|
||||
|
||||
if ( m_fileDeckHasDates )
|
||||
{
|
||||
if ( m_wellOpenType() == WellOpenType::OPEN_AT_DATE )
|
||||
{
|
||||
wellGrp->add( &m_openTimeStep );
|
||||
wellGrp->add( &m_useRestart );
|
||||
if ( !m_useRestart() )
|
||||
{
|
||||
wellGrp->add( &m_includeMSWData );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_includeMSWData = false;
|
||||
}
|
||||
}
|
||||
else if ( m_wellOpenType == WellOpenType::OPEN_BY_POSITION )
|
||||
{
|
||||
wellGrp->add( &m_openSelectButton );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wellGrp->add( &m_openSelectButton );
|
||||
}
|
||||
}
|
||||
|
||||
auto opmGrp = uiOrdering.addNewGroup( "Opm Flow" );
|
||||
opmGrp->add( &m_runButton );
|
||||
opmGrp->add( &m_pauseBeforeRun );
|
||||
opmGrp->add( &m_addToEnsemble );
|
||||
if ( m_addToEnsemble() )
|
||||
{
|
||||
auto advOpmGrp = opmGrp->addNewGroup( "Advanced" );
|
||||
advOpmGrp->setCollapsedByDefault();
|
||||
advOpmGrp->add( &m_resetRunIdButton );
|
||||
}
|
||||
|
||||
uiOrdering.skipRemainingFields();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QList<caf::PdmOptionItemInfo> RimOpmFlowJob::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||
{
|
||||
QList<caf::PdmOptionItemInfo> options;
|
||||
|
||||
if ( fieldNeedingOptions == &m_wellPath )
|
||||
{
|
||||
RimTools::wellPathOptionItems( &options );
|
||||
}
|
||||
else if ( fieldNeedingOptions == &m_openTimeStep )
|
||||
{
|
||||
if ( auto ec = m_eclipseCase() )
|
||||
{
|
||||
RimTools::timeStepsForCase( ec, &options );
|
||||
}
|
||||
}
|
||||
else if ( fieldNeedingOptions == &m_wellOpenKeyword )
|
||||
{
|
||||
options.push_back( caf::PdmOptionItemInfo( "WCONPROD", QVariant::fromValue( QString( "WCONPROD" ) ) ) );
|
||||
options.push_back( caf::PdmOptionItemInfo( "WCONINJE", QVariant::fromValue( QString( "WCONINJE" ) ) ) );
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||
{
|
||||
if ( ( changedField == &m_deckFileName ) || ( changedField == &m_addToEnsemble ) )
|
||||
{
|
||||
m_deckName = "";
|
||||
}
|
||||
else if ( changedField == &m_runButton )
|
||||
{
|
||||
m_runButton = false;
|
||||
RicRunJobFeature::runJob( this );
|
||||
}
|
||||
else if ( changedField == &m_resetRunIdButton )
|
||||
{
|
||||
m_resetRunIdButton = false;
|
||||
auto reply = QMessageBox::information( nullptr,
|
||||
"Opm Flow Job",
|
||||
"Do you want to reset the ensemble run ID to 0?",
|
||||
QMessageBox::Yes | QMessageBox::No );
|
||||
if ( reply == QMessageBox::Yes )
|
||||
{
|
||||
m_currentRunId = 0;
|
||||
}
|
||||
}
|
||||
else if ( changedField == &m_wellOpenKeyword )
|
||||
{
|
||||
if ( newValue.toString() == "WCONPROD" )
|
||||
{
|
||||
m_wellOpenText.setValueWithFieldChanged( "'GRUP' 5000 4* 100 20 5" );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_wellOpenText.setValueWithFieldChanged( "'GRUP' 6500 1* 350" );
|
||||
}
|
||||
}
|
||||
else if ( changedField == &m_openSelectButton )
|
||||
{
|
||||
m_openSelectButton = false;
|
||||
selectOpenWellPosition();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::setWorkingDirectory( QString workDir )
|
||||
{
|
||||
m_workDir = workDir;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::setEclipseCase( RimEclipseCase* eCase )
|
||||
{
|
||||
m_deckName = "";
|
||||
if ( eCase == nullptr )
|
||||
{
|
||||
m_deckFileName.setValue( QString() );
|
||||
return;
|
||||
}
|
||||
|
||||
QFileInfo fi( eCase->gridFileName() );
|
||||
m_deckFileName.setValue( fi.absolutePath() + "/" + fi.completeBaseName() + deckExtension() );
|
||||
m_eclipseCase = eCase;
|
||||
m_deckFile.reset();
|
||||
openDeckFile();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::setInputDataFile( QString filename )
|
||||
{
|
||||
m_deckName = "";
|
||||
m_deckFileName.setValue( filename );
|
||||
m_deckFile.reset();
|
||||
openDeckFile();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimOpmFlowJob::openDeckFile()
|
||||
{
|
||||
if ( m_deckFile == nullptr )
|
||||
{
|
||||
m_deckFile = std::make_unique<RifOpmFlowDeckFile>();
|
||||
bool deckLoadOk = false;
|
||||
try
|
||||
{
|
||||
deckLoadOk = m_deckFile->loadDeck( m_deckFileName().path().toStdString() );
|
||||
}
|
||||
catch ( std::filesystem::filesystem_error& )
|
||||
{
|
||||
RiaLogging::error( QString( "Failed to open %1, possibly unsupported or incorrect format." ).arg( m_deckFileName().path() ) );
|
||||
}
|
||||
|
||||
if ( deckLoadOk )
|
||||
{
|
||||
m_fileDeckHasDates = m_deckFile->hasDatesKeyword();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fileDeckHasDates = false;
|
||||
m_deckFile.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return m_deckFile != nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimOpmFlowJob::copyUnrstFileToWorkDir()
|
||||
{
|
||||
QFileInfo fi( m_deckFileName().path() );
|
||||
|
||||
QString unrstName = fi.absolutePath() + "/" + fi.baseName() + ".UNRST";
|
||||
if ( QFile::exists( unrstName ) )
|
||||
{
|
||||
QString dstName = workingDirectory() + "/" + restartDeckName() + ".UNRST";
|
||||
if ( dstName != unrstName )
|
||||
{
|
||||
QFile::copy( unrstName, dstName );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::title()
|
||||
{
|
||||
return name();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::workingDirectory() const
|
||||
{
|
||||
if ( !m_addToEnsemble() )
|
||||
{
|
||||
return m_workDir().path();
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString( "%1/run-%2" ).arg( m_workDir().path() ).arg( m_currentRunId() );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::deckName()
|
||||
{
|
||||
if ( m_deckName.isEmpty() )
|
||||
{
|
||||
m_deckName = baseDeckName();
|
||||
if ( m_addToEnsemble() )
|
||||
{
|
||||
m_deckName = m_deckName + "-" + QString::number( m_currentRunId() );
|
||||
}
|
||||
}
|
||||
|
||||
return m_deckName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::baseDeckName() const
|
||||
{
|
||||
QFileInfo fi( m_deckFileName().path() );
|
||||
return fi.completeBaseName();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::restartDeckName() const
|
||||
{
|
||||
return baseDeckName() + "_RST";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::deckExtension() const
|
||||
{
|
||||
return ".DATA";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::wellTempFile( int timeStep, bool includeMSW, bool includeLGR ) const
|
||||
{
|
||||
QString postfix = "";
|
||||
if ( timeStep >= 0 )
|
||||
{
|
||||
postfix = QString( "_%1" ).arg( timeStep );
|
||||
}
|
||||
if ( includeLGR )
|
||||
{
|
||||
postfix = postfix + "_LGR";
|
||||
}
|
||||
if ( includeMSW )
|
||||
{
|
||||
postfix = postfix + "_MSW";
|
||||
}
|
||||
|
||||
return workingDirectory() + "/ri_new_well" + postfix + deckExtension();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::openWellTempFile() const
|
||||
{
|
||||
return workingDirectory() + "/ri_open_well" + deckExtension();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RimOpmFlowJob::command()
|
||||
{
|
||||
QStringList cmd;
|
||||
|
||||
QString workDir = workingDirectory();
|
||||
if ( workDir.isEmpty() ) return cmd;
|
||||
|
||||
QString dataFile = workDir + "/" + deckName();
|
||||
if ( !QFile::exists( dataFile + deckExtension() ) ) return cmd;
|
||||
|
||||
auto opmPref = RiaPreferencesOpm::current();
|
||||
if ( opmPref->useWsl() )
|
||||
{
|
||||
cmd.append( RiaWslTools::wslCommand() );
|
||||
cmd.append( opmPref->wslOptions() );
|
||||
|
||||
workDir = RiaWslTools::convertToWslPath( workDir );
|
||||
dataFile = RiaWslTools::convertToWslPath( dataFile );
|
||||
}
|
||||
|
||||
if ( opmPref->useMpi() )
|
||||
{
|
||||
cmd.append( "/usr/bin/mpirun" );
|
||||
cmd.append( QString( "-np" ) );
|
||||
cmd.append( QString( "%1" ).arg( opmPref->mpiProcesses() ) );
|
||||
}
|
||||
|
||||
cmd.append( opmPref->opmFlowCommand() );
|
||||
cmd.append( QString( "--output-dir=%1" ).arg( workDir ) );
|
||||
cmd.append( QString( "--ecl-deck-file-name=%1" ).arg( dataFile ) );
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimOpmFlowJob::onPrepare()
|
||||
{
|
||||
// reload file deck to make sure we start with the original
|
||||
m_deckFile.reset();
|
||||
if ( !openDeckFile() )
|
||||
{
|
||||
RiaLogging::error( "Unable to open input DATA file " + m_deckFileName().path() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// add a new well?
|
||||
if ( m_addNewWell() )
|
||||
{
|
||||
if ( m_wellPath == nullptr )
|
||||
{
|
||||
RiaLogging::error( "Please select a well path to use." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_wellPath->completionSettings()->wellName().isEmpty() )
|
||||
{
|
||||
RiaLogging::error( "Selected Well Path does not have a WELL NAME set, please check the completion settings." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_wellPath->completionSettings()->groupName().isEmpty() )
|
||||
{
|
||||
RiaLogging::error( "Selected Well Path does not have a GROUP NAME set, please check the completion settings." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_includeMSWData && m_wellOpenType == WellOpenType::OPEN_AT_DATE )
|
||||
{
|
||||
if ( m_eclipseCase() )
|
||||
{
|
||||
std::vector<std::string> mswData;
|
||||
int i = 0;
|
||||
for ( auto& date : m_eclipseCase->timeStepDates() )
|
||||
{
|
||||
mswData.push_back( exportMswWellSettings( date, i++ ) );
|
||||
}
|
||||
|
||||
if ( !m_deckFile->mergeMswData( mswData ) )
|
||||
{
|
||||
RiaLogging::error( "Failed to merge MSW data into file deck." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// export new well settings from resinsight
|
||||
exportBasicWellSettings();
|
||||
if ( !QFile::exists( wellTempFile() ) )
|
||||
{
|
||||
RiaLogging::error( "Could not find exported well data from ResInsight: " + wellTempFile() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// merge new well settings from resinsight into DATA deck
|
||||
if ( !m_deckFile->mergeWellDeck( m_openTimeStep(), wellTempFile().toStdString() ) )
|
||||
{
|
||||
RiaLogging::error( "Unable to merge new well data into DATA file. Are there WELSPECS and COMPDAT keywords?" );
|
||||
return false;
|
||||
}
|
||||
QFile::remove( wellTempFile() );
|
||||
}
|
||||
|
||||
QString openWellText = generateBasicOpenWellText();
|
||||
|
||||
// open new well at selected timestep
|
||||
if ( m_fileDeckHasDates && m_wellOpenType == WellOpenType::OPEN_AT_DATE )
|
||||
{
|
||||
if ( !m_deckFile->openWellAtTimeStep( m_openTimeStep(), openWellText.toStdString() ) )
|
||||
{
|
||||
RiaLogging::error( "Unable to open new well in DATA file." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_useRestart() )
|
||||
{
|
||||
if ( !copyUnrstFileToWorkDir() )
|
||||
{
|
||||
RiaLogging::error( "Unable to locate UNRST file from input case." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !m_deckFile->restartAtTimeStep( std::max( m_openTimeStep() - 1, 0 ), restartDeckName().toStdString() ) )
|
||||
{
|
||||
RiaLogging::error( "Unable to insert restart keywords in DATA file." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_deckFile->openWellAtDeckPosition( m_openWellDeckPosition, openWellText.toStdString() ) )
|
||||
{
|
||||
RiaLogging::error( "Unable to open new well at selected position in DATA file." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save DATA file to working folder
|
||||
bool saveOk = m_deckFile->saveDeck( workingDirectory().toStdString(), deckName().toStdString() + deckExtension().toStdString() );
|
||||
m_deckFile.reset();
|
||||
|
||||
if ( m_pauseBeforeRun() )
|
||||
{
|
||||
QString infoText = "Input parameter files can now be found in the working folder:";
|
||||
infoText += " \"" + workingDirectory() + "\"\n";
|
||||
infoText += "\nClick OK to run the Opm Flow simulation.";
|
||||
|
||||
auto reply = QMessageBox::information( nullptr, "Opm Flow simulation", infoText, QMessageBox::Ok | QMessageBox::Cancel );
|
||||
|
||||
if ( reply != QMessageBox::Ok ) return false;
|
||||
}
|
||||
|
||||
return saveOk;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::onCompleted( bool success )
|
||||
{
|
||||
if ( !success ) return;
|
||||
|
||||
QString outputEgridFileName = workingDirectory() + "/" + deckName() + ".EGRID";
|
||||
if ( !QFile::exists( outputEgridFileName ) ) return;
|
||||
|
||||
if ( m_addToEnsemble() )
|
||||
{
|
||||
// grid ensemble
|
||||
if ( m_gridEnsemble() == nullptr )
|
||||
{
|
||||
m_gridEnsemble = RicCreateGridCaseEnsemblesFromFilesFeature::importSingleGridCaseEnsemble( QStringList( outputEgridFileName ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( auto rimResultCase = m_gridEnsemble->findByFileName( outputEgridFileName ) )
|
||||
{
|
||||
rimResultCase->reloadEclipseGridFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
rimResultCase = RicCreateGridCaseEnsemblesFromFilesFeature::importSingleGridCase( outputEgridFileName );
|
||||
m_gridEnsemble->addCase( rimResultCase );
|
||||
}
|
||||
|
||||
for ( auto gridCase : m_gridEnsemble->cases() )
|
||||
{
|
||||
gridCase->updateAutoShortName();
|
||||
}
|
||||
|
||||
RimProject::current()->activeOilField()->analysisModels()->updateConnectedEditors();
|
||||
}
|
||||
|
||||
// summary ensemble
|
||||
if ( m_summaryEnsemble() == nullptr )
|
||||
{
|
||||
QString pattern = m_workDir().path() + "/run-*/" + baseDeckName() + "-*";
|
||||
auto fileSet = RimEnsembleFileSetTools::createEnsembleFileSetFromOpm( pattern, name() );
|
||||
auto ensembles = RimEnsembleFileSetTools::createSummaryEnsemblesFromFileSets( { fileSet } );
|
||||
if ( ensembles.size() > 0 )
|
||||
{
|
||||
m_summaryEnsemble = ensembles[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_summaryEnsemble->reloadCases();
|
||||
}
|
||||
|
||||
m_currentRunId = m_currentRunId + 1;
|
||||
m_deckName = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( auto existingCase = findExistingCase( outputEgridFileName ) )
|
||||
{
|
||||
RimReloadCaseTools::reloadEclipseGridAndSummary( existingCase );
|
||||
existingCase->setCustomCaseName( name() );
|
||||
existingCase->updateConnectedEditors();
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList files( outputEgridFileName );
|
||||
|
||||
RiaImportEclipseCaseTools::FileCaseIdMap newCaseFiles;
|
||||
if ( RiaImportEclipseCaseTools::openEclipseCasesFromFile( files, true /*create view*/, &newCaseFiles, false /* dialog */ ) )
|
||||
{
|
||||
if ( auto newCase = findExistingCase( outputEgridFileName ) )
|
||||
{
|
||||
newCase->setCustomCaseName( name() );
|
||||
newCase->updateConnectedEditors();
|
||||
Riu3DMainWindowTools::selectAsCurrentItem( newCase );
|
||||
Riu3DMainWindowTools::setExpanded( newCase, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimEclipseCase* RimOpmFlowJob::findExistingCase( QString filename )
|
||||
{
|
||||
if ( RimProject* proj = RimProject::current() )
|
||||
{
|
||||
for ( RimCase* c : proj->allGridCases() )
|
||||
{
|
||||
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( c );
|
||||
if ( eclipseCase && ( eclipseCase->gridFileName() == filename ) )
|
||||
{
|
||||
return eclipseCase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::exportBasicWellSettings()
|
||||
{
|
||||
RicExportCompletionDataSettingsUi exportSettings;
|
||||
|
||||
exportSettings.fileSplit = RicExportCompletionDataSettingsUi::ExportSplit::UNIFIED_FILE;
|
||||
exportSettings.caseToApply = m_eclipseCase();
|
||||
exportSettings.setCustomFileName( wellTempFile() );
|
||||
exportSettings.includeMsw = false;
|
||||
exportSettings.setExportDataSourceAsComment( false );
|
||||
|
||||
exportSettings.folder = workingDirectory();
|
||||
|
||||
std::vector<RimWellPathFracture*> wellPathFractures;
|
||||
std::vector<RimFishbones*> wellPathFishbones;
|
||||
std::vector<RimPerforationInterval*> wellPathPerforations;
|
||||
|
||||
auto topLevelWell = m_wellPath->topLevelWellPath();
|
||||
|
||||
std::set<RimWellPath*> uniquePaths;
|
||||
for ( auto w : topLevelWell->allWellPathLaterals() )
|
||||
{
|
||||
uniquePaths.insert( w );
|
||||
}
|
||||
|
||||
for ( auto w : uniquePaths )
|
||||
{
|
||||
auto fractures = w->descendantsIncludingThisOfType<RimWellPathFracture>();
|
||||
wellPathFractures.insert( wellPathFractures.end(), fractures.begin(), fractures.end() );
|
||||
|
||||
auto fishbones = w->descendantsIncludingThisOfType<RimFishbones>();
|
||||
wellPathFishbones.insert( wellPathFishbones.end(), fishbones.begin(), fishbones.end() );
|
||||
|
||||
auto perforations = w->descendantsIncludingThisOfType<RimPerforationInterval>();
|
||||
wellPathPerforations.insert( wellPathPerforations.end(), perforations.begin(), perforations.end() );
|
||||
}
|
||||
|
||||
RicWellPathExportCompletionDataFeatureImpl::exportCompletions( { topLevelWell }, exportSettings );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string RimOpmFlowJob::exportMswWellSettings( QDateTime date, int timeStep )
|
||||
{
|
||||
RicExportCompletionDataSettingsUi exportSettings;
|
||||
|
||||
QString customName = wellTempFile( timeStep );
|
||||
QString customMswName = wellTempFile( timeStep, true /*include msw*/ );
|
||||
|
||||
// this file is not used, but the export generates the file anyways, so we need to remove it
|
||||
QString customMswLgrName = wellTempFile( timeStep, true /*include msw*/, true /*include LGR*/ );
|
||||
|
||||
exportSettings.fileSplit = RicExportCompletionDataSettingsUi::ExportSplit::UNIFIED_FILE;
|
||||
exportSettings.caseToApply = m_eclipseCase();
|
||||
exportSettings.setCustomFileName( customName );
|
||||
exportSettings.includeMsw = true;
|
||||
exportSettings.setExportDataSourceAsComment( false );
|
||||
exportSettings.timeStep = timeStep;
|
||||
|
||||
exportSettings.folder = workingDirectory();
|
||||
|
||||
std::vector<RimWellPathFracture*> wellPathFractures;
|
||||
std::vector<RimFishbones*> wellPathFishbones;
|
||||
std::vector<RimPerforationInterval*> wellPathPerforations;
|
||||
|
||||
auto topLevelWell = m_wellPath->topLevelWellPath();
|
||||
|
||||
std::set<RimWellPath*> uniquePaths;
|
||||
for ( auto w : topLevelWell->allWellPathLaterals() )
|
||||
{
|
||||
uniquePaths.insert( w );
|
||||
}
|
||||
|
||||
for ( auto w : uniquePaths )
|
||||
{
|
||||
auto fractures = w->descendantsIncludingThisOfType<RimWellPathFracture>();
|
||||
wellPathFractures.insert( wellPathFractures.end(), fractures.begin(), fractures.end() );
|
||||
|
||||
auto fishbones = w->descendantsIncludingThisOfType<RimFishbones>();
|
||||
wellPathFishbones.insert( wellPathFishbones.end(), fishbones.begin(), fishbones.end() );
|
||||
|
||||
auto perforations = w->descendantsIncludingThisOfType<RimPerforationInterval>();
|
||||
wellPathPerforations.insert( wellPathPerforations.end(), perforations.begin(), perforations.end() );
|
||||
}
|
||||
|
||||
RicWellPathExportCompletionDataFeatureImpl::exportCompletions( { topLevelWell }, exportSettings );
|
||||
|
||||
QString fileContent = readFileContent( customName );
|
||||
fileContent += readFileContent( customMswName );
|
||||
|
||||
QFile::remove( customName );
|
||||
QFile::remove( customMswName );
|
||||
QFile::remove( customMswLgrName );
|
||||
|
||||
return fileContent.toStdString();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::generateBasicOpenWellText()
|
||||
{
|
||||
auto cs = m_wellPath->completionSettings();
|
||||
|
||||
QString wellText = m_wellOpenKeyword() + "\n";
|
||||
|
||||
if ( m_wellOpenKeyword() == "WCONPROD" )
|
||||
{
|
||||
wellText += QString( "'%1' 'OPEN' %2 /\n" ).arg( cs->wellNameForExport() ).arg( m_wellOpenText );
|
||||
}
|
||||
else if ( m_wellOpenKeyword() == "WCONINJE" )
|
||||
{
|
||||
wellText += QString( "'%1' 'WATER' 'OPEN' %2 /\n" ).arg( cs->wellNameForExport() ).arg( m_wellOpenText );
|
||||
}
|
||||
wellText += "/\n";
|
||||
|
||||
return wellText;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimOpmFlowJob::selectOpenWellPosition()
|
||||
{
|
||||
if ( !openDeckFile() ) return;
|
||||
|
||||
std::vector<std::pair<int, QString>> kwVec;
|
||||
|
||||
auto kws = m_deckFile->keywords();
|
||||
int i = 0;
|
||||
for ( auto& kw : kws )
|
||||
{
|
||||
kwVec.push_back( std::make_pair( i++, QString::fromStdString( kw ) ) );
|
||||
}
|
||||
|
||||
m_openWellDeckPosition = RimDeckPositionDlg::askForPosition( nullptr, kwVec, "--- Open New Well HERE ---", m_openWellDeckPosition );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimOpmFlowJob::readFileContent( QString filename )
|
||||
{
|
||||
QFile file( filename );
|
||||
if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
|
||||
{
|
||||
QTextStream in( &file );
|
||||
QString fileContent = in.readAll();
|
||||
file.close();
|
||||
return fileContent;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2025 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RimGenericJob.h"
|
||||
|
||||
#include "cafPdmPtrField.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class RimEclipseCase;
|
||||
class RimWellPath;
|
||||
class RifOpmFlowDeckFile;
|
||||
class RimEclipseCaseEnsemble;
|
||||
class RimSummaryEnsemble;
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
class RimOpmFlowJob : public RimGenericJob
|
||||
{
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
enum class WellOpenType
|
||||
{
|
||||
OPEN_BY_POSITION,
|
||||
OPEN_AT_DATE
|
||||
};
|
||||
|
||||
public:
|
||||
RimOpmFlowJob();
|
||||
~RimOpmFlowJob() override;
|
||||
|
||||
void setWorkingDirectory( QString workDir );
|
||||
void setEclipseCase( RimEclipseCase* eCase );
|
||||
void setInputDataFile( QString filename );
|
||||
|
||||
QString deckName();
|
||||
|
||||
protected:
|
||||
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
|
||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||
void initAfterRead() override;
|
||||
|
||||
QString title() override;
|
||||
QStringList command() override;
|
||||
QString workingDirectory() const override;
|
||||
bool onPrepare() override;
|
||||
void onCompleted( bool success ) override;
|
||||
|
||||
bool openDeckFile();
|
||||
bool copyUnrstFileToWorkDir();
|
||||
|
||||
private:
|
||||
RimEclipseCase* findExistingCase( QString filename );
|
||||
QString deckExtension() const;
|
||||
QString wellTempFile( int timeStep = -1, bool includeMSW = false, bool includeLGR = false ) const;
|
||||
QString openWellTempFile() const;
|
||||
QString baseDeckName() const;
|
||||
QString restartDeckName() const;
|
||||
|
||||
static QString readFileContent( QString filename );
|
||||
|
||||
void exportBasicWellSettings();
|
||||
std::string exportMswWellSettings( QDateTime date, int timeStep );
|
||||
QString generateBasicOpenWellText();
|
||||
void selectOpenWellPosition();
|
||||
|
||||
private:
|
||||
caf::PdmField<caf::FilePath> m_deckFileName;
|
||||
caf::PdmField<caf::FilePath> m_workDir;
|
||||
caf::PdmField<bool> m_runButton;
|
||||
caf::PdmField<bool> m_openSelectButton;
|
||||
caf::PdmField<int> m_openWellDeckPosition;
|
||||
|
||||
caf::PdmField<bool> m_pauseBeforeRun;
|
||||
caf::PdmField<bool> m_addToEnsemble;
|
||||
caf::PdmField<int> m_currentRunId;
|
||||
caf::PdmField<bool> m_resetRunIdButton;
|
||||
caf::PdmField<bool> m_useRestart;
|
||||
|
||||
caf::PdmPtrField<RimWellPath*> m_wellPath;
|
||||
caf::PdmPtrField<RimEclipseCase*> m_eclipseCase;
|
||||
caf::PdmPtrField<RimEclipseCaseEnsemble*> m_gridEnsemble;
|
||||
caf::PdmPtrField<RimSummaryEnsemble*> m_summaryEnsemble;
|
||||
caf::PdmField<int> m_openTimeStep;
|
||||
caf::PdmField<bool> m_addNewWell;
|
||||
caf::PdmField<caf::AppEnum<WellOpenType>> m_wellOpenType;
|
||||
caf::PdmField<bool> m_includeMSWData;
|
||||
|
||||
caf::PdmField<QString> m_wellOpenKeyword;
|
||||
caf::PdmField<QString> m_wellOpenText;
|
||||
|
||||
QString m_deckName;
|
||||
std::unique_ptr<RifOpmFlowDeckFile> m_deckFile;
|
||||
bool m_fileDeckHasDates;
|
||||
};
|
||||
@@ -34,16 +34,20 @@ int RimProcess::m_nextProcessId = 1;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimProcess::RimProcess()
|
||||
RimProcess::RimProcess( bool logStdOutErr /*true*/ )
|
||||
: m_enableLogging( logStdOutErr )
|
||||
{
|
||||
int defId = m_nextProcessId++;
|
||||
m_monitor = new RimProcessMonitor( defId );
|
||||
m_monitor = new RimProcessMonitor( defId, logStdOutErr );
|
||||
|
||||
CAF_PDM_InitObject( "ResInsight Process", ":/Erase.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_command, "Command", "Command" );
|
||||
m_command.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
CAF_PDM_InitField( &m_workDir, "WorkDir", QString(), "Working Directory" );
|
||||
m_command.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_description, "Description", "Description" );
|
||||
m_description.uiCapability()->setUiReadOnly( true );
|
||||
|
||||
@@ -124,6 +128,24 @@ QStringList RimProcess::parameters() const
|
||||
return m_arguments;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RimProcess::stdOut() const
|
||||
{
|
||||
if ( m_monitor ) return m_monitor->stdOut();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RimProcess::stdErr() const
|
||||
{
|
||||
if ( m_monitor ) return m_monitor->stdErr();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -137,10 +159,14 @@ int RimProcess::ID() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RimProcess::execute( bool enableStdOut, bool enableStdErr )
|
||||
{
|
||||
if ( !m_monitor ) return false;
|
||||
|
||||
QProcess* proc = new QProcess();
|
||||
QString cmd = commandLine();
|
||||
|
||||
RiaLogging::info( QString( "Start process %1: %2" ).arg( m_id ).arg( cmd ) );
|
||||
if ( m_enableLogging ) RiaLogging::info( QString( "Start process %1: %2" ).arg( m_id ).arg( cmd ) );
|
||||
|
||||
m_monitor->clearStdOutErr();
|
||||
|
||||
QObject::connect( proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), m_monitor, SLOT( finished( int, QProcess::ExitStatus ) ) );
|
||||
if ( enableStdOut ) QObject::connect( proc, SIGNAL( readyReadStandardOutput() ), m_monitor, SLOT( readyReadStandardOutput() ) );
|
||||
@@ -155,6 +181,10 @@ bool RimProcess::execute( bool enableStdOut, bool enableStdErr )
|
||||
env.insert( key, val );
|
||||
}
|
||||
proc->setProcessEnvironment( env );
|
||||
if ( !m_workDir().isEmpty() )
|
||||
{
|
||||
proc->setWorkingDirectory( m_workDir );
|
||||
}
|
||||
|
||||
proc->start( m_command, m_arguments );
|
||||
auto error = proc->errorString();
|
||||
@@ -256,3 +286,11 @@ void RimProcess::addEnvironmentVariable( QString name, QString value )
|
||||
{
|
||||
m_environmentVariables.push_back( std::make_pair( name, value ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcess::setWorkingDirectory( QString workDir )
|
||||
{
|
||||
m_workDir = workDir;
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmObject.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
@@ -34,7 +33,7 @@ class RimProcess : public caf::PdmObject
|
||||
CAF_PDM_HEADER_INIT;
|
||||
|
||||
public:
|
||||
RimProcess();
|
||||
RimProcess( bool logStdOutErr = true );
|
||||
~RimProcess() override;
|
||||
|
||||
void setDescription( QString desc );
|
||||
@@ -44,6 +43,8 @@ public:
|
||||
|
||||
void addEnvironmentVariable( QString name, QString value );
|
||||
|
||||
void setWorkingDirectory( QString directory );
|
||||
|
||||
QString commandLine() const;
|
||||
|
||||
QString command() const;
|
||||
@@ -52,6 +53,9 @@ public:
|
||||
|
||||
bool execute( bool enableStdOut = true, bool enableStdErr = true );
|
||||
|
||||
QStringList stdErr() const;
|
||||
QStringList stdOut() const;
|
||||
|
||||
protected:
|
||||
caf::PdmFieldHandle* userDescriptionField() override;
|
||||
|
||||
@@ -66,9 +70,11 @@ private:
|
||||
QStringList m_arguments;
|
||||
caf::PdmField<QString> m_description;
|
||||
caf::PdmField<int> m_id;
|
||||
caf::PdmField<QString> m_workDir;
|
||||
|
||||
std::vector<std::pair<QString, QString>> m_environmentVariables;
|
||||
|
||||
static int m_nextProcessId;
|
||||
RimProcessMonitor* m_monitor;
|
||||
bool m_enableLogging;
|
||||
};
|
||||
@@ -23,17 +23,27 @@
|
||||
#include <QProcess>
|
||||
#include <QtCore/QtCore>
|
||||
|
||||
RimProcessMonitor::RimProcessMonitor( int processId )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimProcessMonitor::RimProcessMonitor( int processId, bool logStdOutErr /*true*/ )
|
||||
: QObject( nullptr )
|
||||
, m_processId( processId )
|
||||
, m_logStdOutErr( logStdOutErr )
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QString RimProcessMonitor::addPrefix( QString message )
|
||||
{
|
||||
return QString( "Process %1: %2" ).arg( m_processId ).arg( message );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::error( QProcess::ProcessError error )
|
||||
{
|
||||
QString errorStr;
|
||||
@@ -64,8 +74,13 @@ void RimProcessMonitor::error( QProcess::ProcessError error )
|
||||
RiaLogging::error( addPrefix( errorStr ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::finished( int exitCode, QProcess::ExitStatus exitStatus )
|
||||
{
|
||||
if ( !m_logStdOutErr ) return;
|
||||
|
||||
QString finishStr;
|
||||
switch ( exitStatus )
|
||||
{
|
||||
@@ -77,10 +92,12 @@ void RimProcessMonitor::finished( int exitCode, QProcess::ExitStatus exitStatus
|
||||
finishStr = QString( "Crash exit, code %1" ).arg( exitCode );
|
||||
break;
|
||||
}
|
||||
|
||||
RiaLogging::debug( addPrefix( finishStr ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::readyReadStandardError()
|
||||
{
|
||||
QProcess* p = (QProcess*)sender();
|
||||
@@ -90,10 +107,17 @@ void RimProcessMonitor::readyReadStandardError()
|
||||
QString line = p->readLine();
|
||||
line = line.trimmed();
|
||||
if ( line.size() == 0 ) continue;
|
||||
RiaLogging::error( addPrefix( line ) );
|
||||
m_stdErr.append( line );
|
||||
if ( m_logStdOutErr )
|
||||
{
|
||||
RiaLogging::error( addPrefix( line ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::readyReadStandardOutput()
|
||||
{
|
||||
QProcess* p = (QProcess*)sender();
|
||||
@@ -103,11 +127,43 @@ void RimProcessMonitor::readyReadStandardOutput()
|
||||
QString line = p->readLine();
|
||||
line = line.trimmed();
|
||||
if ( line.size() == 0 ) continue;
|
||||
RiaLogging::info( addPrefix( line ) );
|
||||
m_stdOut.append( line );
|
||||
if ( m_logStdOutErr )
|
||||
{
|
||||
RiaLogging::info( addPrefix( line ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::started()
|
||||
{
|
||||
RiaLogging::debug( addPrefix( "Started" ) );
|
||||
if ( m_logStdOutErr ) RiaLogging::debug( addPrefix( "Started" ) );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void RimProcessMonitor::clearStdOutErr()
|
||||
{
|
||||
m_stdOut.clear();
|
||||
m_stdErr.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RimProcessMonitor::stdOut() const
|
||||
{
|
||||
return m_stdOut;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QStringList RimProcessMonitor::stdErr() const
|
||||
{
|
||||
return m_stdErr;
|
||||
}
|
||||
@@ -20,12 +20,19 @@
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class RimProcessMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RimProcessMonitor( int processId );
|
||||
explicit RimProcessMonitor( int processId, bool logStdOutErr = true );
|
||||
|
||||
void clearStdOutErr();
|
||||
QStringList stdOut() const;
|
||||
QStringList stdErr() const;
|
||||
|
||||
signals:
|
||||
|
||||
@@ -37,6 +44,9 @@ public slots:
|
||||
void started();
|
||||
|
||||
private:
|
||||
QString addPrefix( QString message );
|
||||
int m_processId;
|
||||
QString addPrefix( QString message );
|
||||
int m_processId;
|
||||
bool m_logStdOutErr;
|
||||
QStringList m_stdOut;
|
||||
QStringList m_stdErr;
|
||||
};
|
||||
@@ -332,7 +332,7 @@ void RimCase::updateAutoShortName()
|
||||
{
|
||||
QStringList filePaths;
|
||||
auto cases = caseCollection->cases();
|
||||
if ( !cases.empty() )
|
||||
if ( cases.size() > 1 )
|
||||
{
|
||||
for ( int i = 0; i < std::min( 4, static_cast<int>( cases.size() ) ); ++i )
|
||||
{
|
||||
|
||||
@@ -1144,6 +1144,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
|
||||
{
|
||||
menuBuilder << "RicCloseSourSimDataFeature";
|
||||
}
|
||||
menuBuilder << "RicNewOpmFlowJobFeature";
|
||||
}
|
||||
else if ( dynamic_cast<RimSummaryPlot*>( firstUiItem ) )
|
||||
{
|
||||
|
||||
@@ -115,6 +115,19 @@ RimEclipseCase* RimEclipseCaseEnsemble::findByDescription( const QString& caseDe
|
||||
return m_caseCollection->findByDescription( caseDescription );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimEclipseCase* RimEclipseCaseEnsemble::findByFileName( const QString& gridFileName ) const
|
||||
{
|
||||
for ( RimEclipseCase* rimReservoir : cases() )
|
||||
{
|
||||
if ( gridFileName == rimReservoir->gridFileName() ) return rimReservoir;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
bool contains( RimEclipseCase* reservoir ) const;
|
||||
|
||||
RimEclipseCase* findByDescription( const QString& description ) const;
|
||||
RimEclipseCase* findByFileName( const QString& gridFileName ) const;
|
||||
|
||||
std::vector<RimEclipseCase*> cases() const;
|
||||
std::set<RimEclipseCase*> casesInViews() const;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "ContourMap/RimEclipseContourMapViewCollection.h"
|
||||
#include "EnsembleFileSet/RimEnsembleFileSetCollection.h"
|
||||
#include "Formations/RimFormationNamesCollection.h"
|
||||
#include "Jobs/RimJobCollection.h"
|
||||
#include "PlotTemplates/RimPlotTemplateFolderItem.h"
|
||||
#include "Polygons/RimPolygonCollection.h"
|
||||
#include "QuickAccess/RimQuickAccessCollection.h"
|
||||
@@ -147,6 +148,8 @@ RimProject::RimProject()
|
||||
CAF_PDM_InitFieldNoDefault( &scriptCollection, "ScriptCollection", "Octave Scripts", ":/octave.png" );
|
||||
scriptCollection.xmlCapability()->disableIO();
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_jobCollection, "JobCollection", "Jobs", ":/gear.png" );
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_mainPlotCollection, "MainPlotCollection", "Plots" );
|
||||
CAF_PDM_InitFieldNoDefault( &m_pinnedFieldCollection, "PinnedFieldCollection", "PinnedFieldCollection" );
|
||||
|
||||
@@ -211,6 +214,7 @@ RimProject::RimProject()
|
||||
|
||||
m_mainPlotCollection = new RimMainPlotCollection();
|
||||
m_pinnedFieldCollection = new RimQuickAccessCollection();
|
||||
m_jobCollection = new RimJobCollection();
|
||||
|
||||
CAF_PDM_InitFieldNoDefault( &m_plotTemplateTopFolder, "PlotTemplateCollection", "Plot Templates" );
|
||||
m_plotTemplateTopFolder = new RimPlotTemplateFolderItem();
|
||||
@@ -253,6 +257,7 @@ void RimProject::close()
|
||||
m_mainPlotCollection()->deleteAllContainedObjects();
|
||||
}
|
||||
|
||||
m_jobCollection->deleteAllJobs();
|
||||
m_ensembleFileSetCollection()->deleteAllFileSets();
|
||||
oilFields.deleteChildren();
|
||||
oilFields.push_back( new RimOilField );
|
||||
@@ -356,6 +361,14 @@ RimQuickAccessCollection* RimProject::pinnedFieldCollection() const
|
||||
return m_pinnedFieldCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimJobCollection* RimProject::jobCollection() const
|
||||
{
|
||||
return m_jobCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -1490,6 +1503,7 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
|
||||
else if ( uiConfigName == "PlotWindow.Scripts" || uiConfigName == "MainWindow.Scripts" )
|
||||
{
|
||||
uiTreeOrdering.add( scriptCollection() );
|
||||
uiTreeOrdering.add( jobCollection() );
|
||||
}
|
||||
else if ( uiConfigName == "PlotWindow.Templates" )
|
||||
{
|
||||
|
||||
@@ -71,6 +71,7 @@ class RimPlotTemplateFolderItem;
|
||||
class RimGridCalculationCollection;
|
||||
class RimQuickAccessCollection;
|
||||
class RimAutomationSettings;
|
||||
class RimJobCollection;
|
||||
class RimEnsembleFileSetCollection;
|
||||
|
||||
namespace caf
|
||||
@@ -194,6 +195,7 @@ public:
|
||||
RimQuickAccessCollection* pinnedFieldCollection() const;
|
||||
RimAutomationSettings* automationSettings() const;
|
||||
RimEnsembleFileSetCollection* ensembleFileSetCollection() const;
|
||||
RimJobCollection* jobCollection() const;
|
||||
|
||||
protected:
|
||||
void initAfterRead() override;
|
||||
@@ -207,6 +209,7 @@ private:
|
||||
caf::PdmChildField<RimQuickAccessCollection*> m_pinnedFieldCollection;
|
||||
caf::PdmChildField<RimAutomationSettings*> m_automationSettings;
|
||||
caf::PdmChildField<RimEnsembleFileSetCollection*> m_ensembleFileSetCollection;
|
||||
caf::PdmChildField<RimJobCollection*> m_jobCollection;
|
||||
|
||||
caf::PdmField<QString> m_globalPathList;
|
||||
caf::PdmField<QString> m_projectFileVersionString;
|
||||
|
||||
@@ -582,6 +582,14 @@ RimSurfaceCollection* RimTools::surfaceCollection()
|
||||
return RimProject::current()->activeOilField()->surfaceCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
RimJobCollection* RimTools::jobCollection()
|
||||
{
|
||||
return RimProject::current()->jobCollection();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -43,6 +43,7 @@ class RimSurfaceCollection;
|
||||
class RimFaultInViewCollection;
|
||||
class RimPolygonCollection;
|
||||
class RimAutomationSettings;
|
||||
class RimJobCollection;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
@@ -78,6 +79,7 @@ public:
|
||||
static RimSurfaceCollection* surfaceCollection();
|
||||
static RimPolygonCollection* polygonCollection();
|
||||
static RimAutomationSettings* automationSettings();
|
||||
static RimJobCollection* jobCollection();
|
||||
|
||||
static void timeStepsForCase( RimCase* gridCase, QList<caf::PdmOptionItemInfo>* options );
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ RimEnsembleFileSet* RimSummaryFileSetEnsemble::ensembleFileSet()
|
||||
void RimSummaryFileSetEnsemble::setEnsembleFileSet( RimEnsembleFileSet* ensembleFileSet )
|
||||
{
|
||||
m_ensembleFileSet = ensembleFileSet;
|
||||
setGroupingMode( m_ensembleFileSet->groupingMode() );
|
||||
connectSignals();
|
||||
}
|
||||
|
||||
|
||||
@@ -1060,6 +1060,10 @@ QString RimSummaryEnsemble::ensembleDescription() const
|
||||
{
|
||||
txt += "The ensemble is grouped by the FMU file folder structure.\n";
|
||||
}
|
||||
else if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::RESINSIGHT_OPMFLOW_STRUCTURE )
|
||||
{
|
||||
txt += "The ensemble is grouped by the ResInsight Opm Flow file folder structure.\n";
|
||||
}
|
||||
|
||||
return txt;
|
||||
}
|
||||
@@ -1118,6 +1122,18 @@ std::pair<std::string, std::string> RimSummaryEnsemble::nameKeys() const
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( m_groupingMode() == RiaDefines::EnsembleGroupingMode::RESINSIGHT_OPMFLOW_STRUCTURE )
|
||||
{
|
||||
if ( !m_cases.empty() )
|
||||
{
|
||||
auto fileNames = RiaEnsembleNameTools::groupFilePathsOpm( { m_cases[0]->summaryHeaderFilename().toStdString() } );
|
||||
if ( !fileNames.empty() )
|
||||
{
|
||||
key1 = fileNames.begin()->first.first;
|
||||
key2 = fileNames.begin()->first.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { key1, key2 };
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user