diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 96d0468833..7f3dd24f34 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -65,16 +65,6 @@ steps: - group: "Unit Tests" steps: - - label: "MPI Regridder unit tests" - key: "regridder_mpi_tests" - command: "srun julia --color=yes --project=test/ test/mpi_tests/regridder_mpi_tests.jl" - timeout_in_minutes: 20 - env: - CLIMACOMMS_CONTEXT: "MPI" - NPROCS: 2 - agents: - slurm_ntasks: 2 - slurm_mem: 16GB - label: "MPI Checkpointer unit tests" key: "checkpointer_mpi_tests" diff --git a/NEWS.md b/NEWS.md index ade6657534..355271b401 100644 --- a/NEWS.md +++ b/NEWS.md @@ -73,6 +73,46 @@ to our output diagnostics using the ClimaDiagnostics interface. This PR also removes the AMIP paperplots function, but this functionality is replaced by the generalized `make_plots` function. + +#### Remove ClimaCoupler.Regridder module - PR [#1109](https://github.com/CliMA/ClimaCoupler.jl/pull/1109) +This PR removes the Regridder module. Most of the functions that were +inside the module are available in [ClimaUtilities](https://github.com/CliMA/ClimaUtilities.jl/). Some functions were moved +to other modules, and some unused functions were deleted. + +The functions: +- `ClimaCoupler.Regridder.dummmy_remap!` +- `ClimaCoupler.Regridder.update_surface_fractions!` +- `ClimaCoupler.Regridder.combine_surfaces!` +- `ClimaCoupler.Regridder.binary_mask` + +are now: +- `ClimaCoupler.FieldExchanger.dummmy_remap!` +- `ClimaCoupler.FieldExchanger.update_surface_fractions!` +- `ClimaCoupler.FieldExchanger.combine_surfaces!` +- `ClimaCoupler.Utilities.binary_mask` + +The following functions were removed from ClimaCoupler and have an equivalent in [ClimaUtilities](https://github.com/CliMA/ClimaUtilities.jl/tree/main): + +- `ClimaCoupler.Regridder.write_to_hdf5` +- `ClimaCoupler.Regridder.read_from_hdf5` +- `ClimaCoupler.Regridder.hdwrite_regridfile_rll_to_cgll` +- `ClimaCoupler.Regridder.reshape_cgll_sparse_to_field!` +- `ClimaCoupler.Regridder.get_time` + +Note that the the `hdwrite_regridfile_rll_to_cgll` in [ClimaUtilities](https://github.com/CliMA/ClimaUtilities.jl/tree/main) does not support 3d fields, but the removed function from the Regridder module did. + +The following functions were deleted and do not have an equivalent in [ClimaUtilities](https://github.com/CliMA/ClimaUtilities.jl/tree/main): + +- `ClimaCoupler.Regridder.remap_field_cgll_to_rll` +- `ClimaCoupler.Regridder.land_fraction` +- `ClimaCoupler.Regridder.combine_surfaces_from_sol!` +- `ClimaCoupler.Regridder.write_datafile_cc` +- `ClimaCoupler.Regridder.read_remapped_field` +- `ClimaCoupler.Regridder.get_coords` + +All the above functions can be found in commit +`9e5bf061f34659188485f066bc322c77bcc0f1fa` + #### Remove PostProcessor module - PR [#1022](https://github.com/CliMA/ClimaCoupler.jl/pull/1022) After switching to use ClimaDiagnostics.jl and ClimaAnalysis.jl for our diagnostics, the PostProcessor module is not needed. diff --git a/Project.toml b/Project.toml index 4db0bfd469..c05aeb790e 100644 --- a/Project.toml +++ b/Project.toml @@ -6,12 +6,8 @@ version = "0.1.1" [deps] ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" -ClimaCoreTempestRemap = "d934ef94-cdd4-4710-83d6-720549644b70" -ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" -NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" SurfaceFluxes = "49b00bb7-8bd4-4f2b-b78c-51cd0450215f" @@ -20,12 +16,8 @@ Thermodynamics = "b60c26fb-14c3-4610-9d3e-2d17fe7ff00c" [compat] ClimaComms = "0.5.6, 0.6" ClimaCore = "0.14.19" -ClimaCoreTempestRemap = "0.3" -ClimaUtilities = "0.1.14" Dates = "1" -JLD2 = "0.4, 0.5" Logging = "1" -NCDatasets = "0.11, 0.12, 0.13, 0.14.2" SciMLBase = "1, 2" StaticArrays = "1.5" SurfaceFluxes = "0.11, 0.12" diff --git a/docs/make.jl b/docs/make.jl index 9297d737d2..40a54567db 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -62,7 +62,6 @@ interface_pages = [ "fieldexchanger.md", "fluxcalculator.md", "interfacer.md", - "regridder.md", "timemanager.md", "utilities.md", ] diff --git a/docs/src/fieldexchanger.md b/docs/src/fieldexchanger.md index 7339054344..544f90f192 100644 --- a/docs/src/fieldexchanger.md +++ b/docs/src/fieldexchanger.md @@ -22,4 +22,12 @@ If an `update_field!` function is not defined for a particular component model, ClimaCoupler.FieldExchanger.update_sim! ClimaCoupler.FieldExchanger.reinit_model_sims! ClimaCoupler.FieldExchanger.step_model_sims! + ClimaCoupler.FieldExchanger.update_surface_fractions! +``` + +## FieldExchanger Internal Functions + +```@docs + ClimaCoupler.FieldExchanger.combine_surfaces! + ClimaCoupler.FieldExchanger.dummmy_remap! ``` diff --git a/docs/src/regridder.md b/docs/src/regridder.md deleted file mode 100644 index 27f4a81e3b..0000000000 --- a/docs/src/regridder.md +++ /dev/null @@ -1,35 +0,0 @@ -# Regridder - -This module contains functions to regrid information between spaces. -Many of the functions used in this module call TempestRemap functions -via ClimaCoreTempestRemap wrappers. - -Information about the TempestRemap library can be found [here](https://github.com/ClimateGlobalChange/tempestremap). -Multiple remapping approaches from TempestRemap have been tested with our -implementation, and information about them is located [here](https://github.com/CliMA/ClimaCoupler.jl/wiki/ClimaCoupler-Lessons-Learned). - -## Regridder API - -```@docs -ClimaCoupler.Regridder.write_to_hdf5 -ClimaCoupler.Regridder.read_from_hdf5 -ClimaCoupler.Regridder.dummmy_remap! -ClimaCoupler.Regridder.remap_field_cgll_to_rll -ClimaCoupler.Regridder.land_fraction -ClimaCoupler.Regridder.update_surface_fractions! -ClimaCoupler.Regridder.combine_surfaces! -ClimaCoupler.Regridder.combine_surfaces_from_sol! -``` - - -## Regridder Internal Functions - -```@docs -ClimaCoupler.Regridder.reshape_cgll_sparse_to_field! -ClimaCoupler.Regridder.hdwrite_regridfile_rll_to_cgll -ClimaCoupler.Regridder.write_datafile_cc -ClimaCoupler.Regridder.binary_mask -ClimaCoupler.Regridder.read_remapped_field -ClimaCoupler.Regridder.get_coords -ClimaCoupler.Regridder.get_time -``` diff --git a/docs/src/utilities.md b/docs/src/utilities.md index af407b22fa..d0024347ed 100644 --- a/docs/src/utilities.md +++ b/docs/src/utilities.md @@ -13,4 +13,5 @@ ClimaCoupler.Utilities.get_device ClimaCoupler.Utilities.show_memory_usage ClimaCoupler.Utilities.setup_output_dirs ClimaCoupler.Utilities.time_to_seconds +ClimaCoupler.Utilities.binary_mask ``` diff --git a/experiments/ClimaCore/Manifest-v1.11.toml b/experiments/ClimaCore/Manifest-v1.11.toml index dd57f9da5a..8ce50b1f0e 100644 --- a/experiments/ClimaCore/Manifest-v1.11.toml +++ b/experiments/ClimaCore/Manifest-v1.11.toml @@ -187,12 +187,6 @@ weakdeps = ["BandedMatrices"] [deps.BlockArrays.extensions] BlockArraysBandedMatricesExt = "BandedMatrices" -[[deps.Blosc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Lz4_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "ef12cdd1c7fb7e1dfd6fa8fd60d4db6bc61d2f23" -uuid = "0b7ba130-8d10-5ba8-a3d6-c5182647fed9" -version = "1.21.6+0" - [[deps.Bzip2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "8873e196c2eb87962a2048b3b8e08946535864a1" @@ -204,12 +198,6 @@ git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc" uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.5.0" -[[deps.CFTime]] -deps = ["Dates", "Printf"] -git-tree-sha1 = "5afb5c5ba2688ca43a9ad2e5a91cbb93921ccfa1" -uuid = "179af706-886a-5703-950a-314cd64e0468" -version = "0.1.3" - [[deps.CPUSummary]] deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] git-tree-sha1 = "5a97e67919535d6841172016c9530fd69494e5ec" @@ -293,14 +281,8 @@ git-tree-sha1 = "e1e82d32ba993a18fc760d5cbd7db3bcabd1f3c8" uuid = "908f55d8-4145-4867-9c14-5dad1a479e4d" version = "0.4.6" -[[deps.ClimaCoreTempestRemap]] -deps = ["ClimaComms", "ClimaCore", "CommonDataModel", "Dates", "LinearAlgebra", "NCDatasets", "PkgVersion", "TempestRemap_jll"] -git-tree-sha1 = "99845c1da7e9f687180c49cf4d53140f21fc8683" -uuid = "d934ef94-cdd4-4710-83d6-720549644b70" -version = "0.3.18" - [[deps.ClimaCoupler]] -deps = ["ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] +deps = ["ClimaComms", "ClimaCore", "Dates", "Logging", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] path = "../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.1" @@ -361,12 +343,6 @@ git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" version = "0.12.11" -[[deps.CommonDataModel]] -deps = ["CFTime", "DataStructures", "Dates", "Preferences", "Printf", "Statistics"] -git-tree-sha1 = "98d64d5b9e5263884276656a43c45424b3a645c2" -uuid = "1fbeeb36-5f17-413c-809b-666fb144f157" -version = "0.3.7" - [[deps.CommonSolve]] git-tree-sha1 = "0eee5eb66b1cf62cd6ad1b460238e60e4b09400c" uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" @@ -566,12 +542,6 @@ version = "0.6.22" Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" -[[deps.DiskArrays]] -deps = ["LRUCache", "OffsetArrays"] -git-tree-sha1 = "e0e89a60637a62d13aa2107f0acd169b9b9b77e7" -uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" -version = "0.4.6" - [[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" @@ -825,11 +795,6 @@ deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" version = "1.11.0" -[[deps.GMP_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" -version = "6.3.0+0" - [[deps.GPUArraysCore]] deps = ["Adapt"] git-tree-sha1 = "83cf05ab16a73219e5f6bd1bdfa9848fa24ac627" @@ -882,12 +847,6 @@ git-tree-sha1 = "674ff0db93fffcd11a3573986e550d66cd4fd71f" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" version = "2.80.5+0" -[[deps.GnuTLS_jll]] -deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Nettle_jll", "P11Kit_jll", "Zlib_jll"] -git-tree-sha1 = "383db7d3f900f4c1f47a8a04115b053c095e48d3" -uuid = "0951126a-58fd-58f1-b5b3-b08c7c4a876d" -version = "3.8.4+0" - [[deps.Graphics]] deps = ["Colors", "LinearAlgebra", "NaNMath"] git-tree-sha1 = "a641238db938fff9b2f60d08ed9030387daf428c" @@ -1067,12 +1026,6 @@ git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Requires", "TranscodingStreams"] -git-tree-sha1 = "ce5737c0d4490b0e0040b5dc77fbb6a351ddf188" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.8" - [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] git-tree-sha1 = "be3dc50a92e5a386872a493a10050136d4703f9b" @@ -1173,15 +1126,6 @@ git-tree-sha1 = "78211fb6cbc872f77cad3fc0b6cf647d923f4929" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" version = "18.1.7+0" -[[deps.LRUCache]] -git-tree-sha1 = "b3cc6698599b10e652832c2f23db3cab99d51b59" -uuid = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" -version = "1.6.1" -weakdeps = ["Serialization"] - - [deps.LRUCache.extensions] - SerializationExt = ["Serialization"] - [[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "854a9c268c43b77b0a27f22d7fab8d33cdb3a731" @@ -1327,12 +1271,6 @@ version = "0.3.28" uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" version = "1.11.0" -[[deps.Lz4_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "abf88ff67f4fd89839efcae2f4c39cbc4ecd0846" -uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" -version = "1.10.0+1" - [[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] git-tree-sha1 = "f046ccd0c6db2832a9f639e2c669c6fe867e5f4f" @@ -1449,12 +1387,6 @@ version = "0.3.3" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -[[deps.NCDatasets]] -deps = ["CFTime", "CommonDataModel", "DataStructures", "Dates", "DiskArrays", "NetCDF_jll", "NetworkOptions", "Printf"] -git-tree-sha1 = "2c9dc92001ac06d432f363f37ff5552954d9947c" -uuid = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" -version = "0.14.6" - [[deps.NVTX]] deps = ["Colors", "JuliaNVTXCallbacks_jll", "Libdl", "NVTX_jll"] git-tree-sha1 = "53046f0483375e3ed78e49190f1154fa0a4083a1" @@ -1473,24 +1405,12 @@ git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.0.2" -[[deps.NetCDF_jll]] -deps = ["Artifacts", "Blosc_jll", "Bzip2_jll", "HDF5_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenMPI_jll", "XML2_jll", "Zlib_jll", "Zstd_jll", "libzip_jll"] -git-tree-sha1 = "a8af1798e4eb9ff768ce7fdefc0e957097793f15" -uuid = "7243133f-43d8-5620-bbf4-c2c921802cf3" -version = "400.902.209+0" - [[deps.Netpbm]] deps = ["FileIO", "ImageCore", "ImageMetadata"] git-tree-sha1 = "d92b107dbb887293622df7697a2223f9f8176fcd" uuid = "f09324ee-3d7c-5217-9330-fc30815ba969" version = "1.1.1" -[[deps.Nettle_jll]] -deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "eca63e3847dad608cfa6a3329b95ef674c7160b4" -uuid = "4c82536e-c426-54e4-b420-14f461c4ed8b" -version = "3.7.2+0" - [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" @@ -1515,12 +1435,6 @@ git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "dd806c813429ff09878ea3eeb317818f3ca02871" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.28+3" - [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" @@ -1572,12 +1486,6 @@ git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.6.3" -[[deps.P11Kit_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "2cd396108e178f3ae8dedbd8e938a18726ab2fbf" -uuid = "c2071276-7c44-58a7-b746-946036e04d0a" -version = "0.24.1+0" - [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" @@ -2148,12 +2056,6 @@ weakdeps = ["IntervalArithmetic", "StaticArrays"] TaylorSeriesIAExt = "IntervalArithmetic" TaylorSeriesSAExt = "StaticArrays" -[[deps.TempestRemap_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "Libdl", "NetCDF_jll", "OpenBLAS32_jll"] -git-tree-sha1 = "723112218783928a20e0d865932694acfb7a7571" -uuid = "8573a8c5-1df0-515e-a024-abad257ee284" -version = "2.2.0+0" - [[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" @@ -2413,12 +2315,6 @@ git-tree-sha1 = "ccbb625a89ec6195856a50aa2b668a5c08712c94" uuid = "c5f90fcd-3b7e-5836-afba-fc50a0988cb2" version = "1.4.0+0" -[[deps.libzip_jll]] -deps = ["Artifacts", "Bzip2_jll", "GnuTLS_jll", "JLLWrappers", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "668ac0297e6bd8f4d53dfdcd3ace71f2e00f4a35" -uuid = "337d8026-41b4-5cde-a456-74a10e5b31d1" -version = "1.11.1+0" - [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" diff --git a/experiments/ClimaCore/Manifest.toml b/experiments/ClimaCore/Manifest.toml index 997ecf8052..5866f0f5f9 100644 --- a/experiments/ClimaCore/Manifest.toml +++ b/experiments/ClimaCore/Manifest.toml @@ -1,6 +1,6 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.10.5" +julia_version = "1.10.6" manifest_format = "2.0" project_hash = "bf83058e7b8cbbdd01fa91af0f6b995b1e2e3f47" @@ -185,12 +185,6 @@ weakdeps = ["BandedMatrices"] [deps.BlockArrays.extensions] BlockArraysBandedMatricesExt = "BandedMatrices" -[[deps.Blosc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Lz4_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "ef12cdd1c7fb7e1dfd6fa8fd60d4db6bc61d2f23" -uuid = "0b7ba130-8d10-5ba8-a3d6-c5182647fed9" -version = "1.21.6+0" - [[deps.Bzip2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "8873e196c2eb87962a2048b3b8e08946535864a1" @@ -202,12 +196,6 @@ git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc" uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.5.0" -[[deps.CFTime]] -deps = ["Dates", "Printf"] -git-tree-sha1 = "5afb5c5ba2688ca43a9ad2e5a91cbb93921ccfa1" -uuid = "179af706-886a-5703-950a-314cd64e0468" -version = "0.1.3" - [[deps.CPUSummary]] deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] git-tree-sha1 = "5a97e67919535d6841172016c9530fd69494e5ec" @@ -290,14 +278,8 @@ git-tree-sha1 = "e1e82d32ba993a18fc760d5cbd7db3bcabd1f3c8" uuid = "908f55d8-4145-4867-9c14-5dad1a479e4d" version = "0.4.6" -[[deps.ClimaCoreTempestRemap]] -deps = ["ClimaComms", "ClimaCore", "CommonDataModel", "Dates", "LinearAlgebra", "NCDatasets", "PkgVersion", "TempestRemap_jll"] -git-tree-sha1 = "99845c1da7e9f687180c49cf4d53140f21fc8683" -uuid = "d934ef94-cdd4-4710-83d6-720549644b70" -version = "0.3.18" - [[deps.ClimaCoupler]] -deps = ["Artifacts", "ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] +deps = ["ClimaComms", "ClimaCore", "Dates", "Logging", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] path = "../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.1" @@ -358,12 +340,6 @@ git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" version = "0.12.11" -[[deps.CommonDataModel]] -deps = ["CFTime", "DataStructures", "Dates", "Preferences", "Printf", "Statistics"] -git-tree-sha1 = "98d64d5b9e5263884276656a43c45424b3a645c2" -uuid = "1fbeeb36-5f17-413c-809b-666fb144f157" -version = "0.3.7" - [[deps.CommonSolve]] git-tree-sha1 = "0eee5eb66b1cf62cd6ad1b460238e60e4b09400c" uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" @@ -562,12 +538,6 @@ version = "0.6.22" Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" -[[deps.DiskArrays]] -deps = ["LRUCache", "OffsetArrays"] -git-tree-sha1 = "e0e89a60637a62d13aa2107f0acd169b9b9b77e7" -uuid = "3c3547ce-8d99-4f5e-a174-61eb10b00ae3" -version = "0.4.6" - [[deps.Distributed]] deps = ["Random", "Serialization", "Sockets"] uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" @@ -818,11 +788,6 @@ version = "0.5.1" deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" -[[deps.GMP_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" -version = "6.2.1+6" - [[deps.GPUArraysCore]] deps = ["Adapt"] git-tree-sha1 = "83cf05ab16a73219e5f6bd1bdfa9848fa24ac627" @@ -875,12 +840,6 @@ git-tree-sha1 = "674ff0db93fffcd11a3573986e550d66cd4fd71f" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" version = "2.80.5+0" -[[deps.GnuTLS_jll]] -deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Nettle_jll", "P11Kit_jll", "Zlib_jll"] -git-tree-sha1 = "383db7d3f900f4c1f47a8a04115b053c095e48d3" -uuid = "0951126a-58fd-58f1-b5b3-b08c7c4a876d" -version = "3.8.4+0" - [[deps.Graphics]] deps = ["Colors", "LinearAlgebra", "NaNMath"] git-tree-sha1 = "a641238db938fff9b2f60d08ed9030387daf428c" @@ -1059,12 +1018,6 @@ git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Requires", "TranscodingStreams"] -git-tree-sha1 = "ce5737c0d4490b0e0040b5dc77fbb6a351ddf188" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.8" - [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] git-tree-sha1 = "be3dc50a92e5a386872a493a10050136d4703f9b" @@ -1165,15 +1118,6 @@ git-tree-sha1 = "78211fb6cbc872f77cad3fc0b6cf647d923f4929" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" version = "18.1.7+0" -[[deps.LRUCache]] -git-tree-sha1 = "b3cc6698599b10e652832c2f23db3cab99d51b59" -uuid = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" -version = "1.6.1" -weakdeps = ["Serialization"] - - [deps.LRUCache.extensions] - SerializationExt = ["Serialization"] - [[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] git-tree-sha1 = "854a9c268c43b77b0a27f22d7fab8d33cdb3a731" @@ -1314,12 +1258,6 @@ version = "0.3.28" [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" -[[deps.Lz4_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "abf88ff67f4fd89839efcae2f4c39cbc4ecd0846" -uuid = "5ced341a-0733-55b8-9ab6-a4889d929147" -version = "1.10.0+1" - [[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] git-tree-sha1 = "f046ccd0c6db2832a9f639e2c669c6fe867e5f4f" @@ -1434,12 +1372,6 @@ version = "0.3.3" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" -[[deps.NCDatasets]] -deps = ["CFTime", "CommonDataModel", "DataStructures", "Dates", "DiskArrays", "NetCDF_jll", "NetworkOptions", "Printf"] -git-tree-sha1 = "2c9dc92001ac06d432f363f37ff5552954d9947c" -uuid = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" -version = "0.14.6" - [[deps.NVTX]] deps = ["Colors", "JuliaNVTXCallbacks_jll", "Libdl", "NVTX_jll"] git-tree-sha1 = "53046f0483375e3ed78e49190f1154fa0a4083a1" @@ -1458,24 +1390,12 @@ git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.0.2" -[[deps.NetCDF_jll]] -deps = ["Artifacts", "Blosc_jll", "Bzip2_jll", "HDF5_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "OpenMPI_jll", "XML2_jll", "Zlib_jll", "Zstd_jll", "libzip_jll"] -git-tree-sha1 = "a8af1798e4eb9ff768ce7fdefc0e957097793f15" -uuid = "7243133f-43d8-5620-bbf4-c2c921802cf3" -version = "400.902.209+0" - [[deps.Netpbm]] deps = ["FileIO", "ImageCore", "ImageMetadata"] git-tree-sha1 = "d92b107dbb887293622df7697a2223f9f8176fcd" uuid = "f09324ee-3d7c-5217-9330-fc30815ba969" version = "1.1.1" -[[deps.Nettle_jll]] -deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "eca63e3847dad608cfa6a3329b95ef674c7160b4" -uuid = "4c82536e-c426-54e4-b420-14f461c4ed8b" -version = "3.7.2+0" - [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" @@ -1500,12 +1420,6 @@ git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6065c4cff8fee6c6770b277af45d5082baacdba1" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.24+0" - [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" @@ -1557,12 +1471,6 @@ git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.6.3" -[[deps.P11Kit_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "2cd396108e178f3ae8dedbd8e938a18726ab2fbf" -uuid = "c2071276-7c44-58a7-b746-946036e04d0a" -version = "0.24.1+0" - [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" @@ -2114,12 +2022,6 @@ weakdeps = ["IntervalArithmetic", "StaticArrays"] TaylorSeriesIAExt = "IntervalArithmetic" TaylorSeriesSAExt = "StaticArrays" -[[deps.TempestRemap_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "Libdl", "NetCDF_jll", "OpenBLAS32_jll"] -git-tree-sha1 = "723112218783928a20e0d865932694acfb7a7571" -uuid = "8573a8c5-1df0-515e-a024-abad257ee284" -version = "2.2.0+0" - [[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" @@ -2376,12 +2278,6 @@ git-tree-sha1 = "ccbb625a89ec6195856a50aa2b668a5c08712c94" uuid = "c5f90fcd-3b7e-5836-afba-fc50a0988cb2" version = "1.4.0+0" -[[deps.libzip_jll]] -deps = ["Artifacts", "Bzip2_jll", "GnuTLS_jll", "JLLWrappers", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "668ac0297e6bd8f4d53dfdcd3ace71f2e00f4a35" -uuid = "337d8026-41b4-5cde-a456-74a10e5b31d1" -version = "1.11.1+0" - [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" diff --git a/experiments/ClimaEarth/Manifest-v1.11.toml b/experiments/ClimaEarth/Manifest-v1.11.toml index 06ed1cc05d..661eb3ae32 100644 --- a/experiments/ClimaEarth/Manifest-v1.11.toml +++ b/experiments/ClimaEarth/Manifest-v1.11.toml @@ -322,14 +322,8 @@ git-tree-sha1 = "e1e82d32ba993a18fc760d5cbd7db3bcabd1f3c8" uuid = "908f55d8-4145-4867-9c14-5dad1a479e4d" version = "0.4.6" -[[deps.ClimaCoreTempestRemap]] -deps = ["ClimaComms", "ClimaCore", "CommonDataModel", "Dates", "LinearAlgebra", "NCDatasets", "PkgVersion", "TempestRemap_jll"] -git-tree-sha1 = "99845c1da7e9f687180c49cf4d53140f21fc8683" -uuid = "d934ef94-cdd4-4710-83d6-720549644b70" -version = "0.3.18" - [[deps.ClimaCoupler]] -deps = ["ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] +deps = ["ClimaComms", "ClimaCore", "Dates", "Logging", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] path = "../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.1" @@ -1168,12 +1162,6 @@ git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Requires", "TranscodingStreams"] -git-tree-sha1 = "ce5737c0d4490b0e0040b5dc77fbb6a351ddf188" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.8" - [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] git-tree-sha1 = "be3dc50a92e5a386872a493a10050136d4703f9b" @@ -1646,12 +1634,6 @@ git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "dd806c813429ff09878ea3eeb317818f3ca02871" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.28+3" - [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" @@ -2328,12 +2310,6 @@ git-tree-sha1 = "31834a05c8a9d52d7f56b23ae7ad1c3b72a4f1bf" uuid = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea" version = "0.13.2" -[[deps.TempestRemap_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "Libdl", "NetCDF_jll", "OpenBLAS32_jll"] -git-tree-sha1 = "723112218783928a20e0d865932694acfb7a7571" -uuid = "8573a8c5-1df0-515e-a024-abad257ee284" -version = "2.2.0+0" - [[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" diff --git a/experiments/ClimaEarth/Manifest.toml b/experiments/ClimaEarth/Manifest.toml index f702e4c217..a5e35e52ba 100644 --- a/experiments/ClimaEarth/Manifest.toml +++ b/experiments/ClimaEarth/Manifest.toml @@ -319,14 +319,8 @@ git-tree-sha1 = "e1e82d32ba993a18fc760d5cbd7db3bcabd1f3c8" uuid = "908f55d8-4145-4867-9c14-5dad1a479e4d" version = "0.4.6" -[[deps.ClimaCoreTempestRemap]] -deps = ["ClimaComms", "ClimaCore", "CommonDataModel", "Dates", "LinearAlgebra", "NCDatasets", "PkgVersion", "TempestRemap_jll"] -git-tree-sha1 = "99845c1da7e9f687180c49cf4d53140f21fc8683" -uuid = "d934ef94-cdd4-4710-83d6-720549644b70" -version = "0.3.18" - [[deps.ClimaCoupler]] -deps = ["ClimaComms", "ClimaCore", "ClimaCoreTempestRemap", "Dates", "JLD2", "Logging", "NCDatasets", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] +deps = ["ClimaComms", "ClimaCore", "Dates", "Logging", "SciMLBase", "StaticArrays", "SurfaceFluxes", "Thermodynamics"] path = "../.." uuid = "4ade58fe-a8da-486c-bd89-46df092ec0c7" version = "0.1.1" @@ -1160,12 +1154,6 @@ git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Requires", "TranscodingStreams"] -git-tree-sha1 = "ce5737c0d4490b0e0040b5dc77fbb6a351ddf188" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.8" - [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] git-tree-sha1 = "be3dc50a92e5a386872a493a10050136d4703f9b" @@ -1631,12 +1619,6 @@ git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" version = "1.3.5+1" -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6065c4cff8fee6c6770b277af45d5082baacdba1" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.24+0" - [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" @@ -2294,12 +2276,6 @@ git-tree-sha1 = "31834a05c8a9d52d7f56b23ae7ad1c3b72a4f1bf" uuid = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea" version = "0.13.2" -[[deps.TempestRemap_jll]] -deps = ["Artifacts", "HDF5_jll", "JLLWrappers", "Libdl", "NetCDF_jll", "OpenBLAS32_jll"] -git-tree-sha1 = "723112218783928a20e0d865932694acfb7a7571" -uuid = "8573a8c5-1df0-515e-a024-abad257ee284" -version = "2.2.0+0" - [[deps.TensorCore]] deps = ["LinearAlgebra"] git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" diff --git a/experiments/ClimaEarth/components/ocean/eisenman_seaice.jl b/experiments/ClimaEarth/components/ocean/eisenman_seaice.jl index 3c98c0fc11..28648c6190 100644 --- a/experiments/ClimaEarth/components/ocean/eisenman_seaice.jl +++ b/experiments/ClimaEarth/components/ocean/eisenman_seaice.jl @@ -1,7 +1,7 @@ import SciMLBase import ClimaCore as CC import ClimaTimeSteppers as CTS -import ClimaCoupler: Checkpointer, FluxCalculator, Interfacer +import ClimaCoupler: Checkpointer, FluxCalculator, Interfacer, Utilities ### ### Functions required by ClimaCoupler.jl for a SurfaceModelSimulation @@ -360,5 +360,5 @@ function ∑tendencies(dY, Y, cache, _) @. dY.q_sfc = -Y.q_sfc / Δt # update ice area fraction (binary mask for now) - cache.ice_area_fraction .= Regridder.binary_mask.(Y.h_ice) + cache.ice_area_fraction .= Utilities.binary_mask.(Y.h_ice) end diff --git a/experiments/ClimaEarth/components/ocean/prescr_seaice.jl b/experiments/ClimaEarth/components/ocean/prescr_seaice.jl index 1d60aded5d..f53f13f4ab 100644 --- a/experiments/ClimaEarth/components/ocean/prescr_seaice.jl +++ b/experiments/ClimaEarth/components/ocean/prescr_seaice.jl @@ -2,7 +2,7 @@ import SciMLBase import ClimaCore as CC import ClimaTimeSteppers as CTS import Thermodynamics as TD -import ClimaCoupler: Checkpointer, FluxCalculator, Interfacer, Regridder, Utilities +import ClimaCoupler: Checkpointer, FluxCalculator, Interfacer, Utilities ### ### Functions required by ClimaCoupler.jl for a SurfaceModelSimulation @@ -146,7 +146,7 @@ end ### # setting that SIC < 0.5 is counted as ocean if binary remapping. get_ice_fraction(h_ice::FT, mono::Bool, threshold = 0.5) where {FT} = - mono ? h_ice : Regridder.binary_mask(h_ice, threshold) + mono ? h_ice : Utilities.binary_mask(h_ice, threshold) """ ice_rhs!(du, u, p, _) @@ -173,7 +173,7 @@ function ice_rhs!(du, u, p, _) # If tendencies lead to temperature above freezing, set temperature to freezing @. rhs = min(rhs, (T_freeze - Y.T_sfc) / p.dt) # mask out no-ice areas - area_mask = Regridder.binary_mask.(area_fraction) + area_mask = Utilities.binary_mask.(area_fraction) dY.T_sfc .= rhs .* area_mask @. p.q_sfc = TD.q_vap_saturation_generic.(p.thermo_params, Y.T_sfc, p.ρ_sfc, TD.Ice()) diff --git a/experiments/ClimaEarth/components/ocean/slab_ocean.jl b/experiments/ClimaEarth/components/ocean/slab_ocean.jl index 43d37cfff1..6597270a07 100644 --- a/experiments/ClimaEarth/components/ocean/slab_ocean.jl +++ b/experiments/ClimaEarth/components/ocean/slab_ocean.jl @@ -170,7 +170,7 @@ function slab_ocean_rhs!(dY, Y, cache, t) p, F_turb_energy, F_radiative, area_fraction = cache FT = eltype(Y.T_sfc) rhs = @. -(F_turb_energy + F_radiative) / (p.h * p.ρ * p.c) - @. dY.T_sfc = rhs * Regridder.binary_mask(area_fraction) * p.evolving_switch + @. dY.T_sfc = rhs * Utilities.binary_mask(area_fraction) * p.evolving_switch @. cache.q_sfc = TD.q_vap_saturation_generic.(cache.thermo_params, Y.T_sfc, cache.ρ_sfc, TD.Liquid()) end diff --git a/experiments/ClimaEarth/run_amip.jl b/experiments/ClimaEarth/run_amip.jl index 504cf17cf9..9487d7e68f 100644 --- a/experiments/ClimaEarth/run_amip.jl +++ b/experiments/ClimaEarth/run_amip.jl @@ -48,7 +48,7 @@ import ClimaCore as CC # ## Coupler specific imports import ClimaCoupler import ClimaCoupler: - ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Regridder, TimeManager, Utilities + ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, TimeManager, Utilities import ClimaUtilities.SpaceVaryingInputs: SpaceVaryingInput import ClimaUtilities.TimeVaryingInputs: TimeVaryingInput, evaluate! @@ -217,7 +217,7 @@ Note that land-sea area fraction is different to the land-sea mask, which is a b # Preprocess the file to be 1s and 0s before remapping into onto the grid land_area_fraction = SpaceVaryingInput(land_mask_data, "landsea", boundary_space) if !mono_surface - land_area_fraction = Regridder.binary_mask.(land_area_fraction) + land_area_fraction = Utilities.binary_mask.(land_area_fraction) end Utilities.show_memory_usage() @@ -607,7 +607,7 @@ The concrete steps for proper initialization are: =# # 1.coupler updates surface model area fractions -Regridder.update_surface_fractions!(cs) +FieldExchanger.update_surface_fractions!(cs) # 2.surface density (`ρ_sfc`): calculated by the coupler by adiabatically extrapolating atmospheric thermal state to the surface. # For this, we need to import surface and atmospheric fields. The model sims are then updated with the new surface density. @@ -699,7 +699,7 @@ function solve_coupler!(cs) ## update the surface fractions for surface models, ## and update all component model simulations with the current fluxes stored in the coupler - Regridder.update_surface_fractions!(cs) + FieldExchanger.update_surface_fractions!(cs) FieldExchanger.update_model_sims!(cs.model_sims, cs.fields, cs.turbulent_fluxes) ## step component model simulations sequentially for one coupling timestep (Δt_cpl) diff --git a/experiments/ClimaEarth/run_cloudless_aquaplanet.jl b/experiments/ClimaEarth/run_cloudless_aquaplanet.jl index 7ca6c71e52..aaa35abd4a 100644 --- a/experiments/ClimaEarth/run_cloudless_aquaplanet.jl +++ b/experiments/ClimaEarth/run_cloudless_aquaplanet.jl @@ -24,7 +24,7 @@ import ClimaCore as CC # ## Coupler specific imports import ClimaCoupler import ClimaCoupler: - ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Regridder, TimeManager, Utilities + ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, TimeManager, Utilities pkg_dir = pkgdir(ClimaCoupler) diff --git a/experiments/ClimaEarth/run_cloudy_aquaplanet.jl b/experiments/ClimaEarth/run_cloudy_aquaplanet.jl index 5601948507..7188f4dba9 100644 --- a/experiments/ClimaEarth/run_cloudy_aquaplanet.jl +++ b/experiments/ClimaEarth/run_cloudy_aquaplanet.jl @@ -24,7 +24,7 @@ import ClimaCore as CC # ## Coupler specific imports import ClimaCoupler import ClimaCoupler: - ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Regridder, TimeManager, Utilities + ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, TimeManager, Utilities pkg_dir = pkgdir(ClimaCoupler) diff --git a/experiments/ClimaEarth/run_cloudy_slabplanet.jl b/experiments/ClimaEarth/run_cloudy_slabplanet.jl index 898c0a711b..e8e3b3329e 100644 --- a/experiments/ClimaEarth/run_cloudy_slabplanet.jl +++ b/experiments/ClimaEarth/run_cloudy_slabplanet.jl @@ -24,7 +24,7 @@ import ClimaCore as CC # ## Coupler specific imports import ClimaCoupler import ClimaCoupler: - ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Regridder, TimeManager, Utilities + ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, TimeManager, Utilities import ClimaUtilities.ClimaArtifacts: @clima_artifact import ClimaUtilities.SpaceVaryingInputs: SpaceVaryingInput diff --git a/experiments/ClimaEarth/run_moist_held_suarez.jl b/experiments/ClimaEarth/run_moist_held_suarez.jl index 0c89aa356c..ceab4edc64 100644 --- a/experiments/ClimaEarth/run_moist_held_suarez.jl +++ b/experiments/ClimaEarth/run_moist_held_suarez.jl @@ -27,7 +27,7 @@ import ClimaCore as CC # ## Coupler specific imports import ClimaCoupler import ClimaCoupler: - ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Regridder, TimeManager, Utilities + ConservationChecker, Checkpointer, FieldExchanger, FluxCalculator, Interfacer, TimeManager, Utilities pkg_dir = pkgdir(ClimaCoupler) diff --git a/src/ClimaCoupler.jl b/src/ClimaCoupler.jl index 044952a47c..7dc7fb5d8f 100644 --- a/src/ClimaCoupler.jl +++ b/src/ClimaCoupler.jl @@ -8,7 +8,6 @@ module ClimaCoupler include("Interfacer.jl") include("Utilities.jl") include("TimeManager.jl") -include("Regridder.jl") include("ConservationChecker.jl") include("FluxCalculator.jl") include("FieldExchanger.jl") diff --git a/src/FieldExchanger.jl b/src/FieldExchanger.jl index b06dbedf8c..8c7558bbb0 100644 --- a/src/FieldExchanger.jl +++ b/src/FieldExchanger.jl @@ -6,10 +6,95 @@ atmospheric and surface component models. """ module FieldExchanger -import ..Interfacer, ..FluxCalculator, ..Regridder +import ..Interfacer, ..FluxCalculator, ..Utilities export import_atmos_fields!, - import_combined_surface_fields!, update_sim!, update_model_sims!, reinit_model_sims!, step_model_sims! + update_surface_fractions!, + import_combined_surface_fields!, + update_sim!, + update_model_sims!, + reinit_model_sims!, + step_model_sims! + +""" + update_surface_fractions!(cs::Interfacer.CoupledSimulation) + +Updates dynamically changing area fractions. +Maintains the invariant that the sum of area fractions is 1 at all points. + +# Arguments +- `cs`: [Interfacer.CoupledSimulation] containing area fraction information. +""" +function update_surface_fractions!(cs::Interfacer.CoupledSimulation) + FT = Interfacer.float_type(cs) + + ice_fraction_before = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) + + # static fraction + land_fraction = Interfacer.get_field(cs.model_sims.land_sim, Val(:area_fraction)) + + # update component models with dynamic area fractions + # max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC) + Interfacer.update_field!( + cs.model_sims.ice_sim, + Val(:area_fraction), + max.(min.(ice_fraction_before, FT(1) .- land_fraction), FT(0)), + ) + ice_fraction = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) + + Interfacer.update_field!( + cs.model_sims.ocean_sim, + Val(:area_fraction), + max.(FT(1) .- (ice_fraction .+ land_fraction), FT(0)), + ) + ocean_fraction = Interfacer.get_field(cs.model_sims.ocean_sim, Val(:area_fraction)) + + # check that the sum of area fractions is 1 + @assert minimum(ice_fraction .+ land_fraction .+ ocean_fraction) ≈ FT(1) + @assert maximum(ice_fraction .+ land_fraction .+ ocean_fraction) ≈ FT(1) +end + +""" + dummmy_remap!(target, source) + +Simple stand-in function for remapping. +For AMIP we don't need regridding of surface model CC.Fields. +When we do, we re-introduce the ClimaCoreTempestRemap remapping functions. + +# Arguments +- `target`: [CC.Fields.Field] destination of remapping. +- `source`: [CC.Fields.Field] source of remapping. +""" +function dummmy_remap!(target, source) + parent(target) .= parent(source) +end + +nans_to_zero(v) = isnan(v) ? typeof(v)(0) : v + +""" + combine_surfaces!(combined_field::CC.Fields.Field, sims, field_name::Val) + +Sums the fields, specified by `field_name`, weighted by the respective area fractions of all +surface simulations. THe result is saved in `combined_field`. + +# Arguments +- `combined_field`: [CC.Fields.Field] output object containing weighted values. +- `sims`: [NamedTuple] containing simulations . +- `field_name`: [Val] containing the name Symbol of the field t be extracted by the `Interfacer.get_field` functions. + +# Example +- `combine_surfaces!(temp_field, cs.model_sims, Val(:surface_temperature))` +""" +function combine_surfaces!(combined_field, sims, field_name) + combined_field .= eltype(combined_field)(0) + for sim in sims + if sim isa Interfacer.SurfaceModelSimulation + combined_field .+= + Interfacer.get_field(sim, Val(:area_fraction)) .* nans_to_zero.(Interfacer.get_field(sim, field_name)) # this ensures that unitialized (masked) areas do not affect (TODO: move to mask / remove) + end + end +end + """ import_atmos_fields!(csf, model_sims, boundary_space, turbulent_fluxes) @@ -28,19 +113,19 @@ function import_atmos_fields!(csf, model_sims, boundary_space, turbulent_fluxes) # turbulent fluxes if turbulent_fluxes isa FluxCalculator.CombinedStateFluxesMOST - Regridder.dummmy_remap!(csf.F_turb_energy, Interfacer.get_field(atmos_sim, Val(:turbulent_energy_flux))) - Regridder.dummmy_remap!(csf.F_turb_moisture, Interfacer.get_field(atmos_sim, Val(:turbulent_moisture_flux))) + dummmy_remap!(csf.F_turb_energy, Interfacer.get_field(atmos_sim, Val(:turbulent_energy_flux))) + dummmy_remap!(csf.F_turb_moisture, Interfacer.get_field(atmos_sim, Val(:turbulent_moisture_flux))) end # surface density - needed for q_sat and requires atmos and sfc states, so it is calculated and saved in the coupler - Regridder.dummmy_remap!(csf.ρ_sfc, FluxCalculator.calculate_surface_air_density(atmos_sim, csf.T_S)) # TODO: generalize for PartitionedStateFluxes (#445) (use individual T_S) + dummmy_remap!(csf.ρ_sfc, FluxCalculator.calculate_surface_air_density(atmos_sim, csf.T_S)) # TODO: generalize for PartitionedStateFluxes (#445) (use individual T_S) # radiative fluxes - Regridder.dummmy_remap!(csf.F_radiative, Interfacer.get_field(atmos_sim, Val(:radiative_energy_flux_sfc))) + dummmy_remap!(csf.F_radiative, Interfacer.get_field(atmos_sim, Val(:radiative_energy_flux_sfc))) # precipitation - Regridder.dummmy_remap!(csf.P_liq, Interfacer.get_field(atmos_sim, Val(:liquid_precipitation))) - Regridder.dummmy_remap!(csf.P_snow, Interfacer.get_field(atmos_sim, Val(:snow_precipitation))) + dummmy_remap!(csf.P_liq, Interfacer.get_field(atmos_sim, Val(:liquid_precipitation))) + dummmy_remap!(csf.P_snow, Interfacer.get_field(atmos_sim, Val(:snow_precipitation))) end """ @@ -61,27 +146,27 @@ function import_combined_surface_fields!(csf, model_sims, turbulent_fluxes) combined_field = csf.temp1 # surface fields - Regridder.combine_surfaces!(combined_field, model_sims, Val(:surface_temperature)) - Regridder.dummmy_remap!(csf.T_S, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:surface_temperature)) + dummmy_remap!(csf.T_S, combined_field) - Regridder.combine_surfaces!(combined_field, model_sims, Val(:surface_direct_albedo)) - Regridder.dummmy_remap!(csf.surface_direct_albedo, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:surface_direct_albedo)) + dummmy_remap!(csf.surface_direct_albedo, combined_field) - Regridder.combine_surfaces!(combined_field, model_sims, Val(:surface_diffuse_albedo)) - Regridder.dummmy_remap!(csf.surface_diffuse_albedo, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:surface_diffuse_albedo)) + dummmy_remap!(csf.surface_diffuse_albedo, combined_field) if turbulent_fluxes isa FluxCalculator.CombinedStateFluxesMOST - Regridder.combine_surfaces!(combined_field, model_sims, Val(:roughness_momentum)) - Regridder.dummmy_remap!(csf.z0m_S, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:roughness_momentum)) + dummmy_remap!(csf.z0m_S, combined_field) - Regridder.combine_surfaces!(combined_field, model_sims, Val(:roughness_buoyancy)) - Regridder.dummmy_remap!(csf.z0b_S, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:roughness_buoyancy)) + dummmy_remap!(csf.z0b_S, combined_field) - Regridder.combine_surfaces!(combined_field, model_sims, Val(:beta)) - Regridder.dummmy_remap!(csf.beta, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:beta)) + dummmy_remap!(csf.beta, combined_field) - Regridder.combine_surfaces!(combined_field, model_sims, Val(:surface_humidity)) - Regridder.dummmy_remap!(csf.q_sfc, combined_field) + combine_surfaces!(combined_field, model_sims, Val(:surface_humidity)) + dummmy_remap!(csf.q_sfc, combined_field) end end @@ -128,7 +213,7 @@ function update_sim!(sim::Interfacer.SurfaceModelSimulation, csf, turbulent_flux Interfacer.update_field!(sim, Val(:air_density), csf.ρ_sfc) # turbulent fluxes - mask = Regridder.binary_mask.(area_fraction) + mask = Utilities.binary_mask.(area_fraction) # when PartitionedStateFluxes, turbulent fluxes are updated during the flux calculation if turbulent_fluxes isa FluxCalculator.CombinedStateFluxesMOST diff --git a/src/FluxCalculator.jl b/src/FluxCalculator.jl index 012b88b7dd..baa42f90e1 100644 --- a/src/FluxCalculator.jl +++ b/src/FluxCalculator.jl @@ -11,7 +11,7 @@ import StaticArrays import SurfaceFluxes as SF import Thermodynamics as TD import ClimaCore as CC -import ..Interfacer, ..Regridder +import ..Interfacer, ..Utilities export PartitionedStateFluxes, CombinedStateFluxesMOST, @@ -155,7 +155,7 @@ function partitioned_turbulent_fluxes!( # get area fraction (min = 0, max = 1) area_fraction = Interfacer.get_field(sim, Val(:area_fraction)) # get area mask [0, 1], where area_mask = 1 if area_fraction > 0 - area_mask = Regridder.binary_mask.(area_fraction) + area_mask = Utilities.binary_mask.(area_fraction) thermo_state_sfc = FluxCalculator.surface_thermo_state(sim, thermo_params, thermo_state_int) diff --git a/src/Regridder.jl b/src/Regridder.jl deleted file mode 100644 index b7f88c1725..0000000000 --- a/src/Regridder.jl +++ /dev/null @@ -1,730 +0,0 @@ -""" - Regridder - -This module contains functions to regrid information between CC.Spaces. -Many of the functions used in this module call TempestRemap functions -via ClimaCoreTempestRemap wrappers. -""" -module Regridder - -import Dates -import JLD2 -import NCDatasets -import ClimaComms -import ClimaCore as CC -import ClimaCoreTempestRemap as CCTR -import ..Interfacer, ..Utilities, ..TimeManager - -export write_to_hdf5, - read_from_hdf5, - dummmy_remap!, - remap_field_cgll_to_rll, - land_fraction, - update_surface_fractions!, - combine_surfaces!, - combine_surfaces_from_sol!, - binary_mask, - nans_to_zero, - truncate_dataset #= Converts NaNs to zeros of the same type. =# - - - -nans_to_zero(v) = isnan(v) ? typeof(v)(0) : v - -""" - reshape_cgll_sparse_to_field!(field::CC.Fields.Field, in_array::Array, R, ::CC.Spaces.SpectralElementSpace2D) - -Reshapes a sparse vector array `in_array` (CGLL, raw output of the TempestRemap), -and uses its data to populate the input Field object `field`. -Redundant nodes are populated using `dss` operations. - -# Arguments -- `field`: [CC.Fields.Field] object populated with the input array. -- `in_array`: [Array] input used to fill `field`. -- `R`: [NamedTuple] containing `target_idxs` and `row_indices` used for indexing. -- `space`: [CC.Spaces.SpectralElementSpace2D] 2d space to which we are mapping. -""" -function reshape_cgll_sparse_to_field!( - field::CC.Fields.Field, - in_array::SubArray, - R, - ::CC.Spaces.SpectralElementSpace2D, -) - field_array = parent(field) - - fill!(field_array, zero(eltype(field_array))) - Nf = size(field_array, 3) - - # populate the field by iterating over the sparse vector per face - for (n, row) in enumerate(R.row_indices) - it, jt, et = (view(R.target_idxs[1], n), view(R.target_idxs[2], n), view(R.target_idxs[3], n)) # cgll_x, cgll_y, elem - for f in 1:Nf - field_array[it, jt, f, et] .= in_array[row] - end - end - - # broadcast to the redundant nodes using unweighted dss - space = axes(field) - topology = CC.Spaces.topology(space) - hspace = CC.Spaces.horizontal_space(space) - CC.Topologies.dss!(CC.Fields.field_values(field), topology) -end - -""" - reshape_cgll_sparse_to_field!(field::CC.Fields.Field, in_array::Array, R, ::CC.Spaces.ExtrudedFiniteDifferenceSpace) - -Reshapes a sparse vector array `in_array` (CGLL, raw output of the TempestRemap), -and uses its data to populate the input Field object `field`. -Redundant nodes are populated using `dss` operations. - -# Arguments -- `field`: [CC.Fields.Field] object populated with the input array. -- `in_array`: [Array] input used to fill `field`. -- `R`: [NamedTuple] containing `target_idxs` and `row_indices` used for indexing. -- `space`: [CC.Spaces.ExtrudedFiniteDifferenceSpace] 3d space to which we are mapping. -""" -function reshape_cgll_sparse_to_field!( - field::CC.Fields.Field, - in_array::SubArray, - R, - ::CC.Spaces.ExtrudedFiniteDifferenceSpace, -) - field_array = parent(field) - - fill!(field_array, zero(eltype(field_array))) - Nf = size(field_array, 4) - Nz = size(field_array, 1) - - # populate the field by iterating over height, then over the sparse vector per face - for z in 1:Nz - for (n, row) in enumerate(R.row_indices) - it, jt, et = (view(R.target_idxs[1], n), view(R.target_idxs[2], n), view(R.target_idxs[3], n)) # cgll_x, cgll_y, elem - for f in 1:Nf - field_array[z, it, jt, f, et] .= in_array[row, z] - end - end - end - # broadcast to the redundant nodes using unweighted dss - space = axes(field) - topology = CC.Spaces.topology(space) - hspace = CC.Spaces.horizontal_space(space) - CC.Topologies.dss!(CC.Fields.field_values(field), topology) -end - -""" - hdwrite_regridfile_rll_to_cgll( - FT, - REGRID_DIR, - datafile_rll, - varname, - space; - hd_outfile_root = "data_cgll", - mono = false, - ) - -Reads and regrids data of the `varname` variable from an input NetCDF file and -saves it as another NetCDF file using Tempest Remap. -The input NetCDF fileneeds to be `Exodus` formatted, and can contain -time-dependent data. The output NetCDF file is then read back, the output -arrays converted into Fields and saved as HDF5 files (one per time slice). -This function should be called by the root process. -The saved regridded HDF5 output is readable by multiple MPI processes. - -# Arguments -- `FT`: [DataType] Float type. -- `REGRID_DIR`: [String] directory to save output files in. -- `datafile_rll`: [String] filename of RLL dataset to be mapped to CGLL. -- `varname`: [String] the name of the variable to be remapped. -- `space`: [CC.Spaces.AbstractSpace] the space to which we are mapping. -- `hd_outfile_root`: [String] root of the output file name. -- `mono`: [Bool] flag to specify monotone remapping. -""" -function hdwrite_regridfile_rll_to_cgll( - FT, - REGRID_DIR, - datafile_rll, - varname, - space; - hd_outfile_root = "data_cgll", - mono = false, -) - out_type = "cgll" - - outfile = hd_outfile_root * ".nc" - outfile_root = mono ? outfile[1:(end - 3)] * "_mono" : outfile[1:(end - 3)] - datafile_cgll = joinpath(REGRID_DIR, outfile_root * ".g") - - meshfile_rll = joinpath(REGRID_DIR, outfile_root * "_mesh_rll.g") - meshfile_cgll = joinpath(REGRID_DIR, outfile_root * "_mesh_cgll.g") - meshfile_overlap = joinpath(REGRID_DIR, outfile_root * "_mesh_overlap.g") - weightfile = joinpath(REGRID_DIR, outfile_root * "_remap_weights.nc") - - if space isa CC.Spaces.ExtrudedFiniteDifferenceSpace - space2d = CC.Spaces.horizontal_space(space) - else - space2d = space - end - - # If doesn't make sense to regrid with GPUs/MPI processes - cpu_singleton_context = ClimaComms.SingletonCommsContext(ClimaComms.CPUSingleThreaded()) - - topology = CC.Topologies.Topology2D( - cpu_singleton_context, - CC.Spaces.topology(space2d).mesh, - CC.Topologies.spacefillingcurve(CC.Spaces.topology(space2d).mesh), - ) - Nq = CC.Spaces.Quadratures.polynomial_degree(CC.Spaces.quadrature_style(space2d)) + 1 - - space2d_undistributed = CC.Spaces.SpectralElementSpace2D(topology, CC.Spaces.Quadratures.GLL{Nq}()) - - if space isa CC.Spaces.ExtrudedFiniteDifferenceSpace - vert_center_space = CC.Spaces.CenterFiniteDifferenceSpace(CC.Spaces.vertical_topology(space)) - space_undistributed = CC.Spaces.ExtrudedFiniteDifferenceSpace(space2d_undistributed, vert_center_space) - else - space_undistributed = space2d_undistributed - end - if isfile(datafile_cgll) == false - nlat, nlon = NCDatasets.NCDataset(datafile_rll) do ds - (ds.dim["lat"], ds.dim["lon"]) - end - # write lat-lon mesh - CCTR.rll_mesh(meshfile_rll; nlat = nlat, nlon = nlon) - - # write cgll mesh, overlap mesh and weight file - CCTR.write_exodus(meshfile_cgll, topology) - CCTR.overlap_mesh(meshfile_overlap, meshfile_rll, meshfile_cgll) - - # 'in_np = 1' and 'mono = true' arguments ensure mapping is conservative and monotone - # Note: for a kwarg not followed by a value, set it to true here (i.e. pass 'mono = true' to produce '--mono') - # Note: out_np = degrees of freedom = polynomial degree + 1 - kwargs = (; out_type = out_type, out_np = Nq) - kwargs = mono ? (; (kwargs)..., in_np = 1, mono = mono) : kwargs - CCTR.remap_weights(weightfile, meshfile_rll, meshfile_cgll, meshfile_overlap; kwargs...) - CCTR.apply_remap(datafile_cgll, datafile_rll, weightfile, [varname]) - else - @warn "Using the existing $datafile_cgll : check topology is consistent" - end - - # read the remapped file with sparse matrices - offline_outvector, coords = NCDatasets.NCDataset(datafile_cgll, "r") do ds_wt - ( - # read the data in, and remove missing type (will error if missing data is present) - offline_outvector = NCDatasets.nomissing(Array(ds_wt[varname])[:, :, :]), # ncol, z, times - coords = get_coords(ds_wt, space), - ) - end - - times = coords[1] - - # weightfile info needed to populate all nodes and save into fields with - # sparse matrices - _, _, row_indices = NCDatasets.NCDataset(weightfile, "r") do ds_wt - (Array(ds_wt["S"]), Array(ds_wt["col"]), Array(ds_wt["row"])) - end - - target_unique_idxs = - out_type == "cgll" ? collect(CC.Spaces.unique_nodes(space2d_undistributed)) : - collect(CC.Spaces.all_nodes(space2d_undistributed)) - target_unique_idxs_i = map(row -> target_unique_idxs[row][1][1], row_indices) - target_unique_idxs_j = map(row -> target_unique_idxs[row][1][2], row_indices) - target_unique_idxs_e = map(row -> target_unique_idxs[row][2], row_indices) - target_unique_idxs = (target_unique_idxs_i, target_unique_idxs_j, target_unique_idxs_e) - - R = (; target_idxs = target_unique_idxs, row_indices = row_indices) - - offline_field = CC.Fields.zeros(FT, space_undistributed) - - offline_fields = ntuple(x -> similar(offline_field), length(times)) - - ntuple( - x -> reshape_cgll_sparse_to_field!( - offline_fields[x], - selectdim(offline_outvector, length(coords) + 1, x), - R, - space, - ), - length(times), - ) - - map( - x -> write_to_hdf5(REGRID_DIR, hd_outfile_root, times[x], offline_fields[x], varname, cpu_singleton_context), - 1:length(times), - ) - JLD2.jldsave(joinpath(REGRID_DIR, hd_outfile_root * "_times.jld2"); times = times) -end - -""" - get_coords(ds, ::CC.Spaces.ExtrudedFiniteDifferenceSpace) - get_coords(ds, ::CC.Spaces.SpectralElementSpace2D) - -Extracts the coordinates from a NetCDF file `ds`. The coordinates are -returned as a tuple of arrays, one for each dimension. The dimensions are -determined by the space type. -""" -function get_coords(ds, ::CC.Spaces.ExtrudedFiniteDifferenceSpace) - data_dates = get_time(ds) - z = Array(ds["z"]) - return (data_dates, z) -end -function get_coords(ds, ::CC.Spaces.SpectralElementSpace2D) - data_dates = get_time(ds) - return (data_dates,) -end - -""" - get_time(ds) - -Extracts the time information from a NetCDF file `ds`. -""" -function get_time(ds) - if "time" in keys(ds.dim) - data_dates = Dates.DateTime.(Array(ds["time"])) - elseif "date" in keys(ds.dim) - data_dates = TimeManager.strdate_to_datetime.(string.(Int.(Array(ds["date"])))) - else - @warn "No dates available in input data file" - data_dates = [Dates.DateTime(0)] - end - return data_dates -end - -""" - write_to_hdf5(REGRID_DIR, hd_outfile_root, time, field, varname, comms_ctx) - -Function to save individual HDF5 files after remapping. -If a CommsContext other than `SingletonCommsContext` is used for `comms_ctx`, -the HDF5 output is readable by multiple MPI processes. - -# Arguments -- `REGRID_DIR`: [String] directory to save output files in. -- `hd_outfile_root`: [String] root of the output file name. -- `time`: [Dates.DateTime] the timestamp of the data being written. -- `field`: [CC.Fields.Field] object to be written. -- `varname`: [String] variable name of data. -- `comms_ctx`: [ClimaComms.AbstractCommsContext] context used for this operation. -""" -function write_to_hdf5(REGRID_DIR, hd_outfile_root, time, field, varname, comms_ctx) - t = Dates.datetime2unix.(time) - hdfwriter = - CC.InputOutput.HDF5Writer(joinpath(REGRID_DIR, hd_outfile_root * "_" * string(time) * ".hdf5"), comms_ctx) - - CC.InputOutput.HDF5.write_attribute(hdfwriter.file, "unix time", t) # TODO: a better way to write metadata, CMIP convention - CC.InputOutput.write!(hdfwriter, field, string(varname)) - Base.close(hdfwriter) -end - -""" - read_from_hdf5(REGIRD_DIR, hd_outfile_root, time, varname, comms_ctx) - -Read in a variable `varname` from an HDF5 file. -If a CommsContext other than `SingletonCommsContext` is used for `comms_ctx`, -the input HDF5 file must be readable by multiple MPI processes. - -# Arguments -- `REGRID_DIR`: [String] directory to save output files in. -- `hd_outfile_root`: [String] root of the output file name. -- `time`: [Dates.DateTime] the timestamp of the data being written. -- `varname`: [String] variable name of data. -- `comms_ctx`: [ClimaComms.AbstractCommsContext] context used for this operation. - -# Returns -- Field or FieldVector -""" -function read_from_hdf5(REGRID_DIR, hd_outfile_root, time, varname, comms_ctx) - hdfreader = - CC.InputOutput.HDF5Reader(joinpath(REGRID_DIR, hd_outfile_root * "_" * string(time) * ".hdf5"), comms_ctx) - - field = CC.InputOutput.read_field(hdfreader, varname) - Base.close(hdfreader) - return field -end - -""" - dummmy_remap!(target, source) - -Simple stand-in function for remapping. -For AMIP we don't need regridding of surface model CC.Fields. -When we do, we re-introduce the ClimaCoreTempestRemap remapping functions. - -# Arguments -- `target`: [CC.Fields.Field] destination of remapping. -- `source`: [CC.Fields.Field] source of remapping. -""" -function dummmy_remap!(target, source) - parent(target) .= parent(source) -end - -""" - write_datafile_cc(datafile_cc, field, name) - -Write the data stored in `field` to an NCDataset file `datafile_cc`. - -# Arguments -- `datafile_cc`: [String] filename of output file. -- `field`: [CC.Fields.Field] to be written to file. -- `name`: [Symbol] variable name. -""" -function write_datafile_cc(datafile_cc, field, name) - space = axes(field) - # write data - NCDatasets.NCDataset(datafile_cc, "c") do nc - CCTR.def_space_coord(nc, space; type = "cgll") - nc_field = NCDatasets.defVar(nc, name, Float64, space) - nc_field[:, 1] = field - - nothing - end -end - -""" - remap_field_cgll_to_rll( - name, - field::CC.Fields.Field, - remap_tmpdir, - datafile_rll; - nlat = 90, - nlon = 180 - ) - -Remap an individual FT-valued Field from model (CGLL) nodes to a lat-lon (RLL) -grid using TempestRemap. - -# Arguments -- `name`: [Symbol] variable name. -- `field`: [CC.Fields.Field] data to be remapped. -- `remap_tmpdir`: [String] directory used for remapping. -- `datafile_rll`: [String] filename of remapped data output. -""" -function remap_field_cgll_to_rll(name, field::CC.Fields.Field, remap_tmpdir, datafile_rll; nlat = 90, nlon = 180) - space = axes(field) - hspace = :topology in propertynames(space) ? space : CC.Spaces.horizontal_space(space) - Nq = CC.Spaces.Quadratures.polynomial_degree(CC.Spaces.quadrature_style(hspace)) + 1 - - # write out our cubed sphere mesh - meshfile_cc = remap_tmpdir * "/mesh_cubedsphere.g" - CCTR.write_exodus(meshfile_cc, CC.Spaces.topology(hspace)) - - meshfile_rll = remap_tmpdir * "/mesh_rll.g" - CCTR.rll_mesh(meshfile_rll; nlat = nlat, nlon = nlon) - - meshfile_overlap = remap_tmpdir * "/mesh_overlap.g" - CCTR.overlap_mesh(meshfile_overlap, meshfile_cc, meshfile_rll) - - weightfile = remap_tmpdir * "/remap_weights.nc" - CCTR.remap_weights(weightfile, meshfile_cc, meshfile_rll, meshfile_overlap; in_type = "cgll", in_np = Nq) - - datafile_cc = remap_tmpdir * "/datafile_cc.nc" - write_datafile_cc(datafile_cc, field, name) - - CCTR.apply_remap( # TODO: this can be done online - datafile_rll, - datafile_cc, - weightfile, - [string(name)], - ) -end - -""" - function land_fraction( - FT, - REGRID_DIR, - comms_ctx::ClimaComms.AbstractCommsContext, - infile, - varname, - boundary_space; - outfile_root = "land_sea_cgll", - mono = false, - threshold = 0.7, - ) - -Initialize a fraction for land/sea classification of grid squares over the space. -With `mono` = `true`, remappings are monotone and conservative, (slower). -With `mono` = `false`, values outside of `threshold` are cutoff (faster). - -See https://github.com/CliMA/ClimaCoupler.jl/wiki/ClimaCoupler-Lessons-Learned - for a detailed comparison of remapping approaches. - -# Arguments -- `FT`: [DataType] Float type -- `REGRID_DIR`: [String] directory to save output files in. -- `comms_ctx`: [ClimaComms.AbstractCommsContext] context used for this operation. -- `infile`: [String] filename containing input data. -- `varname`: [Symbol] variable name. -- `boundary_space`: [CC.Spaces.AbstractSpace] over which we are mapping data. -- `outfile_root`: [String] root for output file name. -- `mono`: [Bool] flag for monotone remapping. -- `threshold`: [FT] cutoff value for `binary_mask` when non-monotone remapping. - -# Returns -- CC.Fields.Field -""" -function land_fraction( - FT, - REGRID_DIR, - comms_ctx::ClimaComms.AbstractCommsContext, - infile, - varname, - boundary_space; - outfile_root = "land_sea_cgll", - mono = false, - threshold = 0.7, -) - - if ClimaComms.iamroot(comms_ctx) - hdwrite_regridfile_rll_to_cgll( - FT, - REGRID_DIR, - infile, - varname, - boundary_space; - hd_outfile_root = outfile_root, - mono = mono, - ) - end - ClimaComms.barrier(comms_ctx) - file_dates = JLD2.load(joinpath(REGRID_DIR, outfile_root * "_times.jld2"), "times") - fraction = read_from_hdf5(REGRID_DIR, outfile_root, file_dates[1], varname, comms_ctx) - fraction = Utilities.swap_space!(boundary_space, fraction) # needed if we are reading from previous run - return mono ? fraction : binary_mask.(fraction, threshold) -end - -""" - update_surface_fractions!(cs::Interfacer.CoupledSimulation) - -Updates dynamically changing area fractions. -Maintains the invariant that the sum of area fractions is 1 at all points. - -# Arguments -- `cs`: [Interfacer.CoupledSimulation] containing area fraction information. -""" -function update_surface_fractions!(cs::Interfacer.CoupledSimulation) - FT = Interfacer.float_type(cs) - - ice_fraction_before = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) - - # static fraction - land_fraction = Interfacer.get_field(cs.model_sims.land_sim, Val(:area_fraction)) - - # update component models with dynamic area fractions - # max needed to avoid Float32 errors (see issue #271; Heisenbug on HPC) - Interfacer.update_field!( - cs.model_sims.ice_sim, - Val(:area_fraction), - max.(min.(ice_fraction_before, FT(1) .- land_fraction), FT(0)), - ) - ice_fraction = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) - - Interfacer.update_field!( - cs.model_sims.ocean_sim, - Val(:area_fraction), - max.(FT(1) .- (ice_fraction .+ land_fraction), FT(0)), - ) - ocean_fraction = Interfacer.get_field(cs.model_sims.ocean_sim, Val(:area_fraction)) - - # check that the sum of area fractions is 1 - @assert minimum(ice_fraction .+ land_fraction .+ ocean_fraction) ≈ FT(1) - @assert maximum(ice_fraction .+ land_fraction .+ ocean_fraction) ≈ FT(1) -end - -""" - binary_mask(var, threshold) - -Converts a number `var` to 1, if `var` is greater or equal than a given `threshold` value, -or 0 otherwise, keeping the same type. - -# Arguments -- `var`: [FT] value to be converted. -- `threshold`: [FT] cutoff value for conversions. -""" -binary_mask(var, threshold) = var >= threshold ? one(var) : zero(var) - -""" - binary_mask(var) - -Converts a number `var` to 1, if `var` is greater or equal than `eps(FT)`, -or 0 otherwise, keeping the same type. - -# Arguments -- `var`: [FT] value to be converted. -""" -binary_mask(var) = binary_mask(var, eps(eltype(var))) - -""" - combine_surfaces!(combined_field::CC.Fields.Field, sims, field_name::Val) - -Sums the fields, specified by `field_name`, weighted by the respective area fractions of all -surface simulations. THe result is saved in `combined_field`. - -# Arguments -- `combined_field`: [CC.Fields.Field] output object containing weighted values. -- `sims`: [NamedTuple] containing simulations . -- `field_name`: [Val] containing the name Symbol of the field t be extracted by the `Interfacer.get_field` functions. - -# Example -- `combine_surfaces!(temp_field, cs.model_sims, Val(:surface_temperature))` -""" -function combine_surfaces!(combined_field::CC.Fields.Field, sims::NamedTuple, field_name::Val) - combined_field .= eltype(combined_field)(0) - for sim in sims - if sim isa Interfacer.SurfaceModelSimulation - combined_field .+= - Interfacer.get_field(sim, Val(:area_fraction)) .* nans_to_zero.(Interfacer.get_field(sim, field_name)) # this ensures that unitialized (masked) areas do not affect (TODO: move to mask / remove) - end - end -end - -""" - combine_surfaces_from_sol!(combined_field::CC.Fields.Field, fractions::NamedTuple, fields::NamedTuple) - -Sums Field objects in `fields` weighted by the respective area fractions, and updates -these values in `combined_field`. -NamedTuples `fields` and `fractions` must have matching field names. -This method can be used to combine fields that were saved in the solution history. - -# Arguments -- `combined_field`: [CC.Fields.Field] output object containing weighted values. -- `fractions`: [NamedTuple] containing weights used on values in `fields`. -- `fields`: [NamedTuple] containing values to be weighted by `fractions`. -""" -function combine_surfaces_from_sol!(combined_field::CC.Fields.Field, fractions::NamedTuple, fields::NamedTuple) - combined_field .= 0 - warn_nans = false - for surface_name in propertynames(fields) # could use dot here? - if any(x -> isnan(x), getproperty(fields, surface_name)) - warn_nans = true - end - combined_field .+= getproperty(fractions, surface_name) .* nans_to_zero.(getproperty(fields, surface_name)) - end - warn_nans && @warn "NaNs were detected and converted to zeros." -end - -""" - read_remapped_field(name::Symbol, datafile_latlon::String, lev_name = "z") - -Extract data and coordinates from `datafile_latlon`. -""" -function read_remapped_field(name::Symbol, datafile_latlon::String, lev_name = "z") - out = NCDatasets.NCDataset(datafile_latlon, "r") do nc - lon = Array(nc["lon"]) - lat = Array(nc["lat"]) - lev = lev_name in keys(nc) ? Array(nc[lev_name]) : Float64(-999) - var = Array(nc[name]) - coords = (; lon = lon, lat = lat, lev = lev) - - (var, coords) - end - - return out -end - -""" - truncate_dataset(datafile, filename, varname, datapath_trunc, date0, t_start, t_end, comms_ctx) - -Truncates given data set, and constructs a new dataset containing only -the dates that are used in the simulation -""" -function truncate_dataset( - datafile, - filename, - varname, - datapath_trunc, - date0, - t_start, - t_end, - comms_ctx::ClimaComms.AbstractCommsContext, -) - date_start = date0 + Dates.Second(t_start) - date_end = date0 + Dates.Second(t_start + t_end) - - filename_truncated = replace( - string(lowercase(filename), "_truncated_data_", string(date_start), string(date_end), ".nc"), - r":" => "", - ) - datafile_truncated = joinpath(datapath_trunc, filename_truncated) - - if ClimaComms.iamroot(comms_ctx) - ds = NCDatasets.NCDataset(datafile, "r") - dates = ds["time"][:] - - # Find the bounding indices of the dates we need - (start_id, end_id) = find_idx_bounding_dates(dates, date_start, date_end) - - var_truncated = NCDatasets.nomissing(NCDatasets.view(ds, time = start_id:end_id)[varname]) - - # Create new dataset to fill with truncated data - ds_truncated = NCDatasets.NCDataset(datafile_truncated, "c") - - # Keep all dimensions of original dataset (except for time, which we truncate) - ds_dim_names = NCDatasets.dimnames(ds[varname]) - for dim_name in ds_dim_names - dim_name != "time" && NCDatasets.defDim(ds_truncated, dim_name, ds.dim[dim_name]) - end - dates_truncated = dates[start_id:end_id] - NCDatasets.defDim(ds_truncated, "time", length(dates_truncated)) - ds_truncated.attrib["title"] = ds.attrib["title"] * " (dates truncated)" - - # Define dimension variables - for dim_name in ds_dim_names - if dim_name == "time" - var = NCDatasets.defVar(ds_truncated, dim_name, dates_truncated, (dim_name,)) - else - var = NCDatasets.defVar(ds_truncated, dim_name, ds[dim_name][:], (dim_name,)) - end - end - - # Create variable of interest in new dataset, and fill with input dataset values - var = NCDatasets.defVar(ds_truncated, varname, var_truncated, ds_dim_names) - - close(ds) - close(ds_truncated) - - return datafile_truncated - end -end - -""" - find_idx_bounding_dates(dates, date_start, date_end) - -Returns the index range from dates that contains date_start to date_end -""" -function find_idx_bounding_dates(dates, date_start, date_end) - # if the simulation start date is before our first date in the dataset - # leave the beginning of the truncated dataset to be first date available - if date_start < dates[1] - start_id = 1 - # if the simulation start date is after the last date in the dataset - # start the truncated dataset at its last possible date - elseif date_start > last(dates) - start_id = length(dates) - # if the simulation start date falls within the range of the dataset - # find the closest date to the start date and truncate there - else - (~, start_id) = findmin(x -> abs(x - date_start), dates) - # if the closest date is after the start date, add one more date before - if dates[start_id] > date_start - start_id = start_id - 1 - end - end - - # if the simulation end date is before our first date in the dataset - # truncate the end of the dataset to be the first date - if date_end < dates[1] - end_id = 1 - # if the simulation end date is after the last date in the dataset - # leave the end of the dataset as is - elseif date_end > last(dates) - end_id = length(dates) - # if the simulation end date falls within the range of the dataset - # find the closest date to the end date and truncate there - else - (~, end_id) = findmin(x -> abs(x - date_end), dates) - # if the closest date is before the end date, add one more date after - if dates[end_id] < date_end - end_id = end_id + 1 - end - end - - return (; start_id, end_id) -end - -end # Module diff --git a/src/Utilities.jl b/src/Utilities.jl index afdd749239..02a0df838b 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -11,7 +11,30 @@ import ClimaCore as CC import Logging import ClimaUtilities.OutputPathGenerator: generate_output_path -export swap_space!, get_device, get_comms_context, show_memory_usage, setup_output_dirs, time_to_seconds +export binary_mask, swap_space!, get_device, get_comms_context, show_memory_usage, setup_output_dirs, time_to_seconds + +""" + binary_mask(var, threshold) + +Converts a number `var` to 1, if `var` is greater or equal than a given `threshold` value, +or 0 otherwise, keeping the same type. + +# Arguments +- `var`: [FT] value to be converted. +- `threshold`: [FT] cutoff value for conversions. +""" +binary_mask(var, threshold) = var >= threshold ? one(var) : zero(var) + +""" + binary_mask(var) + +Converts a number `var` to 1, if `var` is greater or equal than `eps(FT)`, +or 0 otherwise, keeping the same type. + +# Arguments +- `var`: [FT] value to be converted. +""" +binary_mask(var) = binary_mask(var, eps(eltype(var))) """ swap_space!(space_out::CC.Spaces.AbstractSpace, field_in::CC.Fields.Field) diff --git a/test/Project.toml b/test/Project.toml index dd49613652..b26f1ada1e 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,9 +7,11 @@ ClimaAtmos = "b2c96348-7fb7-4fe0-8da9-78d88439e717" ClimaComms = "3a4d1b5c-c61d-41fd-a00a-5873ba7a1b0d" ClimaCore = "d414da3d-4745-48bb-8d80-42e94e092884" ClimaCoreMakie = "908f55d8-4145-4867-9c14-5dad1a479e4d" +ClimaCoreTempestRemap = "d934ef94-cdd4-4710-83d6-720549644b70" ClimaCoupler = "4ade58fe-a8da-486c-bd89-46df092ec0c7" ClimaParams = "5c42b081-d73a-476f-9059-fd94b934656c" ClimaTimeSteppers = "595c0a79-7f3d-439a-bc5a-b232dc3bde79" +ClimaUtilities = "b3f4f4ca-9299-4f7f-bd9b-81e1242a7513" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" diff --git a/test/TestHelper.jl b/test/TestHelper.jl index 537ec17853..e03a3df6d0 100644 --- a/test/TestHelper.jl +++ b/test/TestHelper.jl @@ -9,6 +9,7 @@ module TestHelper import ClimaCore as CC import ClimaComms import NCDatasets +import Dates export create_space, gen_ncdata @@ -118,13 +119,41 @@ function gen_ncdata_time(FT, path, varname, val) # Define variables lon = NCDatasets.defVar(nc, "lon", FT, ("lon",)) lat = NCDatasets.defVar(nc, "lat", FT, ("lat",)) - time = NCDatasets.defVar(nc, "time", Float64, ("time",)) + time = NCDatasets.defVar(nc, "time", Dates.DateTime.([2020.0, 2021.0]), ("time",)) v = NCDatasets.defVar(nc, varname, FT, ("lon", "lat", "time")) # Populate lon and lat lon[:] = [i for i in 0.0:(360 / 64):(360 - (360 / 64))] lat[:] = [i for i in (-90 + (180 / 64)):(180 / 32):(90 - (180 / 64))] - time[:] = [Float64(i) for i in 1:2] + + # Generate some example data and write it to v + v[:, :, 1] = [val * 0 for i in 1:nc.dim["lon"], j in 1:nc.dim["lat"]] + v[:, :, 2] = [val for i in 1:nc.dim["lon"], j in 1:nc.dim["lat"]] + + close(nc) +end + +function gen_ncdata_date(FT, path, varname, val) + isfile(path) && rm(path) + + # Create dataset of all ones + nc = NCDatasets.NCDataset(path, "c") + + # Define dataset information + NCDatasets.defDim(nc, "lon", 64) + NCDatasets.defDim(nc, "lat", 32) + NCDatasets.defDim(nc, "date", 2) + nc.attrib["title"] = "this is an NCDataset containing the same value at each point on a lat/lon grid at two dates" + + # Define variables + lon = NCDatasets.defVar(nc, "lon", FT, ("lon",)) + lat = NCDatasets.defVar(nc, "lat", FT, ("lat",)) + time = NCDatasets.defVar(nc, "date", [20200101, 20210101], ("date",)) + v = NCDatasets.defVar(nc, varname, FT, ("lon", "lat", "date")) + + # Populate lon and lat + lon[:] = [i for i in 0.0:(360 / 64):(360 - (360 / 64))] + lat[:] = [i for i in (-90 + (180 / 64)):(180 / 32):(90 - (180 / 64))] # Generate some example data and write it to v v[:, :, 1] = [val * 0 for i in 1:nc.dim["lon"], j in 1:nc.dim["lat"]] diff --git a/test/component_model_tests/eisenman_seaice_tests.jl b/test/component_model_tests/eisenman_seaice_tests.jl index 85d5c9d581..5d99af8bbd 100644 --- a/test/component_model_tests/eisenman_seaice_tests.jl +++ b/test/component_model_tests/eisenman_seaice_tests.jl @@ -4,7 +4,7 @@ import Thermodynamics as TD import Thermodynamics.Parameters as TDP import ClimaParams # required for TDP import ClimaCoupler -import ClimaCoupler: Interfacer, Regridder +import ClimaCoupler: Interfacer include(joinpath("..", "TestHelper.jl")) import .TestHelper diff --git a/test/field_exchanger_tests.jl b/test/field_exchanger_tests.jl index 3cdde139c5..ee1e8fd5a5 100644 --- a/test/field_exchanger_tests.jl +++ b/test/field_exchanger_tests.jl @@ -56,6 +56,29 @@ Interfacer.get_field(sim::Union{TestSurfaceSimulation2, TestSurfaceSimulation2}, Interfacer.reinit!(::TestSurfaceSimulation1) = nothing Interfacer.step!(::TestSurfaceSimulation1, _) = nothing +struct TestSurfaceSimulationA <: Interfacer.SurfaceModelSimulation end +struct TestSurfaceSimulationB <: Interfacer.SurfaceModelSimulation end +struct TestSurfaceSimulationC <: Interfacer.SurfaceModelSimulation end +struct TestSurfaceSimulationD <: Interfacer.SurfaceModelSimulation end + +# Initialize weights (fractions) and initial values (fields) +Interfacer.get_field(::TestSurfaceSimulationA, ::Val{:random}) = 1.0 +Interfacer.get_field(::TestSurfaceSimulationB, ::Val{:random}) = 1.0 +Interfacer.get_field(::TestSurfaceSimulationC, ::Val{:random}) = 1.0 +Interfacer.get_field(::TestSurfaceSimulationD, ::Val{:random}) = 1.0 + +Interfacer.get_field(::TestSurfaceSimulationA, ::Val{:area_fraction}) = 0.0 +Interfacer.get_field(::TestSurfaceSimulationB, ::Val{:area_fraction}) = 0.5 +Interfacer.get_field(::TestSurfaceSimulationC, ::Val{:area_fraction}) = 2.0 +Interfacer.get_field(::TestSurfaceSimulationD, ::Val{:area_fraction}) = -10.0 + +struct DummyStub{C} <: Interfacer.SurfaceModelSimulation + cache::C +end +Interfacer.get_field(sim::DummyStub, ::Val{:area_fraction}) = sim.cache.area_fraction +function Interfacer.update_field!(sim::DummyStub, ::Val{:area_fraction}, field::CC.Fields.Field) + sim.cache.area_fraction .= field +end # atmos sim struct TestAtmosSimulation{C} <: Interfacer.AtmosModelSimulation cache::C @@ -99,6 +122,90 @@ Interfacer.update_field!(sim::TestSurfaceSimulationLand, ::Val{:liquid_precipita Interfacer.update_field!(sim::TestSurfaceSimulationLand, ::Val{:snow_precipitation}, field) = nothing for FT in (Float32, Float64) + @testset "test dummmy_remap!" begin + test_space = TestHelper.create_space(FT) + test_field_ones = CC.Fields.ones(test_space) + target_field = CC.Fields.zeros(test_space) + + FieldExchanger.dummmy_remap!(target_field, test_field_ones) + @test parent(target_field) == parent(test_field_ones) + end + + @testset "test update_surface_fractions!" begin + test_space = TestHelper.create_space(FT) + # Construct land fraction of 0s in top half, 1s in bottom half + land_fraction = CC.Fields.ones(test_space) + dims = size(parent(land_fraction)) + m = dims[1] + n = dims[2] + parent(land_fraction)[1:(m ÷ 2), :, :, :] .= FT(0) + + # Construct ice fraction of 0s on left, 0.5s on right + ice_d = CC.Fields.zeros(test_space) + parent(ice_d)[:, (n ÷ 2 + 1):n, :, :] .= FT(0.5) + + # Construct ice fraction of 0s on left, 0.5s on right + ocean_d = CC.Fields.zeros(test_space) + + # Fill in only the necessary parts of the simulation + cs = Interfacer.CoupledSimulation{FT}( + nothing, # comms_ctx + nothing, # dates + nothing, # boundary_space + nothing, # fields + nothing, # conservation_checks + (Int(0), Int(1000)), # tspan + Int(200), # Δt_cpl + (; + ice_sim = DummyStub((; area_fraction = ice_d)), + ocean_sim = Interfacer.SurfaceStub((; area_fraction = ocean_d)), + land_sim = DummyStub((; area_fraction = land_fraction)), + ), # model_sims + (;), # mode + (;), # callbacks + (;), # dirs + nothing, # turbulent_fluxes + nothing, # thermo_params + nothing, # amip_diags_handler + ) + + FieldExchanger.update_surface_fractions!(cs) + + # Test that sum of fractions is 1 everywhere + ice_fraction = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) + ocean_fraction = Interfacer.get_field(cs.model_sims.ocean_sim, Val(:area_fraction)) + @test all(parent(ice_fraction .+ ocean_fraction .+ land_fraction) .== FT(1)) + end + + @testset "test combine_surfaces" begin + test_space = TestHelper.create_space(FT) + combined_field = CC.Fields.ones(test_space) + + var_name = Val(:random) + sims = (; + a = TestSurfaceSimulationA(), + b = TestSurfaceSimulationB(), + c = TestSurfaceSimulationC(), + d = TestSurfaceSimulationD(), + ) + + fractions = ( + a = Interfacer.get_field(sims.a, Val(:area_fraction)), + b = Interfacer.get_field(sims.b, Val(:area_fraction)), + c = Interfacer.get_field(sims.c, Val(:area_fraction)), + d = Interfacer.get_field(sims.d, Val(:area_fraction)), + ) + fields = ( + a = Interfacer.get_field(sims.a, var_name), + b = Interfacer.get_field(sims.b, var_name), + c = Interfacer.get_field(sims.c, var_name), + d = Interfacer.get_field(sims.d, var_name), + ) + + FieldExchanger.combine_surfaces!(combined_field, sims, var_name) + @test all(parent(combined_field) .== FT(sum(fractions) * sum(fields) / length(fields))) + end + @testset "import_atmos_fields! for FT=$FT" begin boundary_space = TestHelper.create_space(FT) coupler_names = (:F_turb_energy, :F_turb_moisture, :F_radiative, :P_liq, :P_snow, :ρ_sfc, :T_S) diff --git a/test/mpi_tests/regridder_mpi_tests.jl b/test/mpi_tests/regridder_mpi_tests.jl deleted file mode 100644 index b91857ba7f..0000000000 --- a/test/mpi_tests/regridder_mpi_tests.jl +++ /dev/null @@ -1,47 +0,0 @@ -#= - Unit tests for ClimaCoupler Regridder module functions which require MPI - -These are in a separate testing file from the other Regridder unit tests so -that MPI can be enabled for testing of these functions. -=# -import Test: @test, @testset -import Dates -import ClimaComms -@static pkgversion(ClimaComms) >= v"0.6" && ClimaComms.@import_required_backends -import ClimaCore as CC -import ClimaCoupler -import ClimaCoupler: Regridder - -include(joinpath("..", "TestHelper.jl")) -import .TestHelper - -# Set up MPI communications context -# Note that runs will hang if a context is initialized twice in the same file, -# so this context should be shared among all tests in this file. -device = ClimaComms.CPUSingleThreaded() -const comms_ctx = ClimaComms.context(device) -pid, nprocs = ClimaComms.init(comms_ctx) - -@testset "test write_to_hdf5 and read_from_hdf5 with MPI" begin - for FT in (Float32, Float64) - # Create temporary regrid directory on root process and broadcast - regrid_dir = nothing - if ClimaComms.iamroot(comms_ctx) - regrid_dir = mktempdir(pwd(), prefix = "regrid_tmp_") - end - regrid_dir = ClimaComms.bcast(comms_ctx, regrid_dir) - - hd_outfile_root = "hdf5_out_test" - tx = Dates.DateTime(1979, 01, 01, 01, 00, 00) - test_space = TestHelper.create_space(FT, comms_ctx = comms_ctx) - input_field = CC.Fields.ones(test_space) - varname = "testdata" - - ClimaComms.barrier(comms_ctx) - Regridder.write_to_hdf5(regrid_dir, hd_outfile_root, tx, input_field, varname, comms_ctx) - - ClimaComms.barrier(comms_ctx) - output_field = Regridder.read_from_hdf5(regrid_dir, hd_outfile_root, tx, varname, comms_ctx) - @test parent(input_field) == parent(output_field) - end -end diff --git a/test/mpi_tests/run_mpi_tests.jl b/test/mpi_tests/run_mpi_tests.jl deleted file mode 100644 index fef8c91b98..0000000000 --- a/test/mpi_tests/run_mpi_tests.jl +++ /dev/null @@ -1,37 +0,0 @@ -import MPI -#= -# if running locally: -module purge -module load julia/1.10.1 cuda/12.2 ucx/1.14.1_cuda-12.2 nsight-systems/2023.4.1 -export OPENBLAS_NUM_THREADS=1 -export JULIA_NVTX_CALLBACKS=gc -export OMPI_MCA_opal_warn_on_missing_libcuda=0 -export JULIA_MAX_NUM_PRECOMPILE_FILES=100 -export JULIA_LOAD_PATH= - -export CLIMACORE_DISTRIBUTED="MPI" - -julia -e 'using Pkg; Pkg.add("MPIPreferences"); using MPIPreferences; use_system_binary()' - -julia -e 'using Pkg; Pkg.instantiate(;verbose=true)' -julia -e 'using Pkg; Pkg.precompile()' -julia -e 'using Pkg; Pkg.status()' - -# then precompile all packages and run with `julia` and the default env -=# - -function runmpi(file; ntasks = 1) - MPI.mpiexec() do cmd - Base.run( - `$cmd -n $ntasks $(Base.julia_cmd()) --startup-file=no --project=$(Base.active_project()) $file`; - wait = true, - ) - true - end -end - -if !Sys.iswindows() - @info "tests started" - runmpi(joinpath(@__DIR__, "regridder_mpi_tests.jl"), ntasks = 2) - runmpi(joinpath(@__DIR__, "checkpointer_mpi_tests.jl"), ntasks = 1) -end diff --git a/test/regridder_tests.jl b/test/regridder_tests.jl deleted file mode 100644 index 4ac054c4da..0000000000 --- a/test/regridder_tests.jl +++ /dev/null @@ -1,405 +0,0 @@ -#= - Unit tests for ClimaCoupler Regridder module -=# -import Test: @testset, @test, @test_logs -import Dates -import NCDatasets -import ClimaComms -@static pkgversion(ClimaComms) >= v"0.6" && ClimaComms.@import_required_backends -import ClimaCore as CC -import ClimaCoupler -import ClimaCoupler: Interfacer, Regridder, TimeManager - -include("TestHelper.jl") -import .TestHelper - -const comms_ctx = ClimaComms.SingletonCommsContext() -const pid, nprocs = ClimaComms.init(comms_ctx) - -struct TestSurfaceSimulationA <: Interfacer.SurfaceModelSimulation end -struct TestSurfaceSimulationB <: Interfacer.SurfaceModelSimulation end -struct TestSurfaceSimulationC <: Interfacer.SurfaceModelSimulation end -struct TestSurfaceSimulationD <: Interfacer.SurfaceModelSimulation end - -# Initialize weights (fractions) and initial values (fields) -Interfacer.get_field(::TestSurfaceSimulationA, ::Val{:random}) = 1.0 -Interfacer.get_field(::TestSurfaceSimulationB, ::Val{:random}) = 1.0 -Interfacer.get_field(::TestSurfaceSimulationC, ::Val{:random}) = 1.0 -Interfacer.get_field(::TestSurfaceSimulationD, ::Val{:random}) = 1.0 - -Interfacer.get_field(::TestSurfaceSimulationA, ::Val{:area_fraction}) = 0.0 -Interfacer.get_field(::TestSurfaceSimulationB, ::Val{:area_fraction}) = 0.5 -Interfacer.get_field(::TestSurfaceSimulationC, ::Val{:area_fraction}) = 2.0 -Interfacer.get_field(::TestSurfaceSimulationD, ::Val{:area_fraction}) = -10.0 - -struct DummyStub{C} <: Interfacer.SurfaceModelSimulation - cache::C -end -Interfacer.get_field(sim::DummyStub, ::Val{:area_fraction}) = sim.cache.area_fraction -function Interfacer.update_field!(sim::DummyStub, ::Val{:area_fraction}, field::CC.Fields.Field) - sim.cache.area_fraction .= field -end - -for FT in (Float32, Float64) - @testset "test dummmy_remap!" begin - test_space = TestHelper.create_space(FT) - test_field_ones = CC.Fields.ones(test_space) - target_field = CC.Fields.zeros(test_space) - - Regridder.dummmy_remap!(target_field, test_field_ones) - @test parent(target_field) == parent(test_field_ones) - end - - @testset "test update_surface_fractions!" begin - test_space = TestHelper.create_space(FT) - # Construct land fraction of 0s in top half, 1s in bottom half - land_fraction = CC.Fields.ones(test_space) - dims = size(parent(land_fraction)) - m = dims[1] - n = dims[2] - parent(land_fraction)[1:(m ÷ 2), :, :, :] .= FT(0) - - # Construct ice fraction of 0s on left, 0.5s on right - ice_d = CC.Fields.zeros(test_space) - parent(ice_d)[:, (n ÷ 2 + 1):n, :, :] .= FT(0.5) - - # Construct ice fraction of 0s on left, 0.5s on right - ocean_d = CC.Fields.zeros(test_space) - - # Fill in only the necessary parts of the simulation - cs = Interfacer.CoupledSimulation{FT}( - nothing, # comms_ctx - nothing, # dates - nothing, # boundary_space - nothing, # fields - nothing, # conservation_checks - (Int(0), Int(1000)), # tspan - Int(200), # Δt_cpl - (; - ice_sim = DummyStub((; area_fraction = ice_d)), - ocean_sim = Interfacer.SurfaceStub((; area_fraction = ocean_d)), - land_sim = DummyStub((; area_fraction = land_fraction)), - ), # model_sims - (;), # mode - (;), # callbacks - (;), # dirs - nothing, # turbulent_fluxes - nothing, # thermo_params - nothing, # amip_diags_handler - ) - - Regridder.update_surface_fractions!(cs) - - # Test that sum of fractions is 1 everywhere - ice_fraction = Interfacer.get_field(cs.model_sims.ice_sim, Val(:area_fraction)) - ocean_fraction = Interfacer.get_field(cs.model_sims.ocean_sim, Val(:area_fraction)) - @test all(parent(ice_fraction .+ ocean_fraction .+ land_fraction) .== FT(1)) - end - - @testset "test combine_surfaces_from_sol!" begin - test_space = TestHelper.create_space(FT) - combined_field = CC.Fields.ones(test_space) - - # Initialize weights (fractions) and initial values (fields) - fractions = (a = 0.0, b = 0.5, c = 2.0, d = -10.0) - fields = (a = 1.0, b = 1.0, c = 1.0, d = 1.0) - - Regridder.combine_surfaces_from_sol!(combined_field::CC.Fields.Field, fractions::NamedTuple, fields::NamedTuple) - @test all(parent(combined_field) .== FT(sum(fractions) * sum(fields) / length(fields))) - end - - @testset "test combine_surfaces" begin - test_space = TestHelper.create_space(FT) - combined_field = CC.Fields.ones(test_space) - - var_name = Val(:random) - sims = (; - a = TestSurfaceSimulationA(), - b = TestSurfaceSimulationB(), - c = TestSurfaceSimulationC(), - d = TestSurfaceSimulationD(), - ) - - fractions = ( - a = Interfacer.get_field(sims.a, Val(:area_fraction)), - b = Interfacer.get_field(sims.b, Val(:area_fraction)), - c = Interfacer.get_field(sims.c, Val(:area_fraction)), - d = Interfacer.get_field(sims.d, Val(:area_fraction)), - ) - fields = ( - a = Interfacer.get_field(sims.a, var_name), - b = Interfacer.get_field(sims.b, var_name), - c = Interfacer.get_field(sims.c, var_name), - d = Interfacer.get_field(sims.d, var_name), - ) - - Regridder.combine_surfaces!(combined_field, sims, var_name) - @test all(parent(combined_field) .== FT(sum(fractions) * sum(fields) / length(fields))) - end - - @testset "test get_time" begin - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - # Test dataset containing times - data_path = joinpath(regrid_dir, "data_times.nc") - varname = "test_data" - TestHelper.gen_ncdata_time(FT, data_path, varname, FT(1)) - NCDatasets.NCDataset(data_path, "r") do ds - @test Regridder.get_time(ds) == Dates.DateTime.(Array(ds["time"])) - end - - # Test warning when no dates are available in input data file - data_path = joinpath(regrid_dir, "data_no_times.nc") - varname = "test_data" - TestHelper.gen_ncdata(FT, data_path, varname, FT(1)) - NCDatasets.NCDataset(data_path, "r") do ds - @test_logs (:warn, "No dates available in input data file") Regridder.get_time(ds) - end - end - end - - # Add tests which use TempestRemap here - - # TempestRemap is not built on Windows because of NetCDF support limitations - if !Sys.iswindows() - @testset "test write_to_hdf5 and read_from_hdf5" begin - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - hd_outfile_root = "hdf5_out_test" - tx = Dates.DateTime(1979, 01, 01, 01, 00, 00) - test_space = TestHelper.create_space(FT) - input_field = CC.Fields.ones(test_space) - varname = "testdata" - - Regridder.write_to_hdf5(regrid_dir, hd_outfile_root, tx, input_field, varname, comms_ctx) - - output_field = Regridder.read_from_hdf5(regrid_dir, hd_outfile_root, tx, varname, comms_ctx) - @test parent(input_field) == parent(output_field) - end - end - - @testset "test remap_field_cgll_to_rll for FT=$FT" begin - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - name = "testdata" - datafile_rll = regrid_dir * "/" * name * "_rll.nc" - - test_space = TestHelper.create_space(FT) - field = CC.Fields.ones(test_space) - - Regridder.remap_field_cgll_to_rll(name, field, regrid_dir, datafile_rll) - - # Test no new extrema are introduced in monotone remapping - nt = NCDatasets.NCDataset(datafile_rll) do ds - max_remapped = maximum(ds[name]) - min_remapped = minimum(ds[name]) - (; max_remapped, min_remapped) - end - (; max_remapped, min_remapped) = nt - - @test max_remapped <= maximum(field) - @test min_remapped >= minimum(field) - end - end - - @testset "test land_fraction for FT=$FT" begin - # Test setup - R = FT(6371e3) - test_space = TestHelper.create_space(FT, R = R) - - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - # Initialize dataset of all ones - data_path = joinpath(regrid_dir, "ls_mask_data.nc") - varname = "test_data" - TestHelper.gen_ncdata_time(FT, data_path, varname, FT(1)) - - # Test monotone masking - land_fraction_mono = - Regridder.land_fraction(FT, regrid_dir, comms_ctx, data_path, varname, test_space, mono = true) - - # Test no new extrema are introduced in monotone remapping - nt = NCDatasets.NCDataset(data_path) do ds - max_val = maximum(ds[varname]) - min_val = minimum(ds[varname]) - (; max_val, min_val) - end - (; max_val, min_val) = nt - - @test maximum(land_fraction_mono) <= max_val - @test minimum(land_fraction_mono) >= min_val - - # Test that monotone remapping a dataset of all ones conserves surface area - @test sum(land_fraction_mono) - 4 * π * (R^2) < 10e-14 - end - - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - # Initialize dataset of all 0.5s - data_path = joinpath(regrid_dir, "ls_mask_data.nc") - varname = "test_data_halves" - TestHelper.gen_ncdata_time(FT, data_path, varname, FT(0.5)) - - # Test non-monotone masking - land_fraction_halves = - Regridder.land_fraction(FT, regrid_dir, comms_ctx, data_path, varname, test_space, mono = false) - - # fractioning of values below threshold should result in 0 - @test all(parent(land_fraction_halves) .== FT(0)) - end - end - - @testset "test hdwrite_regridfile_rll_to_cgll 3d space for FT=$FT" begin - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - # Test setup - R = FT(6371e3) - space = TestHelper.create_space(FT, nz = 2, ne = 16, R = R) - - # lat-lon dataset - data = ones(720, 360, 2, 3) # (lon, lat, z, time) - time = [19000101.0, 19000201.0, 19000301.0] - lats = collect(range(-90, 90, length = 360)) - lons = collect(range(-180, 180, length = 720)) - z = [1000.0, 2000.0] - data = reshape(sin.(lats * π / 90)[:], 1, :, 1, 1) .* data - varname = "sinlat" - - # save the lat-lon data to a netcdf file in the required format for TempestRemap - datafile_rll = joinpath(regrid_dir, "lat_lon_data.nc") - NCDatasets.NCDataset(datafile_rll, "c") do ds - NCDatasets.defDim(ds, "lat", size(lats)...) - NCDatasets.defDim(ds, "lon", size(lons)...) - NCDatasets.defDim(ds, "z", size(z)...) - NCDatasets.defDim(ds, "date", size(time)...) - - NCDatasets.defVar(ds, "lon", lons, ("lon",)) - NCDatasets.defVar(ds, "lat", lats, ("lat",)) - NCDatasets.defVar(ds, "z", z, ("z",)) - NCDatasets.defVar(ds, "date", time, ("date",)) - - NCDatasets.defVar(ds, varname, data, ("lon", "lat", "z", "date")) - end - - hd_outfile_root = "data_cgll_test" - Regridder.hdwrite_regridfile_rll_to_cgll( - FT, - regrid_dir, - datafile_rll, - varname, - space, - mono = true, - hd_outfile_root = hd_outfile_root, - ) - - # read in data on CGLL grid from the last saved date - date1 = TimeManager.strdate_to_datetime.(string(Int(time[end]))) - cgll_path = joinpath(regrid_dir, "$(hd_outfile_root)_$date1.hdf5") - hdfreader = CC.InputOutput.HDF5Reader(cgll_path, comms_ctx) - T_cgll = CC.InputOutput.read_field(hdfreader, varname) - Base.close(hdfreader) - - # regrid back to lat-lon - datafile_latlon = joinpath(regrid_dir, "remapped_latlon.nc") - nlat = 360 - nlon = 720 - Regridder.remap_field_cgll_to_rll(:var, T_cgll, regrid_dir, datafile_latlon, nlat = nlat, nlon = nlon) - T_rll, _ = Regridder.read_remapped_field(:var, datafile_latlon) - - # check consistency across z-levels - @test T_rll[:, :, 1] == T_rll[:, :, 2] - - # check consistency of CGLL remapped data with original data - @test all(isapprox.(extrema(data), extrema(parent(T_cgll)), atol = 1e-2)) - - # check consistency of lat-lon remapped data with original data - @test all(isapprox.(extrema(data), extrema(T_rll), atol = 1e-3)) - end - end - end -end - -# test dataset truncation -@testset "test dataset truncation" begin - # Set up regrid directory for this test only - mktempdir(pwd()) do regrid_dir - # Create a dummy dataset for testing - test_data_all = joinpath(regrid_dir, "test_truncation.nc") - ds = NCDatasets.NCDataset(test_data_all, "c") - NCDatasets.defDim(ds, "time", 100) - NCDatasets.defDim(ds, "lat", 32) - NCDatasets.defDim(ds, "lon", 64) - dates = Dates.DateTime.(1923:2022) - first_date = dates[1] - last_date = last(dates) - NCDatasets.defVar(ds, "time", dates, ("time",);) - NCDatasets.defVar(ds, "lat", 1:32, ("lat",);) - NCDatasets.defVar(ds, "lon", 1:64, ("lon",);) - dummy_data = reshape(1:(32 * 64 * 100), 64, 32, 100) - NCDatasets.defVar(ds, "dummy_var", dummy_data, ("lon", "lat", "time")) - ds.attrib["title"] = "dummy dataset" - close(ds) - # set up comms_ctx - device = ClimaComms.device() - comms_ctx_device = ClimaComms.context(device) - ClimaComms.init(comms_ctx_device) - - # values for the truncations - t_start = 0.0 - t_end = 1.728e6 - date0test = ["18690101", "19230101", "19790228", "20220301", "20230101"] - for date in date0test - date0 = Dates.DateTime(date, Dates.dateformat"yyyymmdd") - test_data = Regridder.truncate_dataset( - test_data_all, - "test_truncation", - "dummy_var", - regrid_dir, - date0, - t_start, - t_end, - comms_ctx_device, - ) - ds_truncated = NCDatasets.NCDataset(test_data, "r") - ds = NCDatasets.NCDataset(test_data_all, "r") - new_dates = ds_truncated["time"][:] - - date_start = date0 + Dates.Second(t_start) - date_end = date0 + Dates.Second(t_start + t_end) - - # start date is before the first date of datafile - if date_start < first_date - @test new_dates[1] == first_date - # start date is after the last date in datafile - elseif date_start > last_date - @test new_dates[1] == last_date - # start date is within the bounds of the datafile - else - @test new_dates[1] <= date_start - @test new_dates[2] >= date_start - end - - # end date is before the first date of datafile - if date_end < first_date - @test last(new_dates) == first_date - # end date is after the last date of datafile - elseif date_end > last_date - @test last(new_dates) == last_date - # end date is within the bounds of datafile - else - @test last(new_dates) >= date_end - @test new_dates[length(new_dates) - 1] <= date_end - end - - # check that truncation is indexing correctly - all_data = ds["dummy_var"][:, :, :] - new_data = ds_truncated["dummy_var"][:, :, :] - (start_id, end_id) = Regridder.find_idx_bounding_dates(dates, date_start, date_end) - @test new_data[:, :, 1] ≈ all_data[:, :, start_id] - @test new_data[:, :, length(new_dates)] ≈ all_data[:, :, end_id] - - close(ds_truncated) - end - - close(ds) - end -end diff --git a/test/runtests.jl b/test/runtests.jl index ef7f9b1f78..c890ff2afc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,9 +20,7 @@ end @safetestset "Interfacer tests" begin include("interfacer_tests.jl") end -gpu_broken || @safetestset "Regridder tests" begin - include("regridder_tests.jl") -end + @safetestset "ConservationChecker tests" begin include("conservation_checker_tests.jl") end diff --git a/test/utilities_tests.jl b/test/utilities_tests.jl index 41791ad1a9..c62cd239af 100644 --- a/test/utilities_tests.jl +++ b/test/utilities_tests.jl @@ -54,4 +54,12 @@ for FT in (Float32, Float64) @test typeof(Utilities.get_comms_context(parsed_args)) == typeof(ClimaComms.context(ClimaComms.CPUSingleThreaded())) end + + @testset "test binary_mask" begin + space = TestHelper.create_space(FT) + @test all(parent(Utilities.binary_mask.(zeros(space))) .== 0) + @test all(parent(Utilities.binary_mask.(ones(space))) .== 1) + @test all(parent(Utilities.binary_mask.(fill(FT(0.5), space), FT(0.6))) .== 0) + @test all(parent(Utilities.binary_mask.(fill(FT(0.5), space), FT(0.4))) .== 1) + end end