#14772 Python: Add Reservoir.create_multiple_fractures as object method and forward createMultipleFractures to it

RimEclipseCase_createMultipleFractures takes WellPath objects and a
FractureTemplate object instead of names and ids. The
MultipleFractures::Action enum is moved from the Ricf header to
RicCreateMultipleFracturesFeature.h so the object method does not
depend on CommandFileInterface, and is registered as the Python
StrEnum MultipleFracturesAction.

Add RicfForwarding::findFractureTemplate(). RicfCreateMultipleFractures
resolves names/ids and forwards to the object method.

The hand-written Case.create_multiple_fractures(template_id=...,
well_path_names=...) Python wrapper is removed: the generated
Reservoir method has the same name and shadows it. The test is updated
to the object based signature.
This commit is contained in:
Kristian Bendiksen committed 2026-09-22 14:19:23 +02:00
1 parent afa816826b
commit 6e3e6e738f
10 files changed
+330 -194

No files matched your search

@@ -23,6 +23,7 @@
#include "Rim3dView.h"
#include "RimCase.h"
#include "RimEclipseResultCase.h"
#include "RimFractureTemplate.h"
#include "RimProject.h"
#include "cafPdmObjectHandle.h"
@@ -85,6 +86,22 @@ std::expected<Rim3dView*, QString> RicfForwarding::findView( int viewId )
return std::unexpected( QString( "Could not find view with ID %1" ).arg( viewId ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<RimFractureTemplate*, QString> RicfForwarding::findFractureTemplate( int templateId )
{
RimProject* project = RimProject::current();
if ( !project ) return std::unexpected( "No project is available." );
for ( RimFractureTemplate* fractureTemplate : project->allFractureTemplates() )
{
if ( fractureTemplate && fractureTemplate->id() == templateId ) return fractureTemplate;
}
return std::unexpected( QString( "Could not find fracture template with ID %1" ).arg( templateId ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -26,6 +26,7 @@
class RimCase;
class Rim3dView;
class RimFractureTemplate;
namespace caf
{
@@ -48,6 +49,9 @@ std::expected<Rim3dView*, QString> findView( RimCase* rimCase, int viewId );
/// Find a 3D view by id anywhere in the project. A negative id is not accepted.
std::expected<Rim3dView*, QString> findView( int viewId );
/// Find a fracture template by id.
std::expected<RimFractureTemplate*, QString> findFractureTemplate( int templateId );
/// Convert the result of a Rimc method execution to a script response, logging errors with the command name.
caf::PdmScriptResponse toScriptResponse( const std::expected<caf::PdmObjectHandle*, QString>& result, const QString& commandName );
@@ -19,41 +19,17 @@
#include "RicfCreateMultipleFractures.h"
#include "RicfApplicationTools.h"
#include "RicfCommandFileExecutor.h"
#include "RicfCommandForwarding.h"
#include "FractureCommands/RicCreateMultipleFracturesFeature.h"
#include "FractureCommands/RicCreateMultipleFracturesOptionItemUi.h"
#include "FractureCommands/RicCreateMultipleFracturesUi.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 "RiaLogging.h"
#include "RiaQStringFormatter.h"
#include "RiaWellNameComparer.h"
#include "cafCmdFeatureManager.h"
#include "cafPdmFieldScriptingCapability.h"
CAF_PDM_SOURCE_INIT( RicfCreateMultipleFractures, "createMultipleFractures" );
namespace caf
{
template <>
void AppEnum<MultipleFractures::Action>::setUp()
{
addItem( MultipleFractures::Action::APPEND_FRACTURES, "APPEND_FRACTURES", "Append Fractures" );
addItem( MultipleFractures::Action::REPLACE_FRACTURES, "REPLACE_FRACTURES", "Replace Fractures" );
setDefault( MultipleFractures::Action::NONE );
}
} // namespace caf
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -78,110 +54,43 @@ RicfCreateMultipleFractures::RicfCreateMultipleFractures()
//--------------------------------------------------------------------------------------------------
caf::PdmScriptResponse RicfCreateMultipleFractures::execute()
{
using TOOLS = RicfApplicationTools;
const QString commandName = classKeyword();
RimProject* project = RimProject::current();
RiuCreateMultipleFractionsUi* settings = project->dialogData()->multipleFractionsData();
// Get case and fracture template
auto gridCase = TOOLS::caseFromId( m_caseId );
auto fractureTemplate = fractureTemplateFromId( m_templateId );
std::vector<RimWellPath*> wellPaths;
// Find well paths
if ( m_caseId() < 0 || m_templateId() < 0 )
{
QStringList wellsNotFound;
wellPaths = TOOLS::wellPathsFromNames( TOOLS::toQStringList( m_wellPathNames ), &wellsNotFound );
if ( !wellsNotFound.empty() )
{
QString error = QString( "createMultipleFractures: These well paths were not found: %1" ).arg( wellsNotFound.join( ", " ) );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
return RicfForwarding::errorResponse( "Mandatory argument(s) missing: caseId and templateId are required", commandName );
}
if ( !gridCase )
QStringList wellsNotFound;
std::vector<RimWellPath*> wellPaths =
RicfApplicationTools::wellPathsFromNames( RicfApplicationTools::toQStringList( m_wellPathNames ), &wellsNotFound );
if ( !wellsNotFound.empty() )
{
QString error = QString( "createMultipleFractures: Could not find case with ID %1" ).arg( m_caseId() );
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 wellpaths 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 ( !fractureTemplate )
{
QString error = QString( "createMultipleFractures: Could not find fracture template with ID %1" ).arg( m_templateId() );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
auto fractureTemplate = RicfForwarding::findFractureTemplate( m_templateId() );
if ( !fractureTemplate ) return RicfForwarding::errorResponse( fractureTemplate.error(), commandName );
if ( wellPaths.empty() )
{
QString error( "createMultipleFractures: No wellpaths found" );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
RimEclipseCase_createMultipleFractures method( eclipseCase );
method.setWellPaths( wellPaths );
method.setFractureTemplate( fractureTemplate.value() );
method.setMinDistFromWellTd( m_minDistFromWellTd() );
method.setMaxFracturesPerWell( m_maxFracturesPerWell() );
method.setTopLayer( m_topLayer() );
method.setBaseLayer( m_baseLayer() );
method.setSpacing( m_spacing() );
method.setAction( m_action() );
if ( !validateArguments() )
{
QString error( "createMultipleFractures: Mandatory argument(s) missing" );
RiaLogging::error( error.toStdString() );
return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error );
}
RicCreateMultipleFracturesOptionItemUi* options = new RicCreateMultipleFracturesOptionItemUi();
caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance();
auto feature =
dynamic_cast<RicCreateMultipleFracturesFeature*>( commandManager->getCommandFeature( "RicCreateMultipleFracturesFeature" ) );
// Default layers
int topLayer = m_topLayer;
int baseLayer = m_baseLayer;
if ( feature && ( topLayer < 0 || baseLayer < 0 ) )
{
auto ijkRange = feature->ijkRangeForGrid( gridCase );
if ( topLayer < 0 ) topLayer = static_cast<int>( ijkRange.min().z() );
if ( baseLayer < 0 ) baseLayer = static_cast<int>( ijkRange.max().z() );
}
options->setValues( topLayer, baseLayer, fractureTemplate, m_spacing );
settings->clearWellPaths();
for ( auto wellPath : wellPaths )
{
settings->addWellPath( wellPath );
}
settings->setValues( gridCase, m_minDistFromWellTd, m_maxFracturesPerWell );
settings->clearOptions();
settings->insertOptionItem( nullptr, options );
if ( feature )
{
if ( m_action == MultipleFractures::Action::APPEND_FRACTURES ) feature->appendFractures();
if ( m_action == MultipleFractures::Action::REPLACE_FRACTURES ) feature->replaceFractures();
}
return caf::PdmScriptResponse();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicfCreateMultipleFractures::validateArguments() const
{
bool valid = m_caseId >= 0 && m_templateId >= 0;
return valid;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimFractureTemplate* RicfCreateMultipleFractures::fractureTemplateFromId( int templateId ) const
{
for ( RimFractureTemplate* t : RimProject::current()->allFractureTemplates() )
{
if ( t->id() == templateId ) return t;
}
RiaLogging::error( std::format( "createMultipleFractures: Could not find fracture template with ID {}", templateId ) );
return nullptr;
return RicfForwarding::toScriptResponse( method.execute(), commandName );
}
@@ -20,18 +20,10 @@
#include "RicfCommandObject.h"
#include "FractureCommands/RicCreateMultipleFracturesFeature.h"
#include "cafAppEnum.h"
#include "cafPdmField.h"
namespace MultipleFractures
{
enum class Action
{
NONE,
APPEND_FRACTURES,
REPLACE_FRACTURES
};
}
#include "cafPdmField.h"
class RimEclipseCase;
class RimFractureTemplate;
@@ -52,9 +44,6 @@ public:
caf::PdmScriptResponse execute() override;
private:
bool validateArguments() const;
RimFractureTemplate* fractureTemplateFromId( int templateId ) const;
caf::PdmField<int> m_caseId;
caf::PdmField<std::vector<QString>> m_wellPathNames;
caf::PdmField<double> m_minDistFromWellTd;
@@ -17,10 +17,14 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RicCreateMultipleFracturesFeature.h"
#include "RicFractureNameGenerator.h"
#include "RiaApplication.h"
#include "cafAppEnum.h"
#include "cafPdmScriptEnumNameRegistry.h"
#include "RicCreateMultipleFracturesUi.h"
#include "RigActiveCellInfo.h"
@@ -45,6 +49,28 @@
#include <QAction>
#include <QPushButton>
namespace caf
{
template <>
void AppEnum<MultipleFractures::Action>::setUp()
{
addItem( MultipleFractures::Action::APPEND_FRACTURES, "APPEND_FRACTURES", "Append Fractures" );
addItem( MultipleFractures::Action::REPLACE_FRACTURES, "REPLACE_FRACTURES", "Replace Fractures" );
setDefault( MultipleFractures::Action::NONE );
}
} // namespace caf
namespace
{
// Pin the Python StrEnum class name for the action used by RimEclipseCase_createMultipleFractures
struct RegisterScriptEnumNames
{
RegisterScriptEnumNames() { caf::PdmScriptEnumNameRegistry::registerName<MultipleFractures::Action>( "MultipleFracturesAction" ); }
};
const RegisterScriptEnumNames s_registerScriptEnumNames;
} // namespace
CAF_CMD_SOURCE_INIT( RicCreateMultipleFracturesFeature, "RicCreateMultipleFracturesFeature" );
//--------------------------------------------------------------------------------------------------
@@ -29,6 +29,16 @@
class RiuCreateMultipleFractionsUi;
class RimEclipseCase;
namespace MultipleFractures
{
enum class Action
{
NONE,
APPEND_FRACTURES,
REPLACE_FRACTURES
};
}
namespace caf
{
class PdmUiPropertyViewDialog;
@@ -27,6 +27,8 @@
#include "CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h"
#include "ExportCommands/RicEclipseCellResultToFileImpl.h"
#include "ExportCommands/RicExportLgrFeature.h"
#include "FractureCommands/RicCreateMultipleFracturesOptionItemUi.h"
#include "FractureCommands/RicCreateMultipleFracturesUi.h"
#include "RicCreateTemporaryLgrFeature.h"
#include "RicDeleteTemporaryLgrsFeature.h"
@@ -47,8 +49,10 @@
#include "RimCase.h"
#include "RimCellFilter.h"
#include "RimDialogData.h"
#include "RimEclipseCase.h"
#include "RimEclipseResultCase.h"
#include "RimFractureTemplate.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimRoffCase.h"
@@ -1166,3 +1170,157 @@ std::expected<caf::PdmObjectHandle*, QString> RimEclipseCase_exportLgrForComplet
return nullptr;
}
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseCase, RimEclipseCase_createMultipleFractures, "createMultipleFractures" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseCase_createMultipleFractures::RimEclipseCase_createMultipleFractures( caf::PdmObjectHandle* self )
: caf::PdmVoidObjectMethod( self )
{
CAF_PDM_InitObject( "Create Multiple Fractures", "", "", "Create multiple fractures along the given well paths using a fracture template" );
CAF_PDM_InitScriptableFieldNoDefault( &m_wellPaths, "WellPaths", "Well Paths", "", "", "Well paths to create fractures for" );
CAF_PDM_InitScriptableFieldNoDefault( &m_fractureTemplate, "FractureTemplate", "Fracture Template", "", "", "Template used for the created fractures" );
CAF_PDM_InitScriptableField( &m_minDistFromWellTd,
"MinDistFromWellTd",
100.0,
"Min Distance From Well TD",
"",
"",
"Minimum distance from the well total depth" );
CAF_PDM_InitScriptableField( &m_maxFracturesPerWell, "MaxFracturesPerWell", 100, "Max Fractures per Well" );
CAF_PDM_InitScriptableField( &m_topLayer, "TopLayer", -1, "Top Layer", "", "", "Zero-based K index of the top layer. -1 uses the top of the grid." );
CAF_PDM_InitScriptableField( &m_baseLayer,
"BaseLayer",
-1,
"Base Layer",
"",
"",
"Zero-based K index of the base layer. -1 uses the bottom of the grid." );
CAF_PDM_InitScriptableField( &m_spacing, "Spacing", 300.0, "Spacing", "", "", "Distance between fractures" );
CAF_PDM_InitScriptableField( &m_action,
"Action",
caf::AppEnum<MultipleFractures::Action>( MultipleFractures::Action::APPEND_FRACTURES ),
"Action",
"",
"",
"Append to or replace the existing fractures on the well paths" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setWellPaths( const std::vector<RimWellPath*>& wellPaths )
{
m_wellPaths.setValue( wellPaths );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setFractureTemplate( RimFractureTemplate* fractureTemplate )
{
m_fractureTemplate = fractureTemplate;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setMinDistFromWellTd( double minDist )
{
m_minDistFromWellTd = minDist;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setMaxFracturesPerWell( int maxFractures )
{
m_maxFracturesPerWell = maxFractures;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setTopLayer( int topLayer )
{
m_topLayer = topLayer;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setBaseLayer( int baseLayer )
{
m_baseLayer = baseLayer;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setSpacing( double spacing )
{
m_spacing = spacing;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimEclipseCase_createMultipleFractures::setAction( MultipleFractures::Action action )
{
m_action = action;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimEclipseCase_createMultipleFractures::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." );
RimFractureTemplate* fractureTemplate = m_fractureTemplate();
if ( !fractureTemplate ) return std::unexpected( "No fracture template specified." );
if ( m_action() == MultipleFractures::Action::NONE ) return std::unexpected( "Action must be APPEND_FRACTURES or REPLACE_FRACTURES." );
auto* feature = dynamic_cast<RicCreateMultipleFracturesFeature*>(
caf::CmdFeatureManager::instance()->getCommandFeature( "RicCreateMultipleFracturesFeature" ) );
if ( !feature ) return std::unexpected( "The create multiple fractures feature is not available." );
RimProject* project = RimProject::current();
RiuCreateMultipleFractionsUi* settings = project->dialogData()->multipleFractionsData();
// Default layers
int topLayer = m_topLayer();
int baseLayer = m_baseLayer();
if ( topLayer < 0 || baseLayer < 0 )
{
auto ijkRange = feature->ijkRangeForGrid( eclipseCase );
if ( topLayer < 0 ) topLayer = static_cast<int>( ijkRange.min().z() );
if ( baseLayer < 0 ) baseLayer = static_cast<int>( ijkRange.max().z() );
}
auto* options = new RicCreateMultipleFracturesOptionItemUi();
options->setValues( topLayer, baseLayer, fractureTemplate, m_spacing() );
settings->clearWellPaths();
for ( RimWellPath* wellPath : wellPaths )
{
settings->addWellPath( wellPath );
}
settings->setValues( eclipseCase, m_minDistFromWellTd(), m_maxFracturesPerWell() );
settings->clearOptions();
settings->insertOptionItem( nullptr, options );
if ( m_action() == MultipleFractures::Action::APPEND_FRACTURES ) feature->appendFractures();
if ( m_action() == MultipleFractures::Action::REPLACE_FRACTURES ) feature->replaceFractures();
return nullptr;
}
@@ -23,6 +23,7 @@
#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h"
#include "ExportCommands/RicLgrSplitType.h"
#include "FractureCommands/RicCreateMultipleFracturesFeature.h"
#include "cafAppEnum.h"
#include "cafPdmField.h"
@@ -34,6 +35,7 @@
#include <QString>
class RimCellFilter;
class RimFractureTemplate;
class RimWellPath;
//==================================================================================================
@@ -341,3 +343,35 @@ private:
QStringList m_wellsIntersectingOtherLgrs;
};
//==================================================================================================
/// Create multiple fractures along the given well paths using a fracture template.
//==================================================================================================
class RimEclipseCase_createMultipleFractures : public caf::PdmVoidObjectMethod
{
CAF_PDM_HEADER_INIT;
public:
RimEclipseCase_createMultipleFractures( caf::PdmObjectHandle* self );
void setWellPaths( const std::vector<RimWellPath*>& wellPaths );
void setFractureTemplate( RimFractureTemplate* fractureTemplate );
void setMinDistFromWellTd( double minDist );
void setMaxFracturesPerWell( int maxFractures );
void setTopLayer( int topLayer );
void setBaseLayer( int baseLayer );
void setSpacing( double spacing );
void setAction( MultipleFractures::Action action );
std::expected<caf::PdmObjectHandle*, QString> execute() override;
private:
caf::PdmPtrArrayField<RimWellPath*> m_wellPaths;
caf::PdmPtrField<RimFractureTemplate*> m_fractureTemplate;
caf::PdmField<double> m_minDistFromWellTd;
caf::PdmField<int> m_maxFracturesPerWell;
caf::PdmField<int> m_topLayer;
caf::PdmField<int> m_baseLayer;
caf::PdmField<double> m_spacing;
caf::PdmField<caf::AppEnum<MultipleFractures::Action>> m_action;
};
-46
View File
@@ -506,52 +506,6 @@ def export_msw(self, well_path: str) -> Any:
)
@add_method(Case)
def create_multiple_fractures(
self,
template_id: int,
well_path_names: Union[str, List[str]],
min_dist_from_well_td: float,
max_fractures_per_well: int,
top_layer: int,
base_layer: int,
spacing: float,
action: str,
) -> Any:
"""
Create Multiple Fractures in one go
**Parameters**::
Parameter | Description | Type
-----------------------| ----------------------------------------- | -----
template_id | Id of the template | Integer
well_path_names | List of well path names | List of Strings
min_dist_from_well_td | Minimum distance from well TD | Double
max_fractures_per_well | Max number of fractures per well | Integer
top_layer | Top grid k-level for fractures | Integer
base_layer | Base grid k-level for fractures | Integer
spacing | Spacing between fractures | Double
action | 'APPEND_FRACTURES' or 'REPLACE_FRACTURES' | String enum
"""
if isinstance(well_path_names, str):
well_path_names = [well_path_names]
return self._execute_command(
createMultipleFractures=Cmd.CreateMultipleFracRequest(
caseId=self.id,
templateId=template_id,
wellPathNames=well_path_names,
minDistFromWellTd=min_dist_from_well_td,
maxFracturesPerWell=max_fractures_per_well,
topLayer=top_layer,
baseLayer=base_layer,
spacing=spacing,
action=action,
)
)
@add_method(Case)
def create_lgr_for_completion(
self,
@@ -75,26 +75,61 @@ def test_create_and_export_lgr_for_completions(rips_instance, initialize_test):
def test_create_multiple_fractures(rips_instance, initialize_test):
case = rips_instance.project.load_case(
dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID"
project = rips_instance.project.open(
dataroot.PATH + "/TEST10K_FLT_LGR_NNC/small-completion-export-fractures.rsp"
)
well_files = [dataroot.PATH + "/TEST10K_FLT_LGR_NNC/wellpath_a.dev"]
rips_instance.project.import_well_paths(well_path_files=well_files)
fracture_instances = rips_instance.project.descendants(rips.WellPathFracture)
assert len(fracture_instances) == 0
case = project.cases()[0]
template = project.descendants(rips.FractureTemplate)[0]
well_path = project.well_paths()[0]
case.create_multiple_fractures(
template_id=0,
well_path_names="Well Path A",
well_paths=[well_path],
fracture_template=template,
min_dist_from_well_td=100.0,
max_fractures_per_well=5,
top_layer=1,
base_layer=30,
spacing=100.0,
action="REPLACE_FRACTURES",
action=rips.MultipleFracturesAction.REPLACE_FRACTURES,
)
fracture_instances = rips_instance.project.descendants(rips.WellPathFracture)
fracture_instances = project.descendants(rips.WellPathFracture)
assert len(fracture_instances) > 0
def test_create_multiple_fractures_object_method(rips_instance, initialize_test):
project = rips_instance.project.open(
dataroot.PATH + "/TEST10K_FLT_LGR_NNC/small-completion-export-fractures.rsp"
)
case = project.cases()[0]
template = project.descendants(rips.FractureTemplate)[0]
well_paths = project.well_paths()
assert len(well_paths) > 0
before = len(project.descendants(rips.WellPathFracture))
case.create_multiple_fractures(
well_paths=well_paths[:1],
fracture_template=template,
min_dist_from_well_td=100.0,
max_fractures_per_well=3,
spacing=100.0,
action=rips.MultipleFracturesAction.APPEND_FRACTURES,
)
after_append = len(project.descendants(rips.WellPathFracture))
assert after_append > before
case.create_multiple_fractures(
well_paths=well_paths[:1],
fracture_template=template,
max_fractures_per_well=1,
spacing=100.0,
action=rips.MultipleFracturesAction.REPLACE_FRACTURES,
)
after_replace = len(project.descendants(rips.WellPathFracture))
assert after_replace < after_append
with pytest.raises(rips.RipsError):
case.create_multiple_fractures(well_paths=well_paths[:1])
with pytest.raises(rips.RipsError):
case.create_multiple_fractures(fracture_template=template)