From 96646412cebebc5de23eba8907fba137fe2ebdf5 Mon Sep 17 00:00:00 2001 From: AlexisRenchon Date: Wed, 22 May 2024 10:38:27 -0700 Subject: [PATCH] Add a tutorial of a single site perfect model calibration This commit a calibration tutorial, with detailed explanations. We calibrate two parameters, g1 and g0, on latent heat flux data target, using EnsembleKalmanProcesses.jl. We use a single site model, at the ozark site, and calibrate first on simulation output, with the goal of demonstrating the ability to recover the original parameters and demonstrate a simple calibration framework. --- NEWS.md | 1 + docs/Manifest.toml | 237 ++++++++++++++++-- docs/Project.toml | 2 + docs/list_tutorials.jl | 3 + .../calibration/minimal_working_example.jl | 119 +++++++++ .../src/utilities/make_timestepper.jl | 4 +- 6 files changed, 349 insertions(+), 17 deletions(-) create mode 100644 docs/tutorials/calibration/minimal_working_example.jl diff --git a/NEWS.md b/NEWS.md index 9f433e69a9..8531f7397b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ ClimaLand.jl Release Notes main -------- +- Add a tutorial of a single site calibration of a perfect model PR[#621](https://github.com/CliMA/ClimaLand.jl/pull/621) - Add a longrun simulation for the bucket PR[#807](https://github.com/CliMA/ClimaLand.jl/pull/807) - Add ground heat flux to snow-soil model PR[#796](https://github.com/CliMA/ClimaLand.jl/pull/796) - Add snow-soil model PR [#779](https://github.com/CliMA/ClimaLand.jl/pull/779) diff --git a/docs/Manifest.toml b/docs/Manifest.toml index 5da00d8942..ddda7ea4a7 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -2,7 +2,7 @@ julia_version = "1.10.5" manifest_format = "2.0" -project_hash = "6b19e20727d983c28286d493d461a6afa5ff8e8c" +project_hash = "17901eb92a5662b053574516009767eae929e671" [[deps.ADTypes]] git-tree-sha1 = "eea5d80188827b35333801ef97a40c2ed653b081" @@ -14,6 +14,12 @@ weakdeps = ["ChainRulesCore", "EnzymeCore"] ADTypesChainRulesCoreExt = "ChainRulesCore" ADTypesEnzymeCoreExt = "EnzymeCore" +[[deps.AMD]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse_jll"] +git-tree-sha1 = "45a1272e3f809d36431e57ab22703c6896b8908f" +uuid = "14f7f29c-3bd6-536c-9a0b-7339e30b5a3e" +version = "0.5.3" + [[deps.ANSIColoredPrinters]] git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" @@ -106,6 +112,18 @@ version = "2.3.0" uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.1" +[[deps.Arpack]] +deps = ["Arpack_jll", "Libdl", "LinearAlgebra", "Logging"] +git-tree-sha1 = "9b9b347613394885fd1c8c7729bfc60528faa436" +uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" +version = "0.5.4" + +[[deps.Arpack_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg"] +git-tree-sha1 = "5ba6c757e8feccf03a1554dfaf3e26b3cfc7fd5e" +uuid = "68821587-b530-5797-8361-c406ea357684" +version = "3.5.1+1" + [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] git-tree-sha1 = "3640d077b6dafd64ceb8fd5c1ec76f7ca53bcf76" @@ -223,6 +241,12 @@ git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e" uuid = "9718e550-a3fa-408a-8086-8db961cd8217" version = "0.1.1" +[[deps.BenchmarkTools]] +deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "f1dff6729bc61f4d49e140da1af55dcd1ac97b2f" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.5.0" + [[deps.BitFlags]] git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d" uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" @@ -250,6 +274,12 @@ git-tree-sha1 = "19b98ee7e3db3b4eff74c5c9c72bf32144e24f10" uuid = "0b7ba130-8d10-5ba8-a3d6-c5182647fed9" version = "1.21.5+0" +[[deps.Bonito]] +deps = ["Base64", "CodecZlib", "Colors", "Dates", "Deno_jll", "HTTP", "Hyperscript", "LinearAlgebra", "Markdown", "MsgPack", "Observables", "RelocatableFolders", "SHA", "Sockets", "Tables", "ThreadPools", "URIs", "UUIDs", "WidgetsBase"] +git-tree-sha1 = "468078386104a5c678320b14485cd8c370c53a37" +uuid = "824d6782-a2ef-11e9-3a09-e5662e0c26f8" +version = "3.2.1" + [[deps.Bzip2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "9e2a6b69137e6969bab0152632dcb3bc108c8bdd" @@ -379,9 +409,9 @@ version = "0.6.4" [[deps.ClimaCore]] deps = ["Adapt", "BandedMatrices", "BlockArrays", "ClimaComms", "CubedSphere", "DataStructures", "DocStringExtensions", "ForwardDiff", "GaussQuadrature", "GilbertCurves", "HDF5", "InteractiveUtils", "IntervalSets", "KrylovKit", "LinearAlgebra", "MultiBroadcastFusion", "NVTX", "PkgVersion", "RecursiveArrayTools", "RootSolvers", "SparseArrays", "StaticArrays", "Statistics", "Unrolled"] -git-tree-sha1 = "13c2f4e58c78fa54a22705d15e039c99462112ed" +git-tree-sha1 = "6db06e8234dc67c021d636936803300ea710e0c6" uuid = "d414da3d-4745-48bb-8d80-42e94e092884" -version = "0.14.17" +version = "0.14.18" weakdeps = ["CUDA", "Krylov"] [deps.ClimaCore.extensions] @@ -405,6 +435,12 @@ weakdeps = ["CSV", "CUDA", "ClimaParams", "DataFrames", "Flux", "HTTP", "StatsBa CreateParametersExt = "ClimaParams" NeuralSnowExt = ["CSV", "DataFrames", "HTTP", "Flux", "StatsBase", "cuDNN"] +[[deps.ClimaLandSimulations]] +deps = ["ArtifactWrappers", "Bonito", "CairoMakie", "ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaLand", "ClimaParams", "ClimaTimeSteppers", "ClimaUtilities", "DataFrames", "Dates", "DelimitedFiles", "Formatting", "HTTP", "Insolation", "Interpolations", "InverseFunctions", "JSON", "LaTeXStrings", "MutableArithmetics", "NLsolve", "PlotUtils", "RootSolvers", "SciMLBase", "StaticArrays", "Statistics", "StatsBase", "SurfaceFluxes", "Thermodynamics", "Unitful", "UnitfulMoles", "WGLMakie", "cuDNN"] +path = "../lib/ClimaLandSimulations" +uuid = "348a0bd3-1299-4261-8002-d2cd97df6055" +version = "0.1.0" + [[deps.ClimaParams]] deps = ["TOML"] git-tree-sha1 = "b43ca371c435056129295445122ea87fd843b505" @@ -416,17 +452,11 @@ deps = ["ClimaComms", "Colors", "DataStructures", "DiffEqBase", "KernelAbstracti git-tree-sha1 = "dbc1d2c495f118c36a83fa93cd5311fe3a32f615" uuid = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" version = "0.7.38" +weakdeps = ["BenchmarkTools", "CUDA", "OrderedCollections", "PrettyTables", "StatsBase"] [deps.ClimaTimeSteppers.extensions] ClimaTimeSteppersBenchmarkToolsExt = ["CUDA", "BenchmarkTools", "OrderedCollections", "StatsBase", "PrettyTables"] - [deps.ClimaTimeSteppers.weakdeps] - BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" - CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" - OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" - PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" - StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" - [[deps.ClimaUtilities]] deps = ["Artifacts", "Dates"] git-tree-sha1 = "286cf36603ec68538dda4b0333af694fe70dd628" @@ -457,6 +487,12 @@ git-tree-sha1 = "05ba0d07cd4fd8b7a39541e31a7b0254704ea581" uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" version = "0.1.13" +[[deps.CodecBzip2]] +deps = ["Bzip2_jll", "TranscodingStreams"] +git-tree-sha1 = "e7c529cc31bb85b97631b922fa2e6baf246f5905" +uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" +version = "0.8.4" + [[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" @@ -576,6 +612,12 @@ git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" version = "0.6.3" +[[deps.Convex]] +deps = ["AbstractTrees", "BenchmarkTools", "LDLFactorizations", "LinearAlgebra", "MathOptInterface", "OrderedCollections", "SparseArrays", "Test"] +git-tree-sha1 = "dac1878b4996fa56292d2c3bd28f2498b980bb93" +uuid = "f65535da-76fb-5f13-bab9-19810c17039a" +version = "0.16.3" + [[deps.CpuId]] deps = ["Markdown"] git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" @@ -642,6 +684,12 @@ git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" version = "1.9.1" +[[deps.Deno_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "cd6756e833c377e0ce9cd63fb97689a255f12323" +uuid = "04572ae6-984a-583e-9378-9577a1c2574d" +version = "1.33.4+0" + [[deps.DiffEqBase]] deps = ["ArrayInterface", "ConcreteStructs", "DataStructures", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "ForwardDiff", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PreallocationTools", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SciMLStructures", "Setfield", "Static", "StaticArraysCore", "Statistics", "Tricks", "TruncatedStacktraces"] git-tree-sha1 = "ada2a9faba0e365dca3cc456b5eca94cf3887ac3" @@ -694,6 +742,17 @@ git-tree-sha1 = "ef25c513cad08d7ebbed158c91768ae32f308336" uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" version = "0.3.23" +[[deps.Distances]] +deps = ["LinearAlgebra", "Statistics", "StatsAPI"] +git-tree-sha1 = "66c4c81f259586e8f002eacebc177e1fb06363b0" +uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" +version = "0.10.11" +weakdeps = ["ChainRulesCore", "SparseArrays"] + + [deps.Distances.extensions] + DistancesChainRulesCoreExt = "ChainRulesCore" + DistancesSparseArraysExt = "SparseArrays" + [[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" @@ -737,6 +796,12 @@ git-tree-sha1 = "e3290f2d49e661fbd94046d7e3726ffcb2d41053" uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" version = "2.2.4+0" +[[deps.EnsembleKalmanProcesses]] +deps = ["Convex", "Distributions", "DocStringExtensions", "GaussianRandomFields", "Interpolations", "LinearAlgebra", "MathOptInterface", "Optim", "QuadGK", "Random", "RecipesBase", "SCS", "SparseArrays", "Statistics", "StatsBase", "TOML"] +git-tree-sha1 = "00bb94ff704d7aeed9c72d4a2a05d6abf6cb7946" +uuid = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" +version = "2.0.1" + [[deps.EnumX]] git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237" uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" @@ -843,6 +908,12 @@ git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" version = "0.3.2" +[[deps.FastGaussQuadrature]] +deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "fd923962364b645f3719855c88f7074413a6ad92" +uuid = "442a2c76-b920-505d-bb47-c5924d526838" +version = "1.0.2" + [[deps.FastRounding]] deps = ["ErrorfreeArithmetic", "LinearAlgebra"] git-tree-sha1 = "6344aa18f654196be82e62816935225b3b9abe44" @@ -887,6 +958,22 @@ weakdeps = ["PDMats", "SparseArrays", "Statistics"] FillArraysSparseArraysExt = "SparseArrays" FillArraysStatisticsExt = "Statistics" +[[deps.FiniteDiff]] +deps = ["ArrayInterface", "LinearAlgebra", "Setfield", "SparseArrays"] +git-tree-sha1 = "f9219347ebf700e77ca1d48ef84e4a82a6701882" +uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" +version = "2.24.0" + + [deps.FiniteDiff.extensions] + FiniteDiffBandedMatricesExt = "BandedMatrices" + FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" + FiniteDiffStaticArraysExt = "StaticArrays" + + [deps.FiniteDiff.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + [[deps.FixedPointNumbers]] deps = ["Statistics"] git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" @@ -1036,6 +1123,12 @@ git-tree-sha1 = "eb6f1f48aa994f3018cbd029a17863c6535a266d" uuid = "d54b0c1a-921d-58e0-8e36-89d8069c0969" version = "0.5.8" +[[deps.GaussianRandomFields]] +deps = ["Arpack", "FFTW", "FastGaussQuadrature", "LinearAlgebra", "Plots", "Random", "RecipesBase", "SpecialFunctions", "Statistics", "StatsBase"] +git-tree-sha1 = "aaf37fbddc7bca5391677fb5f5082dd29442ca8f" +uuid = "e4b2fa32-6e09-5554-b718-106ed5adafe9" +version = "2.2.5" + [[deps.GeoFormatTypes]] git-tree-sha1 = "59107c179a586f0fe667024c5eb7033e81333271" uuid = "68eda718-8dee-11e9-39e7-89f7f65f511f" @@ -1153,6 +1246,12 @@ git-tree-sha1 = "7c4195be1649ae622304031ed46a2f4df989f1eb" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" version = "0.3.24" +[[deps.Hyperscript]] +deps = ["Test"] +git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4" +uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" +version = "0.0.5" + [[deps.IOCapture]] deps = ["Logging", "Random"] git-tree-sha1 = "b6d6bfdd7ce25b0f9b2f6b3dd56b2673a66c8770" @@ -1410,6 +1509,12 @@ git-tree-sha1 = "170b660facf5df5de098d866564877e119141cbd" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" version = "3.100.2+0" +[[deps.LDLFactorizations]] +deps = ["AMD", "LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "70f582b446a1c3ad82cf87e62b878668beef9d13" +uuid = "40e66cde-538c-5869-a4ad-c39174c6795b" +version = "0.10.1" + [[deps.LERC_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" @@ -1574,6 +1679,12 @@ git-tree-sha1 = "5ee6203157c120d79034c748a2acba45b82b8807" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" version = "2.40.1+0" +[[deps.LineSearches]] +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] +git-tree-sha1 = "e4c3be53733db1051cc15ecf573b1042b3a712a1" +uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +version = "7.3.0" + [[deps.LinearAlgebra]] deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -1583,17 +1694,13 @@ deps = ["FastClosures", "LinearAlgebra", "Printf", "Requires", "SparseArrays", " git-tree-sha1 = "ae5d90280094348c32fda8bc8b5a88bb16514d43" uuid = "5c8ed15e-5a4c-59e4-a42b-c7e8811fb125" version = "2.8.0" +weakdeps = ["CUDA", "ChainRulesCore", "LDLFactorizations"] [deps.LinearOperators.extensions] LinearOperatorsCUDAExt = "CUDA" LinearOperatorsChainRulesCoreExt = "ChainRulesCore" LinearOperatorsLDLFactorizationsExt = "LDLFactorizations" - [deps.LinearOperators.weakdeps] - CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - LDLFactorizations = "40e66cde-538c-5869-a4ad-c39174c6795b" - [[deps.Literate]] deps = ["Base64", "IOCapture", "JSON", "REPL"] git-tree-sha1 = "b9b38448af801760a608b7a7f895f7dcf166f4a5" @@ -1704,6 +1811,12 @@ git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" version = "0.1.2" +[[deps.MathOptInterface]] +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] +git-tree-sha1 = "5b246fca5420ae176d65ed43a2d0ee5897775216" +uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +version = "1.31.2" + [[deps.MathTeXEngine]] deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "UnicodeFun"] git-tree-sha1 = "e1641f32ae592e415e3dbae7f4a188b5316d4b62" @@ -1763,6 +1876,12 @@ version = "0.3.4" uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2023.1.10" +[[deps.MsgPack]] +deps = ["Serialization"] +git-tree-sha1 = "f5db02ae992c260e4826fe78c942954b48e1d9c2" +uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671" +version = "1.2.1" + [[deps.MuladdMacro]] git-tree-sha1 = "cac9cc5499c25554cba55cd3c30543cff5ca4fab" uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" @@ -1777,12 +1896,30 @@ weakdeps = ["Adapt", "CUDA"] [deps.MultiBroadcastFusion.extensions] MultiBroadcastFusionCUDAExt = ["CUDA", "Adapt"] +[[deps.MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "3eba928678787843e504c153a9b8e80d7d73ab17" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.5.0" + [[deps.NCDatasets]] deps = ["CFTime", "CommonDataModel", "DataStructures", "Dates", "DiskArrays", "NetCDF_jll", "NetworkOptions", "Printf"] git-tree-sha1 = "77df6d3708ec0eb3441551e1f20f7503b37c2393" uuid = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" version = "0.14.5" +[[deps.NLSolversBase]] +deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] +git-tree-sha1 = "a0b464d183da839699f4c79e7606d9d186ec172c" +uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" +version = "7.8.3" + +[[deps.NLsolve]] +deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] +git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" +uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +version = "4.5.1" + [[deps.NNlib]] deps = ["Adapt", "Atomix", "ChainRulesCore", "GPUArraysCore", "KernelAbstractions", "LinearAlgebra", "Random", "Statistics"] git-tree-sha1 = "da09a1e112fd75f9af2a5229323f01b56ec96a4c" @@ -1877,6 +2014,12 @@ git-tree-sha1 = "963a3f28a2e65bb87a68033ea4a616002406037d" uuid = "0b1bfda6-eb8a-41d2-88d8-f5af5cad476f" version = "0.2.5" +[[deps.OpenBLAS32_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6065c4cff8fee6c6770b277af45d5082baacdba1" +uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" +version = "0.3.24+0" + [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" @@ -1923,6 +2066,16 @@ git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" version = "0.5.5+0" +[[deps.Optim]] +deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] +git-tree-sha1 = "d9b79c4eed437421ac4285148fcadf42e0700e89" +uuid = "429524aa-4258-5aef-a3af-852621145aeb" +version = "1.9.4" +weakdeps = ["MathOptInterface"] + + [deps.Optim.extensions] + OptimMOIExt = "MathOptInterface" + [[deps.Optimisers]] deps = ["ChainRulesCore", "Functors", "LinearAlgebra", "Random", "Statistics"] git-tree-sha1 = "6572fe0c5b74431aaeb0b18a4aa5ef03c84678be" @@ -2076,6 +2229,12 @@ git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" version = "1.4.3" +[[deps.PositiveFactorizations]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" +uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" +version = "0.2.4" + [[deps.PreallocationTools]] deps = ["Adapt", "ArrayInterface", "ForwardDiff"] git-tree-sha1 = "6c62ce45f268f3f958821a1e5192cf91c75ae89c" @@ -2115,6 +2274,10 @@ version = "2.4.0" deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" +[[deps.Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + [[deps.ProgressLogging]] deps = ["Logging", "SHA", "UUIDs"] git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" @@ -2305,6 +2468,26 @@ git-tree-sha1 = "04c968137612c4a5629fa531334bb81ad5680f00" uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" version = "0.5.13" +[[deps.SCS]] +deps = ["MathOptInterface", "Requires", "SCS_jll", "SparseArrays"] +git-tree-sha1 = "0dfe49eaa058ce905a4199af379b8e411e6126e5" +uuid = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" +version = "2.0.1" + + [deps.SCS.extensions] + SCSSCS_GPU_jllExt = ["SCS_GPU_jll"] + SCSSCS_MKL_jllExt = ["SCS_MKL_jll"] + + [deps.SCS.weakdeps] + SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4" + SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657" + +[[deps.SCS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl", "OpenBLAS32_jll"] +git-tree-sha1 = "668bcf4b25cf992564321ccb70b205f9a7487cfa" +uuid = "f4f2fc5b-1d94-523c-97ea-2ab488bedf4b" +version = "3.2.6+0" + [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" @@ -2651,6 +2834,12 @@ weakdeps = ["ClimaParams"] [deps.Thermodynamics.extensions] CreateParametersExt = "ClimaParams" +[[deps.ThreadPools]] +deps = ["Printf", "RecipesBase", "Statistics"] +git-tree-sha1 = "50cb5f85d5646bc1422aa0238aa5bfca99ca9ae7" +uuid = "b189fb0b-2eb5-4ed4-bc0c-d34c51242431" +version = "2.1.1" + [[deps.ThreadingUtilities]] deps = ["ManualMemory"] git-tree-sha1 = "eda08f7e9818eb53661b3deb74e3159460dfbc27" @@ -2750,6 +2939,12 @@ git-tree-sha1 = "975c354fcd5f7e1ddcc1f1a23e6e091d99e99bc8" uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" version = "1.6.4" +[[deps.UnitfulMoles]] +deps = ["Unitful"] +git-tree-sha1 = "cf6ae3461c3408332de9ac1253dc81600348a994" +uuid = "999f2bd7-36bf-5ba7-9bc1-c9473aa75374" +version = "0.1.1" + [[deps.Unrolled]] deps = ["MacroTools"] git-tree-sha1 = "6cc9d682755680e0f0be87c56392b7651efc2c7b" @@ -2784,6 +2979,12 @@ git-tree-sha1 = "2f0486047a07670caad3a81a075d2e518acc5c59" uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c" version = "1.3.243+0" +[[deps.WGLMakie]] +deps = ["Bonito", "Colors", "FileIO", "FreeTypeAbstraction", "GeometryBasics", "Hyperscript", "LinearAlgebra", "Makie", "Observables", "PNGFiles", "PrecompileTools", "RelocatableFolders", "ShaderAbstractions", "StaticArrays"] +git-tree-sha1 = "c4c38fe321c94a46617d6f437938d8e4a170a8d9" +uuid = "276b4fcb-3e11-5398-bf8b-a0c2d153d008" +version = "0.10.12" + [[deps.Wayland_jll]] deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703" @@ -2802,6 +3003,12 @@ git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" version = "1.4.2" +[[deps.WidgetsBase]] +deps = ["Observables"] +git-tree-sha1 = "30a1d631eb06e8c868c559599f915a62d55c2601" +uuid = "eead4739-05f7-45a1-878c-cee36b57321c" +version = "0.1.4" + [[deps.WoodburyMatrices]] deps = ["LinearAlgebra", "SparseArrays"] git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511" diff --git a/docs/Project.toml b/docs/Project.toml index 6de9a3d015..15d5463fb5 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -5,6 +5,7 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" ClimaLand = "08f4d4ce-cf43-44bb-ad95-9d2d5f413532" +ClimaLandSimulations = "348a0bd3-1299-4261-8002-d2cd97df6055" ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c" ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" @@ -13,6 +14,7 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0" HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" diff --git a/docs/list_tutorials.jl b/docs/list_tutorials.jl index 3cd65f224b..7f54e354c8 100644 --- a/docs/list_tutorials.jl +++ b/docs/list_tutorials.jl @@ -31,6 +31,9 @@ tutorials = [ "standalone/Snow/data_tutorial.jl", ], ], + "Calibrating your ClimaLand model" => [ + "Recover parameters of a previous simulation" => "calibration/minimal_working_example.jl", + ], "For model developers" => [ "Intro to standalone models" => "standalone/Usage/model_tutorial.jl", "Intro to multi-component models" => "standalone/Usage/LSM_single_column_tutorial.jl", diff --git a/docs/tutorials/calibration/minimal_working_example.jl b/docs/tutorials/calibration/minimal_working_example.jl new file mode 100644 index 0000000000..0300d889bd --- /dev/null +++ b/docs/tutorials/calibration/minimal_working_example.jl @@ -0,0 +1,119 @@ +# # Calibration: "perfect model" experiment. + +# In this tutorial, we demonstrate that we can recover the parameters of a previous model run via our calibration framework, +# by calibrating a single site (Ozark) latent heat flux (LHF). + +# First, we run a simulation of Ozark with known values of parameters g1 and g0, which control the stomatal behavior of leaves +# and therefore the canopy transpiration, and retrieve latent heat flux (transpiration expressed in energy). + +# Then, we use EnsembleKalmanProcesses.jl to perform a calibration by giving a prior distribution of the parameters g1 and g0, different from +# the known parameters used in the first "perfect model" run. Our goal is that, after calibraton on the perfect model latent heat flux, the parameters +# will be close to the original ones, therefore demonstrating that we can recover the parameters of the perfect model. + +# To perform this calibration we will need: +# 1. A function returning our model LHF output given the parameters we want to calibrate. +# 2. The "truth" target data, to calibrate on. +# 3. The prior distribution of these parameters. + +# ## Import required packages: +import ClimaLandSimulations.Fluxnet as CLS # to run the model +import EnsembleKalmanProcesses as EKP # to perform the calibration +import Logging +Logging.disable_logging(Logging.Warn); # hide julia warnings + +# ## Write a function returning our model LHF output given the parameters to calibrate +function Ozark_LatentHeatFlux(params) # params is a 2 element Array + g1, g0 = params + sv = CLS.run_fluxnet( + "US-MOz"; + params = CLS.ozark_default_params(; + conductance = CLS.conductance_ozark(; g1 = g1, g0 = g0), + ), + )[1] + inputs = CLS.make_inputs_df("US-MOz")[1] + simulation_output = CLS.make_output_df("US-MOz", sv, inputs) + LHF_soil = + [parent(sv.saveval[k].soil.turbulent_fluxes.lhf)[1] for k in 1:1441] + LHF_canopy = [parent(sv.saveval[k].canopy.energy.lhf)[1] for k in 1:1441] + LHF = LHF_soil + LHF_canopy + return LHF +end; + +# ## "Truth" target data to calibrate on +# Our default for Ozark, g1 in sqrt(Pa). This is equal to 4.46 sqrt(kPa). +LHF_target = Ozark_LatentHeatFlux([141.0, 0.0001]); + +# ## Parameters prior +# We chooae the prior for each parameter distribution to be a Gaussian distribution, +# for example for g1, with a mean of 221 sqrt(Pa) = 7 sqrt(kPa), std of 100 (3 kPa). +# Returns μ=5.3, σ=0.4 (values are transformed). +prior_g1 = EKP.constrained_gaussian("g1", 221, 1000, 0, Inf); +prior_g0 = EKP.constrained_gaussian("g0", 0.00015, 0.01, 0, Inf); +prior = EKP.combine_distributions([prior_g1, prior_g0]); + +# ## Calibration + +# Generate the initial ensemble and set up the ensemble Kalman inversion +N_ensemble = 5 +N_iterations = 5 +Γ = 20.0 * EKP.I # Γ adds random noise. About 10% of output average. +initial_ensemble = EKP.construct_initial_ensemble(prior, N_ensemble); +ensemble_kalman_process = + EKP.EnsembleKalmanProcess(initial_ensemble, LHF_target, Γ, EKP.Inversion()); + +# We are now ready to carry out the inversion. At each iteration, we get the ensemble from the last iteration, apply +# Ozark_LatentHeatFlux(params) to each ensemble member, and apply the Kalman update to the ensemble. + +# Can be multithreaded, see https://clima.github.io/EnsembleKalmanProcesses.jl/dev/parallel_hpc/ +for i in 1:N_iterations # This will run the model N_ensemble * N_iterations times + params_i = EKP.get_ϕ_final(prior, ensemble_kalman_process) + ClimaLand_ens = + hcat([Ozark_LatentHeatFlux(params_i[:, i]) for i in 1:N_ensemble]...) + EKP.update_ensemble!(ensemble_kalman_process, ClimaLand_ens) +end; + +# Done! Here are the parameters: + +final_ensemble = EKP.get_ϕ_final(prior, ensemble_kalman_process) + +# As you can see, they are close to the perfect model parameter values, which were 141 and 0.0001. + +# ## Plotting +using CairoMakie +CairoMakie.activate!() +fig = Figure() +ax = Axis(fig[1, 1], ylabel = "Latent heat flux (W m^-2)", xlabel = "Half-hour") +range = 1:1:length(LHF_target) + +l1 = lines!(ax, range, LHF_target, color = :black, linewidth = 4) +l2 = [ + lines!( + ax, + range, + Ozark_LatentHeatFlux( + EKP.get_ϕ(prior, ensemble_kalman_process, 1)[:, i], + ), + color = :red, + ) for i in 1:N_ensemble +][1] +l3 = [ + lines!( + ax, + range, + Ozark_LatentHeatFlux(final_ensemble[:, i]), + color = :blue, + ) for i in 1:N_ensemble +][1] +axislegend( + ax, + [l1, l2, l3], + ["Perfect model (target)", "Before calibration", "After calibration"], +) +xlims!(ax, (0, 48)) +save("fig.png", fig); +# ![](fig.png) + +# Note that the figure contains one black line, and 5 red and blue lines, +# drawn from the prior and posterior distrubution of parameters. +# The EKI process is an interative process that, when successful, leads to +# convergence in the ensemble members to a small region of parameter space. diff --git a/lib/ClimaLandSimulations/src/utilities/make_timestepper.jl b/lib/ClimaLandSimulations/src/utilities/make_timestepper.jl index 72a9902735..1da9ed3d97 100644 --- a/lib/ClimaLandSimulations/src/utilities/make_timestepper.jl +++ b/lib/ClimaLandSimulations/src/utilities/make_timestepper.jl @@ -23,11 +23,11 @@ function make_timestepper( site_setup_out; N_spinup_days = 30, N_days_sim = 30, - timestepper = CTS.ARS343(), + timestepper = CTS.ARS111(), ode_algo = CTS.IMEXAlgorithm( timestepper, CTS.NewtonsMethod( - max_iters = 1, + max_iters = 3, update_j = CTS.UpdateEvery(CTS.NewNewtonIteration), ), ),