Source code for kappa_sdk.keg5.keg5_well_property_inputs
import uuid
from typing import Optional, List
[docs]
class Point3D:
"""
Class to store coordinates of a 3D point
"""
def __init__(self, x: float, y: float, z: float):
self.x = x
self.y = y
self.z = z
[docs]
class Keg5WellPropertyInputs:
"""
Class to store the properties to use to create a well in KEG5
"""
__default_radius: float = 0.09144
def __init__(self, name: str,
uwi: str,
x: float,
y: float,
permeability: float,
porosity: float,
thickness: float,
is_horizontal: bool,
radius: Optional[float],
perforation_length: Optional[float],
skin: Optional[float]):
""" Initialization of the well properties to use in a KEG to create a well
Parameters
----------
name: well name
uwi: unique well id
x: x wellhead coordinate
y: y wellhead coordinate
permeability: permeability to apply to the zone where the well is
porosity: porosity to apply to the zone where the well is
thickness: thickness to apply to the zone where the well is
is_horizontal: True if the well is horizontal, False if it is vertical
radius: well radius, can be None, in that case the default radius (0.09144) will be used
perforation_length: perforation length to apply, mandatory for horizontal wells, can be None for vertical ones, in that case all the well will be perforated
skin: skin to apply
"""
if is_horizontal and perforation_length is None:
raise ValueError(f"Error building well '{name}': perforation length has to be defined for a horizontal well")
self.__name: str = name
self.__uwi: str = uwi
self.__x: float = x
self.__y: float = y
self.__permeability = permeability
self.__porosity = porosity
self.__thickness = thickness
self.__is_horizontal = is_horizontal
self.__radius = self.__default_radius if radius is None else radius
self.__perforation_length = perforation_length
self.__skin = skin
self.__well_id: str = str(uuid.uuid4())
self.__perforation_id: str = str(uuid.uuid4())
self.__borehole_id: str = str(uuid.uuid4())
@property
def name(self) -> str:
""" Name of the well
"""
return self.__name
@property
def uwi(self) -> str:
""" Unique well id of the well
"""
return self.__uwi
@property
def x(self) -> float:
""" x well head coordinate
"""
return self.__x
@property
def y(self) -> float:
""" x well head coordinate
"""
return self.__y
@property
def permeability(self) -> float:
""" Permeability to apply to the zone where the well is
"""
return self.__permeability
@property
def porosity(self) -> float:
""" Porosity to apply to the zone where the well is
"""
return self.__porosity
@property
def thickness(self) -> float:
""" Permeability to apply to the zone where the well is
"""
return self.__thickness
@property
def radius(self) -> float:
""" Well radius
"""
return self.__radius
@property
def skin(self) -> Optional[float]:
""" Skin
"""
return self.__skin
@property
def well_id(self) -> str:
""" WellId that will be used internally in KEG5 objects linked to this well
"""
return self.__well_id
@property
def perforation_id(self) -> str:
""" PerforationId that will be used internally in KEG5 objects linked to this well
"""
return self.__perforation_id
@property
def borehole_id(self) -> str:
""" BoreholeId that will be used internally in KEG5 objects linked to this well
"""
return self.__borehole_id
def __get_perforation_length(self) -> float:
assert self.__perforation_length is not None
return self.__perforation_length
def get_perforation_md_start(self, z_top: float) -> float:
""" Returns the md start to use for the well perforation, for vertical wells: if the initial perforation length
is undefined, we take md_start = well_md_start so the perforations will be present all along the well.
If perforation length is defined, we apply that length from the end of the well.
For horizontal wells we take z_top + thickness/2, which correspond to the first point of the well.
Parameters
----------
z_top: z_top at the wellhead position
Returns
-------
md start of the perforation
"""
if self.__is_horizontal:
return z_top + self.thickness/2
if self.__perforation_length is None:
return z_top
return max(z_top, z_top + self.thickness - self.__get_perforation_length())
def get_perforation_md_end(self, z_top: float) -> float:
""" Returns the md end to use for the well perforation, for both type of wells we take the last point of the well
Parameters
----------
z_top: z_top at the wellhead position
Returns
-------
md start of the perforation
"""
if self.__is_horizontal:
return z_top + self.thickness/2 + self.__get_perforation_length()
return z_top + self.thickness
def get_well_trajectory(self, z_top: float) -> List[Point3D]:
""" Calculates the trajectory of the well according to its type (horizontal of vertical)
Parameters
----------
z_top: z_top at the well position
Returns
-------
A list of Point3D representing the trajectory of the well
"""
if self.__is_horizontal:
z = z_top + self.thickness / 2
return [Point3D(self.x, self.y, z), Point3D(self.x + self.__get_perforation_length(), self.y, z)]
return [Point3D(self.x, self.y, z_top), Point3D(self.x, self.y, z_top + self.thickness)]
def get_well_type(self) -> str:
return "HORIZONTAL" if self.__is_horizontal else "VERTICAL"