Soil porosity by USDA texture class and bulk density

This notebook produces interactive charts showing how soil texture, compaction (bulk density), and organic matter change a soil’s capacity to store and transmit water. Charts cover all 12 USDA texture classes and bulk densities from 0.8 to 1.9 g/cm³. The visualizations may inform stormwater design, soil-health assessment, and land-management decisions.

Using the Rosetta pedotransfer functions (usda-ars-ussl/rosetta-soil), we estimate the soil water status for each texture class and bulk density:

Output Definition
Saturation Saturated volumetric water content θₛ (van Genuchten), model is using total porosity so saturation as modeled is a condition if all pores were able to fill with water.
Field-capacity Volumetric water content at 33 kPa (= 330 cm suction)
Permanent-wilting-point Volumetric water content at 1500 kPa (= 15000 cm suction)
Saturated hydraulic conductivity Ksat (cm/day)

Rosetta predicts the van Genuchten water-retention parameters (θᵣ, θₛ, α, n) from texture and bulk density. We then evaluate the retention curve at field-capacity and wilting-point.

van Genuchten (1980) retention model: \[\theta(h) = \theta_r + \frac{\theta_s - \theta_r}{\left[1 + (\alpha\,h)^{n}\right]^{m}}, \qquad m = 1 - \tfrac{1}{n}\]

where \(h\) is the matric potential (suction head) [cm] and \(\alpha\) [1/cm] is related to air entry, \(n\) [-] is a pore-size distribution parameter, \(\theta_r\), \(\theta_s\) are residual and saturated volumetric water content.

Environment: built with pixi (pixi.toml). Run pixi install, then open this notebook with the soil_modeling kernel (pixi run jupyter lab).

Show code
import numpy as np
import pandas as pd
from rosetta import rosetta, SoilData

# Shared helpers (display table, van Genuchten–Mualem functions, extrapolation-aware line plot);
# importing _helpers also sets the shared pandas float_format. See notebooks/_helpers.py.
from _helpers import show, vg_theta, mualem_k, line_with_extrapolation, soil_water_texture_band_diagram, export_water_storage_tables

1. Representative (median) texture values for each USDA class

Each texture class is represented by a single sand/silt/clay triplet via central (representative) values. Each triplet sums to 100% and falls inside the correct region of the USDA texture triangle. Adjust these if you prefer a different convention (e.g. the geometric or modified centroids of Levi, 2017, SSSAJ).

Show code
# texture_class: (sand %, silt %, clay %)
TEXTURE_CLASSES = {
    "sand":            (92,  5,  3),
    "loamy sand":      (82, 12,  6),
    "sandy loam":      (65, 25, 10),
    "loam":            (40, 40, 20),
    "silt loam":       (20, 65, 15),
    "silt":            ( 7, 88,  5),
    "sandy clay loam": (60, 13, 27),
    "clay loam":       (30, 35, 35),
    "silty clay loam": (10, 56, 34),
    "sandy clay":      (50,  7, 43),
    "silty clay":      ( 7, 47, 46),
    "clay":            (20, 20, 60),
}

# NRCS hydrologic soil group (HSG) inferred from texture class. This is the standard
# texture-based approximation used when saturated hydraulic conductivity is unknown
# (e.g. HYSOGs250m, SWAT). Full HSG determination depends on Ksat, depth to a restrictive
# layer, and water-table depth. A = low runoff / high infiltration ... D = high runoff.
# A dual group like "B/D" is the NRCS convention for soils that are group D in their natural
# (undrained, high-water-table) state but the lettered group (B) once drained — silt qualifies.
HYDROLOGIC_SOIL_GROUP = {
    "sand":            "A",
    "loamy sand":      "A",
    "sandy loam":      "A",
    "loam":            "B",
    "silt loam":       "B",
    "silt":            "B/D",
    "sandy clay loam": "C",
    "clay loam":       "D",
    "silty clay loam": "D",
    "sandy clay":      "D",
    "silty clay":      "D",
    "clay":            "D",
}

texture_df = (
    pd.DataFrame.from_dict(
        TEXTURE_CLASSES, orient="index", columns=["sand_pct", "silt_pct", "clay_pct"]
    )
    .rename_axis("texture_class")
    .reset_index()
)
# hydrologic soil group immediately to the right of texture_class
texture_df.insert(1, "hydrologic_soil_group", texture_df["texture_class"].map(HYDROLOGIC_SOIL_GROUP))

# sanity check: each class sums to 100%
assert (texture_df[["sand_pct", "silt_pct", "clay_pct"]].sum(axis=1) == 100).all()
display(texture_df)
texture_class hydrologic_soil_group sand_pct silt_pct clay_pct
0 sand A 92 5 3
1 loamy sand A 82 12 6
2 sandy loam A 65 25 10
3 loam B 40 40 20
4 silt loam B 20 65 15
5 silt B/D 7 88 5
6 sandy clay loam C 60 13 27
7 clay loam D 30 35 35
8 silty clay loam D 10 56 34
9 sandy clay D 50 7 43
10 silty clay D 7 47 46
11 clay D 20 20 60

2. Bulk-density range and suction set-points

Bulk density (g/cm³) is a direct measure of soil compaction: lower values indicate more pore space; higher values reflect a more compacted, denser soil. Field capacity (33 kPa) and permanent wilting point (1500 kPa) are the standard agronomic thresholds that bound plant-available water.

Show code
# Bulk density 0.8 -> 1.9 g/cm3 in 0.1 steps (rounded to avoid float drift). Capped at 1.9:
# BD 2.0 is physically implausible (θₛ > pore space) for most textures — see implausible_bd.
bulk_densities = np.round(np.arange(0.8, 1.9 + 1e-9, 0.1), 1)

# Suction heads (cm) at which to evaluate the retention curve
H_FIELD_CAPACITY = 330.0    # 33 kPa
H_WILTING_POINT = 15000.0   # 1500 kPa

print(f"{len(bulk_densities)} bulk densities: {bulk_densities}")
12 bulk densities: [0.8 0.9 1.  1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9]

3. van Genuchten–Mualem helpers

vg_theta gives the retention curve θ(h); mualem_k gives the unsaturated hydraulic conductivity K(h) from Rosetta’s Mualem–van Genuchten parameters (matching-point K0 and pore-connectivity L, columns 5–6 of the Rosetta output). Used for K at field capacity / wilting point (§4) and carried in the CSV for the hydraulic-conductivity notebook (Notebook 3). Both functions are shared with Notebook 3 and live in notebooks/_helpers.py (imported above).

4. Run Rosetta and build the results DataFrame

Rosetta input columns are [sand%, silt%, clay%, bulk_density]; model version 3 (2017 recalibration) is used. The mean output columns are [θᵣ, θₛ, α, n, Ksat, K0, L] with α in 1/cm and n dimensionless (linear, not log₁₀). We keep Ksat (saturated hydraulic conductivity, column 4) as ksat_cm_day (cm/day) and ksat_in_hr (in/hr = cm/day ÷ 24 ÷ 2.54, the usual stormwater unit). We also retain the Mualem–van Genuchten parameters theta_r, vg_alpha_1cm, vg_n, k0_cm_day, mualem_L (used by the hydraulic-conductivity notebook, Notebook 3) and the unsaturated K at field capacity / wilting point (k_fc_cm_day, k_wp_cm_day).

Show code
# Build every (texture class) x (bulk density) combination
rows = [
    {
        "texture_class": cls,
        "hydrologic_soil_group": HYDROLOGIC_SOIL_GROUP[cls],
        "sand_pct": sand,
        "silt_pct": silt,
        "clay_pct": clay,
        "bulk_density_g_cm3": bd,
    }
    for cls, (sand, silt, clay) in TEXTURE_CLASSES.items()
    for bd in bulk_densities
]
df = pd.DataFrame(rows)

# Rosetta expects [sand, silt, clay, bulk_density]
rosetta_input = df[["sand_pct", "silt_pct", "clay_pct", "bulk_density_g_cm3"]].to_numpy()
mean, stdev, codes = rosetta(3, SoilData.from_iter(rosetta_input.tolist()))
mean = np.asarray(mean)

theta_r, theta_s, alpha, n = mean[:, 0], mean[:, 1], mean[:, 2], mean[:, 3]
ksat = mean[:, 4]  # saturated hydraulic conductivity, cm/day (linear, not log10)
k0 = mean[:, 5]    # Mualem matching-point conductivity, cm/day
Lpar = mean[:, 6]  # Mualem pore-connectivity exponent, dimensionless (often negative)

df["total_porosity"] = theta_s
df["field_capacity_porosity"] = vg_theta(H_FIELD_CAPACITY, theta_r, theta_s, alpha, n)
df["wilting_point_porosity"] = vg_theta(H_WILTING_POINT, theta_r, theta_s, alpha, n)
df["available_water_capacity"] = (
    df["field_capacity_porosity"] - df["wilting_point_porosity"]
)
df["ksat_cm_day"] = ksat  # Rosetta saturated hydraulic conductivity (cm/day)
df["ksat_in_hr"] = ksat / (24.0 * 2.54)  # same Ksat in inches/hour (stormwater units)
# van Genuchten–Mualem parameters kept for the unsaturated-K and infiltration sections (§10–§11)
df["theta_r"] = theta_r
df["vg_alpha_1cm"] = alpha
df["vg_n"] = n
df["k0_cm_day"] = k0
df["mualem_L"] = Lpar
# unsaturated K at field capacity (33 kPa) and wilting point (1500 kPa), cm/day
df["k_fc_cm_day"] = mualem_k(H_FIELD_CAPACITY, alpha, n, k0, Lpar)
df["k_wp_cm_day"] = mualem_k(H_WILTING_POINT, alpha, n, k0, Lpar)
df["rosetta_code"] = np.asarray(codes)  # 3 = texture + bulk density model

