The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
rCTOOL is an open-source R package for running C-TOOL simulations of soil organic carbon dynamics in agricultural systems. It provides a user-friendly R interface for defining carbon inputs, management schedules, soil parameters, temperature forcing, scenario simulations, and parameter calibration.
The package builds on the C-TOOL model framework (Petersen, Olesen,
and Heidmann 2002; Taghizadeh-Toosi et al. 2014) and aims to make
C-TOOL-based simulations easier to configure, reproduce, document, and
extend.
![]()
Once available on CRAN, rCTOOL can be installed with:
install.packages("rCTOOL")The development version can be installed from GitHub:
# install.packages("devtools")
devtools::install_github("francagiannini/rCTOOL")This is a simple example of the potential use of rCTOOL. The example corresponds to one of the treatments presented by (Jensen et al. 2021) and (Jensen et al. 2022) containing the C inputs for the treatment of the spring barley crop with 4 DM Mg/ha straw incorporated into the soil at a long-term experimental station Askov, Denmark.
library(rCTOOL)
library(ggplot2)
# load data ----
data('basic_example')
data('scenario_temperature')The basic_example dataset contains annual carbon inputs
and monthly management allocation information.
head(basic_example, 2)
#> mon yrs id year Cin_top Cin_sub Cin_man manure_monthly_allocation
#> 1 1 1951 1 1951 3.566 0.39 0 0
#> 2 2 1951 1 1952 3.566 0.39 0 0
#> plant_monthly_allocation
#> 1 0
#> 2 0The scenario_temperature dataset contains monthly
temperature data.
head(scenario_temperature, 2)
#> month yr Tavg
#> 1 1 1951 0.890000
#> 2 2 1951 1.170714A standard rCTOOL simulation requires five main inputs:
# define timeperiod
period <- define_timeperiod(
yr_start = 1951,
yr_end = 2019
)
# get annual Carbon inputs
cin <- define_Cinputs(
management_filepath = basic_example
)
# get management
management <- management_config(
management_filepath = basic_example,
grain_monthly_allocation = rep(0, 12),
grass_monthly_allocation = rep(0, 12),
f_man_humification = 0.192
)
# get soil configuration
soil <- soil_config(Csoil_init = 105,
f_hum_top = 0.533,
f_rom_top = 0.405,
f_hum_sub = 0.387,
f_rom_sub = 0.610,
Cproptop = 0.55,
clay_top = 0.11,
clay_sub = 0.20,
phi = 0.035,
f_co2 = 0.628,
f_romi = 0.012,
k_fom = 0.12,
k_hum = 0.0028,
k_rom = 3.85e-5,
ftr = 0.0025
)Initial soil pools are calculated before running the simulation. They depend on the initial soil carbon stock, the initial C:N ratio, and the distribution of carbon among FOM, HUM, and ROM pools.
# initialize soil pools
soil_pools <- initialize_soil_pools(
cn = 12,
soil_config = soil
)
soil_pools <- c(soil_pools[[1]], soil_pools[[2]])The monthly simulation is then run with run_ctool(). The
verbose argument can be used to run additional diagnostic
checks during the simulation.
# run rCTOOL
output <- run_ctool(
time_config = period,
cin_config = cin,
m_config = management,
t_config = scenario_temperature,
s_config = soil,
soil_pools = soil_pools,
verbose = FALSE
)The resulting output contains monthly carbon pools, soil carbon stocks, transport fluxes, and CO2 emissions.
head(output)
#> mon yrs FOM_top FOM_top_decomposition substrate_FOM_decomp_top
#> 1 1 1951 3.435048 -0.1454518 0.1454518
#> 2 2 1951 3.195740 -0.2393079 0.2393079
#> 3 3 1951 2.915547 -0.2801936 0.2801936
#> 4 4 1951 2.668412 -0.5324143 0.5324143
#> 5 5 1951 2.416203 -0.6801291 0.6801291
#> 6 6 1951 2.267384 -0.7193794 0.7193794
#> FOM_humified_top em_CO2_FOM_top FOM_tr FOM_sub FOM_sub_decomposition
#> 1 0.02782131 0.1172668 0.0003636294 0.1375258 -0.004587808
#> 2 0.04577366 0.1929360 0.0005982698 0.1307436 -0.007380504
#> 3 0.05359408 0.2258990 0.0007004840 0.1223929 -0.009051156
#> 4 0.10183764 0.4292456 0.0013310358 0.1324329 -0.022491038
#> 5 0.13009180 0.5483369 0.0017003226 0.1425719 -0.038361325
#> 6 0.13759943 0.5799816 0.0017984486 0.1540850 -0.052685398
#> substrate_FOM_decomp_sub FOM_humified_sub em_CO2_FOM_sub HUM_top
#> 1 0.004587808 0.0009878393 0.003599969 25.95689
#> 2 0.007380504 0.0015891579 0.005791346 25.96039
#> 3 0.009051156 0.0019488800 0.007102276 25.96077
#> 4 0.022491038 0.0048427332 0.017648305 25.96145
#> 5 0.038361325 0.0082598971 0.030101428 25.95782
#> 6 0.052685398 0.0113441328 0.041341265 25.94876
#> HUM_top_decomposition substrate_HUM_decomp_top HUM_romified_top
#> 1 -0.02462729 0.02462729 0.0002955275
#> 2 -0.04226870 0.04226870 0.0005072243
#> 3 -0.05321946 0.05321946 0.0006386335
#> 4 -0.10115380 0.10115380 0.0012138456
#> 5 -0.13372738 0.13372738 0.0016047285
#> 6 -0.14665546 0.14665546 0.0017598655
#> em_CO2_HUM_top HUM_tr HUM_sub HUM_sub_decomposition
#> 1 0.01546594 0.008865824 15.42058 -0.01162135
#> 2 0.02654474 0.015216730 15.42507 -0.01924719
#> 3 0.03342182 0.019159005 15.43030 -0.02481767
#> 4 0.06352458 0.036415367 15.43801 -0.05240850
#> 5 0.08398079 0.048141856 15.44536 -0.07665266
#> 6 0.09209963 0.052795966 15.45048 -0.09220968
#> substrate_HUM_decomp_sub HUM_romified_sub em_CO2_HUM_sub ROM_top
#> 1 0.01162135 0.0001394562 0.007298207 28.21587
#> 2 0.01924719 0.0002309662 0.012087233 28.21598
#> 3 0.02481767 0.0002978120 0.015585495 28.21612
#> 4 0.05240850 0.0006289019 0.032912535 28.21638
#> 5 0.07665266 0.0009198319 0.048137870 28.21673
#> 6 0.09220968 0.0011065161 0.057907677 28.21712
#> ROM_top_decomposition substrate_ROM_decomp_top em_CO2_ROM_top ROM_tr
#> 1 -0.0003677493 0.0003677493 0.0002309465 9.193731e-07
#> 2 -0.0006306740 0.0006306740 0.0003960633 1.576685e-06
#> 3 -0.0007937270 0.0007937270 0.0004984605 1.984317e-06
#> 4 -0.0015058543 0.0015058543 0.0009456765 3.764636e-06
#> 5 -0.0019886082 0.0019886082 0.0012488460 4.971521e-06
#> 6 -0.0021805722 0.0021805722 0.0013693994 5.451431e-06
#> ROM_sub ROM_sub_decomposition substrate_ROM_decomp_sub em_CO2_ROM_sub
#> 1 31.69002 -0.0003282270 0.0003282270 0.0002061265
#> 2 31.68991 -0.0005432775 0.0005432775 0.0003411783
#> 3 31.68977 -0.0007001122 0.0007001122 0.0004396704
#> 4 31.68947 -0.0014760401 0.0014760401 0.0009269532
#> 5 31.68904 -0.0021556707 0.0021556707 0.0013537612
#> 6 31.68853 -0.0025906327 0.0025906327 0.0016269173
#> C_topsoil C_subsoil SOC_stock C_transport em_CO2_top em_CO2_sub em_CO2_total
#> 1 57.60781 47.24813 104.8559 0.009230373 0.1329637 0.01110430 0.1440680
#> 2 57.37211 47.24572 104.6178 0.015816577 0.2198768 0.01821976 0.2380965
#> 3 57.09243 47.24246 104.3349 0.019861474 0.2598193 0.02312744 0.2829468
#> 4 56.84625 47.25992 104.1062 0.037750168 0.4937159 0.05148779 0.5452037
#> 5 56.59075 47.27697 103.8677 0.049847151 0.6335666 0.07959306 0.7131596
#> 6 56.43326 47.29310 103.7264 0.054599866 0.6734506 0.10087586 0.7743265The topsoil SOC trajectory can be visualized as follows.
output$time <- as.Date(
paste(output$yrs, output$mon, "01", sep = "-")
)
ggplot(output, aes(x = time, y = C_topsoil)) +
geom_line() +
geom_smooth() +
theme_classic() +
labs(
x = "Year",
y = "Topsoil SOC stock (Mg C ha-1)"
)
##
Output variables
The rCTOOL output includes time, carbon stocks, pool sizes, transport fluxes, and CO2 emissions.
mon: month of the year (1-12);yrs: year of the simulation.C_topsoil: carbon stock in the topsoil (0-25 cm).C_subsoil: carbon stock in the subsoil (26-100
cm).SOC_stock: total Soil Organic Carbon stock in the soil
(0-100 cm).C_transport: carbon transported to the subsoil.em_CO2_top: total CO2 emissions from the topsoil.em_CO2_sub: total CO2 emissions from the subsoil.em_CO2_total: total CO2 emissions from the soil.FOM_top: FOM in the topsoil.FOM_top_decomposition: monthly decomposition of FOM in
the topsoil.substrate_FOM_decomp_top: substrate for FOM
decomposition in the topsoil.FOM_humified_top: FOM that has been “humified” in the
topsoil (becomes part of topsoil HUM).em_CO2_FOM_top: CO2 emissions from the decomposition of
FOM in the topsoil.FOM_tr: FOM transported from the topsoil to the
subsoil.FOM_sub: FOM in the subsoil.FOM_sub_decomposition: decomposition of FOM in the
subsoil.substrate_FOM_decomp_sub: substrate for FOM
decomposition in the subsoil.FOM_humified_sub: FOM that has been “humified” in the
subsoil (becomes part of subsoil HUM).em_CO2_FOM_sub: CO2 emissions from the decomposition of
FOM in the subsoil.HUM_top: HUM in the topsoil.HUM_top_decomposition: Decomposition of HUM in the
topsoil.substrate_HUM_decomp_top: Substrate for HUM
decomposition in the topsoil.HUM_romified_top: HUM that has been “romified” in the
topsoil (becomes part of topsoil ROM).em_CO2_HUM_top: CO2 emissions from the decomposition of
HUM in the topsoil.HUM_tr: HUM transported from the topsoil to the
subsoil.HUM_sub: HUM in the subsoil.HUM_sub_decomposition: Decomposition of HUM in the
subsoil.substrate_HUM_decomp_sub: Substrate for HUM
decomposition in the subsoil.HUM_romified_sub: HUM that has been “romified” in the
subsoil (becomes part of subsoil ROM).em_CO2_HUM_sub: CO2 emissions from the decomposition of
HUM in the subsoil.ROM_top: ROM in the topsoil.ROM_top_decomposition: Decomposition of ROM in the
topsoil.substrate_ROM_decomp_top: Substrate for ROM
decomposition in the topsoil.em_CO2_ROM_top: CO2 emissions from the decomposition of
ROM in the topsoil.ROM_tr: ROM transported from the topsoil to the
subsoil.ROM_sub: ROM in the subsoil.ROM_sub_decomposition: Decomposition of ROM in the
subsoil.substrate_ROM_decomp_sub: Substrate for ROM
decomposition in the subsoil.em_CO2_ROM_sub: CO2 emissions from the decomposition of
ROM in the subsoil.rCTOOL includes a calibration module for evaluating and calibrating selected CTOOL parameters against observed SOC stocks.
The current calibration module tests combinations of:
f_hum_top: fraction of decomposed topsoil FOM entering
the HUM pool;k_hum: decomposition rate of the HUM pool.For each tested value of f_hum_top, the corresponding
f_rom_top is calculated internally as:
f_rom_top = 1 - f_hum_top - f_fom_topThe only additional data required for calibration is a two-column data frame containing observed SOC stocks by year. In this example, we create a small artificial observed dataset from the simulated output only to demonstrate the workflow.
observed <- aggregate(
C_topsoil ~ yrs,
data = output,
FUN = mean
)
observed <- data.frame(
Year = observed$yrs + 1,
SOC_obs = observed$C_topsoil
)
observed <- observed[observed$Year %in% c(1955, 1965, 1975, 1985, 1995), ]
observed
#> Year SOC_obs
#> 4 1955 56.10409
#> 14 1965 55.52216
#> 24 1975 54.62216
#> 34 1985 54.16431
#> 44 1995 53.38794The tested parameter ranges are defined using min,
max, and by.
calib <- ctool_calibrate(
time_config = period,
cinput_config = cin,
temperature_config = scenario_temperature,
management_config = management,
soil_config = soil,
observed = observed,
f_hum_top = c(min = 0.20, max = 0.60, by = 0.10),
k_hum = c(min = 0.0020, max = 0.0040, by = 0.0010),
verbose = FALSE
)
summary(calib)
#> C-TOOL calibration summary
#> =========================
#>
#> Calibration data:
#> Observations: 5
#> Tested combinations: 15
#>
#> Calibrated parameters:
#> f_hum_top
#> k_hum
#>
#> Parameter ranges:
#> f_hum_top: 0.2 to 0.6 by 0.1
#> k_hum: 0.002 to 0.004 by 0.001
#>
#> Calibration settings:
#> f_fom_top: 0.003
#> cn_init: 10
#> Ranking metric: d_index
#> Minimize metric: FALSE
#>
#> Best tested calibration:
#> f_hum_top k_hum f_rom_top d_index RMSE R2 Bias MAE n
#> 0.4 0.004 0.597 0.8678099 1.038007 0.9781859 0.4954844 0.7633362 5
#>
#> Current parameters versus best tested calibration:
#> Type d_index RMSE R2 Bias MAE n
#> Current C-TOOL parameters 0.5768270 2.460624 0.9908253 -2.2206482 2.2206482 5
#> Best tested calibration 0.8678099 1.038007 0.9781859 0.4954844 0.7633362 5
#> f_hum_top k_hum f_rom_top
#> 0.533 0.0028 0.405
#> 0.400 0.0040 0.597
#>
#> Recommended parameter set:
#> Source f_hum_top k_hum f_rom_top d_index RMSE R2
#> Best tested calibration 0.4 0.004 0.597 0.8678099 1.038007 0.9781859
#> Bias MAE n
#> 0.4954844 0.7633362 5
#>
#> Recommendation:
#> Use the best tested calibration because it improved the selected performance metric compared with the current C-TOOL parameters.The calibration output includes:
Model performance is evaluated using RMSE, MAE, mean bias, R2, and
the Willmott index of agreement, reported as d_index
(Willmott 1981).
calib$recommended_params
#> Source f_hum_top k_hum f_rom_top d_index RMSE
#> 1 Best tested calibration 0.4 0.004 0.597 0.8678099 1.038007
#> R2 Bias MAE n
#> 1 0.9781859 0.4954844 0.7633362 5If the current CTOOL parameters perform as well as or better than the
tested calibration grid, ctool_calibrate() recommends
keeping the current parameter set.
rCTOOL can also be used to compare multiple management or land-use
scenarios. The following example uses the scenario
dataset.
data('scenario')
data('scenario_temperature')The scenario dataset contains different C input
assumptions for different management s options.
For the football court scenario we assume a well-maintained stomped ryegrass cover,
for the organic dairy farming we assume a crop rotation with grass, maize and cereals for happy milking cows,
and finally for the pet cemetery we assume a less healthily reygrass and a certain number of beloved dogs and cats from Viborg municipality burred in the subsoil.
Now we will play with rCTOOL to explore the implications in terms of soil C dynamics.
First lets take a look on the C inputs distribution:
period <- define_timeperiod(
yr_start = 1951,
yr_end = 2019
)
management <- management_config(
manure_monthly_allocation = c(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
plant_monthly_allocation = c(0, 0, 0, 8, 12, 16, 64, 0, 0, 0, 0, 0) / 100,
grain_monthly_allocation = rep(0, 12),
grass_monthly_allocation = rep(0, 12),
f_man_humification = 0
)
soil <- soil_config(
Csoil_init = 100,
f_hum_top = 0.4803,
f_rom_top = 0.4881,
f_hum_sub = 0.3123,
f_rom_sub = 0.6847,
Cproptop = 0.47,
clay_top = 0.1,
clay_sub = 0.15,
phi = 0.035,
f_co2 = 0.628,
f_romi = 0.012,
k_fom = 0.12,
k_hum = 0.0028,
k_rom = 3.85e-5,
ftr = 0.003
)
soil_pools <- initialize_soil_pools(
cn = 10,
soil_config = soil
)Then define carbon inputs and run the model for each scenario.
treatment <- unique(scenario$treatment)
cin_treatment <- lapply(treatment, function(x) {
define_Cinputs(
management_filepath = subset(scenario, treatment == x)
)
})
names(cin_treatment) <- treatment
output_treatment <- lapply(treatment, function(x) {
out <- run_ctool(
time_config = period,
cin_config = cin_treatment[[x]],
m_config = management,
t_config = scenario_temperature,
s_config = soil,
soil_pools = soil_pools,
verbose = FALSE
)
out$treatment <- x
out
})
output_treatment <- data.table::rbindlist(output_treatment)The simulated trajectories can then be compared across scenarios.
plot_df <- output_treatment[
,
c("mon", "yrs", "C_topsoil", "C_subsoil", "em_CO2_total", "treatment")
]
plot_df <- reshape2::melt(
plot_df,
id.vars = c("mon", "yrs", "treatment")
)
labels <- c(
C_topsoil = "SOC topsoil",
C_subsoil = "SOC subsoil",
em_CO2_total = "CO2 emissions"
)
ggplot(plot_df, aes(x = yrs, y = value, colour = treatment)) +
geom_point(size = 0.02, alpha = 0.2) +
geom_smooth() +
facet_wrap(
variable ~ .,
scales = "free_y",
ncol = 1,
labeller = as_labeller(labels)
) +
labs(
x = "Year",
y = "Output (Mg ha-1)",
colour = "Treatment"
) +
theme_classic()
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.