|
| 1 | +""" |
| 2 | +This `OCIM2_48L` module is used to load the OCIM2-48L matrices and grid for use in AIBECS. |
| 3 | +
|
| 4 | +!!! tip |
| 5 | + To load the default OCIM2_48L matrix and grid, do |
| 6 | + ``` |
| 7 | + julia> grd, T = OCIM2_48L.load() |
| 8 | + ``` |
| 9 | + But you can also load the other matrices by specifying which version you want, e.g., |
| 10 | + ``` |
| 11 | + julia> grd, T = OCIM2_48L.load(version="OCIM2_48L_KiHIGH_noHe") |
| 12 | + ``` |
| 13 | + See *DeVries and Holzer* (2019) for more details |
| 14 | +
|
| 15 | +
|
| 16 | +!!! note |
| 17 | + The files, that are downloaded from a public and persistant URL in FigShare, |
| 18 | + were created with the code available at https://github.com/briochemc/OceanCirculations. |
| 19 | +""" |
| 20 | +module OCIM2_48L |
| 21 | + |
| 22 | +using SparseArrays # for sparse matrix |
| 23 | +using DataDeps # for automated download/storage of data |
| 24 | +using Downloads |
| 25 | +using MAT # for reading OCIM2_48L transport operator matrix from MAT file |
| 26 | +using NCDatasets # for reading OCIM2_48L grid from NetCDF file |
| 27 | +using Unitful # for units |
| 28 | +using Unitful: s, yr, m, km, ° |
| 29 | +using Reexport |
| 30 | +@reexport using OceanGrids # To store the grid |
| 31 | + |
| 32 | +function fallback_download(remotepath, localdir) |
| 33 | + @assert(isdir(localdir)) |
| 34 | + filename = basename(remotepath) # only works for URLs with filename as last part of name |
| 35 | + localpath = joinpath(localdir, filename) |
| 36 | + Downloads.download(remotepath, localpath) |
| 37 | + return localpath |
| 38 | +end |
| 39 | + |
| 40 | +# OCIM2_48L URL |
| 41 | +url() = "https://files.figshare.com/28468077/OCIM2_48L_base.tar.gz" |
| 42 | + |
| 43 | +# OCIM2_48L Hashes |
| 44 | +sha() = "7c6e7981df69122957c9f2475be7ffe958819ff44d02be6d004886b6dfc3fac7" |
| 45 | + |
| 46 | +OCIM2versionerror(version) = error("""`$version` is not a valid OCIM2 version name. |
| 47 | +
|
| 48 | + Valid versions are `CTL_He`, `CTL_noHe`, `KiHIGH_He`, `KiHIGH_noHe`, `KiLOW_He`, `KiLOW_noHe`, `KvHIGH_He`, `KvHIGH_KiHIGH_noHe`, `KvHIGH_KiLOW_He`, `KvHIGH_KiLOW_noHe`, and `KvHIGH_noHe`. |
| 49 | +
|
| 50 | + See *DeVries and Holzer* (2019) for more details on OCIM2 configurations.""") |
| 51 | + |
| 52 | + |
| 53 | +# Create registry entry for OCIM in JLD2 format |
| 54 | +function register_OCIM2_48L() |
| 55 | + register( |
| 56 | + DataDep( |
| 57 | + "AIBECS-OCIM2_48L", |
| 58 | + """ |
| 59 | + References: |
| 60 | + - $(citations()) |
| 61 | + """, |
| 62 | + url(), |
| 63 | + sha(), |
| 64 | + fetch_method = fallback_download, |
| 65 | + post_fetch_method = unpack |
| 66 | + ) |
| 67 | + ) |
| 68 | + return nothing |
| 69 | +end |
| 70 | + |
| 71 | +""" |
| 72 | + load |
| 73 | +
|
| 74 | +Returns the grid and the transport matrix of the OCIM2_48L model. |
| 75 | +
|
| 76 | +See *DeVries and Holzer* (2019) and *Holzer et al.* (2021) for more details. |
| 77 | +""" |
| 78 | +function load() |
| 79 | + register_OCIM2_48L() |
| 80 | + files_path = @datadep_str "AIBECS-OCIM2_48L" |
| 81 | + @info """You are about to use the OCIM2_48L model. |
| 82 | + If you use it for research, please cite: |
| 83 | +
|
| 84 | + $(citations()) |
| 85 | +
|
| 86 | + You can find the corresponding BibTeX entries in the CITATION.bib file |
| 87 | + at the root of the AIBECS.jl package repository. |
| 88 | + (Look for the "DeVries_Holzer_2019" and "Holzer_etal_2021" keys.) |
| 89 | + """ |
| 90 | + |
| 91 | + # Convert convergence T in yr⁻¹ from original MAT file to divergence T in s⁻¹ |
| 92 | + T = -ustrip.(s^-1, matread(joinpath(files_path, "OCIM2_48L_base_transport.mat"))["TR"] * yr^-1); |
| 93 | + |
| 94 | + # Create grid object from NetCDF file variables |
| 95 | + # TODO: Add Hyrothermal He fluxes as for the OCIM2 load function |
| 96 | + grid = Dataset(joinpath(files_path, "OCIM2_48L_base_data.nc"), "r") do ds |
| 97 | + wet3D = ds["ocnmask"][:] .== 1 |
| 98 | + nlat, nlon, ndepth = size(wet3D) |
| 99 | + lat_3D = ds["tlat"][:]° |
| 100 | + lon_3D = ds["tlon"][:]° |
| 101 | + depth_3D = ds["tz"][:]m |
| 102 | + lat = unique(lat_3D) |
| 103 | + lon = unique(lon_3D) |
| 104 | + depth = unique(depth_3D) |
| 105 | + ulat = unique(ds["ulon"][:])° # ulat↔ulon in OCIM2-48L original files |
| 106 | + ulon = unique(ds["ulat"][:])° # ulat↔ulon in OCIM2-48L original files |
| 107 | + depth_top_3D = ds["wz"][:]m |
| 108 | + depth_top = unique(depth_top_3D) |
| 109 | + δlat = 2(ulat - lat) |
| 110 | + δlon = 2(ulon - lon) |
| 111 | + δdepth = 2(depth - depth_top) |
| 112 | + R = 6371.0km |
| 113 | + δy = R * δlat ./ 360° |
| 114 | + δy_3D = repeat(reshape(δy, (nlat,1,1)), outer=(1,nlon,ndepth)) |
| 115 | + A_3D = ds["area"][:]m^2 |
| 116 | + δx_3D = A_3D ./ δy_3D |
| 117 | + volume_3D = ds["vol"]m^3 |
| 118 | + δz_3D = volume_3D ./ A_3D |
| 119 | + A_2D = A_3D[:,:,1] |
| 120 | + nboxes = count(wet3D) |
| 121 | + OceanRectilinearGrid( |
| 122 | + lat, |
| 123 | + lon, |
| 124 | + depth, |
| 125 | + δlat, |
| 126 | + δlon, |
| 127 | + δdepth, |
| 128 | + lat_3D, |
| 129 | + lon_3D, |
| 130 | + depth_3D, |
| 131 | + δy, |
| 132 | + δx_3D, |
| 133 | + δy_3D, |
| 134 | + δz_3D, |
| 135 | + volume_3D, |
| 136 | + depth_top, |
| 137 | + depth_top_3D, |
| 138 | + A_2D, |
| 139 | + wet3D, |
| 140 | + nlon, |
| 141 | + nlat, |
| 142 | + ndepth, |
| 143 | + nboxes |
| 144 | + ) |
| 145 | + end |
| 146 | + |
| 147 | + return grid, T |
| 148 | + |
| 149 | +end |
| 150 | + |
| 151 | +citations() = """ |
| 152 | + - Holzer, M., DeVries, T. & de Lavergne, C. Diffusion controls the ventilation of a Pacific Shadow Zone above abyssal overturning. Nat Commun 12, 4348 (2021). https://doi.org/10.1038/s41467-021-24648-x |
| 153 | + - DeVries, T., & Holzer, M. (2019). Radiocarbon and helium isotope constraints on deep ocean ventilation and mantle-3He sources. Journal of Geophysical Research: Oceans, 124, 3036–3057. https://doi.org/10.1029/2018JC014716 |
| 154 | + """ |
| 155 | + |
| 156 | +end # end module |
| 157 | + |
| 158 | +export OCIM2_48L |
| 159 | + |
0 commit comments