# Physical-plausibility flag. Saturated water content θₛ cannot exceed the pore space
# implied by the bulk density (1 - BD/ρ_particle, ρ_particle ≈ 2.65 g/cm³). Where Rosetta's
# θₛ exceeds it, the texture × BD combination is an extrapolation outside Rosetta's training
# domain (e.g. high-BD silt, which drives the spurious Ksat upturn). True = implausible.
PARTICLE_DENSITY = 2.65  # g/cm³, quartz-dominated mineral soil
df["implausible_bd"] = df["total_porosity"] > (1.0 - df["bulk_density_g_cm3"] / PARTICLE_DENSITY)

print(f"{len(df)} rows  ({len(TEXTURE_CLASSES)} classes x {len(bulk_densities)} bulk densities)")
show(df)
144 rows  (12 classes x 12 bulk densities)
texture_class hydrologic_soil_group sand_pct silt_pct clay_pct bulk_density_g_cm3 total_porosity field_capacity_porosity wilting_point_porosity available_water_capacity ksat_cm_day ksat_in_hr theta_r vg_alpha_1cm vg_n k0_cm_day mualem_L k_fc_cm_day k_wp_cm_day rosetta_code implausible_bd
0 sand A 92 5 3 0.800 0.560 0.141 0.072 0.069 992.244 16.277 0.070 0.029 1.848 53.148 -0.574 0.008 0.000 3 False
1 sand A 92 5 3 0.900 0.531 0.129 0.068 0.062 874.440 14.344 0.066 0.026 1.930 36.508 -0.473 0.006 0.000 3 False
2 sand A 92 5 3 1.000 0.503 0.113 0.064 0.049 803.505 13.181 0.063 0.025 2.033 29.219 -0.477 0.004 0.000 3 False
3 sand A 92 5 3 1.100 0.475 0.096 0.061 0.036 763.127 12.518 0.060 0.025 2.154 24.929 -0.542 0.003 0.000 3 False
4 sand A 92 5 3 1.200 0.450 0.082 0.058 0.024 731.398 11.998 0.058 0.026 2.289 22.146 -0.638 0.002 0.000 3 False
5 sand A 92 5 3 1.300 0.425 0.072 0.056 0.016 690.465 11.327 0.056 0.027 2.430 20.779 -0.734 0.002 0.000 3 False
6 sand A 92 5 3 1.400 0.401 0.064 0.054 0.010 630.566 10.344 0.054 0.029 2.563 20.654 -0.809 0.001 0.000 3 False
7 sand A 92 5 3 1.500 0.376 0.059 0.052 0.007 544.378 8.930 0.052 0.031 2.653 21.556 -0.857 0.001 0.000 3 False
8 sand A 92 5 3 1.600 0.352 0.057 0.050 0.006 424.038 6.956 0.050 0.032 2.638 23.625 -0.874 0.001 0.000 3 False
9 sand A 92 5 3 1.700 0.327 0.056 0.049 0.007 301.562 4.947 0.049 0.033 2.532 27.468 -0.876 0.001 0.000 3 False
10 sand A 92 5 3 1.800 0.303 0.055 0.048 0.007 218.069 3.577 0.048 0.035 2.449 36.333 -0.883 0.002 0.000 3 False
11 sand A 92 5 3 1.900 0.281 0.054 0.047 0.007 173.663 2.849 0.047 0.038 2.415 83.843 -0.888 0.003 0.000 3 False
12 loamy sand A 82 12 6 0.800 0.554 0.253 0.097 0.156 487.050 7.990 0.074 0.018 1.545 16.326 -0.346 0.011 0.000 3 False
13 loamy sand A 82 12 6 0.900 0.525 0.228 0.088 0.140 421.489 6.914 0.071 0.018 1.589 14.527 -0.322 0.009 0.000 3 False
14 loamy sand A 82 12 6 1.000 0.498 0.203 0.081 0.123 369.826 6.067 0.068 0.018 1.636 13.651 -0.361 0.008 0.000 3 False
15 loamy sand A 82 12 6 1.100 0.472 0.180 0.074 0.106 321.878 5.280 0.066 0.019 1.684 13.228 -0.433 0.008 0.000 3 False
16 loamy sand A 82 12 6 1.200 0.447 0.159 0.070 0.090 274.748 4.507 0.064 0.020 1.729 13.048 -0.520 0.007 0.000 3 False
17 loamy sand A 82 12 6 1.300 0.423 0.141 0.066 0.076 229.151 3.759 0.061 0.021 1.769 13.056 -0.614 0.006 0.000 3 False
18 loamy sand A 82 12 6 1.400 0.400 0.127 0.062 0.065 186.012 3.051 0.059 0.022 1.799 13.213 -0.706 0.006 0.000 3 False
19 loamy sand A 82 12 6 1.500 0.377 0.116 0.060 0.057 145.188 2.382 0.057 0.024 1.810 13.454 -0.796 0.006 0.000 3 False
20 loamy sand A 82 12 6 1.600 0.353 0.111 0.058 0.053 105.214 1.726 0.055 0.025 1.782 13.723 -0.890 0.006 0.000 3 False
21 loamy sand A 82 12 6 1.700 0.328 0.112 0.058 0.054 69.610 1.142 0.054 0.027 1.716 14.156 -0.996 0.007 0.000 3 False
22 loamy sand A 82 12 6 1.800 0.305 0.112 0.058 0.054 45.577 0.748 0.053 0.028 1.649 16.243 -1.096 0.008 0.000 3 False
23 loamy sand A 82 12 6 1.900 0.282 0.109 0.058 0.051 32.713 0.537 0.052 0.030 1.609 31.984 -1.179 0.015 0.000 3 False
24 sandy loam A 65 25 10 0.800 0.544 0.339 0.129 0.210 345.058 5.660 0.081 0.010 1.455 4.963 0.012 0.013 0.000 3 False
25 sandy loam A 65 25 10 0.900 0.517 0.313 0.119 0.194 261.554 4.291 0.078 0.010 1.472 4.803 -0.047 0.012 0.000 3 False
26 sandy loam A 65 25 10 1.000 0.490 0.289 0.110 0.178 196.156 3.218 0.075 0.011 1.486 4.834 -0.143 0.011 0.000 3 False
27 sandy loam A 65 25 10 1.100 0.466 0.266 0.103 0.163 145.698 2.390 0.073 0.012 1.496 4.954 -0.257 0.010 0.000 3 False
28 sandy loam A 65 25 10 1.200 0.442 0.246 0.097 0.148 107.304 1.760 0.071 0.013 1.501 5.111 -0.381 0.009 0.000 3 False
29 sandy loam A 65 25 10 1.300 0.419 0.228 0.093 0.135 78.162 1.282 0.068 0.014 1.502 5.289 -0.509 0.009 0.000 3 False
30 sandy loam A 65 25 10 1.400 0.396 0.213 0.089 0.124 56.362 0.925 0.066 0.015 1.496 5.509 -0.641 0.008 0.000 3 False
31 sandy loam A 65 25 10 1.500 0.374 0.201 0.087 0.114 39.936 0.655 0.064 0.016 1.481 5.772 -0.776 0.008 0.000 3 False
32 sandy loam A 65 25 10 1.600 0.351 0.192 0.086 0.106 27.110 0.445 0.063 0.017 1.451 6.082 -0.926 0.008 0.000 3 False
33 sandy loam A 65 25 10 1.700 0.328 0.188 0.089 0.099 17.322 0.284 0.061 0.018 1.406 6.551 -1.113 0.008 0.000 3 False
34 sandy loam A 65 25 10 1.800 0.306 0.184 0.092 0.092 10.893 0.179 0.060 0.019 1.360 7.607 -1.347 0.008 0.000 3 False
35 sandy loam A 65 25 10 1.900 0.284 0.179 0.095 0.083 7.269 0.119 0.060 0.021 1.322 11.189 -1.619 0.011 0.000 3 True
36 loam B 40 40 20 0.800 0.559 0.421 0.163 0.258 256.843 4.213 0.098 0.005 1.453 1.999 0.334 0.022 0.000 3 False
37 loam B 40 40 20 0.900 0.530 0.395 0.154 0.241 165.697 2.718 0.095 0.005 1.456 1.745 0.281 0.018 0.000 3 False
38 loam B 40 40 20 1.000 0.502 0.371 0.147 0.224 104.354 1.712 0.093 0.006 1.456 1.624 0.180 0.016 0.000 3 False
39 loam B 40 40 20 1.100 0.476 0.348 0.141 0.207 65.280 1.071 0.091 0.006 1.452 1.585 0.054 0.014 0.000 3 False
40 loam B 40 40 20 1.200 0.451 0.326 0.137 0.190 41.158 0.675 0.089 0.006 1.444 1.588 -0.083 0.012 0.000 3 False
41 loam B 40 40 20 1.300 0.427 0.307 0.133 0.174 26.290 0.431 0.087 0.007 1.432 1.613 -0.227 0.011 0.000 3 False
42 loam B 40 40 20 1.400 0.404 0.290 0.131 0.159 17.009 0.279 0.086 0.007 1.416 1.657 -0.377 0.010 0.000 3 False
43 loam B 40 40 20 1.500 0.381 0.275 0.130 0.145 11.107 0.182 0.084 0.008 1.393 1.731 -0.538 0.009 0.000 3 False
44 loam B 40 40 20 1.600 0.358 0.262 0.130 0.131 7.236 0.119 0.083 0.009 1.362 1.852 -0.732 0.008 0.000 3 False
45 loam B 40 40 20 1.700 0.336 0.250 0.133 0.117 4.656 0.076 0.081 0.009 1.324 2.071 -0.994 0.008 0.000 3 False
46 loam B 40 40 20 1.800 0.314 0.239 0.136 0.103 3.015 0.049 0.080 0.010 1.285 2.502 -1.350 0.008 0.000 3 False
47 loam B 40 40 20 1.900 0.293 0.228 0.139 0.090 2.038 0.033 0.080 0.011 1.252 3.372 -1.803 0.008 0.000 3 True
48 silt loam B 20 65 15 0.800 0.557 0.458 0.146 0.313 330.144 5.416 0.092 0.003 1.572 1.515 0.746 0.069 0.000 3 False
49 silt loam B 20 65 15 0.900 0.527 0.431 0.138 0.293 203.429 3.337 0.088 0.003 1.574 1.286 0.741 0.056 0.000 3 False
50 silt loam B 20 65 15 1.000 0.499 0.404 0.131 0.273 127.725 2.095 0.085 0.003 1.572 1.166 0.668 0.046 0.000 3 False
51 silt loam B 20 65 15 1.100 0.473 0.378 0.125 0.253 81.420 1.336 0.083 0.003 1.565 1.109 0.553 0.038 0.000 3 False
52 silt loam B 20 65 15 1.200 0.449 0.354 0.121 0.233 52.349 0.859 0.080 0.004 1.554 1.095 0.422 0.032 0.000 3 False
53 silt loam B 20 65 15 1.300 0.427 0.331 0.117 0.214 33.895 0.556 0.078 0.004 1.538 1.110 0.284 0.027 0.000 3 False
54 silt loam B 20 65 15 1.400 0.405 0.310 0.115 0.195 22.196 0.364 0.077 0.004 1.516 1.144 0.141 0.023 0.000 3 False
55 silt loam B 20 65 15 1.500 0.384 0.291 0.113 0.178 14.735 0.242 0.075 0.005 1.489 1.195 -0.010 0.019 0.000 3 False
56 silt loam B 20 65 15 1.600 0.364 0.274 0.114 0.161 9.942 0.163 0.074 0.005 1.455 1.269 -0.178 0.016 0.000 3 False
57 silt loam B 20 65 15 1.700 0.343 0.259 0.115 0.144 6.902 0.113 0.073 0.006 1.416 1.390 -0.376 0.013 0.000 3 False
58 silt loam B 20 65 15 1.800 0.323 0.244 0.117 0.127 5.086 0.083 0.073 0.007 1.376 1.603 -0.617 0.012 0.000 3 True
59 silt loam B 20 65 15 1.900 0.303 0.230 0.118 0.111 4.470 0.073 0.073 0.008 1.340 2.003 -0.915 0.011 0.000 3 True
60 silt B/D 7 88 5 0.800 0.562 0.351 0.103 0.249 1381.028 22.655 0.083 0.006 1.711 3.927 0.390 0.039 0.000 3 False
61 silt B/D 7 88 5 0.900 0.533 0.380 0.102 0.278 690.764 11.331 0.078 0.004 1.707 2.692 0.642 0.064 0.000 3 False
62 silt B/D 7 88 5 1.000 0.506 0.377 0.100 0.277 369.838 6.067 0.074 0.004 1.701 2.103 0.713 0.067 0.000 3 False
63 silt B/D 7 88 5 1.100 0.482 0.361 0.096 0.265 215.558 3.536 0.070 0.004 1.693 1.801 0.686 0.059 0.000 3 False
64 silt B/D 7 88 5 1.200 0.459 0.341 0.093 0.248 136.101 2.233 0.068 0.004 1.680 1.669 0.601 0.050 0.000 3 False
65 silt B/D 7 88 5 1.300 0.438 0.319 0.090 0.229 92.347 1.515 0.066 0.004 1.664 1.632 0.482 0.041 0.000 3 False
66 silt B/D 7 88 5 1.400 0.418 0.297 0.088 0.209 68.169 1.118 0.064 0.004 1.644 1.661 0.342 0.033 0.000 3 False
67 silt B/D 7 88 5 1.500 0.398 0.274 0.086 0.189 58.825 0.965 0.063 0.005 1.620 1.760 0.182 0.026 0.000 3 False
68 silt B/D 7 88 5 1.600 0.379 0.252 0.084 0.167 70.476 1.156 0.062 0.006 1.591 1.956 -0.007 0.020 0.000 3 False
69 silt B/D 7 88 5 1.700 0.360 0.228 0.084 0.145 129.258 2.120 0.062 0.008 1.560 2.337 -0.241 0.015 0.000 3 True
70 silt B/D 7 88 5 1.800 0.341 0.201 0.082 0.120 571.274 9.371 0.063 0.010 1.540 3.146 -0.535 0.011 0.000 3 True
71 silt B/D 7 88 5 1.900 0.323 0.174 0.080 0.094 1463.279 24.004 0.064 0.015 1.527 4.956 -0.883 0.009 0.000 3 True
72 sandy clay loam C 60 13 27 0.800 0.586 0.386 0.186 0.200 231.903 3.804 0.112 0.013 1.350 6.082 -0.785 0.010 0.000 3 False
73 sandy clay loam C 60 13 27 0.900 0.560 0.367 0.176 0.191 174.015 2.855 0.108 0.013 1.359 4.962 -0.751 0.009 0.000 3 False
74 sandy clay loam C 60 13 27 1.000 0.534 0.348 0.168 0.181 128.898 2.114 0.106 0.013 1.366 4.333 -0.755 0.008 0.000 3 False
75 sandy clay loam C 60 13 27 1.100 0.509 0.330 0.160 0.170 93.746 1.538 0.103 0.013 1.370 3.974 -0.787 0.007 0.000 3 False
76 sandy clay loam C 60 13 27 1.200 0.484 0.313 0.154 0.159 66.541 1.092 0.101 0.014 1.371 3.742 -0.843 0.006 0.000 3 False
77 sandy clay loam C 60 13 27 1.300 0.459 0.298 0.149 0.149 45.805 0.751 0.099 0.014 1.368 3.551 -0.921 0.006 0.000 3 False
78 sandy clay loam C 60 13 27 1.400 0.434 0.285 0.146 0.138 30.569 0.501 0.097 0.014 1.359 3.371 -1.023 0.006 0.000 3 False
79 sandy clay loam C 60 13 27 1.500 0.408 0.273 0.145 0.128 19.687 0.323 0.096 0.014 1.342 3.212 -1.159 0.005 0.000 3 False
80 sandy clay loam C 60 13 27 1.600 0.381 0.264 0.147 0.117 12.022 0.197 0.094 0.015 1.313 3.111 -1.363 0.005 0.000 3 False
81 sandy clay loam C 60 13 27 1.700 0.354 0.257 0.152 0.105 6.918 0.113 0.094 0.015 1.275 3.166 -1.697 0.005 0.000 3 False
82 sandy clay loam C 60 13 27 1.800 0.327 0.249 0.157 0.091 3.975 0.065 0.093 0.015 1.239 3.572 -2.195 0.005 0.000 3 True
83 sandy clay loam C 60 13 27 1.900 0.301 0.237 0.159 0.078 2.444 0.040 0.093 0.016 1.211 4.640 -2.809 0.006 0.000 3 True
84 clay loam D 30 35 35 0.800 0.599 0.448 0.205 0.244 215.577 3.536 0.121 0.007 1.379 2.611 -0.202 0.016 0.000 3 False
85 clay loam D 30 35 35 0.900 0.570 0.427 0.196 0.231 137.810 2.261 0.118 0.007 1.380 2.049 -0.189 0.013 0.000 3 False
86 clay loam D 30 35 35 1.000 0.542 0.406 0.189 0.216 85.477 1.402 0.115 0.007 1.378 1.713 -0.237 0.010 0.000 3 False
87 clay loam D 30 35 35 1.100 0.514 0.385 0.184 0.202 51.959 0.852 0.113 0.007 1.374 1.511 -0.320 0.009 0.000 3 False
88 clay loam D 30 35 35 1.200 0.487 0.366 0.179 0.187 31.207 0.512 0.112 0.007 1.366 1.386 -0.418 0.008 0.000 3 False
89 clay loam D 30 35 35 1.300 0.461 0.349 0.176 0.172 18.636 0.306 0.111 0.007 1.355 1.299 -0.530 0.007 0.000 3 False
90 clay loam D 30 35 35 1.400 0.434 0.332 0.175 0.157 11.137 0.183 0.110 0.008 1.340 1.232 -0.663 0.006 0.000 3 False
91 clay loam D 30 35 35 1.500 0.408 0.317 0.174 0.142 6.693 0.110 0.109 0.008 1.320 1.186 -0.830 0.006 0.000 3 False
92 clay loam D 30 35 35 1.600 0.381 0.302 0.176 0.127 4.037 0.066 0.109 0.008 1.294 1.174 -1.058 0.005 0.000 3 False
93 clay loam D 30 35 35 1.700 0.355 0.289 0.178 0.110 2.447 0.040 0.109 0.008 1.263 1.228 -1.399 0.005 0.000 3 False
94 clay loam D 30 35 35 1.800 0.330 0.274 0.181 0.094 1.524 0.025 0.109 0.009 1.231 1.412 -1.890 0.005 0.000 3 True
95 clay loam D 30 35 35 1.900 0.305 0.260 0.181 0.078 1.009 0.017 0.110 0.009 1.204 1.848 -2.537 0.006 0.000 3 True
96 silty clay loam D 10 56 34 0.800 0.609 0.479 0.199 0.280 229.209 3.760 0.122 0.005 1.436 2.158 0.129 0.033 0.000 3 False
97 silty clay loam D 10 56 34 0.900 0.578 0.460 0.192 0.267 138.366 2.270 0.118 0.004 1.438 1.567 0.221 0.026 0.000 3 False
98 silty clay loam D 10 56 34 1.000 0.549 0.438 0.186 0.252 81.976 1.345 0.115 0.004 1.437 1.219 0.207 0.021 0.000 3 False
99 silty clay loam D 10 56 34 1.100 0.520 0.416 0.181 0.236 47.675 0.782 0.114 0.004 1.432 1.013 0.132 0.017 0.000 3 False
100 silty clay loam D 10 56 34 1.200 0.492 0.395 0.176 0.218 27.436 0.450 0.112 0.004 1.424 0.895 0.030 0.015 0.000 3 False
101 silty clay loam D 10 56 34 1.300 0.465 0.374 0.174 0.200 15.812 0.259 0.112 0.005 1.412 0.825 -0.087 0.013 0.000 3 False
102 silty clay loam D 10 56 34 1.400 0.439 0.354 0.172 0.182 9.222 0.151 0.111 0.005 1.394 0.779 -0.221 0.011 0.000 3 False
103 silty clay loam D 10 56 34 1.500 0.413 0.336 0.172 0.164 5.486 0.090 0.111 0.005 1.372 0.752 -0.379 0.009 0.000 3 False
104 silty clay loam D 10 56 34 1.600 0.388 0.318 0.172 0.146 3.339 0.055 0.111 0.005 1.343 0.748 -0.573 0.008 0.000 3 False
105 silty clay loam D 10 56 34 1.700 0.362 0.301 0.174 0.127 2.092 0.034 0.111 0.006 1.311 0.779 -0.829 0.007 0.000 3 True
106 silty clay loam D 10 56 34 1.800 0.338 0.285 0.175 0.109 1.377 0.023 0.111 0.006 1.279 0.868 -1.167 0.006 0.000 3 True
107 silty clay loam D 10 56 34 1.900 0.315 0.268 0.176 0.093 0.974 0.016 0.111 0.007 1.250 1.064 -1.599 0.006 0.000 3 True
108 sandy clay D 50 7 43 0.800 0.616 0.408 0.222 0.186 240.026 3.937 0.133 0.018 1.302 8.437 -1.512 0.009 0.000 3 False
109 sandy clay D 50 7 43 0.900 0.590 0.398 0.216 0.183 166.103 2.725 0.130 0.016 1.305 6.062 -1.395 0.008 0.000 3 False
110 sandy clay D 50 7 43 1.000 0.564 0.386 0.209 0.176 115.164 1.889 0.126 0.016 1.305 4.659 -1.351 0.006 0.000 3 False
111 sandy clay D 50 7 43 1.100 0.539 0.372 0.204 0.168 79.444 1.303 0.124 0.015 1.304 3.821 -1.345 0.005 0.000 3 False
112 sandy clay D 50 7 43 1.200 0.514 0.358 0.199 0.159 54.335 0.891 0.122 0.015 1.300 3.312 -1.370 0.005 0.000 3 False
113 sandy clay D 50 7 43 1.300 0.488 0.345 0.195 0.149 36.772 0.603 0.120 0.015 1.293 2.968 -1.434 0.004 0.000 3 False
114 sandy clay D 50 7 43 1.400 0.463 0.332 0.194 0.139 24.361 0.400 0.119 0.015 1.282 2.687 -1.543 0.004 0.000 3 False
115 sandy clay D 50 7 43 1.500 0.436 0.321 0.193 0.127 15.598 0.256 0.118 0.015 1.265 2.441 -1.723 0.004 0.000 3 True
116 sandy clay D 50 7 43 1.600 0.408 0.310 0.196 0.115 9.416 0.154 0.117 0.015 1.242 2.248 -2.029 0.003 0.000 3 True
117 sandy clay D 50 7 43 1.700 0.380 0.300 0.200 0.100 5.387 0.088 0.117 0.015 1.214 2.186 -2.542 0.003 0.000 3 True
118 sandy clay D 50 7 43 1.800 0.350 0.288 0.203 0.084 3.138 0.051 0.118 0.015 1.186 2.423 -3.307 0.003 0.000 3 True
119 sandy clay D 50 7 43 1.900 0.322 0.272 0.203 0.069 2.041 0.033 0.120 0.015 1.165 3.192 -4.266 0.004 0.000 3 True
120 silty clay D 7 47 46 0.800 0.635 0.473 0.224 0.249 217.292 3.565 0.137 0.007 1.372 3.245 -0.458 0.019 0.000 3 False
121 silty clay D 7 47 46 0.900 0.605 0.460 0.219 0.241 131.925 2.164 0.133 0.007 1.372 2.269 -0.334 0.015 0.000 3 False
122 silty clay D 7 47 46 1.000 0.575 0.443 0.213 0.230 78.732 1.292 0.130 0.006 1.369 1.657 -0.298 0.012 0.000 3 False
123 silty clay D 7 47 46 1.100 0.546 0.425 0.209 0.216 45.845 0.752 0.128 0.006 1.364 1.305 -0.330 0.010 0.000 3 False
124 silty clay D 7 47 46 1.200 0.518 0.406 0.205 0.201 26.160 0.429 0.127 0.006 1.356 1.093 -0.405 0.008 0.000 3 False
125 silty clay D 7 47 46 1.300 0.489 0.388 0.203 0.185 14.805 0.243 0.127 0.006 1.344 0.954 -0.503 0.007 0.000 3 False
126 silty clay D 7 47 46 1.400 0.461 0.370 0.202 0.168 8.421 0.138 0.126 0.006 1.328 0.858 -0.624 0.006 0.000 3 False
127 silty clay D 7 47 46 1.500 0.433 0.352 0.201 0.151 4.871 0.080 0.126 0.006 1.309 0.789 -0.786 0.005 0.000 3 False
128 silty clay D 7 47 46 1.600 0.405 0.335 0.202 0.133 2.887 0.047 0.127 0.007 1.285 0.749 -1.013 0.005 0.000 3 True
129 silty clay D 7 47 46 1.700 0.377 0.318 0.203 0.114 1.773 0.029 0.128 0.007 1.259 0.749 -1.338 0.004 0.000 3 True
130 silty clay D 7 47 46 1.800 0.350 0.300 0.204 0.096 1.152 0.019 0.129 0.007 1.233 0.817 -1.791 0.004 0.000 3 True
131 silty clay D 7 47 46 1.900 0.324 0.282 0.203 0.079 0.818 0.013 0.132 0.008 1.209 1.016 -2.381 0.004 0.000 3 True
132 clay D 20 20 60 0.800 0.647 0.449 0.252 0.197 207.818 3.409 0.151 0.016 1.291 6.239 -1.596 0.008 0.000 3 False
133 clay D 20 20 60 0.900 0.619 0.442 0.248 0.194 130.710 2.144 0.147 0.014 1.288 4.412 -1.453 0.007 0.000 3 False
134 clay D 20 20 60 1.000 0.591 0.432 0.244 0.188 82.545 1.354 0.143 0.013 1.285 3.219 -1.393 0.006 0.000 3 False
135 clay D 20 20 60 1.100 0.563 0.418 0.239 0.179 52.323 0.858 0.141 0.012 1.280 2.469 -1.391 0.005 0.000 3 False
136 clay D 20 20 60 1.200 0.536 0.404 0.236 0.168 33.173 0.544 0.139 0.012 1.273 2.010 -1.427 0.004 0.000 3 False
137 clay D 20 20 60 1.300 0.509 0.390 0.233 0.157 20.956 0.344 0.137 0.011 1.264 1.717 -1.501 0.004 0.000 3 False
138 clay D 20 20 60 1.400 0.481 0.375 0.231 0.144 13.182 0.216 0.137 0.011 1.252 1.507 -1.628 0.003 0.000 3 True
139 clay D 20 20 60 1.500 0.453 0.360 0.230 0.131 8.264 0.136 0.136 0.011 1.238 1.350 -1.831 0.003 0.000 3 True
140 clay D 20 20 60 1.600 0.425 0.345 0.230 0.115 5.162 0.085 0.136 0.011 1.219 1.248 -2.163 0.003 0.000 3 True
141 clay D 20 20 60 1.700 0.395 0.330 0.230 0.099 3.240 0.053 0.138 0.011 1.198 1.240 -2.681 0.002 0.000 3 True
142 clay D 20 20 60 1.800 0.366 0.313 0.230 0.083 2.247 0.037 0.140 0.012 1.178 1.417 -3.430 0.003 0.000 3 True
143 clay D 20 20 60 1.900 0.338 0.295 0.228 0.067 2.749 0.045 0.144 0.012 1.159 1.973 -4.424 0.003 0.000 3 True

