API Reference: variogram.py¶
The variogram class encapsulates all variogram model parameters, validation, and semivariance computation for UK_SSPA v2.
Class: variogram¶
class variogram:
def __init__(self, config=None, config_path="config.json")
Constructor Parameters¶
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
config |
dict |
No | None |
Pre-loaded configuration dictionary. If provided, config_path is ignored. |
config_path |
str |
No | "config.json" |
Path to JSON config file. Used only when config is None. |
If config is None, the constructor opens config_path and reads it with json.load. No validation of the file path is performed at this level — a FileNotFoundError or json.JSONDecodeError will propagate from the standard library.
Attributes¶
All attributes are set during __init__ and validated before the constructor returns.
Core Variogram Parameters¶
| Attribute | Type | Source Key | Default | Description |
|---|---|---|---|---|
model_type |
str |
variogram.model |
"spherical" |
Variogram model name. One of "spherical", "exponential", "gaussian", "linear". |
sill |
float |
variogram.sill |
1.0 |
Total sill (variance at large lag distances). Must be > 0. |
range_ |
float |
variogram.range |
1000.0 |
Range parameter. For bounded models (spherical, linear), the semivariance reaches the sill at this distance. For unbounded models (exponential, gaussian), this is the practical range parameter. Must be > 0. |
nugget |
float |
variogram.nugget |
0.0 |
Nugget effect (discontinuity at the origin). Must be >= 0 and < sill. |
Anisotropy Parameters¶
| Attribute | Type | Source Key | Default | Description |
|---|---|---|---|---|
anisotropy_enabled |
bool |
variogram.anisotropy.enabled |
False |
Whether geometric anisotropy is active. |
anisotropy_ratio |
float |
variogram.anisotropy.ratio |
1.0 |
minor_range / major_range. Must be in (0, 1] when anisotropy is enabled. A ratio of 1.0 means isotropic. |
angle_major |
float |
variogram.anisotropy.angle_major |
0.0 |
Direction of the major axis of spatial correlation. Azimuth convention: Clockwise from North (KT3D convention). 0° = North, 90° = East. Must be in [0, 360) when anisotropy is enabled. |
âš Angle Convention:
angle_majoris stored and accepted as an azimuth (compass bearing — clockwise from North), following the KT3D convention. This is not arithmetic (CCW from East). Internally, the code converts to arithmetic viatheta = 90 - angle_majorbefore applying the rotation matrix. To convert:arithmetic_CCW_from_East = 90 - azimuth_CW_from_North(mod 360). Seedocs/glossary.mdfor the full convention table.Anisotropy Ratio:
anisotropy_ratio = minor_range / major_range. A ratio of0.5means the minor (short) range is half the major (long) range. The major axis is the direction of greatest spatial correlation (longest range). The minor axis is perpendicular to it.
Advanced Parameters¶
| Attribute | Type | Source Key | Default | Description |
|---|---|---|---|---|
effective_range_convention |
bool |
variogram.advanced.effective_range_convention |
True |
When True, the range_ value is interpreted as the effective range (distance at which semivariance reaches ~95% of sill for exponential/gaussian). When False, it is the raw scale parameter. |
search_radius |
float or None |
variogram.advanced.search_radius |
None |
Maximum search radius for neighbor selection during kriging. None means no limit. Must be > 0 if set. |
max_neighbors |
int or None |
variogram.advanced.max_neighbors |
None |
Maximum number of neighbors to use in kriging. None means no limit. |
min_neighbors |
int or None |
variogram.advanced.min_neighbors |
None |
Minimum number of neighbors required for kriging at a point. None means no minimum. |
Properties¶
| Property | Returns | Description |
|---|---|---|
model |
str |
Alias for model_type. |
parameters |
dict |
{'sill': ..., 'range': ..., 'nugget': ...} — convenience dict for passing to PyKrige. |
Validation Methods¶
_validate_basic_parameters()¶
Called automatically during __init__. Raises ValueError if:
| Condition | Error Message |
|---|---|
sill <= 0 |
"Variogram sill must be positive, got {sill}" |
range_ <= 0 |
"Variogram range must be positive, got {range_}" |
nugget < 0 |
"Variogram nugget must be non-negative, got {nugget}" |
nugget >= sill |
"Variogram nugget ({nugget}) must be less than total sill ({sill})" |
_validate_anisotropy()¶
Called automatically during __init__ only when anisotropy_enabled=True. Raises ValueError if:
| Condition | Error Message |
|---|---|
anisotropy_ratio not in (0, 1] |
"Anisotropy ratio must be in (0, 1], got {ratio}" |
angle_major not in [0, 360) |
"Angle major must be in [0, 360), got {angle_major}" |
Methods¶
calculate_variogram(h)¶
calculate_variogram(h: float) -> float
Compute the semivariance for a scalar isotropic lag distance h.
| Parameter | Type | Description |
|---|---|---|
h |
float |
Isotropic lag distance. Must be >= 0. |
Returns: float — semivariance γ(h).
Note: When anisotropy_enabled=True, this method still computes the isotropic semivariance. The caller is responsible for passing a pre-transformed (model-space) distance. For directional computation from raw-space lag vectors, use calculate_variogram_at_vector() instead.
Model equations (where psill = sill - nugget):
| Model | Equation |
|---|---|
linear |
γ(h) = nugget + (psill / range) * h for h ≤ range, else sill |
exponential |
γ(h) = nugget + psill * (1 - exp(-h / (range/3))) |
spherical |
γ(h) = nugget + psill * (1.5*(h/range) - 0.5*(h/range)³) for h ≤ range, else sill |
gaussian |
γ(h) = nugget + psill * (1 - exp(-(h / (range/√3))²)) |
calculate_variogram_at_vector(hx, hy)¶
calculate_variogram_at_vector(hx: float, hy: float) -> float
Compute the semivariance for a 2-D lag vector (hx, hy), accounting for geometric anisotropy.
| Parameter | Type | Description |
|---|---|---|
hx |
float |
X-component of the lag vector (in raw/original coordinate space). |
hy |
float |
Y-component of the lag vector (in raw/original coordinate space). |
Returns: float — semivariance γ(hx, hy).
When anisotropy_enabled=False: Computes h = sqrt(hx² + hy²) and delegates to calculate_variogram(h).
When anisotropy_enabled=True: Applies the anisotropy transformation inline:
- Convert
angle_majorfrom azimuth (CW from North) to arithmetic (CCW from East):theta = radians(90 - angle_major) - Rotate the lag vector to align the major axis with the X-axis:
hx' = hx * cos(theta) + hy * sin(theta) hy' = -hx * sin(theta) + hy * cos(theta) - Scale the minor axis (Y') to match the major range:
hy_scaled = hy' / ratio - Compute effective isotropic distance:
h_eff = sqrt(hx'² + hy_scaled²) - Return
calculate_variogram(h_eff)
Note: The rotation convention here matches
transform.py—theta = 90 - angle_majorconverts the azimuth input to the arithmetic rotation angle applied to the coordinate system.
clone()¶
clone() -> variogram
Return a deep copy of this variogram object.
Returns: A new variogram instance with identical attribute values. Modifying the clone does not affect the original.
Use case: The main pipeline clones the variogram and sets anisotropy_enabled=False on the clone before passing it to PyKrige, to prevent double-application of anisotropy after the pre-transformation step has already been applied to the coordinates.
vgm_clone = vgm.clone()
vgm_clone.anisotropy_enabled = False
# Pass vgm_clone to build_uk_model() when using pre-transformation
Usage Examples¶
Instantiate from config file¶
from variogram import variogram
vgm = variogram(config_path="config.json")
print(vgm.model_type) # e.g. "spherical"
print(vgm.sill) # e.g. 1.5
print(vgm.range_) # e.g. 500.0
print(vgm.nugget) # e.g. 0.1
print(vgm.anisotropy_enabled) # e.g. True
print(vgm.angle_major) # e.g. 45.0 (azimuth: 45° CW from North = NE direction)
Instantiate from dict¶
from variogram import variogram
cfg = {
"variogram": {
"model": "exponential",
"sill": 2.0,
"range": 300.0,
"nugget": 0.2,
"anisotropy": {
"enabled": True,
"ratio": 0.4,
"angle_major": 45.0 # azimuth: 45° CW from North = NE direction
# internally converted to arithmetic: 90 - 45 = 45° CCW from East
}
}
}
vgm = variogram(config=cfg)
print(vgm.calculate_variogram(150.0)) # isotropic semivariance at h=150
print(vgm.calculate_variogram_at_vector(100, 50)) # directional semivariance
Clone and disable anisotropy¶
vgm_for_pykrige = vgm.clone()
vgm_for_pykrige.anisotropy_enabled = False
# vgm_for_pykrige.parameters returns {'sill': ..., 'range': ..., 'nugget': ...}