Skip to content

Commit

Permalink
Merge pull request #3378 from CliMA/as/topo-spacevarutil
Browse files Browse the repository at this point in the history
Remove Adapt dependence, use ETOPO2022 dataset and regrid orography using SpaceVaryingInputs
  • Loading branch information
akshaysridhar authored Oct 29, 2024
2 parents 7d36e14 + 35416b4 commit c26e84f
Show file tree
Hide file tree
Showing 22 changed files with 300 additions and 219 deletions.
11 changes: 11 additions & 0 deletions Artifacts.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ git-tree-sha1 = "6693f8451b447543952b3d557d733c7e5c670ed3"
[[ozone_concentrations_lowres.download]]
sha256 = "908384b32e90c733c2173654afbb974d238a9a516ad8965039077c6ddb29b5f0"
url = "https://caltech.box.com/shared/static/6c16wt7i1htxq6tadpt1ng2uftjgdtpr.gz"

[earth_orography_30arcseconds]
git-tree-sha1 = "03dd08fcbf363ed055a176dd7adefb60ff1c3493"

[earth_orography_60arcseconds]
git-tree-sha1 = "fe19d8dbe7a18ff39588e1f718014b0479d9c0f7"
lazy = true

[[earth_orography_60arcseconds.download]]
sha256 = "eca66c0701d1c2b9e271742314915ffbf4a0fae92709df611c323f38e019966e"
url = "https://caltech.box.com/shared/static/4asrxcgl6xsgenfcug9p0wkkyhtqilgk.gz"
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ ClimaAtmos.jl Release Notes
Main
-------

### Features

### ETOPO2022 60arc-second topography dataset.