5. Results

Show code
result = df[[
    "texture_class",
    "hydrologic_soil_group",
    "sand_pct",
    "silt_pct",
    "clay_pct",
    "bulk_density_g_cm3",
    "total_porosity",
    "field_capacity_porosity",
    "wilting_point_porosity",
    "available_water_capacity",
    "ksat_cm_day",
    "ksat_in_hr",
    "k_fc_cm_day",
    "k_wp_cm_day",
    "theta_r",
    "vg_alpha_1cm",
    "vg_n",
    "k0_cm_day",
    "mualem_L",
    "implausible_bd",
]].copy()

show(result)
texture_class hydrologic_soil_group sand_pct silt_pct clay_pct bulk_density_g_cm3 total_porosity field_capacity_porosity wilting_point_porosity available_water_capacity ksat_cm_day ksat_in_hr k_fc_cm_day k_wp_cm_day theta_r vg_alpha_1cm vg_n k0_cm_day mualem_L implausible_bd
0 sand A 92 5 3 0.800 0.560 0.141 0.072 0.069 992.244 16.277 0.008 0.000 0.070 0.029 1.848 53.148 -0.574 False
1 sand A 92 5 3 0.900 0.531 0.129 0.068 0.062 874.440 14.344 0.006 0.000 0.066 0.026 1.930 36.508 -0.473 False
2 sand A 92 5 3 1.000 0.503 0.113 0.064 0.049 803.505 13.181 0.004 0.000 0.063 0.025 2.033 29.219 -0.477 False
3 sand A 92 5 3 1.100 0.475 0.096 0.061 0.036 763.127 12.518 0.003 0.000 0.060 0.025 2.154 24.929 -0.542 False
4 sand A 92 5 3 1.200 0.450 0.082 0.058 0.024 731.398 11.998 0.002 0.000 0.058 0.026 2.289 22.146 -0.638 False
5 sand A 92 5 3 1.300 0.425 0.072 0.056 0.016 690.465 11.327 0.002 0.000 0.056 0.027 2.430 20.779 -0.734 False
6 sand A 92 5 3 1.400 0.401 0.064 0.054 0.010 630.566 10.344 0.001 0.000 0.054 0.029 2.563 20.654 -0.809 False
7 sand A 92 5 3 1.500 0.376 0.059 0.052 0.007 544.378 8.930 0.001 0.000 0.052 0.031 2.653 21.556 -0.857 False
8 sand A 92 5 3 1.600 0.352 0.057 0.050 0.006 424.038 6.956 0.001 0.000 0.050 0.032 2.638 23.625 -0.874 False
9 sand A 92 5 3 1.700 0.327 0.056 0.049 0.007 301.562 4.947 0.001 0.000 0.049 0.033 2.532 27.468 -0.876 False
10 sand A 92 5 3 1.800 0.303 0.055 0.048 0.007 218.069 3.577 0.002 0.000 0.048 0.035 2.449 36.333 -0.883 False
11 sand A 92 5 3 1.900 0.281 0.054 0.047 0.007 173.663 2.849 0.003 0.000 0.047 0.038 2.415 83.843 -0.888 False
12 loamy sand A 82 12 6 0.800 0.554 0.253 0.097 0.156 487.050 7.990 0.011 0.000 0.074 0.018 1.545 16.326 -0.346 False
13 loamy sand A 82 12 6 0.900 0.525 0.228 0.088 0.140 421.489 6.914 0.009 0.000 0.071 0.018 1.589 14.527 -0.322 False
14 loamy sand A 82 12 6 1.000 0.498 0.203 0.081 0.123 369.826 6.067 0.008 0.000 0.068 0.018 1.636 13.651 -0.361 False
15 loamy sand A 82 12 6 1.100 0.472 0.180 0.074 0.106 321.878 5.280 0.008 0.000 0.066 0.019 1.684 13.228 -0.433 False
16 loamy sand A 82 12 6 1.200 0.447 0.159 0.070 0.090 274.748 4.507 0.007 0.000 0.064 0.020 1.729 13.048 -0.520 False
17 loamy sand A 82 12 6 1.300 0.423 0.141 0.066 0.076 229.151 3.759 0.006 0.000 0.061 0.021 1.769 13.056 -0.614 False
18 loamy sand A 82 12 6 1.400 0.400 0.127 0.062 0.065 186.012 3.051 0.006 0.000 0.059 0.022 1.799 13.213 -0.706 False
19 loamy sand A 82 12 6 1.500 0.377 0.116 0.060 0.057 145.188 2.382 0.006 0.000 0.057 0.024 1.810 13.454 -0.796 False
20 loamy sand A 82 12 6 1.600 0.353 0.111 0.058 0.053 105.214 1.726 0.006 0.000 0.055 0.025 1.782 13.723 -0.890 False
21 loamy sand A 82 12 6 1.700 0.328 0.112 0.058 0.054 69.610 1.142 0.007 0.000 0.054 0.027 1.716 14.156 -0.996 False
22 loamy sand A 82 12 6 1.800 0.305 0.112 0.058 0.054 45.577 0.748 0.008 0.000 0.053 0.028 1.649 16.243 -1.096 False
23 loamy sand A 82 12 6 1.900 0.282 0.109 0.058 0.051 32.713 0.537 0.015 0.000 0.052 0.030 1.609 31.984 -1.179 False
24 sandy loam A 65 25 10 0.800 0.544 0.339 0.129 0.210 345.058 5.660 0.013 0.000 0.081 0.010 1.455 4.963 0.012 False
25 sandy loam A 65 25 10 0.900 0.517 0.313 0.119 0.194 261.554 4.291 0.012 0.000 0.078 0.010 1.472 4.803 -0.047 False
26 sandy loam A 65 25 10 1.000 0.490 0.289 0.110 0.178 196.156 3.218 0.011 0.000 0.075 0.011 1.486 4.834 -0.143 False
27 sandy loam A 65 25 10 1.100 0.466 0.266 0.103 0.163 145.698 2.390 0.010 0.000 0.073 0.012 1.496 4.954 -0.257 False
28 sandy loam A 65 25 10 1.200 0.442 0.246 0.097 0.148 107.304 1.760 0.009 0.000 0.071 0.013 1.501 5.111 -0.381 False
29 sandy loam A 65 25 10 1.300 0.419 0.228 0.093 0.135 78.162 1.282 0.009 0.000 0.068 0.014 1.502 5.289 -0.509 False
30 sandy loam A 65 25 10 1.400 0.396 0.213 0.089 0.124 56.362 0.925 0.008 0.000 0.066 0.015 1.496 5.509 -0.641 False
31 sandy loam A 65 25 10 1.500 0.374 0.201 0.087 0.114 39.936 0.655 0.008 0.000 0.064 0.016 1.481 5.772 -0.776 False
32 sandy loam A 65 25 10 1.600 0.351 0.192 0.086 0.106 27.110 0.445 0.008 0.000 0.063 0.017 1.451 6.082 -0.926 False
33 sandy loam A 65 25 10 1.700 0.328 0.188 0.089 0.099 17.322 0.284 0.008 0.000 0.061 0.018 1.406 6.551 -1.113 False
34 sandy loam A 65 25 10 1.800 0.306 0.184 0.092 0.092 10.893 0.179 0.008 0.000 0.060 0.019 1.360 7.607 -1.347 False
35 sandy loam A 65 25 10 1.900 0.284 0.179 0.095 0.083 7.269 0.119 0.011 0.000 0.060 0.021 1.322 11.189 -1.619 True
36 loam B 40 40 20 0.800 0.559 0.421 0.163 0.258 256.843 4.213 0.022 0.000 0.098 0.005 1.453 1.999 0.334 False
37 loam B 40 40 20 0.900 0.530 0.395 0.154 0.241 165.697 2.718 0.018 0.000 0.095 0.005 1.456 1.745 0.281 False
38 loam B 40 40 20 1.000 0.502 0.371 0.147 0.224 104.354 1.712 0.016 0.000 0.093 0.006 1.456 1.624 0.180 False
39 loam B 40 40 20 1.100 0.476 0.348 0.141 0.207 65.280 1.071 0.014 0.000 0.091 0.006 1.452 1.585 0.054 False
40 loam B 40 40 20 1.200 0.451 0.326 0.137 0.190 41.158 0.675 0.012 0.000 0.089 0.006 1.444 1.588 -0.083 False
41 loam B 40 40 20 1.300 0.427 0.307 0.133 0.174 26.290 0.431 0.011 0.000 0.087 0.007 1.432 1.613 -0.227 False
42 loam B 40 40 20 1.400 0.404 0.290 0.131 0.159 17.009 0.279 0.010 0.000 0.086 0.007 1.416 1.657 -0.377 False
43 loam B 40 40 20 1.500 0.381 0.275 0.130 0.145 11.107 0.182 0.009 0.000 0.084 0.008 1.393 1.731 -0.538 False
44 loam B 40 40 20 1.600 0.358 0.262 0.130 0.131 7.236 0.119 0.008 0.000 0.083 0.009 1.362 1.852 -0.732 False
45 loam B 40 40 20 1.700 0.336 0.250 0.133 0.117 4.656 0.076 0.008 0.000 0.081 0.009 1.324 2.071 -0.994 False
46 loam B 40 40 20 1.800 0.314 0.239 0.136 0.103 3.015 0.049 0.008 0.000 0.080 0.010 1.285 2.502 -1.350 False
47 loam B 40 40 20 1.900 0.293 0.228 0.139 0.090 2.038 0.033 0.008 0.000 0.080 0.011 1.252 3.372 -1.803 True
48 silt loam B 20 65 15 0.800 0.557 0.458 0.146 0.313 330.144 5.416 0.069 0.000 0.092 0.003 1.572 1.515 0.746 False
49 silt loam B 20 65 15 0.900 0.527 0.431 0.138 0.293 203.429 3.337 0.056 0.000 0.088 0.003 1.574 1.286 0.741 False
50 silt loam B 20 65 15 1.000 0.499 0.404 0.131 0.273 127.725 2.095 0.046 0.000 0.085 0.003 1.572 1.166 0.668 False
51 silt loam B 20 65 15 1.100 0.473 0.378 0.125 0.253 81.420 1.336 0.038 0.000 0.083 0.003 1.565 1.109 0.553 False
52 silt loam B 20 65 15 1.200 0.449 0.354 0.121 0.233 52.349 0.859 0.032 0.000 0.080 0.004 1.554 1.095 0.422 False
53 silt loam B 20 65 15 1.300 0.427 0.331 0.117 0.214 33.895 0.556 0.027 0.000 0.078 0.004 1.538 1.110 0.284 False
54 silt loam B 20 65 15 1.400 0.405 0.310 0.115 0.195 22.196 0.364 0.023 0.000 0.077 0.004 1.516 1.144 0.141 False
55 silt loam B 20 65 15 1.500 0.384 0.291 0.113 0.178 14.735 0.242 0.019 0.000 0.075 0.005 1.489 1.195 -0.010 False
56 silt loam B 20 65 15 1.600 0.364 0.274 0.114 0.161 9.942 0.163 0.016 0.000 0.074 0.005 1.455 1.269 -0.178 False
57 silt loam B 20 65 15 1.700 0.343 0.259 0.115 0.144 6.902 0.113 0.013 0.000 0.073 0.006 1.416 1.390 -0.376 False
58 silt loam B 20 65 15 1.800 0.323 0.244 0.117 0.127 5.086 0.083 0.012 0.000 0.073 0.007 1.376 1.603 -0.617 True
59 silt loam B 20 65 15 1.900 0.303 0.230 0.118 0.111 4.470 0.073 0.011 0.000 0.073 0.008 1.340 2.003 -0.915 True
60 silt B/D 7 88 5 0.800 0.562 0.351 0.103 0.249 1381.028 22.655 0.039 0.000 0.083 0.006 1.711 3.927 0.390 False
61 silt B/D 7 88 5 0.900 0.533 0.380 0.102 0.278 690.764 11.331 0.064 0.000 0.078 0.004 1.707 2.692 0.642 False
62 silt B/D 7 88 5 1.000 0.506 0.377 0.100 0.277 369.838 6.067 0.067 0.000 0.074 0.004 1.701 2.103 0.713 False
63 silt B/D 7 88 5 1.100 0.482 0.361 0.096 0.265 215.558 3.536 0.059 0.000 0.070 0.004 1.693 1.801 0.686 False
64 silt B/D 7 88 5 1.200 0.459 0.341 0.093 0.248 136.101 2.233 0.050 0.000 0.068 0.004 1.680 1.669 0.601 False
65 silt B/D 7 88 5 1.300 0.438 0.319 0.090 0.229 92.347 1.515 0.041 0.000 0.066 0.004 1.664 1.632 0.482 False
66 silt B/D 7 88 5 1.400 0.418 0.297 0.088 0.209 68.169 1.118 0.033 0.000 0.064 0.004 1.644 1.661 0.342 False
67 silt B/D 7 88 5 1.500 0.398 0.274 0.086 0.189 58.825 0.965 0.026 0.000 0.063 0.005 1.620 1.760 0.182 False
68 silt B/D 7 88 5 1.600 0.379 0.252 0.084 0.167 70.476 1.156 0.020 0.000 0.062 0.006 1.591 1.956 -0.007 False
69 silt B/D 7 88 5 1.700 0.360 0.228 0.084 0.145 129.258 2.120 0.015 0.000 0.062 0.008 1.560 2.337 -0.241 True
70 silt B/D 7 88 5 1.800 0.341 0.201 0.082 0.120 571.274 9.371 0.011 0.000 0.063 0.010 1.540 3.146 -0.535 True
71 silt B/D 7 88 5 1.900 0.323 0.174 0.080 0.094 1463.279 24.004 0.009 0.000 0.064 0.015 1.527 4.956 -0.883 True
72 sandy clay loam C 60 13 27 0.800 0.586 0.386 0.186 0.200 231.903 3.804 0.010 0.000 0.112 0.013 1.350 6.082 -0.785 False
73 sandy clay loam C 60 13 27 0.900 0.560 0.367 0.176 0.191 174.015 2.855 0.009 0.000 0.108 0.013 1.359 4.962 -0.751 False
74 sandy clay loam C 60 13 27 1.000 0.534 0.348 0.168 0.181 128.898 2.114 0.008 0.000 0.106 0.013 1.366 4.333 -0.755 False
75 sandy clay loam C 60 13 27 1.100 0.509 0.330 0.160 0.170 93.746 1.538 0.007 0.000 0.103 0.013 1.370 3.974 -0.787 False
76 sandy clay loam C 60 13 27 1.200 0.484 0.313 0.154 0.159 66.541 1.092 0.006 0.000 0.101 0.014 1.371 3.742 -0.843 False
77 sandy clay loam C 60 13 27 1.300 0.459 0.298 0.149 0.149 45.805 0.751 0.006 0.000 0.099 0.014 1.368 3.551 -0.921 False
78 sandy clay loam C 60 13 27 1.400 0.434 0.285 0.146 0.138 30.569 0.501 0.006 0.000 0.097 0.014 1.359 3.371 -1.023 False
79 sandy clay loam C 60 13 27 1.500 0.408 0.273 0.145 0.128 19.687 0.323 0.005 0.000 0.096 0.014 1.342 3.212 -1.159 False
80 sandy clay loam C 60 13 27 1.600 0.381 0.264 0.147 0.117 12.022 0.197 0.005 0.000 0.094 0.015 1.313 3.111 -1.363 False
81 sandy clay loam C 60 13 27 1.700 0.354 0.257 0.152 0.105 6.918 0.113 0.005 0.000 0.094 0.015 1.275 3.166 -1.697 False
82 sandy clay loam C 60 13 27 1.800 0.327 0.249 0.157 0.091 3.975 0.065 0.005 0.000 0.093 0.015 1.239 3.572 -2.195 True
83 sandy clay loam C 60 13 27 1.900 0.301 0.237 0.159 0.078 2.444 0.040 0.006 0.000 0.093 0.016 1.211 4.640 -2.809 True
84 clay loam D 30 35 35 0.800 0.599 0.448 0.205 0.244 215.577 3.536 0.016 0.000 0.121 0.007 1.379 2.611 -0.202 False
85 clay loam D 30 35 35 0.900 0.570 0.427 0.196 0.231 137.810 2.261 0.013 0.000 0.118 0.007 1.380 2.049 -0.189 False
86 clay loam D 30 35 35 1.000 0.542 0.406 0.189 0.216 85.477 1.402 0.010 0.000 0.115 0.007 1.378 1.713 -0.237 False
87 clay loam D 30 35 35 1.100 0.514 0.385 0.184 0.202 51.959 0.852 0.009 0.000 0.113 0.007 1.374 1.511 -0.320 False
88 clay loam D 30 35 35 1.200 0.487 0.366 0.179 0.187 31.207 0.512 0.008 0.000 0.112 0.007 1.366 1.386 -0.418 False
89 clay loam D 30 35 35 1.300 0.461 0.349 0.176 0.172 18.636 0.306 0.007 0.000 0.111 0.007 1.355 1.299 -0.530 False
90 clay loam D 30 35 35 1.400 0.434 0.332 0.175 0.157 11.137 0.183 0.006 0.000 0.110 0.008 1.340 1.232 -0.663 False
91 clay loam D 30 35 35 1.500 0.408 0.317 0.174 0.142 6.693 0.110 0.006 0.000 0.109 0.008 1.320 1.186 -0.830 False
92 clay loam D 30 35 35 1.600 0.381 0.302 0.176 0.127 4.037 0.066 0.005 0.000 0.109 0.008 1.294 1.174 -1.058 False
93 clay loam D 30 35 35 1.700 0.355 0.289 0.178 0.110 2.447 0.040 0.005 0.000 0.109 0.008 1.263 1.228 -1.399 False
94 clay loam D 30 35 35 1.800 0.330 0.274 0.181 0.094 1.524 0.025 0.005 0.000 0.109 0.009 1.231 1.412 -1.890 True
95 clay loam D 30 35 35 1.900 0.305 0.260 0.181 0.078 1.009 0.017 0.006 0.000 0.110 0.009 1.204 1.848 -2.537 True
96 silty clay loam D 10 56 34 0.800 0.609 0.479 0.199 0.280 229.209 3.760 0.033 0.000 0.122 0.005 1.436 2.158 0.129 False
97 silty clay loam D 10 56 34 0.900 0.578 0.460 0.192 0.267 138.366 2.270 0.026 0.000 0.118 0.004 1.438 1.567 0.221 False
98 silty clay loam D 10 56 34 1.000 0.549 0.438 0.186 0.252 81.976 1.345 0.021 0.000 0.115 0.004 1.437 1.219 0.207 False
99 silty clay loam D 10 56 34 1.100 0.520 0.416 0.181 0.236 47.675 0.782 0.017 0.000 0.114 0.004 1.432 1.013 0.132 False
100 silty clay loam D 10 56 34 1.200 0.492 0.395 0.176 0.218 27.436 0.450 0.015 0.000 0.112 0.004 1.424 0.895 0.030 False
101 silty clay loam D 10 56 34 1.300 0.465 0.374 0.174 0.200 15.812 0.259 0.013 0.000 0.112 0.005 1.412 0.825 -0.087 False
102 silty clay loam D 10 56 34 1.400 0.439 0.354 0.172 0.182 9.222 0.151 0.011 0.000 0.111 0.005 1.394 0.779 -0.221 False
103 silty clay loam D 10 56 34 1.500 0.413 0.336 0.172 0.164 5.486 0.090 0.009 0.000 0.111 0.005 1.372 0.752 -0.379 False
104 silty clay loam D 10 56 34 1.600 0.388 0.318 0.172 0.146 3.339 0.055 0.008 0.000 0.111 0.005 1.343 0.748 -0.573 False
105 silty clay loam D 10 56 34 1.700 0.362 0.301 0.174 0.127 2.092 0.034 0.007 0.000 0.111 0.006 1.311 0.779 -0.829 True
106 silty clay loam D 10 56 34 1.800 0.338 0.285 0.175 0.109 1.377 0.023 0.006 0.000 0.111 0.006 1.279 0.868 -1.167 True
107 silty clay loam D 10 56 34 1.900 0.315 0.268 0.176 0.093 0.974 0.016 0.006 0.000 0.111 0.007 1.250 1.064 -1.599 True
108 sandy clay D 50 7 43 0.800 0.616 0.408 0.222 0.186 240.026 3.937 0.009 0.000 0.133 0.018 1.302 8.437 -1.512 False
109 sandy clay D 50 7 43 0.900 0.590 0.398 0.216 0.183 166.103 2.725 0.008 0.000 0.130 0.016 1.305 6.062 -1.395 False
110 sandy clay D 50 7 43 1.000 0.564 0.386 0.209 0.176 115.164 1.889 0.006 0.000 0.126 0.016 1.305 4.659 -1.351 False
111 sandy clay D 50 7 43 1.100 0.539 0.372 0.204 0.168 79.444 1.303 0.005 0.000 0.124 0.015 1.304 3.821 -1.345 False
112 sandy clay D 50 7 43 1.200 0.514 0.358 0.199 0.159 54.335 0.891 0.005 0.000 0.122 0.015 1.300 3.312 -1.370 False
113 sandy clay D 50 7 43 1.300 0.488 0.345 0.195 0.149 36.772 0.603 0.004 0.000 0.120 0.015 1.293 2.968 -1.434 False
114 sandy clay D 50 7 43 1.400 0.463 0.332 0.194 0.139 24.361 0.400 0.004 0.000 0.119 0.015 1.282 2.687 -1.543 False
115 sandy clay D 50 7 43 1.500 0.436 0.321 0.193 0.127 15.598 0.256 0.004 0.000 0.118 0.015 1.265 2.441 -1.723 True
116 sandy clay D 50 7 43 1.600 0.408 0.310 0.196 0.115 9.416 0.154 0.003 0.000 0.117 0.015 1.242 2.248 -2.029 True
117 sandy clay D 50 7 43 1.700 0.380 0.300 0.200 0.100 5.387 0.088 0.003 0.000 0.117 0.015 1.214 2.186 -2.542 True
118 sandy clay D 50 7 43 1.800 0.350 0.288 0.203 0.084 3.138 0.051 0.003 0.000 0.118 0.015 1.186 2.423 -3.307 True
119 sandy clay D 50 7 43 1.900 0.322 0.272 0.203 0.069 2.041 0.033 0.004 0.000 0.120 0.015 1.165 3.192 -4.266 True
120 silty clay D 7 47 46 0.800 0.635 0.473 0.224 0.249 217.292 3.565 0.019 0.000 0.137 0.007 1.372 3.245 -0.458 False
121 silty clay D 7 47 46 0.900 0.605 0.460 0.219 0.241 131.925 2.164 0.015 0.000 0.133 0.007 1.372 2.269 -0.334 False
122 silty clay D 7 47 46 1.000 0.575 0.443 0.213 0.230 78.732 1.292 0.012 0.000 0.130 0.006 1.369 1.657 -0.298 False
123 silty clay D 7 47 46 1.100 0.546 0.425 0.209 0.216 45.845 0.752 0.010 0.000 0.128 0.006 1.364 1.305 -0.330 False
124 silty clay D 7 47 46 1.200 0.518 0.406 0.205 0.201 26.160 0.429 0.008 0.000 0.127 0.006 1.356 1.093 -0.405 False
125 silty clay D 7 47 46 1.300 0.489 0.388 0.203 0.185 14.805 0.243 0.007 0.000 0.127 0.006 1.344 0.954 -0.503 False
126 silty clay D 7 47 46 1.400 0.461 0.370 0.202 0.168 8.421 0.138 0.006 0.000 0.126 0.006 1.328 0.858 -0.624 False
127 silty clay D 7 47 46 1.500 0.433 0.352 0.201 0.151 4.871 0.080 0.005 0.000 0.126 0.006 1.309 0.789 -0.786 False
128 silty clay D 7 47 46 1.600 0.405 0.335 0.202 0.133 2.887 0.047 0.005 0.000 0.127 0.007 1.285 0.749 -1.013 True
129 silty clay D 7 47 46 1.700 0.377 0.318 0.203 0.114 1.773 0.029 0.004 0.000 0.128 0.007 1.259 0.749 -1.338 True
130 silty clay D 7 47 46 1.800 0.350 0.300 0.204 0.096 1.152 0.019 0.004 0.000 0.129 0.007 1.233 0.817 -1.791 True
131 silty clay D 7 47 46 1.900 0.324 0.282 0.203 0.079 0.818 0.013 0.004 0.000 0.132 0.008 1.209 1.016 -2.381 True
132 clay D 20 20 60 0.800 0.647 0.449 0.252 0.197 207.818 3.409 0.008 0.000 0.151 0.016 1.291 6.239 -1.596 False
133 clay D 20 20 60 0.900 0.619 0.442 0.248 0.194 130.710 2.144 0.007 0.000 0.147 0.014 1.288 4.412 -1.453 False
134 clay D 20 20 60 1.000 0.591 0.432 0.244 0.188 82.545 1.354 0.006 0.000 0.143 0.013 1.285 3.219 -1.393 False
135 clay D 20 20 60 1.100 0.563 0.418 0.239 0.179 52.323 0.858 0.005 0.000 0.141 0.012 1.280 2.469 -1.391 False
136 clay D 20 20 60 1.200 0.536 0.404 0.236 0.168 33.173 0.544 0.004 0.000 0.139 0.012 1.273 2.010 -1.427 False
137 clay D 20 20 60 1.300 0.509 0.390 0.233 0.157 20.956 0.344 0.004 0.000 0.137 0.011 1.264 1.717 -1.501 False
138 clay D 20 20 60 1.400 0.481 0.375 0.231 0.144 13.182 0.216 0.003 0.000 0.137 0.011 1.252 1.507 -1.628 True
139 clay D 20 20 60 1.500 0.453 0.360 0.230 0.131 8.264 0.136 0.003 0.000 0.136 0.011 1.238 1.350 -1.831 True
140 clay D 20 20 60 1.600 0.425 0.345 0.230 0.115 5.162 0.085 0.003 0.000 0.136 0.011 1.219 1.248 -2.163 True
141 clay D 20 20 60 1.700 0.395 0.330 0.230 0.099 3.240 0.053 0.002 0.000 0.138 0.011 1.198 1.240 -2.681 True
142 clay D 20 20 60 1.800 0.366 0.313 0.230 0.083 2.247 0.037 0.003 0.000 0.140 0.012 1.178 1.417 -3.430 True
143 clay D 20 20 60 1.900 0.338 0.295 0.228 0.067 2.749 0.045 0.003 0.000 0.144 0.012 1.159 1.973 -4.424 True
Show code
# Save to CSV
result.to_csv("rosetta_porosity_by_texture.csv", index=False)
print("Wrote rosetta_porosity_by_texture.csv")
Wrote rosetta_porosity_by_texture.csv

