# ClimaCoreTempestRemap.jl

ClimaCoreTempestRemap.jl provides an interfaces for using ClimaCore data with the TempestRemap remapping package, by Paul Ullrich.

# Interface

## Online remap

`ClimaCoreTempestRemap.LinearMap`

— Type`LinearMap{S, T, W, I, V}`

stores information on the TempestRemap map and the source and target data:

where:

`source_space`

and`target_space`

are ClimaCore's 2D spaces.`weights`

is a vector of remapping weights. (length = number of overlap-mesh nodes).`source_local_idxs`

a 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_idxs`

is the same as`source_local_idxs`

but for the target mesh.`row_indices`

are the target row indices from TempestRemap. (length = number of overlap-mesh nodes)`out_type`

string that defines the output type.

`ClimaCoreTempestRemap.generate_map`

— Function`generate_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!`

— Function```
remap!(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`

— Function`remap(R::LinearMap, source::Field)`

Applies the remapping `R`

to a `source`

Field, allocating a new field in the output.

## Mesh export

`ClimaCoreTempestRemap.write_exodus`

— Function`write_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`

— Function```
def_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`

— Function`def_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`

— Method`NCDatasets.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.

This does not write any data to the variable.

`Base.setindex!`

— Method`var[:, extraidx...] = field`

Write 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]
end
```

## Wrapper functions

`ClimaCoreTempestRemap.rll_mesh`

— Function`rll_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`

— Function`overlap_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`

— Function```
remap_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)

- 'in
*np'/'out*np': 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`

— Function`apply_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"])
```