diff --git a/docs/Manifest-v1.11.toml b/docs/Manifest-v1.11.toml index b7413bbcda..516c703697 100644 --- a/docs/Manifest-v1.11.toml +++ b/docs/Manifest-v1.11.toml @@ -2,12 +2,12 @@ julia_version = "1.11.6" manifest_format = "2.0" -project_hash = "53eaaa3557cec5df76ee8d7b9a7b00e0b499fc9f" +project_hash = "dc918b2fbc2f4c5c8339bef498fec07d53107151" [[deps.ADTypes]] -git-tree-sha1 = "7927b9af540ee964cc5d1b73293f1eb0b761a3a1" +git-tree-sha1 = "60665b326b75db6517939d0e1875850bc4a54368" uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -version = "1.16.0" +version = "1.17.0" weakdeps = ["ChainRulesCore", "ConstructionBase", "EnzymeCore"] [deps.ADTypes.extensions] @@ -163,9 +163,9 @@ version = "1.11.0" [[deps.Atomix]] deps = ["UnsafeAtomics"] -git-tree-sha1 = "b5bb4dc6248fde467be2a863eb8452993e74d402" +git-tree-sha1 = "29bb0eb6f578a587a49da16564705968667f5fa8" uuid = "a9b6321e-bd34-4604-b9c9-b65b8de01458" -version = "1.1.1" +version = "1.1.2" [deps.Atomix.extensions] AtomixCUDAExt = "CUDA" @@ -363,14 +363,25 @@ version = "1.72.5" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "06ee8d1aa558d2833aa799f6f0b31b30cada405f" +git-tree-sha1 = "e4c6a16e77171a5f5e25e9646617ab1c276c5607" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.25.2" +version = "1.26.0" weakdeps = ["SparseArrays"] [deps.ChainRulesCore.extensions] ChainRulesCoreSparseArraysExt = "SparseArrays" +[[deps.ClimaAnalysis]] +deps = ["Artifacts", "Dates", "Interpolations", "NCDatasets", "NaNStatistics", "OrderedCollections", "Reexport", "Statistics", "Unitful"] +git-tree-sha1 = "2488781691ad571f17dc40b02e5380296a80cd2e" +uuid = "29b5916a-a76c-4e73-9657-3c8fd22e65e6" +version = "0.5.19" +weakdeps = ["GeoMakie", "Makie"] + + [deps.ClimaAnalysis.extensions] + ClimaAnalysisGeoMakieExt = "GeoMakie" + ClimaAnalysisMakieExt = "Makie" + [[deps.ClimaComms]] deps = ["Adapt", "Logging", "LoggingExtras"] git-tree-sha1 = "f3961fa943c1bbbc376af910cb98db67084dc642" @@ -410,26 +421,13 @@ deps = ["ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaParams", "ClimaTime path = ".." uuid = "08f4d4ce-cf43-44bb-ad95-9d2d5f413532" version = "0.18.0" +weakdeps = ["BSON", "CSV", "CairoMakie", "ClimaAnalysis", "DataFrames", "DelimitedFiles", "Flux", "GeoMakie", "HTTP", "Poppler_jll", "Printf", "StatsBase"] [deps.ClimaLand.extensions] FluxnetSimulationsExt = ["DelimitedFiles"] LandSimulationVisualizationExt = ["CairoMakie", "ClimaAnalysis", "GeoMakie", "Poppler_jll", "Printf", "StatsBase"] NeuralSnowExt = ["CSV", "DataFrames", "HTTP", "Flux", "StatsBase", "BSON"] - [deps.ClimaLand.weakdeps] - BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" - CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" - CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" - ClimaAnalysis = "29b5916a-a76c-4e73-9657-3c8fd22e65e6" - DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" - DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" - Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" - GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" - HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" - Poppler_jll = "9c32591e-4766-534b-9725-b71a8799265b" - Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" - StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" - [[deps.ClimaLandSimulations]] deps = ["Bonito", "CairoMakie", "ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaLand", "ClimaParams", "ClimaTimeSteppers", "ClimaUtilities", "DataFrames", "Dates", "DelimitedFiles", "Format", "HTTP", "Insolation", "Interpolations", "InverseFunctions", "JSON", "LaTeXStrings", "MutableArithmetics", "NLsolve", "PlotUtils", "RootSolvers", "SciMLBase", "StaticArrays", "Statistics", "StatsBase", "SurfaceFluxes", "Thermodynamics", "Unitful", "UnitfulMoles", "WGLMakie"] path = "../lib/ClimaLandSimulations" @@ -616,6 +614,12 @@ git-tree-sha1 = "dec769959be3af9ba94970b1f14b31c196b0fb9e" uuid = "f65535da-76fb-5f13-bab9-19810c17039a" version = "0.16.4" +[[deps.CoordinateTransformations]] +deps = ["LinearAlgebra", "StaticArrays"] +git-tree-sha1 = "a692f5e257d332de1e554e4566a4e5a8a72de2b2" +uuid = "150eb455-5306-5404-9cee-2592286d6298" +version = "0.6.4" + [[deps.CpuId]] deps = ["Markdown"] git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" @@ -691,9 +695,9 @@ version = "1.33.4+0" [[deps.DiffEqBase]] deps = ["ArrayInterface", "ConcreteStructs", "DataStructures", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SciMLStructures", "Setfield", "Static", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "TruncatedStacktraces"] -git-tree-sha1 = "803ea1b97e06d9f4b0da348589d451c5a456e9f4" +git-tree-sha1 = "6fecfae8b2d9983e939378c8eacff6562e8a2567" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.182.1" +version = "6.183.0" [deps.DiffEqBase.extensions] DiffEqBaseCUDAExt = "CUDA" @@ -793,9 +797,9 @@ version = "0.7.4" [[deps.DiskArrays]] deps = ["ConstructionBase", "LRUCache", "Mmap", "OffsetArrays"] -git-tree-sha1 = "16d93ff95ecc421463eaefd694e6746bb1c0919e" +git-tree-sha1 = "bfde0790720fcac006a3d62149309a685fc3aa13" uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" -version = "0.4.14" +version = "0.4.15" [[deps.Distances]] deps = ["LinearAlgebra", "Statistics", "StatsAPI"] @@ -1035,9 +1039,9 @@ weakdeps = ["PDMats", "SparseArrays", "Statistics"] [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Setfield"] -git-tree-sha1 = "f089ab1f834470c525562030c8cfde4025d5e915" +git-tree-sha1 = "d84e026183bb3fc764110ae98792c2e004f8c240" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.27.0" +version = "2.28.0" [deps.FiniteDiff.extensions] FiniteDiffBandedMatricesExt = "BandedMatrices" @@ -1199,12 +1203,72 @@ git-tree-sha1 = "294e99f19869d0b0cb71aef92f19d03649d028d5" uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" version = "1.4.1" +[[deps.GeoInterfaceMakie]] +deps = ["GeoInterface", "GeometryBasics", "MakieCore"] +git-tree-sha1 = "378afe561ba990392146e1a7abd472c7db7f1479" +uuid = "0edc0954-3250-4c18-859d-ec71c1660c08" +version = "0.1.9" + +[[deps.GeoInterfaceRecipes]] +deps = ["GeoInterface", "RecipesBase"] +git-tree-sha1 = "fb1156076f24f1dfee45b3feadb31d05730a49ac" +uuid = "0329782f-3d07-4b52-b9f6-d3137cf03c7a" +version = "1.0.2" + +[[deps.GeoJSON]] +deps = ["Extents", "GeoFormatTypes", "GeoInterface", "GeoInterfaceMakie", "GeoInterfaceRecipes", "JSON3", "StructTypes", "Tables"] +git-tree-sha1 = "c803640368acf4ae02bb5a69a986cecc4a5cb984" +uuid = "61d90e0f-e114-555e-ac52-39dfb47a3ef9" +version = "0.8.3" +weakdeps = ["Makie"] + + [deps.GeoJSON.extensions] + GeoJSONMakieExt = "Makie" + +[[deps.GeoMakie]] +deps = ["Colors", "CoordinateTransformations", "Downloads", "GeoFormatTypes", "GeoInterface", "GeoInterfaceMakie", "GeoJSON", "Geodesy", "GeometryBasics", "GeometryOps", "ImageIO", "LinearAlgebra", "Makie", "NaturalEarth", "Proj", "Reexport", "Statistics", "StructArrays"] +git-tree-sha1 = "2db1d309af35a1ad440e75b9275e4b3b4715ed39" +uuid = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" +version = "0.7.12" + +[[deps.Geodesy]] +deps = ["CoordinateTransformations", "Dates", "LinearAlgebra", "StaticArrays"] +git-tree-sha1 = "ed98a4429bf0a033ccc5e036120181dd52f06d31" +uuid = "0ef565a4-170c-5f04-8de2-149903a85f3d" +version = "1.1.0" + [[deps.GeometryBasics]] deps = ["EarCut_jll", "Extents", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] git-tree-sha1 = "b62f2b2d76cee0d61a2ef2b3118cd2a3215d3134" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" version = "0.4.11" +[[deps.GeometryOps]] +deps = ["AbstractTrees", "AdaptivePredicates", "CoordinateTransformations", "DataAPI", "DelaunayTriangulation", "ExactPredicates", "Extents", "GeoFormatTypes", "GeoInterface", "GeometryOpsCore", "LinearAlgebra", "SortTileRecursiveTree", "StaticArrays", "Statistics", "Tables"] +git-tree-sha1 = "1b7fef8228b2fb471548d6a1e1b644056b536970" +uuid = "3251bfac-6a57-4b6d-aa61-ac1fef2975ab" +version = "0.1.26" + + [deps.GeometryOps.extensions] + GeometryOpsDataFramesExt = "DataFrames" + GeometryOpsFlexiJoinsExt = "FlexiJoins" + GeometryOpsLibGEOSExt = "LibGEOS" + GeometryOpsProjExt = "Proj" + GeometryOpsTGGeometryExt = "TGGeometry" + + [deps.GeometryOps.weakdeps] + DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" + FlexiJoins = "e37f2e79-19fa-4eb7-8510-b63b51fe0a37" + LibGEOS = "a90b1aa1-3769-5649-ba7e-abc5a9d163eb" + Proj = "c94c279d-25a6-4763-9509-64d165bea63e" + TGGeometry = "d7e755d2-3c95-4bcf-9b3c-79ab1a78647b" + +[[deps.GeometryOpsCore]] +deps = ["DataAPI", "GeoInterface", "StableTasks", "Tables"] +git-tree-sha1 = "69fc98947b06f8ac4279cf5bf8810373fe042be4" +uuid = "05efe853-fabf-41c8-927e-7063c8b9f013" +version = "0.1.7" + [[deps.GettextRuntime_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll"] git-tree-sha1 = "45288942190db7c5f760f59c04495064eedf9340" @@ -1657,9 +1721,9 @@ version = "1.4.0" [[deps.Latexify]] deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] -git-tree-sha1 = "4f34eaabe49ecb3fb0d58d6015e32fd31a733199" +git-tree-sha1 = "52e1296ebbde0db845b356abbbe67fb82a0a116c" uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.16.8" +version = "0.16.9" [deps.Latexify.extensions] DataFramesExt = "DataFrames" @@ -1803,6 +1867,12 @@ git-tree-sha1 = "da046be6d63304f7ba9c1bb04820fb306ba1ab12" uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" version = "2.20.1" +[[deps.LittleCMS_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll"] +git-tree-sha1 = "fa7fd067dca76cadd880f1ca937b4f387975a9f5" +uuid = "d3a379c0-f9a3-5b72-a4c0-6bf4d2e8af0f" +version = "2.16.0+0" + [[deps.LogExpFunctions]] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" @@ -2121,12 +2191,34 @@ git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.1.3" +[[deps.NaNStatistics]] +deps = ["PrecompileTools", "Static", "StaticArrayInterface"] +git-tree-sha1 = "473b6054828a4f238d3a8fd71e7ef24d5e68337a" +uuid = "b946abbf-3ea7-4610-9019-9858bfdeaf2d" +version = "0.6.54" + + [deps.NaNStatistics.extensions] + NaNStatisticsDimensionalDataExt = "DimensionalData" + NaNStatisticsHwlocExt = "Hwloc" + NaNStatisticsUnitfulExt = "Unitful" + + [deps.NaNStatistics.weakdeps] + DimensionalData = "0703355e-b756-11e9-17c0-8b28908087d0" + Hwloc = "0e44f5e4-bd66-52a0-8798-143a42290a1d" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + [[deps.NameResolution]] deps = ["PrettyPrint"] git-tree-sha1 = "1a0fa0e9613f46c9b8c11eee38ebb4f590013c5e" uuid = "71a1bf82-56d0-4bbc-8a3c-48b961074391" version = "0.1.5" +[[deps.NaturalEarth]] +deps = ["Downloads", "GeoJSON", "Pkg", "Scratch"] +git-tree-sha1 = "3f75210ac08fe4496a55f9694b95859c40b8eaea" +uuid = "436b0209-26ab-4e65-94a9-6526d86fea76" +version = "0.1.0" + [[deps.NetCDF_jll]] deps = ["Artifacts", "Blosc_jll", "Bzip2_jll", "HDF5_jll", "JLLWrappers", "LazyArtifacts", "LibCURL_jll", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "TOML", "XML2_jll", "Zlib_jll", "Zstd_jll", "libaec_jll", "libzip_jll"] git-tree-sha1 = "d574803b6055116af212434460adf654ce98e345" @@ -2198,6 +2290,12 @@ git-tree-sha1 = "8292dd5c8a38257111ada2174000a33745b06d4e" uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" version = "3.2.4+0" +[[deps.OpenJpeg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libtiff_jll", "LittleCMS_jll", "libpng_jll"] +git-tree-sha1 = "7dc7028a10d1408e9103c0a77da19fdedce4de6c" +uuid = "643b3616-a352-519d-856d-80112ee9badc" +version = "2.5.4+0" + [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" @@ -2287,6 +2385,12 @@ git-tree-sha1 = "cf181f0b1e6a18dfeb0ee8acc4a9d1672499626c" uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" version = "0.4.4" +[[deps.PROJ_jll]] +deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "Libtiff_jll", "SQLite_jll"] +git-tree-sha1 = "29d4224ba271e3b679cca03a8fd72e271525c113" +uuid = "58948b4f-47e0-5654-a9ad-f609743f8632" +version = "902.600.200+0" + [[deps.PackageExtensionCompat]] git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518" uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930" @@ -2358,9 +2462,9 @@ version = "1.4.3" [[deps.Plots]] deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "TOML", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] -git-tree-sha1 = "3db9167c618b290a05d4345ca70de6d95304a32a" +git-tree-sha1 = "9a9216c0cf706cb2cc58fd194878180e3e51e8c0" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.40.17" +version = "1.40.18" [deps.Plots.extensions] FileIOExt = "FileIO" @@ -2399,6 +2503,12 @@ git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" version = "1.4.3" +[[deps.Poppler_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "JpegTurbo_jll", "LibCURL_jll", "Libdl", "Libtiff_jll", "OpenJpeg_jll", "libpng_jll"] +git-tree-sha1 = "7dbfb7f61c3aa5def7b7dad3fa344c1c2858a83b" +uuid = "9c32591e-4766-534b-9725-b71a8799265b" +version = "24.6.0+0" + [[deps.PositiveFactorizations]] deps = ["LinearAlgebra"] git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" @@ -2413,9 +2523,9 @@ version = "1.2.1" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.3" +version = "1.5.0" [[deps.PrettyPrint]] git-tree-sha1 = "632eb4abab3449ab30c5e1afaa874f0b98b586e4" @@ -2449,6 +2559,12 @@ git-tree-sha1 = "13c5103482a8ed1536a54c08d0e742ae3dca2d42" uuid = "92933f4c-e287-5a05-a399-4b506db050ca" version = "1.10.4" +[[deps.Proj]] +deps = ["CEnum", "CoordinateTransformations", "GeoFormatTypes", "GeoInterface", "NetworkOptions", "PROJ_jll"] +git-tree-sha1 = "61188669db4f5b400173e4ec60da8bcb72d6e749" +uuid = "c94c279d-25a6-4763-9509-64d165bea63e" +version = "1.9.0" + [[deps.PtrArrays]] git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" @@ -2676,6 +2792,12 @@ git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" uuid = "94e857df-77ce-4151-89e5-788b33177be4" version = "0.1.0" +[[deps.SQLite_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "9a325057cdb9b066f1f96dc77218df60fe3007cb" +uuid = "76ed43ae-9a5d-5a62-8c75-30186b810ce8" +version = "3.48.0+0" + [[deps.SciMLBase]] deps = ["ADTypes", "Accessors", "Adapt", "ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "Moshi", "PrecompileTools", "Preferences", "Printf", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "SciMLStructures", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface"] git-tree-sha1 = "04bbcdc8d1f7d6f667f75fbcc68728231e21fabe" @@ -2705,9 +2827,9 @@ version = "2.101.0" [[deps.SciMLOperators]] deps = ["Accessors", "ArrayInterface", "DocStringExtensions", "LinearAlgebra", "MacroTools"] -git-tree-sha1 = "7d3a1519dc4d433a6b20035eaff20bde8be77c66" +git-tree-sha1 = "aea915a39b547c48a18ee041120db1ae8df5a691" uuid = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" -version = "1.4.0" +version = "1.5.0" weakdeps = ["SparseArrays", "StaticArraysCore"] [deps.SciMLOperators.extensions] @@ -2797,6 +2919,12 @@ version = "0.1.5" uuid = "6462fe0b-24de-5631-8697-dd941f90decc" version = "1.11.0" +[[deps.SortTileRecursiveTree]] +deps = ["AbstractTrees", "Extents", "GeoInterface"] +git-tree-sha1 = "f9aa6616a9b3bd01f93f27c010f1d25fc5a094a9" +uuid = "746ee33f-1797-42c2-866d-db2fce69d14d" +version = "0.1.4" + [[deps.SortingAlgorithms]] deps = ["DataStructures"] git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9" @@ -2836,6 +2964,11 @@ git-tree-sha1 = "95af145932c2ed859b63329952ce8d633719f091" uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" version = "1.0.3" +[[deps.StableTasks]] +git-tree-sha1 = "c4f6610f85cb965bee5bfafa64cbeeda55a4e0b2" +uuid = "91464d47-22a1-43fe-8b7f-2d57ee82463f" +version = "0.1.7" + [[deps.StackViews]] deps = ["OffsetArrays"] git-tree-sha1 = "be1cf4eb0ac528d96f5115b4ed80c26a8d8ae621" @@ -2964,10 +3097,14 @@ weakdeps = ["ClimaParams"] CreateParametersExt = "ClimaParams" [[deps.SymbolicIndexingInterface]] -deps = ["Accessors", "ArrayInterface", "PrettyTables", "RuntimeGeneratedFunctions", "StaticArraysCore"] -git-tree-sha1 = "59ca6eddaaa9849e7de9fd1153b6faf0b1db7b80" +deps = ["Accessors", "ArrayInterface", "RuntimeGeneratedFunctions", "StaticArraysCore"] +git-tree-sha1 = "93104ca226670c0cb92ba8bc6998852ad55a2d4c" uuid = "2efcf032-c050-4f8e-a9bb-153293bab1f5" -version = "0.3.42" +version = "0.3.43" +weakdeps = ["PrettyTables"] + + [deps.SymbolicIndexingInterface.extensions] + SymbolicIndexingInterfacePrettyTablesExt = "PrettyTables" [[deps.TOML]] deps = ["Dates"] diff --git a/docs/Manifest.toml b/docs/Manifest.toml index e9f11fbec5..9d462667b2 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -2,12 +2,12 @@ julia_version = "1.10.10" manifest_format = "2.0" -project_hash = "0e313427333375504d76ddc31cd582bee13918ac" +project_hash = "9154a208909b8fdf5c46e5746627f9c3fc1e1607" [[deps.ADTypes]] -git-tree-sha1 = "7927b9af540ee964cc5d1b73293f1eb0b761a3a1" +git-tree-sha1 = "60665b326b75db6517939d0e1875850bc4a54368" uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -version = "1.16.0" +version = "1.17.0" weakdeps = ["ChainRulesCore", "ConstructionBase", "EnzymeCore"] [deps.ADTypes.extensions] @@ -162,9 +162,9 @@ uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [[deps.Atomix]] deps = ["UnsafeAtomics"] -git-tree-sha1 = "b5bb4dc6248fde467be2a863eb8452993e74d402" +git-tree-sha1 = "29bb0eb6f578a587a49da16564705968667f5fa8" uuid = "a9b6321e-bd34-4604-b9c9-b65b8de01458" -version = "1.1.1" +version = "1.1.2" [deps.Atomix.extensions] AtomixCUDAExt = "CUDA" @@ -360,14 +360,25 @@ version = "1.72.5" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "06ee8d1aa558d2833aa799f6f0b31b30cada405f" +git-tree-sha1 = "e4c6a16e77171a5f5e25e9646617ab1c276c5607" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.25.2" +version = "1.26.0" weakdeps = ["SparseArrays"] [deps.ChainRulesCore.extensions] ChainRulesCoreSparseArraysExt = "SparseArrays" +[[deps.ClimaAnalysis]] +deps = ["Artifacts", "Dates", "Interpolations", "NCDatasets", "NaNStatistics", "OrderedCollections", "Reexport", "Statistics", "Unitful"] +git-tree-sha1 = "2488781691ad571f17dc40b02e5380296a80cd2e" +uuid = "29b5916a-a76c-4e73-9657-3c8fd22e65e6" +version = "0.5.19" +weakdeps = ["GeoMakie", "Makie"] + + [deps.ClimaAnalysis.extensions] + ClimaAnalysisGeoMakieExt = "GeoMakie" + ClimaAnalysisMakieExt = "Makie" + [[deps.ClimaComms]] deps = ["Adapt", "Logging", "LoggingExtras"] git-tree-sha1 = "f3961fa943c1bbbc376af910cb98db67084dc642" @@ -407,26 +418,13 @@ deps = ["ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaParams", "ClimaTime path = ".." uuid = "08f4d4ce-cf43-44bb-ad95-9d2d5f413532" version = "0.18.0" +weakdeps = ["BSON", "CSV", "CairoMakie", "ClimaAnalysis", "DataFrames", "DelimitedFiles", "Flux", "GeoMakie", "HTTP", "Poppler_jll", "Printf", "StatsBase"] [deps.ClimaLand.extensions] FluxnetSimulationsExt = ["DelimitedFiles"] LandSimulationVisualizationExt = ["CairoMakie", "ClimaAnalysis", "GeoMakie", "Poppler_jll", "Printf", "StatsBase"] NeuralSnowExt = ["CSV", "DataFrames", "HTTP", "Flux", "StatsBase", "BSON"] - [deps.ClimaLand.weakdeps] - BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" - CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" - CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" - ClimaAnalysis = "29b5916a-a76c-4e73-9657-3c8fd22e65e6" - DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" - DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" - Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" - GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" - HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" - Poppler_jll = "9c32591e-4766-534b-9725-b71a8799265b" - Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" - StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" - [[deps.ClimaLandSimulations]] deps = ["Bonito", "CairoMakie", "ClimaComms", "ClimaCore", "ClimaDiagnostics", "ClimaLand", "ClimaParams", "ClimaTimeSteppers", "ClimaUtilities", "DataFrames", "Dates", "DelimitedFiles", "Format", "HTTP", "Insolation", "Interpolations", "InverseFunctions", "JSON", "LaTeXStrings", "MutableArithmetics", "NLsolve", "PlotUtils", "RootSolvers", "SciMLBase", "StaticArrays", "Statistics", "StatsBase", "SurfaceFluxes", "Thermodynamics", "Unitful", "UnitfulMoles", "WGLMakie"] path = "../lib/ClimaLandSimulations" @@ -613,6 +611,12 @@ git-tree-sha1 = "dec769959be3af9ba94970b1f14b31c196b0fb9e" uuid = "f65535da-76fb-5f13-bab9-19810c17039a" version = "0.16.4" +[[deps.CoordinateTransformations]] +deps = ["LinearAlgebra", "StaticArrays"] +git-tree-sha1 = "a692f5e257d332de1e554e4566a4e5a8a72de2b2" +uuid = "150eb455-5306-5404-9cee-2592286d6298" +version = "0.6.4" + [[deps.CpuId]] deps = ["Markdown"] git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" @@ -687,9 +691,9 @@ version = "1.33.4+0" [[deps.DiffEqBase]] deps = ["ArrayInterface", "ConcreteStructs", "DataStructures", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SciMLStructures", "Setfield", "Static", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "TruncatedStacktraces"] -git-tree-sha1 = "803ea1b97e06d9f4b0da348589d451c5a456e9f4" +git-tree-sha1 = "6fecfae8b2d9983e939378c8eacff6562e8a2567" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.182.1" +version = "6.183.0" [deps.DiffEqBase.extensions] DiffEqBaseCUDAExt = "CUDA" @@ -789,9 +793,9 @@ version = "0.7.4" [[deps.DiskArrays]] deps = ["ConstructionBase", "LRUCache", "Mmap", "OffsetArrays"] -git-tree-sha1 = "16d93ff95ecc421463eaefd694e6746bb1c0919e" +git-tree-sha1 = "bfde0790720fcac006a3d62149309a685fc3aa13" uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" -version = "0.4.14" +version = "0.4.15" [[deps.Distances]] deps = ["LinearAlgebra", "Statistics", "StatsAPI"] @@ -1029,9 +1033,9 @@ weakdeps = ["PDMats", "SparseArrays", "Statistics"] [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Setfield"] -git-tree-sha1 = "f089ab1f834470c525562030c8cfde4025d5e915" +git-tree-sha1 = "d84e026183bb3fc764110ae98792c2e004f8c240" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.27.0" +version = "2.28.0" [deps.FiniteDiff.extensions] FiniteDiffBandedMatricesExt = "BandedMatrices" @@ -1192,12 +1196,72 @@ git-tree-sha1 = "294e99f19869d0b0cb71aef92f19d03649d028d5" uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" version = "1.4.1" +[[deps.GeoInterfaceMakie]] +deps = ["GeoInterface", "GeometryBasics", "MakieCore"] +git-tree-sha1 = "378afe561ba990392146e1a7abd472c7db7f1479" +uuid = "0edc0954-3250-4c18-859d-ec71c1660c08" +version = "0.1.9" + +[[deps.GeoInterfaceRecipes]] +deps = ["GeoInterface", "RecipesBase"] +git-tree-sha1 = "fb1156076f24f1dfee45b3feadb31d05730a49ac" +uuid = "0329782f-3d07-4b52-b9f6-d3137cf03c7a" +version = "1.0.2" + +[[deps.GeoJSON]] +deps = ["Extents", "GeoFormatTypes", "GeoInterface", "GeoInterfaceMakie", "GeoInterfaceRecipes", "JSON3", "StructTypes", "Tables"] +git-tree-sha1 = "c803640368acf4ae02bb5a69a986cecc4a5cb984" +uuid = "61d90e0f-e114-555e-ac52-39dfb47a3ef9" +version = "0.8.3" +weakdeps = ["Makie"] + + [deps.GeoJSON.extensions] + GeoJSONMakieExt = "Makie" + +[[deps.GeoMakie]] +deps = ["Colors", "CoordinateTransformations", "Downloads", "GeoFormatTypes", "GeoInterface", "GeoInterfaceMakie", "GeoJSON", "Geodesy", "GeometryBasics", "GeometryOps", "ImageIO", "LinearAlgebra", "Makie", "NaturalEarth", "Proj", "Reexport", "Statistics", "StructArrays"] +git-tree-sha1 = "2db1d309af35a1ad440e75b9275e4b3b4715ed39" +uuid = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" +version = "0.7.12" + +[[deps.Geodesy]] +deps = ["CoordinateTransformations", "Dates", "LinearAlgebra", "StaticArrays"] +git-tree-sha1 = "ed98a4429bf0a033ccc5e036120181dd52f06d31" +uuid = "0ef565a4-170c-5f04-8de2-149903a85f3d" +version = "1.1.0" + [[deps.GeometryBasics]] deps = ["EarCut_jll", "Extents", "GeoInterface", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] git-tree-sha1 = "b62f2b2d76cee0d61a2ef2b3118cd2a3215d3134" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" version = "0.4.11" +[[deps.GeometryOps]] +deps = ["AbstractTrees", "AdaptivePredicates", "CoordinateTransformations", "DataAPI", "DelaunayTriangulation", "ExactPredicates", "Extents", "GeoFormatTypes", "GeoInterface", "GeometryOpsCore", "LinearAlgebra", "SortTileRecursiveTree", "StaticArrays", "Statistics", "Tables"] +git-tree-sha1 = "1b7fef8228b2fb471548d6a1e1b644056b536970" +uuid = "3251bfac-6a57-4b6d-aa61-ac1fef2975ab" +version = "0.1.26" + + [deps.GeometryOps.extensions] + GeometryOpsDataFramesExt = "DataFrames" + GeometryOpsFlexiJoinsExt = "FlexiJoins" + GeometryOpsLibGEOSExt = "LibGEOS" + GeometryOpsProjExt = "Proj" + GeometryOpsTGGeometryExt = "TGGeometry" + + [deps.GeometryOps.weakdeps] + DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" + FlexiJoins = "e37f2e79-19fa-4eb7-8510-b63b51fe0a37" + LibGEOS = "a90b1aa1-3769-5649-ba7e-abc5a9d163eb" + Proj = "c94c279d-25a6-4763-9509-64d165bea63e" + TGGeometry = "d7e755d2-3c95-4bcf-9b3c-79ab1a78647b" + +[[deps.GeometryOpsCore]] +deps = ["DataAPI", "GeoInterface", "StableTasks", "Tables"] +git-tree-sha1 = "69fc98947b06f8ac4279cf5bf8810373fe042be4" +uuid = "05efe853-fabf-41c8-927e-7063c8b9f013" +version = "0.1.7" + [[deps.GettextRuntime_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll"] git-tree-sha1 = "45288942190db7c5f760f59c04495064eedf9340" @@ -1649,9 +1713,9 @@ version = "1.4.0" [[deps.Latexify]] deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] -git-tree-sha1 = "4f34eaabe49ecb3fb0d58d6015e32fd31a733199" +git-tree-sha1 = "52e1296ebbde0db845b356abbbe67fb82a0a116c" uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.16.8" +version = "0.16.9" [deps.Latexify.extensions] DataFramesExt = "DataFrames" @@ -1791,6 +1855,12 @@ git-tree-sha1 = "da046be6d63304f7ba9c1bb04820fb306ba1ab12" uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" version = "2.20.1" +[[deps.LittleCMS_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll"] +git-tree-sha1 = "fa7fd067dca76cadd880f1ca937b4f387975a9f5" +uuid = "d3a379c0-f9a3-5b72-a4c0-6bf4d2e8af0f" +version = "2.16.0+0" + [[deps.LogExpFunctions]] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" @@ -2106,12 +2176,34 @@ git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.1.3" +[[deps.NaNStatistics]] +deps = ["PrecompileTools", "Static", "StaticArrayInterface"] +git-tree-sha1 = "473b6054828a4f238d3a8fd71e7ef24d5e68337a" +uuid = "b946abbf-3ea7-4610-9019-9858bfdeaf2d" +version = "0.6.54" + + [deps.NaNStatistics.extensions] + NaNStatisticsDimensionalDataExt = "DimensionalData" + NaNStatisticsHwlocExt = "Hwloc" + NaNStatisticsUnitfulExt = "Unitful" + + [deps.NaNStatistics.weakdeps] + DimensionalData = "0703355e-b756-11e9-17c0-8b28908087d0" + Hwloc = "0e44f5e4-bd66-52a0-8798-143a42290a1d" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + [[deps.NameResolution]] deps = ["PrettyPrint"] git-tree-sha1 = "1a0fa0e9613f46c9b8c11eee38ebb4f590013c5e" uuid = "71a1bf82-56d0-4bbc-8a3c-48b961074391" version = "0.1.5" +[[deps.NaturalEarth]] +deps = ["Downloads", "GeoJSON", "Pkg", "Scratch"] +git-tree-sha1 = "3f75210ac08fe4496a55f9694b95859c40b8eaea" +uuid = "436b0209-26ab-4e65-94a9-6526d86fea76" +version = "0.1.0" + [[deps.NetCDF_jll]] deps = ["Artifacts", "Blosc_jll", "Bzip2_jll", "HDF5_jll", "JLLWrappers", "LazyArtifacts", "LibCURL_jll", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "TOML", "XML2_jll", "Zlib_jll", "Zstd_jll", "libaec_jll", "libzip_jll"] git-tree-sha1 = "d574803b6055116af212434460adf654ce98e345" @@ -2183,6 +2275,12 @@ git-tree-sha1 = "8292dd5c8a38257111ada2174000a33745b06d4e" uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" version = "3.2.4+0" +[[deps.OpenJpeg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libtiff_jll", "LittleCMS_jll", "libpng_jll"] +git-tree-sha1 = "7dc7028a10d1408e9103c0a77da19fdedce4de6c" +uuid = "643b3616-a352-519d-856d-80112ee9badc" +version = "2.5.4+0" + [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" @@ -2272,6 +2370,12 @@ git-tree-sha1 = "cf181f0b1e6a18dfeb0ee8acc4a9d1672499626c" uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" version = "0.4.4" +[[deps.PROJ_jll]] +deps = ["Artifacts", "JLLWrappers", "LibCURL_jll", "Libdl", "Libtiff_jll", "SQLite_jll"] +git-tree-sha1 = "29d4224ba271e3b679cca03a8fd72e271525c113" +uuid = "58948b4f-47e0-5654-a9ad-f609743f8632" +version = "902.600.200+0" + [[deps.PackageExtensionCompat]] git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518" uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930" @@ -2339,9 +2443,9 @@ version = "1.4.3" [[deps.Plots]] deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "TOML", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] -git-tree-sha1 = "3db9167c618b290a05d4345ca70de6d95304a32a" +git-tree-sha1 = "9a9216c0cf706cb2cc58fd194878180e3e51e8c0" uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.40.17" +version = "1.40.18" [deps.Plots.extensions] FileIOExt = "FileIO" @@ -2380,6 +2484,12 @@ git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" version = "1.4.3" +[[deps.Poppler_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "JpegTurbo_jll", "LibCURL_jll", "Libdl", "Libtiff_jll", "OpenJpeg_jll", "libpng_jll"] +git-tree-sha1 = "7dbfb7f61c3aa5def7b7dad3fa344c1c2858a83b" +uuid = "9c32591e-4766-534b-9725-b71a8799265b" +version = "24.6.0+0" + [[deps.PositiveFactorizations]] deps = ["LinearAlgebra"] git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" @@ -2394,9 +2504,9 @@ version = "1.2.1" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.3" +version = "1.5.0" [[deps.PrettyPrint]] git-tree-sha1 = "632eb4abab3449ab30c5e1afaa874f0b98b586e4" @@ -2429,6 +2539,12 @@ git-tree-sha1 = "13c5103482a8ed1536a54c08d0e742ae3dca2d42" uuid = "92933f4c-e287-5a05-a399-4b506db050ca" version = "1.10.4" +[[deps.Proj]] +deps = ["CEnum", "CoordinateTransformations", "GeoFormatTypes", "GeoInterface", "NetworkOptions", "PROJ_jll"] +git-tree-sha1 = "61188669db4f5b400173e4ec60da8bcb72d6e749" +uuid = "c94c279d-25a6-4763-9509-64d165bea63e" +version = "1.9.0" + [[deps.PtrArrays]] git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" @@ -2654,6 +2770,12 @@ git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" uuid = "94e857df-77ce-4151-89e5-788b33177be4" version = "0.1.0" +[[deps.SQLite_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "9a325057cdb9b066f1f96dc77218df60fe3007cb" +uuid = "76ed43ae-9a5d-5a62-8c75-30186b810ce8" +version = "3.48.0+0" + [[deps.SciMLBase]] deps = ["ADTypes", "Accessors", "Adapt", "ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "Moshi", "PrecompileTools", "Preferences", "Printf", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "SciMLStructures", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface"] git-tree-sha1 = "04bbcdc8d1f7d6f667f75fbcc68728231e21fabe" @@ -2683,9 +2805,9 @@ version = "2.101.0" [[deps.SciMLOperators]] deps = ["Accessors", "ArrayInterface", "DocStringExtensions", "LinearAlgebra", "MacroTools"] -git-tree-sha1 = "7d3a1519dc4d433a6b20035eaff20bde8be77c66" +git-tree-sha1 = "aea915a39b547c48a18ee041120db1ae8df5a691" uuid = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" -version = "1.4.0" +version = "1.5.0" weakdeps = ["SparseArrays", "StaticArraysCore"] [deps.SciMLOperators.extensions] @@ -2772,6 +2894,12 @@ version = "0.1.5" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +[[deps.SortTileRecursiveTree]] +deps = ["AbstractTrees", "Extents", "GeoInterface"] +git-tree-sha1 = "f9aa6616a9b3bd01f93f27c010f1d25fc5a094a9" +uuid = "746ee33f-1797-42c2-866d-db2fce69d14d" +version = "0.1.4" + [[deps.SortingAlgorithms]] deps = ["DataStructures"] git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9" @@ -2811,6 +2939,11 @@ git-tree-sha1 = "95af145932c2ed859b63329952ce8d633719f091" uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" version = "1.0.3" +[[deps.StableTasks]] +git-tree-sha1 = "c4f6610f85cb965bee5bfafa64cbeeda55a4e0b2" +uuid = "91464d47-22a1-43fe-8b7f-2d57ee82463f" +version = "0.1.7" + [[deps.StackViews]] deps = ["OffsetArrays"] git-tree-sha1 = "be1cf4eb0ac528d96f5115b4ed80c26a8d8ae621" @@ -2930,10 +3063,14 @@ weakdeps = ["ClimaParams"] CreateParametersExt = "ClimaParams" [[deps.SymbolicIndexingInterface]] -deps = ["Accessors", "ArrayInterface", "PrettyTables", "RuntimeGeneratedFunctions", "StaticArraysCore"] -git-tree-sha1 = "59ca6eddaaa9849e7de9fd1153b6faf0b1db7b80" +deps = ["Accessors", "ArrayInterface", "RuntimeGeneratedFunctions", "StaticArraysCore"] +git-tree-sha1 = "93104ca226670c0cb92ba8bc6998852ad55a2d4c" uuid = "2efcf032-c050-4f8e-a9bb-153293bab1f5" -version = "0.3.42" +version = "0.3.43" +weakdeps = ["PrettyTables"] + + [deps.SymbolicIndexingInterface.extensions] + SymbolicIndexingInterfacePrettyTablesExt = "PrettyTables" [[deps.TOML]] deps = ["Dates"] diff --git a/docs/Project.toml b/docs/Project.toml index 4110f36337..704685eac1 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,7 +3,10 @@ AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" BSON = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +ClimaAnalysis = "29b5916a-a76c-4e73-9657-3c8fd22e65e6" +ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" +ClimaDiagnostics = "1ecacbb8-0713-4841-9a07-eb5aa8a2d53f" ClimaLand = "08f4d4ce-cf43-44bb-ad95-9d2d5f413532" ClimaLandSimulations = "348a0bd3-1299-4261-8002-d2cd97df6055" ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c" @@ -17,6 +20,7 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" Format = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8" +GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" Insolation = "e98cc03f-d57e-4e3c-b70c-8d51efe9e0d8" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" @@ -25,6 +29,7 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" MethodAnalysis = "85b6ec6f-f7df-4429-9514-a64bcd9ee824" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Poppler_jll = "9c32591e-4766-534b-9725-b71a8799265b" PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" diff --git a/docs/list_of_apis.jl b/docs/list_of_apis.jl index 4e5aabb477..28d8f6ae8e 100644 --- a/docs/list_of_apis.jl +++ b/docs/list_of_apis.jl @@ -4,9 +4,6 @@ apis = [ "ClimaLand" => [ - "ClimaLand" => "APIs/ClimaLand.md", - "Shared Utilities" => - ["APIs/Simulations.md", "APIs/shared_utilities.md"], "Soil" => [ "Soil Energy and Hydrology" => "APIs/Soil.md", "Soil Biogeochemistry" => "APIs/SoilBiogeochemistry.md", @@ -25,4 +22,7 @@ apis = [ "Bucket Model" => "APIs/Bucket.md", "Snow Model" => "APIs/Snow.md", ], + "Integrated Models" => "APIs/ClimaLand.md", + "Shared Utilities" => + ["APIs/Simulations.md", "APIs/shared_utilities.md"], ] diff --git a/docs/list_tutorials.jl b/docs/list_tutorials.jl index 53b65e7167..f24f376b6d 100644 --- a/docs/list_tutorials.jl +++ b/docs/list_tutorials.jl @@ -1,19 +1,7 @@ tutorials = [ - "Running land simulations" => [ - "Bucket LSM" => [ - "standalone/Bucket/bucket_tutorial.jl", - "standalone/Bucket/coupled_bucket.jl", - ], - "Integrated soil+canopy modeling" => [ - "Coupled Canopy and Soil" => "integrated/soil_canopy_tutorial.jl", - ], - "Handling interactions between model components" => [ - "Adjusting boundary conditions for the soil" => "integrated/handling_soil_fluxes.jl", - "Adjusting boundary conditions for the snow" => "integrated/handling_snow_fluxes.jl", - ], - ], "Running standalone component simulations" => [ - "Soil modeling" => [ + "Bucket" => "standalone/Bucket/bucket_tutorial.jl", + "Soil" => [ "Boundary conditions" => "standalone/Soil/boundary_conditions.jl", "Richards Equation" => "standalone/Soil/richards_equation.jl", "Energy and Hydrology" => "standalone/Soil/soil_energy_hydrology.jl", @@ -25,22 +13,40 @@ tutorials = [ "Coarse Sand Evaporation" => "standalone/Soil/evaporation.jl", "Gilat Loess Evaporation" => "standalone/Soil/evaporation_gilat_loess.jl", "Bare soil site" => "standalone/Soil/sublimation.jl", + "Changing soil parameterizations" => "standalone/Soil/changing_soil_parameterizations.jl", ], - "Canopy modeling" => [ + "Canopy" => [ "Standalone Canopy" => "standalone/Canopy/canopy_tutorial.jl", + "Changing canopy parameterizations" => "standalone/Canopy/changing_canopy_parameterizations.jl", ], - "Snow Modeling" => [ - "standalone/Snow/base_tutorial.jl", - "standalone/Snow/data_tutorial.jl", + "Snow" => [ + "Base tutorial" => "standalone/Snow/base_tutorial.jl", + "Data tutorial" => "standalone/Snow/data_tutorial.jl", ], ], - "Calibrating your ClimaLand model" => [ + "Running Fluxnet simulations" => [ + "Canopy and soil" => "integrated/soil_canopy_fluxnet_tutorial.jl", + "Canopy, soil, and snow" => "integrated/snowy_land_fluxnet_tutorial.jl", + "Data processing" => "integrated/fluxnet_data.jl", + "Visualization" => "integrated/fluxnet_vis.jl", + ], + "Running global simulations" => [ + "Bucket" => "global/bucket.jl", + "Snow, soil, canopy" => "global/snowy_land.jl", + ], + "Calibrating a ClimaLand model" => [ "Single site perfect model" => "calibration/minimal_working_example.jl", "Single site observations" => "calibration/minimal_working_example_obs.jl", ], + "Running coupled simulations" => + ["Coupled bucket model" => "standalone/Bucket/coupled_bucket.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", + "Intro to multi-component models" => [ + "Single column tutorial" => "standalone/Usage/LSM_single_column_tutorial.jl", + "Adjusting boundary conditions for the soil" => "integrated/handling_soil_fluxes.jl", + "Adjusting boundary conditions for the snow" => "integrated/handling_snow_fluxes.jl", + ], "Intro to ClimaLand Domains" => "standalone/Usage/domain_tutorial.jl", "Intro to forced site-level runs" => "shared_utilities/driver_tutorial.jl", "Intro to implicit/explicit timestepping" => "shared_utilities/timestepping.jl", diff --git a/docs/make.jl b/docs/make.jl index 6034f8ba1e..8f470e2611 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -52,25 +52,25 @@ include("list_diagnostics.jl") pages = Any[ "Home" => "index.md", "Running your first simulation" => "getting_started.md", - "ClimaLand structure" => [ + "Tutorials" => tutorials, + "Additional resources" => [ "Model structure" => "model_structure.md", "Repository structure" => "repo_structure.md", + "Analyzing model output" => [ + "Diagnostics" => diagnostics, + "Leaderboard" => "leaderboard/leaderboard.md", + ], + "Running on GPU or with MPI" => "architectures.md", + "Calibration" => "calibration.md", + "Restarting a simulation" => "restarts.md", + "Software utilities" => [ + "ITime type" => "itime.md", + "Shared utilities" => "shared_utilities.md", + ], + "Physical units" => "physical_units.md", + "Model Equations" => standalone_models, + "Julia background" => "julia.md", ], - "Tutorials" => tutorials, - "Standalone models" => standalone_models, - "Analyzing model output" => [ - "Diagnostics" => diagnostics, - "Leaderboard" => "leaderboard/leaderboard.md", - ], - "Running on GPU or with MPI" => "architectures.md", - "Calibration" => "calibration.md", - "Restarting a simulation" => "restarts.md", - "Software utilities" => [ - "ITime type" => "itime.md", - "Shared utilities" => "shared_utilities.md", - ], - "Physical units" => "physical_units.md", - "Julia background" => "julia.md", "APIs" => apis, "Contributor guide" => "contributing.md", ] diff --git a/docs/src/APIs/ClimaLand.md b/docs/src/APIs/ClimaLand.md index 198a0fa19b..105a939259 100644 --- a/docs/src/APIs/ClimaLand.md +++ b/docs/src/APIs/ClimaLand.md @@ -3,11 +3,14 @@ ```@meta CurrentModule = ClimaLand ``` -## LSM Model Types and methods +## Integrated Land Model Types and methods ```@docs -ClimaLand.LandSoilBiogeochemistry +ClimaLand.LandModel +ClimaLand.SoilCanopyModel ClimaLand.LandHydrology +ClimaLand.LandSoilBiogeochemistry +ClimaLand.SoilSnowModel ClimaLand.land_components ClimaLand.lsm_aux_vars ClimaLand.lsm_aux_types diff --git a/docs/src/getting_started.md b/docs/src/getting_started.md index 22f2dd1871..1a4ebb9756 100644 --- a/docs/src/getting_started.md +++ b/docs/src/getting_started.md @@ -14,7 +14,7 @@ julia> Pkg.add(ClimaLand) julia> using ClimaLand ``` -A typical land simulation employs several different parameterizations to model the various land-surface processes. Let's start our journet into ClimaLand by looking at one of those. +A typical land simulation employs several different parameterizations to model the various land-surface processes. Let's start our journey into ClimaLand by looking at one of those. ### Parameterization diff --git a/docs/src/tutorials/global/bucket.jl b/docs/src/tutorials/global/bucket.jl new file mode 100644 index 0000000000..2f4180c50e --- /dev/null +++ b/docs/src/tutorials/global/bucket.jl @@ -0,0 +1,140 @@ +# # Global bucket run + +# The code sets up and runs the bucket model on a spherical domain, +# using ERA5 data. + +# First we import a lot of packages: +import ClimaComms +using ClimaCore +using ClimaUtilities +import Interpolations +import ClimaUtilities.TimeVaryingInputs: + TimeVaryingInput, LinearInterpolation, PeriodicCalendar +ClimaComms.@import_required_backends +import ClimaTimeSteppers as CTS +import ClimaParams as CP +using ClimaLand.Bucket: + BucketModel, BucketModelParameters, PrescribedBaregroundAlbedo +import ClimaLand +import ClimaLand.Parameters as LP +import ClimaLand.Simulations: LandSimulation, solve! +using Dates +using CairoMakie, ClimaAnalysis, GeoMakie, Poppler_jll, Printf, StatsBase +import ClimaLand.LandSimVis as LandSimVis; + +# Set the simulation float type, determine the +# context (MPI or on a single node), and device type. Create +# a default output directory for diagnostics. +const FT = Float64; +context = ClimaComms.context() +ClimaComms.init(context) +device = ClimaComms.device() +device_suffix = device isa ClimaComms.CPUSingleThreaded ? "cpu" : "gpu" +root_path = "bucket_longrun_$(device_suffix)" +diagnostics_outdir = joinpath(root_path, "global_diagnostics") +outdir = + ClimaUtilities.OutputPathGenerator.generate_output_path(diagnostics_outdir); + +# Set timestep, start_date, stop_date: +Δt = 900.0 +start_date = DateTime(2008) +stop_date = DateTime(2009); + +# Create the domain - this is intentionally low resolution, +# about 4.5 degrees x 4.5 degrees, to run quickly +# when making the documentation on CPU. +nelements = (20, 7) +depth = FT(3.5) +dz_tuple = FT.((1.0, 0.05)) +domain = + ClimaLand.Domains.global_domain(FT; context, nelements, depth, dz_tuple); + +# Parameters: +earth_param_set = LP.LandParameters(FT) +α_snow = FT(0.8) +albedo = PrescribedBaregroundAlbedo{FT}(α_snow, domain.space.surface) +bucket_parameters = BucketModelParameters( + FT; + albedo, + σS_c = FT(0.2), + W_f = FT(0.2), + z_0m = FT(1e-3), + z_0b = FT(1e-3), + κ_soil = FT(1.5), + ρc_soil = FT(2e6), + τc = FT(float(Δt)), +); + +# Low-resolution forcing data from ERA5 is used here, +# but high-resolution should be used for production runs. +era5_ncdata_path = ClimaLand.Artifacts.era5_land_forcing_data2008_path(; + context, + lowres = true, +) +atmos, radiation = ClimaLand.prescribed_forcing_era5( + era5_ncdata_path, + domain.space.surface, + start_date, + earth_param_set, + FT; + max_wind_speed = 25.0, + time_interpolation_method = LinearInterpolation(PeriodicCalendar()), + regridder_type = :InterpolationsRegridder, +); + +# Make the model: +bucket = BucketModel( + parameters = bucket_parameters, + domain = domain, + atmosphere = atmos, + radiation = radiation, +); + +# Create a function which sets the initial conditions. +# This should have the argument structure (Y,p,t, model) +# in order to be used by the `LandSimulation` struct, below: +function set_ic!(Y, p, t, bucket) + coords = ClimaCore.Fields.coordinate_field(Y.bucket.T) + T_sfc_0 = 271.0 + @. Y.bucket.T = T_sfc_0 + 40 * cosd(coords.lat)^4 + Y.bucket.W .= 0.15 + Y.bucket.Ws .= 0.0 + Y.bucket.σS .= 0.0 +end + +# Define timestepper and ODE algorithm +timestepper = CTS.RK4() +timestepper = CTS.ExplicitAlgorithm(timestepper); + +# Create the simulation and solve it: +simulation = LandSimulation( + start_date, + stop_date, + Δt, + bucket; + set_ic!, + timestepper, + outdir, +); + +solve!(simulation); + +# Make some plots: +short_names = ["tsfc", "lhf", "shf", "wsoil"] + +LandSimVis.make_annual_timeseries( + simulation; + savedir = ".", + short_names, + plot_name = "bucket_annual_timeseries.pdf", +) +# ![](bucket_annual_timeseries.pdf) + +LandSimVis.make_heatmaps( + simulation; + savedir = ".", + short_names, + date = stop_date, + plot_name = "bucket_figures.pdf", +) +# ![](bucket_figures.pdf) diff --git a/docs/src/tutorials/global/snowy_land.jl b/docs/src/tutorials/global/snowy_land.jl new file mode 100644 index 0000000000..db846bc671 --- /dev/null +++ b/docs/src/tutorials/global/snowy_land.jl @@ -0,0 +1,90 @@ +# # Global full land (snow+soil+canopy) run + +# The code sets up the ClimaLand land model on a spherical domain, +# forcing with ERA5 data, but does not actually run the simulation. +# To run the simulation, we strongly recommend using a GPU. + +# First we import a lot of packages: +import ClimaComms +ClimaComms.@import_required_backends +using ClimaUtilities +import Interpolations +import ClimaUtilities.TimeVaryingInputs: + TimeVaryingInput, LinearInterpolation, PeriodicCalendar +import ClimaParams as CP +import ClimaLand +import ClimaLand.Parameters as LP +import ClimaLand.Simulations: LandSimulation, solve! +using Dates +using CairoMakie, ClimaAnalysis, GeoMakie, Poppler_jll, Printf, StatsBase +import ClimaLand.LandSimVis as LandSimVis; + +# Set the simulation float type, determine the +# context (MPI or on a single node), and device type (CPU or GPU). +# Create a default output directory for diagnostics. +const FT = Float64; +context = ClimaComms.context() +ClimaComms.init(context) +device = ClimaComms.device() +device_suffix = device isa ClimaComms.CPUSingleThreaded ? "cpu" : "gpu" +root_path = "land_longrun_$(device_suffix)" +diagnostics_outdir = joinpath(root_path, "global_diagnostics") +outdir = + ClimaUtilities.OutputPathGenerator.generate_output_path(diagnostics_outdir); +earth_param_set = LP.LandParameters(FT); + +# Set timestep, start_date, stop_date: +Δt = 450.0 +start_date = DateTime(2008) +stop_date = DateTime(2009); + +# Create the domain: +nelements = (101, 15) +domain = ClimaLand.Domains.global_domain(FT; context, nelements); + +# Low-resolution forcing data from ERA5 is used here, +# but high-resolution should be used for production runs. +era5_ncdata_path = ClimaLand.Artifacts.era5_land_forcing_data2008_path(; + context, + lowres = true, +) +forcing = ClimaLand.prescribed_forcing_era5( + era5_ncdata_path, + domain.space.surface, + start_date, + earth_param_set, + FT; + max_wind_speed = 25.0, + time_interpolation_method = LinearInterpolation(PeriodicCalendar()), + regridder_type = :InterpolationsRegridder, +); + +# MODIS LAI is prescribed for the canopy model: +modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; + context, + start_date, + end_date = stop_date, +) +LAI = ClimaLand.prescribed_lai_modis( + modis_lai_ncdata_path, + domain.space.surface, + start_date; + time_interpolation_method = LinearInterpolation(), +); +# Make the model: +model = ClimaLand.LandModel{FT}(forcing, LAI, earth_param_set, domain, Δt); +simulation = ClimaLand.Simulations.LandSimulation( + start_date, + stop_date, + Δt, + model; + outdir, +); +# Run the simulation and make plots: +# +# ``` julia +# ClimaLand.Simulations.solve!(simulation) +# LandSimVis.make_annual_timeseries(simulation; savedir = root_path) +# LandSimVis.make_heatmaps(simulation;date = stop_date, savedir = root_path) +# LandSimVis.make_leaderboard_plots(simulation, savedir = root_path) +# ``` diff --git a/docs/src/tutorials/integrated/fluxnet_data.jl b/docs/src/tutorials/integrated/fluxnet_data.jl new file mode 100644 index 0000000000..500cc0289b --- /dev/null +++ b/docs/src/tutorials/integrated/fluxnet_data.jl @@ -0,0 +1,183 @@ +# # Fluxnet forcing data: LAI, radiation, and atmospheric variables + +# In this tutorial, we will demonstrate how we read in forcing data at a Fluxnet site +# using our ClimaLand infrastructure. To see an example running a simulation at a +# Fluxnet site, please see the corresponding tutorials for the [SoilCanopyModel](docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.md) +# or [LandModel](docs/src/tutorials/integrated/snowy_land_fluxnet_tutorial.md) +# To access the forcing data (LAI from MODIS, SW_d, LW_d, T_air, q_air, +# P_air, and precipitation from fluxtower data), you first need the +# the fluxtower site ID. +# Currently, ClimaLand provides an interface for working with four +# fluxtower sites; adding support for a much larger set of sites is +# in progress. The sites we support are Vaira Ranch (US_Var), +# Missouri Ozark (US-MOz), Niwot Ridge (US-NR1), and Harvard Forest +# (US-Ha1). + +using Dates +import ClimaParams as CP +using ClimaLand +using ClimaLand.Domains: Column +import ClimaLand.Parameters as LP +using DelimitedFiles +using CairoMakie +import ClimaLand.FluxnetSimulations as FluxnetSimulations + +# Define the floating point precision desired (64 or 32 bit), and get the +# parameter set holding constants used across CliMA Models. +const FT = Float32; +earth_param_set = LP.LandParameters(FT); + +# Pick a site ID; convert the dash to an underscore: +site_ID = "US-NR1"; +site_ID_val = FluxnetSimulations.replace_hyphen(site_ID) +# The functions we use below use multiple dispatch, treating the +# site_ID_val as a Julia type. + +# First, we need the latitude and longitude of the site. These are used +# to get the zenith angle as a function of time, and to look up +# default parameters using the global ClimaLand parameter maps. We also +# need the offset of the local time of the site in hours from UTC. This is +# because ClimaLand simulations are carried out in UTC, while the fluxtower +# data is reported in local time. +(; time_offset, lat, long) = + FluxnetSimulations.get_location(FT, Val(site_ID_val)) + +# ClimaLand also needs to know the height at which the atmospheric data +# was recorded. +(; atmos_h) = FluxnetSimulations.get_fluxtower_height(FT, Val(site_ID_val)) + +# It is also useful to know the bounds of the data, +# in UTC, to use as the start and stop date of the simulation. +(start_date, stop_date) = + FluxnetSimulations.get_data_dates(site_ID, time_offset) + +# Now we can construct the forcing objects. Under the hood, this +# function finds the local path to the fluxtower data (and downloads it +# if it is not present) and reads the data in. It then creates +# two objects, one called `atmos`, of type `PrescibedAtmosphere`, and +# one called `radiation`, of type `PrescribedRadiativeFluxes`. These +# encode the data in interpolating functions which allow us to +# estimate the forcing at any time during the simulation using linear +# interpolation across gaps in the data. +(; atmos, radiation) = FluxnetSimulations.prescribed_forcing_fluxnet( + site_ID, + lat, + long, + time_offset, + atmos_h, + start_date, + earth_param_set, + FT, +); +# The atmosphere object holds the air temperature, pressure, specific +# humidity, wind speed, and liquid and solid precipitation fluxes. +# Since many fluxtower sites do not measure the snow and rain fluxes +# separately, we estimate them internally. This is optional, and by providing +# the kwarg `split_precip = false`, you can change the behavior to +# return all measured precip as a liquid water flux (no snow). +# The radiation object holds the downwelling short and long wave +# radiative fluxes. The diffuse fraction is estimated internally +# using an empirical function, and the zenith angle is computed +# analytically. + +# The simulation time is measured in seconds since the `start_date`. We +# can get the atmospheric temperature at the `start_date` as follows: +sim_time = 0.0 +T = [NaN] +evaluate!(T, atmos.T, sim_time); +@show T +# Note that `evaluate!` updates `T` in place. This is important: in our +# simulations, we allocate memory for the forcing, and then update the values +# at each step. If we did not do this, the dynamic memory allocation +# would cause the simulation to be incredibly slow. +# We can plot the interpolated air temperature for the first day: +sim_times = 0.0:1800.0:86400.0 # one day in seconds +air_temps = []; +for sim_time in sim_times + evaluate!(T, atmos.T, sim_time) + push!(air_temps, T[1]) +end +fig = CairoMakie.Figure() +ax = CairoMakie.Axis( + fig[1, 1], + ylabel = "Temperature (K)", + xlabel = "Date", + title = "Near-surface air temperature at Niwot Ridge", +) +lines!(ax, Second.(sim_times) .+ start_date, air_temps) +CairoMakie.save("air_temp.png", fig); +# ![](air_temp.png) + +# We do something very similar with LAI, but now the data is coming +# from MODIS. In this case, we use nearest-neighbor interpolatation +# to move from the gridded +# MODIS data to the LAI at the latitude and longitude of the site. +# To do spatial interpolation, we need to create a ClimaLand domain. +domain = + Column(; zlim = (FT(-3.0), FT(0.0)), nelements = 10, longlat = (long, lat)) +surface_space = domain.space.surface; +# Get the paths to each year of MODIS data within the start and stop dates. +modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; + start_date, + end_date = stop_date, +) +LAI = ClimaLand.prescribed_lai_modis( + modis_lai_ncdata_path, + surface_space, + start_date, +); + +# Just like with the air temperature, the LAI is an object that we can use +# to linearly interpolate observed LAI to any simulation time. + +# It can also be useful to know the maximum LAI at a site. To do so, we +# can call, for the first year of data (first element of `modis_lai_ncdata_path`): +maxLAI = + FluxnetSimulations.get_maxLAI_at_site(modis_lai_ncdata_path[1], lat, long) + +# # Fluxnet comparison data + +# To assess performance of the simulation, we need comparison data from the +# site. This is complicated since different sites provided different +# data (e.g. soil moisture and temperature and depth). ClimaLand +# provides a function to get the comparison data for a select number of +# variables: + +# | Variable | Unit | ClimaLand short name | Fluxnet Column name +# |:---------| :--------:| :------------:| -----------:| +# |Gross primary prod. | mol/m^2/s |"gpp"|"GPP\_DT\_VUT\_REF"| +# |Latent heat flux | W/m^2/s |"lhf"|"LE\_CORR"| +# |Sensible heat flux | W/m^2/s |"shf"|"H\_CORR"| +# |Upwelling SW | W/m^2/s |"swu"|"SW\_OUT"| +# |Upwelling LW | W/m^2/s |"lwu"|"LW\_OUT"| +# |Soil water content | |"swc"|"SWC\_F\_MDS\_1"| +# |Soil temperature | K|"tsoil"|"TS\_F\_MDS\_1"| +# |Total precipitation | m/s|"precip"|"P\_F"| + +comparison_data = FluxnetSimulations.get_comparison_data(site_ID, time_offset); +@show propertynames(comparison_data) +# If a column is missing, the column is not returned. Missing values +# are replaced with the mean of the not missing values. + +# The data we use to force the simulations and to compare the results against +# were obtained from Ameriflux: + +# US-Moz: https://doi.org/10.17190/AMF/1854370 +# Citation: Jeffrey Wood, Lianhong Gu (2025), AmeriFlux FLUXNET-1F US-MOz Missouri Ozark +# Site, Ver. 5-7, AmeriFlux AMP, (Dataset). https://doi.org/10.17190/AMF/1854370 + +# US-NR1: https://doi.org/10.17190/AMF/1871141 +# Citation: Peter D. Blanken, Russel K. Monson, Sean P. Burns, +# David R. Bowling, Andrew A. Turnipseed (2022), +# AmeriFlux FLUXNET-1F US-NR1 Niwot Ridge Forest (LTER NWT1), +# Ver. 3-5, AmeriFlux AMP, (Dataset). https://doi.org/10.17190/AMF/1871141 + +# US-Var: https://doi.org/10.17190/AMF/1993904 +# Citation: Siyan Ma, Liukang Xu, Joseph Verfaillie, Dennis Baldocchi (2023), +# AmeriFlux FLUXNET-1F US-Var Vaira Ranch- Ione, Ver. 3-5, AmeriFlux AMP, (Dataset). +# https://doi.org/10.17190/AMF/1993904 + +# US-Ha1: https://doi.org/10.17190/AMF/1871137 +# Citation: J. William Munger (2022), AmeriFlux FLUXNET-1F US-Ha1 +# Harvard Forest EMS Tower (HFR1), Ver. 3-5, AmeriFlux AMP, (Dataset). +# https://doi.org/10.17190/AMF/1871137 diff --git a/docs/src/tutorials/integrated/fluxnet_vis.jl b/docs/src/tutorials/integrated/fluxnet_vis.jl new file mode 100644 index 0000000000..9d860e5a3e --- /dev/null +++ b/docs/src/tutorials/integrated/fluxnet_vis.jl @@ -0,0 +1,55 @@ +# # Visualizing the output of a Fluxnet simulation + +# We current support some default plotting functions for Fluxnet simulations. +# Please let us know if you would like to add other functionality; we +# are also implementing a method to write the simulation data to +# file so that you can use your plotting methods of choice. + +# First, take a look at the fluxnet simulation tutorials for [SoilCanopyModel](docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.md) or [LandModel](docs/src/tutorials/integrated/snowy_land_fluxnet_tutorial.md). +# To use the default plotting tools (`LandSimVis`), +# you need to start by importing the packages required: + +# ``` julia +# using ClimaLand +# using CairoMakie, ClimaAnalysis, GeoMakie, Poppler_jll, Printf, StatsBase +# import ClimaLand.LandSimVis as LandSimVis; +# ``` + +# We assume you have setup your `simulation` and the solve step has finished. +# Two key functions are supported, `make_diurnal_timeseries` and +# `make_timeseries`. Both require the `simulation`: + +# ``` julia +# LandSimVis.make_diurnal_timeseries(simulation); +# LandSimVis.make_timeseries(simulation); +# ``` + +# These make plots of each variable saved as a diagnostic during the +# simulation. Only the top layer of vertically resolved variables is +# plotted. +# To plot a subset of the variables, pass in a list of ClimaLand +# Diagnostic short_names. You can also optionally pass in a spinup +# date: only data after this date will be included in plotting. You +# can also pass in a directory and plot name to overwrite the defaults: + +# ```julia +# LandSimVis.make_timeseries( +# simulation; +# savedir = path_to_dir, +# plot_name = "myplot.pdf", +# short_names = ["swc", "si", "swe"], +# spinup_date = start_date + Day(20)) +# ``` + +# To plot comparison data, you first need to get the comparison data +# ```julia +# comparison_data = FluxnetSimulations.get_comparison_data(site_ID, time_offset) +# LandSimVis.make_timeseries( +# simulation; +# short_names = ["swc", "si", "swe"], +# comparison_data) +# ``` + +# The diurnal timeseries plotted is an average diurnal timeseries. We +# interpolate the data or simulation output to an hourly interval, and +# then compute the average of each hour of the day over the entire data. diff --git a/docs/src/tutorials/integrated/snowy_land_fluxnet_tutorial.jl b/docs/src/tutorials/integrated/snowy_land_fluxnet_tutorial.jl new file mode 100644 index 0000000000..1ddc3f7c06 --- /dev/null +++ b/docs/src/tutorials/integrated/snowy_land_fluxnet_tutorial.jl @@ -0,0 +1,140 @@ +# # Fluxnet simulations with the full land model: snow, soil, canopy + +# In the +# [SoilCanopyModel tutorial](docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.md), +# we demonstrated how to run the an integrated model with a soil and +# canopy component at the US-MOz fluxnet site. +# Here we add in a snow component, and run the site at the Niwot Ridge site instead. +# The forcing data was obtained from +# AmeriFlux FLUXNET: https://doi.org/10.17190/AMF/1871141 +# Citation: Peter D. Blanken, Russel K. Monson, Sean P. Burns, +# David R. Bowling, Andrew A. Turnipseed (2022), +# AmeriFlux FLUXNET-1F US-NR1 Niwot Ridge Forest (LTER NWT1), +# Ver. 3-5, AmeriFlux AMP, (Dataset). https://doi.org/10.17190/AMF/1871141 + +# The focus of this tutorial is to learn the steps towards setting up and +# running an integrated simulation, and less on the parameterization +# choices. As such, the default parameters are implicitly set. +# To experiment with modularity in the parameters and parameterizations, please see the [canopy parameterizations tutorial](docs/src/tutorials/standalone/Canopy/changing_canopy_parameterizations.md) or the [soiil parameterizations tutorial](docs/src/tutorials/standalone/Soil/changing_soil_parameterizations.md). + +# # Preliminary Setup +using Dates +import ClimaParams as CP +using ClimaDiagnostics +using ClimaLand +using ClimaLand.Domains: Column +using ClimaLand.Simulations +import ClimaLand.Parameters as LP +using DelimitedFiles +import ClimaLand.FluxnetSimulations as FluxnetSimulations +using CairoMakie, ClimaAnalysis, GeoMakie, Poppler_jll, Printf, StatsBase +import ClimaLand.LandSimVis as LandSimVis; + +# Define the floating point precision desired (64 or 32 bit), and get the +# parameter set holding constants used across CliMA Models. + +const FT = Float32; +earth_param_set = LP.LandParameters(FT); + +# We will use prescribed atmospheric and radiative forcing from the +# US-NR1 tower. We also +# read in the MODIS LAI and let that vary in time in a prescribed manner. +site_ID = "US-NR1"; +site_ID_val = FluxnetSimulations.replace_hyphen(site_ID) +# Get the latitude and longitude in degrees, as well as the +# time offset in hours of local time from UTC +(; time_offset, lat, long) = + FluxnetSimulations.get_location(FT, Val(site_ID_val)); +# Get the height of the sensors in m +(; atmos_h) = FluxnetSimulations.get_fluxtower_height(FT, Val(site_ID_val)); +# Set a start and stop date of the simulation in UTC, as well as +# a timestep in seconds +(start_date, stop_date) = + FluxnetSimulations.get_data_dates(site_ID, time_offset) +Δt = 450.0; + +# Setup the domain for the model. This corresponds to +# a column of 2m in depth, with 10 equally spaced layers. +# The lat and long are provided so that we can look up default parameters +# for this location using the default ClimaLand parameter maps. +zmin = FT(-2) # in m +zmax = FT(0) # in m +domain = Column(; zlim = (zmin, zmax), nelements = 10, longlat = (long, lat)); + +# Forcing data for the site - this uses our interface for working with Fluxnet data +forcing = FluxnetSimulations.prescribed_forcing_fluxnet( + site_ID, + lat, + long, + time_offset, + atmos_h, + start_date, + earth_param_set, + FT, +); +# LAI for the site - this uses our interface for working with MODIS data. +modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; + start_date, + end_date = stop_date, +) +LAI = ClimaLand.prescribed_lai_modis( + modis_lai_ncdata_path, + domain.space.surface, + start_date, +); + +# # Setup the integrated model + +# We want to simulate the canopy-soil-snow system together, so the model type +# [`LandModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/ClimaLand/#Integrated-Land-Model-Types-and-methods) +# is chosen. Here we use the highest level model constructor, which uses default parameters, +# and parameterizations, for the soil, snow, and canopy models. + +land_model = LandModel{FT}(forcing, LAI, earth_param_set, domain, Δt); +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( + site_ID, + start_date, + time_offset, + land_model, +); +output_vars = ["swu", "lwu", "shf", "lhf", "swe", "swc", "si"] +diagnostics = ClimaLand.default_diagnostics( + land_model, + start_date; + output_writer = ClimaDiagnostics.Writers.DictWriter(), + output_vars, + average_period = :hourly, +); + +# How often we want to update the forcing. +data_dt = Second(FluxnetSimulations.get_data_dt(site_ID)); +updateat = Array(start_date:data_dt:stop_date); + +# Now we can construct the simulation object and solve it. +simulation = Simulations.LandSimulation( + start_date, + stop_date, + Δt, # seconds + land_model; + set_ic!, + updateat, + user_callbacks = (), + diagnostics, +); +solve!(simulation); + +# # Plotting results +LandSimVis.make_diurnal_timeseries( + simulation; + short_names = ["shf", "lhf", "swu", "lwu"], + spinup_date = start_date + Day(20), + plot_name = "US_NR1_diurnal_timeseries.pdf", +); +# ![](US_NR1_diurnal_timeseries.pdf) +LandSimVis.make_timeseries( + simulation; + short_names = ["swc", "si", "swe"], + spinup_date = start_date + Day(20), + plot_name = "US_NR1_variable_timeseries.pdf", +); +# ![](US_NR1_variable_timeseries.pdf) diff --git a/docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.jl b/docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.jl new file mode 100644 index 0000000000..64422e2684 --- /dev/null +++ b/docs/src/tutorials/integrated/soil_canopy_fluxnet_tutorial.jl @@ -0,0 +1,136 @@ +# # Fluxnet simulations with an integrated soil and canopy model + +# In the +# [standalone canopy tutorial](docs/src/tutorials/standalone/Canopy/canopy_tutorial.md), +# we demonstrated how to run the canopy model in +# standalone mode using a prescribed soil moisture +# and ground temperature. ClimaLand can also +# integrate the canopy model with a prognostic soil model +# and timestep the two components together to simulate an +# interacting canopy-soil system. This tutorial +# demonstrates how to set that up. +# We use initial conditions, atmospheric and radiative flux conditions, +# and leaf area index observed at the US-MOz flux tower, a flux tower +# located within an oak-hickory forest in Ozark, Missouri, USA. +# The forcing data was obtained from +# AmeriFlux FLUXNET: https://doi.org/10.17190/AMF/1854370 +# Citation: Jeffrey Wood, Lianhong Gu (2025), AmeriFlux FLUXNET-1F US-MOz Missouri Ozark +# Site, Ver. 5-7, AmeriFlux AMP, (Dataset). https://doi.org/10.17190/AMF/1854370 + +# The focus of this tutorial is to learn the steps towards setting up and +# running an integrated simulation, and less on the parameterization +# choices. As such, the default parameters are implicitly set. +# To experiment with modularity in the parameters and parameterizations, please see the [canopy parameterizations tutorial](docs/src/tutorials/standalone/Canopy/changing_canopy_parameterizations.md) or the [soiil parameterizations tutorial](docs/src/tutorials/standalone/Soil/changing_soil_parameterizations.md). + +# # Preliminary Setup +using Dates +import ClimaParams as CP +using ClimaDiagnostics +using ClimaLand +using ClimaLand.Domains: Column +using ClimaLand.Simulations +import ClimaLand.Parameters as LP +using DelimitedFiles +import ClimaLand.FluxnetSimulations as FluxnetSimulations +using CairoMakie, ClimaAnalysis, GeoMakie, Poppler_jll, Printf, StatsBase +import ClimaLand.LandSimVis as LandSimVis; + +# Define the floating point precision desired (64 or 32 bit), and get the +# parameter set holding constants used across CliMA Models. + +const FT = Float32; +earth_param_set = LP.LandParameters(FT); + +# We will use prescribed atmospheric and radiative forcing from the +# US-MOz tower. +site_ID = "US-MOz"; +site_ID_val = FluxnetSimulations.replace_hyphen(site_ID) +# Get the latitude and longitude in degrees, as well as the +# time offset in hours of local time from UTC +(; time_offset, lat, long) = + FluxnetSimulations.get_location(FT, Val(site_ID_val)); +# Get the height of the sensors in m +(; atmos_h) = FluxnetSimulations.get_fluxtower_height(FT, Val(site_ID_val)); + +# Setup the domain for the model. This corresponds to +# a column of 2m in depth, with 10 equally spaced layers. +# The lat and long are provided so that we can look up default parameters +# for this location using the default ClimaLand parameter maps. +zmin = FT(-2) # in m +zmax = FT(0) # in m +domain = Column(; zlim = (zmin, zmax), nelements = 10, longlat = (long, lat)); + +# Set a start and stop date of the simulation in UTC, as well as +# a timestep in seconds +start_date = DateTime("2010-05-01", "yyyy-mm-dd") +stop_date = DateTime("2010-09-01", "yyyy-mm-dd") +Δt = 450.0; + +# Forcing data for the site - this uses our interface for working with Fluxnet data +forcing = FluxnetSimulations.prescribed_forcing_fluxnet( + site_ID, + lat, + long, + time_offset, + atmos_h, + start_date, + earth_param_set, + FT, +); +# LAI for the site - this uses our interface for working with MODIS data. +modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; + start_date, + end_date = stop_date, +) +LAI = ClimaLand.prescribed_lai_modis( + modis_lai_ncdata_path, + domain.space.surface, + start_date, +); + +# # Setup the integrated model + +# We want to simulate the canopy-soil system together, so we pick the model type +# [`SoilCanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/ClimaLand/#Integrated-Land-Model-Types-and-methods) +# Here we use the highest level model constructor, which uses default parameters, +# and parameterizations, for the soil and canopy models. +land_model = SoilCanopyModel{FT}(forcing, LAI, earth_param_set, domain); +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( + site_ID, + start_date, + time_offset, + land_model, +); +output_vars = ["gpp", "swu", "lwu", "shf", "lhf"] +diagnostics = ClimaLand.default_diagnostics( + land_model, + start_date; + output_writer = ClimaDiagnostics.Writers.DictWriter(), + output_vars, + average_period = :hourly, +); + +# How often we want to update the forcing. +data_dt = Second(FluxnetSimulations.get_data_dt(site_ID)); +updateat = Array(start_date:data_dt:stop_date); + +simulation = Simulations.LandSimulation( + start_date, + stop_date, + Δt, # seconds + land_model; + set_ic!, + updateat, + user_callbacks = (), + diagnostics, +); +solve!(simulation); + +# # Plotting results, ignoring the first 20 days as spinup +LandSimVis.make_diurnal_timeseries( + simulation; + short_names = ["gpp", "shf", "lhf", "swu", "lwu"], + spinup_date = start_date + Day(20), + plot_name = "US_MOz_diurnal_timeseries.pdf", +); +# ![](US_MOz_diurnal_timeseries.pdf) diff --git a/docs/src/tutorials/integrated/soil_canopy_tutorial.jl b/docs/src/tutorials/integrated/soil_canopy_tutorial.jl deleted file mode 100644 index f6cd4e755b..0000000000 --- a/docs/src/tutorials/integrated/soil_canopy_tutorial.jl +++ /dev/null @@ -1,459 +0,0 @@ -# # Coupling the CliMA Canopy and Soil Hydraulics Models - -# In the -# [`previous tutorial`](@ref https://clima.github.io/ClimaLand.jl/dev/generated/soil_plant_hydrology_tutorial/), -# we demonstrated how to run the canopy model in -# standalone mode using prescribed values for the inputs of soil hydraulics -# into the canopy hydraulics model. However, ClimaLand has the built-in capacity -# to couple the canopy model with a soil physics model and timestep the two -# simulations together to model a canopy-soil system. This tutorial -# demonstrates how to setup and run a coupled simulation, again using -# initial conditions, atmospheric and radiative flux conditions, and canopy -# properties observed at the US-MOz flux tower, a flux tower located within an -# oak-hickory forest in Ozark, Missouri, USA. See [Wang et al. 2021] -# (https://doi.org/10.5194/gmd-14-6741-2021) for details on the site and -# parameters. - - -# In ClimaLand, the coupling of the canopy and soil models is done by -# pairing the inputs and outputs which between the two models so that they match. -# For example, the root extraction of the canopy hydraulics model, which acts as a -# boundary flux for the plant system, is paired with a source term for root extraction in -# the soil model, so that the flux of water from the soil into the roots is -# equal and factored into both models. This pairing is done automatically in the -# constructor for a -# [`SoilCanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/ClimaLand/#LSM-Model-Types-and-methods) -# so that a -# user needs only specify the necessary arguments for each of the component -# models, and the two models will automatically be paired into a coupled -# simulation. - -# # Preliminary Setup - -# Load External Packages: - -import SciMLBase -using Plots -using Statistics -using Dates -using Insolation - - -# Load CliMA Packages and ClimaLand Modules: - -using ClimaCore -import ClimaParams as CP -import ClimaTimeSteppers as CTS -using ClimaLand -using ClimaLand.Domains: Column, obtain_surface_domain -using ClimaLand.Soil -using ClimaLand.Soil.Biogeochemistry -using ClimaLand.Canopy -using ClimaLand.Canopy.PlantHydraulics -import ClimaLand.Simulations: LandSimulation, solve! -import ClimaLand -import ClimaLand.Parameters as LP -using DelimitedFiles -import ClimaLand.FluxnetSimulations as FluxnetSimulations - -# Define the floating point precision desired (64 or 32 bit), and get the -# parameter set holding constants used across CliMA Models: - -const FT = Float32; -earth_param_set = LP.LandParameters(FT); - -# First provide some information about the site -site_ID = "US-MOz" -# Timezone (offset from UTC in hrs) -time_offset = 7 -start_date = DateTime(2010) + Hour(time_offset) + Day(150) # start mid year -# Specify the time range and dt value over which to perform the simulation. -N_days = 100 -end_date = start_date + Day(N_days) -dt = Float64(30) - -# Site latitude and longitude -lat = FT(38.7441) # degree -long = FT(-92.2000) # degree - -# Height of the sensor at the site -atmos_h = FT(32) # m - - -# - We will be using prescribed atmospheric and radiative drivers from the -# US-MOz tower, which we read in here. We are using prescribed -# atmospheric and radiative flux conditions, but it is also possible to couple -# the simulation with atmospheric and radiative flux models. We also -# read in the observed LAI and let that vary in time in a prescribed manner. - -# Forcing data -(; atmos, radiation) = FluxnetSimulations.prescribed_forcing_fluxnet( - site_ID, - lat, - long, - time_offset, - atmos_h, - start_date, - earth_param_set, - FT, -); - -# Setup the domain for the model: - -nelements = 10 -zmin = FT(-2) -zmax = FT(0) -domain = - Column(; zlim = (zmin, zmax), nelements = nelements, longlat = (long, lat)); - -# # Setup the Coupled Canopy and Soil Physics Model - -# We want to simulate the canopy-soil system together, so the model type -# [`SoilCanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/ClimaLand/#LSM-Model-Types-and-methods) -# is chosen. -# From the linked documentation, we see that we need to provide the soil model -# type and arguments as well as the canopy model component types, component -# arguments, and the canopy model arguments, so we first need to initialize -# all of these. -prognostic_land_components = (:canopy, :soil, :soilco2); - -# For our soil model, we will choose the -# [`EnergyHydrology`](https://clima.github.io/ClimaLand.jl/dev/APIs/Soil/#Soil-Models-2) -# and set up all the necessary arguments. See the -# [tutorial](https://clima.github.io/ClimaLand.jl/dev/generated/Soil/soil_energy_hydrology/) -# on the model for a more detailed explanation of the soil model. - -# Define the parameters for the soil model and provide them to the model constructor. - -# Soil parameters -soil_ν = FT(0.5) # m3/m3 -soil_K_sat = FT(4e-7) # m/s -soil_S_s = FT(1e-3) # 1/m -soil_vg_n = FT(2.05) # unitless -soil_vg_α = FT(0.04) # inverse meters -θ_r = FT(0.067); # m3/m3 -ν_ss_quartz = FT(0.1) -ν_ss_om = FT(0.1) -ν_ss_gravel = FT(0.0); - -z_0m_soil = FT(0.1) -z_0b_soil = FT(0.1) -soil_ϵ = FT(0.98) -soil_α_PAR = FT(0.2) -soil_α_NIR = FT(0.4) - -soil_albedo = ClimaLand.Soil.ConstantTwoBandSoilAlbedo{FT}(; - PAR_albedo = soil_α_PAR, - NIR_albedo = soil_α_NIR, -) -runoff_model = ClimaLand.Soil.Runoff.NoRunoff() - -soil = EnergyHydrology{FT}( - domain, - (; atmos, radiation), - earth_param_set; - prognostic_land_components, - albedo = soil_albedo, - runoff = runoff_model, - additional_sources = (ClimaLand.RootExtraction{FT}(),), - retention_parameters = (; - ν = soil_ν, - θ_r, - K_sat = soil_K_sat, - hydrology_cm = vanGenuchten{FT}(; α = soil_vg_α, n = soil_vg_n), - ), - composition_parameters = (; ν_ss_om, ν_ss_quartz, ν_ss_gravel), - S_s = soil_S_s, - z_0m = z_0m_soil, - z_0b = z_0b_soil, - emissivity = soil_ϵ, -); - -# For the heterotrophic respiration model, see the -# [documentation](https://clima.github.io/ClimaLand.jl/previews/PR214/dynamicdocs/pages/soil_biogeochemistry/microbial_respiration/) -# to understand the parameterisation. -# The domain is defined similarly to the soil domain described above. -soil_organic_carbon = - ClimaLand.PrescribedSoilOrganicCarbon{FT}(TimeVaryingInput((t) -> 5)); -co2_prognostic_soil = Soil.Biogeochemistry.PrognosticMet(soil.parameters); -drivers = Soil.Biogeochemistry.SoilDrivers( - co2_prognostic_soil, - soil_organic_carbon, - atmos, -); -soilco2 = Soil.Biogeochemistry.SoilCO2Model{FT}(domain, drivers); - -# Read in prescribed LAI at the site from global MODIS data -surface_space = domain.space.surface; -modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; - start_date = start_date, - end_date = end_date, -); -LAI = ClimaLand.prescribed_lai_modis( - modis_lai_ncdata_path, - surface_space, - start_date, -); -# Get the maximum LAI at this site over the first year of the simulation -maxLAI = - FluxnetSimulations.get_maxLAI_at_site(modis_lai_ncdata_path[1], lat, long); - -# For a coupled SoilCanopyModel, we provide a flag to the canopy that indicates -# the ground forcing is prognostic (i.e. the soil model) rather than prescribed. -ground = ClimaLand.PrognosticSoilConditions{FT}(); - -# Next we need to set up the [`CanopyModel`](https://clima.github.io/ClimaLand.jl/dev/APIs/canopy/Canopy/#Canopy-Model-Structs). -# For more details on the specifics of this model see the previous tutorial. -surface_domain = ClimaLand.Domains.obtain_surface_domain(domain); - -# Let's overwrite some default parameters for the canopy model components. -# This involves constructing the components individually and then -# passing them to the canopy model constructor. - -# Canopy conductance -conductance = Canopy.MedlynConductanceModel{FT}(surface_domain; g1 = 141); - -# Canopy radiative transfer -radiation_parameters = (; - G_Function = ConstantGFunction(FT(0.5)), - α_PAR_leaf = 0.1, - α_NIR_leaf = 0.45, - τ_PAR_leaf = 0.05, - τ_NIR_leaf = 0.25, - Ω = 0.69, -); -radiative_transfer = TwoStreamModel{FT}(surface_domain; radiation_parameters); - -# Canopy photosynthesis -photosynthesis_parameters = (; is_c3 = FT(1), Vcmax25 = FT(5e-5)); -photosynthesis = FarquharModel{FT}(surface_domain; photosynthesis_parameters); - -# Canopy hydraulics -n_stem = Int64(1) -n_leaf = Int64(1) -h_stem = FT(9) -h_leaf = FT(9.5) -f_root_to_shoot = FT(3.5) -plant_ν = FT(0.7) -plant_S_s = FT(1e-2 * 0.0098) -SAI = FT(0.00242) -RAI = (SAI + maxLAI) * f_root_to_shoot; -K_sat_plant = FT(1.8e-8) -ψ63 = FT(-4 / 0.0098) -Weibull_param = FT(4) -conductivity_model = - PlantHydraulics.Weibull{FT}(K_sat_plant, ψ63, Weibull_param) -hydraulics = Canopy.PlantHydraulicsModel{FT}( - surface_domain, - LAI; - SAI, - RAI, - n_stem, - n_leaf, - h_stem, - h_leaf, - ν = plant_ν, - S_s = plant_S_s, - conductivity_model, - rooting_depth = FT(1), -) - -canopy = ClimaLand.Canopy.CanopyModel{FT}( - surface_domain, - (; atmos, radiation, ground), - LAI, - earth_param_set; - prognostic_land_components = (:canopy, :soil, :soilco2), - conductance, - radiative_transfer, - photosynthesis, - hydraulics, -); - -# Now we can combine the soil and canopy models into a single combined model. -land = SoilCanopyModel{FT}(soilco2, soil, canopy); - -# We need to provide initial conditions for the model: -function set_ic!(Y, p, t0, model) - Y.soil.ϑ_l = FT(0.4) - Y.soil.θ_i = FT(0.0) - T_0 = FT(288.7) - ρc_s = - volumetric_heat_capacity.( - Y.soil.ϑ_l, - Y.soil.θ_i, - land.soil.parameters.ρc_ds, - earth_param_set, - ) - Y.soil.ρe_int = - volumetric_internal_energy.(Y.soil.θ_i, ρc_s, T_0, earth_param_set) - - Y.soilco2.C .= FT(0.000412) # set to atmospheric co2, mol co2 per mol air - - canopy_retention_model = canopy.hydraulics.parameters.retention_model - ψ_stem_0 = FT(-1e5 / 9800) - ψ_leaf_0 = FT(-2e5 / 9800) - - S_l_ini = - inverse_water_retention_curve.( - canopy_retention_model, - [ψ_stem_0, ψ_leaf_0], - plant_ν, - plant_S_s, - ) - for i in 1:2 - Y.canopy.hydraulics.ϑ_l.:($i) .= - augmented_liquid_fraction.(plant_ν, S_l_ini[i]) - end - evaluate!(Y.canopy.energy.T, atmos.T, t0) -end - -# Choose the timestepper and solver needed for the problem. -timestepper = CTS.ARS343() -ode_algo = CTS.IMEXAlgorithm( - timestepper, - CTS.NewtonsMethod( - max_iters = 1, - update_j = CTS.UpdateEvery(CTS.NewNewtonIteration), - ), -); - - -# Set the callbacks update times, which govern -# how often we save output, and how often we update -# the forcing data ("drivers") - -n = 120 -saveat = Array(start_date:Second(n * dt):end_date); -sv = (; - t = Array{DateTime}(undef, length(saveat)), - saveval = Array{NamedTuple}(undef, length(saveat)), -) -saving_cb = ClimaLand.NonInterpSavingCallback(sv, saveat) -updateat = Array(start_date:Second(1800):end_date); - -# Create the LandSimulation object, which will also create and initialize the state vectors, -# the cache, the driver callbacks, and set the initial conditions. -simulation = LandSimulation( - start_date, - end_date, - dt, - land; - set_ic! = set_ic!, - updateat = updateat, - solver_kwargs = (; saveat = deepcopy(saveat)), - timestepper = ode_algo, - user_callbacks = (saving_cb,), - diagnostics = (), -); - -sol = solve!(simulation); - -# # Plotting - -# Now that we have both a soil and canopy model incorporated together, we will -# show how to plot some model data demonstrating the time series produced from -# each of these models. As before, we may plot the GPP of the system as well -# as transpiration showing fluxes in the canopy. - -daily = FT.(sol.t) ./ 3600 ./ 24 -model_GPP = [ - parent(sv.saveval[k].canopy.photosynthesis.GPP)[1] for - k in 1:length(sv.saveval) -] - -plt1 = Plots.plot(size = (600, 700)); -Plots.plot!( - plt1, - daily, - model_GPP .* 1e6, - label = "Model", - xlim = [minimum(daily), maximum(daily)], - xlabel = "days", - ylabel = "GPP [μmol/mol]", -); - -# Transpiration plot: - -T = [ - parent(sv.saveval[k].canopy.turbulent_fluxes.transpiration)[1] for - k in 1:length(sv.saveval) -] -T = T .* (1e3 * 24 * 3600) - -plt2 = Plots.plot(size = (500, 700)); -Plots.plot!( - plt2, - daily, - T, - label = "Model", - xlim = [minimum(daily), maximum(daily)], - xlabel = "days", - ylabel = "Vapor Flux [mm/day]", -); - -# Show the two plots together: - -Plots.plot(plt1, plt2, layout = (2, 1)); - -# Save the output: -savefig("ozark_canopy_flux_test.png"); -# ![](ozark_canopy_flux_test.png) - -# Now, we will plot the augmented volumetric liquid water fraction at different -# depths in the soil over the course of the simulation. - -plt1 = Plots.plot(size = (500, 700)); -ϑ_l_10 = [parent(sol.u[k].soil.ϑ_l)[end] for k in 1:1:length(sol.t)] -plt1 = Plots.plot( - daily, - ϑ_l_10, - label = "10 cm", - xlabel = "Days", - ylabel = "SWC [m/m]", - xlim = [minimum(daily), maximum(daily)], - size = (500, 700), - margins = 10Plots.mm, - color = "blue", -); - -plot!( - plt1, - daily, - [parent(sol.u[k].soil.ϑ_l)[end - 1] for k in 1:1:length(sol.t)], - label = "20cm", - color = "red", -); - -plot!( - plt1, - daily, - [parent(sol.u[k].soil.ϑ_l)[end - 2] for k in 1:1:length(sol.t)], - label = "30cm", - color = "purple", -); - -# Save the output: -savefig("ozark_soil_test.png"); -# ![](ozark_soil_test.png) - -# And now to demonstrate the coupling of the soil and canopy models we will plot -# the water fluxes from the soil up into the plant hydraulic system: - -root_stem_flux = [ - sum(sv.saveval[k].root_extraction) .* (1e3 * 3600 * 24) for - k in 1:length(sol.t) -] -plt1 = Plots.plot( - daily, - root_stem_flux, - label = "soil-root-stem water flux", - ylabel = "Water flux[mm/day]", - xlim = [minimum(daily), maximum(daily)], - size = (500, 700), - margins = 10Plots.mm, -); - -# And save the output -savefig("ozark_soil_plant_flux.png"); -# ![](ozark_soil_plant_flux.png) diff --git a/docs/src/tutorials/shared_utilities/driver_tutorial.jl b/docs/src/tutorials/shared_utilities/driver_tutorial.jl index b0e5482e2f..37261d97f2 100644 --- a/docs/src/tutorials/shared_utilities/driver_tutorial.jl +++ b/docs/src/tutorials/shared_utilities/driver_tutorial.jl @@ -67,7 +67,8 @@ seconds = 0:data_dt:((length(local_datetime) - 1) * data_dt); T = @. 298.15 + 5.0 * sin(2π * (seconds - 3600 * 6) / (3600 * 24)); LW_d = 5.67 * 10^(-8) .* T .^ 4; SW_d = @. max(1400 * sin(2π * (seconds - 3600 * 6) / (3600 * 24)), 0.0); -diffuse_fraction = 0.5 .+ zeros(length(seconds)) +diffuse_fraction = 0.5 .+ zeros(length(seconds)); + # Next, fit interpolators to the data. These interpolators are what are stored in # the driver function. Then we can evaluate the radiative forcing # at any simulation time (and not just at times coinciding with measurements). diff --git a/docs/src/tutorials/standalone/Canopy/changing_canopy_parameterizations.jl b/docs/src/tutorials/standalone/Canopy/changing_canopy_parameterizations.jl new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/docs/src/tutorials/standalone/Canopy/changing_canopy_parameterizations.jl @@ -0,0 +1 @@ + diff --git a/docs/src/tutorials/standalone/Soil/changing_soil_parameterizations.jl b/docs/src/tutorials/standalone/Soil/changing_soil_parameterizations.jl new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/docs/src/tutorials/standalone/Soil/changing_soil_parameterizations.jl @@ -0,0 +1 @@ + diff --git a/experiments/integrated/fluxnet/ozark_pft.jl b/experiments/integrated/fluxnet/ozark_pft.jl index aab7f719c7..cca540d114 100644 --- a/experiments/integrated/fluxnet/ozark_pft.jl +++ b/experiments/integrated/fluxnet/ozark_pft.jl @@ -297,19 +297,12 @@ canopy = Canopy.CanopyModel{FT}( # Integrated plant hydraulics and soil model land = SoilCanopyModel{FT}(soilco2, soil, canopy) - - - - - -set_ic!(Y, _, _, model) = FluxnetSimulations.set_fluxnet_ic!( - Y, +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( site_ID, start_date, time_offset, - model, + land, ) - # Callbacks output_writer = ClimaDiagnostics.Writers.DictWriter() diff --git a/experiments/integrated/fluxnet/ozark_soilsnow.jl b/experiments/integrated/fluxnet/ozark_soilsnow.jl index 73f5635ad1..5256bb0083 100644 --- a/experiments/integrated/fluxnet/ozark_soilsnow.jl +++ b/experiments/integrated/fluxnet/ozark_soilsnow.jl @@ -160,12 +160,11 @@ snow_model = Snow.SnowModel( land = ClimaLand.SoilSnowModel{FT}(; snow = snow_model, soil = soil_model) # Initial conditions -set_ic!(Y, p, _, model) = FluxnetSimulations.set_fluxnet_ic!( - Y, +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( site_ID, start_date, time_offset, - model, + land, ) saveat = Array(start_date:Second(dt):end_date) diff --git a/experiments/integrated/fluxnet/run_fluxnet.jl b/experiments/integrated/fluxnet/run_fluxnet.jl index ca84627e99..10aeaa078c 100644 --- a/experiments/integrated/fluxnet/run_fluxnet.jl +++ b/experiments/integrated/fluxnet/run_fluxnet.jl @@ -263,18 +263,13 @@ snow = Snow.SnowModel( # Integrated plant hydraulics, soil, and snow model land = LandModel{FT}(canopy, snow, soil, soilco2); - - -set_ic!(Y, p, _, model) = FluxnetSimulations.set_fluxnet_ic!( - Y, +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( site_ID, start_date, time_offset, - model, + land, ) - - # Callbacks output_vars = [ "sif", @@ -305,14 +300,14 @@ diags = ClimaLand.default_diagnostics( ## How often we want to update the drivers. data_dt = Second(FluxnetSimulations.get_data_dt(site_ID)) - updateat = Array(start_date:data_dt:end_date) + simulation = LandSimulation( start_date, end_date, dt, land; - set_ic! = set_ic!, + set_ic!, updateat, diagnostics = diags, ) diff --git a/experiments/integrated/performance/conservation/ozark_conservation_setup.jl b/experiments/integrated/performance/conservation/ozark_conservation_setup.jl index 5a00d9527c..addea74b7f 100644 --- a/experiments/integrated/performance/conservation/ozark_conservation_setup.jl +++ b/experiments/integrated/performance/conservation/ozark_conservation_setup.jl @@ -225,5 +225,11 @@ Y, p, cds = initialize(land) jac_kwargs = (; jac_prototype = ClimaLand.FieldMatrixWithSolver(Y), Wfact = jacobian!); -FluxnetSimulations.set_fluxnet_ic!(Y, site_ID, start_date, time_offset, land) +set_ic! = FluxnetSimulations.make_set_fluxnet_initial_conditions( + site_ID, + start_date, + time_offset, + land, +) +set_ic!(Y, p, t0, land) set_initial_cache!(p, Y, t0) diff --git a/ext/FluxnetSimulationsExt.jl b/ext/FluxnetSimulationsExt.jl index 20a49e84eb..2ec5060846 100644 --- a/ext/FluxnetSimulationsExt.jl +++ b/ext/FluxnetSimulationsExt.jl @@ -13,7 +13,7 @@ using ClimaLand using ClimaLand.Canopy using ClimaLand.PlantHydraulics export prescribed_forcing_fluxnet, - set_fluxnet_ic!, + make_set_fluxnet_initial_conditions, get_comparison_data, get_data_dates, get_data_dt, diff --git a/ext/LandSimulationVisualizationExt.jl b/ext/LandSimulationVisualizationExt.jl index 352bb04c7d..d30dd26d68 100644 --- a/ext/LandSimulationVisualizationExt.jl +++ b/ext/LandSimulationVisualizationExt.jl @@ -6,7 +6,7 @@ import ClimaAnalysis import ClimaAnalysis.Visualize as viz using CairoMakie import GeoMakie -import ClimaUtilities.TimeManager: ITime +import ClimaUtilities.TimeManager: ITime, date using Dates import NCDatasets using ClimaLand diff --git a/ext/fluxnet_simulations/initial_conditions.jl b/ext/fluxnet_simulations/initial_conditions.jl index 466bd2984d..75271a5e5d 100644 --- a/ext/fluxnet_simulations/initial_conditions.jl +++ b/ext/fluxnet_simulations/initial_conditions.jl @@ -1,3 +1,30 @@ +""" + FluxnetSimulations.make_set_fluxnet_initial_conditions( + site_ID, + start_date, + hour_offset_from_UTC, + model, + ) + +Creates and returns a function `set_ic!(Y,p,t,model)` which +updates `Y` in place with an estimated set of initial conditions +based on the fluxnet observations at `site_ID` at the `start_date` in UTC, +and the type of the `model`. +In order to convert between local time and UTC, the hour offset from +UTC is required. +""" +function FluxnetSimulations.make_set_fluxnet_initial_conditions( + site_ID, + start_date, + hour_offset_from_UTC, + model, +) + set_ic!(Y, p, t, model) = + set_fluxnet_ic!(Y, site_ID, start_date, hour_offset_from_UTC, model) + return set_ic! +end + + """ set_fluxnet_ic!( Y, @@ -13,7 +40,7 @@ is provided in local time, we require the offset from UTC in hours `hour_offset_ The `model` indicates which how to update it `Y` from these observations, via different methods of `set_fluxnet_ic!`. """ -function FluxnetSimulations.set_fluxnet_ic!( +function set_fluxnet_ic!( Y, site_ID, start_date, @@ -27,13 +54,7 @@ function FluxnetSimulations.set_fluxnet_ic!( UTC_datetime = local_datetime .+ Dates.Hour(hour_offset_from_UTC) Δ_date = UTC_datetime .- start_date for component in ClimaLand.land_components(model) - FluxnetSimulations.set_fluxnet_ic!( - Y, - data, - columns, - Δ_date, - getproperty(model, component), - ) + set_fluxnet_ic!(Y, data, columns, Δ_date, getproperty(model, component)) end end @@ -41,7 +62,7 @@ end set_fluxnet_ic!(Y, data, columns, Δ_date, model::ClimaLand.Soil.EnergyHydrology) Sets the values of Y.soil in place with: -- \vartheta_l: observed value of SWC at the surface at the observation date closest to the start date +- \vartheta_l: observed value of SWC at the surface at the observation date closest to the start date, unless this is larger than 90% of porosity. - θ_i: no ice (θ_i = 0) - \rho e_int: an internal energy computed using the above θ_l, θ_i, and the temperature of the soil in the first layer, at the observation date closest to the start date. If the soil @@ -53,7 +74,7 @@ a CSV file, `columns` is the list of column names, start date (in UTC), and `model` indicates which part of `Y` we are updating, and how to update it, via different methods of `set_fluxnet_ic!`. """ -function FluxnetSimulations.set_fluxnet_ic!( +function set_fluxnet_ic!( Y, data, columns, @@ -66,20 +87,25 @@ function FluxnetSimulations.set_fluxnet_ic!( column_name_map = Dict( varname => findfirst(columns[:] .== varname) for varname in varnames ) - + FT = eltype(Y.soil.ρe_int) if isnothing(column_name_map["SWC_F_MDS_1"]) θ_l_0 = model.parameters.ν / 2 elseif unique(data[:, column_name_map["SWC_F_MDS_1"]]) == val θ_l_0 = model.parameters.ν / 2 else - θ_l_0 = get_data_at_start_date( - data[:, column_name_map["SWC_F_MDS_1"]], - Δ_date; - preprocess_func = x -> x / 100, - val, - ) + θ_l_0 = + min.( + FT( + get_data_at_start_date( + data[:, column_name_map["SWC_F_MDS_1"]], + Δ_date; + preprocess_func = x -> x / 100, + val, + ), + ), + model.parameters.ν .* FT(0.9), + ) end - Y.soil.ϑ_l .= θ_l_0 Y.soil.θ_i .= 0 @@ -113,7 +139,6 @@ function FluxnetSimulations.set_fluxnet_ic!( model.parameters.ρc_ds, model.parameters.earth_param_set, ) - FT = eltype(Y.soil.ρe_int) Y.soil.ρe_int = ClimaLand.Soil.volumetric_internal_energy.( Y.soil.θ_i, @@ -133,7 +158,7 @@ of the plant. If ony a leaf compartment is used, only the leaf ψ is used. """ -function FluxnetSimulations.set_fluxnet_ic!( +function set_fluxnet_ic!( Y, data, columns, @@ -183,7 +208,7 @@ Sets Y.snow.S, Y.snow.S_l, and Y.snow.U in place to be zero at the start of the Note that the Snow NeuralDensity model has additional prognostic variables which also must be set to zero; another method may work well for that case. """ -function FluxnetSimulations.set_fluxnet_ic!( +function set_fluxnet_ic!( Y, data, columns, @@ -200,7 +225,7 @@ end Sets Y.soilco2.C in place with the atmospheric CO2 concentration, in mol co2 per mol air. """ -function FluxnetSimulations.set_fluxnet_ic!( +function set_fluxnet_ic!( Y, data, columns, diff --git a/ext/land_sim_vis/plotting_utils.jl b/ext/land_sim_vis/plotting_utils.jl index befa230b56..d6cb7aa92d 100644 --- a/ext/land_sim_vis/plotting_utils.jl +++ b/ext/land_sim_vis/plotting_utils.jl @@ -322,6 +322,33 @@ function make_ocean_masked_annual_timeseries( return nothing end +""" + time_to_date(t::AbstractFloat, start_date) + +Converts a time since the start_date (measured in seconds) +to a date. +""" +function time_to_date(t::AbstractFloat, start_date) + return start_date + Dates.Millisecond(round(1_000 * t)) +end + +""" + time_to_date(t::ITime, start_date) + +Converts an ITime to a date using the epoch +of the Itime, the counter, and the period (unit) +of the counter. + +Although the epoch can be different from the start_date, +we usually think of the simulation time as relative to the start_date, +and so we warn here if that is not the case +""" +function time_to_date(t::ITime, start_date) + start_date != t.epoch && + @warn("$(start_date) is different from the simulation time epoch.") + return isnothing(t.epoch) ? start_date + t.counter * t.period : date(t) +end + """ make_diurnal_timeseries( savedir, @@ -368,8 +395,8 @@ function LandSimVis.make_diurnal_timeseries( diagnostics[1].output_writer, dn, ) - save_Δt = model_time[2] - model_time[1] # in seconds - model_dates = Second.(float.(model_time)) .+ start_date + save_Δt = model_time[2] - model_time[1] # in seconds since the start_date. if model_time is an Itime, the epoch should be start_date + model_dates = time_to_date.(model_time, start_date) spinup_idx = findfirst(spinup_date .<= model_dates) hour_of_day, model_diurnal_cycle = compute_diurnal_cycle( model_dates[spinup_idx:end], @@ -486,7 +513,7 @@ function LandSimVis.make_timeseries( dn, ) save_Δt = model_time[2] - model_time[1] # in seconds - model_dates = Second.(float.(model_time)) .+ start_date + model_dates = time_to_date.(model_time, start_date) spinup_idx = findfirst(spinup_date .<= model_dates) hour_of_day, model_diurnal_cycle = compute_diurnal_cycle( model_dates[spinup_idx:end], diff --git a/src/diagnostics/Diagnostics.jl b/src/diagnostics/Diagnostics.jl index d1ce2e93d1..9a2f4fb9bd 100644 --- a/src/diagnostics/Diagnostics.jl +++ b/src/diagnostics/Diagnostics.jl @@ -1,6 +1,6 @@ module Diagnostics -import Dates: Month, Period +import Dates: Month, Period, DateTime import ClimaComms using ClimaCore: Spaces, Fields diff --git a/src/diagnostics/default_diagnostics.jl b/src/diagnostics/default_diagnostics.jl index 1bfe032734..c23e70ad31 100644 --- a/src/diagnostics/default_diagnostics.jl +++ b/src/diagnostics/default_diagnostics.jl @@ -49,6 +49,12 @@ end include("standard_diagnostic_frequencies.jl") +default_diagnostics( + model::ClimaLand.AbstractModel, + start_date::ITime{<:Any, <:Any, <:DateTime}, + outdir, +) = default_diagnostics(model, date(start_date), outdir) + # The default diagnostics currently require a start date because they use Dates.Period. default_diagnostics( model::ClimaLand.AbstractModel, diff --git a/src/ext/FluxnetSimulations.jl b/src/ext/FluxnetSimulations.jl index 47cf996391..56784e1a79 100644 --- a/src/ext/FluxnetSimulations.jl +++ b/src/ext/FluxnetSimulations.jl @@ -4,7 +4,7 @@ function prescribed_forcing_fluxnet end function prescribed_LAI_fluxnet end -function set_fluxnet_ic! end +function make_set_fluxnet_initial_conditions end function get_data_dt end diff --git a/src/integrated/soil_canopy_model.jl b/src/integrated/soil_canopy_model.jl index e520660ca0..365a5e158d 100644 --- a/src/integrated/soil_canopy_model.jl +++ b/src/integrated/soil_canopy_model.jl @@ -75,6 +75,85 @@ struct SoilCanopyModel{ end end +""" + SoilCanopyModel{FT}( + forcing, + LAI, + earth_param_set, + domain::Union{ClimaLand.Domains.Column, ClimaLand.Domains.SphericalShell}; + soil = Soil.EnergyHydrology{FT}( + domain, + forcing, + earth_param_set; + prognostic_land_components = (:canopy, :soil, :soilco2), + additional_sources = (ClimaLand.RootExtraction{FT}(),), + ), + soilco2 = Soil.Biogeochemistry.SoilCO2Model{FT}( + domain, + Soil.Biogeochemistry.SoilDrivers( + Soil.Biogeochemistry.PrognosticMet(soil.parameters), + PrescribedSoilOrganicCarbon{FT}(TimeVaryingInput((t) -> 5)), + forcing.atmos, + ), + ), + canopy = Canopy.CanopyModel{FT}( + Domains.obtain_surface_domain(domain), + (; + atmos = forcing.atmos, + radiation = forcing.radiation, + ground = ClimaLand.PrognosticSoilConditions{FT}(), + ), + LAI, + earth_param_set; + prognostic_land_components = (:canopy, :soil, :soilco2), + ), + ) where {FT} + +A convenience constructor for setting up the default SoilCanpyModel, +where all the parameterizations and parameter values are set to default values +or passed in via the `earth_param_set`. The boundary conditions of all models +correspond to `forcing` with the atmosphere, as specified by `forcing`, a NamedTuple +of the form (;atmos, radiation), with `atmos` an AbstractAtmosphericDriver and `radiation` +and AbstractRadiativeDriver. The leaf area index `LAI` must be provided (prescribed) +as a TimeVaryingInput, and the domain must be a ClimaLand domain with a vertical extent. +""" +function SoilCanopyModel{FT}( + forcing, + LAI, + earth_param_set, + domain::Union{ClimaLand.Domains.Column, ClimaLand.Domains.SphericalShell}; + soil = Soil.EnergyHydrology{FT}( + domain, + forcing, + earth_param_set; + prognostic_land_components = (:canopy, :soil, :soilco2), + additional_sources = (ClimaLand.RootExtraction{FT}(),), + ), + soilco2 = Soil.Biogeochemistry.SoilCO2Model{FT}( + domain, + Soil.Biogeochemistry.SoilDrivers( + Soil.Biogeochemistry.PrognosticMet(soil.parameters), + PrescribedSoilOrganicCarbon{FT}(TimeVaryingInput((t) -> 5)), + forcing.atmos, + ), + ), + canopy = Canopy.CanopyModel{FT}( + Domains.obtain_surface_domain(domain), + (; + atmos = forcing.atmos, + radiation = forcing.radiation, + ground = ClimaLand.PrognosticSoilConditions{FT}(), + ), + LAI, + earth_param_set; + prognostic_land_components = (:canopy, :soil, :soilco2), + ), +) where {FT} + return SoilCanopyModel{FT}(soilco2, soil, canopy) +end + + + """ SoilCanopyModel{FT}(; soilco2_type::Type{MM}, diff --git a/src/shared_utilities/Domains.jl b/src/shared_utilities/Domains.jl index 94555443af..52df523c0c 100644 --- a/src/shared_utilities/Domains.jl +++ b/src/shared_utilities/Domains.jl @@ -1167,7 +1167,7 @@ apply_threshold(field, value) = """ landsea_mask( surface_space; - filepath = ClimaLand.Artifacts.landseamask_file_path(; + filepath = landseamask_file_path(; context = ClimaComms.context(surface_space), ), threshold = 0.5, @@ -1246,10 +1246,21 @@ end """ global_domain( FT; + apply_mask = true, + mask_threshold = 0.5, nelements = (101, 15), dz_tuple = (10.0, 0.05), depth = 50.0, npolynomial = 0, + context = ClimaComms.context(), + filepath = landseamask_file_path(;context), + regridder_type = :InterpolationsRegridder, + extrapolation_bc = ( + Interpolations.Periodic(), + Interpolations.Flat(), + Interpolations.Flat(), + ), + interpolation_method = Interpolations.Constant() ) Helper function to create a SphericalShell domain with (101,15) elements, a @@ -1282,6 +1293,14 @@ function global_domain( depth = 50.0, npolynomial = 0, context = ClimaComms.context(), + filepath = landseamask_file_path(; context), + regridder_type = :InterpolationsRegridder, + extrapolation_bc = ( + Interpolations.Periodic(), + Interpolations.Flat(), + Interpolations.Flat(), + ), + interpolation_method = Interpolations.Constant(), ) if pkgversion(ClimaCore) < v"0.14.30" && apply_mask @warn "The land mask cannot be applied with ClimaCore < v0.14.30. Update ClimaCore for significant performance gains." @@ -1301,7 +1320,14 @@ function global_domain( ) if apply_mask surface_space = domain.space.surface # 2d space - binary_mask = landsea_mask(domain; threshold = mask_threshold) + binary_mask = landsea_mask( + domain; + threshold = mask_threshold, + regridder_type, + extrapolation_bc, + interpolation_method, + filepath, + ) Spaces.set_mask!(surface_space, binary_mask) end diff --git a/src/simulations/Simulations.jl b/src/simulations/Simulations.jl index 9552d38892..f24185846b 100644 --- a/src/simulations/Simulations.jl +++ b/src/simulations/Simulations.jl @@ -53,6 +53,7 @@ struct LandSimulation{ } model::M timestepper::T + start_date::Union{DateTime, Nothing} user_callbacks::UC diagnostics::DI required_callbacks::RC @@ -141,6 +142,8 @@ function LandSimulation( updateat = [promote(t0:(ITime(3600 * 3)):tf...)...], solver_kwargs = (;), ) + start_date = isnothing(t0.epoch) ? nothing : date(t0) + if !isnothing(diagnostics) && !isempty(diagnostics) && !( @@ -151,7 +154,6 @@ function LandSimulation( @warn "Note that the kwarg outdir and outdir used in diagnostics are inconsistent; using $(first(diagnostics).output_writer.output_dir)" end - # set initial conditions Y, p, cds = initialize(model) set_ic!(Y, p, t0, model) @@ -212,6 +214,7 @@ function LandSimulation( return LandSimulation( model, timestepper, + start_date, user_callbacks, diagnostics, required_callbacks, @@ -226,25 +229,24 @@ end tf::AbstractFloat, Δt::AbstractFloat, args...; - start_date = nothing, kwargs..., ) -A convenience constructor for `LandSimulation` that converts `t0`, `tf`, `Δt` into `ITime`(s), -using `start_date` as the epoch if provided. If the `kwargs` contain `updateat`, it will +A convenience constructor for `LandSimulation` that converts `t0`, `tf`, `Δt` into `ITime`(s), setting the epoch of the ITime to nothing. +If the `kwargs` contain `updateat`, it will convert the update times to `ITime`(s) as well. The same applies to `saveat` in `solver_kwargs`. +If your simulation has a notion of a calendar date, please use one of the +other constructors. """ function LandSimulation( t0::AbstractFloat, tf::AbstractFloat, Δt::AbstractFloat, args...; - start_date = nothing, kwargs..., ) - t0_itime, tf_itime, Δt_itime = - promote(ITime.((t0, tf, Δt); epoch = start_date)...) + t0_itime, tf_itime, Δt_itime = promote(ITime.((t0, tf, Δt))...) kwargs = convert_kwarg_updates(t0_itime, kwargs) LandSimulation(t0_itime, tf_itime, Δt_itime, args...; kwargs...) end @@ -307,7 +309,6 @@ function solve!(landsim::LandSimulation) end end - """ ClimaComms.context(landsim::LandSimulation) diff --git a/src/standalone/Vegetation/Canopy.jl b/src/standalone/Vegetation/Canopy.jl index ef99edcc18..3b5db88891 100644 --- a/src/standalone/Vegetation/Canopy.jl +++ b/src/standalone/Vegetation/Canopy.jl @@ -141,7 +141,7 @@ end ψ63 = FT(-4 / 0.0098), c = FT(4), ), - retention_model = LinearRetentionCurve{FT}(a = FT(0.05 * 0.0098)), + retention_model = LinearRetentionCurve{FT}(a = FT(0.2 * 0.0098)), rooting_depth = clm_rooting_depth(domain.space.surface), transpiration = PlantHydraulics.DiagnosticTranspiration{FT}(), ) where {FT <: AbstractFloat} @@ -160,9 +160,9 @@ The following default parameters are used: - ν = 1.44e-4 (m3/m3) - porosity - S_s = 1e-2 * 0.0098 (m⁻¹) - storativity - K_sat = 7e-8 (m/s) - saturated hydraulic conductivity -- ψ63 = -4 / 0.0098 (MPa to m) - xylem percentage loss of conductivity curve parameters; Holtzman's original value -- c = 4 (unitless) - Weibull parameter; Holtzman's original value -- a = 0.05 * 0.0098 (m) - bulk modulus of elasticity; Holtzman's original value +- ψ63 = -4 / 0.0098 (MPa to m) - xylem percentage loss of conductivity curve parameters; +- c = 4 (unitless) - Weibull parameter; +- a = 0.2 * 0.0098 (m) - bulk modulus of elasticity; Citation: Holtzman, N., Wang, Y., Wood, J. D., Frankenberg, C., & Konings, A. G. (2023). @@ -192,7 +192,7 @@ function PlantHydraulicsModel{FT}( FT(4), # c ), retention_model = PlantHydraulics.LinearRetentionCurve{FT}( - FT(0.05 * 0.0098), # a + FT(0.2 * 0.0098), # a ), rooting_depth = clm_rooting_depth(domain.space.surface), transpiration = PlantHydraulics.DiagnosticTranspiration{FT}(), diff --git a/test/integrated/full_land.jl b/test/integrated/full_land.jl index 7e847c1252..2b77a040fc 100644 --- a/test/integrated/full_land.jl +++ b/test/integrated/full_land.jl @@ -80,58 +80,138 @@ for FT in (Float32, Float64) end end -include("full_land_utils.jl"); +""" + check_ocean_values_p(p, binary_mask; val = 0.0) + +This function tests that every field stored in `p` has all of +its values (where binary_mask == 1) equal to `val`. Note that +this is meant to be used with the full land model (canopy, +snow, soil, soilco2). + +Useful for checking if land model functions are updating the +values over the ocean. +""" +function check_ocean_values_p(p, binary_mask; val = 0.0) + properties = [ + p.drivers, + p.soil, + p.soilco2, + p.snow, + p.canopy.energy, + p.canopy.hydraulics, + p.canopy.radiative_transfer, + p.canopy.photosynthesis, + p.canopy.sif, + p.canopy.turbulent_fluxes, + p.canopy.autotrophic_respiration, + p.canopy.conductance, + ] + for property in properties + for var in propertynames(property) + field_values = Array(parent(getproperty(property, var))) + if length(size(field_values)) == 5 # 3d var + @test extrema(field_values[:, 1, 1, :, Array(binary_mask)]) == + (val, val) + else + @test extrema(field_values[1, 1, :, Array(binary_mask)]) == + (val, val) + end + end + end + + field_pn_p = [ + pn for pn in propertynames(p) if pn != :soil && + pn != :canopy && + pn != :snow && + pn != :soilco2 && + pn != :drivers && + ~occursin("dss", String(pn)) + ] + + for var in field_pn_p + field_values = Array(parent(getproperty(p, var))) + if length(size(field_values)) == 5 # 3d var + @test extrema(field_values[:, 1, 1, :, Array(binary_mask)]) == + (val, val) + else + @test extrema(field_values[1, 1, :, Array(binary_mask)]) == + (val, val) + + end + end +end + +""" + check_ocean_values_Y(Y, binary_mask; val = 0.0) + +This function tests that every field stored in `Y` has all of +its values (where binary_mask == 1) equal to `val`. Note that +this is meant to be used with the full land model (canopy, +snow, soil, soilco2). + +Useful for checking if land model functions are updating the +values over the ocean. +""" +function check_ocean_values_Y(Y, binary_mask; val = 0.0) + @test extrema(Array(parent(Y.soil.ϑ_l))[:, 1, 1, 1, Array(binary_mask)]) == + (val, val) + @test extrema(Array(parent(Y.soil.θ_i))[:, 1, 1, 1, Array(binary_mask)]) == + (val, val) + @test extrema( + Array(parent(Y.soil.ρe_int))[:, 1, 1, 1, Array(binary_mask)], + ) == (val, val) + @test extrema(Array(parent(Y.snow.U))[1, 1, 1, Array(binary_mask)]) == + (val, val) + @test extrema(Array(parent(Y.snow.S))[1, 1, 1, Array(binary_mask)]) == + (val, val) + @test extrema(Array(parent(Y.snow.S_l))[1, 1, 1, Array(binary_mask)]) == + (val, val) + @test extrema( + Array(parent(Y.canopy.energy.T))[1, 1, 1, Array(binary_mask)], + ) == (val, val) + @test extrema( + Array(parent(Y.canopy.hydraulics.ϑ_l.:1))[1, 1, 1, Array(binary_mask)], + ) == (val, val) +end + context = ClimaComms.context() nelements = (101, 15) -start_date = DateTime(2008) Δt = 450.0 -t0 = 0.0 -tf = t0 + Δt - FT = Float64 earth_param_set = LP.LandParameters(FT) -f_over = FT(3.28) # 1/m -R_sb = FT(1.484e-4 / 1000) # m/s -scalar_soil_params = (; f_over, R_sb) - -α_snow = Snow.ConstantAlbedoModel(FT(0.67)) -scalar_snow_params = (; α_snow, Δt) - -# Energy Balance model -ac_canopy = FT(2.5e3) -K_sat_plant = FT(5e-9) # m/s # seems much too small? -ψ63 = FT(-4 / 0.0098) # / MPa to m, Holtzman's original parameter value is -4 MPa -Weibull_param = FT(4) # unitless, Holtzman's original c param value -a = FT(0.05 * 0.0098) # Holtzman's original parameter for the bulk modulus of elasticity -plant_ν = FT(1.44e-4) -plant_S_s = FT(1e-2 * 0.0098) # m3/m3/MPa to m3/m3/m -h_leaf = FT(1.0) - -scalar_canopy_params = (; - ac_canopy, - K_sat_plant, - a, - ψ63, - Weibull_param, - plant_ν, - plant_S_s, - h_leaf, +domain = ClimaLand.Domains.global_domain( + FT; + nelements = nelements, + mask_threshold = FT(0.99), ); - -domain = ClimaLand.Domains.global_domain(FT; nelements = nelements); surface_space = domain.space.surface; start_date = DateTime(2008); -land = global_land_model( - FT, - scalar_soil_params, - scalar_canopy_params, - scalar_snow_params, - earth_param_set; - context = context, - domain = domain, +stop_date = start_date + Second(Δt) +era5_ncdata_path = ClimaLand.Artifacts.era5_land_forcing_data2008_path(; + context, + lowres = true, +) +forcing = ClimaLand.prescribed_forcing_era5( + era5_ncdata_path, + domain.space.surface, + start_date, + earth_param_set, + FT; +) +modis_lai_ncdata_path = ClimaLand.Artifacts.modis_lai_multiyear_paths(; + start_date, + end_date = stop_date, +) +LAI = ClimaLand.prescribed_lai_modis( + modis_lai_ncdata_path, + domain.space.surface, + start_date, ); + +land = LandModel{FT}(forcing, LAI, earth_param_set, domain, Δt); + @test domain == ClimaLand.get_domain(land) @test ClimaComms.context(land) == ClimaComms.context() @test ClimaComms.device(land) == ClimaComms.device() @@ -275,12 +355,13 @@ if pkgversion(ClimaCore) >= v"0.14.30" check_ocean_values_p(p, binary_mask) # Set initial conditions - ic_path = ClimaLand.Artifacts.soil_ic_2008_50m_path(; context = context) + ic_path = ClimaLand.Artifacts.soil_ic_2008_50m_path(; context) set_initial_state! = ClimaLand.Simulations.make_set_initial_state_from_file( ic_path, land, ) + t0 = 0.0 set_initial_state!(Y, p, t0, land) # Now, set the cache with physical values and make sure there are no NaNs, or values set over the ocean set_initial_cache! = make_set_initial_cache(land) @@ -382,7 +463,7 @@ if pkgversion(ClimaCore) >= v"0.14.30" dss! = ClimaLand.dss!, ), Y, - (t0, tf), + (t0, t0 + Δt), p, ) # Define timestepper and ODE algorithm @@ -400,7 +481,7 @@ if pkgversion(ClimaCore) >= v"0.14.30" ode_algo; dt = Δt, adaptive = false, - saveat = [t0, tf], + saveat = [t0, t0 + Δt], ) u = sol.u[end] check_ocean_values_Y(u, binary_mask) diff --git a/test/integrated/full_land_utils.jl b/test/integrated/full_land_utils.jl deleted file mode 100644 index 942a0b5647..0000000000 --- a/test/integrated/full_land_utils.jl +++ /dev/null @@ -1,345 +0,0 @@ -using Dates -import ClimaUtilities.TimeVaryingInputs: TimeVaryingInput - -using ClimaLand -using ClimaLand.Snow -using ClimaLand.Soil -using ClimaLand.Canopy -import ClimaLand - -""" - global_land_model(FT, - context, - scalar_soil_params, - scalar_canopy_params, - scalar_snow_params, - earth_param_set; - context = nothing, - domain = ClimaLand.Domains.global_domain(FT; context = context), - forcing = ClimaLand.prescribed_forcing_era5(ClimaLand.Artifacts.era5_land_forcing_data2008_path(; context), - domain.space.surface, - DateTime(2008), - earth_param_set, - FT), - LAI = ClimaLand.prescribed_lai_modis(ClimaLand.Artifacts.modis_lai_single_year_path(DateTime(2008); context), - domain.space.surface, - DateTime(2008)) - ) - -An helper function for creating a land model corresponding to a global simulation of the snow, soil, and canopy models. - -While not explicitly an outer constructor, this creates and returns `LandModel` struct. This is meant as a helper for setting up a standard -global land model easily, and is useful for testing. Note that the user can construct any land model they -wish by using the default (inner) constructor method for `LandModel`, or using the alternate outer constructor method defined in src/integrated/land.jl. - -Over time, all scalar parameters will be moved to ClimaParameters, so that only a single parameter set `earth_param_set` is passed. -""" -function global_land_model( - FT, - scalar_soil_params, - scalar_canopy_params, - scalar_snow_params, - earth_param_set; - context = nothing, - domain = ClimaLand.Domains.global_domain(FT; context = context), - forcing = ClimaLand.prescribed_forcing_era5( - ClimaLand.Artifacts.era5_land_forcing_data2008_path(; context), - domain.space.surface, - DateTime(2008), - earth_param_set, - FT, - ), - LAI = ClimaLand.prescribed_lai_modis( - ClimaLand.Artifacts.modis_lai_single_year_path(; - context = nothing, - year = 2008, - ), - domain.space.surface, - DateTime(2008), - ), -) - # Unpack forcing - (atmos, radiation) = forcing - - # Unpack scalar parameters - (; α_snow, Δt) = scalar_snow_params - (; f_over, R_sb) = scalar_soil_params - (; - ac_canopy, - K_sat_plant, - a, - ψ63, - Weibull_param, - plant_ν, - plant_S_s, - h_leaf, - ) = scalar_canopy_params - - # Construct spatially varying parameters. - surface_space = domain.space.surface - subsurface_space = domain.space.subsurface - - (; ν_ss_om, ν_ss_quartz, ν_ss_gravel) = - ClimaLand.Soil.soil_composition_parameters(subsurface_space, FT) - (; ν, hydrology_cm, K_sat, θ_r) = - ClimaLand.Soil.soil_vangenuchten_parameters(subsurface_space, FT) - soil_albedo = Soil.CLMTwoBandSoilAlbedo{FT}(; - ClimaLand.Soil.clm_soil_albedo_parameters(surface_space)..., - ) - S_s = ClimaCore.Fields.zeros(subsurface_space) .+ FT(1e-3) - soil_params = Soil.EnergyHydrologyParameters( - FT; - ν, - ν_ss_om, - ν_ss_quartz, - ν_ss_gravel, - hydrology_cm, - K_sat, - S_s, - θ_r, - albedo = soil_albedo, - ) - f_over = FT(3.28) # 1/m - R_sb = FT(1.484e-4 / 1000) # m/s - runoff_model = ClimaLand.Soil.Runoff.TOPMODELRunoff{FT}(; - f_over = f_over, - f_max = ClimaLand.Soil.topmodel_fmax(surface_space, FT), - R_sb = R_sb, - ) - - # Spatially varying canopy parameters from CLM - g1 = ClimaLand.Canopy.clm_medlyn_g1(surface_space) - rooting_depth = ClimaLand.Canopy.clm_rooting_depth(surface_space) - (; is_c3, Vcmax25) = - ClimaLand.Canopy.clm_photosynthesis_parameters(surface_space) - (; Ω, G_Function, α_PAR_leaf, τ_PAR_leaf, α_NIR_leaf, τ_NIR_leaf) = - ClimaLand.Canopy.clm_canopy_radiation_parameters(surface_space) - - conductivity_model = - Canopy.PlantHydraulics.Weibull{FT}(K_sat_plant, ψ63, Weibull_param) - retention_model = Canopy.PlantHydraulics.LinearRetentionCurve{FT}(a) - SAI = FT(0.0) # m2/m2 - RAI = FT(1.0) - n_stem = 0 - n_leaf = 1 - h_stem = FT(0.0) - zmax = FT(0.0) - - h_canopy = h_stem + h_leaf - compartment_midpoints = - n_stem > 0 ? [h_stem / 2, h_stem + h_leaf / 2] : [h_leaf / 2] - compartment_surfaces = - n_stem > 0 ? [zmax, h_stem, h_canopy] : [zmax, h_leaf] - - z0_m = FT(0.13) * h_canopy - z0_b = FT(0.1) * z0_m - - soil_args = (domain = domain, parameters = soil_params) - soil_model_type = Soil.EnergyHydrology{FT} - - # Soil microbes model - soilco2_type = Soil.Biogeochemistry.SoilCO2Model{FT} - soilco2_ps = Soil.Biogeochemistry.SoilCO2ModelParameters(FT) - Csom = ClimaLand.PrescribedSoilOrganicCarbon{FT}(TimeVaryingInput((t) -> 5)) - soilco2_args = (; domain = domain, parameters = soilco2_ps) - - # Now we set up the canopy model, which we set up by component: - # Component Types - canopy_component_types = (; - autotrophic_respiration = Canopy.AutotrophicRespirationModel{FT}, - radiative_transfer = Canopy.TwoStreamModel{FT}, - photosynthesis = Canopy.FarquharModel{FT}, - conductance = Canopy.MedlynConductanceModel{FT}, - hydraulics = Canopy.PlantHydraulicsModel{FT}, - energy = Canopy.BigLeafEnergyModel{FT}, - ) - # Individual Component arguments - # Set up autotrophic respiration - autotrophic_respiration_args = - (; parameters = Canopy.AutotrophicRespirationParameters(FT)) - # Set up radiative transfer - radiative_transfer_args = (; - parameters = Canopy.TwoStreamParameters( - FT; - Ω, - α_PAR_leaf, - τ_PAR_leaf, - α_NIR_leaf, - τ_NIR_leaf, - G_Function, - ) - ) - # Set up conductance - conductance_args = - (; parameters = Canopy.MedlynConductanceParameters(FT; g1)) - # Set up photosynthesis - photosynthesis_args = - (; parameters = Canopy.FarquharParameters(FT, is_c3; Vcmax25 = Vcmax25)) - # Set up plant hydraulics - ai_parameterization = Canopy.PrescribedSiteAreaIndex{FT}(LAI, SAI, RAI) - - plant_hydraulics_ps = Canopy.PlantHydraulics.PlantHydraulicsParameters(; - ai_parameterization = ai_parameterization, - ν = plant_ν, - S_s = plant_S_s, - rooting_depth = rooting_depth, - conductivity_model = conductivity_model, - retention_model = retention_model, - ) - plant_hydraulics_args = ( - parameters = plant_hydraulics_ps, - n_stem = n_stem, - n_leaf = n_leaf, - compartment_midpoints = compartment_midpoints, - compartment_surfaces = compartment_surfaces, - ) - - energy_args = (parameters = Canopy.BigLeafEnergyParameters{FT}(ac_canopy),) - - # Canopy component args - canopy_component_args = (; - autotrophic_respiration = autotrophic_respiration_args, - radiative_transfer = radiative_transfer_args, - photosynthesis = photosynthesis_args, - conductance = conductance_args, - hydraulics = plant_hydraulics_args, - energy = energy_args, - ) - - # Other info needed - shared_params = Canopy.SharedCanopyParameters{FT, typeof(earth_param_set)}( - z0_m, - z0_b, - earth_param_set, - ) - - canopy_model_args = (; - parameters = shared_params, - domain = ClimaLand.obtain_surface_domain(domain), - ) - - # Snow model - snow_parameters = SnowParameters{FT}( - Δt; - earth_param_set = earth_param_set, - α_snow = α_snow, - ) - snow_args = (; - parameters = snow_parameters, - domain = ClimaLand.obtain_surface_domain(domain), - ) - snow_model_type = Snow.SnowModel - - land_input = ( - atmos = atmos, - radiation = radiation, - runoff = runoff_model, - soil_organic_carbon = Csom, - ) - return LandModel{FT}(; - soilco2_type = soilco2_type, - soilco2_args = soilco2_args, - land_args = land_input, - soil_model_type = soil_model_type, - soil_args = soil_args, - canopy_component_types = canopy_component_types, - canopy_component_args = canopy_component_args, - canopy_model_args = canopy_model_args, - snow_args = snow_args, - snow_model_type = snow_model_type, - ) -end - -""" - check_ocean_values_p(p, binary_mask; val = 0.0) - -This function tests that every field stored in `p` has all of -its values (where binary_mask == 1) equal to `val`. Note that -this is meant to be used with the full land model (canopy, -snow, soil, soilco2). - -Useful for checking if land model functions are updating the -values over the ocean. -""" -function check_ocean_values_p(p, binary_mask; val = 0.0) - properties = [ - p.drivers, - p.soil, - p.soilco2, - p.snow, - p.canopy.energy, - p.canopy.hydraulics, - p.canopy.radiative_transfer, - p.canopy.photosynthesis, - p.canopy.sif, - p.canopy.turbulent_fluxes, - p.canopy.autotrophic_respiration, - p.canopy.conductance, - ] - for property in properties - for var in propertynames(property) - field_values = Array(parent(getproperty(property, var))) - if length(size(field_values)) == 5 # 3d var - @test extrema(field_values[:, 1, 1, :, Array(binary_mask)]) == - (val, val) - else - @test extrema(field_values[1, 1, :, Array(binary_mask)]) == - (val, val) - end - end - end - - field_pn_p = [ - pn for pn in propertynames(p) if pn != :soil && - pn != :canopy && - pn != :snow && - pn != :soilco2 && - pn != :drivers && - ~occursin("dss", String(pn)) - ] - - for var in field_pn_p - field_values = Array(parent(getproperty(p, var))) - if length(size(field_values)) == 5 # 3d var - @test extrema(field_values[:, 1, 1, :, Array(binary_mask)]) == - (val, val) - else - @test extrema(field_values[1, 1, :, Array(binary_mask)]) == - (val, val) - - end - end -end - -""" - check_ocean_values_Y(Y, binary_mask; val = 0.0) - -This function tests that every field stored in `Y` has all of -its values (where binary_mask == 1) equal to `val`. Note that -this is meant to be used with the full land model (canopy, -snow, soil, soilco2). - -Useful for checking if land model functions are updating the -values over the ocean. -""" -function check_ocean_values_Y(Y, binary_mask; val = 0.0) - @test extrema(Array(parent(Y.soil.ϑ_l))[:, 1, 1, 1, Array(binary_mask)]) == - (val, val) - @test extrema(Array(parent(Y.soil.θ_i))[:, 1, 1, 1, Array(binary_mask)]) == - (val, val) - @test extrema( - Array(parent(Y.soil.ρe_int))[:, 1, 1, 1, Array(binary_mask)], - ) == (val, val) - @test extrema(Array(parent(Y.snow.U))[1, 1, 1, Array(binary_mask)]) == - (val, val) - @test extrema(Array(parent(Y.snow.S))[1, 1, 1, Array(binary_mask)]) == - (val, val) - @test extrema(Array(parent(Y.snow.S_l))[1, 1, 1, Array(binary_mask)]) == - (val, val) - @test extrema( - Array(parent(Y.canopy.energy.T))[1, 1, 1, Array(binary_mask)], - ) == (val, val) - @test extrema( - Array(parent(Y.canopy.hydraulics.ϑ_l.:1))[1, 1, 1, Array(binary_mask)], - ) == (val, val) -end diff --git a/test/standalone/Soil/Biogeochemistry/biogeochemistry_module.jl b/test/standalone/Soil/Biogeochemistry/biogeochemistry_module.jl index 10f891d1e8..bafdb9d0c8 100644 --- a/test/standalone/Soil/Biogeochemistry/biogeochemistry_module.jl +++ b/test/standalone/Soil/Biogeochemistry/biogeochemistry_module.jl @@ -68,8 +68,8 @@ for FT in (Float32, Float64) soil_domain, soil_drivers; parameters, - boundary_conditions = boundary_conditions, - sources = sources, + boundary_conditions, + sources, ) Y, p, coords = initialize(model) @@ -148,8 +148,8 @@ for FT in (Float32, Float64) soil_domain, soil_drivers; parameters, - boundary_conditions = boundary_conditions, - sources = sources, + boundary_conditions, + sources, ) Y, p, coords = initialize(model)