Per-bulk-density water-storage snapshots

Export one CSV per bulk-density step to data/ROSETTA/ — rows by texture (HSG), columns wilting point, field capacity, saturation, available water, drainable water (cm³/cm³, the same six fields as the home-page slider table). These are static snapshots of the raw ROSETTA outputs at each bulk density. export_water_storage_tables is shared with _helpers so Notebook 2 can later export its blended outputs the same way.

Show code
# NB1 executes in notebooks/ (Quarto execute-dir: file), so the repo-root data/ROSETTA is ../data/ROSETTA.
_rosetta_exports = export_water_storage_tables(result, "../data/ROSETTA", prefix="rosetta")
print(f"Wrote {len(_rosetta_exports)} per-bulk-density tables to data/ROSETTA/:")
print("  " + ", ".join(p.name for p in _rosetta_exports))
Wrote 12 per-bulk-density tables to data/ROSETTA/:
  rosetta_bd_0.8.csv, rosetta_bd_0.9.csv, rosetta_bd_1.0.csv, rosetta_bd_1.1.csv, rosetta_bd_1.2.csv, rosetta_bd_1.3.csv, rosetta_bd_1.4.csv, rosetta_bd_1.5.csv, rosetta_bd_1.6.csv, rosetta_bd_1.7.csv, rosetta_bd_1.8.csv, rosetta_bd_1.9.csv

