Variable Grout Properties

The SoilMoisture class updates grout thermal conductivity, volumetric heat capacity, and density over time as a function of volumetric water content, to account for irrigation-driven moisture changes around the borehole.

At each timestep, a water volume balance is tracked around the borehole: irrigation adds water, while gravity drainage and evaporation remove it. Drainage loss follows the Brooks-Corey (1964) unsaturated hydraulic conductivity model, so it depends on the current water content relative to the soil’s residual and saturated values (theta_r, theta_s) and on two soil-specific parameters, the saturated hydraulic conductivity Ks and the pore-size distribution index lambda. Evaporation loss is driven by the thermal power exchanged with the ground. The resulting water volume is clipped between the residual and saturated volumes and converted back to a volumetric water content, which feeds the Chung-Horton/de Vries correlations for thermal conductivity, heat capacity, and density.

class carm.properties.SoilMoisture[source]

Bases: object

Soil moisture and thermophysical properties module.

Computes borehole thermophysical properties (thermal conductivity, specific heat capacity, density) as a function of volumetric water content, using Chung-Horton (1987) for thermal conductivity, de Vries (1963) for volumetric heat capacity, and a mass-weighted average for density.

At each timestep, the water volume stored around the borehole is updated from a water balance: irrigation input increases it, while gravity drainage (Brooks-Corey, 1964, unsaturated hydraulic conductivity) and evaporation (driven by the exchanged thermal power) deplete it. The resulting volume is converted back to a volumetric water content and fed into the property correlations above.

w_rho

Density of water [kg/m³].

Type:

float

w_latent

Latent heat of vaporization of water [J/kg].

Type:

float

SOIL_PARAMS

Tabulated parameters for sand, loam, and clay soil types. Each entry contains: b1, b2, b3 (Chung-Horton), theta_s, theta_r (Rawls et al.), xs (solid volume fraction), x0 (organic matter fraction), lambda (Brooks-Corey pore-size distribution index), Ks (saturated hydraulic conductivity [m/s]).

Type:

dict

water_input

Water flux time series [m/s].

Type:

NDArray

rho_dry

Dry soil density [kg/m³].

Type:

float

b1_loc

Chung-Horton parameter b1 for the selected soil type [W/(m K)].

Type:

float

b2_loc

Chung-Horton parameter b2 for the selected soil type [W/(m K)].

Type:

float

b3_loc

Chung-Horton parameter b3 for the selected soil type [W/(m K)].

Type:

float

theta_s_loc

Saturated volumetric water content for the selected soil type [-].

Type:

float

theta_r_loc

Residual volumetric water content for the selected soil type [-].

Type:

float

xs_loc

Solid volume fraction for the selected soil type [-].

Type:

float

x0_loc

Organic matter volume fraction for the selected soil type [-].

Type:

float

lambda_loc

Brooks-Corey pore-size distribution index for the selected soil type [-]. Governs how steeply unsaturated hydraulic conductivity (and thus drainage loss) drops as water content decreases.

Type:

float

Ks_loc

Saturated hydraulic conductivity for the selected soil type [m/s].

Type:

float

Wvol_prev

Water volume at the previous timestep [m³]. None before the first call to _properties_calculation(), when it is initialized to the residual water volume (theta_r_loc * V).

Type:

float | None

Wvol_r

Water volume at the current timestep [m³], clipped between the residual (theta_r_loc * V) and saturated (theta_s_loc * V) volumes. None until the first call to _properties_calculation().

Type:

float | None

Wvol_loss

Water volume lost by gravity drainage at the current timestep [m³], computed from the Brooks-Corey unsaturated hydraulic conductivity.

Type:

float

Wvol_evap

Water volume lost by evaporation at the current timestep [m³].

Type:

float

W_content

Volumetric water content at the current timestep [-].

Type:

float

w_rho = 1000.0
w_latent = 2250000.0
SOIL_PARAMS = {'clay': {'Ks': 1.6699999999999997e-07, 'b1': -0.197, 'b2': -0.962, 'b3': 2.521, 'lambda': 0.165, 'theta_r': 0.09, 'theta_s': 0.385, 'x0': 0.024, 'xs': 0.591}, 'loam': {'Ks': 3.6699999999999996e-06, 'b1': 0.243, 'b2': 0.393, 'b3': 1.534, 'lambda': 0.252, 'theta_r': 0.027, 'theta_s': 0.434, 'x0': 0.018, 'xs': 0.548}, 'sand': {'Ks': 5.830000000000001e-05, 'b1': 0.228, 'b2': -2.406, 'b3': 4.909, 'lambda': 0.694, 'theta_r': 0.0295, 'theta_s': 0.417, 'x0': 0.012, 'xs': 0.571}}

When to use it

SoilMoisture is only instantiated when water_input is provided in EnvironmentalTimeSeries. In that case, D_irrigation and perf_fraction must also be set on BoreholeGeometry, since they define the irrigation pipe surface area used in the water balance:

A_irr = pi * borehole.D_irrigation * borehole.perf_fraction * borehole.Lbore

Field-level update

Properties are recomputed once per timestep at the field level, not once per borehole. All boreholes share the same grout composition and receive the same irrigation input; the evaporation term uses the mean heat flux across the field rather than a per-borehole value:

q = np.mean(self.q_nbhes[step - 1])

Sensitivity of the water content to the per-borehole heat flux (as opposed to the field average) was verified to be negligible over the operating range (0–10 kW).

Example

from carm import BoreholeGeometry, BoreholeThermalProperties

geom = BoreholeGeometry(
    Lbore=30, D0=0.5,
    D_irrigation=0.030, perf_fraction=0.5,
)
thermalprops = BoreholeThermalProperties(
    cp_0=796.14, rho_0=1587.09, k0=1.0, soil_type="sand",
)

Note

rho_0 above is the dry soil density, required when water_input is active. For simulations without irrigation, use the density at residual water content instead.