partitioning¶
Biomass allocation to plant organs.
References
Biomass partitioning block of Lintul5.java.
Partitioning fractions depend on DVS via the parameters FLTB, FSTB,
FRTB, FOTB (leaves, stems, roots, storage). The above-ground fraction
(leaves+stems+storage) plus the below-ground fraction (roots) sum to ~1.
Partitioning (Module)
¶
Allocate daily gross biomass production to organ-specific pools.
Source code in torchcrop/processes/partitioning.py
class Partitioning(nn.Module):
"""Allocate daily gross biomass production to organ-specific pools."""
def forward(
self,
state: ModelState,
gtotal: torch.Tensor,
params: CropParameters,
) -> dict[str, torch.Tensor]:
"""Split gross daily biomass production across organs.
Args:
state: Current state (uses ``state.dvs`` for table lookups).
gtotal: Gross daily biomass production [g DM m⁻² d⁻¹], shape
``[B]``.
params: Crop parameters; uses the partitioning tables ``frtb``,
``fltb``, ``fstb``, ``fotb``.
Returns:
Dict of ``[B]`` tensors grouped as follows.
Rate variables (per-organ growth, fed to leaf/root/state updates
and nutrient demand):
* ``g_root`` [g DM m⁻² d⁻¹] — Root biomass growth rate
(``= gtotal * fr``); becomes ``wrt_rate``.
* ``g_lv`` [g DM m⁻² d⁻¹] — Leaf growth before senescence;
`LeafDynamics` converts it into ``wlv_rate`` and
``lai_rate``.
* ``g_st`` [g DM m⁻² d⁻¹] — Stem growth rate; becomes
``wst_rate`` directly.
* ``g_so`` [g DM m⁻² d⁻¹] — Storage organ growth rate;
becomes ``wso_rate`` and drives final yield.
Diagnostics (normalised partitioning fractions):
* ``fr`` [-] — Below-ground (root) fraction, clamped to
``[0, 0.95]``.
* ``fl``, ``fs``, ``fo`` [-] — Above-ground fractions to
leaves, stems, storage organs. Re-normalised so that
``fl + fs + fo == 1``.
"""
dvs = state.dvs
fr = interpolate(params.frtb, dvs)
fl = interpolate(params.fltb, dvs)
fs = interpolate(params.fstb, dvs)
fo = interpolate(params.fotb, dvs)
# Normalise above-ground fractions so that fl + fs + fo = 1
ag_sum = fl + fs + fo
ag_sum = torch.where(ag_sum > 1e-8, ag_sum, torch.ones_like(ag_sum))
fl_n = fl / ag_sum
fs_n = fs / ag_sum
fo_n = fo / ag_sum
# fr controls the root:shoot split
fr = torch.clamp(fr, 0.0, 0.95)
g_root = gtotal * fr
g_shoot = gtotal * (1.0 - fr)
g_lv = g_shoot * fl_n
g_st = g_shoot * fs_n
g_so = g_shoot * fo_n
return {
"g_root": g_root,
"g_lv": g_lv,
"g_st": g_st,
"g_so": g_so,
"fr": fr,
"fl": fl_n,
"fs": fs_n,
"fo": fo_n,
}
forward(self, state, gtotal, params)
¶
Split gross daily biomass production across organs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state |
ModelState |
Current state (uses |
required |
gtotal |
torch.Tensor |
Gross daily biomass production [g DM m⁻² d⁻¹], shape
|
required |
params |
CropParameters |
Crop parameters; uses the partitioning tables |
required |
Returns:
| Type | Description | ||
|---|---|---|---|
Dict of ``[B]`` tensors grouped as follows.
Rate variables (per-organ growth, fed to leaf/root/state updates
and nutrient demand) |
Diagnostics (normalised partitioning fractions):
|
Source code in torchcrop/processes/partitioning.py
def forward(
self,
state: ModelState,
gtotal: torch.Tensor,
params: CropParameters,
) -> dict[str, torch.Tensor]:
"""Split gross daily biomass production across organs.
Args:
state: Current state (uses ``state.dvs`` for table lookups).
gtotal: Gross daily biomass production [g DM m⁻² d⁻¹], shape
``[B]``.
params: Crop parameters; uses the partitioning tables ``frtb``,
``fltb``, ``fstb``, ``fotb``.
Returns:
Dict of ``[B]`` tensors grouped as follows.
Rate variables (per-organ growth, fed to leaf/root/state updates
and nutrient demand):
* ``g_root`` [g DM m⁻² d⁻¹] — Root biomass growth rate
(``= gtotal * fr``); becomes ``wrt_rate``.
* ``g_lv`` [g DM m⁻² d⁻¹] — Leaf growth before senescence;
`LeafDynamics` converts it into ``wlv_rate`` and
``lai_rate``.
* ``g_st`` [g DM m⁻² d⁻¹] — Stem growth rate; becomes
``wst_rate`` directly.
* ``g_so`` [g DM m⁻² d⁻¹] — Storage organ growth rate;
becomes ``wso_rate`` and drives final yield.
Diagnostics (normalised partitioning fractions):
* ``fr`` [-] — Below-ground (root) fraction, clamped to
``[0, 0.95]``.
* ``fl``, ``fs``, ``fo`` [-] — Above-ground fractions to
leaves, stems, storage organs. Re-normalised so that
``fl + fs + fo == 1``.
"""
dvs = state.dvs
fr = interpolate(params.frtb, dvs)
fl = interpolate(params.fltb, dvs)
fs = interpolate(params.fstb, dvs)
fo = interpolate(params.fotb, dvs)
# Normalise above-ground fractions so that fl + fs + fo = 1
ag_sum = fl + fs + fo
ag_sum = torch.where(ag_sum > 1e-8, ag_sum, torch.ones_like(ag_sum))
fl_n = fl / ag_sum
fs_n = fs / ag_sum
fo_n = fo / ag_sum
# fr controls the root:shoot split
fr = torch.clamp(fr, 0.0, 0.95)
g_root = gtotal * fr
g_shoot = gtotal * (1.0 - fr)
g_lv = g_shoot * fl_n
g_st = g_shoot * fs_n
g_so = g_shoot * fo_n
return {
"g_root": g_root,
"g_lv": g_lv,
"g_st": g_st,
"g_so": g_so,
"fr": fr,
"fl": fl_n,
"fs": fs_n,
"fo": fo_n,
}