6. Visualization of Water Storage

Interactive hvPlot / HoloViews (Bokeh) line plots of total porosity, field-capacity, and wilting-point vs. bulk density, one line per texture class. Hover for values, click on key to highlight each plot line, use the toolbar to pan/zoom. (Hydraulic conductivity and infiltration are in Notebook 3.)

Extrapolation greyed out. Each line is solid only over physically plausible bulk densities; where Rosetta’s θₛ exceeds the BD-implied pore space (the implausible_bd flag from §5) the curve continues as a faint grey dashed tail.

Show code
# line_with_extrapolation (shared with Notebook 3) is imported from _helpers: each texture's
# curve is solid over plausible bulk densities and grey-dashed where implausible_bd is True.
line_with_extrapolation(
    result,
    "total_porosity",
    "Total porosity θₛ (cm³/cm³)",
    "Rosetta total porosity vs. bulk density by USDA texture class",
)
Show code
line_with_extrapolation(
    result,
    "field_capacity_porosity",
    "Field-capacity at 33 kPa (cm³/cm³)",
    "Rosetta field-capacity vs. bulk density by USDA texture class",
)
Show code
line_with_extrapolation(
    result,
    "wilting_point_porosity",
    "Wilting-point at 1500 kPa (cm³/cm³)",
    "Rosetta wilting-point vs. bulk density by USDA texture class",
)