- Update artifacts to use 60arc-second ETOPO2022 ice-surface topography
dataset. Update surface smoothing functions to rely only on spectral
Laplacian operations. Update raw-topo gravity wave parameterization
dataset. Update interfaces in `make_hybrid_spaces` to support new
inputs using `SpaceVaryingInput` utility. Include a simple example
to generate spectra from scalar variables.
PR [3378](https://github.com/CliMA/ClimaAtmos.jl/pull/3378)

v0.27.7
-------

Expand Down
2 changes: 0 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ authors = ["Climate Modeling Alliance"]
version = "0.27.7"

[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
ArtifactWrappers = "a14bc488-3040-4b00-9dc1-f6467924858a"
Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
Expand Down Expand Up @@ -37,7 +36,6 @@ UnrolledUtilities = "0fe1646c-419e-43be-ac14-22321958931b"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"

[compat]
Adapt = "3.7, 4"
ArgParse = "1"
ArtifactWrappers = "0.2"
Artifacts = "1"
Expand Down
13 changes: 0 additions & 13 deletions artifacts/artifact_funcs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,6 @@ function mima_gwf_path()
return AW.get_data_folder(mima_data)
end

function topo_elev_dataset_path()
etopo1_elev_data = AW.ArtifactWrapper(
@__DIR__,
"topo-elev-info",
AW.ArtifactFile[AW.ArtifactFile(
url = "https://caltech.box.com/shared/static/gvilybsu5avxso1wubxjthpip9skc6mf.nc",
filename = "ETOPO1_coarse.nc",
),],
)
return AW.get_data_folder(etopo1_elev_data)
end


function gfdl_ogw_data_path()
gfdl_data = AW.ArtifactWrapper(
@__DIR__,
Expand Down
1 change: 0 additions & 1 deletion artifacts/download_artifacts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ function trigger_download(lazy_download = true)
@info "Era single column dataset path:`$(era_single_column_dataset_path())`"
@info "topo dataset path:`$(topo_res_path())`"
@info "MiMA convective gravity wave path:`$(mima_gwf_path())`"
@info "ETOPO1 arc-minute relief model:`$(topo_elev_dataset_path())`"
@info "GFDL OGWD test data:`$(gfdl_ogw_data_path())`"
return nothing
end
Expand Down
6 changes: 3 additions & 3 deletions config/default_configs/default_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ sleve_s:
topo_smoothing:
help: "Choose whether to order-2 smoothing on the LGL mesh"
value: false
smoothing_order:
help: "Define the surface smoothing kernel factor (integer) [`3 (default)`]"
value: 3
topography_damping_factor:
help: "Factor by which smallest resolved length-scale is to be damped"
value: 512
# ODE
use_newton_rtol:
help: "Whether to check if the current iteration of Newton's method has an error within a relative tolerance, instead of always taking the maximum number of iterations (only for ClimaTimeSteppers.jl)"
Expand Down
1 change: 0 additions & 1 deletion examples/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[deps]
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63"
ArtifactWrappers = "a14bc488-3040-4b00-9dc1-f6467924858a"
AtmosphericProfilesLibrary = "86bc3604-9858-485a-bdbe-831ec50de11d"
Expand Down
144 changes: 144 additions & 0 deletions examples/topography_spectra.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using LazyArtifacts
using ClimaAtmos.AtmosArtifacts
import ClimaAtmos as CA
import ClimaCore as CC
import ClimaComms
import ClimaParams as CP
import ClimaCore.Quadratures
using ClimaUtilities: SpaceVaryingInputs
using ClimaCore.Hypsography: diffuse_surface_elevation!
using ClimaCore: Remapping, Geometry, Operators, Spaces
using CairoMakie

import ClimaCoreSpectra: power_spectrum_2d

const AA = AtmosArtifacts


function mask(x::FT) where {FT}
return x * FT(x > 0)
end

"""
generate_spaces(; h_elem=16)
For a given number of elements `h_elem`, this function generates a
horizontal spectral space (ClimaCore.SpectralElementSpace2D) and
generates an interpolated (using SpaceVaryingInputs) orography field
on this space. The `diffuse_surface_elevation` function is called
to apply Laplacian diffusion (canonical diffusion equation) passes,
with a timescale defined by the attenuation required at the smallest
resolved lengthscale.
Returns a `Field` containing surface orography.
"""
function generate_spaces(;
h_elem = 16,
n_attenuation = 1000,
planet_radius = 6.378e6,
)
FT = Float32
cubed_sphere_mesh =
CA.cubed_sphere_mesh(; radius = FT(planet_radius), h_elem)
quad = Quadratures.GLL{4}()
comms_ctx = ClimaComms.context()
h_space = CA.make_horizontal_space(cubed_sphere_mesh, quad, comms_ctx, true)
Δh_scale = Spaces.node_horizontal_length_scale(h_space)
@assert h_space isa CC.Spaces.SpectralElementSpace2D
coords = CC.Fields.coordinate_field(h_space)
target_field = CC.Fields.zeros(h_space)
elev_from_file = SpaceVaryingInputs.SpaceVaryingInput(
AA.earth_orography_file_path(; context = comms_ctx),
"z",
h_space,
)
elev_from_file = @. mask(elev_from_file)
# Fractional damping of smallest resolved scale
# Approximated as k₀ ≈ 1/Δx, with n_attenuation
# the factor by which we wish to damp wavenumber
# k₀. Assume dt == 1 for this example.
diff_courant = FT(0.05)
κ = diff_courant * Δh_scale^2
maxiter = Int(round(log(n_attenuation) / diff_courant))
diffuse_surface_elevation!(elev_from_file; κ, dt = FT(1), maxiter)
elev_from_file = @. mask(elev_from_file)
return elev_from_file
end

"""
remap_to_array(test_var, hcoords)
Given an Array of `hcoords`, this function remaps a ClimaCore
Field `test_var` onto `hcoords`.
Returns an `Array` containing the values which make up `test_var`.
"""
function remap_to_array(test_var, hcoords)
remapper = Remapping.Remapper(axes(test_var), hcoords)
orog = Array(Remapping.interpolate(remapper, test_var))
end

"""
gen_spectra(test_var)
Given a Field `test_var`, this function first calls `remap_to_array`
to remap this spectral element field onto a latitude-longitude
grid, and computes the spectra.
Returns (`w_numbers`, `power_spectrum`) which contain the spherical
wavenumbers and the spectral energy corresponding to this array
of `w_numbers`.
"""
function gen_spectra(test_var)
FT = eltype(test_var)
Δh_scale = Spaces.node_horizontal_length_scale(Spaces.axes(test_var))
planet_radius = FT(6.378e6)
npts = Int(round(2π * planet_radius / Δh_scale))
npts = ifelse(rem(npts, 2) == 0, npts, npts + 1)
longpts = range(FT(-180), FT(180.0), Int(npts))
latpts = range(FT(-90), FT(90), Int(npts // 2))
hcoords =
[Geometry.LatLongPoint(lat, long) for long in longpts, lat in latpts]
test_var = remap_to_array(test_var, hcoords)
# Use ClimaCoreSpectra to generate power spectra for orography data.
len1 = size(test_var)[1]
len2 = size(test_var)[2]
@assert len1 == 2len2
mass_weight = FT(1) # No weighting applied
spectrum_data, wave_numbers, _spherical, mesh_info =
power_spectrum_2d(FT, test_var, mass_weight)
power_spectrum =
dropdims(sum(spectrum_data, dims = 1), dims = 1)[begin:(end - 1), :]
w_numbers = collect(0:1:(mesh_info.num_spherical - 1))
@info "Returning wavenumber array (spherical) and orography power spectrum"
return w_numbers, power_spectrum
end

"""
generate_all_spectra(;h_elem=16)
Uses the spectral calculator and space generation tools in this example file
to generate a series of surface orography fields with different extents of
Laplacian smoothing.
Returns a `CairoMakie.Figure`.
"""
function generate_all_spectra(; h_elem = 16)
fig = Figure(; size = (1200, 900))
ax1 = Axis(
fig[1, 1],
xlabel = "spherical wavenumber",
ylabel = "elevation spectra",
title = "Surface elevation spectra",
xticks = [2, 4, 8, 16, 32, 64, 128, 256],
yticks = [10^-1, 10^0, 10^1, 10^2, 10^3, 10^4],
xscale = log10,
yscale = log10,
xgridvisible = true,
ygridvisible = false,
)
for ii in (1, 2, 4, 8, 16, 32, 64, 128, 256, 512)
n_attenuation = ii
test_var = generate_spaces(; h_elem, n_attenuation)
Δh_scale = Spaces.node_horizontal_length_scale(Spaces.axes(test_var))
diff_courant = 0.05 # Arbitrary example value.
κ = diff_courant * Δh_scale^2
maxiter = Int(round(log(n_attenuation) / diff_courant))
sph_wn, psd = gen_spectra(test_var)
scatterlines!(sph_wn[2:end], psd[2:end], label = "iter = $(maxiter)")
end
CairoMakie.Legend(fig[1, 2], ax1)
return fig
end
10 changes: 9 additions & 1 deletion reproducibility_tests/ref_counter.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
185
186

# **README**
#
Expand All @@ -20,6 +20,14 @@


#=
186
- Topography dataset has been modified to the 60 arc-second ETOPO2022 dataset.
This is behaviour changing for the gravity-wave (raw-topo) parameterization
when computing `hmax` and `T tensor`.
185
184
- Changed default ozone profile.
Jobs that failed:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ function orographic_gravity_wave_cache(Y, ogw::OrographicGravityWave)
elseif ogw.topo_info == "raw_topo"
# TODO: right now this option may easily crash
# because we did not incorporate any smoothing when interpolate back to model grid
elevation_rll = joinpath(topo_elev_dataset_path(), "ETOPO1_coarse.nc")
elevation_rll =
AA.earth_orography_file_path(; context = ClimaComms.context(Y.c))
radius =
Spaces.topology(
Spaces.horizontal_space(axes(Y.c)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,13 @@ end

function compute_OGW_info(Y, elev_data, earth_radius, γ, h_frac)
# obtain lat, lon, elevation from the elev_data
FT = Spaces.undertype(Spaces.axes(Y.c))
# downsample to elev dims (3600×1800)
skip_pt = 6
nt = NCDataset(elev_data, "r") do ds
lon = Array(ds["longitude"])
lat = Array(ds["latitude"])
elev = Array(ds["elevation"])
lon = FT.(Array(ds["lon"]))[1:skip_pt:end]
lat = FT.(Array(ds["lat"]))[1:skip_pt:end]
elev = FT.(Array(ds["z"]))[1:skip_pt:end, 1:skip_pt:end]
(; lon, lat, elev)
end
(; lon, lat, elev) = nt
Expand Down
73 changes: 3 additions & 70 deletions src/solver/type_getters.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Adapt
using Dates: DateTime, @dateformat_str
import Interpolations
import NCDatasets
Expand Down Expand Up @@ -132,47 +131,9 @@ function get_spaces(parsed_args, params, comms_ctx)
z_elem = Int(parsed_args["z_elem"])
z_max = FT(parsed_args["z_max"])
dz_bottom = FT(parsed_args["dz_bottom"])
topography = parsed_args["topography"]
bubble = parsed_args["bubble"]
deep = parsed_args["deep_atmosphere"]

@assert topography in ("NoWarp", "DCMIP200", "Earth", "Agnesi", "Schar")
if topography == "DCMIP200"
warp_function = topography_dcmip200
elseif topography == "Agnesi"
warp_function = topography_agnesi
elseif topography == "Schar"
warp_function = topography_schar
elseif topography == "NoWarp"
warp_function = nothing
elseif topography == "Earth"
data_path = joinpath(topo_elev_dataset_path(), "ETOPO1_coarse.nc")
array_type = ClimaComms.array_type(comms_ctx.device)
earth_spline = NCDatasets.NCDataset(data_path) do data
zlevels = Array(data["elevation"])
lon = Array(data["longitude"])
lat = Array(data["latitude"])
# Apply Smoothing
smooth_degree = Int(parsed_args["smoothing_order"])
esmth = CA.gaussian_smooth(zlevels, smooth_degree)
Adapt.adapt(
array_type,
Interpolations.linear_interpolation(
(lon, lat),
esmth,
extrapolation_bc = (
Interpolations.Periodic(),
Interpolations.Flat(),
),
),
)
end
@info "Generated interpolation stencil"
warp_function = generate_topography_warp(earth_spline)
end
@info "Topography" topography


h_elem = parsed_args["h_elem"]
radius = CAP.planet_radius(params)
center_space, face_space = if parsed_args["config"] == "sphere"
Expand All @@ -186,19 +147,7 @@ function get_spaces(parsed_args, params, comms_ctx)
else
Meshes.Uniform()
end
if warp_function == nothing
make_hybrid_spaces(h_space, z_max, z_elem, z_stretch; deep)
else
make_hybrid_spaces(
h_space,
z_max,
z_elem,
z_stretch;
parsed_args = parsed_args,
surface_warp = warp_function,
deep,
)
end
make_hybrid_spaces(h_space, z_max, z_elem, z_stretch; deep, parsed_args)
elseif parsed_args["config"] == "column" # single column
@warn "perturb_initstate flag is ignored for single column configuration"
FT = eltype(params)
Expand Down Expand Up @@ -243,15 +192,7 @@ function get_spaces(parsed_args, params, comms_ctx)
else
Meshes.Uniform()
end
make_hybrid_spaces(
h_space,
z_max,
z_elem,
z_stretch;
parsed_args,
surface_warp = warp_function,
deep,
)
make_hybrid_spaces(h_space, z_max, z_elem, z_stretch; parsed_args, deep)
elseif parsed_args["config"] == "plane"
FT = eltype(params)
nh_poly = parsed_args["nh_poly"]
Expand All @@ -267,15 +208,7 @@ function get_spaces(parsed_args, params, comms_ctx)
else
Meshes.Uniform()
end
make_hybrid_spaces(
h_space,
z_max,
z_elem,
z_stretch;
parsed_args,
surface_warp = warp_function,
deep,
)
make_hybrid_spaces(h_space, z_max, z_elem, z_stretch; parsed_args, deep)
end
ncols = Fields.ncolumns(center_space)
ndofs_total = ncols * z_elem
Expand Down
Loading

0 comments on commit c26e84f

Please sign in to comment.