From 897eeecdc5ce59a5f3d594de84f23ab86bc13308 Mon Sep 17 00:00:00 2001 From: nefrathenrici Date: Mon, 30 Sep 2024 12:26:56 -0700 Subject: [PATCH] Bump compat for EKP, JLD2 --- .buildkite/clima_server_test/pipeline.yml | 2 +- .buildkite/pipeline.yml | 2 +- Project.toml | 6 ++--- docs/Project.toml | 2 -- .../Manifest.toml | 4 +-- test/Project.toml | 3 --- test/emulate_sample.jl | 23 +++++++++--------- test/pure_julia_e2e.jl | 10 ++++---- test/test_case_inputs/eki_test.jld2 | Bin 29854 -> 0 bytes 9 files changed, 24 insertions(+), 28 deletions(-) delete mode 100644 test/test_case_inputs/eki_test.jld2 diff --git a/.buildkite/clima_server_test/pipeline.yml b/.buildkite/clima_server_test/pipeline.yml index 02faaaad..90c24eb1 100644 --- a/.buildkite/clima_server_test/pipeline.yml +++ b/.buildkite/clima_server_test/pipeline.yml @@ -17,7 +17,7 @@ steps: key: "init_cpu_env" command: - echo "--- Instantiate SurfaceFluxes calibration project" - - julia --project=experiments/surface_fluxes_perfect_model -e 'using Pkg; Pkg.develop(;path="."); Pkg.precompile()' + - julia --project=experiments/surface_fluxes_perfect_model -e 'using Pkg; Pkg.precompile()' - wait - label: "SurfaceFluxes perfect model calibration" diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 7288490b..085008e6 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -13,7 +13,7 @@ steps: key: "init_cpu_env" command: - echo "--- Instantiate SurfaceFluxes calibration project" - - julia --project=experiments/surface_fluxes_perfect_model -e 'using Pkg; Pkg.develop(;path="."); Pkg.precompile()' + - julia --project=experiments/surface_fluxes_perfect_model -e 'using Pkg; Pkg.precompile()' - wait - label: "SurfaceFluxes perfect model calibration" diff --git a/Project.toml b/Project.toml index 95d0fe19..bbadcc44 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ClimaCalibrate" uuid = "4347a170-ebd6-470c-89d3-5c705c0cacc2" authors = ["Climate Modeling Alliance"] -version = "0.0.3" +version = "0.0.4" [deps] Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" @@ -22,8 +22,8 @@ CESExt = "CalibrateEmulateSample" CalibrateEmulateSample = "0.5" Distributed = "1" Distributions = "0.25" -EnsembleKalmanProcesses = "1" -JLD2 = "0.4" +EnsembleKalmanProcesses = "1, 2" +JLD2 = "0.4, 0.5" Random = "1" TOML = "1" YAML = "0.4" diff --git a/docs/Project.toml b/docs/Project.toml index dfb9f086..0be233e7 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,8 +1,6 @@ [deps] ClimaCalibrate = "4347a170-ebd6-470c-89d3-5c705c0cacc2" -CalibrateEmulateSample = "95e48a1f-0bec-4818-9538-3db4340308e3" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244" EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" - diff --git a/experiments/surface_fluxes_perfect_model/Manifest.toml b/experiments/surface_fluxes_perfect_model/Manifest.toml index f6e2cc6e..29b8841c 100644 --- a/experiments/surface_fluxes_perfect_model/Manifest.toml +++ b/experiments/surface_fluxes_perfect_model/Manifest.toml @@ -183,10 +183,10 @@ weakdeps = ["SparseArrays"] ChainRulesCoreSparseArraysExt = "SparseArrays" [[deps.ClimaCalibrate]] -deps = ["Distributions", "EnsembleKalmanProcesses", "JLD2", "Random", "TOML", "YAML"] +deps = ["Distributed", "Distributions", "EnsembleKalmanProcesses", "JLD2", "Random", "TOML", "YAML"] path = "../.." uuid = "4347a170-ebd6-470c-89d3-5c705c0cacc2" -version = "0.0.2" +version = "0.0.4" [deps.ClimaCalibrate.extensions] CESExt = "CalibrateEmulateSample" diff --git a/test/Project.toml b/test/Project.toml index 895336b4..be47dac3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -11,6 +11,3 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[compat] -EnsembleKalmanProcesses = "< 1.1.6" diff --git a/test/emulate_sample.jl b/test/emulate_sample.jl index 84b8e6c9..beae2365 100644 --- a/test/emulate_sample.jl +++ b/test/emulate_sample.jl @@ -13,23 +13,24 @@ import ClimaCalibrate as CAL @testset "Emulate and Sample tests" begin y_obs = [261.5493] y_noise_cov = [0.02619;;] - ekp = JLD2.load_object(joinpath("test_case_inputs", "eki_test.jld2")) - init_params = [EKP.get_u_final(ekp)[1]] - + init_params = [4.1928479297330306] prior_path = joinpath("test_case_inputs", "sphere_hs_rhoe.toml") - prior = CAL.get_prior(prior_path) - input_output_pairs = CAL.get_input_output_pairs(ekp) - - @test input_output_pairs.inputs.stored_data == - hcat([ekp.u[i].stored_data for i in 1:(length(ekp.u) - 1)]...) - @test input_output_pairs.outputs.stored_data == - hcat([ekp.g[i].stored_data for i in 1:length(ekp.g)]...) + # Sample data + input_output_pairs = EKP.DataContainers.PairedDataContainer( + # Parameter values + EKP.DataContainers.DataContainer( + [5.05038266176406 4.49801357065531 4.625175276903062 4.497648108467572 5.049462857273453 5.470189766650297 4.945930038719361 4.694723166004012 4.936413547464582 4.618148508404665 4.041965675651152 4.121910454258125 4.077521148463588 4.119541027138994 4.043163793654862 4.21813038496636 4.0249164182511485 4.0292005257357895 4.026103892229238 4.0880286181841585 4.1861745817794205 4.20048531589655 4.187992300461601 4.19870114405988 4.209232786450678 4.191675948737242 4.187239734960614 4.186875241183792 4.189230960868622 4.19193208121736], + ), + # Observation map output values + EKP.DataContainers.DataContainer( + [229.28858947753906 249.54794311523438 244.09906005859375 249.78701782226562 229.31289672851562 221.62457275390625 232.126953125 240.37799072265625 232.520751953125 244.3943634033203 266.1481628417969 263.6910705566406 265.0572509765625 263.7556457519531 266.0339660644531 260.7401428222656 266.4653015136719 266.42529296875 266.4148864746094 264.5828552246094 261.7020568847656 261.2137451171875 261.7446594238281 261.2926025390625 260.7995910644531 261.4737548828125 261.597900390625 261.69354248046875 261.52777099609375 261.3088684082031], + ), + ) emulator = CAL.gp_emulator(input_output_pairs, y_noise_cov) - (; mcmc, chain) = CAL.sample(emulator, y_obs, prior, init_params) @test mean(chain.value[1:100000]) ≈ 4.19035299 rtol = 0.0001 diff --git a/test/pure_julia_e2e.jl b/test/pure_julia_e2e.jl index 12718e26..3c10a19b 100644 --- a/test/pure_julia_e2e.jl +++ b/test/pure_julia_e2e.jl @@ -19,7 +19,7 @@ import JLD2 output_file = "model_output.jld2" prior = constrained_gaussian("test_param", 10, 5, 0, Inf) n_iterations = 1 -ensemble_size = 10 +ensemble_size = 20 observations = [20.0] noise = [0.01;;] output_dir = joinpath("test", "e2e_test_output") @@ -34,6 +34,8 @@ experiment_config = ExperimentConfig( ) # Model interface +# This "model" just samples parameters and returns them, we are checking that the +# results are reproducible. function set_up_forward_model( member, iteration, @@ -55,9 +57,7 @@ function run_forward_model(config) JLD2.save_object(joinpath(config["output_dir"], output_file), output) end -# Observation map function observation_map(iteration) - (; ensemble_size) = experiment_config dims = 1 G_ensemble = Array{Float64}(undef, dims..., ensemble_size) @@ -76,8 +76,8 @@ ekp = calibrate(JuliaBackend, experiment_config) @testset "Test end-to-end calibration" begin parameter_values = [EKP.get_ϕ_mean(prior, ekp, it) for it in 1:(n_iterations + 1)] - @test parameter_values[1][1] ≈ 9.779 rtol = 0.01 - @test parameter_values[end][1] ≈ 19.63 rtol = 0.01 + @test parameter_values[1][1] ≈ 9.215 rtol = 0.01 + @test parameter_values[end][1] ≈ 20.224 rtol = 0.01 end rm(output_dir; recursive = true) diff --git a/test/test_case_inputs/eki_test.jld2 b/test/test_case_inputs/eki_test.jld2 deleted file mode 100644 index 924eb89e311a344a11e8405a273fc380dc7d9f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29854 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