Output
The output and restart files, and how to read isochrones from them
elsa writes two kinds of NetCDF file through ncio: a time-resolved output file, and a restart file that holds one instant. Both live on elsa’s own grid, which differs from the host grid if grid_factor is not 1.
The layer convention
The vertical axis of elsa is the layer index, and reading the files requires the following convention.
- Layer 1 is at the bed. Layer
n_topis the topmost active layer, which is the one currently receiving accumulation. Layers aboven_tophave been allocated but not yet laid down, and hold zero thickness. d_iso(i,j,k)is the thickness of layerk.dsum_iso(i,j,k)is the height of the top of layerkabove the bed, so thatdsum_iso(i,j,n_top)is the ice thickness.- The deposition time of layer
k(t_depin the state and in the restart file,layer_timein the output file) is the time of the update at which the layer was opened. This is the first update at or after the scheduled isochrone time, so it equals the scheduled time only if an update lands on it, and is otherwise later by less than one coupling period. It is the age label of the isochrone at the base of layerk. The ice inside layerkwas deposited betweenlayer_time(k)andlayer_time(k+1). - The initialization layers,
1ton_layers_init, carry the missing value \(-9999\) as deposition time, as do the layers aboven_top. The missing value is written as a plain number and not as a_FillValueattribute.
The height above the bed of the isochrone deposited at layer_time(k) is therefore dsum_iso(i,j,k-1), and its depth below the surface is H_ice(i,j) - dsum_iso(i,j,k-1). The oldest dated isochrone is the base of layer n_layers_init + 1, which is the ice surface at the initial time.
The output file
elsa_write_init creates the file and its axes, and each call to elsa_write_step appends one time slice.
| Dimension | Size | Units | Content |
|---|---|---|---|
xc, yc |
elsa grid | m | cell-centre coordinates |
layer |
n_layers |
1 | layer index, 1 at the bed |
time |
unlimited | years | model time of each slice |
| Variable | Dimensions | Units | Content |
|---|---|---|---|
layer_time |
layer |
years | deposition time of each layer |
n_top |
time |
1 | index of the topmost active layer |
H_ice |
xc, yc, time |
m | ice thickness on elsa’s grid |
d_iso |
xc, yc, layer, time |
m | layer thickness |
dsum_iso |
xc, yc, layer, time |
m | height of the layer top above the bed |
ux_iso |
xc, yc, layer, time |
m yr\(^{-1}\) | layer-mean velocity in x, on acx faces |
uy_iso |
xc, yc, layer, time |
m yr\(^{-1}\) | layer-mean velocity in y, on acy faces |
Three properties of this file should be kept in mind.
First, layer_time has no time dimension. It is rewritten at every step from the state, so the file always holds the deposition times of the layers laid down so far. A slice at an earlier time must be read together with its own n_top, since layers above it did not yet exist at that time.
Second, the three-dimensional fields are written in single precision, since they dominate the file size. At 3000 m of ice this limits the resolution of dsum_iso to around \(2 \times 10^{-4}\) m, which is irrelevant for analysis but means that the output file cannot be used to restart.
Third, the velocities are located on elsa’s staggered faces, not at the cell centres. ux_iso(i,j,k) sits at xc(i) + dx/2. The last face in each direction carries zero flux and is written as zero.
Every slice holds all n_layers layers, including those not yet laid down. A long run with many layers and frequent output therefore produces a large file, and the output interval should be chosen accordingly.
The restart file
elsa_restart_write writes the complete state at one instant. The file also serves as a diagnostic snapshot, but only part of it is read back.
| Variable | Dimensions | Precision | Read back |
|---|---|---|---|
time |
one |
double | yes |
time_acc |
one |
double | yes |
n_top, i_add |
one |
integer | yes |
n_reseed_total |
one |
integer | yes |
n_reseed |
one |
integer | no |
n_layers_init |
one |
integer | yes |
time_add |
isochrone |
double | yes |
d_iso |
xc, yc, layer |
double | yes |
H_ice_prev |
xc, yc |
double | yes |
t_dep |
layer |
double | yes |
smb_acc, bmb_acc |
xc_src, yc_src |
double | yes |
ux_acc, uy_acc |
xc_src, yc_src, zeta |
double | yes |
dsum_iso, ux_iso, uy_iso |
xc, yc, layer |
single | no |
H_ice, smb, bmb |
xc, yc |
single | no |
ux_lev, uy_lev |
xc, yc, zeta |
single | no |
The axes xc, yc and zeta are read back as well, and are compared with the current grid. time is the time of the last update and time_acc the time at which the file was written. The _acc fields are the forcing integrated between the two, on the host grid (xc_src, yc_src). They are zero if the file was written on an update. smb, bmb, ux_lev and uy_lev are the means over the last completed coupling period. time_add is the full isochrone schedule and i_add the index of its next entry. time_add is absent if no isochrone was scheduled. The reasons for carrying each item are given under Design.
Reading isochrones
The Julia helpers in analysis/elsa_analysis.jl implement the convention above. ElsaRun(path) opens an output file and converts the missing deposition times to NaN, isochrone_layers returns the layers that have a dated base, and isochrone_height returns the ages and the heights of all isochrones in one column at one time index.
The depth of one isochrone can also be obtained directly. The following example extracts the depth below the surface of the isochrone that was laid down at t_iso, at the last time slice.
using NCDatasets
ds = NCDataset("output/GRL-16KM/elsa.nc")
lt = ds["layer_time"][:]
it = length(ds["time"])
H = ds["H_ice"][:, :, it]
dsum = ds["dsum_iso"][:, :, :, it]
t_iso = 1000.0
k = findfirst(>=(t_iso), lt) # the layer whose base is this isochrone
depth = H .- dsum[:, :, k-1]
depth[H .<= 0] .= NaNThe age of this isochrone at time t is t - lt[k]. A comparison with observed radiostratigraphy requires the depth of a given age, so the isochrone schedule should contain the dated horizons of interest, either through a suitable layer_resolution or through a layer_file.