From ef6d85ff60f5c51309ac958988973c2c4836f06a Mon Sep 17 00:00:00 2001 From: Akshay Sridhar Date: Wed, 13 Mar 2024 15:30:16 -0700 Subject: [PATCH] modified: coupler_driver_calibration.jl new file: coupler_driver_init.jl new file: coupler_init_components.jl new file: coupler_parse_args.jl --- calibration/coupler_driver_calibration.jl | 400 +--------------------- calibration/coupler_driver_init.jl | 77 +++++ calibration/coupler_init_components.jl | 256 ++++++++++++++ calibration/coupler_parse_args.jl | 47 +++ 4 files changed, 383 insertions(+), 397 deletions(-) create mode 100644 calibration/coupler_driver_init.jl create mode 100644 calibration/coupler_init_components.jl create mode 100644 calibration/coupler_parse_args.jl diff --git a/calibration/coupler_driver_calibration.jl b/calibration/coupler_driver_calibration.jl index 62f1930f6a..e49b7de1cf 100644 --- a/calibration/coupler_driver_calibration.jl +++ b/calibration/coupler_driver_calibration.jl @@ -1,385 +1,6 @@ -redirect_stderr(IOContext(stderr, :stacktrace_types_limited => Ref(false))) - -using ClimaComms -comms_ctx = ClimaComms.context() -const pid, nprocs = ClimaComms.init(comms_ctx) - - -import SciMLBase: ODEProblem, solve, step!, init, reinit! -using LinearAlgebra -import Test: @test -using Dates -using Plots -using Statistics: mean -import ClimaAtmos as CA -import YAML - -using ClimaCore.Utilities: half, PlusHalf -using ClimaCore: InputOutput, Fields -import ClimaCore.Spaces as Spaces - -## coupler specific imports -import ClimaCoupler -import ClimaCoupler.Regridder -import ClimaCoupler.Regridder: - update_surface_fractions!, combine_surfaces!, combine_surfaces_from_sol!, dummmy_remap!, binary_mask -import ClimaCoupler.ConservationChecker: - EnergyConservationCheck, WaterConservationCheck, check_conservation!, plot_global_conservation -import ClimaCoupler.Utilities: swap_space! -import ClimaCoupler.BCReader: - bcfile_info_init, float_type_bcf, update_midmonth_data!, next_date_in_file, interpolate_midmonth_to_daily -import ClimaCoupler.TimeManager: - current_date, - datetime_to_strdate, - trigger_callback, - Monthly, - EveryTimestep, - HourlyCallback, - MonthlyCallback, - update_firstdayofmonth!, - trigger_callback! -import ClimaCoupler.Diagnostics: get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean -import ClimaCoupler.PostProcessor: postprocess - -import ClimaCoupler.Interfacer: - CoupledSimulation, - float_type, - AtmosModelSimulation, - SurfaceModelSimulation, - SurfaceStub, - SeaIceModelSimulation, - LandModelSimulation, - OceanModelSimulation, - get_field, - update_field! -import ClimaCoupler.FluxCalculator: - PartitionedStateFluxes, - CombinedStateFluxes, - combined_turbulent_fluxes!, - MoninObukhovScheme, - partitioned_turbulent_fluxes! -import ClimaCoupler.FieldExchanger: - import_atmos_fields!, - import_combined_surface_fields!, - update_sim!, - update_model_sims!, - reinit_model_sims!, - step_model_sims! -import ClimaCoupler.Checkpointer: checkpoint_model_state, get_model_state_vector, restart_model_state! - -## helpers for component models -include("../experiments/AMIP/components/atmosphere/climaatmos_init.jl") -include("../experiments/AMIP/components/land/bucket_init.jl") -include("../experiments/AMIP/components/land/bucket_utils.jl") -include("../experiments/AMIP/components/ocean/slab_ocean_init.jl") -include("../experiments/AMIP/components/ocean/prescr_seaice_init.jl") -include("../experiments/AMIP/user_io/user_diagnostics.jl") -include("../experiments/AMIP/user_io/user_logging.jl") - -## coupler defaults -# get component model dictionaries -include("../experiments/AMIP/cli_options.jl") -parsed_args = parse_commandline(argparse_settings()) -config_dict = YAML.load_file("./experiments/amip_coupled/coupler_config.yml") -config_dict = YAML.load_file(joinpath(experiment_dir, "coupler_config.yml")); -config_dict["t_end"] = "150secs"; -config_dict["output_dir"] = output_dir; -config_dict = merge(parsed_args, config_dict) -config_dict_atmos = get_atmos_config(config_dict) - -# merge dictionaries of command line arguments, coupler dictionary and component model dictionaries -# (if there are common keys, the last dictorionary in the `merge` arguments takes precedence) -config_dict = merge(config_dict_atmos, config_dict) - - -## read in some parsed command line arguments -mode_name = config_dict["mode_name"] -run_name = config_dict["run_name"] -energy_check = config_dict["energy_check"] -FT = config_dict["FLOAT_TYPE"] == "Float64" ? Float64 : Float32 -land_sim_name = "bucket" -t_end = Float64(time_to_seconds(config_dict["t_end"])) -t_start = 0.0 -tspan = (t_start, t_end) -Δt_cpl = Float64(config_dict["dt_cpl"]) -saveat = Float64(time_to_seconds(config_dict["dt_save_to_sol"])) -date0 = date = DateTime(config_dict["start_date"], dateformat"yyyymmdd") -mono_surface = config_dict["mono_surface"] -hourly_checkpoint = config_dict["hourly_checkpoint"] -restart_dir = config_dict["restart_dir"] -restart_t = Int(config_dict["restart_t"]) -evolving_ocean = config_dict["evolving_ocean"] -config_dict["print_config_dict"] = false - -## I/O directory setup -COUPLER_OUTPUT_DIR = "/Users/akshaysridhar/Research/Codes/ClimaCoupler.jl/calibration/output/amip/" -mkpath(COUPLER_OUTPUT_DIR) - -REGRID_DIR = joinpath(COUPLER_OUTPUT_DIR, "regrid_tmp/") -mkpath(REGRID_DIR) - -COUPLER_ARTIFACTS_DIR = COUPLER_OUTPUT_DIR * "_artifacts" -isdir(COUPLER_ARTIFACTS_DIR) ? nothing : mkpath(COUPLER_ARTIFACTS_DIR) - -config_dict["print_config_dict"] ? @info(config_dict) : nothing - -# get the paths to the necessary data files: land-sea mask, sst map, sea ice concentration -include(joinpath(pkgdir(ClimaCoupler), "artifacts", "artifact_funcs.jl")) -sst_data = joinpath(sst_dataset_path(), "sst.nc") -sic_data = joinpath(sic_dataset_path(), "sic.nc") -co2_data = joinpath(co2_dataset_path(), "mauna_loa_co2.nc") -land_mask_data = joinpath(mask_dataset_path(), "seamask.nc") - -config_dict_atmos["output_dir"] = COUPLER_OUTPUT_DIR -atmos_sim = atmos_init(FT, config_dict_atmos); -thermo_params = get_thermo_params(atmos_sim) # TODO: this should be shared by all models - -#= -We use a common `Space` for all global surfaces. This enables the MPI processes to operate on the same columns in both -the atmospheric and surface components, so exchanges are parallelized. Note this is only possible when the -atmosphere and surface are of the same horizontal resolution. -=# -## init a 2D boundary space at the surface -boundary_space = Spaces.horizontal_space(atmos_sim.domain.face_space) - -# init land-sea fraction -land_fraction = - FT.( - Regridder.land_fraction( - FT, - REGRID_DIR, - comms_ctx, - land_mask_data, - "LSMASK", - boundary_space, - mono = mono_surface, - ) - ) - -@info mode_name -if mode_name == "amip" - @info "AMIP boundary conditions - do not expect energy conservation" - - ## land - land_sim = bucket_init( - FT, - tspan, - config_dict["land_domain_type"], - config_dict["land_albedo_type"], - config_dict["land_temperature_anomaly"], - comms_ctx, - REGRID_DIR; - dt = Δt_cpl, - space = boundary_space, - saveat = saveat, - area_fraction = land_fraction, - date_ref = date0, - t_start = t_start, - ) - - ## ocean - SST_info = bcfile_info_init( - FT, - REGRID_DIR, - sst_data, - "SST", - boundary_space, - comms_ctx, - interpolate_daily = true, - scaling_function = clean_sst, ## convert to Kelvin - land_fraction = land_fraction, - date0 = date0, - mono = mono_surface, - ) - - update_midmonth_data!(date0, SST_info) - SST_init = interpolate_midmonth_to_daily(date0, SST_info) - ocean_sim = SurfaceStub((; - T_sfc = SST_init, - ρ_sfc = ClimaCore.Fields.zeros(boundary_space), - z0m = FT(1e-3), - z0b = FT(1e-3), - beta = FT(1), - α = FT(0.06), - area_fraction = (FT(1) .- land_fraction), - phase = TD.Liquid(), - thermo_params = thermo_params, - )) - - ## sea ice - SIC_info = bcfile_info_init( - FT, - REGRID_DIR, - sic_data, - "SEAICE", - boundary_space, - comms_ctx, - interpolate_daily = true, - scaling_function = clean_sic, ## convert to fraction - land_fraction = land_fraction, - date0 = date0, - mono = mono_surface, - ) - update_midmonth_data!(date0, SIC_info) - SIC_init = interpolate_midmonth_to_daily(date0, SIC_info) - ice_fraction = get_ice_fraction.(SIC_init, mono_surface) - ice_sim = ice_init( - FT; - tspan = tspan, - dt = Δt_cpl, - space = boundary_space, - saveat = saveat, - area_fraction = ice_fraction, - thermo_params = thermo_params, - ) - - ## CO2 concentration - CO2_info = bcfile_info_init( - FT, - REGRID_DIR, - co2_data, - "co2", - boundary_space, - comms_ctx, - interpolate_daily = true, - land_fraction = ones(boundary_space), - date0 = date0, - mono = mono_surface, - ) - - update_midmonth_data!(date0, CO2_info) - CO2_init = interpolate_midmonth_to_daily(date0, CO2_info) - update_field!(atmos_sim, Val(:co2_gm), CO2_init) - - mode_specifics = (; name = mode_name, SST_info = SST_info, SIC_info = SIC_info, CO2_info = CO2_info) - -elseif mode_name in ("slabplanet", "slabplanet_aqua", "slabplanet_terra") - - land_fraction = mode_name == "slabplanet_aqua" ? land_fraction .* 0 : land_fraction - land_fraction = mode_name == "slabplanet_terra" ? land_fraction .* 0 .+ 1 : land_fraction - - ## land - land_sim = bucket_init( - FT, - tspan, - config_dict["land_domain_type"], - config_dict["land_albedo_type"], - config_dict["land_temperature_anomaly"], - comms_ctx, - REGRID_DIR; - dt = Δt_cpl, - space = boundary_space, - saveat = saveat, - area_fraction = land_fraction, - date_ref = date0, - t_start = t_start, - ) - - ## ocean - ocean_sim = ocean_init( - FT; - tspan = tspan, - dt = Δt_cpl, - space = boundary_space, - saveat = saveat, - area_fraction = (FT(1) .- land_fraction), ## NB: this ocean fraction includes areas covered by sea ice (unlike the one contained in the cs) - thermo_params = thermo_params, - evolving = evolving_ocean, - ) - - ## sea ice (here set to zero area coverage) - ice_sim = SurfaceStub((; - T_sfc = ClimaCore.Fields.ones(boundary_space), - ρ_sfc = ClimaCore.Fields.zeros(boundary_space), - z0m = FT(0), - z0b = FT(0), - beta = FT(1), - α = FT(1), - area_fraction = ClimaCore.Fields.zeros(boundary_space), - phase = TD.Ice(), - thermo_params = thermo_params, - )) - - mode_specifics = (; name = mode_name, SST_info = nothing, SIC_info = nothing) -end - -#= -## Coupler Initialization -The coupler needs to contain exchange information, manage the calendar and be able to access all component models. It can also optionally -save online diagnostics. These are all initialized here and saved in a global `CouplerSimulation` struct, `cs`. -=# - -## coupler exchange fields -coupler_field_names = ( - :T_S, - :z0m_S, - :z0b_S, - :ρ_sfc, - :q_sfc, - :albedo, - :beta, - :F_turb_energy, - :F_turb_moisture, - :F_turb_ρτxz, - :F_turb_ρτyz, - :F_radiative, - :P_liq, - :P_snow, - :F_radiative_TOA, - :P_net, -) -coupler_fields = - NamedTuple{coupler_field_names}(ntuple(i -> ClimaCore.Fields.zeros(boundary_space), length(coupler_field_names))) - -## model simulations -model_sims = (atmos_sim = atmos_sim, ice_sim = ice_sim, land_sim = land_sim, ocean_sim = ocean_sim); - -## dates -dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)], new_month = [false]) - -#= -### Online Diagnostics -User can write custom diagnostics in the `user_diagnostics.jl`. -=# -monthly_3d_diags = init_diagnostics( - (:T, :u, :q_tot, :q_liq_ice), - atmos_sim.domain.center_space; - save = Monthly(), - operations = (; accumulate = TimeMean([Int(0)])), - output_dir = COUPLER_OUTPUT_DIR, - name_tag = "monthly_mean_3d_", -) - -monthly_2d_diags = init_diagnostics( - (:precipitation_rate, :toa_fluxes, :T_sfc, :tubulent_energy_fluxes), - boundary_space; - save = Monthly(), - operations = (; accumulate = TimeMean([Int(0)])), - output_dir = COUPLER_OUTPUT_DIR, - name_tag = "monthly_mean_2d_", -) - -diagnostics = (monthly_3d_diags, monthly_2d_diags) - -#= -## Initialize Conservation Checks -=# -## init conservation info collector -conservation_checks = nothing -if energy_check - @assert( - mode_name[1:10] == "slabplanet" && !CA.is_distributed(ClimaComms.context(boundary_space)), - "Only non-distributed slabplanet allowable for energy_check" - ) - conservation_checks = (; energy = EnergyConservationCheck(model_sims), water = WaterConservationCheck(model_sims)) -end - -dir_paths = (; output = COUPLER_OUTPUT_DIR, artifacts = COUPLER_ARTIFACTS_DIR) -checkpoint_cb = - HourlyCallback(dt = FT(480), func = checkpoint_sims, ref_date = [dates.date[1]], active = hourly_checkpoint) # 20 days -update_firstdayofmonth!_cb = - MonthlyCallback(dt = FT(1), func = update_firstdayofmonth!, ref_date = [dates.date1[1]], active = true) # for BCReader -callbacks = (; checkpoint = checkpoint_cb, update_firstdayofmonth! = update_firstdayofmonth!_cb) +include("coupler_driver_init.jl") +include("coupler_pargs_args.jl") +include("coupler_init_components.jl") ## coupler simulation cs = CoupledSimulation{FT}( @@ -400,21 +21,6 @@ cs = CoupledSimulation{FT}( dir_paths, ); -#= -## Restart component model states if specified -=# -#if restart_dir !== "unspecified" -# for sim in cs.model_sims -# if get_model_state_vector(sim) !== nothing -# @skipping restart -# restart_model_state!(sim, comms_ctx, restart_t; input_dir = restart_dir) -# end -# end -#end - -#= -## Initialize Component Model Exchange -=# turbulent_fluxes = nothing if config_dict["turb_flux_partition"] == "PartitionedStateFluxes" turbulent_fluxes = PartitionedStateFluxes() diff --git a/calibration/coupler_driver_init.jl b/calibration/coupler_driver_init.jl new file mode 100644 index 0000000000..806a83ae1c --- /dev/null +++ b/calibration/coupler_driver_init.jl @@ -0,0 +1,77 @@ +redirect_stderr(IOContext(stderr, :stacktrace_types_limited => Ref(false))) + +using ClimaComms +comms_ctx = ClimaComms.context() +const pid, nprocs = ClimaComms.init(comms_ctx) + + +import SciMLBase: ODEProblem, solve, step!, init, reinit! +using LinearAlgebra +import Test: @test +using Dates +using Plots +using Statistics: mean +import ClimaAtmos as CA +import YAML + +using ClimaCore.Utilities: half, PlusHalf +using ClimaCore: InputOutput, Fields +import ClimaCore.Spaces as Spaces + +## coupler specific imports +import ClimaCoupler +import ClimaCoupler.Regridder +import ClimaCoupler.Regridder: + update_surface_fractions!, combine_surfaces!, combine_surfaces_from_sol!, dummmy_remap!, binary_mask +import ClimaCoupler.ConservationChecker: + EnergyConservationCheck, WaterConservationCheck, check_conservation!, plot_global_conservation +import ClimaCoupler.Utilities: swap_space! +import ClimaCoupler.BCReader: + bcfile_info_init, float_type_bcf, update_midmonth_data!, next_date_in_file, interpolate_midmonth_to_daily +import ClimaCoupler.TimeManager: + current_date, + datetime_to_strdate, + trigger_callback, + Monthly, + EveryTimestep, + HourlyCallback, + MonthlyCallback, + update_firstdayofmonth!, + trigger_callback! +import ClimaCoupler.Diagnostics: get_var, init_diagnostics, accumulate_diagnostics!, save_diagnostics, TimeMean +import ClimaCoupler.PostProcessor: postprocess + +import ClimaCoupler.Interfacer: + CoupledSimulation, + float_type, + AtmosModelSimulation, + SurfaceModelSimulation, + SurfaceStub, + SeaIceModelSimulation, + LandModelSimulation, + OceanModelSimulation, + get_field, + update_field! +import ClimaCoupler.FluxCalculator: + PartitionedStateFluxes, + CombinedStateFluxes, + combined_turbulent_fluxes!, + MoninObukhovScheme, + partitioned_turbulent_fluxes! +import ClimaCoupler.FieldExchanger: + import_atmos_fields!, + import_combined_surface_fields!, + update_sim!, + update_model_sims!, + reinit_model_sims!, + step_model_sims! +import ClimaCoupler.Checkpointer: checkpoint_model_state, get_model_state_vector, restart_model_state! + +## helpers for component models +include("../experiments/AMIP/components/atmosphere/climaatmos_init.jl") +include("../experiments/AMIP/components/land/bucket_init.jl") +include("../experiments/AMIP/components/land/bucket_utils.jl") +include("../experiments/AMIP/components/ocean/slab_ocean_init.jl") +include("../experiments/AMIP/components/ocean/prescr_seaice_init.jl") +include("../experiments/AMIP/user_io/user_diagnostics.jl") +include("../experiments/AMIP/user_io/user_logging.jl") diff --git a/calibration/coupler_init_components.jl b/calibration/coupler_init_components.jl new file mode 100644 index 0000000000..70e2657e19 --- /dev/null +++ b/calibration/coupler_init_components.jl @@ -0,0 +1,256 @@ +# get the paths to the necessary data files: land-sea mask, sst map, sea ice concentration +include(joinpath(pkgdir(ClimaCoupler), "artifacts", "artifact_funcs.jl")) +sst_data = joinpath(sst_dataset_path(), "sst.nc") +sic_data = joinpath(sic_dataset_path(), "sic.nc") +co2_data = joinpath(co2_dataset_path(), "mauna_loa_co2.nc") +land_mask_data = joinpath(mask_dataset_path(), "seamask.nc") + +atmos_sim = atmos_init(FT, config_dict_atmos); +thermo_params = get_thermo_params(atmos_sim) # TODO: this should be shared by all models + +#= +We use a common `Space` for all global surfaces. This enables the MPI processes to operate on the same columns in both +the atmospheric and surface components, so exchanges are parallelized. Note this is only possible when the +atmosphere and surface are of the same horizontal resolution. +=# +## init a 2D boundary space at the surface +boundary_space = Spaces.horizontal_space(atmos_sim.domain.face_space) + +# init land-sea fraction +land_fraction = + FT.( + Regridder.land_fraction( + FT, + REGRID_DIR, + comms_ctx, + land_mask_data, + "LSMASK", + boundary_space, + mono = mono_surface, + ) + ) + +@info mode_name +if mode_name == "amip" + @info "AMIP boundary conditions - do not expect energy conservation" + + ## land + land_sim = bucket_init( + FT, + tspan, + config_dict["land_domain_type"], + config_dict["land_albedo_type"], + config_dict["land_temperature_anomaly"], + comms_ctx, + REGRID_DIR; + dt = Δt_cpl, + space = boundary_space, + saveat = saveat, + area_fraction = land_fraction, + date_ref = date0, + t_start = t_start, + ) + + ## ocean + SST_info = bcfile_info_init( + FT, + REGRID_DIR, + sst_data, + "SST", + boundary_space, + comms_ctx, + interpolate_daily = true, + scaling_function = clean_sst, ## convert to Kelvin + land_fraction = land_fraction, + date0 = date0, + mono = mono_surface, + ) + + update_midmonth_data!(date0, SST_info) + SST_init = interpolate_midmonth_to_daily(date0, SST_info) + ocean_sim = SurfaceStub((; + T_sfc = SST_init, + ρ_sfc = ClimaCore.Fields.zeros(boundary_space), + z0m = FT(1e-3), + z0b = FT(1e-3), + beta = FT(1), + α = FT(0.06), + area_fraction = (FT(1) .- land_fraction), + phase = TD.Liquid(), + thermo_params = thermo_params, + )) + + ## sea ice + SIC_info = bcfile_info_init( + FT, + REGRID_DIR, + sic_data, + "SEAICE", + boundary_space, + comms_ctx, + interpolate_daily = true, + scaling_function = clean_sic, ## convert to fraction + land_fraction = land_fraction, + date0 = date0, + mono = mono_surface, + ) + update_midmonth_data!(date0, SIC_info) + SIC_init = interpolate_midmonth_to_daily(date0, SIC_info) + ice_fraction = get_ice_fraction.(SIC_init, mono_surface) + ice_sim = ice_init( + FT; + tspan = tspan, + dt = Δt_cpl, + space = boundary_space, + saveat = saveat, + area_fraction = ice_fraction, + thermo_params = thermo_params, + ) + + ## CO2 concentration + CO2_info = bcfile_info_init( + FT, + REGRID_DIR, + co2_data, + "co2", + boundary_space, + comms_ctx, + interpolate_daily = true, + land_fraction = ones(boundary_space), + date0 = date0, + mono = mono_surface, + ) + + update_midmonth_data!(date0, CO2_info) + CO2_init = interpolate_midmonth_to_daily(date0, CO2_info) + update_field!(atmos_sim, Val(:co2_gm), CO2_init) + + mode_specifics = (; name = mode_name, SST_info = SST_info, SIC_info = SIC_info, CO2_info = CO2_info) + +elseif mode_name in ("slabplanet", "slabplanet_aqua", "slabplanet_terra") + + land_fraction = mode_name == "slabplanet_aqua" ? land_fraction .* 0 : land_fraction + land_fraction = mode_name == "slabplanet_terra" ? land_fraction .* 0 .+ 1 : land_fraction + + ## land + land_sim = bucket_init( + FT, + tspan, + config_dict["land_domain_type"], + config_dict["land_albedo_type"], + config_dict["land_temperature_anomaly"], + comms_ctx, + REGRID_DIR; + dt = Δt_cpl, + space = boundary_space, + saveat = saveat, + area_fraction = land_fraction, + date_ref = date0, + t_start = t_start, + ) + + ## ocean + ocean_sim = ocean_init( + FT; + tspan = tspan, + dt = Δt_cpl, + space = boundary_space, + saveat = saveat, + area_fraction = (FT(1) .- land_fraction), ## NB: this ocean fraction includes areas covered by sea ice (unlike the one contained in the cs) + thermo_params = thermo_params, + evolving = evolving_ocean, + ) + + ## sea ice (here set to zero area coverage) + ice_sim = SurfaceStub((; + T_sfc = ClimaCore.Fields.ones(boundary_space), + ρ_sfc = ClimaCore.Fields.zeros(boundary_space), + z0m = FT(0), + z0b = FT(0), + beta = FT(1), + α = FT(1), + area_fraction = ClimaCore.Fields.zeros(boundary_space), + phase = TD.Ice(), + thermo_params = thermo_params, + )) + + mode_specifics = (; name = mode_name, SST_info = nothing, SIC_info = nothing) +end + +#= +## Coupler Initialization +The coupler needs to contain exchange information, manage the calendar and be able to access all component models. It can also optionally +save online diagnostics. These are all initialized here and saved in a global `CouplerSimulation` struct, `cs`. +=# + +## coupler exchange fields +coupler_field_names = ( + :T_S, + :z0m_S, + :z0b_S, + :ρ_sfc, + :q_sfc, + :albedo, + :beta, + :F_turb_energy, + :F_turb_moisture, + :F_turb_ρτxz, + :F_turb_ρτyz, + :F_radiative, + :P_liq, + :P_snow, + :F_radiative_TOA, + :P_net, +) +coupler_fields = + NamedTuple{coupler_field_names}(ntuple(i -> ClimaCore.Fields.zeros(boundary_space), length(coupler_field_names))) + +## model simulations +model_sims = (atmos_sim = atmos_sim, ice_sim = ice_sim, land_sim = land_sim, ocean_sim = ocean_sim); + +## dates +dates = (; date = [date], date0 = [date0], date1 = [Dates.firstdayofmonth(date0)], new_month = [false]) + +#= +### Online Diagnostics +User can write custom diagnostics in the `user_diagnostics.jl`. +=# +monthly_3d_diags = init_diagnostics( + (:T, :u, :q_tot, :q_liq_ice), + atmos_sim.domain.center_space; + save = Monthly(), + operations = (; accumulate = TimeMean([Int(0)])), + output_dir = COUPLER_OUTPUT_DIR, + name_tag = "monthly_mean_3d_", +) + +monthly_2d_diags = init_diagnostics( + (:precipitation_rate, :toa_fluxes, :T_sfc, :tubulent_energy_fluxes), + boundary_space; + save = Monthly(), + operations = (; accumulate = TimeMean([Int(0)])), + output_dir = COUPLER_OUTPUT_DIR, + name_tag = "monthly_mean_2d_", +) + +diagnostics = (monthly_3d_diags, monthly_2d_diags) + +#= +## Initialize Conservation Checks +=# +## init conservation info collector +conservation_checks = nothing +if energy_check + @assert( + mode_name[1:10] == "slabplanet" && !CA.is_distributed(ClimaComms.context(boundary_space)), + "Only non-distributed slabplanet allowable for energy_check" + ) + conservation_checks = (; energy = EnergyConservationCheck(model_sims), water = WaterConservationCheck(model_sims)) +end + +dir_paths = (; output = COUPLER_OUTPUT_DIR, artifacts = COUPLER_ARTIFACTS_DIR) +checkpoint_cb = + HourlyCallback(dt = FT(480), func = checkpoint_sims, ref_date = [dates.date[1]], active = hourly_checkpoint) # 20 days +update_firstdayofmonth!_cb = + MonthlyCallback(dt = FT(1), func = update_firstdayofmonth!, ref_date = [dates.date1[1]], active = true) # for BCReader +callbacks = (; checkpoint = checkpoint_cb, update_firstdayofmonth! = update_firstdayofmonth!_cb) diff --git a/calibration/coupler_parse_args.jl b/calibration/coupler_parse_args.jl new file mode 100644 index 0000000000..1aa6121891 --- /dev/null +++ b/calibration/coupler_parse_args.jl @@ -0,0 +1,47 @@ +## coupler defaults +# get component model dictionaries +include("../experiments/AMIP/cli_options.jl") +parsed_args = parse_commandline(argparse_settings()) +config_dict = YAML.load_file("./experiments/amip_coupled/coupler_config.yml") +config_dict = YAML.load_file(joinpath(experiment_dir, "coupler_config.yml")); +config_dict["t_end"] = "150secs"; +config_dict["output_dir"] = output_dir; +config_dict = merge(parsed_args, config_dict) +config_dict_atmos = get_atmos_config(config_dict) + +# merge dictionaries of command line arguments, coupler dictionary and component model dictionaries +# (if there are common keys, the last dictorionary in the `merge` arguments takes precedence) +config_dict = merge(config_dict_atmos, config_dict) + + +## read in some parsed command line arguments +mode_name = config_dict["mode_name"] +run_name = config_dict["run_name"] +energy_check = config_dict["energy_check"] +FT = config_dict["FLOAT_TYPE"] == "Float64" ? Float64 : Float32 +land_sim_name = "bucket" +t_end = Float64(time_to_seconds(config_dict["t_end"])) +t_start = 0.0 +tspan = (t_start, t_end) +Δt_cpl = Float64(config_dict["dt_cpl"]) +saveat = Float64(time_to_seconds(config_dict["dt_save_to_sol"])) +date0 = date = DateTime(config_dict["start_date"], dateformat"yyyymmdd") +mono_surface = config_dict["mono_surface"] +hourly_checkpoint = config_dict["hourly_checkpoint"] +restart_dir = config_dict["restart_dir"] +restart_t = Int(config_dict["restart_t"]) +evolving_ocean = config_dict["evolving_ocean"] +config_dict["print_config_dict"] = false + +## I/O directory setup +COUPLER_OUTPUT_DIR = "/Users/akshaysridhar/Research/Codes/ClimaCoupler.jl/calibration/output/amip/" +mkpath(COUPLER_OUTPUT_DIR) + +REGRID_DIR = joinpath(COUPLER_OUTPUT_DIR, "regrid_tmp/") +mkpath(REGRID_DIR) + +COUPLER_ARTIFACTS_DIR = COUPLER_OUTPUT_DIR * "_artifacts" +isdir(COUPLER_ARTIFACTS_DIR) ? nothing : mkpath(COUPLER_ARTIFACTS_DIR) + +config_dict["print_config_dict"] ? @info(config_dict) : nothing +config_dict_atmos["output_dir"] = COUPLER_OUTPUT_DIR