Skip to content

Commit 15759cf

Browse files
committed
fix config file parsing order
1 parent 82bf3a6 commit 15759cf

File tree

4 files changed

+56
-52
lines changed

4 files changed

+56
-52
lines changed

experiments/ClimaEarth/cli_options.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ function argparse_settings()
135135
default = "PrescribedSurface"
136136
"--atmos_config_file"
137137
help = "An optional YAML file used to overwrite the default model parameters."
138+
arg_type = String
139+
default = nothing
138140
"--albedo_model"
139141
help = "Type of albedo model. [`ConstantAlbedo`, `RegressionFunctionAlbedo`, `CouplerAlbedo` (default)]"
140142
arg_type = String

experiments/ClimaEarth/components/atmosphere/climaatmos.jl

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,10 @@ end
473473
### ClimaAtmos.jl model-specific functions (not explicitly required by ClimaCoupler.jl)
474474
###
475475
"""
476-
get_atmos_config_dict(coupler_dict::Dict, atmos_output_dir)
476+
get_atmos_config_dict(coupler_config::Dict, atmos_output_dir)
477477
478478
Returns the specified atmospheric configuration (`atmos_config`) overwitten by arguments
479-
in the coupler dictionary (`config_dict`).
479+
in the coupler dictionary (`coupler_config`).
480480
The returned `atmos_config` dictionary will then be used to set up the atmosphere simulation.
481481
482482
In this function, parameters are overwritten in a specific order, from lowest to highest priority:
@@ -489,20 +489,11 @@ The TOML parameter file to use is chosen using the following priority:
489489
If a coupler TOML file is provided, it is used. Otherwise we use an atmos TOML
490490
file if it's provided. If neither is provided, we use a default coupler TOML file.
491491
"""
492-
function get_atmos_config_dict(coupler_dict::Dict, atmos_output_dir)
493-
atmos_config_file = coupler_dict["atmos_config_file"]
494-
# override default or specified configs with coupler arguments, and set the correct atmos config_file
495-
if isnothing(atmos_config_file)
496-
@info "Using Atmos default configuration"
497-
atmos_config = merge(CA.default_config_dict(), coupler_dict, Dict("config_file" => atmos_config_file))
498-
else
499-
@info "Using Atmos configuration from ClimaCoupler in $atmos_config_file"
500-
atmos_config = merge(
501-
CA.override_default_config(joinpath(pkgdir(ClimaCoupler), atmos_config_file)),
502-
coupler_dict,
503-
Dict("config_file" => atmos_config_file),
504-
)
505-
end
492+
function get_atmos_config_dict(coupler_config::Dict, atmos_output_dir)
493+
atmos_config = deepcopy(coupler_config)
494+
495+
# Rename atmosphere config file from ClimaCoupler convention to ClimaAtmos convention
496+
atmos_config["config_file"] = coupler_config["atmos_config_file"]
506497

507498
# use atmos toml if coupler toml is not defined
508499
# If we can't find the file at the relative path, prepend pkgdir(ClimaAtmos)
@@ -523,25 +514,25 @@ function get_atmos_config_dict(coupler_dict::Dict, atmos_output_dir)
523514
# Ensure Atmos's own checkpoints are synced up with ClimaCoupler, so that we
524515
# can pick up from where we have left. NOTE: This should not be needed, but
525516
# there is no easy way to initialize ClimaAtmos with a different t_start
526-
atmos_config["dt_save_state_to_disk"] = coupler_dict["checkpoint_dt"]
517+
atmos_config["dt_save_state_to_disk"] = coupler_config["checkpoint_dt"]
527518

528519
# Add all extra atmos diagnostic entries into the vector of atmos diagnostics
529520
atmos_config["diagnostics"] =
530521
haskey(atmos_config, "diagnostics") ?
531-
vcat(atmos_config["diagnostics"], coupler_dict["extra_atmos_diagnostics"]) :
532-
coupler_dict["extra_atmos_diagnostics"]
522+
vcat(atmos_config["diagnostics"], coupler_config["extra_atmos_diagnostics"]) :
523+
coupler_config["extra_atmos_diagnostics"]
533524

534525
# The Atmos `get_simulation` function expects the atmos config to contains its timestep size
535-
# in the `dt` field. If there is a `dt_atmos` field in coupler_dict, we add it to the atmos config as `dt`
536-
dt_atmos = haskey(coupler_dict, "dt_atmos") ? coupler_dict["dt_atmos"] : coupler_dict["dt"]
526+
# in the `dt` field. If there is a `dt_atmos` field in coupler_config, we add it to the atmos config as `dt`
527+
dt_atmos = haskey(coupler_config, "dt_atmos") ? coupler_config["dt_atmos"] : coupler_config["dt"]
537528
atmos_config["dt"] = dt_atmos
538529

539530
# set restart file to the initial file saved in this location if it is not nothing
540531
# TODO this is hardcoded and should be fixed once we have a better restart system
541532
if !isnothing(atmos_config["restart_file"])
542533
atmos_config["restart_file"] = replace(atmos_config["restart_file"], "active" => "0000")
543534
end
544-
return atmos_config
535+
return CA.AtmosConfig(atmos_config)
545536
end
546537

