Skip to content

Commit f3e71b0

Browse files
authored
Merge branch 'main' into albert-de-montserrat-patch-1
2 parents 50c827d + b21943a commit f3e71b0

23 files changed

+67905
-14
lines changed

.typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
MOR = "MOR"
33
dum = "dum"
44
Shepard = "Shepard"
5+
nin = "nin"
56

67
[files]
78
extend-exclude = ["tutorials/*.pvsm"]

Project.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
name = "GeophysicalModelGenerator"
22
uuid = "3700c31b-fa53-48a6-808a-ef22d5a84742"
33
authors = ["Boris Kaus", "Marcel Thielmann"]
4-
version = "0.7.4"
4+
version = "0.7.6"
55

66
[deps]
77
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
88
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
99
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
1010
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
1111
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
12+
GDAL_jll = "a7073274-a066-55f0-b90d-d619367d196c"
1213
GeoParams = "e018b62d-d9de-4a26-8697-af89c310ae38"
1314
Geodesy = "0ef565a4-170c-5f04-8de2-149903a85f3d"
1415
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
@@ -26,6 +27,7 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2627
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
2728
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
2829
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
30+
WhereTheWaterFlows = "ea906314-1493-4d22-a0af-f886a20c9fba"
2931
WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192"
3032

3133
[weakdeps]
@@ -43,7 +45,8 @@ Colors = "0.9 - 0.12"
4345
Downloads = "1"
4446
FFMPEG = "0.4"
4547
FileIO = "1"
46-
GLMakie = "0.10.3"
48+
GDAL_jll = "300.900.0 - 301.900.0"
49+
GLMakie = "0.10"
4750
GMT = "1"
4851
GeoParams = "0.2 - 0.6"
4952
Geodesy = "1"
@@ -60,6 +63,7 @@ Parameters = "0.9 - 0.12"
6063
SpecialFunctions = "1.0, 2"
6164
StaticArrays = "1"
6265
WriteVTK = "1"
66+
WhereTheWaterFlows = "0.10"
6367
julia = "1.9"
6468

6569
[extras]
@@ -69,4 +73,4 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
6973
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7074

7175
[targets]
72-
test = ["Test", "GMT", "StableRNGs","GridapGmsh"]
76+
test = ["Test", "GMT", "StableRNGs", "GridapGmsh"]

ext/GLMakie_Visualisation.jl

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module GLMakie_Visualisation
33

44
using Statistics
55
using GeophysicalModelGenerator: lonlatdepth_grid, GeoData, CartData, km, AbstractGeneralGrid
6-
import GeophysicalModelGenerator: visualise
6+
import GeophysicalModelGenerator: visualise, ustrip
77

88
# We do not check `isdefined(Base, :get_extension)` as recommended since
99
# Julia v1.9.0 does not load package extensions when their dependency is
@@ -14,7 +14,9 @@ else
1414
using ..GLMakie
1515
end
1616

17-
export visualise
17+
import GLMakie: heatmap!, heatmap
18+
19+
export visualise, heatmap, heatmap!
1820

1921
println("Loading GLMakie extensions for GMG")
2022

