SpeedyWeather/SpeedyWeather.jl

Set! discontinuous across prime meridian

Closed this issue · 7 comments

orography = NoOrography(spectral_grid)
model = PrimitiveWetModel(;spectral_grid, orography)
H, λ₀, φ₀, σ = 4000, 0, 50, 15         # height, lon, lat position, and width
set!(model, orography=(λ,φ) -> H*exp((--λ₀)^2 --φ₀)^2)/2σ^2), add=true)
heatmap(model.orography.orography)

has a discontinuity at 0˚E

image

@maximilian-gelbrecht you think we can fix that within the set! function or does one need to account for that in the (λ,φ) -> function definition?

Huh, I'll look into it. There has to be a possibility to do that neatly within set!

Okay, after thinking about this a bit more. This is too poorly defined mathematically to do within set!. You'd have to provide more additional information of how you want to have the continuity to be enforced and this just becomes messy.

I'd just add a "ghost point" to the function definition in the individual cases

using SpeedyWeather 
spectral_grid = SpectralGrid()
orography = NoOrography(spectral_grid)
model = PrimitiveWetModel(;spectral_grid, orography)
H, λ₀, φ₀, σ = 4000, 0, 50, 15         # height, lon, lat position, and width
set!(model, orography=(λ,φ) -> H*(exp((--λ₀)^2 --φ₀)^2)/2σ^2) + exp((--(λ₀+360))^2 --φ₀)^2)/2σ^2)), add=true)
plot(model.orography.orography)

`

It's not easy to generalise this to arbitrary functions, so I'd prefer to keep this out of set! I think.

One thing we could think to implement is a function that shifts a RingGrid by a certain longitude. I am not even sure if this is easy to do with all reduced grids, but it would be helpful in cases in which you - in some way - want the prime meridian to be somewhere else to solve a discontinuity.

One thing we could think to implement is a function that shifts a RingGrid by a certain longitude. I am not even sure if this is easy to do with all reduced grids, but it would be helpful in cases in which you - in some way - want the prime meridian to be somewhere else to solve a discontinuity.

All reduced grids we have have 4 faces around the poles, so you could shift longitudinally by 90, 180, or 270˚, e.g.

Ring1: (1, 2, 3, 4) -> (4, 1, 2, 3)
Ring2: (5, 6, 7, 8, 9, 10, 11, 12) -> (11, 12, 5, 6, 7, 8, 9, 10)
Ring3: (13, ..., 24 ) -> (21, ..., 24, 13, ..., 20)

Just putting my comment here from SpeedyWeather/RainMaker.jl#15 for persistence:

I think the problem here stems from the fact that the function (λ,φ) -> H*(exp((-(λ-λ₀)^2 - (φ-φ₀)^2)/2σ^2) + exp((-(λ-(λ₀+360))^2 - (φ-φ₀)^2)/2σ^2)) is using a Euclidean distance function when the underlying geometry of the space is actually non-Euclidean. So instead calculating the distances between (lon, lat) pairs using geodesics should fix this.

Using GeographicLib.jl

using GeographicLib
earth_geodesic((lon1, lat1), (lon2, lat2)) = GeographicLib.inverse(lon1, lat1, lon2, lat2)[:dist]

as the distance works. But this calculates the distance in meters so the width of the mountain needs to be adjusted

H, λ₀, φ₀, σ = 4000, 0, 50, 1_500_000
orography = NoOrography(spectral_grid)
model = PrimitiveWetModel(;spectral_grid, orography)
set!(model, orography=(λ,φ) -> H*exp((- earth_geodesic((λ,φ), mountain_loc)^2)/2σ^2), add=true) heatmap(model.orography.orography)

gives

display

Yes, that's the more proper way of doing that.

So, to answer Milan's initial question here: The functions should take care of that. GeographicLib.jl is a good find for that.

I guess we can close this issue?

I think with #588 we can close this now.