diff --git a/src/alfasim_score/constants.py b/src/alfasim_score/constants.py index a83b5ad..fca8d95 100644 --- a/src/alfasim_score/constants.py +++ b/src/alfasim_score/constants.py @@ -1,10 +1,13 @@ from barril.units import Scalar from alfasim_score.units import DENSITY_UNIT +from alfasim_score.units import DIAMETER_UNIT +from alfasim_score.units import DIMENSIONLESS from alfasim_score.units import FRACTION_UNIT from alfasim_score.units import HEAT_TRANSFER_COEFFICIENT_UNIT from alfasim_score.units import LENGTH_UNIT from alfasim_score.units import MASS_FLOW_RATE_UNIT +from alfasim_score.units import PRESSURE_UNIT from alfasim_score.units import ROUGHNESS_UNIT from alfasim_score.units import STD_VOLUMETRIC_FLOW_RATE_UNIT @@ -14,6 +17,7 @@ ANNULUS_TOP_NODE_NAME = "WELLBORE_ANNULUS_TOP_NODE" GAS_LIFT_MASS_NODE_NAME = "GAS_LIFT_MASS_NODE" CEMENT_NAME = "cement" +GAS_LIFT_VALVE_NAME = "GAS_LIFT_VALVE" ROCK_DEFAULT_ROUGHNESS = Scalar(0.1, ROUGHNESS_UNIT) ROCK_DEFAULT_HEAT_TRANSFER_COEFFICIENT = Scalar(1000.0, HEAT_TRANSFER_COEFFICIENT_UNIT) @@ -22,7 +26,7 @@ REFERENCE_VERTICAL_COORDINATE = Scalar(0.0, LENGTH_UNIT, "length") -# This default fluid name for packer and fluid above filler +# this default fluid name for packer and fluid above filler FLUID_DEFAULT_NAME = "fluid_default" # nodes data @@ -37,3 +41,8 @@ # default values used in the context of black-oil models H2S_MOLAR_FRACTION_DEFAULT = Scalar(0.0, FRACTION_UNIT) CO2_MOLAR_FRACTION_DEFAULT = Scalar(0.0, FRACTION_UNIT) + +# gas lift default values +GAS_LIFT_VALVE_DEFAULT_DIAMETER = Scalar(0.25, DIAMETER_UNIT, "diameter") +GAS_LIFT_VALVE_DEFAULT_DISCHARGE = Scalar(0.826, DIMENSIONLESS) +GAS_LIFT_VALVE_DEFAULT_DELTA_P_MIN = Scalar(0.0, PRESSURE_UNIT) diff --git a/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase.alfacase b/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase.alfacase index a660420..8f01b46 100644 --- a/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase.alfacase +++ b/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase.alfacase @@ -954,7 +954,7 @@ wells: values: - 288.6 unit: K - top_node: WELLBORE_ANNULUS_TOP_NODE + top_node: GAS_LIFT_MASS_NODE formation: reference_y_coordinate: value: 0.0 diff --git a/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase_with_operation.alfacase b/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase_with_operation.alfacase index 99dfe9b..f189c43 100644 --- a/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase_with_operation.alfacase +++ b/src/alfasim_score/converter/alfacase/_tests/test_convert_alfacase/test_create_alfacase_with_operation.alfacase @@ -126,7 +126,7 @@ pipes: [] nodes: - name: WELLBORE_TOP_NODE node_type: mass_source_boundary - pvt_model: base + pvt_model: DFLT_BLACK_OIL_27.40_230.00_1.17 pressure_properties: pressure: value: 100000.0 @@ -217,7 +217,7 @@ nodes: max_rate_of_change: 1e+50 - name: WELLBORE_BOTTOM_NODE node_type: pressure_boundary - pvt_model: base + pvt_model: DFLT_BLACK_OIL_27.40_230.00_1.17 pressure_properties: pressure: value: 9814.11 @@ -298,7 +298,7 @@ nodes: max_rate_of_change: 1e+50 - name: GAS_LIFT_MASS_NODE node_type: mass_source_boundary - pvt_model: gas_lift + pvt_model: DFLT_BLACK_OIL_27.40_230.00_1.17 pressure_properties: pressure: value: 100000.0 @@ -389,7 +389,7 @@ nodes: max_rate_of_change: 1e+50 wells: - name: WELLBORE - pvt_model: base + pvt_model: DFLT_BLACK_OIL_27.40_230.00_1.17 stagnant_fluid: fluid_default profile: x_and_y: @@ -803,7 +803,8 @@ wells: value: 0.1 unit: mm annulus: - has_annulus_flow: False + has_annulus_flow: True + pvt_model: DFLT_BLACK_OIL_27.40_230.00_1.17 initial_conditions: pressures: position_input_type: length @@ -954,7 +955,23 @@ wells: values: - 288.6 unit: K - top_node: WELLBORE_ANNULUS_TOP_NODE + equipment: + gas_lift_valves: + GAS_LIFT_VALVE_1: + position: + value: 928.0 + unit: m + diameter: + value: 0.25 + unit: in + valve_type: check_valve + delta_p_min: + value: 0.0 + unit: psi + discharge_coefficient: + value: 0.826 + unit: unitless + top_node: GAS_LIFT_MASS_NODE formation: reference_y_coordinate: value: 0.0 diff --git a/src/alfasim_score/converter/alfacase/base_operation.py b/src/alfasim_score/converter/alfacase/base_operation.py index 269ccef..d2bb42a 100644 --- a/src/alfasim_score/converter/alfacase/base_operation.py +++ b/src/alfasim_score/converter/alfacase/base_operation.py @@ -1,17 +1,36 @@ +from typing import Dict from typing import List import attr +from alfasim_sdk import AnnulusDescription +from alfasim_sdk import AnnulusEquipmentDescription +from alfasim_sdk import GasLiftValveEquipmentDescription +from alfasim_sdk import InitialConditionsDescription +from alfasim_sdk import InitialPressuresDescription +from alfasim_sdk import InitialTemperaturesDescription +from alfasim_sdk import InitialVelocitiesDescription +from alfasim_sdk import InitialVolumeFractionsDescription from alfasim_sdk import MassInflowSplitType from alfasim_sdk import MassSourceNodePropertiesDescription from alfasim_sdk import MassSourceType from alfasim_sdk import MultiInputType from alfasim_sdk import NodeDescription +from alfasim_sdk import PressureContainerDescription from alfasim_sdk import PressureNodePropertiesDescription +from alfasim_sdk import TableInputType +from alfasim_sdk import ValveType +from alfasim_sdk import WellDescription from alfasim_sdk._internal.constants import FLUID_GAS from alfasim_sdk._internal.constants import FLUID_OIL from alfasim_sdk._internal.constants import FLUID_WATER +from alfasim_score.common import LiftMethod +from alfasim_score.common import ModelFluidType from alfasim_score.constants import GAS_LIFT_MASS_NODE_NAME +from alfasim_score.constants import GAS_LIFT_VALVE_DEFAULT_DELTA_P_MIN +from alfasim_score.constants import GAS_LIFT_VALVE_DEFAULT_DIAMETER +from alfasim_score.constants import GAS_LIFT_VALVE_DEFAULT_DISCHARGE +from alfasim_score.constants import GAS_LIFT_VALVE_NAME from alfasim_score.constants import NULL_VOLUMETRIC_FLOW_RATE from alfasim_score.constants import WELLBORE_BOTTOM_NODE_NAME from alfasim_score.constants import WELLBORE_TOP_NODE_NAME @@ -23,7 +42,37 @@ class BaseOperationBuilder(ScoreAlfacaseConverter): def __init__(self, score_reader: ScoreInputReader): super().__init__(score_reader) + def has_gas_lift(self) -> bool: + """Check the operation has gas lift.""" + return self.score_input.read_operation_data()["lift_method"] == LiftMethod.GAS_LIFT + + def _get_gas_lift_valves(self) -> Dict[str, GasLiftValveEquipmentDescription]: + """Create the gas lift valves for the annulus.""" + gas_lift_data = self.score_input.read_operation_method_data() + valves = { + f"{GAS_LIFT_VALVE_NAME}_1": GasLiftValveEquipmentDescription( + position=self._get_position_in_well(gas_lift_data["valve_depth"]), + diameter=GAS_LIFT_VALVE_DEFAULT_DIAMETER, + valve_type=ValveType.CheckValve, + delta_p_min=GAS_LIFT_VALVE_DEFAULT_DELTA_P_MIN, + discharge_coefficient=GAS_LIFT_VALVE_DEFAULT_DISCHARGE, + ) + } + return valves + + def build_annulus(self) -> AnnulusDescription: + """Configure the annulus with data from SCORE operation.""" + return AnnulusDescription( + has_annulus_flow=self.has_gas_lift(), + pvt_model=self.get_fluid_model_name(), + equipment=AnnulusEquipmentDescription( + gas_lift_valves=self._get_gas_lift_valves(), + ), + top_node=GAS_LIFT_MASS_NODE_NAME, + ) + def build_nodes(self) -> List[NodeDescription]: + """ "Configure the nodes with data from SCORE operation.""" operation_data = self.score_input.read_operation_data() default_nodes = {node.name: node for node in super().build_nodes()} configured_nodes = [ @@ -40,6 +89,7 @@ def build_nodes(self) -> List[NodeDescription]: FLUID_WATER: -1.0 * operation_data["water_flow_rate"], }, ), + pvt_model=self.get_fluid_model_name(), ), attr.evolve( default_nodes.pop(WELLBORE_BOTTOM_NODE_NAME), @@ -48,9 +98,10 @@ def build_nodes(self) -> List[NodeDescription]: pressure=operation_data["flow_initial_pressure"], split_type=MassInflowSplitType.Pvt, ), + pvt_model=self.get_fluid_model_name(), ), ] - if GAS_LIFT_MASS_NODE_NAME in default_nodes: + if self.has_gas_lift(): gas_lift_data = self.score_input.read_operation_method_data() configured_nodes.append( attr.evolve( @@ -65,6 +116,14 @@ def build_nodes(self) -> List[NodeDescription]: FLUID_WATER: NULL_VOLUMETRIC_FLOW_RATE, }, ), + pvt_model=self.get_fluid_model_name(), ) ) return configured_nodes + + def build_well(self) -> WellDescription: + """Create the description for the well.""" + return attr.evolve( + super().build_well(), + pvt_model=self.get_fluid_model_name(), + ) diff --git a/src/alfasim_score/converter/alfacase/convert_alfacase.py b/src/alfasim_score/converter/alfacase/convert_alfacase.py index f3bdd7d..66d2fc1 100644 --- a/src/alfasim_score/converter/alfacase/convert_alfacase.py +++ b/src/alfasim_score/converter/alfacase/convert_alfacase.py @@ -35,11 +35,10 @@ from alfasim_sdk._internal.constants import FLUID_WATER from barril.units import Scalar -from alfasim_score.common import LiftMethod +from alfasim_score.common import ModelFluidType from alfasim_score.common import convert_api_gravity_to_oil_density from alfasim_score.common import convert_gas_gravity_to_gas_density from alfasim_score.common import convert_quota_to_tvd -from alfasim_score.constants import ANNULUS_TOP_NODE_NAME from alfasim_score.constants import BASE_PVT_TABLE_NAME from alfasim_score.constants import CASING_DEFAULT_ROUGHNESS from alfasim_score.constants import CEMENT_NAME @@ -58,6 +57,7 @@ from alfasim_score.constants import WELLBORE_TOP_NODE_NAME from alfasim_score.converter.alfacase.score_input_reader import ScoreInputReader from alfasim_score.units import LENGTH_UNIT +from alfasim_score.units import PRESSURE_UNIT from alfasim_score.units import TEMPERATURE_UNIT @@ -90,6 +90,10 @@ def _get_position_in_well(self, position: Scalar) -> Scalar: """Get the position relative to the well start position.""" return position - self.well_start_position + def get_fluid_model_name(self) -> ModelFluidType: + """Get the name of the fluid model used for this operation.""" + return self.score_input.read_operation_fluid_data()["name"] + def _convert_well_trajectory(self) -> ProfileDescription: """ Convert the trajectory for the imported well. @@ -123,11 +127,9 @@ def _convert_materials(self) -> List[MaterialDescription]: ) return filter_duplicated_materials(material_descriptions) - def _convert_annulus(self) -> AnnulusDescription: - # TODO PWPA-1937: implement this method - # TODO PWPA-1937: Use the GAS_LIFT_MASS_NODE, check for the gas lift presence - # and set flow rate zero with the flag false for annulus flow. - return AnnulusDescription(has_annulus_flow=False, top_node=ANNULUS_TOP_NODE_NAME) + def build_annulus(self) -> AnnulusDescription: + """Create the description for the annulus.""" + return AnnulusDescription(has_annulus_flow=False, top_node=GAS_LIFT_MASS_NODE_NAME) def _convert_formation(self) -> FormationDescription: """Create the description for the formations.""" @@ -305,25 +307,21 @@ def build_nodes(self) -> List[NodeDescription]: split_type=MassInflowSplitType.Pvt, ), ), + NodeDescription( + name=GAS_LIFT_MASS_NODE_NAME, + node_type=NodeCellType.MassSource, + pvt_model=GAS_LIFT_PVT_TABLE_NAME, + mass_source_properties=MassSourceNodePropertiesDescription( + temperature_input_type=MultiInputType.Constant, + source_type=MassSourceType.AllVolumetricFlowRates, + volumetric_flow_rates_std={ + FLUID_GAS: NULL_VOLUMETRIC_FLOW_RATE, + FLUID_OIL: NULL_VOLUMETRIC_FLOW_RATE, + FLUID_WATER: NULL_VOLUMETRIC_FLOW_RATE, + }, + ), + ), ] - operation_input_data = self.score_input.read_operation_data() - if operation_input_data["lift_method"] == LiftMethod.GAS_LIFT: - nodes.append( - NodeDescription( - name=GAS_LIFT_MASS_NODE_NAME, - node_type=NodeCellType.MassSource, - pvt_model=GAS_LIFT_PVT_TABLE_NAME, - mass_source_properties=MassSourceNodePropertiesDescription( - temperature_input_type=MultiInputType.Constant, - source_type=MassSourceType.AllVolumetricFlowRates, - volumetric_flow_rates_std={ - "gas": NULL_VOLUMETRIC_FLOW_RATE, - "oil": NULL_VOLUMETRIC_FLOW_RATE, - "water": NULL_VOLUMETRIC_FLOW_RATE, - }, - ), - ) - ) return nodes def build_well(self) -> WellDescription: @@ -334,7 +332,7 @@ def build_well(self) -> WellDescription: stagnant_fluid=FLUID_DEFAULT_NAME, profile=self._convert_well_trajectory(), casing=self._convert_casings(), - annulus=self._convert_annulus(), + annulus=self.build_annulus(), formation=self._convert_formation(), top_node=WELLBORE_TOP_NODE_NAME, bottom_node=WELLBORE_BOTTOM_NODE_NAME, @@ -342,7 +340,7 @@ def build_well(self) -> WellDescription: ) def build_case_description(self) -> CaseDescription: - """ "Create the description for the alfacase.""" + """Create the description for the alfacase.""" return CaseDescription( name=self.general_data["case_name"], physics=self.build_physics(), diff --git a/src/alfasim_score/units.py b/src/alfasim_score/units.py index 59f9d56..9e9c081 100644 --- a/src/alfasim_score/units.py +++ b/src/alfasim_score/units.py @@ -14,3 +14,4 @@ TEMPERATURE_UNIT = "degC" GAS_OIL_RATIO_UNIT = "sm3/sm3" HEAT_TRANSFER_COEFFICIENT_UNIT = "W/m2.K" +DIMENSIONLESS = "unitless"