carm package

Subpackages

Submodules

carm.external_environment module

Environmental conditions module.

Defines the thermal and radiative properties of the external environment used as boundary conditions in the borehole heat exchanger simulation.

class carm.external_environment.EnvironmentalProperties[source]

Bases: object

Physical and thermal properties of the external environment.

Groups all site-specific parameters that characterize the surface boundary condition: radiative exchange coefficients, surface optical properties, and the seasonal air temperature signal.

R_ext

External thermal resistance [W / (K m²)].

Type:

float

absorptance

Surface absorptance for solar radiation [-].

Type:

float

eps

Surface emittance for longwave radiation [-].

Type:

float

At

Annual amplitude of monthly average air temperature [K].

Type:

float

tau

Current simulation time [s].

Type:

float

tau_y

Duration of one year (315,536,000 s) [s].

Type:

float

tau_shift

Time offset to account for the date of minimum surface temperature [s].

Type:

float

R_ext: float
absorptance: float
eps: float
At: float
tau: float
tau_y: float
tau_shift: float
class carm.external_environment.EnvironmentalTimeSeries[source]

Bases: object

Time series of external environmental inputs.

Stores the external air temperature and solar irradiance arrays used to drive the surface boundary condition over the simulation period. Instances should be created via the class methods to ensure input validation.

Tm

Mean annual air temperature [°C].

Type:

float

T_ext

External air temperature time series [°C].

Type:

NDArray[np.float64]

SolarRad

Solar irradiance time series [W/m²].

Type:

NDArray[np.float64]

water_input

Water input series by irrigation or metherological phenomena [m3 / s].

Type:

NDArray[np.float64] | None = None

Tm: float
T_ext: ndarray[tuple[Any, ...], dtype[float64]]
SolarRad: ndarray[tuple[Any, ...], dtype[float64]]
water_input: ndarray[tuple[Any, ...], dtype[float64]] | None = None
classmethod from_excel(Tm, path)[source]

Construct an instance from an Excel file.

The file must contain columns named T_ext and SolarRad. All values must be finite (no NaN or Inf).

Parameters:
  • Tm (float) – Mean annual air temperature [°C].

  • path (Path or str) – Path to the Excel file (.xlsx).

Returns:

A validated instance populated from the file.

Return type:

EnvironmentalTimeSeries

Raises:

ValueError – If T_ext, SolarRad, or water_input contain non-finite values.

Examples

>>> env = EnvironmentalTimeSeries.from_excel(12.0, "data/climate.xlsx")
>>> env.T_ext.shape
(8760,)
classmethod from_array(Tm, T_ext, SolarRad, water_input=None)[source]

Construct an instance from NumPy arrays.

All values must be finite (no NaN or Inf).

Parameters:
  • Tm (float) – Mean annual air temperature [°C].

  • T_ext (NDArray[np.float64]) – External air temperature time series [°C].

  • SolarRad (NDArray[np.float64]) – Solar irradiance time series [W/m²].

  • water_input (NDArray[np.float64] | None = None) – Water input series by irrigation or metherological phenomena [m3 / s].

Returns:

A validated instance populated from the arrays.

Return type:

EnvironmentalTimeSeries

Raises:

ValueError – If T_ext, SolarRad, or water_input contain non-finite values.

Examples

>>> import numpy as np
>>> T = np.linspace(-5, 25, 8760)
>>> rad = np.abs(np.sin(np.linspace(0, 2 * np.pi, 8760))) * 600
>>> env = EnvironmentalTimeSeries.from_array(12.0, T, rad)
class carm.external_environment.ExternalEnvironment[source]

Bases: object

Assembled external environment for simulation boundary conditions.

Combines physical properties and time-series inputs, and derives the sky radiation temperature from the external air temperature at construction time.

envprops

Static physical and radiative properties of the site.

Type:

EnvironmentalProperties

envinput

Time-varying environmental inputs (temperature and solar radiation).

Type:

EnvironmentalTimeSeries

T_sky

Effective sky temperature time series, derived from T_ext [K].

Type:

NDArray[np.float64]

boltzmann

Stefan-Boltzmann constant (5.670374419 × 10⁻⁸) [W / (m² K⁴)].

Type:

float

Examples

>>> env = ExternalEnvironment(envprops=props, envinput=series)
>>> env.T_sky.shape
(8760,)
envprops: EnvironmentalProperties
envinput: EnvironmentalTimeSeries
T_sky: ndarray[tuple[Any, ...], dtype[float64]]
boltzmann: float = 5.670374419e-08

carm.field_layout module

Borehole field geometry module.

Defines the spatial layout of the borehole field: coordinate input and validation (FieldInput), Voronoi decomposition, distance matrix, and neighbor graph (Field).

class carm.field_layout.FieldInput[source]

Bases: object

Geometry container for the borehole field layout.

Stores the field bounding box and borehole coordinates, with validation. Coordinates must be loaded explicitly via one of the from_* methods before the field can be used downstream.

n_bhes

Number of boreholes in the field.

Type:

int

xmin, xmax

Field bounding box x-extent [m].

Type:

float

ymin, ymax

Field bounding box y-extent [m].