547538
"""

experiments/ClimaEarth/setup_run.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ function CoupledSimulation(config_dict::AbstractDict)
157157
## Note this step must come after parsing the coupler config dictionary, since
158158
## some parameters are passed from the coupler config to the component model configs
159159
atmos_config_dict = get_atmos_config_dict(config_dict, atmos_output_dir)
160-
(; dt_rad) = get_atmos_args(atmos_config_dict)
161160

162161
## set unique random seed if desired, otherwise use default
163162
Random.seed!(random_seed)
@@ -177,12 +176,12 @@ function CoupledSimulation(config_dict::AbstractDict)
177176
# We only support a round number of seconds
178177
isinteger(float(t_start)) || error("Cannot restart from a non integer number of seconds")
179178
t_start_int = Int(float(t_start))
180-
atmos_config_dict["t_start"] = "$(t_start_int)secs"
179+
atmos_config_dict.parsed_args["t_start"] = "$(t_start_int)secs"
181180
else
182181
# There was no `t_start`, so we have to use a workaround for this.
183182
# This does not support passing the command-line arguments (unless
184183
# restart_dir is exactly the same as output_dir_root)
185-
atmos_config_dict["restart_file"] = climaatmos_restart_path(output_dir_root, restart_t)
184+
atmos_config_dict.parsed_args["restart_file"] = climaatmos_restart_path(output_dir_root, restart_t)
186185
end
187186

188187
@info "Starting from t_start $(t_start)"
@@ -207,7 +206,7 @@ function CoupledSimulation(config_dict::AbstractDict)
207206
=#
208207

209208
## init atmos model component
210-
atmos_sim = ClimaAtmosSimulation(CA.AtmosConfig(atmos_config_dict))
209+
atmos_sim = ClimaAtmosSimulation(atmos_config_dict)
211210
thermo_params = get_thermo_params(atmos_sim) # TODO: this should be shared by all models #342
212211

213212
#=

experiments/ClimaEarth/user_io/arg_parsing.jl

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,49 @@ mode_name_dict = Dict(
1414
Read in the configuration file and job ID from the command line.
1515
A dictionary is constructed from the input configuration file and returned.
1616
17+
Since the atmosphere model also uses a configuration file, we read in the atmosphere
18+
configuration file specified in the coupler configuration file (if any), and overwrite
19+
it with the coupler configuration.
20+
21+
The order of priority for overwriting configuration options from lowest to highest is:
22+
1. ClimaAtmos defaults
23+
2. ClimaCoupler defaults (defined in `experiments/ClimaEarth/cli_options.jl`)
24+
3. Command line arguments provided to ClimaCoupler
25+
4. ClimaAtmos configuration file (if specified in coupler config file)
26+
5. ClimaCoupler configuration file
27+
1728
# Returns
1829
- `config_dict`: A dictionary mapping configuration keys to the specified settings
1930
"""
2031
function get_coupler_config_dict(config_file)
21-
# Extract the job ID from the command line arguments
22-
parsed_args = parse_commandline(argparse_settings())
23-
job_id = parsed_args["job_id"]
24-
25-
# Get the job ID from the config file string if not provided
26-
job_id = isnothing(job_id) ? string(split(split(config_file, '/')[end], '.')[1]) : job_id
32+
# Get the coupler default configuration dictionary, overwritten by any command line arguments
33+
# Typically the command line arguments are only `config_file` and `job_id`
34+
coupler_default_cli = parse_commandline(argparse_settings())
35+
36+
# Extract the job ID from the command line arguments, or from the config file name if not provided
37+
job_id = coupler_default_cli["job_id"]
38+
coupler_default_cli["job_id"] = isnothing(job_id) ? string(split(split(config_file, '/')[end], '.')[1]) : job_id
39+
40+
# Load the coupler config file into a dictionary
41+
coupler_config_dict = YAML.load_file(config_file)
42+
43+
# Get ClimaAtmos default configuration dictionary
44+
atmos_default = CA.default_config_dict()
45+
atmos_config_file = merge(coupler_default_cli, coupler_config_dict)["atmos_config_file"]
46+
if isnothing(atmos_config_file)
47+
@info "Using Atmos default configuration"
48+
49+
# Merge the atmos default config, coupler default config + command line inputs,
50+
# and user-provided coupler config
51+
config_dict = merge(atmos_default, coupler_default_cli, coupler_config_dict)
52+
else
53+
@info "Using Atmos configuration from ClimaCoupler in $atmos_config_file"
54+
atmos_config_dict = YAML.load_file(joinpath(pkgdir(ClimaCoupler), atmos_config_file))
2755

28-
# Read in config dictionary from file, overriding the defaults in `parsed_args`
29-
config_dict = merge(parsed_args, YAML.load_file(config_file))
30-
config_dict["job_id"] = job_id
56+
# Merge the atmos default config, coupler default config + command line inputs,
57+
# user-provided atmos config, and user-provided coupler config
58+
config_dict = merge(atmos_default, coupler_default_cli, atmos_config_dict, coupler_config_dict)
59+
end
3160

3261
# Select the correct timestep for each component model based on which are available
3362
parse_component_dts!(config_dict)
@@ -159,23 +188,6 @@ function get_coupler_args(config_dict::Dict)
159188
)
160189
end
161190

162-
"""
163-
get_atmos_args(atmos_config_dict)
164-
165-
Extract the necessary arguments from the atmosphere configuration dictionary.
166-
167-
# Arguments
168-
- `atmos_config_dict`: A dictionary mapping atmosphere configuration keys to the specified settings
169-
170-
# Returns
171-
- All arguments needed for the atmosphere simulation
172-
"""
173-
function get_atmos_args(atmos_config_dict)
174-
dt_rad = atmos_config_dict["dt_rad"]
175-
return (; dt_rad)
176-
end
177-
178-
179191
### Helper functions used in argument parsing ###
180192

181193
"""

0 commit comments

Comments
 (0)