Source code for bhr.borehole

from typing import cast

from bhr.coaxial_borehole import Coaxial
from bhr.double_u_borehole import DoubleUTube
from bhr.enums import BoreholeType, BoundaryCondition
from bhr.single_u_borehole import SingleUBorehole
from bhr.utilities import set_boundary_condition_enum

AnyBHType = Coaxial | DoubleUTube | SingleUBorehole | None


[docs] class Borehole: def __init__(self): self._bh_type = None self._boundary_condition = None self._bh: AnyBHType = None self.length = None
[docs] def init_single_u_borehole( self, borehole_diameter: float, pipe_outer_diameter: float, pipe_dimension_ratio: float, length: float, shank_space: float, pipe_conductivity: float, grout_conductivity: float, soil_conductivity: float, fluid_type: str, fluid_concentration: float = 0, boundary_condition: str = "UNIFORM_HEAT_FLUX", ) -> None: """ Constructs a grouted single u-tube borehole. :param borehole_diameter: borehole diameter, in m. :param pipe_outer_diameter: outer diameter of the pipe, in m. :param pipe_dimension_ratio: non-dimensional ratio of pipe diameter to pipe thickness. :param length: length of borehole from top to bottom, in m. :param shank_space: radial distance from the borehole center to the pipe center, in m. :param pipe_conductivity: pipe thermal conductivity, in W/m-K. :param grout_conductivity: grout thermal conductivity, in W/m-K. :param soil_conductivity: soil thermal conductivity, in W/m-K. :param fluid_type: fluid type. "ETHYLALCOHOL", "ETHYLENEGLYCOL", "METHYLALCOHOL", "PROPYLENEGLYCOL", or "WATER" :param fluid_concentration: fractional concentration of antifreeze mixture, from 0-0.6. :param boundary_condition: borehole wall boundary condition. "UNIFORM_HEAT_FLUX" or "UNIFORM_BOREHOLE_WALL_TEMP" """ self._bh_type = BoreholeType.SINGLE_U_TUBE self._boundary_condition = set_boundary_condition_enum(boundary_condition) self._bh = SingleUBorehole( borehole_diameter, pipe_outer_diameter, pipe_dimension_ratio, length, shank_space, pipe_conductivity, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, )
[docs] def init_double_u_borehole( self, borehole_diameter: float, pipe_outer_diameter: float, pipe_dimension_ratio: float, length: float, shank_space: float, pipe_conductivity: float, pipe_inlet_arrangement: str, grout_conductivity: float, soil_conductivity: float, fluid_type: str, fluid_concentration: float = 0, boundary_condition: str = "UNIFORM_HEAT_FLUX", ) -> None: """ Constructs a grouted double u-tube borehole with u-tubes in parallel. :param borehole_diameter: borehole diameter, in m. :param pipe_outer_diameter: outer diameter of the pipe, in m. :param pipe_dimension_ratio: non-dimensional ratio of pipe diameter to pipe thickness. :param length: length of borehole from top to bottom, in m. :param shank_space: radial distance from the borehole center to the pipe center, in m. :param pipe_conductivity: pipe thermal conductivity, in W/m-K. :param pipe_inlet_arrangement: arrangement of the pipe inlets. "ADJACENT", or "DIAGONAL" :param grout_conductivity: grout thermal conductivity, in W/m-K. :param soil_conductivity: soil thermal conductivity, in W/m-K. :param fluid_type: fluid type. "ETHYLALCOHOL", "ETHYLENEGLYCOL", "METHYLALCOHOL", "PROPYLENEGLYCOL", or "WATER" :param fluid_concentration: fractional concentration of antifreeze mixture, from 0-0.6. :param boundary_condition: borehole wall boundary condition. "UNIFORM_HEAT_FLUX" or "UNIFORM_BOREHOLE_WALL_TEMP" """ self._bh_type = BoreholeType.DOUBLE_U_TUBE self._boundary_condition = set_boundary_condition_enum(boundary_condition) self._bh = DoubleUTube( borehole_diameter, pipe_outer_diameter, pipe_dimension_ratio, length, shank_space, pipe_conductivity, pipe_inlet_arrangement, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, )
[docs] def init_coaxial_borehole( self, borehole_diameter: float, outer_pipe_outer_diameter: float, outer_pipe_dimension_ratio: float, outer_pipe_conductivity: float, inner_pipe_outer_diameter: float, inner_pipe_dimension_ratio: float, inner_pipe_conductivity: float, length: float, grout_conductivity: float, soil_conductivity: float, fluid_type: str, fluid_concentration: float, boundary_condition: str = "UNIFORM_HEAT_FLUX", ) -> None: """ Constructs a grouted coaxial borehole. :param borehole_diameter: borehole diameter, in m. :param outer_pipe_outer_diameter: outer diameter of outer pipe, in m. :param outer_pipe_dimension_ratio: non-dimensional ratio of outer pipe diameter to thickness. :param outer_pipe_conductivity: outer pipe thermal conductivity, in W/m-K. :param inner_pipe_outer_diameter: inner diameter of outer pipe, in m. :param inner_pipe_dimension_ratio: non-dimensional ratio of inner pipe diameter to thickness. :param inner_pipe_conductivity: inner pipe thermal conductivity, in W/m-K. :param length: length of borehole from top to bottom, in m. :param grout_conductivity: grout thermal conductivity, in W/m-K. :param soil_conductivity: pipe thermal conductivity, in W/m-K. :param fluid_type: fluid type. "ETHYLALCOHOL", "ETHYLENEGLYCOL", "METHYLALCOHOL", "PROPYLENEGLYCOL", or "WATER" :param fluid_concentration: fractional concentration of antifreeze mixture, from 0-0.6. :param boundary_condition: borehole wall boundary condition. "UNIFORM_HEAT_FLUX" or "UNIFORM_BOREHOLE_WALL_TEMP" """ self._bh_type = BoreholeType.COAXIAL self._boundary_condition = set_boundary_condition_enum(boundary_condition) self._bh = Coaxial( borehole_diameter, outer_pipe_outer_diameter, outer_pipe_dimension_ratio, outer_pipe_conductivity, inner_pipe_outer_diameter, inner_pipe_dimension_ratio, inner_pipe_conductivity, length, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, )
[docs] def init_from_dict(self, inputs: dict): """ Constructs a borehole from a set of dictionary inputs. :param inputs: dict of input data. """ bh_type_str = inputs["borehole_type"].upper() if bh_type_str == BoreholeType.SINGLE_U_TUBE.name: self._bh_type = BoreholeType.SINGLE_U_TUBE elif bh_type_str == BoreholeType.DOUBLE_U_TUBE.name: self._bh_type = BoreholeType.DOUBLE_U_TUBE elif bh_type_str == BoreholeType.COAXIAL.name: self._bh_type = BoreholeType.COAXIAL else: raise LookupError(f'borehole_type "{bh_type_str}" not supported') bc_str = inputs.get("boundary_condition", BoundaryCondition.UNIFORM_HEAT_FLUX.name).upper() if bc_str == BoundaryCondition.UNIFORM_HEAT_FLUX.name: self._boundary_condition = BoundaryCondition.UNIFORM_HEAT_FLUX elif bc_str == BoundaryCondition.UNIFORM_BOREHOLE_WALL_TEMP.name: self._boundary_condition = BoundaryCondition.UNIFORM_BOREHOLE_WALL_TEMP else: raise LookupError(f'boundary_condition "{bc_str}" not supported') bh_diameter = inputs["borehole_diameter"] length = inputs["length"] grout_conductivity = inputs["grout_conductivity"] soil_conductivity = inputs["soil_conductivity"] fluid_type = inputs["fluid_type"] fluid_concentration = inputs["fluid_concentration"] if self._bh_type == BoreholeType.SINGLE_U_TUBE: pipe_outer_dia_single = inputs["single_u_tube"]["pipe_outer_diameter"] dimension_ratio_single = inputs["single_u_tube"]["pipe_dimension_ratio"] shank_space_single = inputs["single_u_tube"]["shank_space"] pipe_conductivity_single = inputs["single_u_tube"]["pipe_conductivity"] self.init_single_u_borehole( bh_diameter, pipe_outer_dia_single, dimension_ratio_single, length, shank_space_single, pipe_conductivity_single, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, bc_str, ) elif self._bh_type == BoreholeType.DOUBLE_U_TUBE: pipe_outer_dia_double = inputs["double_u_tube"]["pipe_outer_diameter"] dimension_ratio_double = inputs["double_u_tube"]["pipe_dimension_ratio"] shank_space_double = inputs["double_u_tube"]["shank_space"] pipe_conductivity_double = inputs["double_u_tube"]["pipe_conductivity"] pipe_inlet_arrangement = inputs["double_u_tube"]["pipe_inlet_arrangement"] self.init_double_u_borehole( bh_diameter, pipe_outer_dia_double, dimension_ratio_double, length, shank_space_double, pipe_conductivity_double, pipe_inlet_arrangement, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, bc_str, ) elif self._bh_type == BoreholeType.COAXIAL: pipe_outer_dia_coax = inputs["coaxial"]["outer_pipe_outer_diameter"] outer_pipe_dimension_ratio = inputs["coaxial"]["outer_pipe_dimension_ratio"] pipe_conductivity_coax = inputs["coaxial"]["outer_pipe_conductivity"] inner_pipe_outer_diameter = inputs["coaxial"]["inner_pipe_outer_diameter"] inner_pipe_dimension_ratio = inputs["coaxial"]["inner_pipe_dimension_ratio"] inner_pipe_conductivity = inputs["coaxial"]["inner_pipe_conductivity"] self.init_coaxial_borehole( bh_diameter, pipe_outer_dia_coax, outer_pipe_dimension_ratio, pipe_conductivity_coax, inner_pipe_outer_diameter, inner_pipe_dimension_ratio, inner_pipe_conductivity, length, grout_conductivity, soil_conductivity, fluid_type, fluid_concentration, bc_str, ) else: raise NotImplementedError(f'bh_type "{self._bh_type.name}" not implemented')
[docs] def calc_bh_resist(self, mass_flow_rate: float, temperature: float) -> float: """ Computes the effective borehole thermal resistance. :param mass_flow_rate: total borehole mass flow rate, in kg/s :param temperature: average fluid temperature, in Celsius :return: effective borehole resistance, in K/W-m """ if self._bh is None: raise TypeError("Borehole not initialized") if self._boundary_condition == BoundaryCondition.UNIFORM_HEAT_FLUX: return self._bh.calc_effective_bh_resistance_uhf(mass_flow_rate, temperature) if self._boundary_condition == BoundaryCondition.UNIFORM_BOREHOLE_WALL_TEMP: return self._bh.calc_effective_bh_resistance_ubwt(mass_flow_rate, temperature) raise NotImplementedError(f'Boundary Condition: "{self._boundary_condition}" implemented.')
[docs] def calc_pipe_cond_resist(self) -> float: """ Computes the pipe conduction resistance. In the case of coaxial boreholes, the function only returns the conduction resistances for the outer pipe. :return: pipe conduction resistance, K/(W/m) """ match self._bh_type: case BoreholeType.SINGLE_U_TUBE: return cast(SingleUBorehole, self._bh).calc_cond_resist() case BoreholeType.DOUBLE_U_TUBE: return cast(DoubleUTube, self._bh).calc_cond_resist() case BoreholeType.COAXIAL: return cast(Coaxial, self._bh).calc_cond_resist()[1] case _: raise NotImplementedError(f"{self._bh_type} not implemented.")
[docs] def calc_fluid_resist(self, mass_flow_rate: float, temperature: float) -> float: """ Computes the fluid convection resistance. In the case of coaxial boreholes, the function returns the sum of the convection resistances for the inner pipe and annular region. :return: fluid convection, K/(W/m) """ match self._bh_type: case BoreholeType.SINGLE_U_TUBE: return cast(SingleUBorehole, self._bh).calc_conv_resist(mass_flow_rate, temperature) case BoreholeType.DOUBLE_U_TUBE: return cast(DoubleUTube, self._bh).calc_conv_resist(mass_flow_rate, temperature) case BoreholeType.COAXIAL: return sum(cast(Coaxial, self._bh).calc_conv_resist_annulus(mass_flow_rate, temperature)) case _: raise NotImplementedError(f"{self._bh_type} not implemented.")
[docs] def calc_fluid_pipe_resist(self, mass_flow_rate: float, temperature: float) -> float: """ Computes the fluid convection + pipe conduction resistance. In the case of coaxial boreholes, this returns the convection resistance of the annulus + the conduction resistance of the outer pipe. :return: fluid convection + pipe conduction resistance, K/(W/m) """ if self._bh is None: raise TypeError("Borehole not initialized") if self._bh_type is None: raise NotImplementedError(f"{self._bh_type} not implemented.") return self._bh.calc_fluid_pipe_resist(mass_flow_rate, temperature)