Allocates a total profile mineral nitrogen amount (\(kg/ha\)) into soil layers using a generic depth-weighted kernel. This function is deterministic, returns non-negative layer values, and conserves the supplied total nitrogen.

distribute_soil_n(
  total_n,
  thickness_mm,
  method = c("exponential", "uniform", "truncated"),
  lambda_mm = 500,
  max_depth_mm = NULL
)

Arguments

total_n

Numeric scalar. Total profile mineral nitrogen to distribute (\(kg/ha\)). Must be finite and non-negative.

thickness_mm

Numeric vector. Layer thicknesses in mm. All values must be finite and strictly positive.

method

Character scalar. Distribution kernel to use: "exponential" (default), "uniform", or "truncated".

lambda_mm

Numeric scalar. Exponential decay length scale in mm, used only when method = "exponential". Smaller values produce steeper surface concentration; larger values approach uniform distributions.

max_depth_mm

Numeric scalar. Cutoff depth in mm for method = "truncated"; nitrogen is distributed uniformly from 0 to this depth and zero below.

Value

Numeric vector of layer nitrogen values (\(kg/ha\)), with length equal to length(thickness_mm).

Details

The exponential method is intended as a pragmatic default for pre-sowing initialisation when measured soil nitrate profiles are unavailable, representing situations where mineralised nitrogen from decomposing residues and roots is concentrated near the soil surface and declines with depth. Alternative kernels are provided to support simpler assumptions or truncated rooting zones.

This function does not attempt to reproduce measured soil nitrate profiles or rainfall-driven redistribution. Where detailed soil nitrogen measurements or continuous system spin-up simulations are available, those approaches should be preferred.

Examples

library(agrillm)
thickness <- rep(100, 10)

distribute_soil_n(50, thickness)
#>  [1] 10.482054  8.581980  7.026331  5.752673  4.709891  3.856132  3.157134
#>  [8]  2.584843  2.116290  1.732672
distribute_soil_n(50, thickness, method = "uniform")
#>  [1] 5 5 5 5 5 5 5 5 5 5
distribute_soil_n(50, thickness, method = "truncated", max_depth_mm = 600)
#>  [1] 8.333333 8.333333 8.333333 8.333333 8.333333 8.333333 0.000000 0.000000
#>  [9] 0.000000 0.000000

# Compare distribution methods in a single figure.
if (requireNamespace("ggplot2", quietly = TRUE)) {
  layer_bounds <- cumsum(thickness)
  layer_labels <- paste0(c(0, head(layer_bounds, -1)), "-", layer_bounds, " mm")

  profiles <- rbind(
    data.frame(layer = layer_labels,
               n_kg_ha = distribute_soil_n(50, thickness, method = "uniform"),
               method = "uniform"),
    data.frame(layer = layer_labels,
               n_kg_ha = distribute_soil_n(50, thickness, method = "exponential", lambda_mm = 500),
               method = "exponential"),
    data.frame(layer = layer_labels,
               n_kg_ha = distribute_soil_n(50, thickness, method = "truncated", max_depth_mm = 600),
               method = "truncated")
  ) |>
  dplyr::mutate(layer = factor(layer, levels = layer_labels))
  profiles$method <- factor(profiles$method, levels = c("uniform", "exponential", "truncated"))

  ggplot2::ggplot(profiles, ggplot2::aes(x = layer, y = n_kg_ha, fill = method)) +
    ggplot2::geom_col(position = "dodge") +
    ggplot2::labs(
      title = "Example Soil N Allocation by Method",
      x = "Soil layer",
      y = "N per layer (kg/ha)",
      fill = "Method"
    ) +
    ggplot2::theme_minimal(base_size = 11) +
    ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))
}