Skip to content

Commit

Permalink
Code for preprocessing Rabatel (2023) data (#71)
Browse files Browse the repository at this point in the history
* Calculatio of Transversal Mercator Projection for glacier coordinates

* Fix typo and force run of all tests

* Update test files

* Add missng glaciers to see if fixes tests

* Include zone projection in Mercator

* [WIP] Adding methods to process Rabatel (2023) ice surface velocity data

* Data adquisition of Rabatel data

* Closes #3

* Remove sync CI

* restore original test data files

* fix typo

* Adding dates for interp dataset

* Fix small comments
  • Loading branch information
facusapienza21 authored Feb 24, 2025
1 parent c9759a5 commit 0b3536a
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 27 deletions.
12 changes: 0 additions & 12 deletions .github/sync.yml

This file was deleted.

2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66"
CoordRefSystems = "b46f11dc-f210-4604-bfba-323c1ec968cb"
DateFormats = "44557152-fe0a-4de1-8405-416d90313ce6"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
Expand All @@ -17,6 +18,7 @@ Infiltrator = "5903a43b-9cc3-4c30-8d17-598619ec4e9b"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab"
NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Rasters = "a3a2b9e3-a471-40c9-b274-f788e487c689"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Expand Down
8 changes: 6 additions & 2 deletions src/Sleipnir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ using Tar
import NCDatasets
using Unitful: m, rad, °
using CoordRefSystems
using Dates, DateFormats
using NetCDF

# ##############################################
# ############ PARAMETERS ###############
Expand All @@ -39,11 +41,13 @@ const global prepro_dir::String = joinpath(homedir(), ".ODINN", "ODINN_prepro")
include("setup/config.jl")
# All parameters needed for the models
include("parameters/Parameters.jl")
# Anything related to managing glacier topographical and climate data
# Anything related to managing glacier topographical and climate variables
include("glaciers/glacier/Glacier.jl")
# Anything related to managing glacier data used for data assimilation
include("glaciers/data/Data.jl")
# All structures and functions related to ODINN models
include("models/Model.jl")
# Everything related to running simulations in ODINN
include("simulations/Simulation.jl")

end # module
end # module
5 changes: 5 additions & 0 deletions src/glaciers/data/Data.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export AbstractData

abstract type AbstractData end

include("SurfaceVelocityData.jl")
75 changes: 75 additions & 0 deletions src/glaciers/data/SurfaceVelocityData.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export SurfaceVelocityData

mutable struct SurfaceVelocityData{F <: AbstractFloat} <: AbstractData
x::Union{Vector{F}, Nothing}
y::Union{Vector{F}, Nothing}
lat::Union{Vector{F}, Nothing}
lon::Union{Vector{F}, Nothing}
vx::Union{Array{F, 3}, Nothing}
vy::Union{Array{F, 3}, Nothing}
vabs::Union{Array{F, 3}, Nothing}
vx_error::Union{Array{F, 1}, Nothing}
vy_error::Union{Array{F, 1}, Nothing}
vabs_error::Union{Array{F, 1}, Nothing}
date::Union{Vector{DateTime}, Nothing}
date1::Union{Vector{DateTime}, Nothing}
date2::Union{Vector{DateTime}, Nothing}
date_error::Union{Vector{Day}, Vector{Millisecond}, Nothing}
end

"""
function SurfaceVelocityData(;
x::Union{Vector{F}, Nothing} = nothing,
y::Union{Vector{F}, Nothing} = nothing,
lat::Union{Vector{F}, Nothing} = nothing,
lon::Union{Vector{F}, Nothing} = nothing,
vx::Union{Array{F, 3}, Nothing} = nothing,
vy::Union{Array{F, 3}, Nothing} = nothing,
vabs::Union{Array{F, 3}, Nothing} = nothing,
vx_error::Union{Array{F, 1}, Nothing} = nothing,
vy_error::Union{Array{F, 1}, Nothing} = nothing,
vabs_error::Union{Array{F, 1}, Nothing} = nothing,
date::Union{Vector{DateTime}, Nothing} = nothing,
date1::Union{Vector{DateTime}, Nothing} = nothing,
date2::Union{Vector{DateTime}, Nothing} = nothing,
date_error::Union{Vector{Day}, Vector{Millisecond}, Nothing} = nothing,
) where {F <: AbstractFloat}
Constructor for ice surface velocity data based on Rabatel et. al (2023).
Important remarks:
- Projections in longitude and latitude assume we are working in the north hemisphere.
If working with south hemisphere glaciers, this needs to be changed.
- The error in velocity is unique per timestamp, rather than being pixel distributed.
- The error in the absolute velocities `vabs_error` is overestimated.
References:
- Rabatel, A., Ducasse, E., Millan, R. & Mouginot, J.
Satellite-Derived Annual Glacier Surface Flow Velocity Products for the European Alps, 2015–2021.
Data 8, 66 (2023).
"""
function SurfaceVelocityData(;
x::Union{Vector{F}, Nothing} = nothing,
y::Union{Vector{F}, Nothing} = nothing,
lat::Union{Vector{F}, Nothing} = nothing,
lon::Union{Vector{F}, Nothing} = nothing,
vx::Union{Array{F, 3}, Nothing} = nothing,
vy::Union{Array{F, 3}, Nothing} = nothing,
vabs::Union{Array{F, 3}, Nothing} = nothing,
vx_error::Union{Array{F, 1}, Nothing} = nothing,
vy_error::Union{Array{F, 1}, Nothing} = nothing,
vabs_error::Union{Array{F, 1}, Nothing} = nothing,
date::Union{Vector{DateTime}, Nothing} = nothing,
date1::Union{Vector{DateTime}, Nothing} = nothing,
date2::Union{Vector{DateTime}, Nothing} = nothing,
date_error::Union{Vector{Day}, Vector{Millisecond}, Nothing} = nothing,
) where {F <: AbstractFloat}

ft = typeof(x[begin])

return SurfaceVelocityData{ft}(x, y, lat, lon, vx, vy, vabs, vx_error, vy_error, vabs_error, date, date1, date2, date_error)
end


include("surfacevelocitydata_utils.jl")
109 changes: 109 additions & 0 deletions src/glaciers/data/surfacevelocitydata_utils.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
export initialize_surfacevelocitydata
export plot_timeseries, plot_count

"""
initialize_surfacevelocitydata(file::String; interp=false)
Initialize SurfaceVelocityData from Rabatel et. al (2023).
Arguments
=================
- `file`: name of netcdf file with data
- `interp`: boolean variable indicating if we use the inporpolated data or not
"""
function initialize_surfacevelocitydata(file::String; interp=false, compute_vabs_error::Bool=true)

# Date of first adquisition
date1 = ncread(file, "date1")
# Date of second adquisition
date2 = ncread(file, "date2")

# Middle date
if !interp
date_mean = 0.5 .* date1 .+ 0.5 .* date2
date_mean_offset = date1_offset = date2_offset = 0
else
date_mean = ncread(file, "mid_date")
# Extract string from metadata of when days start counting
# Default format of attribute "units" is "days since 2015-08-14 00:00:00"
date_mean_since = ncgetatt(file, "mid_date", "units")[12:21] # e.g., "2015-08-14"
date1_offset_since = ncgetatt(file, "date1", "units")[12:21] # e.g., "2015-07-30"
date2_offset_since = ncgetatt(file, "date2", "units")[12:21] # e.g., "2015-08-29"
# Convertion to Julia datetime
date_mean_offset = datetime2julian(DateTime(date_mean_since)) - 2400000.5
date1_offset = datetime2julian(DateTime(date1_offset_since)) - 2400000.5
date2_offset = datetime2julian(DateTime(date_mean_offset)) - 2400000.5
end

# Convert dates from Modified Julian Days to datetipes
date1 = mjd.(date1 .+ date1_offset)
date2 = mjd.(date2 .+ date2_offset)
date_mean = mjd.(date_mean .+ date_mean_offset)
date_error = date2 .- date1

# We convert from Date to DateTime
date_mean = DateTime.(date_mean)
date1 = DateTime.(date1)
date2 = DateTime.(date2)

# Read data from netcdf file
x = ncread(file, "x")
y = ncread(file, "y")

# Velocity in the x direction (m/yr)
vx = ncread(file, "vx")
vy = ncread(file, "vy")

# Compute absolute velocity
vabs = (vx.^2 .+ vy.^2).^0.5
# The sqrt operation in Julia promotes Float32 to Float64. We convert manually
# to keep type consistency
vabs = convert(typeof(vx), vabs)

# Error is reported once per timespan, so upper bounds are given by absolute error
if !interp
vx_error = ncread(file, "error_vx")
vy_error = ncread(file, "error_vy")
# Absolute error uncertanty using propagation of uncertanties
if compute_vabs_error
vx_ratio_max = map(i -> max_or_empty(abs.(vx[:,:,i][vabs[:,:,i] .> 0.0]) ./ vabs[:,:,i][vabs[:,:,i] .> 0.0]), 1:size(vx)[3])
vy_ratio_max = map(i -> max_or_empty(abs.(vy[:,:,i][vabs[:,:,i] .> 0.0]) ./ vabs[:,:,i][vabs[:,:,i] .> 0.0]), 1:size(vy)[3])
vabs_error = ((vx_ratio_max .* vx_error).^2 .+ (vy_ratio_max .* vy_error).^2).^0.5
vabs_error = convert(typeof(vx_error), vabs_error)
else
vabs_error = nothing
end
else
vx_error = nothing
vy_error = nothing
vabs_error = nothing
end

# Run some basic tests
nx, ny, ntimes = size(vx)
@assert length(date1) == length(date2) == ntimes
@assert nx == ny == 250

# Spatial preprocessing
proj_zone = ncgetatt(file, "mapping", "utm_zone_number")
transform(X,Y) = Sleipnir.UTMercator(X, Y; zone=proj_zone, hemisphere=:north)
Coordinates = transform.(x, y)
latitudes = map(x -> x.lat.val, Coordinates)
longitudes = map(x -> x.lon.val, Coordinates)

return SurfaceVelocityData(x=x, y=y, lat=latitudes, lon=longitudes, vx=vx, vy=vy, vabs=vabs, vx_error=vx_error, vy_error=vy_error, vabs_error=vabs_error, date=date_mean, date1=date1, date2=date2, date_error=date_error)
end

"""
max_or_empyt(A::Array)
Return maximum value for non-empty arrays.
This is just required to compute the error in the absolute velocity.
"""
function max_or_empty(A::Array)
if length(A) == 0
return 0.0
else
return maximum(A)
end
end
27 changes: 14 additions & 13 deletions src/parameters/PhysicalParameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,29 @@ end

"""
PhysicalParameters(;
ρ::Float64 = 900.0,
g::Float64 = 9.81,
ϵ::Float64 = 1e-3,
η₀::F = 1.0,
maxA::Float64 = 8e-17,
minA::Float64 = 8.5e-20,
maxTlaw::Float64 = 1.0,
minTlaw::Float64 = -25.0,
noise_A_magnitude::Float64 = 5e-18
)
ρ::F = 900.0,
g::F = 9.81,
ϵ::F = 1e-3,
η₀::F = 1.0,
maxA::F = 8e-17,
minA::F = 8.5e-20,
maxTlaw::F = 1.0,
minTlaw::F = -25.0,
noise_A_magnitude::F = 5e-18
)
Initialize the physical parameters of a model.
Keyword arguments
=================
- `ρ`: Ice density
- `g`: Gravitational constant
- `n`: Glen's exponent
- `A`: Glen's coefficient
- `ϵ`: Small number
- `C`: Sliding coefficient
- `η₀`:
- `maxA`: Maximum value for `A` (Glen's coefficient)
- `minA`: Minimum value for `A` (Glen's coefficient)
- `maxTlaw`: Maximum value of Temperature used in simulations on fake law
- `minTlaw`: Minimum value of Temperature used in simulations on fake law
- `noise_A_magnitude`: Magnitude of noise added to A
"""
function PhysicalParameters(;
ρ::F = 900.0,
Expand Down

0 comments on commit 0b3536a

Please sign in to comment.