Skip to content

Commit

Permalink
Add center_longitude!
Browse files Browse the repository at this point in the history
  • Loading branch information
Sbozzolo committed Feb 27, 2024
1 parent 0b22435 commit 63d0ac7
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ average_lon
average_time
window
arecompatible
center_longitude!
```


Expand Down
4 changes: 4 additions & 0 deletions docs/src/howdoi.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ import ClimaAnalysis.Utils: kwargs as ca_kwargs
plot!(fig, var, more_kwargs = Dict(:axis => ca_kwargs(yscale = log)))
```
where inside `ca_kwargs` you pass the arguments you would pass to `Makie.Axis`.
## How do I center my longitude to 180 instead of 0?
You can use the `center_longitude!` function.
42 changes: 41 additions & 1 deletion src/OutputVar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export OutputVar,
is_z_1D,
slice,
window,
arecompatible
arecompatible,
center_longitude!

"""
Representing an output variable
Expand Down Expand Up @@ -237,6 +238,45 @@ function average_time(var)
return reduced_var
end

"""
center_longitude!(var::OutputVar, lon::Real)
Shift the longitudes in `var` so that `lon` is the center one.
This is useful to center the global projection to the 180 meridian instead of the 0.
"""
function center_longitude!(var, lon)
LONG_NAMES = Set(["long", "lon"])

# Pick the correct longitude name and check that we have a longitude variable
lon_name = ""
for possible_lon_name in LONG_NAMES
haskey(var.dims, possible_lon_name) &&
(lon_name = possible_lon_name; break)
end
lon_name != "" || error("var does not have longitude among its dimensions")

old_center_lon_index = nearest_index(var.dims[lon_name], lon)
half_index = div(length(var.dims[lon_name]), 2)

# half_index = old_index + shift => shift = half_index - old_index
shift = half_index - old_center_lon_index

# We do not use circshift! because it can lead to unpredictable problems when mutating
shifted_lon = circshift(var.dims[lon_name], shift)
var.dims[lon_name] = shifted_lon

lon_dim_index = var.dim2index[lon_name]

# Prepare the shift tuple for the data array: do not shift, except for the dimension
# corresponding to the longitude
shift_tuple = zeros(length(var.dims))
shift_tuple[lon_dim_index] = shift

shifted_data = circshift(var.data, shift)
var.data .= shifted_data
end

"""
_slice_general(var::OutputVar, val, dim_name)
Expand Down
33 changes: 32 additions & 1 deletion test/OutputVar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,43 @@ import OrderedCollections: OrderedDict

@testset "General" begin
# Add test for short constructor
long = 0.0:180.0 |> collect
long = -180.0:180.0 |> collect
data = copy(long)

longvar = ClimaAnalysis.OutputVar(Dict("long" => long), data)

@test longvar.dims["long"] == long


# center_longitude!
#
# Check var without long
dims = Dict("z" => long)
var_error = ClimaAnalysis.OutputVar(
Dict{String, Any}(),
dims,
Dict{String, Any}(),
data,
)
@test_throws ErrorException ClimaAnalysis.center_longitude!(
var_error,
180.0,
)

time = 0:10.0 |> collect
dims = Dict("lon" => long, "time" => time)
data = collect(reshape(1:(361 * 11), (361, 11)))
var_good = ClimaAnalysis.OutputVar(
Dict{String, Any}(),
dims,
Dict{String, Any}(),
data,
)
ClimaAnalysis.center_longitude!(var_good, 90.0)
# We are shifting by 91
@test var_good.dims["lon"][180] == 90
@test var_good.data[3, :] == data[3, :]
@test var_good.data[180, 1] == 271
end

@testset "Arithmetic operations" begin
Expand Down

0 comments on commit 63d0ac7

Please sign in to comment.