Takeaway: As bulk density increases total porosity, field capacity, and available water all decline across every texture class, so compaction directly reduces the water a soil can hold and release to plants and infiltration.

7. Soil water partitioning by texture

Horizontal stacked bars (one per texture class, in the order defined above) partitioning the pore space into three volumetric water states, in the style of the AQP water-retention-curve plots:

Band Range Color
Unavailable water 0 → wilting point (1500 kPa) orange
Available water wilting point → field capacity (33 kPa) green
Drainable water field capacity → total porosity (saturation) blue

The three bands sum to total porosity θₛ. Use the bulk-density slider at the bottom to vary BD across the 0.8–1.9 g/cm³ range; the selected value is shown in the plot title. A red ⚠ marks bars at bulk densities that are physically implausible for that texture (implausible_bd: θₛ > 1 − BD/2.65 — extrapolation).

Show code
import holoviews as hv

# Place HoloViews widgets (the bulk-density slider) along the bottom of the plot.
hv.output(widget_location="bottom")

# Partition pore space into three water states for every bulk density, then plot as
# horizontal stacked bars (AQP water-retention-curve style) with a bulk-density slider.
part = result.copy()
part["unavailable"] = part["wilting_point_porosity"]                          # 0 -> PWP
part["available"] = part["available_water_capacity"]                          # PWP -> FC
part["drainable"] = part["total_porosity"] - part["field_capacity_porosity"]  # FC -> saturation