Type:

float

borehole_coordinates

List of (x, y) coordinate pairs for each borehole [m]. [] until populated via a from_* method.

Type:

Sequence[tuple[float, float]]

rb

External Borehole radius [m]

Type:

float

layout

Borehole spacing layout. The layout can be “regular” or “irregular”. If regular, the adiabatic condition will be applied at mid-distancce between thoe adjacent boreholes. If irregular, the FLS calculation will be performed to account for penalty temperature at the ground maximum radius. By default it is “regular”. It is important that even if regularly spaced, if series connection is present, the layout must be set as irregular.

Type:

str

property borehole_coordinates: Sequence[tuple[float, float]]
from_excel(path)[source]

Load borehole coordinates from an Excel file.

The file must contain columns named x and y.

Parameters:

path (Path or str) – Path to the Excel file (.xlsx).

Raises:

ValueError – If coordinates are non-finite, outside the bounding box, or the number of rows does not match n_bhes.

Return type:

None

Examples

>>> fi = FieldInput(n_bhes=4, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_excel("data/field.xlsx")
>>> fi.borehole_coordinates
[(2.5, 2.5), (7.5, 2.5), (2.5, 7.5), (7.5, 7.5)]
from_array(x, y)[source]

Load borehole coordinates from two 1-D arrays.

Parameters:
  • x (NDArray) – x-coordinates of the boreholes [m].

  • y (NDArray) – y-coordinates of the boreholes [m].

Raises:

ValueError – If x and y have different lengths, contain non-finite values, or coordinates fall outside the bounding box.

Return type:

None

Examples

>>> fi = FieldInput(n_bhes=2, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_array(np.array([3.0, 7.0]), np.array([5.0, 5.0]))
from_matrix(matrix)[source]

Load borehole coordinates from a 2-D array of shape (n_bhes, 2).

Parameters:

matrix (NDArray) – Array with columns [x, y] for each borehole [m].

Raises:

ValueError – If the array is not 2-D, does not have exactly 2 columns, or coordinates fail validation.

Return type:

None

Examples

>>> coords = np.array([[3.0, 5.0], [7.0, 5.0]])
>>> fi = FieldInput(n_bhes=2, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_matrix(coords)
class carm.field_layout.Field[source]

Bases: object

Voronoi decomposition and interaction geometry of the borehole field.

Built from a populated FieldInput, computes the Voronoi cell for each borehole, the equivalent radius r_eq = sqrt(area / pi), the pairwise distance matrix (corrected for r_eq), and the neighbor graph.

fieldinput

Source geometry object (must have coordinates loaded).

Type:

FieldInput

field_dict

Mapping from borehole index to its Voronoi cell data:

{i: {"cell": Polygon, "area": float, "req": float, "coords": (x, y)}}
Type:

dict

distance_matrix

Symmetric matrix of shape (n_bhes, n_bhes) with inter-borehole distances corrected by r_eq [m]. Diagonal entries are zero.

Type:

NDArray[np.float64]

property distance_matrix: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property field_dict: dict
plot_field(ax=None, show_points=True, show_ids=False, show_area=False, show_req=False, color_by_area=False, alpha=0.35, linewidth=0.5, point_size=8, save_path=None, show=True, show_graph=False)[source]

Plot the Voronoi field decomposition.

Parameters:
  • ax (matplotlib.axes.Axes or None) – Axes to draw on. If None, a new figure is created.

  • show_points (bool) – If True, draw borehole generator points.

  • show_ids (bool) – If True, annotate each point with its borehole index.

  • show_area (bool) – If True, label each cell with its area.

  • show_req (bool) – If True, label each cell with its equivalent radius r_eq.

  • color_by_area (bool) – If True, shade cells according to their area.

  • alpha (float) – Cell fill transparency.

  • linewidth (float) – Line width for cell edges and domain boundary.

  • point_size (float) – Marker size for borehole points.

  • save_path (str or None) – If provided, save the figure to this path at 300 dpi.

  • show (bool) – If True, call plt.show().

  • show_graph (bool) – If True, draw edges of the Voronoi neighbor graph.

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

Return type:

tuple[Figure, Axes]

Examples

>>> fi = FieldInput(n_bhes=4, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_array(np.array([2.5, 7.5, 2.5, 7.5]),
...               np.array([2.5, 2.5, 7.5, 7.5]))
>>> f = Field(fieldinput=fi)
>>> fig, ax = f.plot_field(show=False)

carm.fluid module

Fluid properties module.

Defines the thermophysical properties of the heat carrier fluid circulating in the borehole heat exchanger.

class carm.fluid.Fluid[source]

Bases: object

Thermophysical properties of the heat carrier fluid.

k_w

Thermal conductivity [W / (m K)].

Type:

float

rho_w

Density [kg/m³].

Type:

float

cp_w

Specific heat capacity [J / (kg K)].

Type:

float

ni_w

Kinematic viscosity [m²/s].

Type:

float

k_w: float
rho_w: float
cp_w: float
ni_w: float

carm.model module

Physical model module.

Assembles the complete physical description of the borehole heat exchanger system: ground geometry, mesh, borehole type, fluid properties, and field layout. Handles both single-borehole and multi-borehole configurations.

class carm.model.PhysicalModel[source]

Bases: object

Container for the full physical model of the BHE system.

Combines ground, borehole, fluid, and field layout into a single object. On construction, validates the configuration and builds one GroundProperties instance per borehole (with Voronoi-derived r_eq in the multi-borehole case).

ground_geom

Geometric parameters of the borehole and surrounding ground.

Type:

GroundGeometry

ground_mesh

Discretization settings for the ground domain.

Type:

GroundMesh

borehole

Borehole heat exchanger type and its geometric parameters.

Type:

SingleUtube or DoubleUtube or Helical or Coaxial

fluid

Thermophysical properties of the heat carrier fluid.

Type:

Fluid

Tg

Undisturbed ground temperature [°C].

Type:

float

stratification

Ground layer stratification as a sequence of (z_top, z_bot, k, rho_cp) tuples.

Type:

Sequence[tuple[float, float, float, float]]

ground

One GroundProperties instance per borehole, populated at construction time.

Type:

list[GroundProperties]

fieldinput

Field layout object. If None or n_bhes == 1, single-borehole mode is used.

Type:

FieldInput or None

field

Voronoi field decomposition. Present only in multi-borehole mode.

Type:

Field

ground_geom: GroundGeometry
ground_mesh: GroundMesh
borehole: SingleUtube | DoubleUtube | Helical | Coaxial
fluid: Fluid
Tg: float
stratification: Sequence[tuple[float, float, float, float]]
ground: list
fieldinput: FieldInput | None = None

carm.state module

Simulation state module.

Manages the temperature state vector during time-stepping, tracking both the current and previous time step values.

class carm.state.State[source]

Bases: object

Temperature state vector for the BHE simulation.

Holds the current and previous time step temperature arrays, used by the time-stepping loop to advance and roll back the solution.

T_state

Current temperature state vector.

Type:

NDArray

T_old

Temperature state vector at the previous time step.

Type:

NDArray

save_old()[source]
Return type:

None

update(T_new)[source]
Return type:

None

Module contents

class carm.GroundGeometry[source]

Bases: object

Geometric parameters of the ground domain.

D0

Borehole diameter [m].

Type:

float

L

Active borehole length (middle ground region) [m].

Type:

float

L_sup

Length of the upper ground region [m].

Type:

float

L_inf

Length of the lower ground region [m].

Type:

float

rn

Outer radius of the radial discretization [m]. Required for single-borehole mode; None in multi-borehole mode (where r_eq from the Voronoi decomposition is used instead).

Type:

float or None

r0

Borehole radius, derived as D0 / 2 [m].

Type:

float

D0: float
L: float
L_sup: float
L_inf: float
rn: float | None
property r0: float
class carm.GroundMesh[source]

Bases: object

Discretization parameters for the ground domain.

n_mesh

Number of radial mesh elements.

Type:

int

m_mesh

Number of axial mesh elements in the middle (active) region.

Type:

int

m_mesh_sup

Number of axial mesh elements in the upper region.

Type:

int

m_mesh_inf

Number of axial mesh elements in the lower region.

Type:

int

f

Radial expansion factor for the mesh (default 1.2). Controls how rapidly cell thickness increases moving outward from the borehole.

Type:

float

n_mesh: int
m_mesh: int
m_mesh_sup: int
m_mesh_inf: int
f: float
class carm.GroundProperties[source]

Bases: object

Thermophysical and discretization properties of the ground domain.

Computes layer-averaged thermal properties from the stratigraphic input, then derives all radial/axial resistances and capacitances used in the global system matrix.

geom

Geometric parameters of the ground domain.

Type:

GroundGeometry

mesh

Discretization settings.

Type:

GroundMesh

Tg

Undisturbed ground temperature [°C].

Type:

float

stratification

Ground layering as a sequence of (k, cp, rho, thickness) tuples. The sum of layer thicknesses must equal the total discretized length.

Type:

Sequence[tuple[float, float, float, float]]

k

Layer-averaged thermal conductivity, shape (n_cells, 1) [W / (m K)].

Type:

NDArray

cp

Layer-averaged specific heat capacity, shape (n_cells, 1) [J / (kg K)].

Type:

NDArray

rho

Layer-averaged density, shape (n_cells, 1) [kg/m³].

Type:

NDArray

k_mean

Mean thermal conductivity over the active (middle) region [W / (m K)].

Type:

float

cp_mean

Mean specific heat capacity over the active region [J / (kg K)].

Type:

float

rho_mean

Mean density over the active region [kg/m³].

Type:

float

radius

Radial cell boundary positions, shape (1, n_mesh + 1) [m].

Type:

NDArray

rm

Barycentric radii for resistance calculations, shape (1, n_mesh + 2) [m].

Type:

NDArray

C_ground

Radial thermal capacitances, shape (m_mesh, n_mesh) [J/K].

Type:

NDArray

R_ground

Radial thermal resistances, shape (m_mesh, n_mesh + 1) [K/W].

Type:

NDArray

R_axial

Axial thermal resistances in the middle region, shape (m_mesh, n_mesh) [K/W].

Type:

NDArray

R_sup

Axial thermal resistances in the upper region, shape (m_mesh_sup,) [K/W].

Type:

NDArray

C_sup

Axial thermal capacitances in the upper region, shape (m_mesh_sup,) [J/K].

Type:

NDArray

R_inf

Axial thermal resistances in the lower region, shape (m_mesh_inf,) [K/W].

Type:

NDArray

C_inf

Axial thermal capacitances in the lower region, shape (m_mesh_inf,) [J/K].

Type:

NDArray

class carm.BoreholeProperties[source]

Bases: object

Base class for all BHE configurations.

Assembles geometry, mesh, thermal properties, and fluid into a single object. Computes derived quantities (dz, mesh-shaped property arrays) shared by all BHE types.

geom

Borehole geometric parameters.

Type:

BoreholeGeometry

mesh

Axial discretization settings.

Type:

BoreholeMesh

thermalprops

Thermal properties of the grout.

Type:

BoreholeThermalProperties

fluid

Thermophysical properties of the heat carrier fluid.

Type:

Fluid

Lbore

Active borehole length [m].

Type:

float

D0

Borehole diameter [m].

Type:

float

m_mesh

Number of axial mesh elements.

Type:

int

dz

Axial mesh element size [m].

Type:

float

cp_0

Specific heat capacity array, shape (m_mesh, 1) [J / (kg K)].

Type:

NDArray

rho_0

Density array, shape (m_mesh, 1) [kg/m³].

Type:

NDArray

k0

Thermal conductivity array, shape (m_mesh, 1) [W / (m K)].

Type:

NDArray

class carm.BoreholeGeometry[source]

Bases: object

Geometric parameters of the borehole. D_irrigation and perf_fraction parameters must be set as None if

grout variable properties are not taken into account.

Note: the irrigation system is feasible only with shallow helical heat exchangers.

Lbore

Active borehole length [m].

Type:

float

D0

Borehole diameter [m].

Type:

float

D_irrigation

Irrigation pipe diameter [m].

Type:

None | float = None

perf_fraction

Irrigation pipe perforation fraction [-].

Type:

None | float = None

Lbore: float
D0: float
D_irrigation: None | float
perf_fraction: None | float
property r0: float
class carm.BoreholeMesh[source]

Bases: object

Axial discretization of the borehole.

m_mesh

Number of axial mesh elements along the borehole.

Type:

int

m_mesh: int
class carm.BoreholeThermalProperties[source]

Bases: object

Thermal properties of the borehole filling material (grout). The user must define whether he wants to define equivalent properties or grout stratification.

cp_0

Specific heat capacity [J / (kg K)].

Type:

float | None

rho_0

Density [kg/m³].

Type:

float | None

k0

Thermal conductivity [W / (m K)].

Type:

float | None

stratification

Grout layering as a sequence of (k, cp, rho, thickness) tuples. The sum of layer thicknesses must equal the borehole discretized length. Stratification is set as None by default.

Type:

Sequence[tuple[float, float, float, float]] | None

soil_type

Soil type string. This is set as None by default. If accounting for time variable properties, it must be set as ‘sand’, ‘loam’, or ‘clay’ and the correct properties must be given as input.

Type:

str

cp_0: float | None = None
rho_0: float | None = None
k0: float | None = None
stratification: Sequence[tuple[float, float, float, float]] | None = None
soil_type: str | None = None
class carm.SingleUtube[source]

Bases: Utube

Single U-tube BHE configuration (2 pipes).

Extends Utube with pipe-to-grout and grout-to-ground resistances specific to the single U-tube layout.

Rp0

Pipe-to-grout thermal resistance [K m / W].

Type:

float

RppB

Grout-to-ground thermal resistance [K m / W].

Type:

float

n_equations

Number of nodal equations in the discretized system (6).

Type:

int

Rp0_dz

Rp0 normalized by dz [K/W].

Type:

float

RppB_dz

RppB normalized by dz [K/W].

Type:

float

crossing_time_calculation(mw_tot)[source]

Compute the fluid transit time through the U-tube.

Parameters:

mw_tot (NDArray) – Total mass flow rate [kg/s].

Returns:

Time for the fluid to travel the full U-tube length (2 × Lbore) [s].

Return type:

NDArray

Examples

>>> mw_tot = np.full(n_steps, 2)
>>> t = bhe.crossing_time_calculation(mw_tot=mw_tot)
class carm.DoubleUtube[source]

Bases: Utube

Double U-tube BHE configuration (4 pipes).

Extends Utube with an additional pipe-to-pipe resistance and support for series (S) or parallel (P) pipe connection.

connection

Pipe connection mode: 'S' for series, 'P' for parallel.

Type:

str

Rp0

Pipe-to-grout thermal resistance [K m / W].

Type:

float

RppB

Grout-to-ground thermal resistance [K m / W].

Type:

float

RppA

Pipe-to-pipe thermal resistance [K m / W].

Type:

float

n_equations

Number of nodal equations in the discretized system (10).

Type:

int

Rp0_dz

Rp0 normalized by dz [K/W].

Type:

float

RppB_dz

RppB normalized by dz [K/W].

Type:

float

RppA_dz

RppA normalized by dz [K/W].

Type:

float

crossing_time_calculation(mw_tot)[source]

Compute the fluid transit time through the double U-tube.

Accounts for series (full flow in each pipe) vs. parallel (half flow in each pipe) connection.

Parameters:

mw_tot (NDArray) – Total mass flow rate [kg/s].

Returns:

Fluid transit time [s].

Return type:

NDArray

class carm.Coaxial[source]

Bases: BoreholeProperties

Coaxial pipe BHE configuration.

Two concentric pipes: inner pipe (1) and annular outer pipe (2). Flow direction is set by supply_and_return.

Dp1i

Inner diameter of pipe 1 (inner pipe) [m].

Type:

float

Dp2i

Inner diameter of pipe 2 (outer annulus) [m].

Type:

float

pipe1_thick

Wall thickness of pipe 1 [m].

Type:

float

pipe2_thick

Wall thickness of pipe 2 [m].

Type:

float

k_pipe1

Thermal conductivity of the pipe 1 material [W / (m K)].

Type:

float

k_pipe2

Thermal conductivity of the pipe 2 material [W / (m K)].

Type:

float

supply_and_return

Flow direction: '1_2' (supply in pipe 1) or '2_1' (supply in pipe 2).

Type:

str

n_equations

Number of nodal equations in the discretized system (5).

Type:

int

De

Hydraulic diameter of the annular region [m].

Type:

float

S_shell

Cross-sectional area of the grout annulus [m²].

Type:

float

R_cond1

Conductive resistance of pipe 1 wall [K/W].

Type:

float

R_cond2

Conductive resistance of pipe 2 wall [K/W].

Type:

float

R_shell

Conductive resistance of the grout annulus [K/W].

Type:

float

R_pipes1

Conductive resistance of stationary fluid in pipe 1, used when mw=0 [K/W].

Type:

float

R_pipes2

Conductive resistance of stationary fluid in the annulus, used when mw=0 [K/W].

Type:

float

R_axial_shell

Axial conductive resistance of the grout shell [K/W].

Type:

float

C_shell

Thermal capacitance of the grout shell [J/K].

Type:

float

C_fluid1

Thermal capacitance of the fluid in pipe 1 [J/K].

Type:

float

C_fluid2

Thermal capacitance of the fluid in the annulus [J/K].

Type:

float

crossing_time_calculation(mw_tot)[source]

Compute fluid transit times for both flow paths in the coaxial BHE.

Parameters:

mw_tot (NDArray) – Total mass flow rate [kg/s].

Returns:

crossing_time – Transit time through pipes [s].

Return type:

NDArray

class carm.Helical[source]

Bases: BoreholeProperties

Helical pipe BHE configuration.

A helical coil wound inside the borehole. The geometry is parameterized by the helix radius, pipe diameter, and number of turns.

Dpi1

Inner pipe 1 diameter (straight tube) [m].

Type:

float

Dpi2

Inner pipe 2 diameter (helical tube) [m].

Type:

float

rih

Inner helix radius (centre of pipe to borehole axis) [m].

Type:

float

pipe_thick

Pipe wall thickness [m].

Type:

float

N

Number of helix turns.

Type:

int

P

Helix pitch [m].

Type:

float

supply_and_return

Flow direction: '1_2' (supply in pipe 1) or '2_1' (supply in pipe 2).

Type:

str

Lp2tot

Total length helical pipe [m].

Type:

float

k_pipe

Thermal conductivity of the pipe material [W / (m K)].

Type:

float

n_equations

Number of nodal equations in the discretized system (6).

Type:

int

F

Turn density (turns per metre) [1/m].

Type:

float

S_shell

Cross-sectional area of the outer grout annulus [m²].

Type:

float

S_core

Cross-sectional area of the inner grout core [m²].

Type:

float

C_shell

Thermal capacitance of the shell, shape (m_mesh, 1) [J/K].

Type:

NDArray

C_shell_middle

Thermal capacitance of the node between pipe 2 and shell, shape (m_mesh, 1) [J/K]

Type:

NDArray

C_core

Thermal capacitance of the core, shape (m_mesh, 1) [J/K].

Type:

NDArray

C_fluid1

Thermal capacitance of the supply fluid [J/K].

Type:

float

C_fluid2

Thermal capacitance of the return fluid [J/K].

Type:

float

crossing_time_calculation(mw_tot)[source]

Compute the fluid transit time through the helical pipe.

Parameters:

mw_tot (NDArray) – Total mass flow rate [kg/s].

Returns:

Fluid transit time [s].

Return type:

NDArray

class carm.PhysicalModel[source]

Bases: object

Container for the full physical model of the BHE system.

Combines ground, borehole, fluid, and field layout into a single object. On construction, validates the configuration and builds one GroundProperties instance per borehole (with Voronoi-derived r_eq in the multi-borehole case).

ground_geom

Geometric parameters of the borehole and surrounding ground.

Type:

GroundGeometry

ground_mesh

Discretization settings for the ground domain.

Type:

GroundMesh

borehole

Borehole heat exchanger type and its geometric parameters.

Type:

SingleUtube or DoubleUtube or Helical or Coaxial

fluid

Thermophysical properties of the heat carrier fluid.

Type:

Fluid

Tg

Undisturbed ground temperature [°C].

Type:

float

stratification

Ground layer stratification as a sequence of (z_top, z_bot, k, rho_cp) tuples.

Type:

Sequence[tuple[float, float, float, float]]

ground

One GroundProperties instance per borehole, populated at construction time.

Type:

list[GroundProperties]

fieldinput

Field layout object. If None or n_bhes == 1, single-borehole mode is used.

Type:

FieldInput or None

field

Voronoi field decomposition. Present only in multi-borehole mode.

Type:

Field

ground_geom: GroundGeometry
ground_mesh: GroundMesh
borehole: SingleUtube | DoubleUtube | Helical | Coaxial
fluid: Fluid
Tg: float
stratification: Sequence[tuple[float, float, float, float]]
ground: list
fieldinput: FieldInput | None = None
class carm.Simulation[source]

Bases: object

Time-stepping orchestrator for the BHE simulation.

Assembles all physical inputs, initializes the FLS model and boundary conditions, and runs the simulation via run(). Supports parallel (independent boreholes) and series (fluid outlet of one borehole feeds the next) configurations.

model

Full physical model of the BHE system.

Type:

PhysicalModel

envprops

Static radiative and thermal properties of the external environment.

Type:

EnvironmentalProperties

envinput

Time series of external air temperature and solar irradiance.

Type:

EnvironmentalTimeSeries

timesteps

Duration of each time step [s].

Type:

float

n_steps

Total number of simulation time steps.

Type:

int

mw_tot

Mass flow rate time series, shape (n_bhes, n_steps) or (n_groups, n_steps) in series mode [kg/s].

Type:

NDArray[np.float64]

Tf1

Inlet fluid temperature time series, shape (n_bhes, n_steps) or (n_groups, n_steps) [°C]. When mw is 0 this value must be set as NaN.

Example

>>> Tf1_5 = np.full((1, 100), 4, dtype = np.float64)
>>> Tf1_null = np.full((1, 200), np.nan, dtype = np.float64)
>>> Tf1 = np.concatenate((Tf1_5, Tf1_null), axis = 1)
Type:

NDArray[np.float64]

fls_mode

FLS simulation mode. Accepts 'sqrt' or 'continuous'. The first is less expensive; the latter is more accurate.

Type:

str

groups

Series groups mapping group index to ordered list of borehole indices. Required for series mode, None in parallel mode.

Type:

dict or None

env

Assembled external environment, built at construction time.

Type:

ExternalEnvironment

T_sup_kusuda

Kusuda-Achenbach temperature profile for upper ground layers, shape (n_steps, m_mesh_sup + 1) [°C].

Type:

NDArray[np.float64]

T_middle_kusuda

Kusuda-Achenbach temperature profile for middle ground and borehole layers, shape (n_steps, m_mesh * (n_mesh + n_equations)) [°C].

Type:

NDArray[np.float64]

T_inf_kusuda

Kusuda-Achenbach temperature profile for lower ground layers, shape (n_steps, m_mesh_inf) [°C].

Type:

NDArray[np.float64]

T_bc

Far-field boundary condition array, shape (n_steps, n_bhes, m_mesh) [°C].

Type:

NDArray[np.float64]

T_history

Output temperature history, shape (n_steps + 1, n_bhes, n_dof) [°C].

Type:

NDArray[np.float64]

fls

FLS thermal interference model. None in single-borehole mode.

Type:

FiniteLineSolution or None

gr_p_varprops

Soil moisture module for ground thermophysical properties. Instantiated only if envinput.water_input is not None.

Type:

SoilMoisture or None

bh_p_varprops

Soil moisture module for borehole thermophysical properties. Instantiated only if envinput.water_input is not None.

Type:

SoilMoisture or None

k_ground_history

Thermal conductivity history for the ground, shape (n_steps, n_bhes) [W/(m K)]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

cp_ground_history

Volumetric heat capacity history for the ground, shape (n_steps, n_bhes) [J/(m³ K)]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

rho_ground_history

Density history for the ground, shape (n_steps, n_bhes) [kg/m³]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

k_borehole_history

Thermal conductivity history for the borehole, shape (n_steps, n_bhes) [W/(m K)]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

cp_borehole_history

Volumetric heat capacity history for the borehole, shape (n_steps, n_bhes) [J/(m³ K)]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

rho_borehole_history

Density history for the borehole, shape (n_steps, n_bhes) [kg/m³]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

wc_history_ground

Residual water volume history for the ground, shape (n_steps, n_bhes) [m³]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

wc_history_borehole

Residual water volume history for the borehole, shape (n_steps, n_bhes) [m³]. Available only if envinput.water_input is not None.

Type:

NDArray[np.float64]

model: PhysicalModel
envprops: EnvironmentalProperties
envinput: EnvironmentalTimeSeries
timesteps: float
n_steps: int
mw_tot: ndarray[tuple[Any, ...], dtype[float64]]
Tf1: ndarray[tuple[Any, ...], dtype[float64]] | None = None
heat_flux: bool = False
Q_buildings: ndarray[tuple[Any, ...], dtype[float64]] | None = None
T_supply: ndarray[tuple[Any, ...], dtype[float64]] | None = None
fls_mode: str = 'sqrt'
groups: Dict | None = None
T_sup_kusuda: ndarray[tuple[Any, ...], dtype[float64]]
T_middle_kusuda: ndarray[tuple[Any, ...], dtype[float64]]
T_inf_kusuda: ndarray[tuple[Any, ...], dtype[float64]]
env: ExternalEnvironment
T_bc: ndarray[tuple[Any, ...], dtype[float64]]
T_history: ndarray[tuple[Any, ...], dtype[float64]]
fls: FiniteLineSolution | None = None
run(parallel=None, series=None)[source]

Run the simulation in parallel or series mode.

Dispatches to _run_parallel() or _run_series() based on the provided flags. For single-borehole configurations, parallel and series must both be None.

Parameters:
  • parallel (bool or None) – Set to True to run in parallel mode (independent boreholes).

  • series (bool or None) – Set to True to run in series mode (fluid outlet chaining).

Returns:

Temperature history array of shape (n_steps + 1, n_bhes, n_dof).

Return type:

NDArray[np.float64]

Raises:

ValueError – If both or neither flags are set, or if series groups are not defined.

Examples

>>> T_hist = sim.run(parallel=True)
>>> T_hist.shape
(n_steps + 1, n_bhes, n_dof)
class carm.Fluid[source]

Bases: object

Thermophysical properties of the heat carrier fluid.

k_w

Thermal conductivity [W / (m K)].

Type:

float

rho_w

Density [kg/m³].

Type:

float

cp_w

Specific heat capacity [J / (kg K)].

Type:

float

ni_w

Kinematic viscosity [m²/s].

Type:

float

k_w: float
rho_w: float
cp_w: float
ni_w: float
class carm.EnvironmentalProperties[source]

Bases: object

Physical and thermal properties of the external environment.

Groups all site-specific parameters that characterize the surface boundary condition: radiative exchange coefficients, surface optical properties, and the seasonal air temperature signal.

R_ext

External thermal resistance [W / (K m²)].

Type:

float

absorptance

Surface absorptance for solar radiation [-].

Type:

float

eps

Surface emittance for longwave radiation [-].

Type:

float

At

Annual amplitude of monthly average air temperature [K].

Type:

float

tau

Current simulation time [s].

Type:

float

tau_y

Duration of one year (315,536,000 s) [s].

Type:

float

tau_shift

Time offset to account for the date of minimum surface temperature [s].

Type:

float

R_ext: float
absorptance: float
eps: float
At: float
tau: float
tau_y: float
tau_shift: float
class carm.EnvironmentalTimeSeries[source]

Bases: object

Time series of external environmental inputs.

Stores the external air temperature and solar irradiance arrays used to drive the surface boundary condition over the simulation period. Instances should be created via the class methods to ensure input validation.

Tm

Mean annual air temperature [°C].

Type:

float

T_ext

External air temperature time series [°C].

Type:

NDArray[np.float64]

SolarRad

Solar irradiance time series [W/m²].

Type:

NDArray[np.float64]

water_input

Water input series by irrigation or metherological phenomena [m3 / s].

Type:

NDArray[np.float64] | None = None

Tm: float
T_ext: ndarray[tuple[Any, ...], dtype[float64]]
SolarRad: ndarray[tuple[Any, ...], dtype[float64]]
water_input: ndarray[tuple[Any, ...], dtype[float64]] | None = None
classmethod from_excel(Tm, path)[source]

Construct an instance from an Excel file.

The file must contain columns named T_ext and SolarRad. All values must be finite (no NaN or Inf).

Parameters:
  • Tm (float) – Mean annual air temperature [°C].

  • path (Path or str) – Path to the Excel file (.xlsx).

Returns:

A validated instance populated from the file.

Return type:

EnvironmentalTimeSeries

Raises:

ValueError – If T_ext, SolarRad, or water_input contain non-finite values.

Examples

>>> env = EnvironmentalTimeSeries.from_excel(12.0, "data/climate.xlsx")
>>> env.T_ext.shape
(8760,)
classmethod from_array(Tm, T_ext, SolarRad, water_input=None)[source]

Construct an instance from NumPy arrays.

All values must be finite (no NaN or Inf).

Parameters:
  • Tm (float) – Mean annual air temperature [°C].

  • T_ext (NDArray[np.float64]) – External air temperature time series [°C].

  • SolarRad (NDArray[np.float64]) – Solar irradiance time series [W/m²].

  • water_input (NDArray[np.float64] | None = None) – Water input series by irrigation or metherological phenomena [m3 / s].

Returns:

A validated instance populated from the arrays.

Return type:

EnvironmentalTimeSeries

Raises:

ValueError – If T_ext, SolarRad, or water_input contain non-finite values.

Examples

>>> import numpy as np
>>> T = np.linspace(-5, 25, 8760)
>>> rad = np.abs(np.sin(np.linspace(0, 2 * np.pi, 8760))) * 600
>>> env = EnvironmentalTimeSeries.from_array(12.0, T, rad)
class carm.FieldInput[source]

Bases: object

Geometry container for the borehole field layout.

Stores the field bounding box and borehole coordinates, with validation. Coordinates must be loaded explicitly via one of the from_* methods before the field can be used downstream.

n_bhes

Number of boreholes in the field.

Type:

int

xmin, xmax

Field bounding box x-extent [m].

Type:

float

ymin, ymax

Field bounding box y-extent [m].

Type:

float

borehole_coordinates

List of (x, y) coordinate pairs for each borehole [m]. [] until populated via a from_* method.

Type:

Sequence[tuple[float, float]]

rb

External Borehole radius [m]

Type:

float

layout

Borehole spacing layout. The layout can be “regular” or “irregular”. If regular, the adiabatic condition will be applied at mid-distancce between thoe adjacent boreholes. If irregular, the FLS calculation will be performed to account for penalty temperature at the ground maximum radius. By default it is “regular”. It is important that even if regularly spaced, if series connection is present, the layout must be set as irregular.

Type:

str

property borehole_coordinates: Sequence[tuple[float, float]]
from_excel(path)[source]

Load borehole coordinates from an Excel file.

The file must contain columns named x and y.

Parameters:

path (Path or str) – Path to the Excel file (.xlsx).

Raises:

ValueError – If coordinates are non-finite, outside the bounding box, or the number of rows does not match n_bhes.

Return type:

None

Examples

>>> fi = FieldInput(n_bhes=4, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_excel("data/field.xlsx")
>>> fi.borehole_coordinates
[(2.5, 2.5), (7.5, 2.5), (2.5, 7.5), (7.5, 7.5)]
from_array(x, y)[source]

Load borehole coordinates from two 1-D arrays.

Parameters:
  • x (NDArray) – x-coordinates of the boreholes [m].

  • y (NDArray) – y-coordinates of the boreholes [m].

Raises:

ValueError – If x and y have different lengths, contain non-finite values, or coordinates fall outside the bounding box.

Return type:

None

Examples

>>> fi = FieldInput(n_bhes=2, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_array(np.array([3.0, 7.0]), np.array([5.0, 5.0]))
from_matrix(matrix)[source]

Load borehole coordinates from a 2-D array of shape (n_bhes, 2).

Parameters:

matrix (NDArray) – Array with columns [x, y] for each borehole [m].

Raises:

ValueError – If the array is not 2-D, does not have exactly 2 columns, or coordinates fail validation.

Return type:

None

Examples

>>> coords = np.array([[3.0, 5.0], [7.0, 5.0]])
>>> fi = FieldInput(n_bhes=2, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_matrix(coords)
class carm.Field[source]

Bases: object

Voronoi decomposition and interaction geometry of the borehole field.

Built from a populated FieldInput, computes the Voronoi cell for each borehole, the equivalent radius r_eq = sqrt(area / pi), the pairwise distance matrix (corrected for r_eq), and the neighbor graph.

fieldinput

Source geometry object (must have coordinates loaded).

Type:

FieldInput

field_dict

Mapping from borehole index to its Voronoi cell data:

{i: {"cell": Polygon, "area": float, "req": float, "coords": (x, y)}}
Type:

dict

distance_matrix

Symmetric matrix of shape (n_bhes, n_bhes) with inter-borehole distances corrected by r_eq [m]. Diagonal entries are zero.

Type:

NDArray[np.float64]

property distance_matrix: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property field_dict: dict
plot_field(ax=None, show_points=True, show_ids=False, show_area=False, show_req=False, color_by_area=False, alpha=0.35, linewidth=0.5, point_size=8, save_path=None, show=True, show_graph=False)[source]

Plot the Voronoi field decomposition.

Parameters:
  • ax (matplotlib.axes.Axes or None) – Axes to draw on. If None, a new figure is created.

  • show_points (bool) – If True, draw borehole generator points.

  • show_ids (bool) – If True, annotate each point with its borehole index.

  • show_area (bool) – If True, label each cell with its area.

  • show_req (bool) – If True, label each cell with its equivalent radius r_eq.

  • color_by_area (bool) – If True, shade cells according to their area.

  • alpha (float) – Cell fill transparency.

  • linewidth (float) – Line width for cell edges and domain boundary.

  • point_size (float) – Marker size for borehole points.

  • save_path (str or None) – If provided, save the figure to this path at 300 dpi.

  • show (bool) – If True, call plt.show().

  • show_graph (bool) – If True, draw edges of the Voronoi neighbor graph.

Returns:

  • fig (matplotlib.figure.Figure) – The figure object.

  • ax (matplotlib.axes.Axes) – The axes object.

Return type:

tuple[Figure, Axes]

Examples

>>> fi = FieldInput(n_bhes=4, xmin=0, ymin=0, xmax=10, ymax=10)
>>> fi.from_array(np.array([2.5, 7.5, 2.5, 7.5]),
...               np.array([2.5, 2.5, 7.5, 7.5]))
>>> f = Field(fieldinput=fi)
>>> fig, ax = f.plot_field(show=False)