library(jsonlite)
library(readr)
library(stringr)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
# File paths
apsimx_file <- "D:/Mes Donnees/R/Biomass_Crops/Modeling/APSIM/apsimx_runs/BioCrops_Base200.apsimx"
apsimx_out <- "D:/Mes Donnees/R/Biomass_Crops/Modeling/APSIM/apsimx_runs/BioCrops_Final200.apsimx"
par_dir <- "D:/Mes Donnees/R/Biomass_Crops/Modeling/APSIM/soils_par"
weather_dir <- "D:/Mes Donnees/R/Biomass_Crops/Modeling/APSIM/weather"
# Helper: constrain values
clip_soil_layer <- function(x, lower = -Inf, upper = Inf) {
x <- pmax(x, lower)
x <- pmin(x, upper)
return(x)
}
# Update soil node
update_soil_from_par <- function(existing_soil, par_path) {
lines <- read_lines(par_path)
data <- lines[!str_starts(lines, "\\*") & str_detect(lines, "=")]
data <- str_split_fixed(data, "=", 2)
df <- as.data.frame(data, stringsAsFactors = FALSE)
colnames(df) <- c("key", "value")
df <- df %>% mutate(key = tolower(trimws(key)), value = trimws(value))
get_val <- function(k) df$value[df$key == tolower(k)]
parse_num_vec <- function(k) {
if (tolower(k) %in% df$key) {
as.numeric(unlist(str_split(get_val(k), ",")))
} else {
NULL
}
}
idx_physical <- which(sapply(existing_soil$Children, \(x) x$Name == "Physical"))
if (length(idx_physical) == 1) {
physical <- existing_soil$Children[[idx_physical]]
if (!is.null(v <- parse_num_vec("dlayer"))) physical$Thickness <- v
if (!is.null(v <- parse_num_vec("bd"))) physical$BD <- v
if (!is.null(v <- parse_num_vec("airdry"))) physical$AirDry <- v
if (!is.null(v <- parse_num_vec("ll15"))) physical$LL15 <- clip_soil_layer(v, lower = physical$AirDry)
if (!is.null(v <- parse_num_vec("dul"))) physical$DUL <- clip_soil_layer(v, lower = physical$LL15)
if (!is.null(v <- parse_num_vec("sat"))) physical$SAT <- clip_soil_layer(v, lower = physical$DUL)
if (!is.null(v <- parse_num_vec("ks"))) physical$KS <- v
# Add sand and clay
sand <- parse_num_vec("sand")
clay <- parse_num_vec("clay")
if (!is.null(sand)) physical$ParticleSizeSand <- sand
if (!is.null(clay)) physical$ParticleSizeClay <- clay
# Compute silt if sand and clay are present
if (!is.null(sand) && !is.null(clay)) {
silt <- 100 - sand - clay
physical$ParticleSizeSilt <- clip_soil_layer(silt, lower = 0)
}
existing_soil$Children[[idx_physical]] <- physical
}
idx_organic <- which(sapply(existing_soil$Children, \(x) x$Name == "Organic"))
if (length(idx_organic) == 1) {
organic <- existing_soil$Children[[idx_organic]]
if (!is.null(v <- parse_num_vec("carbon"))) {
organic$Carbon <- v
organic$Thickness <- parse_num_vec("dlayer")
existing_soil$Children[[idx_organic]] <- organic
}
}
idx_chemical <- which(sapply(existing_soil$Children, \(x) x$Name == "Chemical"))
if (length(idx_chemical) == 1) {
chemical <- existing_soil$Children[[idx_chemical]]
if (!is.null(v <- parse_num_vec("ph"))) chemical$PH <- v
if (!is.null(v <- parse_num_vec("cec"))) chemical$CEC <- v
if (!is.null(v <- parse_num_vec("ec"))) chemical$EC <- v
if (!is.null(v <- parse_num_vec("dlayer"))) chemical$Thickness <- v
existing_soil$Children[[idx_chemical]] <- chemical
}
idx_water <- which(sapply(existing_soil$Children, \(x) x$Name == "Water"))
if (length(idx_water) == 1 && exists("physical")) {
iw <- existing_soil$Children[[idx_water]]
if (
!is.null(iw$InitialValues) &&
is.numeric(iw$InitialValues) &&
!is.null(physical$SAT) &&
is.numeric(physical$SAT)
) {
n <- min(length(iw$InitialValues), length(physical$SAT), length(physical$Thickness))
if (n > 0) {
iw$InitialValues <- iw$InitialValues[1:n]
iw$InitialValues <- clip_soil_layer(iw$InitialValues, upper = physical$SAT[1:n])
iw$Thickness <- physical$Thickness[1:n]
existing_soil$Children[[idx_water]] <- iw
}
}
}
# Meta fields
if (!is.null(v <- get_val("latitude"))) existing_soil$Latitude <- as.numeric(v)
if (!is.null(v <- get_val("longitude"))) existing_soil$Longitude <- as.numeric(v)
if (!is.null(v <- get_val("site"))) existing_soil$Site <- v
if (!is.null(v <- get_val("country"))) existing_soil$Country <- v
return(existing_soil)
}
# Load APSIMX file
apsim_json <- fromJSON(apsimx_file, simplifyVector = FALSE)
# Loop through all simulations
for (i in seq_along(apsim_json$Children)) {
sim <- apsim_json$Children[[i]]
if (sim$`$type` == "Models.Core.Simulation, Models") {
sim_name <- sim$Name
point_id <- str_extract(sim_name, "point\\d+")
if (is.na(point_id)) next
par_file <- file.path(par_dir, paste0(point_id, ".par"))
weather_file <- file.path(weather_dir, paste0(point_id, ".met"))
for (j in seq_along(sim$Children)) {
if (sim$Children[[j]]$`$type` == "Models.Climate.Weather, Models") {
sim$Children[[j]]$FileName <- weather_file
}
}
existing_soil <- sim$Children[[6]]$Children[[3]]
updated_soil <- update_soil_from_par(existing_soil, par_file)
sim$Children[[6]]$Children[[3]] <- updated_soil
apsim_json$Children[[i]] <- sim
message(paste0("✅ Updated simulation: ", sim_name))
}
}
## ✅ Updated simulation: Mungbean_point1
## ✅ Updated simulation: Mungbean_point2
## ✅ Updated simulation: Mungbean_point3
## ✅ Updated simulation: Mungbean_point4
## ✅ Updated simulation: Mungbean_point5
## ✅ Updated simulation: Mungbean_point6
## ✅ Updated simulation: Mungbean_point7
## ✅ Updated simulation: Mungbean_point8
## ✅ Updated simulation: Mungbean_point9
## ✅ Updated simulation: Mungbean_point10
## ✅ Updated simulation: Mungbean_point11
## ✅ Updated simulation: Mungbean_point12
## ✅ Updated simulation: Mungbean_point13
## ✅ Updated simulation: Mungbean_point14
## ✅ Updated simulation: Mungbean_point15
## ✅ Updated simulation: Mungbean_point16
## ✅ Updated simulation: Mungbean_point17
## ✅ Updated simulation: Mungbean_point18
## ✅ Updated simulation: Mungbean_point19
## ✅ Updated simulation: Mungbean_point20
## ✅ Updated simulation: Mungbean_point21
## ✅ Updated simulation: Mungbean_point22
## ✅ Updated simulation: Mungbean_point23
## ✅ Updated simulation: Mungbean_point24
## ✅ Updated simulation: Mungbean_point25
## ✅ Updated simulation: Mungbean_point26
## ✅ Updated simulation: Mungbean_point27
## ✅ Updated simulation: Mungbean_point28
## ✅ Updated simulation: Mungbean_point29
## ✅ Updated simulation: Mungbean_point30
## ✅ Updated simulation: Mungbean_point31
## ✅ Updated simulation: Mungbean_point32
## ✅ Updated simulation: Mungbean_point33
## ✅ Updated simulation: Mungbean_point34
## ✅ Updated simulation: Mungbean_point35
## ✅ Updated simulation: Mungbean_point36
## ✅ Updated simulation: Mungbean_point37
## ✅ Updated simulation: Mungbean_point38
## ✅ Updated simulation: Mungbean_point39
## ✅ Updated simulation: Mungbean_point40
## ✅ Updated simulation: Mungbean_point41
## ✅ Updated simulation: Mungbean_point42
## ✅ Updated simulation: Mungbean_point43
## ✅ Updated simulation: Mungbean_point44
## ✅ Updated simulation: Mungbean_point45
## ✅ Updated simulation: Mungbean_point46
## ✅ Updated simulation: Mungbean_point47
## ✅ Updated simulation: Mungbean_point48
## ✅ Updated simulation: Mungbean_point49
## ✅ Updated simulation: Mungbean_point50
## ✅ Updated simulation: Mungbean_point51
## ✅ Updated simulation: Mungbean_point52
## ✅ Updated simulation: Mungbean_point53
## ✅ Updated simulation: Mungbean_point54
## ✅ Updated simulation: Mungbean_point55
## ✅ Updated simulation: Mungbean_point56
## ✅ Updated simulation: Mungbean_point57
## ✅ Updated simulation: Mungbean_point58
## ✅ Updated simulation: Mungbean_point59
## ✅ Updated simulation: Mungbean_point60
## ✅ Updated simulation: Mungbean_point61
## ✅ Updated simulation: Mungbean_point62
## ✅ Updated simulation: Mungbean_point63
## ✅ Updated simulation: Mungbean_point64
## ✅ Updated simulation: Mungbean_point65
## ✅ Updated simulation: Mungbean_point66
## ✅ Updated simulation: Mungbean_point67
## ✅ Updated simulation: Mungbean_point68
## ✅ Updated simulation: Mungbean_point69
## ✅ Updated simulation: Mungbean_point70
## ✅ Updated simulation: Mungbean_point71
## ✅ Updated simulation: Mungbean_point72
## ✅ Updated simulation: Mungbean_point73
## ✅ Updated simulation: Mungbean_point74
## ✅ Updated simulation: Mungbean_point75
## ✅ Updated simulation: Mungbean_point76
## ✅ Updated simulation: Mungbean_point77
## ✅ Updated simulation: Mungbean_point78
## ✅ Updated simulation: Mungbean_point79
## ✅ Updated simulation: Mungbean_point80
## ✅ Updated simulation: Mungbean_point81
## ✅ Updated simulation: Mungbean_point82
## ✅ Updated simulation: Mungbean_point83
## ✅ Updated simulation: Mungbean_point84
## ✅ Updated simulation: Mungbean_point85
## ✅ Updated simulation: Mungbean_point86
## ✅ Updated simulation: Mungbean_point87
## ✅ Updated simulation: Mungbean_point88
## ✅ Updated simulation: Mungbean_point89
## ✅ Updated simulation: Mungbean_point90
## ✅ Updated simulation: Mungbean_point91
## ✅ Updated simulation: Mungbean_point92
## ✅ Updated simulation: Mungbean_point93
## ✅ Updated simulation: Mungbean_point94
## ✅ Updated simulation: Mungbean_point95
## ✅ Updated simulation: Mungbean_point96
## ✅ Updated simulation: Mungbean_point97
## ✅ Updated simulation: Mungbean_point98
## ✅ Updated simulation: Mungbean_point99
## ✅ Updated simulation: Mungbean_point100
## ✅ Updated simulation: Mungbean_point101
## ✅ Updated simulation: Mungbean_point102
## ✅ Updated simulation: Mungbean_point103
## ✅ Updated simulation: Mungbean_point104
## ✅ Updated simulation: Mungbean_point105
## ✅ Updated simulation: Mungbean_point106
## ✅ Updated simulation: Mungbean_point107
## ✅ Updated simulation: Mungbean_point108
## ✅ Updated simulation: Mungbean_point109
## ✅ Updated simulation: Mungbean_point110
## ✅ Updated simulation: Mungbean_point111
## ✅ Updated simulation: Mungbean_point112
## ✅ Updated simulation: Mungbean_point113
## ✅ Updated simulation: Mungbean_point114
## ✅ Updated simulation: Mungbean_point115
## ✅ Updated simulation: Mungbean_point116
## ✅ Updated simulation: Mungbean_point117
## ✅ Updated simulation: Mungbean_point118
## ✅ Updated simulation: Mungbean_point119
## ✅ Updated simulation: Mungbean_point120
## ✅ Updated simulation: Mungbean_point121
## ✅ Updated simulation: Mungbean_point122
## ✅ Updated simulation: Mungbean_point123
## ✅ Updated simulation: Mungbean_point124
## ✅ Updated simulation: Mungbean_point125
## ✅ Updated simulation: Mungbean_point126
## ✅ Updated simulation: Mungbean_point127
## ✅ Updated simulation: Mungbean_point128
## ✅ Updated simulation: Mungbean_point129
## ✅ Updated simulation: Mungbean_point130
## ✅ Updated simulation: Mungbean_point131
## ✅ Updated simulation: Mungbean_point132
## ✅ Updated simulation: Mungbean_point133
## ✅ Updated simulation: Mungbean_point134
## ✅ Updated simulation: Mungbean_point135
## ✅ Updated simulation: Mungbean_point136
## ✅ Updated simulation: Mungbean_point137
## ✅ Updated simulation: Mungbean_point138
## ✅ Updated simulation: Mungbean_point139
## ✅ Updated simulation: Mungbean_point140
## ✅ Updated simulation: Mungbean_point141
## ✅ Updated simulation: Mungbean_point142
## ✅ Updated simulation: Mungbean_point143
## ✅ Updated simulation: Mungbean_point144
## ✅ Updated simulation: Mungbean_point145
## ✅ Updated simulation: Mungbean_point146
## ✅ Updated simulation: Mungbean_point147
## ✅ Updated simulation: Mungbean_point148
## ✅ Updated simulation: Mungbean_point149
## ✅ Updated simulation: Mungbean_point150
## ✅ Updated simulation: Mungbean_point151
## ✅ Updated simulation: Mungbean_point152
## ✅ Updated simulation: Mungbean_point153
## ✅ Updated simulation: Mungbean_point154
## ✅ Updated simulation: Mungbean_point155
## ✅ Updated simulation: Mungbean_point156
## ✅ Updated simulation: Mungbean_point157
## ✅ Updated simulation: Mungbean_point158
## ✅ Updated simulation: Mungbean_point159
## ✅ Updated simulation: Mungbean_point160
## ✅ Updated simulation: Mungbean_point161
## ✅ Updated simulation: Mungbean_point162
## ✅ Updated simulation: Mungbean_point163
## ✅ Updated simulation: Mungbean_point164
## ✅ Updated simulation: Mungbean_point165
## ✅ Updated simulation: Mungbean_point166
## ✅ Updated simulation: Mungbean_point167
## ✅ Updated simulation: Mungbean_point168
## ✅ Updated simulation: Mungbean_point169
## ✅ Updated simulation: Mungbean_point170
## ✅ Updated simulation: Mungbean_point171
## ✅ Updated simulation: Mungbean_point172
## ✅ Updated simulation: Mungbean_point173
## ✅ Updated simulation: Mungbean_point174
## ✅ Updated simulation: Mungbean_point175
## ✅ Updated simulation: Mungbean_point176
## ✅ Updated simulation: Mungbean_point177
## ✅ Updated simulation: Mungbean_point178
## ✅ Updated simulation: Mungbean_point179
## ✅ Updated simulation: Mungbean_point180
## ✅ Updated simulation: Mungbean_point181
## ✅ Updated simulation: Mungbean_point182
## ✅ Updated simulation: Mungbean_point183
## ✅ Updated simulation: Mungbean_point184
## ✅ Updated simulation: Mungbean_point185
## ✅ Updated simulation: Mungbean_point186
## ✅ Updated simulation: Mungbean_point187
## ✅ Updated simulation: Mungbean_point188
## ✅ Updated simulation: Mungbean_point189
## ✅ Updated simulation: Mungbean_point190
## ✅ Updated simulation: Mungbean_point191
## ✅ Updated simulation: Mungbean_point192
## ✅ Updated simulation: Mungbean_point193
## ✅ Updated simulation: Mungbean_point194
## ✅ Updated simulation: Mungbean_point195
## ✅ Updated simulation: Mungbean_point196
## ✅ Updated simulation: Mungbean_point197
## ✅ Updated simulation: Mungbean_point198
## ✅ Updated simulation: Mungbean_point199
## ✅ Updated simulation: Mungbean_point200
# Write the modified APSIMX
json_text <- toJSON(apsim_json, pretty = TRUE, auto_unbox = TRUE, null = "null")
writeLines(json_text, apsimx_out)
cat("\n🎉 All simulations updated successfully!\n")
##
## 🎉 All simulations updated successfully!
cat("📁 Updated APSIMX saved to:\n", apsimx_out, "\n")
## 📁 Updated APSIMX saved to:
## D:/Mes Donnees/R/Biomass_Crops/Modeling/APSIM/apsimx_runs/BioCrops_Final200.apsimx