From da69c1f0499b9ff7749e2341d211d68679a5f8c3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 10 Jan 2025 18:25:46 +0100 Subject: [PATCH] Python: Enforce checking on script name to make sure conversion between camelCase and snake_case works correctly * #12044 Python: Add Non-Darcy properties available in Python * #12049 Python: Add checking for multiple consecutive upper case letters The scripting keyword is transformed to snake_case for use in Python. When data in Python is sent back to ResInsight, the opposite operation happens. This concept works well for most variants of keywords, but there are some corner cases that is not working. Add compile time checking to make sure that the scripting keywords are formatted correctly. Fix keyword that has been formatted the wrong way and has never worked. * Avoid running test if ResInsight executable path is not defined in env * Make sure dash is allowed in enumeration text string --- .../RicfExportWellPathCompletions.cpp | 15 ++- .../Completions/RimFractureTemplate.cpp | 59 ++++----- .../RimWellPathCompletionSettings.cpp | 12 +- .../ProjectDataModel/RimWbsParameters.cpp | 68 +++++++--- .../cafPdmFieldScriptingCapability.h | 75 ++++++++++- .../rips/tests/test_create_well_path.py | 45 ------- .../Python/rips/tests/test_launch.py | 13 ++ .../rips/tests/test_wells_path_completions.py | 118 ++++++++++++++++++ GrpcInterface/RiaGrpcServiceInterface.cpp | 23 +++- 9 files changed, 327 insertions(+), 101 deletions(-) diff --git a/ApplicationLibCode/CommandFileInterface/RicfExportWellPathCompletions.cpp b/ApplicationLibCode/CommandFileInterface/RicfExportWellPathCompletions.cpp index 321a441f8d..3ddc780787 100644 --- a/ApplicationLibCode/CommandFileInterface/RicfExportWellPathCompletions.cpp +++ b/ApplicationLibCode/CommandFileInterface/RicfExportWellPathCompletions.cpp @@ -66,11 +66,16 @@ RicfExportWellPathCompletions::RicfExportWellPathCompletions() CAF_PDM_InitScriptableField( &m_performTransScaling, "performTransScaling", false, "Perform Transmissibility Scaling" ); CAF_PDM_InitScriptableField( &m_transScalingTimeStep, "transScalingTimeStep", 0, "Transmissibility Scaling Pressure Time Step" ); - CAF_PDM_InitScriptableField( &m_transScalingInitialWBHP, - "transScalingWBHPFromSummary", - RicExportCompletionDataSettingsUi::TransScalingWBHPSource(), - "Transmissibility Scaling WBHP from summary" ); - CAF_PDM_InitScriptableField( &m_transScalingWBHP, "transScalingWBHP", 200.0, "Transmissibility Scaling Constant WBHP Value" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_transScalingInitialWBHP, + "transScalingWBHPFromSummary", + "transScalingWbhpFromSummary", + RicExportCompletionDataSettingsUi::TransScalingWBHPSource(), + "Transmissibility Scaling WBHP from summary" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_transScalingWBHP, + "transScalingWBHP", + "transScalingWbhp", + 200.0, + "Transmissibility Scaling Constant WBHP Value" ); CAF_PDM_InitScriptableField( &m_exportDataSourceAsComments, "exportComments", true, "Export Data Source as Comments" ); CAF_PDM_InitScriptableField( &m_exportWelspec, "exportWelspec", true, "Export WELSPEC keyword" ); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimFractureTemplate.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimFractureTemplate.cpp index 2083b5811e..1e3effd0d4 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimFractureTemplate.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimFractureTemplate.cpp @@ -156,34 +156,37 @@ RimFractureTemplate::RimFractureTemplate() m_fractureContainment.uiCapability()->setUiTreeChildrenHidden( true ); // Non-Darcy Flow options - CAF_PDM_InitFieldNoDefault( &m_nonDarcyFlowType, "NonDarcyFlowType", "Non-Darcy Flow" ); - - CAF_PDM_InitField( &m_userDefinedDFactor, "UserDefinedDFactor", 1.0, "D Factor" ); - - CAF_PDM_InitFieldNoDefault( &m_fractureWidthType, "FractureWidthType", "Type" ); - CAF_PDM_InitField( &m_fractureWidth, "FractureWidth", 0.01, "Fracture Width (h)" ); - - CAF_PDM_InitFieldNoDefault( &m_betaFactorType, "BetaFactorType", "Type" ); - CAF_PDM_InitField( &m_inertialCoefficient, "InertialCoefficient", 0.006083236, "Inertial Coefficient (β) [Forch. unit]" ); - - CAF_PDM_InitFieldNoDefault( &m_permeabilityType, "PermeabilityType", "Type" ); - CAF_PDM_InitField( &m_relativePermeability, "RelativePermeability", 1.0, "Relative Permeability" ); - CAF_PDM_InitField( &m_userDefinedEffectivePermeability, "EffectivePermeability", 0.0, "Effective Permeability (Ke) [mD]" ); - - CAF_PDM_InitField( &m_relativeGasDensity, - "RelativeGasDensity", - 0.8, - "Relative Gas Density (γ)", - "", - "Relative density of gas at surface conditions with respect to air at STP", - "" ); - CAF_PDM_InitField( &m_gasViscosity, - "GasViscosity", - 0.02, - "Gas Viscosity (μ) [cP]", - "", - "Gas viscosity at bottom hole pressure", - "" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_nonDarcyFlowType, "NonDarcyFlowType", "Non-Darcy Flow" ); + + CAF_PDM_InitScriptableField( &m_userDefinedDFactor, "UserDefinedDFactor", 1.0, "D Factor" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_fractureWidthType, "FractureWidthType", "Type" ); + CAF_PDM_InitScriptableField( &m_fractureWidth, "FractureWidth", 0.01, "Fracture Width (h)" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_betaFactorType, "BetaFactorType", "Type" ); + CAF_PDM_InitScriptableField( &m_inertialCoefficient, + "InertialCoefficient", + 0.006083236, + "Inertial Coefficient (β) [Forch. unit]" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_permeabilityType, "PermeabilityType", "Type" ); + CAF_PDM_InitScriptableField( &m_relativePermeability, "RelativePermeability", 1.0, "Relative Permeability" ); + CAF_PDM_InitScriptableField( &m_userDefinedEffectivePermeability, "EffectivePermeability", 0.0, "Effective Permeability (Ke) [mD]" ); + + CAF_PDM_InitScriptableField( &m_relativeGasDensity, + "RelativeGasDensity", + 0.8, + "Relative Gas Density (γ)", + "", + "Relative density of gas at surface conditions with respect to air at STP", + "" ); + CAF_PDM_InitScriptableField( &m_gasViscosity, + "GasViscosity", + 0.02, + "Gas Viscosity (μ) [cP]", + "", + "Gas viscosity at bottom hole pressure", + "" ); CAF_PDM_InitFieldNoDefault( &m_dFactorDisplayField, "dFactorDisplayField", "D Factor" ); m_dFactorDisplayField.registerGetMethod( this, &RimFractureTemplate::dFactorForTemplate ); diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp index 91e75108ff..91eff5015c 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimWellPathCompletionSettings.cpp @@ -88,11 +88,19 @@ RimWellPathCompletionSettings::RimWellPathCompletionSettings() CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_groupName, "WellGroupNameForExport", "GroupNameForExport", QString(), "Group Name" ); CAF_PDM_InitScriptableField( &m_referenceDepth, "ReferenceDepthForExport", QString(), "Reference Depth for BHP" ); CAF_PDM_InitScriptableFieldNoDefault( &m_preferredFluidPhase, "WellTypeForExport", "Preferred Fluid Phase" ); - CAF_PDM_InitScriptableField( &m_drainageRadiusForPI, "DrainageRadiusForPI", QString( "0.0" ), "Drainage Radius for PI" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_drainageRadiusForPI, + "DrainageRadiusForPI", + "DrainageRadiusForPi", + QString( "0.0" ), + "Drainage Radius for PI" ); CAF_PDM_InitScriptableFieldNoDefault( &m_gasInflowEquation, "GasInflowEq", "Gas Inflow Equation" ); CAF_PDM_InitScriptableFieldNoDefault( &m_automaticWellShutIn, "AutoWellShutIn", "Automatic well shut-in" ); CAF_PDM_InitScriptableField( &m_allowWellCrossFlow, "AllowWellCrossFlow", true, "Allow Well Cross-Flow" ); - CAF_PDM_InitScriptableField( &m_wellBoreFluidPVTTable, "WellBoreFluidPVTTable", 0, "Wellbore Fluid PVT table" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_wellBoreFluidPVTTable, + "WellBoreFluidPVTTable", + "WellBoreFluidPvtTable", + 0, + "Wellbore Fluid PVT table" ); CAF_PDM_InitScriptableFieldNoDefault( &m_hydrostaticDensity, "HydrostaticDensity", "Hydrostatic Density" ); CAF_PDM_InitScriptableField( &m_fluidInPlaceRegion, "FluidInPlaceRegion", 0, "Fluid In-Place Region" ); diff --git a/ApplicationLibCode/ProjectDataModel/RimWbsParameters.cpp b/ApplicationLibCode/ProjectDataModel/RimWbsParameters.cpp index 5b644a9add..8f6c1210a7 100644 --- a/ApplicationLibCode/ProjectDataModel/RimWbsParameters.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimWbsParameters.cpp @@ -51,26 +51,49 @@ RimWbsParameters::RimWbsParameters() "", "Data source for Non-Reservoir Pore Pressure", "" ); - CAF_PDM_InitScriptableField( &m_userDefinedPPShale, "UserPPNonReservoir", 1.0, " Multiplier of hydrostatic PP" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_userDefinedPPShale, + "UserPPNonReservoir", + "UserPpNonReservoir", + 1.0, + " Multiplier of hydrostatic PP" ); CAF_PDM_InitScriptableFieldNoDefault( &m_poissonRatioSource, "PoissionRatioSource", "Poisson Ratio", "", "Data source for Poisson Ratio", "" ); CAF_PDM_InitScriptableFieldNoDefault( &m_ucsSource, "UcsSource", "Uniaxial Compressive Strength", "", "Data source for UCS", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_OBG0Source, "OBG0Source", "Initial Overburden Gradient", "", "Data source for OBG0", "" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_DFSource, "DFSource", "Depletion Factor (DF)", "", "Data source for Depletion Factor", "" ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_K0SHSource, - "K0SHSource", - "K0_SH", - "", - "SH from Matthews & Kelly = K0_SH * (OBG0-PP0) + PP0 + DF * " - "(PP-PP0)\nK0_SH = " - "(SH - PP)/(OBG-PP)", - "" ); - - CAF_PDM_InitScriptableFieldNoDefault( &m_FGShaleSource, "FGShaleSource", "FG in Shale Calculation" ); - CAF_PDM_InitScriptableFieldNoDefault( &m_K0FGSource, "K0FGSource", "K0_FG", "", "FG in shale = K0_FG * (OBG0-PP0)\nK0_FG = (FG-PP)/(OBG-PP)", "" ); + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_OBG0Source, + "OBG0Source", + "ObgSource", + "Initial Overburden Gradient", + "", + "Data source for OBG0", + "" ); + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_DFSource, + "DFSource", + "DfSource", + "Depletion Factor (DF)", + "", + "Data source for Depletion Factor", + "" ); + + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_K0SHSource, + "K0SHSource", + "KshSource", + "K0_SH", + "", + "SH from Matthews & Kelly = K0_SH * (OBG0-PP0) + PP0 + DF * " + "(PP-PP0)\nK0_SH = " + "(SH - PP)/(OBG-PP)", + "" ); + + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_FGShaleSource, "FGShaleSource", "FgShaleSource", "FG in Shale Calculation" ); + CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_K0FGSource, + "K0FGSource", + "KfgSource", + "K0_FG", + "", + "FG in shale = K0_FG * (OBG0-PP0)\nK0_FG = (FG-PP)/(OBG-PP)", + "" ); CAF_PDM_InitFieldNoDefault( &m_waterDensitySource, "WaterDensitySource", "Water Density" ); m_waterDensitySource.uiCapability()->setUiHidden( true ); @@ -86,10 +109,17 @@ RimWbsParameters::RimWbsParameters() // Typical UCS for Shale is 5 - 100 MPa -> 50 - 1000 bar. CAF_PDM_InitScriptableField( &m_userDefinedUcs, "UserUcs", 100.0, "User Defined UCS [bar]", "", "User Defined UCS [bar]", "" ); - CAF_PDM_InitScriptableField( &m_userDefinedDF, "UserDF", 0.7, "User Defined DF", "", "User Defined Depletion Factor", "" ); - CAF_PDM_InitScriptableField( &m_userDefinedK0FG, "UserK0FG", 0.75, "User Defined K0_FG" ); - CAF_PDM_InitScriptableField( &m_userDefinedK0SH, "UserK0SH", 0.65, "User Defined K0_SH" ); - CAF_PDM_InitScriptableField( &m_FGShaleMultiplier, "FGMultiplier", 1.05, "SH Multiplier for FG in Shale", "", "FG in Shale = Multiplier * SH", "" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_userDefinedDF, "UserDF", "UserDf", 0.7, "User Defined DF", "", "User Defined Depletion Factor", "" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_userDefinedK0FG, "UserK0FG", "UserKfg", 0.75, "User Defined K0_FG" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_userDefinedK0SH, "UserK0SH", "UserKsh", 0.65, "User Defined K0_SH" ); + CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_FGShaleMultiplier, + "FGMultiplier", + "FgMultiplier", + 1.05, + "SH Multiplier for FG in Shale", + "", + "FG in Shale = Multiplier * SH", + "" ); CAF_PDM_InitScriptableField( &m_userDefinedDensity, "WaterDensity", 1.03, "Density of Sea Water [g/cm^3]", "", "Units: g/cm^3", "" ); diff --git a/Fwk/AppFwk/cafPdmScripting/cafPdmFieldScriptingCapability.h b/Fwk/AppFwk/cafPdmScripting/cafPdmFieldScriptingCapability.h index 796dfea3c6..04aafef68c 100644 --- a/Fwk/AppFwk/cafPdmScripting/cafPdmFieldScriptingCapability.h +++ b/Fwk/AppFwk/cafPdmScripting/cafPdmFieldScriptingCapability.h @@ -47,6 +47,75 @@ #include #include +namespace +{ +constexpr bool isUpper( char c ) +{ + return c >= 'A' && c <= 'Z'; +} + +constexpr bool isLower( char c ) +{ + return c >= 'a' && c <= 'z'; +} + +constexpr bool isNumber( char c ) +{ + return c >= '0' && c <= '9'; +} + +constexpr bool isCamelCase( std::string_view str ) +{ + if ( str.empty() ) return false; + + bool hasLower = false; + int prevUpperCount = 0; + + if ( isUpper( str[0] ) || isNumber( str[0] ) ) prevUpperCount++; + + for ( size_t i = 1; i < str.size(); ++i ) + { + if ( isUpper( str[i] ) || isNumber( str[i] ) ) + { + if ( prevUpperCount >= 2 ) + { + // Three consecutive uppercase letters/numbers + return false; + } + prevUpperCount++; + } + else if ( isLower( str[i] ) ) + { + prevUpperCount = 0; + hasLower = true; + } + else + { + // Invalid character + return false; + } + } + + if ( prevUpperCount > 1 ) + { + // Two or more consecutive uppercase letters/numbers at the end + return false; + } + + return hasLower; +} + +} //namespace + +// The scripting system converts from camel case to snake case by inserting an underscore before each uppercase letter. +// When an object is updated in Python, the keyword is converted back to camel case. This operation does not work if +// there are three or more consecutive uppercase letters. +// See PdmPythonGenerator::camelToSnakeCase() +// See snake_to_camel() and camel_to_snake() in pdmObject.py +// Conversion of values from rips object to caf object is done in RiaGrpcServiceInterface::copyPdmObjectFromRipsToCaf +#define CAF_PDM_CheckScriptableKeyword( keyword ) \ + static_assert( isCamelCase( keyword ), "Keyword used for scripting must be in compatible formatted camel casing" ); + #define CAF_PDM_InitScriptableField( field, keyword, default, uiName, ... ) \ { \ std::vector arguments = { __VA_ARGS__ }; \ @@ -64,6 +133,7 @@ iconResourceName, \ caf::PdmAbstractFieldScriptingCapability::helpString( toolTip, keyword ), \ whatsThis ); \ + CAF_PDM_CheckScriptableKeyword( keyword ); \ caf::AddScriptingCapabilityToField( field, keyword ); \ } @@ -83,6 +153,7 @@ iconResourceName, \ caf::PdmAbstractFieldScriptingCapability::helpString( toolTip, keyword ), \ whatsThis ); \ + CAF_PDM_CheckScriptableKeyword( keyword ); \ caf::AddScriptingCapabilityToField( field, keyword ); \ } @@ -103,6 +174,7 @@ iconResourceName, \ caf::PdmAbstractFieldScriptingCapability::helpString( toolTip, scriptKeyword ), \ whatsThis ); \ + CAF_PDM_CheckScriptableKeyword( scriptKeyword ); \ caf::AddScriptingCapabilityToField( field, scriptKeyword ); \ } @@ -122,6 +194,7 @@ iconResourceName, \ caf::PdmAbstractFieldScriptingCapability::helpString( toolTip, scriptKeyword ), \ whatsThis ); \ + CAF_PDM_CheckScriptableKeyword( scriptKeyword ); \ caf::AddScriptingCapabilityToField( field, scriptKeyword ); \ } @@ -196,7 +269,7 @@ struct PdmFieldScriptingCapabilityIOHandler> while ( !inputStream.atEnd() ) { nextChar = errorMessageContainer->peekNextChar( inputStream ); - if ( nextChar.isLetterOrNumber() || nextChar == QChar( '_' ) ) + if ( nextChar.isLetterOrNumber() || nextChar == QChar( '_' ) || nextChar == QChar( '-' ) ) { currentChar = errorMessageContainer->readCharWithLineNumberCount( inputStream ); accumulatedFieldValue += currentChar; diff --git a/GrpcInterface/Python/rips/tests/test_create_well_path.py b/GrpcInterface/Python/rips/tests/test_create_well_path.py index 36fbff133a..2cc866e05e 100644 --- a/GrpcInterface/Python/rips/tests/test_create_well_path.py +++ b/GrpcInterface/Python/rips/tests/test_create_well_path.py @@ -64,48 +64,3 @@ def test_add_well_path_targets(rips_instance, initialize_test): assert target.use_fixed_azimuth == False assert target.azimuth == 0.0 assert target.inclination == 25.6 - - -def test_add_well_path_completions(rips_instance, initialize_test): - well_path_coll = rips_instance.project.descendants(rips.WellPathCollection)[0] - - well_path = well_path_coll.add_new_object(rips.ModeledWellPath) - well_path.name = "test" - well_path.update() - - # Update the completion settings - completions_settings = well_path.completion_settings() - completions_settings.msw_roughness = 12.34 - completions_settings.msw_liner_diameter = 0.2123 - completions_settings.well_name_for_export = "file name" - completions_settings.group_name_for_export = "msj" - completions_settings.well_type_for_export = "GAS" - completions_settings.update() # Commit updates back to ResInsight - - completions_settings_updated = well_path.completion_settings() - assert completions_settings_updated.msw_roughness == 12.34 - assert completions_settings_updated.msw_liner_diameter == 0.2123 - assert completions_settings_updated.well_name_for_export == "file name" - assert completions_settings_updated.group_name_for_export == "msj" - assert completions_settings_updated.well_type_for_export == "GAS" - - msw_settings = well_path.msw_settings() - msw_settings.custom_values_for_lateral = True - msw_settings.enforce_max_segment_length = True - msw_settings.liner_diameter = 20.0 - msw_settings.max_segment_length = 123.05 - msw_settings.pressure_drop = "HFA" - msw_settings.reference_md_type = "UserDefined" - msw_settings.roughness_factor = 1.3 - msw_settings.user_defined_reference_md = 1234.56 - msw_settings.update() - - msw_settings_updated = well_path.msw_settings() - assert msw_settings_updated.custom_values_for_lateral == True - assert msw_settings_updated.enforce_max_segment_length == True - assert msw_settings_updated.liner_diameter == 20.0 - assert msw_settings_updated.max_segment_length == 123.05 - assert msw_settings_updated.pressure_drop == "HFA" - assert msw_settings_updated.reference_md_type == "UserDefined" - assert msw_settings_updated.roughness_factor == 1.3 - assert msw_settings_updated.user_defined_reference_md == 1234.56 diff --git a/GrpcInterface/Python/rips/tests/test_launch.py b/GrpcInterface/Python/rips/tests/test_launch.py index b62f83457c..c65649d3cd 100644 --- a/GrpcInterface/Python/rips/tests/test_launch.py +++ b/GrpcInterface/Python/rips/tests/test_launch.py @@ -14,6 +14,10 @@ def launch_resinsight(sec=1): + resinsight_executable_from_env = os.environ.get("RESINSIGHT_EXECUTABLE") + if resinsight_executable_from_env is None: + print("RESINSIGHT_EXECUTABLE environment variable is not set") + return instance = rips.Instance.launch(console=True, launch_port=0) print(instance.location) @@ -25,6 +29,10 @@ def launch_resinsight(sec=1): def test_launch_sequential(rips_instance, initialize_test): + resinsight_executable_from_env = os.environ.get("RESINSIGHT_EXECUTABLE") + if resinsight_executable_from_env is None: + print("RESINSIGHT_EXECUTABLE environment variable is not set") + return instance_list = [] for i in range(4): rips_instance = rips.Instance.launch(console=True) @@ -36,6 +44,11 @@ def test_launch_sequential(rips_instance, initialize_test): def test_launch_parallell(rips_instance, initialize_test): + resinsight_executable_from_env = os.environ.get("RESINSIGHT_EXECUTABLE") + if resinsight_executable_from_env is None: + print("RESINSIGHT_EXECUTABLE environment variable is not set") + return + process_list = [] instance_count = 10 diff --git a/GrpcInterface/Python/rips/tests/test_wells_path_completions.py b/GrpcInterface/Python/rips/tests/test_wells_path_completions.py index 3b8a95adbb..5a0bff8d8b 100644 --- a/GrpcInterface/Python/rips/tests/test_wells_path_completions.py +++ b/GrpcInterface/Python/rips/tests/test_wells_path_completions.py @@ -23,3 +23,121 @@ def test_10k(rips_instance, initialize_test): well_path_names=["Well-1"], file_split="UNIFIED_FILE", ) + + +def test_add_well_path_completions(rips_instance, initialize_test): + well_path_coll = rips_instance.project.descendants(rips.WellPathCollection)[0] + + well_path = well_path_coll.add_new_object(rips.ModeledWellPath) + well_path.name = "test" + well_path.update() + + # Update the completion settings + completions_settings = well_path.completion_settings() + completions_settings.allow_well_cross_flow = True + completions_settings.auto_well_shut_in = "STOP" + completions_settings.drainage_radius_for_pi = 1.56 + completions_settings.fluid_in_place_region = 99 + completions_settings.gas_inflow_eq = "R-G" + completions_settings.group_name_for_export = "TestGroup" + completions_settings.hydrostatic_density = "AVG" + completions_settings.msw_liner_diameter = 0.12 + completions_settings.msw_roughness = 4.66 + completions_settings.reference_depth_for_export = 1234 + completions_settings.well_bore_fluid_pvt_table = 33 + completions_settings.well_name_for_export = "TestWellName" + completions_settings.well_type_for_export = "LIQUID" + completions_settings.update() # Commit updates back to ResInsight + + completions_settings_updated = well_path.completion_settings() + assert completions_settings_updated.allow_well_cross_flow == True + assert completions_settings_updated.auto_well_shut_in == "STOP" + assert completions_settings_updated.drainage_radius_for_pi == "1.56" + assert completions_settings_updated.fluid_in_place_region == 99 + assert completions_settings_updated.gas_inflow_eq == "R-G" + assert completions_settings_updated.group_name_for_export == "TestGroup" + assert completions_settings_updated.hydrostatic_density == "AVG" + assert completions_settings_updated.msw_liner_diameter == 0.12 + assert completions_settings_updated.msw_roughness == 4.66 + assert completions_settings_updated.reference_depth_for_export == "1234" + assert completions_settings_updated.well_bore_fluid_pvt_table == 33 + assert completions_settings_updated.well_name_for_export == "TestWellName" + assert completions_settings_updated.well_type_for_export == "LIQUID" + + msw_settings = well_path.msw_settings() + msw_settings.custom_values_for_lateral = True + msw_settings.enforce_max_segment_length = True + msw_settings.liner_diameter = 20.0 + msw_settings.max_segment_length = 123.05 + msw_settings.pressure_drop = "HFA" + msw_settings.reference_md_type = "UserDefined" + msw_settings.roughness_factor = 1.3 + msw_settings.user_defined_reference_md = 1234.56 + msw_settings.update() + + msw_settings_updated = well_path.msw_settings() + assert msw_settings_updated.custom_values_for_lateral == True + assert msw_settings_updated.enforce_max_segment_length == True + assert msw_settings_updated.liner_diameter == 20.0 + assert msw_settings_updated.max_segment_length == 123.05 + assert msw_settings_updated.pressure_drop == "HFA" + assert msw_settings_updated.reference_md_type == "UserDefined" + assert msw_settings_updated.roughness_factor == 1.3 + assert msw_settings_updated.user_defined_reference_md == 1234.56 + + +def test_add_well_path_fracture_template(rips_instance, initialize_test): + + # Add test for all properties + # Some properties depend on availablility of other data and is not tested, these tests are commented out + + fracture_template = rips_instance.project.descendants(rips.FractureTemplate)[0] + fracture_template.azimuth_angle = 23.0 + # fracture_template.beta_factor_type = "FractureBetaFactor" + fracture_template.conductivity_factor = 12.5 + fracture_template.conductivity_type = "FiniteConductivity" + fracture_template.d_factor_scale_factor = 1.2 + fracture_template.effective_permeability = 55 + fracture_template.fracture_width = 0.5 + fracture_template.fracture_width_type = "UserDefinedWidth" + fracture_template.gas_viscosity = 0.1 + fracture_template.height_scale_factor = 1.2 + fracture_template.height_scale_factor = 4 + fracture_template.inertial_coefficient = 0.7 + fracture_template.non_darcy_flow_type = "Computed" + fracture_template.orientation = "Azimuth" + fracture_template.perforation_length = 5 + fracture_template.permeability_type = "UserDefinedPermeability" + fracture_template.relative_gas_density = 0.1 + fracture_template.relative_permeability = 0.2 + fracture_template.user_defined_d_factor = 14 + fracture_template.user_defined_perforation_length = True + fracture_template.user_description = "my frac name" + fracture_template.width_scale_factor = 7 + + fracture_template.update() + + fracture_template_updated = rips_instance.project.descendants( + rips.FractureTemplate + )[0] + assert fracture_template_updated.azimuth_angle == 23.0 + # assert fracture_template_updated.beta_factor_type == "FractureBetaFactor" + assert fracture_template_updated.conductivity_factor == 12.5 + assert fracture_template_updated.conductivity_type == "FiniteConductivity" + assert fracture_template_updated.d_factor_scale_factor == 1.2 + assert fracture_template_updated.effective_permeability == 55 + assert fracture_template_updated.fracture_width == 0.5 + assert fracture_template_updated.fracture_width_type == "UserDefinedWidth" + assert fracture_template_updated.gas_viscosity == 0.1 + assert fracture_template_updated.height_scale_factor == 4 + assert fracture_template_updated.inertial_coefficient == 0.7 + assert fracture_template_updated.non_darcy_flow_type == "Computed" + assert fracture_template_updated.orientation == "Azimuth" + assert fracture_template_updated.perforation_length == 5 + assert fracture_template_updated.permeability_type == "UserDefinedPermeability" + assert fracture_template_updated.relative_gas_density == 0.1 + assert fracture_template_updated.relative_permeability == 0.2 + assert fracture_template_updated.user_defined_d_factor == 14 + assert fracture_template_updated.user_defined_perforation_length == True + assert fracture_template_updated.user_description == "my frac name" + assert fracture_template_updated.width_scale_factor == 7 diff --git a/GrpcInterface/RiaGrpcServiceInterface.cpp b/GrpcInterface/RiaGrpcServiceInterface.cpp index 5b87695944..6c72a2bd9f 100644 --- a/GrpcInterface/RiaGrpcServiceInterface.cpp +++ b/GrpcInterface/RiaGrpcServiceInterface.cpp @@ -134,7 +134,28 @@ void RiaGrpcServiceInterface::copyPdmObjectFromRipsToCaf( const rips::PdmObject* auto parametersMap = source->parameters(); - bool printContent = false; // Flag to control debug output to debugger + // Check for duplicate lowercase keywords. If this happens, the script checking in CAF_PDM_CheckScriptableKeyword in + // cafPdmFieldScriptingCapability.h is not working as expected + { + std::set uniqueNames; + + for ( const auto& p : parametersMap ) + { + auto lowerCase = QString::fromStdString( p.first ).toLower(); + if ( uniqueNames.count( lowerCase ) > 0 ) + { + QString txt = "When receiving an object from Python, multiple key/values for a field keyword was " + "detected. This is an error will most likely fail to update the object as intende. " + "Keyword name : " + + QString::fromStdString( p.first ); + RiaLogging::error( txt ); + } + uniqueNames.insert( lowerCase ); + } + } + + bool printContent = false; // Flag to control debug output to debugger. Do not remove this code, as it is useful for + // debugging if ( printContent ) { for ( const auto& p : parametersMap )