Geography and Visualization#
This tutorial focuses on the relation between the gridded space in MeshArrays.jl and the geospatial space (longitude, lattitude). A common use case is for plotting in the form of maps. Going back and forth between the two is also often useful for analysis of simulations (transports, averages, etc) and e.g. simulating particle trajectories.
This notebook is adapated from the Geography Tutorial found in the MeshArrays.jl docs.
Set Everything Up#
We use MeshArrays.jl
to handle gridded variables from MITgcm and ECCO.
install julia packages
use julia packages
read MITgcm grid (LLC90)
ocean basins, sections, zonal averages
#Let's start a temporary environment for this notebook, and add julia packages that we will
if !isdefined(Main,:MeshArrays)
using Pkg; Pkg.activate(temp=true)
Pkg.add.(["MeshArrays", "Climatology", "Statistics","JLD2", "Downloads",
"DataDeps", "ZipFile", "PlutoUI","CairoMakie", "Proj", "GeoJSON", "Shapefile"])
end
#Then the using command turns on the Julia packages
using MeshArrays, Climatology, Statistics, JLD2, Downloads
using DataDeps, ZipFile, PlutoUI, CairoMakie, Proj, GeoJSON, Shapefile
#read ECCO4 grid (LLC90)
pth=MeshArrays.GRID_LLC90
γ=GridSpec(ID=:LLC90)
Γ=GridLoad(γ;option="light")
#define grid paths, sections, ocean basins
LC=LatitudeCircles(-89.0:89.0,Γ)
basins=demo.ocean_basins()
sections,path_sec=demo.ocean_sections(Γ);
Interpolation#
The rest of this notebook focuses on ECCO output defined on native ocean model grids – without interpolation to a regular grid. This approach generally allows for improved accuracy calculations in model space.
But let’s first look at interpolating ECCO output to regular grid, which is important to visualize results.
Here we interpolate from the global LLC90 grid (see MeshArrays.jl) to a set of arbitary locations (longitude, latitude pairs) as is commonly done, for example, to plot gridded fields in geographic coordinates (example below shows Ocean bottom depth) or to compare climate models to sparse field observations (e.g., Argo profiles).
Later in this notebook, we break down the MeshArrays.Interpolate
function into several steps. In brief, the program finds a grid point quadrilateral (4 grid points) that encloses the target location. Computation is chuncked in subdomains (tiles) to allow for parallelism. MeshArrays.InterpolationFactors
outputs interpolation coefficients, which can then be reused repeatedly – e.g. to speed up calls to MeshArrays.Interpolate
in loops that generate animations.
# Interpolate Γ.Depth to regular grid:
λ=interpolation_setup()
hFacC=GridLoadVar("hFacC",γ)
μ=land_mask(hFacC[:,1])
Depth_interpolated=Interpolate(λ.μ*Γ.Depth,λ.f,λ.i,λ.j,λ.w)
Depth_interpolated=reshape(Depth_interpolated,size(λ.lon));
#Depth_interpolated[findall(Depth_interpolated.==0.0)].=NaN
Domain Decomposition#
In this example, we decompose the global domain into 117 tiles of 30 by 30.
nn=30
τ=Tiles(γ,nn,nn)
XC_tiled=Tiles(τ,Γ.XC)
YC_tiled=Tiles(τ,Γ.YC)
Depth_tiled=Tiles(τ,Γ.Depth);
ii=11
fi=heatmap(Γ.Depth,interpolation=λ,colormap=:grayC,colorbar=false)
scatter!(current_axis(),XC_tiled[ii][:],YC_tiled[ii][:],color=Depth_tiled[ii][:],
markersize=4.0,colormap=:thermal,colorrange=(0.0,6000.0))
fi
LLC90 Grid Faces#
These are the larger areas that MITgcm defines. Tiles are chunks of faces.
faceID=3
fi=Figure(size=(600,400)); ax=Axis(fi[1,1]); scatter!(ax,Γ.XC,Γ.YC,color=:black,markersize=2.0); MS=log10.(Γ.RAC)*μ;
scatter!(ax,Γ.XC[faceID][:],Γ.YC[faceID][:],color=MS[faceID][:], colorrange = (8.8,10.2),markersize=3.0,colormap=:thermal)
fi
Calculating transports between two end-points#
lon1=20.0; lon2=-63.0; lat1=-20.0; lat2=-66.0
lons=[lon1 lon2]; lats=[lat1 lat2]
my_section=demo.one_section(Γ,lons,lats)
fig_section=heatmap(λ.μ*Γ.Depth,interpolation=λ,colormap=:spring); ax=current_axis(fig_section)
scatter!(ax,my_section.lon[:],my_section.lat[:],color=:blue,markersize=2.0)
scatter!(ax,my_section.lon[:],my_section.lat[:],color=:black,markersize=4.0)
scatter!(ax,lons[:],lats[:],color=:blue)
fig_section
Regional Masks#
There are many ways to split up the global domain into Oceans, Seas, etc. Here is one example.
basin_ID=1
jj=findall(basins.mask.==basin_ID)
fi=Figure(size=(600,400)); ax=Axis(fi[1,1]);
scatter!(ax,Γ.XC,Γ.YC,color=basins.mask*μ,colormap=:lisbon,markersize=3.0)
[scatter!(ax,Γ.XC[jj][k],Γ.YC[jj][k],color=:red,markersize=3) for k in 1:length(jj)]
fi
Polygons on Maps#
#read polygons for plotting
#fil=demo.download_polygons("ne_110m_admin_0_countries.shp")
fil=demo.download_polygons("countries.geojson")
pol=MeshArrays.read_polygons(fil);
fig_polygons=Figure(size=(600,400))
ax1=Axis(fig_polygons[1,1])
[lines!(ax1,l1,color = :black, linewidth = 0.5) for l1 in pol]
fig_polygons
Geographic Projection#
meta=(colorrange=(0.0,6000.0),cmap=:berlin,gridcolor=:lightgreen,ttl="Ocean Depth (m)")
data=(lon=λ.lon,lat=λ.lat,var=Depth_interpolated,meta=meta,polygons=pol)
proj_ID=1; lon0=-160.0
proj_name=["wintri","natearth2","longlat"]
proj=Proj.Transformation(MA_preset=proj_ID,lon0=lon0)
fig0=let
f = Figure(size=(600,400))
ax = f[1, 1] = Axis(f, aspect = DataAspect(), title = "Ocean Depth (m)")
pr_ax=MeshArrays.ProjAxis(ax; proj=proj,lon0=lon0)
surf = surface!(pr_ax,λ.lon,λ.lat,0*λ.lat; color=Depth_interpolated,
colorrange=(0.0,6000.0), colormap=:berlin, shading = NoShading)
lines!(pr_ax; polygons=pol,color=:black,linewidth=0.5)
#y1=-90:5:90; x1=lon0.+0*y1; scatter!(pr_ax,x1,y1,color=:yellow,markersize=5,marker=:x)
MeshArrays.grid_lines!(pr_ax;color=:lightgreen,linewidth=0.5)
Colorbar(f[1,2], surf, height = Relative(0.5))
f
end
Zonal Averaging Detail#
LC=LatitudeCircles(79.0,Γ)
aa=LC.C
locClat=( lon=[Γ.XC[aa[i,1]][aa[i,2],aa[i,3]] for i in 1:size(aa,1)],
lat=[Γ.YC[aa[i,1]][aa[i,2],aa[i,3]] for i in 1:size(aa,1)])
"Done with latitude line"
Interpolation Scheme Detail#
Wondering about the Interpolation Code? Let’s Break It Down:
find nearest neighbor (
MeshArray
&set
)define subdomain tiles (
MeshArray
->tiles
)exchange and start loop (
tile
&subset
)local stereographic projection
define array of quadrilaterals
find enclosing quadrilaterals
compute interpolation coefficients
(fig1,fig2,fig3)=MeshArrays.plot_examples(:interpolation_demo,Γ);