@@ -271,5 +273,121 @@ function visualise(Data::AbstractGeneralGrid; Topography=nothing, Topo_range=not
271273
return nothing
272274
end
273275

276+
"""
277+
heatmap(x::GeoData, args...; field=:Topography, kwargs...)
278+
heatmap for a 2D GeoData object (surface)
279+
"""
280+
function heatmap(x::GeoData, args...; field=:Topography, kwargs...)
281+
@assert size(x.depth.val,3)==1
282+
@assert hasfield(typeof(x.fields), field)
283+
284+
heatmap(x.lon.val[:,1], x.lat.val[1,:], ustrip.(x.fields[field][:,:,1]), args...; kwargs...)
285+
286+
end
287+
288+
"""
289+
heatmap(x::GeoData, a::Array{_T,N}, args...; kwargs...)
290+
in-place heatmap for a 2D GeoData object (surface) with an array `a`.
291+
"""
292+
function heatmap(x::GeoData, a::Array{_T,N}, args...; kwargs...) where{_T,N}
293+
@assert size(x.depth.val,3)==1
294+
295+
if N==3
296+
heatmap(x.lon.val[:,1], x.lat.val[1,:], ustrip.(a[:,:,1]), args...; kwargs...)
297+
elseif N==2
298+
heatmap(x.lon.val[:,1], x.lat.val[1,:], ustrip.(a), args...; kwargs...)
299+
end
300+
301+
end
302+
303+
"""
304+
heatmap(x::CartData, args...; field=:Topography, kwargs...)
305+
heatmap for a 2D CartData object (surface)
306+
"""
307+
function heatmap(x::CartData, args...; field=:Topography, kwargs...)
308+
@assert size(x.z.val,3)==1
309+
@assert hasfield(typeof(x.fields), field)
310+
311+
heatmap(x.x.val[:,1], x.y.val[1,:], ustrip.(x.fields[field][:,:,1]), args...; kwargs...)
312+
313+
end
314+
315+
"""
316+
heatmap(x::CartData, a::Array{_T,N}, args...; kwargs...)
317+
in-place heatmap for a 2D CartData object (surface) with an array `a`.
318+
"""
319+
function heatmap(x::CartData, a::Array{_T,N}, args...; kwargs...) where{_T,N}
320+
@assert size(x.z.val,3)==1
321+
322+
if N==3
323+
heatmap(x.x.val[:,1], x.y.val[1,:], ustrip.(a[:,:,1]), args...; kwargs...)
324+
elseif N==2
325+
heatmap(x.x.val[:,1], x.y.val[1,:], ustrip.(a), args...; kwargs...)
326+
end
327+
328+
end
329+
330+
331+
"""
332+
heatmap!(x::GeoData, args...; field=:Topography, kwargs...)
333+
in-place heatmap for a 2D GeoData object (surface),
334+
"""
335+
function heatmap!(x::GeoData, args...; field=:Topography, kwargs...)
336+
@assert size(x.depth.val,3)==1
337+
@assert hasfield(typeof(x.fields), field)
338+
339+
heatmap(x.lon.val[:,1], x.lat.val[1,:], ustrip.(x.fields[field][:,:,1]), args...; kwargs...)
340+
341+
end
342+
343+
"""
344+
heatmap!(x::GeoData, a::Array{_T,N}, args...; kwargs...)
345+
in-place heatmap for a 2D GeoData object (surface) with an array `a`.
346+
"""
347+
function heatmap!(x::GeoData, a::Array{_T,N}, args...; kwargs...) where{_T,N}
348+
@assert size(x.depth.val,3)==1
349+
350+
if N==3
351+
heatmap!(x.lon.val[:,1], x.lat.val[1,:], ustrip.(a[:,:,1]), args...; kwargs...)
352+
elseif N==2
353+
heatmap!(x.lon.val[:,1], x.lat.val[1,:], ustrip.(a), args...; kwargs...)
354+
end
355+
356+
end
357+
358+
"""
359+
heatmap!(x::CartData, args...; field=:Topography, colorbar=false, kwargs...)
360+
in-place heatmap for a 2D CartData object (surface)
361+
"""
362+
function heatmap!(x::CartData, args...; field=:Topography, colorbar=false, kwargs...)
363+
@assert size(x.z.val,3)==1
364+
@assert hasfield(typeof(x.fields), field)
365+
366+
data = ustrip.(x.fields[field][:,:,1])
367+
368+
fig,ax,hm = heatmap!(x.x.val[:,1], x.y.val[1,:], data, args...; kwargs...)
369+
370+
cb = nothing
371+
if colorbar
372+
cb = Colorbar(fig[1,2], limits=extrema(filter(!isnan,x.fields[field])), label=field)
373+
end
374+
375+
return fig_out
376+
end
377+
378+
"""
379+
heatmap!(x::CartData, a::Array{_T,N}, args...; kwargs...)
380+
in-place heatmap for a 2D CartData object (surface) with an array `a`.
381+
"""
382+
function heatmap!(x::CartData, a::Array{_T,N}, args...; kwargs...) where{_T,N}
383+
@assert size(x.z.val,3)==1
384+
385+
if N==3
386+
heatmap!(x.x.val[:,1], x.y.val[1,:], ustrip.(a[:,:,1]), args...; kwargs...)
387+
elseif N==2
388+
heatmap!(x.x.val[:,1], x.y.val[1,:], ustrip.(a[:,:]), args...; kwargs...)
389+
end
390+
391+
end
274392

275393
end

src/GeophysicalModelGenerator.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ include("IO.jl")
4747
include("event_counts.jl")
4848
include("surface_functions.jl")
4949
include("movies_from_pics.jl")
50+
include("sea_lvl.jl")
51+
include("WaterFlow.jl")
5052

5153
# Add optional routines (only activated when the packages are loaded)
5254

src/WaterFlow.jl

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# These are routes to perform waterflow calculations (upstream area etc.) on a DEM
2+
3+
using WhereTheWaterFlows
4+
import WhereTheWaterFlows: waterflows
5+
6+
export waterflows
7+
8+
"""
9+
dlon, dlat = spacing(lon,lat)
10+
11+
Computes the spacing with central differences
12+
"""
13+
function spacing(lon,lat)
14+
dlon = zeros(size(lon.val)[1:2])
15+
dlat = zeros(size(lat.val)[1:2])
16+
@views dlon[2:end-1,:] = (lon.val[3:end,:,1] - lon.val[1:end-2,:,1])/2
17+
dlon[1,:] = dlon[2,:]
18+
dlon[end,:] = dlon[end-1,:]
19+
dlat[:,2:end-1] = (lat.val[:,3:end,1] - lat.val[:,1:end-2,1])/2
20+
dlat[:,1] = dlat[:,2]
21+
dlat[:,end] = dlat[:,end-1]
22+
23+
return dlon, dlat
24+
end
25+
26+
"""
27+
area_m2 = cell_area(Topo::GeoData)
28+
Returns the cell area for a Topographic dataset in m² (required for upstream area calculation)
29+
"""
30+
function cell_area(Topo::GeoData)
31+
32+
proj = ProjectionPoint(Lon=mean(Topo.lon.val[:]), Lat=mean(Topo.lat.val[:]))
33+
Topo_cart = convert2CartData(Topo, proj)
34+
dx, dy = spacing(Topo_cart.x, Topo_cart.y)
35+
36+
area_m2 = dx.*dy*1e6
37+
return area_m2
38+
end
39+
40+
41+
"""
42+
Topo_water, sinks, pits, bnds = waterflows(Topo::GeoData;
43+
flowdir_fn=WhereTheWaterFlows.d8dir_feature, feedback_fn=nothing, drain_pits=true, bnd_as_sink=true,
44+
rainfall = nothing,
45+
minsize=300)
46+
47+
Takes a GMG GeoData object of a topographic map and routes water through the grid. Optionally,
48+
you can specify `rainfall` in which case we accumulate the rain as specified in this 2D array instead of the cellarea.
49+
This allows you to, for example, sum, up water if you have variable rainfall in the area.
50+
The other options are as in the `waterflows` function of the package `WhereTheWaterFlows`.
51+
52+
Example
53+
===
54+
```julia
55+
# Download some topographic data
56+
julia> Topo = import_topo([6.5,7.3,50.2,50.6], file="@earth_relief_03s");
57+
58+
# Flow the water through the area:
59+
julia> Topo_water, sinks, pits, bnds = waterflows(Topo)
60+
julia> Topo_water
61+
GeoData
62+
size : (961, 481, 1)
63+
lon ϵ [ 6.5 : 7.3]
64+
lat ϵ [ 50.2 : 50.59999999999999]
65+
depth ϵ [ 0.045 : 0.724]
66+
fields : (:Topography, :area, :slen, :dir, :nout, :nin, :c)
67+
68+
```
69+
70+
"""
71+
function waterflows(Topo::GeoData, flowdir_fn= WhereTheWaterFlows.d8dir_feature; feedback_fn=nothing, drain_pits=true, bnd_as_sink=true, rainfall=nothing, minsize=300)
72+
73+
cellarea = cell_area(Topo)
74+
cellarea_m2 = cellarea
75+
if !isnothing(rainfall)
76+
@assert typeof(rainfall) == Array{Float64,2}
77+
cellarea = rainfall
78+
end
79+
80+
dem = Topo.depth.val[:,:,1]
81+
82+
ni = size(Topo.depth.val)
83+
area = zeros(ni)
84+
slen = zeros(Int64, ni)
85+
dir = zeros(Int8, ni)
86+
nout = zeros(Int8, ni)
87+
nin = zeros(Int8, ni)
88+
c = zeros(Int64, ni)
89+
90+
area[:,:,1], slen[:,:,1], dir[:,:,1], nout[:,:,1], nin[:,:,1], sinks, pits, c[:,:,1], bnds = waterflows(dem, cellarea, flowdir_fn;
91+
feedback_fn=feedback_fn, drain_pits=drain_pits, bnd_as_sink=bnd_as_sink)
92+
93+
catchment_large = prune_catchments(c, minsize; val=0)
94+
largest_catchment = catchment_large .== maximum(catchment_large)
95+
largest_area = copy(area)
96+
largest_area[.!largest_catchment] .= NaN
97+
98+
log10_area = log10.(area)
99+
100+
Topo_water = addfield(Topo,(;area, slen, dir, nout, nin, c, cellarea_m2, catchment_large, log10_area, largest_catchment, largest_area))
101+
return Topo_water, sinks, pits, bnds
102+
end

src/data_types.jl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,14 +1464,6 @@ end
14641464
extrema(d::FEData) = extrema(d.vertices, dims=2)
14651465
size(d::FEData) = size(d.connectivity,2)
14661466

1467-
"""
1468-
convert2FEData(d::Q1Data
1469-
1470-
"""
1471-
convert2FEData(d::Q1Data)
1472-
1473-
1474-
14751467
"""
14761468
X,Y,Z = coordinate_grids(Data::Q1Data; cell=false)
14771469
@@ -1531,4 +1523,4 @@ function convert2FEData(data::Q1Data)
15311523
end
15321524

15331525
return FEData(vertices,connectivity, NamedTuple{keys(data.fields)}(data_fields), NamedTuple{keys(data.cellfields)}(data_cellfields))
1534-
end
1526+
end

src/sea_level.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
export sea_level_files, SeaLevel, load_sea_level, curve_name
2+
3+
const sea_level_path = "sea_level_data"
4+
5+
const sea_level_files = Dict(
6+
:Spratt_800ka => "Spratt2016-800ka.txt",
7+
:Spratt_450ka => "Spratt2016-450ka.txt",
8+
:Bintanja_3Ma => "Bintanja-3Ma.txt",
9+
:Grant_153ka => "Grant2012_153ka.txt",
10+
:Rohl_Bint_3Ma => "Rohl-Bint-3Ma.txt",
11+
:Rohling2009_516ka => "Rohling2009-516ka.txt",
12+
:Siddall2003_379ka => "Siddall2003-379ka.txt",
13+
:Waelbroeck2002 => "Waelbroeck2002.txt",
14+
)
15+
16+
struct SeaLevel{T}
17+
elevation::Vector{T}
18+
age::Vector{T}
19+
name::Symbol
20+
21+
function SeaLevel(name::Symbol; flip_elevation = false, flip_age = false)
22+
age, elevation = load_sea_level(
23+
name;
24+
flip_age = flip_age,
25+
flip_elevation = flip_elevation
26+
)
27+
new{eltype(age)}(age, elevation, name)
28+
end
29+
end
30+
31+
Base.getindex(x::SeaLevel, i::Int64) = x.elevation[i]
32+
Base.getindex(x::SeaLevel, i::Int64, j::Int64) = x.elevation[i], x.age[j]
33+
Base.getindex(x::SeaLevel, i::Tuple{Int64}) = x.elevation[i...], x.age[i...]
34+
Base.size(x::SeaLevel) = size(x.elevation)
35+
Base.eachindex(x::SeaLevel) = eachindex(x.elevation)
36+
Base.axes(x::SeaLevel) = axes(x.elevation)
37+
Base.length(x::SeaLevel) = length(x.elevation)
38+
curve_name(x::SeaLevel) = x.name
39+
40+
function load_sea_level(name::Symbol; flip_elevation = false, flip_age = false)
41+
fname = sea_level_files[name]
42+
data = readdlm(joinpath(sea_level_path, fname))
43+
h = data[:, 1]
44+
age = data[:, 2]
45+
flip_elevation && reverse!(h)
46+
flip_age && reverse!(age)
47+
return h, age
48+
end

0 commit comments

Comments
 (0)