#14772 Python: Add Reservoir.create_lgr_for_completions and export_lgr_for_completions as object methods

RimEclipseCase_createLgrForCompletions and
RimEclipseCase_exportLgrForCompletions take WellPath objects and
expose refinement and split type. Lgr::SplitType is registered as the
Python StrEnum LgrSplitType. RicfCreateLgrForCompletions forwards to
the create method. Case.create_lgr_for_completion() in Python is kept
and emits a DeprecationWarning.
This commit is contained in:
Kristian Bendiksen committed 2026-09-22 14:19:23 +02:00
1 parent b40d19f55f
commit e54363133e
5 files changed
+343 -77

No files matched your search

@@ -18,27 +18,13 @@
#include "RicfCreateLgrForCompletions.h"
#include "RiaLogging.h"
#include "RiaWellNameComparer.h"
#include "RicfApplicationTools.h"
#include "RicfCommandFileExecutor.h"
#include "RicfCommandForwarding.h"
#include "ExportCommands/RicExportLgrFeature.h"
#include "RicCreateTemporaryLgrFeature.h"
#include "RicDeleteTemporaryLgrsFeature.h"
#include "RigReservoirGridTools.h"
#include "RimDialogData.h"
#include "RimEclipseCase.h"
#include "RimEclipseCaseCollection.h"
#include "RimFractureTemplate.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimWellPath.h"
#include "RimcEclipseCase.h"
#include "cafCmdFeatureManager.h"
#include "cafPdmFieldScriptingCapability.h"
#include <QStringList>
@@ -64,75 +50,41 @@ RicfCreateLgrForCompletions::RicfCreateLgrForCompletions()
//--------------------------------------------------------------------------------------------------
caf::PdmScriptResponse RicfCreateLgrForCompletions::execute()
{
using TOOLS = RicfApplicationTools;
const QString commandName = classKeyword();
std::vector<RimWellPath*> wellPaths;
// Find well paths
QStringList wellsNotFound;
std::vector<RimWellPath*> wellPaths =
RicfApplicationTools::wellPathsFromNames( RicfApplicationTools::toQStringList( m_wellPathNames ), &wellsNotFound );
if ( !wellsNotFound.empty() )
{
QStringList wellsNotFound;
wellPaths = TOOLS::wellPathsFromNames( TOOLS::toQStringList( m_wellPathNames ), &wellsNotFound );
if ( !wellsNotFound.empty() )
{
QString error = QString( "createLgrForCompletions: These well paths were not found: " ) + wellsNotFound.join( ", " );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
return RicfForwarding::errorResponse( "These well paths were not found: " + wellsNotFound.join( ", " ), commandName );
}
if ( wellPaths.empty() ) return RicfForwarding::errorResponse( "No well paths found", commandName );
auto rimCase = RicfForwarding::findCase( m_caseId() );
if ( !rimCase ) return RicfForwarding::errorResponse( rimCase.error(), commandName );
auto* eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase.value() );
if ( !eclipseCase )
{
return RicfForwarding::errorResponse( QString( "Case with ID %1 is not an Eclipse case" ).arg( m_caseId() ), commandName );
}
if ( wellPaths.empty() )
{
QString error( "No well paths found" );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
RimEclipseCase_createLgrForCompletions method( eclipseCase );
method.setWellPaths( wellPaths );
method.setTimeStep( m_timeStep() );
method.setRefinement( m_refinementI(), m_refinementJ(), m_refinementK() );
method.setSplitType( m_splitType() );
caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance();
auto feature = dynamic_cast<RicCreateTemporaryLgrFeature*>( commandManager->getCommandFeature( "RicCreateTemporaryLgrFeature" ) );
RimEclipseCase* eclipseCase = nullptr;
{
for ( RimEclipseCase* c : RimProject::current()->activeOilField()->analysisModels->cases() )
{
if ( c->caseId() == m_caseId() )
{
eclipseCase = c;
break;
}
}
if ( !eclipseCase )
{
QString error( QString( "createLgrForCompletions: Could not find case with ID %1" ).arg( m_caseId() ) );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
}
RicDeleteTemporaryLgrsFeature::deleteAllTemporaryLgrs( eclipseCase );
cvf::Vec3st lgrCellCounts( m_refinementI, m_refinementJ, m_refinementK );
QStringList wellsIntersectingOtherLgrs;
feature->createLgrsForWellPaths( wellPaths,
eclipseCase,
m_timeStep,
lgrCellCounts,
m_splitType(),
{ RigCompletionData::CompletionType::PERFORATION,
RigCompletionData::CompletionType::FRACTURE,
RigCompletionData::CompletionType::FISHBONES },
&wellsIntersectingOtherLgrs );
RigReservoirGridTools::refreshEclipseCaseDataAndViews( eclipseCase );
auto result = method.execute();
if ( !result ) return RicfForwarding::errorResponse( result.error(), commandName );
caf::PdmScriptResponse response;
if ( !wellsIntersectingOtherLgrs.empty() )
if ( !method.wellsIntersectingOtherLgrs().empty() )
{
auto wellsList = wellsIntersectingOtherLgrs.join( ", " );
QString warning( "createLgrForCompletions: No LGRs created for some wells due to existing intersecting "
"LGR(s).Affected wells : " +
wellsList );
RiaLogging::warning( warning.toStdString() );
QString warning = QString( "%1: No LGRs created for some wells due to existing intersecting LGR(s). Affected wells: %2" )
.arg( commandName )
.arg( method.wellsIntersectingOtherLgrs().join( ", " ) );
response.updateStatus( caf::PdmScriptResponse::COMMAND_WARNING, warning );
}
return response;
@@ -23,10 +23,21 @@
#include "RimEclipseCase.h"
#include "RimTools.h"
#include "cafPdmScriptEnumNameRegistry.h"
#include "cafPdmUiFilePathEditor.h"
#include "cafPdmUiTextEditor.h"
#include "cafVecIjk.h"
namespace
{
// Pin the Python StrEnum class name for the LGR split type used by RimEclipseCase_createLgrForCompletions
struct RegisterScriptEnumNames
{
RegisterScriptEnumNames() { caf::PdmScriptEnumNameRegistry::registerName<Lgr::SplitType>( "LgrSplitType" ); }
};
const RegisterScriptEnumNames s_registerScriptEnumNames;
} // namespace
CAF_PDM_SOURCE_INIT( RicExportLgrUi, "RicExportLgrUi" );
//--------------------------------------------------------------------------------------------------
@@ -21,10 +21,14 @@
#include "RiaApplication.h"
#include "RiaGuiApplication.h"
#include "RiaKeyValueStoreUtil.h"
#include "RiaLogging.h"
#include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h"
#include "CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h"
#include "ExportCommands/RicEclipseCellResultToFileImpl.h"
#include "ExportCommands/RicExportLgrFeature.h"
#include "RicCreateTemporaryLgrFeature.h"
#include "RicDeleteTemporaryLgrsFeature.h"
#include "RifInputPropertyLoader.h"
@@ -37,6 +41,7 @@
#include "RigMainGrid.h"
#include "RigNoRefinement.h"
#include "RigResdataGridConverter.h"
#include "RigReservoirGridTools.h"
#include "RigResultAccessor.h"
#include "RigResultAccessorFactory.h"
@@ -52,6 +57,7 @@
#include "RimcDataContainerString.h"
#include "cafCmdFeatureManager.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cvfArray.h"
@@ -936,3 +942,227 @@ std::expected<caf::PdmObjectHandle*, QString> RimEclipseCase_exportMswCompletion
return nullptr;
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseCase, RimEclipseCase_createLgrForCompletions, "createLgrForCompletions" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseCase_createLgrForCompletions::RimEclipseCase_createLgrForCompletions( caf::PdmObjectHandle* self )
: caf::PdmVoidObjectMethod( self )
{
CAF_PDM_InitObject( "Create LGR for Completions",
"",
"",
"Create temporary local grid refinements around the completions of the given well paths" );
CAF_PDM_InitScriptableFieldNoDefault( &m_wellPaths, "WellPaths", "Well Paths", "", "", "Well paths to create LGRs for" );
CAF_PDM_InitScriptableField( &m_timeStep, "TimeStep", 0, "Time Step", "", "", "Zero-based time step index" );
CAF_PDM_InitScriptableField( &m_refinementI, "RefinementI", 1, "Refinement I", "", "", "Number of refined cells in I direction" );
CAF_PDM_InitScriptableField( &m_refinementJ, "RefinementJ", 1, "Refinement J", "", "", "Number of refined cells in J direction" );
CAF_PDM_InitScriptableField( &m_refinementK, "RefinementK", 1, "Refinement K", "", "", "Number of refined cells in K direction" );
CAF_PDM_InitScriptableField( &m_splitType, "SplitType", Lgr::SplitTypeEnum(), "Split Type", "", "", "Defines how to split the LGRs" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createLgrForCompletions::setWellPaths( const std::vector<RimWellPath*>& wellPaths )
{
m_wellPaths.setValue( wellPaths );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createLgrForCompletions::setTimeStep( int timeStep )
{
m_timeStep = timeStep;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createLgrForCompletions::setRefinement( int refinementI, int refinementJ, int refinementK )
{
m_refinementI = refinementI;
m_refinementJ = refinementJ;
m_refinementK = refinementK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createLgrForCompletions::setSplitType( Lgr::SplitType splitType )
{
m_splitType = splitType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RimEclipseCase_createLgrForCompletions::wellsIntersectingOtherLgrs() const
{
return m_wellsIntersectingOtherLgrs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimEclipseCase_createLgrForCompletions::execute()
{
auto* eclipseCase = self<RimEclipseCase>();
if ( !eclipseCase ) return std::unexpected( "No case is available." );
std::vector<RimWellPath*> wellPaths = m_wellPaths.ptrReferencedObjectsByType();
if ( wellPaths.empty() ) return std::unexpected( "No well paths specified." );
if ( m_refinementI() < 1 || m_refinementJ() < 1 || m_refinementK() < 1 )
{
return std::unexpected( "Refinement must be at least 1 in all directions." );
}
auto* feature = dynamic_cast<RicCreateTemporaryLgrFeature*>(
caf::CmdFeatureManager::instance()->getCommandFeature( "RicCreateTemporaryLgrFeature" ) );
if ( !feature ) return std::unexpected( "The create LGR feature is not available." );
RicDeleteTemporaryLgrsFeature::deleteAllTemporaryLgrs( eclipseCase );
cvf::Vec3st lgrCellCounts( m_refinementI(), m_refinementJ(), m_refinementK() );
m_wellsIntersectingOtherLgrs.clear();
feature->createLgrsForWellPaths( wellPaths,
eclipseCase,
m_timeStep(),
lgrCellCounts,
m_splitType(),
{ RigCompletionData::CompletionType::PERFORATION,
RigCompletionData::CompletionType::FRACTURE,
RigCompletionData::CompletionType::FISHBONES },
&m_wellsIntersectingOtherLgrs );
RigReservoirGridTools::refreshEclipseCaseDataAndViews( eclipseCase );
if ( !m_wellsIntersectingOtherLgrs.empty() )
{
RiaLogging::warning( QString( "No LGRs created for some wells due to existing intersecting LGR(s). Affected wells: %1" )
.arg( m_wellsIntersectingOtherLgrs.join( ", " ) )
.toStdString() );
}
return nullptr;
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseCase, RimEclipseCase_exportLgrForCompletions, "exportLgrForCompletions" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseCase_exportLgrForCompletions::RimEclipseCase_exportLgrForCompletions( caf::PdmObjectHandle* self )
: caf::PdmVoidObjectMethod( self )
{
CAF_PDM_InitObject( "Export LGR for Completions",
"",
"",
"Export local grid refinements around the completions of the given well paths to CARFIN files" );
CAF_PDM_InitScriptableFieldNoDefault( &m_wellPaths, "WellPaths", "Well Paths", "", "", "Well paths to export LGRs for" );
CAF_PDM_InitScriptableField( &m_timeStep, "TimeStep", 0, "Time Step", "", "", "Zero-based time step index" );
CAF_PDM_InitScriptableField( &m_exportFolder, "ExportFolder", QString(), "Export Folder", "", "", "Folder to write the export files to" );
CAF_PDM_InitScriptableField( &m_refinementI, "RefinementI", 1, "Refinement I", "", "", "Number of refined cells in I direction" );
CAF_PDM_InitScriptableField( &m_refinementJ, "RefinementJ", 1, "Refinement J", "", "", "Number of refined cells in J direction" );
CAF_PDM_InitScriptableField( &m_refinementK, "RefinementK", 1, "Refinement K", "", "", "Number of refined cells in K direction" );
CAF_PDM_InitScriptableField( &m_splitType, "SplitType", Lgr::SplitTypeEnum(), "Split Type", "", "", "Defines how to split the LGRs" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_exportLgrForCompletions::setWellPaths( const std::vector<RimWellPath*>& wellPaths )
{
m_wellPaths.setValue( wellPaths );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_exportLgrForCompletions::setTimeStep( int timeStep )
{
m_timeStep = timeStep;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_exportLgrForCompletions::setExportFolder( const QString& exportFolder )
{
m_exportFolder = exportFolder;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_exportLgrForCompletions::setRefinement( int refinementI, int refinementJ, int refinementK )
{
m_refinementI = refinementI;
m_refinementJ = refinementJ;
m_refinementK = refinementK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_exportLgrForCompletions::setSplitType( Lgr::SplitType splitType )
{
m_splitType = splitType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList RimEclipseCase_exportLgrForCompletions::wellsIntersectingOtherLgrs() const
{
return m_wellsIntersectingOtherLgrs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimEclipseCase_exportLgrForCompletions::execute()
{
auto* eclipseCase = self<RimEclipseCase>();
if ( !eclipseCase ) return std::unexpected( "No case is available." );
std::vector<RimWellPath*> wellPaths = m_wellPaths.ptrReferencedObjectsByType();
if ( wellPaths.empty() ) return std::unexpected( "No well paths specified." );
if ( m_exportFolder().isEmpty() ) return std::unexpected( "No export folder specified." );
if ( m_refinementI() < 1 || m_refinementJ() < 1 || m_refinementK() < 1 )
{
return std::unexpected( "Refinement must be at least 1 in all directions." );
}
cvf::Vec3st lgrCellCounts( m_refinementI(), m_refinementJ(), m_refinementK() );
m_wellsIntersectingOtherLgrs.clear();
RicExportLgrFeature::exportLgrsForWellPaths( m_exportFolder(),
wellPaths,
eclipseCase,
m_timeStep(),
lgrCellCounts,
m_splitType(),
{ RigCompletionData::CompletionType::PERFORATION,
RigCompletionData::CompletionType::FRACTURE,
RigCompletionData::CompletionType::FISHBONES },
&m_wellsIntersectingOtherLgrs );
if ( !m_wellsIntersectingOtherLgrs.empty() )
{
RiaLogging::warning( QString( "No export for some wells due to existing intersecting LGR(s). Affected wells: %1" )
.arg( m_wellsIntersectingOtherLgrs.join( ", " ) )
.toStdString() );
}
return nullptr;
}
@@ -22,6 +22,7 @@
#include "RiaPorosityModel.h"
#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h"
#include "ExportCommands/RicLgrSplitType.h"
#include "cafAppEnum.h"
#include "cafPdmField.h"
@@ -275,3 +276,68 @@ private:
caf::PdmField<bool> m_includeFishbones;
caf::PdmField<bool> m_includeFractures;
};
//==================================================================================================
/// Create temporary local grid refinements (LGRs) around the completions of the given well paths.
/// Existing temporary LGRs in the case are deleted first.
//==================================================================================================
class RimEclipseCase_createLgrForCompletions : public caf::PdmVoidObjectMethod
{
CAF_PDM_HEADER_INIT;
public:
RimEclipseCase_createLgrForCompletions( caf::PdmObjectHandle* self );
void setWellPaths( const std::vector<RimWellPath*>& wellPaths );
void setTimeStep( int timeStep );
void setRefinement( int refinementI, int refinementJ, int refinementK );
void setSplitType( Lgr::SplitType splitType );
std::expected<caf::PdmObjectHandle*, QString> execute() override;
/// Wells skipped because they intersect existing LGRs. Valid after execute().
QStringList wellsIntersectingOtherLgrs() const;
private:
caf::PdmPtrArrayField<RimWellPath*> m_wellPaths;
caf::PdmField<int> m_timeStep;
caf::PdmField<int> m_refinementI;
caf::PdmField<int> m_refinementJ;
caf::PdmField<int> m_refinementK;
caf::PdmField<Lgr::SplitTypeEnum> m_splitType;
QStringList m_wellsIntersectingOtherLgrs;
};
//==================================================================================================
/// Export local grid refinements (LGRs) around the completions of the given well paths to CARFIN files.
//==================================================================================================
class RimEclipseCase_exportLgrForCompletions : public caf::PdmVoidObjectMethod
{
CAF_PDM_HEADER_INIT;
public:
RimEclipseCase_exportLgrForCompletions( caf::PdmObjectHandle* self );
void setWellPaths( const std::vector<RimWellPath*>& wellPaths );
void setTimeStep( int timeStep );
void setExportFolder( const QString& exportFolder );
void setRefinement( int refinementI, int refinementJ, int refinementK );
void setSplitType( Lgr::SplitType splitType );
std::expected<caf::PdmObjectHandle*, QString> execute() override;
/// Wells skipped because they intersect existing LGRs. Valid after execute().
QStringList wellsIntersectingOtherLgrs() const;
private:
caf::PdmPtrArrayField<RimWellPath*> m_wellPaths;
caf::PdmField<int> m_timeStep;
caf::PdmField<QString> m_exportFolder;
caf::PdmField<int> m_refinementI;
caf::PdmField<int> m_refinementJ;
caf::PdmField<int> m_refinementK;
caf::PdmField<Lgr::SplitTypeEnum> m_splitType;
QStringList m_wellsIntersectingOtherLgrs;
};
+7
View File
@@ -584,7 +584,14 @@ def create_lgr_for_completion(
"LGR_PER_COMPLETION" | One LGR for each completion (fracture, perforation, ...)
"LGR_PER_WELL" | One LGR for each well
Deprecated: use Reservoir.create_lgr_for_completions(well_paths=[...], ...) instead, which takes
WellPath objects.
"""
warnings.warn(
"Case.create_lgr_for_completion() is deprecated, use Reservoir.create_lgr_for_completions() instead",
DeprecationWarning,
stacklevel=3,
)
if isinstance(well_path_names, str):
well_path_names = [well_path_names]
return self._execute_command(