|
| 1 | +import ClimaAnalysis |
| 2 | +import Dates |
| 3 | +import Test: @test, @testset |
| 4 | + |
| 5 | +include("data_sources.jl") |
| 6 | + |
| 7 | +""" |
| 8 | + test_rmse_thresholds(diagnostics_folder_path, spinup) |
| 9 | +
|
| 10 | +Test that the annual RMSE values for specific variables have not increased |
| 11 | +beyond acceptable thresholds. The variables tested are: |
| 12 | +- pr (precipitation) |
| 13 | +- rsut (top of atmosphere outgoing shortwave radiation) |
| 14 | +- rsutcs (clear-sky top of atmosphere outgoing shortwave radiation) |
| 15 | +
|
| 16 | +The spinup is the number of months to remove from the beginning of the |
| 17 | +simulation. |
| 18 | +
|
| 19 | +More variables can be added by adding the short name and RMSE pair to the |
| 20 | +dictionary returned by `get_rmse_thresholds`. |
| 21 | +
|
| 22 | +If this test fails, it indicates a regression in the model's physics, resulting |
| 23 | +in a higher RMSE. If this increased RMSE is considered acceptable, then the |
| 24 | +thresholds should be updated accordingly. |
| 25 | +""" |
| 26 | +function test_rmse_thresholds(diagnostics_folder_path, spinup) |
| 27 | + sim_var_dict = get_sim_var_dict(diagnostics_folder_path) |
| 28 | + obs_var_dict = get_obs_var_dict() |
| 29 | + rmse_thresholds = get_rmse_thresholds() |
| 30 | + |
| 31 | + sim_vars = (sim_var_dict[short_name]() for short_name in keys(rmse_thresholds)) |
| 32 | + obs_vars = |
| 33 | + (obs_var_dict[ClimaAnalysis.short_name(sim_var)](sim_var.attributes["start_date"]) for sim_var in sim_vars) |
| 34 | + short_names = (ClimaAnalysis.short_name(var) for var in sim_vars) |
| 35 | + |
| 36 | + rmses = map(sim_vars, obs_vars) do sim_var, obs_var |
| 37 | + # Remove first spin_up_months from simulation |
| 38 | + spinup_cutoff = spinup * 31 * 86400.0 |
| 39 | + ClimaAnalysis.times(sim_var)[end] >= spinup_cutoff && |
| 40 | + (sim_var = ClimaAnalysis.window(sim_var, "time", left = spinup_cutoff)) |
| 41 | + |
| 42 | + obs_var = ClimaAnalysis.resampled_as(obs_var, sim_var) |
| 43 | + obs_var = ClimaAnalysis.average_time(obs_var) |
| 44 | + sim_var = ClimaAnalysis.average_time(sim_var) |
| 45 | + |
| 46 | + ClimaAnalysis.global_rmse(sim_var, obs_var) |
| 47 | + end |
| 48 | + |
| 49 | + @testset "RMSE thresholds" begin |
| 50 | + for (short_name, rmse) in zip(short_names, rmses) |
| 51 | + @info "RMSE for $short_name: $rmse" |
| 52 | + @test rmse < rmse_thresholds[short_name] |
| 53 | + end |
| 54 | + end |
| 55 | +end |
| 56 | + |
| 57 | +""" |
| 58 | + get_rmse_thresholds() |
| 59 | +
|
| 60 | +Return a dictionary mapping short names to maximum acceptable RMSE values. |
| 61 | +""" |
| 62 | +function get_rmse_thresholds() |
| 63 | + rmse_thresholds = Dict( |
| 64 | + "pr" => 3.0, # mm/day |
| 65 | + "rsut" => 20.0, # W/m² |
| 66 | + "rsutcs" => 7.0, # W/m² |
| 67 | + ) |
| 68 | + return rmse_thresholds |
| 69 | +end |
| 70 | + |
| 71 | +if abspath(PROGRAM_FILE) == @__FILE__ |
| 72 | + if length(ARGS) != 1 |
| 73 | + error("Usage: julia test_rmses.jl <Filepath to simulation data>") |
| 74 | + end |
| 75 | + leaderboard_base_path = ARGS[begin] |
| 76 | + spinup = 3 |
| 77 | + test_rmse_thresholds(leaderboard_base_path, spinup) |
| 78 | +end |
0 commit comments