2025-06-11 15:43:53 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// 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"
|
|
|
|
|
|
2026-01-21 19:11:41 +01:00
|
|
|
#include "RiaGuiApplication.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
#include "RiaImportEclipseCaseTools.h"
|
|
|
|
|
#include "RiaLogging.h"
|
|
|
|
|
#include "RiaPreferencesOpm.h"
|
|
|
|
|
#include "RiaWslTools.h"
|
|
|
|
|
|
|
|
|
|
#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h"
|
|
|
|
|
#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h"
|
2025-11-07 10:05:53 +01:00
|
|
|
#include "CompletionExportCommands/RicWellPathExportMswTableData.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
#include "EclipseCommands/RicCreateGridCaseEnsemblesFromFilesFeature.h"
|
|
|
|
|
#include "JobCommands/RicRunJobFeature.h"
|
2025-10-18 02:42:11 +02:00
|
|
|
#include "JobCommands/RicStopJobFeature.h"
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
#include "RifOpmFlowDeckFile.h"
|
|
|
|
|
|
2025-11-07 10:05:53 +01:00
|
|
|
#include "CompletionsMsw/RigMswTableData.h"
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
#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"
|
2025-10-24 11:10:25 +02:00
|
|
|
#include "RimKeywordFactory.h"
|
2025-10-02 14:52:19 +02:00
|
|
|
#include "RimKeywordWconinje.h"
|
|
|
|
|
#include "RimKeywordWconprod.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
#include "RimOilField.h"
|
2025-11-14 12:56:23 +01:00
|
|
|
#include "RimOpmFlowJobSettings.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
#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"
|
|
|
|
|
|
2025-10-21 18:36:24 +02:00
|
|
|
#include "cafPdmUiButton.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
#include "cafPdmUiCheckBoxEditor.h"
|
|
|
|
|
#include "cafPdmUiComboBoxEditor.h"
|
|
|
|
|
#include "cafPdmUiFilePathEditor.h"
|
|
|
|
|
#include "cafPdmUiPushButtonEditor.h"
|
2025-09-24 16:46:48 +02:00
|
|
|
#include "cafProgressInfo.h"
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-02 14:52:19 +02:00
|
|
|
#include "opm/input/eclipse/Deck/DeckKeyword.hpp"
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
|
|
CAF_PDM_SOURCE_INIT( RimOpmFlowJob, "OpmFlowJob" );
|
|
|
|
|
|
|
|
|
|
namespace caf
|
|
|
|
|
{
|
|
|
|
|
template <>
|
|
|
|
|
void caf::AppEnum<RimOpmFlowJob::WellOpenType>::setUp()
|
|
|
|
|
{
|
2025-10-03 00:51:02 +02:00
|
|
|
addItem( RimOpmFlowJob::WellOpenType::OPEN_BY_POSITION, "OpenByPosition", "By Position in File" );
|
|
|
|
|
addItem( RimOpmFlowJob::WellOpenType::OPEN_AT_DATE, "AtSelectedDate", "By Date" );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
setDefault( RimOpmFlowJob::WellOpenType::OPEN_AT_DATE );
|
|
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
void caf::AppEnum<RimOpmFlowJob::DateAppendType>::setUp()
|
|
|
|
|
{
|
|
|
|
|
addItem( RimOpmFlowJob::DateAppendType::ADD_DAYS, "AppendDays", "Day(s)" );
|
|
|
|
|
addItem( RimOpmFlowJob::DateAppendType::ADD_MONTHS, "AppendMonths", "Month(s)" );
|
|
|
|
|
|
|
|
|
|
setDefault( RimOpmFlowJob::DateAppendType::ADD_MONTHS );
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
} // namespace caf
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RimOpmFlowJob::RimOpmFlowJob()
|
|
|
|
|
: m_fileDeckHasDates( false )
|
2025-09-29 16:57:21 +02:00
|
|
|
, m_fileDeckIsRestart( false )
|
2025-10-18 02:42:11 +02:00
|
|
|
, m_startStepForProgress( -1 )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
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" );
|
2025-11-14 12:56:23 +01:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_eclipseCase, "EclipseCase", "Eclipse Case for Well Data", "", "Eclipse Case to use for Well Data" );
|
2025-06-11 15:43:53 +02:00
|
|
|
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" );
|
2025-11-28 16:43:51 +01:00
|
|
|
CAF_PDM_InitField( &m_includeMSWData, "IncludeMswData", false, "Include MSW Data" );
|
2025-06-11 15:43:53 +02:00
|
|
|
CAF_PDM_InitField( &m_addToEnsemble, "AddToEnsemble", false, "Add Runs to Ensemble" );
|
|
|
|
|
CAF_PDM_InitField( &m_useRestart, "UseRestart", false, "Restart Simulation at Well Open Date" );
|
2025-11-14 12:56:23 +01:00
|
|
|
CAF_PDM_InitField( &m_currentRunId, "CurrentRunID", 0, "Current Ensemble Run ID" );
|
|
|
|
|
m_currentRunId.uiCapability()->setUiReadOnly( true );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-03 00:51:02 +02:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_wellGroupName, "WellGroupName", "Well Group Name" );
|
|
|
|
|
m_wellGroupName.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
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();
|
|
|
|
|
|
2025-10-02 14:52:19 +02:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_wconprodKeyword, "WconprodKeyword", "WCONPROD Settings" );
|
|
|
|
|
m_wconprodKeyword = new RimKeywordWconprod();
|
|
|
|
|
m_wconprodKeyword.uiCapability()->setUiTreeChildrenHidden( true );
|
|
|
|
|
|
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_wconinjeKeyword, "WconinjeKeyword", "WCONINJE Settings" );
|
|
|
|
|
m_wconinjeKeyword = new RimKeywordWconinje();
|
|
|
|
|
m_wconinjeKeyword.uiCapability()->setUiTreeChildrenHidden( true );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-11-14 12:56:23 +01:00
|
|
|
CAF_PDM_InitFieldNoDefault( &m_jobSettings, "JobSettings", "Opm Flow Settings" );
|
|
|
|
|
m_jobSettings = RiaPreferencesOpm::current()->createDefaultJobSettings();
|
|
|
|
|
m_jobSettings.uiCapability()->setUiTreeChildrenHidden( true );
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
CAF_PDM_InitField( &m_openTimeStep, "OpenTimeStep", 0, " " );
|
2025-09-29 16:57:21 +02:00
|
|
|
CAF_PDM_InitField( &m_endTimeStep, "EndTimeStep", 0, " " );
|
|
|
|
|
CAF_PDM_InitField( &m_endTimeStepEnabled, "EndTimeStepEnabled", false, "Stop Simulation at Date" );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
CAF_PDM_InitField( &m_appendNewDates, "AppendNewDates", false, "Append Extra Dates" );
|
|
|
|
|
CAF_PDM_InitField( &m_newDatesInterval, "NewDatesInterval", 1, "Interval" );
|
|
|
|
|
CAF_PDM_InitField( &m_numberOfNewDates, "NumberOfNewDates", 12, "Number of Dates to Append" );
|
|
|
|
|
CAF_PDM_InitField( &m_dateAppendType, "DateAppendType", caf::AppEnum<DateAppendType>( DateAppendType::ADD_MONTHS ), " " );
|
|
|
|
|
|
2025-09-29 16:57:21 +02:00
|
|
|
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::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_endTimeStepEnabled );
|
2025-10-07 18:21:15 +02:00
|
|
|
caf::PdmUiNativeCheckBoxEditor::configureFieldForEditor( &m_appendNewDates );
|
2025-09-29 16:57:21 +02:00
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
setDeletable( true );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RimOpmFlowJob::~RimOpmFlowJob()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::initAfterRead()
|
|
|
|
|
{
|
|
|
|
|
openDeckFile();
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-18 02:42:11 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2025-11-14 12:56:23 +01:00
|
|
|
void RimOpmFlowJob::processLogOutput( const QString& logLine )
|
2025-10-18 02:42:11 +02:00
|
|
|
{
|
2025-11-14 12:56:23 +01:00
|
|
|
// progress output parsing
|
2025-10-18 02:42:11 +02:00
|
|
|
// Example log lines:
|
|
|
|
|
// Report step 757/773 at day 9466/10958, date = 01-Dec-2025
|
|
|
|
|
// Report step 758/773 at day 9497/10958, date = 01-Jan-2026
|
|
|
|
|
if ( logLine.startsWith( "Report step" ) )
|
|
|
|
|
{
|
|
|
|
|
auto parts = logLine.split( ' ', Qt::SkipEmptyParts );
|
|
|
|
|
if ( parts.size() >= 4 )
|
|
|
|
|
{
|
|
|
|
|
auto stepPart = parts[2]; // 756/773
|
|
|
|
|
auto stepParts = stepPart.split( '/' );
|
|
|
|
|
if ( stepParts.size() == 2 )
|
|
|
|
|
{
|
|
|
|
|
bool ok1 = false;
|
|
|
|
|
bool ok2 = false;
|
|
|
|
|
int currentStep = stepParts[0].toInt( &ok1 );
|
|
|
|
|
if ( ok1 && ( m_startStepForProgress < 0 ) )
|
|
|
|
|
{
|
|
|
|
|
m_startStepForProgress = currentStep;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int totalSteps = stepParts[1].toInt( &ok2 );
|
|
|
|
|
if ( ok1 && ok2 )
|
|
|
|
|
{
|
|
|
|
|
auto noSteps = totalSteps - m_startStepForProgress;
|
|
|
|
|
if ( noSteps > 0 )
|
|
|
|
|
{
|
|
|
|
|
double perc = ( (double)( currentStep - m_startStepForProgress ) / (double)( noSteps ) ) * 100.0;
|
|
|
|
|
perc = std::max( 0.0, perc );
|
|
|
|
|
perc = std::min( perc, 100.0 );
|
|
|
|
|
onProgress( perc );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-14 12:56:23 +01:00
|
|
|
else if ( logLine.startsWith( "Warning" ) )
|
|
|
|
|
{
|
|
|
|
|
m_warningsDetected++;
|
|
|
|
|
}
|
|
|
|
|
else if ( logLine.startsWith( "Problem" ) )
|
|
|
|
|
{
|
|
|
|
|
m_warningsDetected++;
|
|
|
|
|
}
|
|
|
|
|
else if ( logLine.startsWith( "Error" ) )
|
|
|
|
|
{
|
|
|
|
|
m_errorsDetected++;
|
|
|
|
|
}
|
2025-10-18 02:42:11 +02:00
|
|
|
}
|
|
|
|
|
|
2025-11-28 16:43:51 +01:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RimOpmFlowJob::matchesKeyValue( const QString& key, const QString& value ) const
|
|
|
|
|
{
|
|
|
|
|
if ( key == jobInputFileKey() )
|
|
|
|
|
{
|
|
|
|
|
return ( m_deckFileName() == value );
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-03 00:51:02 +02:00
|
|
|
else if ( field == &m_wellGroupName )
|
|
|
|
|
{
|
|
|
|
|
auto attr = dynamic_cast<caf::PdmUiComboBoxEditorAttribute*>( attribute );
|
|
|
|
|
if ( attr )
|
|
|
|
|
{
|
2025-10-07 18:54:54 +02:00
|
|
|
attr->enableEditableContent = true;
|
|
|
|
|
attr->enableAutoComplete = false;
|
|
|
|
|
attr->adjustWidthToContents = true;
|
2025-10-18 02:42:11 +02:00
|
|
|
attr->notifyWhenTextIsEdited = false;
|
2025-10-03 00:51:02 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
|
|
|
{
|
2025-10-18 02:42:11 +02:00
|
|
|
if ( isRunning() )
|
|
|
|
|
{
|
|
|
|
|
auto runGrp = uiOrdering.addNewGroup( "Running" );
|
|
|
|
|
m_workDir.uiCapability()->setUiReadOnly( true );
|
|
|
|
|
runGrp->add( &m_workDir );
|
2025-10-21 18:36:24 +02:00
|
|
|
auto stopButton = runGrp->addNewButton( "Stop", [this]() { RicStopJobFeature::stopJob( this ); } );
|
|
|
|
|
stopButton->setUiIconFromResourceString( ":/stop.svg" );
|
|
|
|
|
stopButton->setAlignment( Qt::AlignCenter );
|
2025-10-18 02:42:11 +02:00
|
|
|
uiOrdering.skipRemainingFields();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_workDir.uiCapability()->setUiReadOnly( false );
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
auto genGrp = uiOrdering.addNewGroup( "General" );
|
|
|
|
|
genGrp->add( nameField() );
|
|
|
|
|
genGrp->add( &m_deckFileName );
|
|
|
|
|
genGrp->add( &m_workDir );
|
2025-11-14 12:56:23 +01:00
|
|
|
genGrp->add( &m_addToEnsemble );
|
2025-10-07 18:21:15 +02:00
|
|
|
|
2025-09-24 16:46:48 +02:00
|
|
|
if ( m_eclipseCase() == nullptr )
|
|
|
|
|
{
|
|
|
|
|
m_addNewWell = false;
|
|
|
|
|
}
|
|
|
|
|
else
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
auto wellGrp = uiOrdering.addNewGroup( "New Well Settings" );
|
2025-10-07 18:21:15 +02:00
|
|
|
wellGrp->add( &m_addNewWell );
|
2025-11-14 12:56:23 +01:00
|
|
|
wellGrp->add( &m_eclipseCase );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
if ( m_addNewWell() )
|
2025-10-02 14:52:19 +02:00
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
wellGrp->add( &m_wellPath );
|
|
|
|
|
wellGrp->add( &m_wellGroupName );
|
|
|
|
|
wellGrp->add( &m_wellOpenKeyword );
|
|
|
|
|
if ( m_wellOpenKeyword() == "WCONPROD" )
|
|
|
|
|
{
|
|
|
|
|
auto wconGrp = wellGrp->addNewGroup( "WCONPROD Settings" );
|
|
|
|
|
m_wconprodKeyword->uiOrdering( wconGrp );
|
|
|
|
|
wconGrp->setCollapsedByDefault();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto wconGrp = wellGrp->addNewGroup( "WCONINJE Settings" );
|
|
|
|
|
m_wconinjeKeyword->uiOrdering( wconGrp );
|
|
|
|
|
wconGrp->setCollapsedByDefault();
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
wellGrp->add( &m_wellOpenType );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-21 18:36:24 +02:00
|
|
|
bool createOpenPostionButton = false;
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
if ( m_fileDeckHasDates )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
if ( m_wellOpenType() == WellOpenType::OPEN_AT_DATE )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
wellGrp->add( &m_openTimeStep );
|
|
|
|
|
if ( !m_fileDeckIsRestart )
|
|
|
|
|
{
|
|
|
|
|
wellGrp->add( &m_useRestart );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_useRestart = false;
|
|
|
|
|
}
|
|
|
|
|
if ( m_eclipseCase() ) wellGrp->add( &m_includeMSWData );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
else if ( m_wellOpenType == WellOpenType::OPEN_BY_POSITION )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-21 18:36:24 +02:00
|
|
|
createOpenPostionButton = true;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
m_wellOpenType.uiCapability()->setUiReadOnly( false );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
else
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-21 18:36:24 +02:00
|
|
|
createOpenPostionButton = true;
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
m_wellOpenType = WellOpenType::OPEN_BY_POSITION;
|
|
|
|
|
m_wellOpenType.uiCapability()->setUiReadOnly( true );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-21 18:36:24 +02:00
|
|
|
|
|
|
|
|
if ( createOpenPostionButton )
|
|
|
|
|
{
|
|
|
|
|
auto openSelectButton = wellGrp->addNewButton( "Select Open Keyword Position", [this]() { selectOpenWellPosition(); } );
|
|
|
|
|
openSelectButton->setAlignment( Qt::AlignRight );
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( m_fileDeckHasDates )
|
|
|
|
|
{
|
|
|
|
|
auto dateGrp = uiOrdering.addNewGroup( "Date Settings" );
|
|
|
|
|
dateGrp->setCollapsedByDefault();
|
2025-11-14 12:56:23 +01:00
|
|
|
|
|
|
|
|
dateGrp->add( &m_endTimeStepEnabled );
|
|
|
|
|
if ( m_endTimeStepEnabled() )
|
|
|
|
|
{
|
|
|
|
|
dateGrp->add( &m_endTimeStep );
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
dateGrp->add( &m_appendNewDates );
|
|
|
|
|
if ( m_appendNewDates() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
dateGrp->add( &m_numberOfNewDates );
|
|
|
|
|
dateGrp->add( &m_newDatesInterval );
|
|
|
|
|
dateGrp->appendToRow( &m_dateAppendType );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
auto opmGrp = uiOrdering.addNewGroup( "OPM Flow" );
|
2025-10-21 18:36:24 +02:00
|
|
|
|
|
|
|
|
auto runButton = opmGrp->addNewButton( "Run", [this]() { RicRunJobFeature::runJob( this ); } );
|
|
|
|
|
runButton->setUiIconFromResourceString( ":/Play.svg" );
|
|
|
|
|
runButton->setAlignment( Qt::AlignCenter );
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
opmGrp->add( &m_pauseBeforeRun );
|
2025-10-21 18:36:24 +02:00
|
|
|
|
2025-11-14 12:56:23 +01:00
|
|
|
m_jobSettings->uiOrdering( opmGrp, false /* expand by default */ );
|
|
|
|
|
|
|
|
|
|
auto advGrp = uiOrdering.addNewGroup( "Advanced" );
|
|
|
|
|
advGrp->setCollapsedByDefault();
|
|
|
|
|
advGrp->add( &m_currentRunId );
|
|
|
|
|
auto resetRunIdButton = advGrp->addNewButton( "Reset Ensemble Run Id", [this]() { resetEnsembleRunId(); } );
|
|
|
|
|
resetRunIdButton->setAlignment( Qt::AlignRight );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
uiOrdering.skipRemainingFields();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
QList<caf::PdmOptionItemInfo> RimOpmFlowJob::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
|
|
|
|
{
|
|
|
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
|
|
|
|
|
|
|
|
if ( fieldNeedingOptions == &m_wellPath )
|
|
|
|
|
{
|
|
|
|
|
RimTools::wellPathOptionItems( &options );
|
|
|
|
|
}
|
2025-09-29 16:57:21 +02:00
|
|
|
else if ( ( fieldNeedingOptions == &m_openTimeStep ) || ( fieldNeedingOptions == &m_endTimeStep ) )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-18 02:42:11 +02:00
|
|
|
if ( openDeckFile() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
auto timeStepNames = dateStrings();
|
2025-09-29 16:57:21 +02:00
|
|
|
for ( int i = 0; i < static_cast<int>( timeStepNames.size() - 1 ); ++i )
|
|
|
|
|
{
|
2025-10-07 18:21:15 +02:00
|
|
|
options.push_back( caf::PdmOptionItemInfo( timeStepNames[i], QVariant::fromValue( i ) ) );
|
2025-09-29 16:57:21 +02:00
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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" ) ) ) );
|
|
|
|
|
}
|
2025-10-03 00:51:02 +02:00
|
|
|
else if ( fieldNeedingOptions == &m_wellGroupName )
|
|
|
|
|
{
|
2025-10-18 02:42:11 +02:00
|
|
|
for ( auto& grp : wellgroupsInFileDeck() )
|
2025-10-03 00:51:02 +02:00
|
|
|
{
|
|
|
|
|
options.push_back( caf::PdmOptionItemInfo( grp, QVariant::fromValue( grp ) ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
else if ( fieldNeedingOptions == &m_eclipseCase )
|
|
|
|
|
{
|
|
|
|
|
RimTools::eclipseCaseOptionItems( &options );
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::vector<QString> RimOpmFlowJob::dateStrings()
|
|
|
|
|
{
|
|
|
|
|
std::vector<QString> dateStrs;
|
|
|
|
|
|
|
|
|
|
for ( auto& dt : dateTimes() )
|
|
|
|
|
{
|
|
|
|
|
dateStrs.push_back( dt.toString( "dd-MMM-yyyy (HH:mm)" ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dateStrs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::vector<QDateTime> RimOpmFlowJob::dateTimes()
|
|
|
|
|
{
|
|
|
|
|
auto dates = datesInFileDeck();
|
|
|
|
|
auto newDates = addedDateTimes();
|
|
|
|
|
dates.insert( dates.end(), newDates.begin(), newDates.end() );
|
|
|
|
|
|
|
|
|
|
return dates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::vector<QDateTime> RimOpmFlowJob::addedDateTimes()
|
|
|
|
|
{
|
|
|
|
|
if ( !m_appendNewDates() || !m_fileDeckHasDates ) return {};
|
|
|
|
|
|
|
|
|
|
auto existingDates = datesInFileDeck();
|
|
|
|
|
auto& startDate = existingDates.back();
|
|
|
|
|
|
|
|
|
|
std::vector<QDateTime> newDates;
|
|
|
|
|
for ( auto dt = startDate; newDates.size() < static_cast<size_t>( m_numberOfNewDates() ); )
|
|
|
|
|
{
|
|
|
|
|
if ( m_dateAppendType() == DateAppendType::ADD_DAYS )
|
|
|
|
|
{
|
|
|
|
|
dt = dt.addDays( m_newDatesInterval() );
|
|
|
|
|
}
|
|
|
|
|
else if ( m_dateAppendType() == DateAppendType::ADD_MONTHS )
|
|
|
|
|
{
|
|
|
|
|
dt = dt.addMonths( m_newDatesInterval() );
|
|
|
|
|
}
|
|
|
|
|
newDates.push_back( dt );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newDates;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
|
|
|
{
|
2025-12-07 03:43:48 +01:00
|
|
|
if ( changedField == &m_wellPath )
|
2025-10-03 00:51:02 +02:00
|
|
|
{
|
|
|
|
|
if ( ( m_wellPath() != nullptr ) && ( m_wellPath->completionSettings() != nullptr ) )
|
|
|
|
|
{
|
|
|
|
|
auto wellSettings = m_wellPath->completionSettings();
|
|
|
|
|
if ( !wellSettings->groupName().isEmpty() && m_wellGroupName().isEmpty() )
|
|
|
|
|
{
|
|
|
|
|
m_wellGroupName = wellSettings->groupName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::setWorkingDirectory( QString workDir )
|
|
|
|
|
{
|
|
|
|
|
m_workDir = workDir;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-13 23:39:38 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
QString RimOpmFlowJob::mainWorkingDirectory() const
|
|
|
|
|
{
|
|
|
|
|
return m_workDir().path();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::setEclipseCase( RimEclipseCase* eCase )
|
|
|
|
|
{
|
|
|
|
|
if ( eCase == nullptr )
|
|
|
|
|
{
|
|
|
|
|
m_deckFileName.setValue( QString() );
|
2025-10-18 02:42:11 +02:00
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QFileInfo fi( eCase->gridFileName() );
|
|
|
|
|
m_deckFileName.setValue( fi.absolutePath() + "/" + fi.completeBaseName() + deckExtension() );
|
|
|
|
|
m_eclipseCase = eCase;
|
2025-10-18 02:42:11 +02:00
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
openDeckFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::setInputDataFile( QString filename )
|
|
|
|
|
{
|
|
|
|
|
m_deckFileName.setValue( filename );
|
2025-10-18 02:42:11 +02:00
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
openDeckFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RimOpmFlowJob::openDeckFile()
|
|
|
|
|
{
|
2025-10-18 02:42:11 +02:00
|
|
|
if ( m_deckFile.get() == nullptr )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
m_deckFile = std::make_unique<RifOpmFlowDeckFile>();
|
|
|
|
|
bool deckLoadOk = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
deckLoadOk = m_deckFile->loadDeck( m_deckFileName().path().toStdString() );
|
2025-10-18 02:42:11 +02:00
|
|
|
if ( deckLoadOk )
|
|
|
|
|
{
|
|
|
|
|
m_fileDeckHasDates = m_deckFile->hasDatesKeyword();
|
|
|
|
|
m_fileDeckIsRestart = m_deckFile->isRestartFile();
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
catch ( std::filesystem::filesystem_error& )
|
|
|
|
|
{
|
2025-10-18 02:42:11 +02:00
|
|
|
deckLoadOk = false;
|
2025-06-11 15:43:53 +02:00
|
|
|
RiaLogging::error( QString( "Failed to open %1, possibly unsupported or incorrect format." ).arg( m_deckFileName().path() ) );
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-18 02:42:11 +02:00
|
|
|
if ( !deckLoadOk )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-09-29 16:57:21 +02:00
|
|
|
m_fileDeckHasDates = false;
|
|
|
|
|
m_fileDeckIsRestart = false;
|
2025-10-18 02:42:11 +02:00
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-18 02:42:11 +02:00
|
|
|
return m_deckFile.get() != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::closeDeckFile()
|
|
|
|
|
{
|
|
|
|
|
m_deckFile.reset();
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
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::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()
|
|
|
|
|
{
|
2025-12-07 03:43:48 +01:00
|
|
|
auto deckName = baseDeckName();
|
|
|
|
|
if ( m_addToEnsemble() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-12-07 03:43:48 +01:00
|
|
|
deckName = deckName + "-" + QString::number( m_currentRunId() );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-12-07 03:43:48 +01:00
|
|
|
return deckName;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2025-11-28 16:43:51 +01:00
|
|
|
QString RimOpmFlowJob::baseDeckName()
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-12-07 03:43:48 +01:00
|
|
|
auto baseName = name();
|
|
|
|
|
baseName.replace( ' ', '_' );
|
|
|
|
|
baseName = baseName.toUpper();
|
|
|
|
|
return baseName;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2025-11-28 16:43:51 +01:00
|
|
|
QString RimOpmFlowJob::restartDeckName()
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-11-28 16:43:51 +01:00
|
|
|
return inputDeckName() + "_RST";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
QString RimOpmFlowJob::inputDeckName() const
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fi( m_deckFileName().path() );
|
|
|
|
|
return fi.completeBaseName();
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
QString RimOpmFlowJob::deckExtension() const
|
|
|
|
|
{
|
|
|
|
|
return ".DATA";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
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() )
|
|
|
|
|
{
|
2025-07-02 16:09:44 +02:00
|
|
|
cmd.append( opmPref->mpirunCommand() );
|
2025-06-11 15:43:53 +02:00
|
|
|
cmd.append( QString( "-np" ) );
|
2025-11-14 12:56:23 +01:00
|
|
|
cmd.append( QString( "%1" ).arg( m_jobSettings->mpiProcesses() ) );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd.append( opmPref->opmFlowCommand() );
|
|
|
|
|
cmd.append( QString( "--output-dir=%1" ).arg( workDir ) );
|
|
|
|
|
cmd.append( QString( "--ecl-deck-file-name=%1" ).arg( dataFile ) );
|
2025-11-14 12:56:23 +01:00
|
|
|
|
2025-11-17 23:05:01 +01:00
|
|
|
cmd.append( m_jobSettings->commandLineOptions( workingDirectory(), workDir ) );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 16:57:21 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::map<QString, QString> RimOpmFlowJob::environment()
|
|
|
|
|
{
|
|
|
|
|
auto opmPref = RiaPreferencesOpm::current();
|
|
|
|
|
if ( opmPref->useWsl() )
|
|
|
|
|
{
|
|
|
|
|
return RiaWslTools::wslEnvironmentVariables();
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RimOpmFlowJob::onPrepare()
|
|
|
|
|
{
|
2025-11-28 16:43:51 +01:00
|
|
|
if ( name().isEmpty() )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Please set a name for the OPM Flow Job." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
// reload file deck to make sure we start with the original
|
2025-10-18 02:42:11 +02:00
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
if ( !openDeckFile() )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Unable to open input DATA file " + m_deckFileName().path() );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 18:21:15 +02:00
|
|
|
// add extra date keywords
|
|
|
|
|
if ( m_appendNewDates() && m_fileDeckHasDates )
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::time_t> newDates;
|
|
|
|
|
for ( auto& dt : addedDateTimes() )
|
|
|
|
|
{
|
|
|
|
|
newDates.push_back( dt.toSecsSinceEpoch() );
|
|
|
|
|
}
|
|
|
|
|
m_deckFile->appendDateKeywords( newDates );
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
// add a new well?
|
|
|
|
|
if ( m_addNewWell() )
|
|
|
|
|
{
|
|
|
|
|
if ( m_wellPath == nullptr )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Please select a well path to use." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-03 00:51:02 +02:00
|
|
|
if ( m_wellPath->completionSettings() == nullptr )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "The selected well path has no completions defined." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-02 14:52:19 +02:00
|
|
|
auto wellNameInDeck = m_wellPath->completionSettings()->wellName();
|
|
|
|
|
if ( wellNameInDeck.isEmpty() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Selected Well Path does not have a WELL NAME set, please check the completion settings." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-03 00:51:02 +02:00
|
|
|
if ( m_wellGroupName().isEmpty() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-03 00:51:02 +02:00
|
|
|
RiaLogging::error( "Please set the well group name." );
|
2025-06-11 15:43:53 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2025-10-07 18:21:15 +02:00
|
|
|
m_wellPath->completionSettings()->setGroupName( m_wellGroupName() );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-30 11:57:22 +01:00
|
|
|
int mergePosition = mergeBasicWellSettings();
|
|
|
|
|
if ( mergePosition < 0 )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-30 11:57:22 +01:00
|
|
|
RiaLogging::error( "Unable to merge new well data into DATA file. Please check file format." );
|
|
|
|
|
return false;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-30 11:57:22 +01:00
|
|
|
|
|
|
|
|
if ( ( m_includeMSWData ) && ( m_wellOpenType == WellOpenType::OPEN_AT_DATE ) )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-30 11:57:22 +01:00
|
|
|
mergePosition = mergeMswData( mergePosition );
|
2025-10-24 11:10:25 +02:00
|
|
|
if ( mergePosition < 0 )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-30 11:57:22 +01:00
|
|
|
RiaLogging::error( "Failed to merge MSW data into file deck." );
|
2025-06-11 15:43:53 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-24 11:10:25 +02:00
|
|
|
Opm::DeckKeyword openKeyword = ( m_wellOpenKeyword() == "WCONPROD" ) ? m_wconprodKeyword->keyword( wellNameInDeck )
|
|
|
|
|
: m_wconinjeKeyword->keyword( wellNameInDeck );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
// open new well at selected timestep
|
2025-09-29 16:57:21 +02:00
|
|
|
if ( m_wellOpenType == WellOpenType::OPEN_AT_DATE )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-02 14:52:19 +02:00
|
|
|
if ( !m_deckFile->openWellAtTimeStep( m_openTimeStep(), openKeyword ) )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-09-29 16:57:21 +02:00
|
|
|
RiaLogging::error( "Unable to open new well at selected timestep in DATA file." );
|
2025-06-11 15:43:53 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-10-02 14:52:19 +02:00
|
|
|
if ( !m_deckFile->openWellAtDeckPosition( mergePosition, openKeyword ) )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Unable to open new well at selected position in DATA file." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 16:57:21 +02:00
|
|
|
if ( m_useRestart() )
|
|
|
|
|
{
|
|
|
|
|
if ( !copyUnrstFileToWorkDir() )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Unable to locate UNRST file from input case." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !m_deckFile->restartAtTimeStep( m_openTimeStep(), restartDeckName().toStdString() ) )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Unable to insert restart keywords in DATA file." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( m_endTimeStepEnabled() )
|
|
|
|
|
{
|
|
|
|
|
if ( !m_deckFile->stopAtTimeStep( m_endTimeStep() ) )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Unable to insert END keyword in DATA file." );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-24 16:46:48 +02:00
|
|
|
caf::ProgressInfo saveProgress( 1, "Saving updated information to DATA file.", false );
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
// save DATA file to working folder
|
|
|
|
|
bool saveOk = m_deckFile->saveDeck( workingDirectory().toStdString(), deckName().toStdString() + deckExtension().toStdString() );
|
2025-10-18 02:42:11 +02:00
|
|
|
|
|
|
|
|
closeDeckFile();
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-09-24 16:46:48 +02:00
|
|
|
return saveOk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RimOpmFlowJob::onRun()
|
|
|
|
|
{
|
2025-06-11 15:43:53 +02:00
|
|
|
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.";
|
|
|
|
|
|
2026-01-21 19:11:41 +01:00
|
|
|
auto parent = RiaGuiApplication::widgetToUseAsParent();
|
|
|
|
|
|
|
|
|
|
auto reply = QMessageBox::information( parent, "Opm Flow simulation", infoText, QMessageBox::Ok | QMessageBox::Cancel );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
|
|
|
|
if ( reply != QMessageBox::Ok ) return false;
|
|
|
|
|
}
|
2025-09-24 16:46:48 +02:00
|
|
|
return true;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-18 02:42:11 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::onProgress( double percentageDone )
|
|
|
|
|
{
|
|
|
|
|
m_percentageDone = percentageDone;
|
|
|
|
|
updateConnectedEditors();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
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 } );
|
2025-06-16 02:36:13 +00:00
|
|
|
if ( !ensembles.empty() )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
|
|
|
|
m_summaryEnsemble = ensembles[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_summaryEnsemble->reloadCases();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_currentRunId = m_currentRunId + 1;
|
|
|
|
|
}
|
|
|
|
|
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();
|
2025-09-24 16:46:48 +02:00
|
|
|
if ( m_eclipseCase() == nullptr )
|
|
|
|
|
{
|
|
|
|
|
m_eclipseCase = newCase;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2025-10-27 23:33:56 +01:00
|
|
|
/// Returns value < 0 if failure to merge
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2025-10-24 11:10:25 +02:00
|
|
|
int RimOpmFlowJob::mergeBasicWellSettings()
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-24 11:10:25 +02:00
|
|
|
const int failure = -1;
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-12-04 19:25:41 +01:00
|
|
|
if ( m_eclipseCase() == nullptr || m_wellPath() == nullptr || m_wellPath()->completionSettings() == nullptr ||
|
|
|
|
|
m_eclipseCase()->eclipseCaseData() == nullptr )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Cannot create COMPDAT keyword - check case, wellpath and completion settings data." );
|
|
|
|
|
return failure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto compdata = RicWellPathExportCompletionDataFeatureImpl::completionDataForWellPath( m_wellPath(), m_eclipseCase() );
|
|
|
|
|
auto wellName = m_wellPath()->completionSettings()->wellNameForExport().toStdString();
|
|
|
|
|
|
2025-10-24 11:10:25 +02:00
|
|
|
int mergePosition = m_openWellDeckPosition();
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-12-04 19:25:41 +01:00
|
|
|
auto compdatKw = RimKeywordFactory::compdatKeyword( compdata, wellName );
|
|
|
|
|
auto wpimultKw = RimKeywordFactory::wpimultKeyword( compdata, wellName );
|
|
|
|
|
auto complumpKw = RimKeywordFactory::complumpKeyword( compdata, wellName );
|
2025-10-24 11:10:25 +02:00
|
|
|
auto welspecsKw = RimKeywordFactory::welspecsKeyword( m_wellGroupName().toStdString(), m_eclipseCase(), m_wellPath() );
|
2025-06-11 15:43:53 +02:00
|
|
|
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( welspecsKw.empty() || compdatKw.empty() )
|
2025-10-30 23:55:50 +01:00
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Failed to create WELSPECS and COMPDAT keywords for selected well path. Do you have a valid case selected?" );
|
|
|
|
|
return failure;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-24 11:10:25 +02:00
|
|
|
if ( m_wellOpenType == WellOpenType::OPEN_AT_DATE )
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-24 11:10:25 +02:00
|
|
|
// reverse order for correct insertion order
|
2025-12-04 19:25:41 +01:00
|
|
|
if ( !complumpKw.empty() )
|
|
|
|
|
{
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), complumpKw ) ) return failure;
|
|
|
|
|
}
|
|
|
|
|
if ( !wpimultKw.empty() )
|
|
|
|
|
{
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), wpimultKw ) ) return failure;
|
|
|
|
|
}
|
2025-10-24 11:10:25 +02:00
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), compdatKw ) ) return failure;
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), welspecsKw ) ) return failure;
|
2025-10-30 11:57:22 +01:00
|
|
|
mergePosition = 0;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
2025-10-24 11:10:25 +02:00
|
|
|
else
|
2025-06-11 15:43:53 +02:00
|
|
|
{
|
2025-10-24 11:10:25 +02:00
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, welspecsKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, compdatKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
2025-12-04 19:25:41 +01:00
|
|
|
if ( !wpimultKw.empty() )
|
|
|
|
|
{
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, wpimultKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
}
|
|
|
|
|
if ( !complumpKw.empty() )
|
|
|
|
|
{
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, complumpKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
}
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-24 11:10:25 +02:00
|
|
|
// increase wells and connections in welldims to make sure they are big enough
|
|
|
|
|
auto additionalConnections = (int)compdatKw.size();
|
|
|
|
|
auto welldims = m_deckFile->welldims();
|
2025-10-30 11:57:22 +01:00
|
|
|
if ( ( welldims.size() < 4 ) ||
|
|
|
|
|
!m_deckFile->setWelldims( (int)welldims[0] + 1, (int)( welldims[1] + additionalConnections ), (int)welldims[2] + 1, (int)welldims[3] + 1 ) )
|
2025-10-24 11:10:25 +02:00
|
|
|
{
|
2025-10-30 11:57:22 +01:00
|
|
|
RiaLogging::error( "Failed to update WELLDIMS keyword in DATA file, is it missing?" );
|
2025-10-24 11:10:25 +02:00
|
|
|
return failure;
|
|
|
|
|
}
|
|
|
|
|
return mergePosition;
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-30 11:57:22 +01:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
int RimOpmFlowJob::mergeMswData( int mergePosition )
|
|
|
|
|
{
|
|
|
|
|
const int failure = -1;
|
|
|
|
|
|
2025-11-07 10:05:53 +01:00
|
|
|
auto mswDataResult = RicWellPathExportMswTableData::extractSingleWellMswData( m_eclipseCase(), m_wellPath(), 0 );
|
|
|
|
|
if ( !mswDataResult.has_value() )
|
|
|
|
|
{
|
|
|
|
|
RiaLogging::error( QString::fromStdString( mswDataResult.error() ) );
|
|
|
|
|
return failure;
|
|
|
|
|
}
|
2025-10-30 11:57:22 +01:00
|
|
|
|
2025-11-14 16:54:05 +01:00
|
|
|
int maxSegNum = 0;
|
|
|
|
|
int maxBranches = 0;
|
|
|
|
|
auto welsegsKw = RimKeywordFactory::welsegsKeyword( mswDataResult.value(), maxSegNum, maxBranches );
|
|
|
|
|
auto compsegsKw = RimKeywordFactory::compsegsKeyword( mswDataResult.value() );
|
|
|
|
|
auto wsegvalvKw = RimKeywordFactory::wsegvalvKeyword( mswDataResult.value() );
|
|
|
|
|
auto wsegaicdKw = RimKeywordFactory::wsegaicdKeyword( mswDataResult.value() );
|
2025-10-30 11:57:22 +01:00
|
|
|
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( welsegsKw.empty() || compsegsKw.empty() )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Failed to create WELSEGS or COMPSEGS keyword from MSW data." );
|
|
|
|
|
return failure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( m_wellOpenType == WellOpenType::OPEN_AT_DATE )
|
|
|
|
|
{
|
|
|
|
|
// make sure we insert after COMPDAT kw
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), welsegsKw, "COMPDAT" ) ) return failure;
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), compsegsKw, welsegsKw.name() ) ) return failure;
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( !wsegvalvKw.empty() )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), wsegvalvKw, compsegsKw.name() ) ) return failure;
|
|
|
|
|
}
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( !wsegaicdKw.empty() )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
if ( !m_deckFile->mergeKeywordAtTimeStep( m_openTimeStep(), wsegaicdKw, compsegsKw.name() ) ) return failure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mergePosition = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, welsegsKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
mergePosition++;
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, compsegsKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
mergePosition++;
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( !wsegvalvKw.empty() )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, wsegvalvKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
mergePosition++;
|
|
|
|
|
}
|
2025-10-31 02:26:18 +00:00
|
|
|
if ( !wsegaicdKw.empty() )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
mergePosition = m_deckFile->mergeKeywordAtPosition( mergePosition, wsegaicdKw );
|
|
|
|
|
if ( mergePosition < 0 ) return failure;
|
|
|
|
|
mergePosition++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-14 16:54:05 +01:00
|
|
|
int branches = (int)m_wellPath->allWellPathLaterals().size() + 1;
|
2025-10-30 11:57:22 +01:00
|
|
|
|
2025-11-14 16:54:05 +01:00
|
|
|
// wsegdims contains: max segmented wells, max segments, max branches
|
|
|
|
|
auto wsegdims = m_deckFile->wsegdims();
|
|
|
|
|
int maxSegWells = wsegdims[0] + 1; // we have added one well
|
|
|
|
|
maxSegNum = std::max( wsegdims[1], maxSegNum );
|
|
|
|
|
maxBranches = std::max( branches, maxBranches );
|
|
|
|
|
maxBranches = std::max( wsegdims[2], maxBranches );
|
|
|
|
|
if ( !m_deckFile->setWsegdims( maxSegWells, maxSegNum, maxBranches ) )
|
2025-10-30 11:57:22 +01:00
|
|
|
{
|
|
|
|
|
RiaLogging::error( "Failed to update WSEGDIMS keyword in DATA file." );
|
|
|
|
|
return failure;
|
|
|
|
|
}
|
|
|
|
|
return mergePosition;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-11 15:43:53 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
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 ) ) );
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-21 19:11:41 +01:00
|
|
|
m_openWellDeckPosition = RimDeckPositionDlg::askForPosition( RiaGuiApplication::widgetToUseAsParent(),
|
|
|
|
|
kwVec,
|
|
|
|
|
"--- Open New Well HERE ---",
|
|
|
|
|
m_openWellDeckPosition );
|
2025-06-11 15:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-21 18:36:24 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::resetEnsembleRunId()
|
|
|
|
|
{
|
2026-01-21 19:11:41 +01:00
|
|
|
if ( QMessageBox::information( RiaGuiApplication::widgetToUseAsParent(),
|
|
|
|
|
"Opm Flow Job",
|
|
|
|
|
"Do you want to reset the ensemble run ID to 0?",
|
|
|
|
|
QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes )
|
2025-10-21 18:36:24 +02:00
|
|
|
{
|
|
|
|
|
m_currentRunId = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-24 11:10:25 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RimOpmFlowJob::initAfterCopy()
|
|
|
|
|
{
|
|
|
|
|
m_currentRunId = 0;
|
|
|
|
|
m_gridEnsemble = nullptr;
|
|
|
|
|
m_summaryEnsemble = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 16:57:21 +02:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::vector<QDateTime> RimOpmFlowJob::datesInFileDeck()
|
|
|
|
|
{
|
|
|
|
|
std::vector<QDateTime> dates;
|
|
|
|
|
|
|
|
|
|
if ( openDeckFile() )
|
|
|
|
|
{
|
|
|
|
|
for ( auto tt : m_deckFile->dates() )
|
|
|
|
|
{
|
|
|
|
|
dates.push_back( QDateTime::fromSecsSinceEpoch( tt ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dates;
|
|
|
|
|
}
|
2025-10-03 00:51:02 +02:00
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
std::vector<QString> RimOpmFlowJob::wellgroupsInFileDeck()
|
|
|
|
|
{
|
|
|
|
|
std::vector<QString> groups;
|
|
|
|
|
|
|
|
|
|
if ( openDeckFile() )
|
|
|
|
|
{
|
|
|
|
|
for ( auto& grp : m_deckFile->wellGroupsInFile() )
|
|
|
|
|
{
|
|
|
|
|
groups.push_back( QString::fromStdString( grp ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return groups;
|
|
|
|
|
}
|
2025-11-28 16:43:51 +01:00
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
QString RimOpmFlowJob::jobInputFileKey()
|
|
|
|
|
{
|
|
|
|
|
return "OpmFlowInputFile";
|
|
|
|
|
}
|