# y-axis label: texture class with its hydrologic soil group in parentheses, e.g. "sand (A)"
part["texture_label"] = part["texture_class"] + " (" + part["hydrologic_soil_group"] + ")"

water_states = ["unavailable", "available", "drainable"]
state_colors = ["orange", "green", "blue"]
label_order = [f"{cls} ({HYDROLOGIC_SOIL_GROUP[cls]})" for cls in TEXTURE_CLASSES]  # sand ... clay

part_long = part.melt(
    id_vars=["texture_label", "bulk_density_g_cm3"],
    value_vars=water_states,
    var_name="water_state",
    value_name="volumetric_fraction",
)
# reverse texture order so sand plots at the TOP of the horizontal (inverted) axis
part_long["texture_label"] = pd.Categorical(
    part_long["texture_label"], categories=label_order[::-1], ordered=True
)
part_long["water_state"] = pd.Categorical(
    part_long["water_state"], categories=water_states, ordered=True
)
part_long = part_long.sort_values(["bulk_density_g_cm3", "texture_label", "water_state"])

# groupby -> bulk-density slider; dynamic=False embeds every frame so the slider works
# in the saved/exported notebook without a live kernel. {dimensions} interpolates the
# selected slider value into the title, so it updates as the slider moves.
hmap = part_long.hvplot.barh(
    x="texture_label",
    y="volumetric_fraction",
    by="water_state",
    groupby="bulk_density_g_cm3",
    dynamic=False,
    stacked=True,
    color=state_colors,
    ylim=(0, 0.7),  # fixed value axis so bars don't rescale while sliding
    xlabel="texture class (hydrologic soil group)",
    ylabel="volumetric water content (cm³/cm³)",
    title="Soil water partitioning by texture (Rosetta) — {dimensions}",
    width=750,
    height=550,
    legend="top_right",
)
# Per-BD "⚠" markers at the end of bars for textures that are physically implausible at that
# BD (extrapolation, implausible_bd). Built as a HoloMap keyed like the bars so it tracks the slider.
def _implausible_marks(bd):
    sub = result[result["bulk_density_g_cm3"] == bd]
    # barh inverts axes, so in data space the categorical texture is the FIRST coordinate and the
    # numeric bar value is the SECOND; passing them the other way injects the numeric values as
    # spurious extra y-axis categories (the bug this fixes).
    marks = [
        hv.Text(f"{r.texture_class} ({r.hydrologic_soil_group})", r.total_porosity + 0.01, "⚠",
                halign="left").opts(text_color="red", text_font_size="9pt")
        for r in sub.itertuples() if r.implausible_bd
    ]
    # every frame must be the same type (Overlay); use an off-canvas blank when none are flagged
    if not marks:
        first = next(iter(TEXTURE_CLASSES))
        marks = [hv.Text(f"{first} ({HYDROLOGIC_SOIL_GROUP[first]})", -1.0, " ").opts(text_alpha=0)]
    return hv.Overlay(marks)

