ClimaCoreTempestRemap.jl
ClimaCoreTempestRemap.jl provides an interfaces for using ClimaCore data with the TempestRemap remapping package, by Paul Ullrich.
Interface
Online remap
ClimaCoreTempestRemap.LinearMap — TypeLinearMap{S, T, W, I, V}stores information on the TempestRemap map and the source and target data:
where:
source_spaceandtarget_spaceare ClimaCore's 2D spaces.weightsis a vector of remapping weights. (length = number of overlap-mesh nodes).source_local_idxsa 3-element Tuple with 3 index vectors, representing local (i,j,elem) indices on the source mesh. (length of each index vector = number of overlap-mesh nodes)target_local_idxsis the same assource_local_idxsbut for the target mesh.row_indicesare the target row indices from TempestRemap. (length = number of overlap-mesh nodes)out_typestring that defines the output type.
ClimaCoreTempestRemap.generate_map — Functiongenerate_map(target_space, source_space; in_type="cgll", out_type="cgll")Generate the remapping weights from TempestRemap, returning a LinearMap object. This should only be called once.
ClimaCoreTempestRemap.remap! — Functionremap!(target::IJFH{S, Nqt}, R::LinearMap, source::IJFH{S, Nqs})
remap!(target::Fields.Field, R::LinearMap, source::Fields.Field)Applies the remapping R to a source Field and stores the result in target.
ClimaCoreTempestRemap.remap — Functionremap(R::LinearMap, source::Field)Applies the remapping R to a source Field, allocating a new field in the output.
Mesh export
ClimaCoreTempestRemap.write_exodus — Functionwrite_exodus(filename, topology::Topology2D; normalize_coordinates=true)Write the topology to an Exodus-formatted NetCDF file.
It tries to adhere to the Exodus II specification, but it is primarily intended for use with TempestRemap.
Note: the generated meshes will use a different ordering of nodes and elements than those generated by TempestRemap itself.
When using this function with a distributed topology input for MPI, it should only be called on a single process.
Options:
normalize_coordinates: if true, the coordinates are normalized to be on the unit sphere (this is required for use with TempestRemap)
References
- EXODUS II: A finite element data model: https://www.osti.gov/biblio/10102115-exodus-ii-finite-element-data-model
NetCDF data export
ClimaCoreTempestRemap.def_time_coord — Functiondef_time_coord(nc::NCDataset, length=Inf, eltype=Float64;
units = "seconds since 2020-01-01 00:00:00"
kwargs...
)Deine a time coordinate (dimension + variable) "time" in the NetCDF dataset nc. By default its length is set to be unlimited. The variable corresponding to the coordinate is returned.
Additional attributes can be added as keyword arguments.
Example
timevar = add_time_coord!(nc; units = "seconds since 2020-01-01 00:00:00",)
timevar[:] = collect(0.0:0.5:60)ClimaCoreTempestRemap.def_space_coord — Functiondef_space_coord(nc::NCDataset, space::Spaces.AbstractSpace; type = "dgll")Add spatial dimensions for space in the NetCDF dataset nc, compatible with the type used by remap_weights.
If a compatible dimension already exists, it will be reused.
CommonDataModel.defVar — MethodNCDatasets.defVar(nc::NCDataset, name, field::Field, extradims=())Define a new variable in nc named name of suitable for storing field, along with any further dimensions specified in extradims. The new variable is returned.
Base.setindex! — Methodvar[:, extraidx...] = fieldWrite the data in field to a NetCDF variable var. extraidx are any extra indices of var.
Appropriate spatial dimensions should already be defined by defVar.
# Given a collection of fields U, write them as a single array to a NetCDF file.
def_space_coord(nc, space)
nc_time = def_time_coord(nc)
nc_u = defVar(nc, "u", Float64, space, ("time",))
for (i,t) in enumerate(times)
nc_time[i] = t
nc_u[:,i] = U[i]
endWrapper functions
ClimaCoreTempestRemap.rll_mesh — Functionrll_mesh(filename::AbstractString; nlat=90, nlon = round(Int, nlat * 1.6); verbose=false)Create a regular latitude-longitude (RLL) mesh and write it to filename in Exodus format. nlat is the number of latitudinal cells, and nlon is the number of longitudinal cells.
Set verbose=true to print information.
ClimaCoreTempestRemap.overlap_mesh — Functionoverlap_mesh(outfile::AbstractString, meshfile_a::AbstractString, meshfile_b::AbstractString; verbose=false)Create the overlap mesh of meshfile_a and meshfile_b and write it to outfile. All files should be in Exodus format.
Set verbose=true to print information.
ClimaCoreTempestRemap.remap_weights — Functionremap_weights(
weightfile::AbstractString,
meshfile_in::AbstractString,
meshfile_out::AbstractString,
meshfile_overlap::AbstractString;
verbose=false,
kwargs...
)Create a file weightfile in SCRIP format containing the remapping weights from meshfile_in to meshfile_out, where meshfile_overlap is constructed via overlap_mesh.
Keyword arguments are passed as command-line options. These include:
in_type/out_type: the type of the input and output mesh:"fv"(default): finite volume (one value per element)"cgll": continuous GLL finite element method (a single value for colocated nodes)"dgll": discontinuous GLL finite element method (duplicate values for colocated nodes)
- 'innp'/'outnp': Order of input and output meshes
- 'mono': Monotonicity of remapping
Set mono = true for monotone remapping Set verbose=true to print information.
ClimaCoreTempestRemap.apply_remap — Functionapply_remap(outfile::AbstractString, infile::AbstractString, weightfile::AbstractString, vars; verbose=false)Remap the NetCDF file infile to outfile, using the remapping weights weightfile constructed via remap_weights. vars should be a collection of variable names to remap.
Set verbose=true to print information.
Example
The following example converts an OrdinaryDiffEq solution object sol to a netcdf file, and remaps it to an regular latitude-longitude (RLL) grid.
using ClimaCore: Geometry, Meshes, Domains, Topologies, Spaces, Quadratures
using NCDatasets, ClimaCoreTempestRemap
# sol is the integrator solution
# cspace is the center extrduded space
# fspace is the face extruded space
# the issue is that the Space types changed since this changed
# we can reconstruct it by digging around a bit
Nq = Quadratures.degrees_of_freedom(Spaces.quadrature_style(cspace))
datafile_cc = "test.nc"
NCDataset(datafile_cc, "c") do nc
# defines the appropriate dimensions and variables for a space coordinate
def_space_coord(nc, cspace, type = "cgll")
def_space_coord(nc, fspace, type = "cgll")
# defines the appropriate dimensions and variables for a time coordinate (by default, unlimited size)
nc_time = def_time_coord(nc)
# define variables
nc_rho = defVar(nc, "rho", Float64, cspace, ("time",))
nc_theta = defVar(nc, "theta", Float64, cspace, ("time",))
nc_u = defVar(nc, "u", Float64, cspace, ("time",))
nc_v = defVar(nc, "v", Float64, cspace, ("time",))
nc_w = defVar(nc, "w", Float64, fspace, ("time",))
# write data to netcdf file
for i = 1:length(sol.u)
nc_time[i] = sol.t[i]
# extract fields and convert to orthogonal coordinates
Yc = sol.u[i].Yc
uₕ = Geometry.UVVector.(sol.u[i].uₕ)
w = Geometry.WVector.(sol.u[i].w)
# write fields to file
nc_rho[:,i] = Yc.ρ
nc_theta[:,i] = Yc.ρθ ./ Yc.ρ
nc_u[:,i] = map(u -> u.u, uₕ)
nc_v[:,i] = map(u -> u.v, uₕ)
nc_w[:,i] = map(u -> u.w, w)
end
end
# write out our cubed sphere mesh
meshfile_cc = "mesh_cubedsphere.g"
write_exodus(meshfile_cc, Spaces.topology(Spaces.horizontal_space(cspace)))
# write out RLL mesh
nlat = 90
nlon = 180
meshfile_rll = "mesh_rll.g"
rll_mesh(meshfile_rll; nlat = nlat, nlon = nlon)
# construct overlap mesh
meshfile_overlap = "mesh_overlap.g"
overlap_mesh(meshfile_overlap, meshfile_cc, meshfile_rll)
# construct remap weight file
weightfile = "remap_weights.nc"
remap_weights(
weightfile,
meshfile_cc,
meshfile_rll,
meshfile_overlap;
in_type = "cgll",
in_np = Quadratures.degrees_of_freedom(Spaces.quadrature_style(cspace)),
)
# apply remap
datafile_rll = "data_rll.nc"
apply_remap(datafile_rll, datafile_cc, weightfile, ["rho", "theta", "u", "v", "w"])