Loimis — Soil Texture Parser¶
What is the Loimis field?¶
The Loimis (loimis) field encodes the particle-size composition of a soil profile across up to four depth layers, all in a single compact string. It tells you what the soil is physically made of — how much sand, silt, clay, and rock fragment content there is — and how that composition changes with depth.
A simple example:
l40-70/ls₂30/+ls₂
This reads as three layers:
| Layer | Notation | Meaning |
|---|---|---|
| 1 | l40-70 |
Sand (liiv), from 40 to 70 cm depth |
| 2 | ls₂30 |
Sandy clay (liivsavi) with moderate rock content, upper boundary at 30 cm |
| 3 | +ls₂ |
Sandy clay, continuing deeper |
The notation system¶
Fine earth (peenes)¶
The dominant soil material in each layer is described by a texture code:
| Code | Estonian name | International class |
|---|---|---|
l |
liiv | Sand |
pl |
peenliiv | Fine sand |
sl |
saviliiv | Loamy sand / clayey sand |
ls |
liivsavi | Sandy loam / sandy clay loam |
s |
savi | Clay |
tsl |
tolmjas saviliiv | Silt loam |
tls |
tolmjas liivsavi | Silty clay loam |
dk |
liivakivirähk | Sandy grit / sandstone debris |
Rock skeleton (kores)¶
Coarse fragments mixed into the layer are described by a skeleton code:
| Code | Estonian name | Description |
|---|---|---|
r |
rähk | Gravel (2–60 mm fragments) |
v |
veeris | Cobbles (>60 mm rounded fragments) |
k |
kruus | Coarse gravel / limestone fragments |
kb |
killustik | Angular rubble |
p |
paas | Limestone bedrock plate |
lu |
lupjakivi | Calcareous / carbonate material |
ck |
kiltkivirähk | Slate or schist debris |
Organic material (turfs)¶
| Code | Estonian name | Description |
|---|---|---|
th |
toorhuumus | Raw/mor humus horizon (> 10 cm) |
t₁ / t1 |
turvas I aste | Weakly decomposed peat |
t₂ / t2 |
turvas II aste | Moderately decomposed peat |
t₃ / t3 |
turvas III aste | Strongly decomposed peat |
Amplitude subscripts ₁–₅¶
An amplitude subscript immediately after a code indicates abundance or intensity of that component. The scale runs from 1 (weak / minor presence) to 5 (very strong / dominant). For example:
r₁ls— slight gravel content in a sandy clay layerr₃ls— substantial gravel in sandy clayls₂— moderately gravelly sandy clay (peenes with skeleton modifier)
Depth ranges¶
Depth is written in centimetres, either as a single value or a range:
| Notation | Meaning |
|---|---|
l40 |
Sand layer with upper boundary at 40 cm |
l40-70 |
Sand layer from 40 to 70 cm |
+ls₂ |
Sandy clay continues deeper (no explicit lower boundary) |
The + prefix means deeper than the previous layer — no explicit depth given.
Carbonate flag¶
A + immediately before a component code (not a depth marker) means the material
is calcareous (e.g. +ls = calcareous sandy clay). Context distinguishes this
from the depth-continuation +.
Layer separator¶
Layers are separated by /. Up to four layers per polygon.
The 7-step parsing pipeline¶
Because the loimis notation is complex and the raw data contains many encoding errors, parsing proceeds through seven stages:
- Normalise and split — apply error-correction lookups, discard secondary siffer annotations, and split the string into individual layer tokens.
- Bracket fix — validate and remove parenthesised numeric artefacts in each token.
- Grammar test — try each of ten grammar variants (covering all possible orderings of kores, peenes, and turfs components) and produce a canonical normalised string.
- Reconstituate — reassemble the normalised layers into a clean slash-separated string.
- Visitor — apply a structured tree-walker to extract a nested dictionary of all soil constituents, their codes, amplitudes, carbonate flags, and depth ranges.
- Layer depths — read the depth information from the structured dictionary to determine the number of layers and the depth of each layer boundary.
- Texture fractions — look up each constituent code in the texture rules table to derive clay, silt, sand, and rock-fragment percentages, and map to international texture classes.
Output fields¶
Depth and layer summary (6 values)¶
| Field | Type | Description |
|---|---|---|
nlayers |
int | Number of distinct texture layers in this profile (1–4) |
ZMX |
float | Total profile depth — deepest layer boundary (cm) |
Z1 |
float | Lower boundary of layer 1 (cm) |
Z2 |
float | Lower boundary of layer 2 (cm); 0 if fewer than 2 layers |
Z3 |
float | Lower boundary of layer 3 (cm); 0 if fewer than 3 layers |
Z4 |
float | Lower boundary of layer 4 (cm); 0 if fewer than 4 layers |
Per-layer texture (×4 layers, 32 values + 1 diagnostic)¶
For each layer number n (1 to 4):
| Field | Type | Description |
|---|---|---|
EST_TXTn |
str | Estonian texture code for this layer (e.g. sl, ls) |
EST_CRSn |
str | Coarse fraction type code (e.g. r, k, v); empty if no skeleton |
LXTYPEn |
str | International texture class: SAND, LOAM, CLAY, PEAT, GRAVELS, … |
CLAYn |
float | Clay fraction (0–100 %) |
SILTn |
float | Silt fraction (0–100 %) |
SANDn |
float | Sand fraction (0–100 %) |
ROCKn |
float | Rock / skeleton fragment fraction (0–100 %) |
KARBn |
int | Carbonate flag: 1 if any constituent in the layer is calcareous (+ prefix), 0 otherwise |
Diagnostic fields¶
| Field | Type | Description |
|---|---|---|
parse_ok_l |
bool | True if all layers were parsed successfully. Used in the map viewer error-review style together with parse_ok_s and parse_ok_h. |
parse_info |
str | Parse status: "successful", "empty_loimis", "partial_no_info", "parse_error" |
has_no_info |
bool | True if one or more layers could not be parsed |
loimis_grammar |
dict | Full structured parse result (stored in DB but excluded from map viewer popup) |
loimis_search |
dict | Internal search-parameter snapshot (stored in DB but excluded from map viewer popup) |
NaN values in texture fractions
For gravel- or rock-dominated layers (LXTYPE = "GRAVELS"), the clay, silt,
and sand fractions are NaN. The rock fragment content is recorded in
ROCK instead. Guard for this when computing weighted averages.
Layers beyond the profile
Z2, Z3, Z4 are 0 (not NaN) when the profile has fewer
layers. Always check nlayers before using these values.
Worked example¶
Raw field value: "sl60/r₁l"
| Layer | Token | Meaning |
|---|---|---|
| 1 | sl60 |
Clayey sand (saviliiv), upper boundary at 60 cm |
| 2 | r₁l |
Sand with slight gravel content |
Parsed output (selected fields):
nlayers=2, ZMX=60, Z1=60, Z2=0
EST_TXT1="sl", LXTYPE1="LOAM", CLAY1=15, SILT1=20, SAND1=65, ROCK1=0, KARB1=0
EST_TXT2="l", LXTYPE2="SAND", CLAY2=4, SILT2=6, SAND2=90, ROCK2=5, KARB2=0