diff --git a/Project.toml b/Project.toml index 880c580..94cd608 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "XESMF" uuid = "2e0b0046-e7a1-486f-88de-807ee8ffabe5" authors = ["NumericalEarth and contributors"] -version = "0.1.1" +version = "0.1.2" [deps] CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab" diff --git a/src/XESMF.jl b/src/XESMF.jl index 738b354..46ee3d5 100644 --- a/src/XESMF.jl +++ b/src/XESMF.jl @@ -4,29 +4,24 @@ using CondaPkg using PythonCall using SparseArrays -# Placeholder (will be overwritten in __init__) -xesmf = Py(nothing) +struct Regridder{S, M, V1, V2} + method :: M + weights :: S + src_temp :: V1 + dst_temp :: V2 +end -function __init__() - global xesmf - try - xesmf = pyimport("xesmf") - catch e - if occursin("No module named 'ESMF'", string(e)) - error(""" - XESMF.jl requires the ESMF library to be installed. - This is usually handled automatically by CondaPkg, but on some systems - (particularly Windows) it may need to be installed manually. +Base.summary(r::Regridder{S, M, V1, V2}) where {S, M, V1, V2} = "$(r.method) Regridder" - Try running: - julia -e "using CondaPkg; CondaPkg.add(["esmf", "esmpy"])" - """) - else - rethrow(e) - end - end +function Base.show(io::IO, r::Regridder) + print(io, summary(r), '\n') + print(io, "├── weights: ", summary(r.weights), '\n') + print(io, "├── src_temp: ", summary(r.src_temp), '\n') + print(io, "└── dst_temp: ", summary(r.dst_temp)) end +function extract_xesmf_coordinates_structure end + """ sparse_regridder_weights(FT, regridder) @@ -47,4 +42,73 @@ end sparse_regridder_weights(regridder) = sparse_regridder_weights(Float64, regridder) +""" + Regridder(src_coordinates::Dict{String, <:AbstractArray}, + dst_coordinates::Dict{String, <:AbstractArray}; + method="conservative", periodic=false) + +Return a Regridder from the xESMF Python package to regrid data from +`src_coordinates` to `dst_coordinates` using the specified `method`. + +The `src_coordinates` and `dst_coordinates` are dictionaries that contain +information about the two grids. + +xESMF exposes five different regridding algorithms from the ESMF library, +specified with the `method` keyword argument: + +* `"bilinear"`: `ESMF.RegridMethod.BILINEAR` +* `"conservative"`: `ESMF.RegridMethod.CONSERVE` +* `"conservative_normed"`: `ESMF.RegridMethod.CONSERVE` +* `"patch"`: `ESMF.RegridMethod.PATCH` +* `"nearest_s2d"`: `ESMF.RegridMethod.NEAREST_STOD` +* `"nearest_d2s"`: `ESMF.RegridMethod.NEAREST_DTOS` + +where `conservative_normed` is just the conservative method with the normalization set to +`ESMF.NormType.FRACAREA` instead of the default `norm_type = ESMF.NormType.DSTAREA`. + +For more information, see the Python xESMF documentation at: + +> https://xesmf.readthedocs.io/en/latest/notebooks/Compare_algorithms.html +""" +function Regridder(src_coordinates::Dict{String, <:AbstractArray}, + dst_coordinates::Dict{String, <:AbstractArray}; + method="conservative", periodic=false) + + xesmf = XESMF.xesmf + regridder = xesmf.Regridder(src_coordinates, dst_coordinates, method; periodic) + method = uppercasefirst(string(regridder.method)) + + weights = XESMF.sparse_regridder_weights(regridder) + + Ndst, Nsrc = size(weights) + + temp_src = zeros(Nsrc) + temp_dst = zeros(Ndst) + + return Regridder(method, weights, temp_src, temp_dst) +end + +# Placeholder (will be overwritten in __init__) +xesmf = Py(nothing) + +function __init__() + global xesmf + try + xesmf = pyimport("xesmf") + catch e + if occursin("No module named 'ESMF'", string(e)) + error(""" + XESMF.jl requires the ESMF library to be installed. + This is usually handled automatically by CondaPkg, but on some systems + (particularly Windows) it may need to be installed manually. + + Try running: + julia -e "using CondaPkg; CondaPkg.add(["esmf", "esmpy"])" + """) + else + rethrow(e) + end + end +end + end # module XESMF