marks_hmap = hv.HoloMap({bd: _implausible_marks(bd) for bd in bulk_densities}, kdims=["bulk_density_g_cm3"])

# readable slider/title label + consistent one-decimal bulk density
(hmap * marks_hmap).redim(
    bulk_density_g_cm3=hv.Dimension("Bulk density, g/cm³ (higher is more compacted)", default=1.4, value_format=lambda v: f"{v:.1f}")
)

Takeaway: Clays hold a lot of total water but lock much of it below the wilting point (a wide unavailable band), while silt and silt loam offer the most plant-available water — the green band — making these silty, medium textures the most productive for crops and vegetation. Sands sit at the low end.

8. Soil water vs. texture (transposed line view)

The same three water states as Section 7, transposed and drawn as a line/area diagram in the style of the classic FAO available-water figure: texture on the x-axis (coarse → fine), water volume on the y-axis expressed as inches of water per foot of soil depth (volumetric water content × 12), with the permanent wilting point, field capacity, and total porosity curves bounding the filled bands:

  • Unavailable water (orange): 0 → permanent wilting point
  • Available water (green): wilting point → field capacity
  • Drainable water (blue): field capacity → total porosity

Use the bulk-density slider at the bottom to vary BD; the selected value appears in the title. Texture columns are greyed out at bulk densities where the combination is physically implausible (implausible_bd: Rosetta θₛ > pore space 1 − BD/2.65) — i.e. extrapolation.

Show code
# Transposed line/area view: texture on x (coarse -> fine), water content on y, with a
# bulk-density slider. Built as a HoloMap of overlays (one frame per bulk density) so it
# embeds every frame and works in the saved notebook without a live kernel. Columns flagged
# implausible_bd (θₛ > 1 − BD/2.65) are greyed as an extrapolation warning.
hv.output(widget_location="bottom")

texture_x = {cls: i for i, cls in enumerate(TEXTURE_CLASSES)}  # sand=0 ... clay=11
# x tick labels: texture class with its hydrologic soil group in parentheses, e.g. "sand (A)"
texture_ticks = [(i, f"{cls} ({HYDROLOGIC_SOIL_GROUP[cls]})") for cls, i in texture_x.items()]

# volumetric water content (cm³/cm³) -> inches of water per foot of soil depth (FAO style)
INCHES_PER_FOOT = 12.0


def _water_profile(bd):
    d = (
        result[result["bulk_density_g_cm3"] == bd]
        .set_index("texture_class")
        .reindex(list(TEXTURE_CLASSES))
        .reset_index()
    )
    x = d["texture_class"].map(texture_x).to_numpy()
    pwp = d["wilting_point_porosity"].to_numpy() * INCHES_PER_FOOT
    fc = d["field_capacity_porosity"].to_numpy() * INCHES_PER_FOOT
    por = d["total_porosity"].to_numpy() * INCHES_PER_FOOT
    return soil_water_texture_band_diagram(
        x, pwp, fc, por,
        texture_labels=d["texture_class"].astype(str).tolist(),
        implausible=d["implausible_bd"].to_numpy(),
    )


profiles = hv.HoloMap(
    {bd: _water_profile(bd) for bd in bulk_densities},
    kdims=[hv.Dimension("bulk density", label="bulk density", unit="g/cm³", default=1.4, value_format=lambda v: f"{v:.1f}")],
)

profiles.opts(
    hv.opts.Overlay(
        width=820,
        height=520,
        legend_position="top_left",
        xlabel="Texture class (Hydrologic Soil Group); coarse → fine",
        ylabel="Water Storage Capacity (inches per foot of soil depth)",
        title="Soil water vs. texture from ROSETTA for {dimensions}",
    ),
    hv.opts.Curve(xticks=texture_ticks, xrotation=45, ylim=(0, 0.7 * INCHES_PER_FOOT)),
    hv.opts.Area(xticks=texture_ticks, xrotation=45, ylim=(0, 0.7 * INCHES_PER_FOOT)),
)

Takeaway: Silt and silt loam soils store the most plant-available water (roughly 2–2.5 inches per foot of depth at moderate bulk density), while sandy soils drain quickly and clay soils lock much of their water below the wilting point — a pattern that shifts as you move the bulk-density slider toward more compacted values.

Back to top