|
| 1 | +function bucket_integrator(; |
| 2 | + t0 = 0.0, |
| 3 | + tf = 86400.0, |
| 4 | + dt = 450.0, |
| 5 | + stepper = CTS.ARS111(), |
| 6 | + dlat_degrees = 1.0, |
| 7 | + FT = Float32, |
| 8 | + n_vertical_elements = 15, |
| 9 | + diagnostics = false, |
| 10 | + update_drivers = false, |
| 11 | + info = true, |
| 12 | +) |
| 13 | + context = ClimaComms.context() |
| 14 | + ClimaComms.init(context) |
| 15 | + device = ClimaComms.device() |
| 16 | + info && @info "Running on $device" |
| 17 | + |
| 18 | + n_horizontal_elements, effective_resolution, num_columns = |
| 19 | + resolution(; dlat_degrees) |
| 20 | + info && |
| 21 | + @info "Running with $(n_horizontal_elements) horizontal elements ($(round(effective_resolution, sigdigits = 2)) degrees, $num_columns columns)" |
| 22 | + |
| 23 | + earth_param_set = LP.LandParameters(FT) |
| 24 | + radius = FT(6378.1e3) |
| 25 | + depth = FT(3.5) |
| 26 | + domain = ClimaLand.Domains.SphericalShell(; |
| 27 | + radius = radius, |
| 28 | + depth = depth, |
| 29 | + nelements = (n_horizontal_elements, n_vertical_elements), |
| 30 | + npolynomial = 0, |
| 31 | + dz_tuple = FT.((1.0, 0.05)), |
| 32 | + ) |
| 33 | + surface_space = domain.space.surface |
| 34 | + subsurface_space = domain.space.subsurface |
| 35 | + |
| 36 | + start_date = DateTime(2008) |
| 37 | + time_interpolation_method = LinearInterpolation(Throw()) |
| 38 | + # Forcing data |
| 39 | + era5_artifact_path = |
| 40 | + ClimaLand.Artifacts.era5_land_forcing_data2008_folder_path(; context) |
| 41 | + era5_ncdata_path = joinpath(era5_artifact_path, "era5_2008_1.0x1.0.nc") |
| 42 | + atmos, radiation = ClimaLand.prescribed_forcing_era5( |
| 43 | + era5_ncdata_path, |
| 44 | + surface_space, |
| 45 | + start_date, |
| 46 | + earth_param_set, |
| 47 | + FT; |
| 48 | + time_interpolation_method = time_interpolation_method, |
| 49 | + regridder_type = :InterpolationsRegridder, |
| 50 | + ) |
| 51 | + # Set up parameters |
| 52 | + σS_c = FT(0.2) |
| 53 | + W_f = FT(0.2) |
| 54 | + z_0m = FT(1e-3) |
| 55 | + z_0b = FT(1e-3) |
| 56 | + κ_soil = FT(1.5) |
| 57 | + ρc_soil = FT(2e6) |
| 58 | + τc = FT(dt) |
| 59 | + α_snow = FT(0.8) |
| 60 | + albedo = PrescribedBaregroundAlbedo{FT}(α_snow, surface_space) |
| 61 | + bucket_parameters = BucketModelParameters(FT; albedo, z_0m, z_0b, τc) |
| 62 | + bucket = BucketModel( |
| 63 | + parameters = bucket_parameters, |
| 64 | + domain = domain, |
| 65 | + atmosphere = atmos, |
| 66 | + radiation = radiation, |
| 67 | + ) |
| 68 | + |
| 69 | + temp_anomaly_amip(coord) = 40 * cosd(coord.lat)^4 |
| 70 | + Y, p, cds = initialize(bucket) |
| 71 | + # Set temperature IC including anomaly, based on atmospheric setup |
| 72 | + T_sfc_0 = FT(271.0) |
| 73 | + @. Y.bucket.T = T_sfc_0 + temp_anomaly_amip(cds.subsurface) |
| 74 | + Y.bucket.W .= FT(0.15) |
| 75 | + Y.bucket.Ws .= FT(0.0) |
| 76 | + Y.bucket.σS .= FT(0.0) |
| 77 | + |
| 78 | + set_initial_cache! = make_set_initial_cache(bucket) |
| 79 | + set_initial_cache!(p, Y, t0) |
| 80 | + exp_tendency! = make_exp_tendency(bucket) |
| 81 | + |
| 82 | + callbacks = tuple() |
| 83 | + |
| 84 | + if info |
| 85 | + walltime_info = WallTimeInfo() |
| 86 | + every10steps(u, t, integrator) = mod(integrator.step, 10) == 0 |
| 87 | + report = let wt = walltime_info |
| 88 | + (integrator) -> report_walltime(wt, integrator) |
| 89 | + end |
| 90 | + report_cb = SciMLBase.DiscreteCallback(every10steps, report) |
| 91 | + callbacks = (callbacks..., report_cb) |
| 92 | + end |
| 93 | + |
| 94 | + if diagnostics |
| 95 | + outdir = mktempdir(pwd()) |
| 96 | + info && @info "Output directory: $outdir" |
| 97 | + nc_writer = ClimaDiagnostics.Writers.NetCDFWriter( |
| 98 | + subsurface_space, |
| 99 | + outdir; |
| 100 | + start_date, |
| 101 | + ) |
| 102 | + |
| 103 | + diags = ClimaLand.default_diagnostics( |
| 104 | + land, |
| 105 | + start_date; |
| 106 | + output_writer = nc_writer, |
| 107 | + output_vars = :short, |
| 108 | + average_period = :monthly, |
| 109 | + ) |
| 110 | + |
| 111 | + diagnostic_handler = |
| 112 | + ClimaDiagnostics.DiagnosticsHandler(diags, Y, p, t0; dt = dt) |
| 113 | + |
| 114 | + diag_cb = ClimaDiagnostics.DiagnosticsCallback(diagnostic_handler) |
| 115 | + callbacks = (callbacks..., diag_cb) |
| 116 | + end |
| 117 | + |
| 118 | + if update_drivers |
| 119 | + info && @info "Updating drivers every 3 hours" |
| 120 | + updateat = Array(t0:(3600 * 3):tf) |
| 121 | + drivers = ClimaLand.get_drivers(bucket) |
| 122 | + updatefunc = ClimaLand.make_update_drivers(drivers) |
| 123 | + driver_cb = ClimaLand.DriverUpdateCallback(updateat, updatefunc) |
| 124 | + callbacks = (callbacks..., driver_cb) |
| 125 | + end |
| 126 | + |
| 127 | + ode_algo = CTS.IMEXAlgorithm( |
| 128 | + stepper, |
| 129 | + CTS.NewtonsMethod( |
| 130 | + max_iters = 3, |
| 131 | + update_j = CTS.UpdateEvery(CTS.NewNewtonIteration), |
| 132 | + ), |
| 133 | + ) |
| 134 | + prob = SciMLBase.ODEProblem( |
| 135 | + CTS.ClimaODEFunction(T_exp! = exp_tendency!, dss! = ClimaLand.dss!), |
| 136 | + Y, |
| 137 | + (t0, tf), |
| 138 | + p, |
| 139 | + ) |
| 140 | + callback = SciMLBase.CallbackSet(callbacks...) |
| 141 | + |
| 142 | + integrator = SciMLBase.init(prob, ode_algo; dt, callback) |
| 143 | + return integrator |
| 144 | +end |
0 commit comments