Source code for kappa_sdk.kw.well_intake.well_intake_parser

import io
from xml.etree.ElementTree import ElementTree, Element, fromstring, register_namespace
from ..parser_exception import ParserException
from typing import Optional, List, Union, Tuple, cast
from .intake_properties_enum import IntakePropertiesEnum
from .trajectory_enum import TrajectoryEnum
from .geometry_properties_enum import GeometryPropertiesEnum
from .temperature_properties_enum import TemperaturePropertiesEnum
from .gas_lift_properties_enum import GasLiftPropertiesEnum
from .flow_path_enum import FlowPathEnum
from ...datetime_utils import datetime_to_str, str_to_datetime
from datetime import datetime
from uuid import UUID


[docs] class WellIntakeParser: """ Parses XML Well Intake from KW document's well intake 5.50 """ __ns = {'Export': 'KWKA_XML_Export', 'Intake': 'KWKA_XML_Intake', 'Base': 'KW_XML_Base', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'} def __init__(self, xml_string: str) -> None: register_namespace('AA', 'KWKA_XML_Export') register_namespace('KWKAModel', 'KWKA_XML_Model') register_namespace('ns', 'KWKA_XML_Intake') register_namespace('Export', 'KWKA_XML_Export') register_namespace('Intake', 'KWKA_XML_Intake') register_namespace('Base', 'KW_XML_Base') register_namespace('xsi', 'http://www.w3.org/2001/XMLSchema-instance') self.__tree = ElementTree(fromstring(xml_string)) self.__root = self.__tree.getroot() self.__model = self.__get_intake_element("Model") self.__version = cast(str, self.__find_parameter_in_element(self.__root, "Export", "WellIntake").get('WellIntakeVersion')) @property def version(self) -> str: return self.__version def __get_intake_element(self, name: str) -> Element: well_intake_element = self.__find_parameter_in_element(self.__root, "Export", "WellIntake") return self.__find_parameter_in_element(well_intake_element, "Intake", name) def __find_parameter_in_element(self, element: Element, namespace_prefix: str, parameter_name: str) -> Element: parameter = element.find(f"{namespace_prefix}:{parameter_name}", self.__ns) if parameter is None: raise ParserException(f"Cannot find {self.__ns[namespace_prefix]}:{parameter_name} in the xml document") return parameter def __get_intake_info_element(self, intake_element_name: str) -> Element: well_intake_element = self.__find_parameter_in_element(self.__root, "Export", "WellIntake") return self.__find_parameter_in_element(well_intake_element, "Intake", intake_element_name) def __set_well_log_value(self, element: Element, value: Union[Tuple[List[float], List[float]], float, int], is_only_non_constant_well_log: bool = False) -> None: element.clear() if isinstance(value, tuple): x_values, y_values = value non_constant_value_element = Element("Base:NonConstantValue") array = self.__build_array(x_values, y_values) non_constant_value_element.append(array) element.append(non_constant_value_element) else: if not is_only_non_constant_well_log: constant_value_element = Element("Base:ConstantValue") constant_value_element.text = str(value) element.append(constant_value_element) else: raise ValueError(f"{element.tag} can only be a tuple of 2 lists of floats") def __build_array(self, x_values: List[float], y_values: List[float]) -> Element: array = Element("Base:Array") for x, y in zip(x_values, y_values): well_log_element = Element("Base:WellLogElement") x_element = Element("Base:X") x_element.text = str(x) y_element = Element("Base:Y") y_element.text = str(y) well_log_element.append(x_element) well_log_element.append(y_element) array.append(well_log_element) return array def get_properties_value(self, parameter: IntakePropertiesEnum) -> Optional[Union[str, datetime]]: if parameter == IntakePropertiesEnum.start_date: return cast(datetime, str_to_datetime(self.__find_parameter_in_element(self.__model, "Intake", parameter.value).text)) elif parameter == IntakePropertiesEnum.gauge_depth: geometry = self.__find_parameter_in_element(self.__model, "Intake", "Geometry") return self.__find_parameter_in_element(geometry, "Intake", "BottomholeDepth").text else: try: value = cast(str, self.__get_intake_info_element(str(parameter.value)).text) except ParserException: return None return value def set_properties_value(self, parameter: IntakePropertiesEnum, value: Union[str, float, datetime]) -> None: if parameter == IntakePropertiesEnum.start_date: self.__find_parameter_in_element(self.__model, "Intake", parameter.value).text = datetime_to_str(cast(datetime, value)) elif parameter == IntakePropertiesEnum.gauge_depth: geometry = self.__find_parameter_in_element(self.__model, "Intake", "Geometry") self.__find_parameter_in_element(geometry, "Intake", "BottomholeDepth").text = str(value) else: self.__get_intake_info_element(str(parameter.value)).text = str(value) def set_trajectory(self, trajectory_type: TrajectoryEnum, value: Union[Tuple[List[float], List[float]], float]) -> None: if trajectory_type == TrajectoryEnum.md_tvd and isinstance(value, float): raise ValueError(f"{trajectory_type} accept only 2 lists of floats") trajectory = self.__get_intake_element("Trajectory") try: element = self.__find_parameter_in_element(trajectory, "Intake", trajectory_type.value) except ParserException: trajectory.clear() element = Element(f"Intake:{trajectory_type.value}") trajectory.append(element) if trajectory_type == TrajectoryEnum.md_tvd: element.clear() x_values, y_values = cast(Tuple[List[float], List[float]], value) array = self.__build_array(x_values, y_values) element.append(array) else: self.__set_well_log_value(element, value) def set_geometry(self, geometry_property: GeometryPropertiesEnum, value: Union[Tuple[List[float], List[float]], float]) -> None: geometry = self.__find_parameter_in_element(self.__model, "Intake", "Geometry") if geometry_property == GeometryPropertiesEnum.tubing_id or geometry_property == GeometryPropertiesEnum.tubing_absolute_roughness: tubing_geometry = self.__find_parameter_in_element(geometry, "Intake", "TubingGeometry") element = self.__find_parameter_in_element(tubing_geometry, "Intake", geometry_property.value) self.__set_well_log_value(element, value) if geometry_property is not GeometryPropertiesEnum.tubing_id: tubing_geometry = self.__find_parameter_in_element(geometry, "Intake", "CasingGeometry") element = self.__find_parameter_in_element(tubing_geometry, "Intake", geometry_property.value) self.__set_well_log_value(element, value) def set_temperature(self, temperature_property: TemperaturePropertiesEnum, value: Union[Tuple[List[float], List[float]], float, int]) -> None: temperature = self.__find_parameter_in_element(self.__model, "Intake", "Temperature") linear = self.__find_parameter_in_element(temperature, "Intake", "Linear") self.__find_parameter_in_element(linear, "Intake", temperature_property.value).text = str(value) def set_gas_lift_properties(self, gas_lift_property: GasLiftPropertiesEnum, value: Union[str, float, int, UUID]) -> None: gas_lift_element = self.__find_parameter_in_element(self.__model, "Intake", "GasLift") if gas_lift_property in [GasLiftPropertiesEnum.specific_gas_gravity, GasLiftPropertiesEnum.z_correlation_choice, GasLiftPropertiesEnum.cg_correlation_choice, GasLiftPropertiesEnum.mug_correlation_choice]: injected_gas_pvt_description_element = self.__find_parameter_in_element(gas_lift_element, "Intake", "InjectedGasPvtDescription") parameter_element = self.__find_parameter_in_element(injected_gas_pvt_description_element, "Intake", str(gas_lift_property.value)) parameter_element.text = str(value) else: element = self.__find_parameter_in_element(gas_lift_element, "Intake", str(gas_lift_property.value)) if gas_lift_property == GasLiftPropertiesEnum.injection_pressure: element.clear() if type(value) is str: value = UUID(value) if type(value) is float or type(value) is int: injection_pressure_value_element = Element("Intake:ConstantPressure") elif type(value) is UUID: injection_pressure_value_element = Element("Intake:InjectedPressureGaugeID") else: raise ValueError(f"To set the value of {gas_lift_property.value} you must pass a float or a UUID") injection_pressure_value_element.text = str(value) element.append(injection_pressure_value_element) elif gas_lift_property == GasLiftPropertiesEnum.injection_gas_rate: element.clear() if type(value) is str: value = UUID(value) if type(value) is float or type(value) is int: injection_gas_rate_value_element = Element("Intake:ConstantGasRate") elif type(value) is UUID: injection_gas_rate_value_element = Element("Intake:InjectedGasRateGaugeID") else: raise ValueError(f"To set the value of {gas_lift_property.value} you must pass a float or a UUID") injection_gas_rate_value_element.text = str(value) element.append(injection_gas_rate_value_element) else: element.text = str(value) def is_gas_lift(self) -> bool: gas_lift_parameter = self.__model.find("Intake:GasLift", self.__ns) if gas_lift_parameter is None: return False else: return True def set_flow_path(self, flow_path: FlowPathEnum) -> None: geometry = self.__find_parameter_in_element(self.__model, "Intake", "Geometry") self.__find_parameter_in_element(geometry, "Intake", "FlowPath").text = str(flow_path.value) def export(self) -> str: self.__root.set('xmlns:ns', self.__ns['Intake']) stream = io.StringIO() self.__tree.write(stream, encoding='unicode', method='xml', xml_declaration=True) return stream.getvalue()