RingGrids

RingGrids is a submodule that has been developed for SpeedyWeather.jl which is technically independent (SpeedyWeather.jl however imports it and so does SpeedyTransforms) and can also be used without running simulations. It is just not put into its own respective repository.

RingGrids defines several iso-latitude grids, which are mathematically described in the section on Grids. In brief, they include the regular latitude-longitude grids (here called FullClenshawGrid) as well as grids which latitudes are shifted to the Gaussian latitudes and reduced grids, meaning that they have a decreasing number of longitudinal points towards the poles to be more equal-area than full grids.

Defined grids

RingGrids defines and exports the following grids, see also Implemented grids for a more mathematical description.

Full grids

using SpeedyWeather.RingGrids
subtypes(RingGrids.AbstractFullGrid)
4-element Vector{Any}:
 FullClenshawGrid
 FullGaussianGrid
 FullHEALPixGrid
 FullOctaHEALPixGrid

and reduced grids

subtypes(RingGrids.AbstractReducedGrid)
5-element Vector{Any}:
 HEALPixGrid
 OctaHEALPixGrid
 OctahedralClenshawGrid
 OctahedralGaussianGrid
 OctaminimalGaussianGrid

The following explanation of how to use these can be mostly applied to any of them, however, there are certain functions that are not defined, e.g. the full grids can be trivially converted to a Matrix (i.e. they are rectangular grids) but not the OctahedralGaussianGrid.

What is a ring?

We use the term ring, short for iso-latitude ring, to refer to a sequence of grid points that all share the same latitude. A latitude-longitude grid is a ring grid, as it organises its grid-points into rings. However, other grids, like the cubed-sphere are not based on iso-latitude rings. SpeedyWeather.jl only works with ring grids because its a requirement for the Spherical Harmonic Transform to be efficient. See Grids.

Grid versus Field

With "grid" we mean the discretization of space. Also called tesselation given that we are tiling a space with polygons, we subdivide the sphere into grid cells, with vertices, faces and centres. In that sense, a grid does not contain any data it purely describes the location of grid cells. Grids in RingGrids are identified by their name, e.g. FullGaussianGrid, and a resolution parameter where we use nlat_half (the number of latitudes on one hemisphere, Equator included) for all grids. This is because some grids have an even number some an odd number number of latitudes so not all nlat are valid, but all nlat_half are. While an instance of a grid stores some precomputed arrays to facilitate faster indexing it does not store coordinates and similar grid information, these can be recomputed on the fly whenever needed given a grid. All grids are considered to be two-dimensional, so they do not contain information about the vertical or time, for example. The horizontal grid points are unravelled into a vector, starting at 0˚E at the north pole, going first east, then ring by ring to the south pole.

Data on a grid is called a Field, many variables, like temperature are a field. Surface temperature would be a 2D field (though represented as a vector), temperature on several vertical layers of the atmosphere would be 3D (data represented as a matrix, horizontal x vertical), including time would make it 4D. Several fields can share the same grid. Given that the grid is always two-dimensional, a 2D and 3D field can also share the same grid, leaving the 3rd dimension not further specified for flexibility.

Creating a grid

All grids are specified by name and the resolution parameter nlat_half::Integer (number of latitude rings on one hemisphere, Equator included). An instance of a grid is simply created by

grid = FullGaussianGrid(24)
48-ring FullGaussianGrid
├ nlat_half=24 (4608 points, ~2.99˚, full)
└ architecture: SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}

As a second argument architecture can be provided which helps to share information on the computing architecture (CPU/GPU) but this will not be further explained here.

Accessing coordinates

With a grid you can get the coordinates through get_lat, get_latd, get_colat, get_lond but note that the latter is only defined for full grids as the reduced grids do not share the same longitudes across rings. To obtain the longitudes and latitudes for all grid points use get_londlatds, get_lonlats, get_loncolats, e.g.

grid = OctaminimalGaussianGrid(2)   # a tiny grid with 4 latitudes only
get_latd(grid)
4-element Vector{Float64}:
  59.44440828916677
  19.87571914744092
 -19.875719147440904
 -59.44440828916677

Creating a Field

Creating Field, that means data on a grid can be done in many ways, for example using zeros, ones,rand, orrandn`

grid = HEALPixGrid(2)               # smallest HEALPix
field = zeros(grid)                 # 2D field
field = rand(grid, 10)              # 3D field with 10 vertical layers or time steps
field = randn(Float32, grid, 2, 2)  # 4D using Float32 as element type
12×2×2, 3-ring HEALPixField{Float32, 3} on Array on SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}:
[:, :, 1] =
  0.528445    1.38823
  0.902092   -2.28841
  0.0137256  -0.169604
  0.56375     1.04275
  0.24798     0.205433
  0.367311    1.54549
 -0.277966    0.291509
 -0.077809   -0.275442
  1.1505     -0.103696
  1.708      -0.3625
 -1.44639    -0.432482
  0.802202   -1.40018

[:, :, 2] =
 -1.00012      0.419898
 -1.22261     -0.314402
 -0.174813    -0.817883
 -0.856552    -0.115961
  0.820857    -1.51992
 -0.6256      -0.0162026
  0.00974021   0.881491
 -0.39891      0.31353
  2.075        0.748379
  0.649459     0.881274
 -2.35438     -1.12761
  0.107548     0.748362

Note that in this case all fields share the same grid. Or the grid can be created on the fly when the grid type is specified, followed by nlat_half. Every ?Grid also has a corresponding ?Field type, e.g.

field = zeros(OctaminimalGaussianGrid, 2)   # nlat_half=2
field = HEALPixField(undef, 2)              # using undef initializor
field = HEALPixField{Float16}(undef, 2, 3)  # using Float16 as eltype
12×3, 3-ring HEALPixField{Float16, 2} on Array on SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}:
 0.0     0.0    0.0
 0.0     0.0    0.0
 0.0     0.0    0.0
 0.0     0.0    0.0
 6.0e-8  0.0    0.0
 0.0     0.0    0.0
 0.0     0.0    0.0
 0.0     0.0    0.0
 1.0e-7  0.0    0.0
 0.0     0.0    0.0
 0.0     0.0    0.0
 0.0     0.0  NaN

Creating a Field from data

A field has field.data (some AbstractArray{T, N}) and field.grid (some AbstractGrid as described above). The first dimension of data describes the horizontal as the grid points on every grid (full and reduced) are unravelled west to east then north to south, meaning that it starts at 90˚N and 0˚E then walks eastward for 360˚ before jumping on the next latitude ring further south, this way circling around the sphere till reaching the south pole. This may also be called ring order.

Data in a Matrix which follows this ring order can be put on a FullGaussianGrid like so

data = randn(Float32, 8, 4)
field = FullGaussianGrid(data, input_as=Matrix)
field = FullGaussianField(data, input_as=Matrix)    # equivalent
32-element, 4-ring FullGaussianField{Float32, 1} on Array on SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}:
 -0.38344693
  1.405129
 -0.19379693
 -2.852835
 -0.6202498
  2.3144612
  0.78139436
  0.7354708
 -0.6882388
  0.3935247
  ⋮
 -0.5921266
 -0.37767333
 -2.021389
  0.10450825
 -0.40006062
  0.59731764
 -1.5947759
  0.21457809
 -0.040189262

Both return a field (there is no data in the grid itself) and create an instance of FullGaussianGrid on the fly. The input_as=Matrix is required to denote that the horizontal dimension is not unravelled into a vector, triggering a reshape internally, input_as=Vector is the default. A full Gaussian grid has always $2N$ x $N$ grid points, but a FullClenshawGrid has $2N$ x $N-1$, if those dimensions don't match, the creation will throw an error.

If you have the data and know which grid it comes one you can also create a Field by providing both

data = randn(Float32, 8, 4)         # data of some shape
grid = OctaminimalGaussianGrid(1)   # you need to know the nlat_half (here 1) of that grid!
field = Field(data, grid)
8×4, 2-ring OctaminimalGaussianField{Float32, 2} on Array on SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}:
 -0.266735  -1.75085   -2.41422   -0.822543
 -1.95032   -1.59219    0.254568  -1.90568
  0.121229  -0.76742   -0.022275   1.12088
 -0.544872  -1.00373    1.66832   -0.723818
 -0.719442   1.24238   -0.485193   0.724279
 -0.394944   1.08514    0.102127   0.0360136
 -0.850132   0.338575   0.884069  -0.659707
  0.903572   0.715901   0.465761   1.55655

But you can also automatically let nlat_half be calculated from the shape of the data. Note that you have to provide the name of the field though, FullGaussianField here to create a Field on a FullGaussianGrid.

field = FullGaussianField(data, input_as=Matrix)
32-element, 4-ring FullGaussianField{Float32, 1} on Array on SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}:
 -0.2667355
 -1.950322
  0.12122941
 -0.5448722
 -0.71944165
 -0.3949442
 -0.8501315
  0.9035725
 -1.7508496
 -1.5921855
  ⋮
  0.4657607
 -0.82254314
 -1.9056796
  1.1208777
 -0.72381777
  0.7242793
  0.036013626
 -0.65970683
  1.5565485

To return to the original data array you can reshape the data of a full grid (which is representable as a matrix) as follows

data == Matrix(FullGaussianField(data, input_as=Matrix))
true

which in general is Array(field, as=Vector) for no reshaping (equivalent to field.data including possible conversion to Array) and Array(field, as=Matrix) with reshaping (full grids only).

Visualising Fields

As only the full fields can be reshaped into a matrix, the underlying data structure of any AbstractField is a vector for consistency. As shown in the examples above, one can therefore inspect the data as if it was a vector. But a field has through field.grid all the geometric information available to plot it on a map, SpeedyWeather also implements extensions for Makie's and UnicodePlots's' heatmap, also see Visualisation via Makie and Visualisation via UnicodePlots.

using CairoMakie    # triggers loading of Makie extension, or do using UnicodePlots instead!
grid = OctahedralGaussianGrid(24)
field = randn(grid)
heatmap(field)
Example block output

Reduced fields are automatically interpolated to the corresponding full fields so that they can be visualised as a matrix.

Indexing Fields

All fields have a single index ij which follows the ring order. While this is obviously not super exciting here are some examples how to make better use of the information that the data sits on a two-dimensional grid covering the sphere. We obtain the latitudes of the rings of a grid by calling get_latd (get_lond is only defined for full grids, or use get_londlatds for latitudes, longitudes per grid point not per ring). Now we could calculate Coriolis and add it on the grid as follows

grid = OctahedralClenshawGrid(5)    # define a grid
field = randn(grid)                 # random data on that grid
latd = get_latd(grid)               # get a vector of latitudes [˚N] per ring, north to south

rotation = 7.29e-5                  # angular frequency of Earth's rotation [rad/s]
coriolis = 2rotation*sind.(latd)    # vector of coriolis parameters per latitude ring

for (j, ring) in enumerate(eachring(field))     # loop over every ring j
    f = coriolis[j]
    for ij in ring                              # loop over every longitude point on that ring
        field[ij] += f
    end
end

eachring(field) accesses field.grid.rings a precomputed vector of UnitRange indices, such that we can loop over the ring index j (j=1 being closest to the North pole) pull the coriolis parameter at that latitude and then loop over all in-ring indices i (changing longitudes) to do something on the grid. Something similar can be done to scale/unscale with the cosine of latitude for example.

We can always loop over all horizontal grid points with eachgridpoint and over every other dimensions with eachlayer, e.g. for 2D fields you can do

for ij in eachgridpoint(grid)
    field[ij]
end

or use eachindex instead. For 3D fields eachindex loops over all elements, including the 3rd dimension but eachgridpoint would only loop over the horizontal. To loop with an index k over all additional dimensions (vertical, time, ...) do

field = zeros(grid, 2, 3)           # 4D, 2D defined by grid x 2 x 3
for k in eachlayer(field)           # loop over 2 x 3
    for ij in eachgridpoint(field)  # loop over 2D grid points
        field[ij, k]
    end
end

Interpolation between grids

In most cases we will want to use RingGrids so that our data directly comes with the geometric information of where the grid-point is one the sphere. We have seen how to use get_latd, get_lond, ... for that above. This information generally can also be used to interpolate our data from one grid to another or to request an interpolated value on some coordinates. Using a OctahedralGaussianField (data on an OctahedralGaussianGrid) from above we can use the interpolate function to get it onto a FullGaussianGrid (or any other grid for purpose)

grid = OctahedralGaussianGrid(4)
field = randn(Float32, grid)
interpolate(FullGaussianGrid, field)

By default this will linearly interpolate (it's an Anvil interpolator, see below) onto a grid with the same nlat_half, but we can also coarse-grain or fine-grain by specifying any other grid as an instance not a type (or provide nlat_half as the second argument), e.g.

output_grid = HEALPixGrid(6)
interpolate(output_grid, field)
interpolate(HEALPixGrid, 6, field)  # equivalent

To change the number format during interpolation you can preallocate the output field

output_field = Field(Float16, output_grid)
interpolate!(output_field, field)

Which will convert from Float64 to Float16 on the fly too. Note that we use interpolate! here not interpolate without ! as the former writes into output_field and therefore changes it in place.

Interpolation on coordinates

One can also interpolate a 2D field onto a given coordinate ˚N, ˚E like so

interpolate(30.0, 10.0, field)
0.5234863f0

we interpolated the data from field onto 30˚N, 10˚E. To do this simultaneously for many coordinates they can be packed into a vector too

interpolate([30.0, 40.0, 50.0], [10.0, 10.0, 10.0], field)
3-element Vector{Float32}:
 0.5234863
 1.138837
 0.7421146

which returns the data on field at 30˚N, 40˚N, 50˚N, and 10˚E respectively. Note how the interpolation here retains the element type of field.

Performance for RingGrid interpolation

Every time an interpolation like interpolate(30.0, 10.0, field) is called, several things happen, which are important to understand to know how to get the fastest interpolation out of this module in a given situation. Under the hood an interpolation takes three arguments

  • output array
  • input field
  • interpolator

The output array is just an array into which the interpolated data is written, providing this prevents unnecessary allocation of memory in case the destination array of the interpolation already exists. Such a destination can be a field but it does not have to be (see Interpolation on coordinates). The input field contains the data which is subject to interpolation, it must come on a ring grid, however, its coordinate information is actually already in the interpolator. The interpolator knows about the geometry of the grid of the field and the coordinates it is supposed to interpolate onto. It has therefore precalculated the indices that are needed to access the right data on the input field and the weights it needs to apply in the actual interpolation operation. The only thing it does not know is the actual data values of that field. So in the case you want to interpolate from field A to field B many times, you can just reuse the same interpolator. If you want to change the coordinates of the output but its total number of points remain constant then you can update the locator inside the interpolator and only else you will need to create a new interpolator. Let's look at this in practice. Say we have two grids and want to interpolate between them

grid_in = HEALPixGrid(4)
grid_out = FullClenshawGrid(6)
interp = RingGrids.interpolator(grid_out, grid_in)
AnvilInterpolator{Float64} for 7-ring HEALPixGrid
├ nlat_half=4 (48 points, ~29.3˚, reduced)
└ architecture: SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}
└ onto: 264 points

Now we have created an interpolator interp which knows about the geometry where to interpolate from and the coordinates there to interpolate to. It is also initialized, meaning it has precomputed the indices to of grid_in that are supposed to be used. It just does not know about the data (it has only seen grids, no fields). We can now do

field_in = rand(grid_in)
field_out = zeros(grid_out)
interpolate!(field_out, field_in, interp)

which is identical to interpolate(field_out, field_in) but you can reuse interp for other data. The interpolation can also handle various element types (the interpolator interp does not have to be updated for this either)

field_out = zeros(Float16, grid_out)
interpolate!(field_out, field_in, interp)

and we have converted data from a HEALPixField{Float64} (Float64 is always default if not specified) to a FullClenshawField{Float16} including the type conversion Float64-Float16 on the fly. Technically there are three data types and their combinations possible: The input data will come with a type, the output array has an element type and the interpolator has precomputed weights with a given type. Say we want to go from Float16 data on an OctahedralGaussianGrid to Float16 on a FullClenshawGrid but using Float32 precision for the interpolation itself, we would do this by

field_in = randn(OctahedralGaussianField{Float16}, 24)
field_out = zeros(FullClenshawField{Float16}, 24)
interp = RingGrids.interpolator(field_out, field_in, NF=Float32)
interpolate!(field_out, field_in, interp)

As a last example we want to illustrate a situation where we would always want to interpolate onto 10 coordinates, but their locations may change. In order to avoid recreating an interpolator object we would do (AnvilInterpolator is described in Anvil interpolator)

npoints = 10    # number of coordinates to interpolate onto
grid = HEALPixGrid(24)
interp = AnvilInterpolator(grid, npoints, NF=Float32)
AnvilInterpolator{Float32} for 47-ring HEALPixGrid
├ nlat_half=24 (1728 points, ~4.9˚, reduced)
└ architecture: SpeedyWeather.Architectures.CPU{KernelAbstractions.CPU}
└ onto: 10 points

with the first argument being the input grid and then the number of points to interpolate onto. The number format used for the interpolator is provided as NF. However, interp is not yet initialized as it does not know about the destination coordinates yet. Let's define them, but note that we already decided there's only 10 of them above.

londs = collect(-10.0:2.0:8.0)
latds = collect(0.0:5.0:45.0)

now we can update the locator inside our interpolator as follows

RingGrids.update_locator!(interp, londs, latds)

With data matching the input from above, a nlat_half=24 HEALPixGrid, and allocate 10-element output vector

output_vec = zeros(10)
field_in = rand(grid)

we can use the interpolator as follows

interpolate!(output_vec, field_in, interp)
10-element Vector{Float64}:
 0.8710519066147959
 0.6353694186748435
 0.3722537000105374
 0.43345751424978096
 0.642058202617076
 0.5827298430253576
 0.1566683023170532
 0.8107771689645376
 0.3853662807031979
 0.2521237526289433

which is the approximately the same as doing it directly without creating an interpolator first and updating its locator

interpolate(londs, latds, field_in)
10-element Vector{Float64}:
 0.871051906137655
 0.6353694179872488
 0.3722537004868922
 0.43345751086984674
 0.6420582042880308
 0.5827298440655148
 0.15666830034609613
 0.8107771658471706
 0.3853662801269159
 0.25212375182368274

but allows for a reuse of the interpolator. Note that the two output arrays are not exactly identical because we manually set our interpolator interp to use Float32 for the interpolation whereas the default is Float64.

Anvil interpolator

Currently the only interpolator implemented is a 4-point bilinear interpolator, which schematically works as follows. Anvil interpolation is the bilinear average of a, b, c, d which are values at grid points in an anvil-shaped configuration at location x, which is denoted by Δab, Δcd, Δy, the fraction of distances between a-b, c-d, and ab-cd, respectively. Note that a, c and b, d do not necessarily share the same longitude/x-coordinate.

        0..............1    # fraction of distance Δab between a, b
        |<  Δab   >|

0^      a -------- o - b    # anvil-shaped average of a, b, c, d at location x
.Δy                |
.                  |
.v                 x 
.                  |
1         c ------ o ---- d

          |<  Δcd >|
          0...............1 # fraction of distance Δcd between c, d

^ fraction of distance Δy between a-b and c-d.

This interpolation is chosen as by definition of the ring grids, a and b share the same latitude, so do c and d, but the longitudes can be different for all four, a, b, c, d.

Function index

Core.TypeMethod

Create a new grid of type Grid with resolution parameter nlat_half. architecture is the device type (CPU/GPU). Precomputes the ring indices rings.

source
Core.TypeMethod

Zero generator function for the 4-point average AnvilLocator. Use update_locator! to update the grid indices used for interpolation and their weights. The number format NF is the format used for the calculations within the interpolation, the input data and/or output data formats may differ.

source
SpeedyWeather.RingGrids.AbstractFieldType

Abstract supertype for all fields, i.e. data on a grid. A field is an AbstractArray with a number format T, a number of dimensions N, an ArrayType (e.g. Vector, Matrix, Tensor) and a grid type Grid. Fields can be full or reduced, 2D, 3D, or 4D, depending on the grid and the number of dimensions. Fields are used to store data on the grid, e.g. temperature, pressure, or any other variable. Every Field has data the grid-free array of the data and grid which contains information about the grid the field is defined on.

source
SpeedyWeather.RingGrids.AbstractField2DType

Abstract supertype for all 2D fields, i.e. fields with the horizontal dimensions only. Note that this is a <:AbstractVector as the horizontal dimensions are unravelled into a vector for all grids to be conistent with the reduced grids that cannot be represented as a matrix.

source
SpeedyWeather.RingGrids.AbstractFullGridType

Abstract supertype for all full grids, representing a horizontal grid with a constant number of longitude points across latitude rings. Different latitudes can be used, Gaussian latitudes, equi-angle latitudes (also called Clenshaw from Clenshaw-Curtis quadrature), or others.

source
SpeedyWeather.RingGrids.AbstractGridType

Abstract supertype for all grids in RingGrids.jl, representing a discretization (particularly a tessellation or tiling) of the sphere. A "grid" does not contain any data only its resolution is defined by nlat_half (number of latitude rings on one hemisphere including the equator). A grid does not contain the coordinates of the grid points, vertices, latitudes, longtiudes etc but they can be recomputed from the grid object (or its type and resolution) at any time.

A grid is regarded as 2D but a field (data on a grid) can have N additional dimensions, e.g. for vertical levels or time. In that sense, a grid does not have a number format / eltype. This is a property of a Field which can be different for every field even when using the same grid. Points on the grid (cell centres) are unravalled into a vector ordered 0 to 360˚E, starting at the north pole, then going ring by ring to the south pole. This way both full (those representable as a matrix) and reduced grids (not representable as a matrix, with fewer longitude points towards the poles) can be represented.

A grid has a parameter Architecture (the type of the field architecture) that can be used to store information about the architecture the grid is on, e.g. CPU or GPU.

Furthermore all grids have a rings to allow ring-by-ring indexing. Other precomputed indices can be added for specific grids.

source
SpeedyWeather.RingGrids.AbstractInterpolatorType
abstract type AbstractInterpolator end

Supertype for Interpolators. Every Interpolator <: AbstractInterpolator is expected to have two fields,

  • geometry, which describes the grid G to interpolate from
  • locator, which locates the indices on G and their weights to interpolate onto a new grid.

NF is the number format used to calculate the interpolation, which can be different from the input data and/or the interpolated data on the new grid.

source
SpeedyWeather.RingGrids.AbstractLocatorType

Supertype of every Locator, which locates the indices on a grid to be used to perform an interpolation. E.g. AnvilLocator uses a 4-point stencil for every new coordinate to interpolate onto. Higher order stencils can be implemented by defining OtherLocator <: AbstractLocactor.

source
SpeedyWeather.RingGrids.AbstractReducedGridType

Abstract supertype for all reduced grids, representing arrays of ring grids that have a reduced number of longitude points towards the poles, i.e. they are not "full", see AbstractFullGrid. Data on these grids (a Field) cannot be represented as matrix and has to be unravelled into a vector, ordered 0 to 360˚E then north to south, ring by ring. Examples for reduced grids are the octahedral Gaussian or Clenshaw grids, or the HEALPix grid.

source
SpeedyWeather.RingGrids.AbstractSphericalDistanceType
abstract type AbstractSphericalDistance end

Super type of formulas to calculate the spherical distance or great-circle distance. To define a NewFormula, define struct NewFormula <: AbstractSphericalDistance end and the actual calculation as a functor

function NewFormula(lonlat1::Tuple, lonlat2::Tuple; radius=DEFAULT_RADIUS, kwargs...)

assuming inputs in degrees and returning the distance in meters (or radians for radius=1). Then use the general interface spherical_distance(NewFormula, args...; kwargs...)

source
SpeedyWeather.RingGrids.AnvilLocatorType

Contains arrays that locates grid points of a given field to be uses in an interpolation and their weights. This Locator is a 4-point average in an anvil-shaped grid-point arrangement between two latitude rings.

source
SpeedyWeather.RingGrids.FieldType

Field contains data on a grid. There is only one Field type which can be used for all grids. data is the data array, the first dimension is always the horizontal dimension (unravelled into a vector for compatibility across full and reduced grids), the other dimensions can be used for the vertical and/or time or other dimensions. The grid can be shared across multiple fields, e.g. a 2D and a 3D field can share the same grid which just defines the discretization and the architecture (CPU/GPU) the grid is on.

  • data::AbstractArray

  • grid::AbstractGrid

source
SpeedyWeather.RingGrids.FullClenshawGridType

A FullClenshawGrid is a discretization of the sphere, a full grid, subtyping AbstractFullGrid, using equidistant latitudes for each ring (a regular lon-lat grid). These require the Clenshaw-Curtis quadrature in the spectral transform, hence the name. One ring is on the equator, total number of rings is odd, no rings on the north or south pole.

The first dimension of data on this grid (a Field) represents the horizontal dimension, in ring order (0 to 360˚E, then north to south), other dimensions can be used for the vertical and/or time or other dimensions. Note that a Grid does not contain any data, it only describes the discretization of the space, see Field for a data on a Grid. But a "grid" only defines the two horizontal dimensions, two fields, one 2D and one 3D, possibly different ArrayTypes or element types, can share the same grid which just defines the discretization and the architecture (CPU/GPU) the grid is on.

The resolution parameter of the horizontal grid is nlat_half (number of latitude rings on one hemisphere, Equator included) and the ring indices are precomputed in rings.

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.FullGaussianGridType

A FullGaussianGrid is a discretization of the sphere that uses Gaussian latitudes for each latitude ring. As a "full" grid it has the same number of longitude points on every latitude ring, i.e. it is representable as a matrix, with denser grid points towards the poles. The Gaussian latitudes enable to use the Gaussian quadrature for the spectral transform, hence the name. No ring is on the equator, total number of rings is even and symmetric around the Equator, no rings on the north or south pole.

The first dimension of data on this grid (a Field) represents the horizontal dimension, in ring order (0 to 360˚E, then north to south), other dimensions can be used for the vertical and/or time or other dimensions. Note that a Grid does not contain any data, it only describes the discretization of the space, see Field for a data on a Grid. But a "grid" only defines the two horizontal dimensions, two fields, one 2D and one 3D, possibly different ArrayTypes or element types, can share the same grid which just defines the discretization and the architecture (CPU/GPU) the grid is on.

The resolution parameter of the horizontal grid is nlat_half (number of latitude rings on one hemisphere, Equator included) and the ring indices are precomputed in rings.

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.FullHEALPixGridType

A FullHEALPixGrid is like a HEALPixGrid but with every latitude ring having the same number of longitude points (a full grid). This grid is mostly defined for output to minimize the interpolation needed from a HEALPixGrid to a full grid. A FullHEALPixGrid has none of the equal-area properties of the HEALPixGrid. It only shares the latitudes with the HEALPixGrid but uses the longitudes from the FullGaussianGrid without offset, i.e. the first longitude point on every ring is at 0˚E.

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.FullOctaHEALPixGridType

A FullOctaHEALPixGrid is like a OctaHEALPixGrid but with every latitude ring having the same number of longitude points (a full grid). This grid is mostly defined for output to minimize the interpolation needed from an OctaHEALPixGrid to a full grid required for output. A FullOctaHEALPixGrid has none of the equal-area properties of the OctaHEALPixGrid. It only shares the latitudes with the OctaHEALPixGrid but uses the longitudes from the FullGaussianGrid without offset, i.e. the first longitude point on every ring is at 0˚E.

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.GridGeometryMethod
GridGeometry(
    grid::AbstractGrid;
    NF,
    ArrayType
) -> SpeedyWeather.RingGrids.GridGeometry{<:AbstractGrid{Architecture}, Vector{Float64}, Vector{Int64}} where Architecture

Precomputed arrays describing the geometry of the Grid with resolution nlat_half. Contains longitudes, latitudes of grid points, their ring index j and their unravelled indices ij.

source
SpeedyWeather.RingGrids.HEALPixGridType

A HEALPixGrid is a equal-area discretization of the sphere. A HEALPix grid has 12 faces, each nsidexnside grid points, each covering the same area of the sphere. They start with 4 longitude points on the northern-most ring, increase by 4 points per ring in the "polar cap" (the top half of the 4 northern-most faces) but have a constant number of longitude points in the equatorial belt. The southern hemisphere is symmetric to the northern, mirrored around the Equator. HEALPix grids have a ring on the Equator. For more details see Górski et al. 2005, DOI:10.1086/427976.

rings are the precomputed ring indices, for nlat_half = 4 it is rings = [1:4, 5:12, 13:20, 21:28, 29:36, 37:44, 45:48]. So the first ring has indices 1:4 in the unravelled first dimension, etc. For efficient looping see eachring and eachgrid. whichring is a precomputed vector of ring indices for each grid point ij, i.e. whichring[ij] gives the ring index j of grid point ij. Fields are

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.HaversineMethod
Haversine(lonlat1::Tuple, lonlat2::Tuple; radius) -> Any

Haversine formula calculating the great-circle or spherical distance (in meters) on the sphere between two tuples of longitude-latitude points in degrees ˚E, ˚N. Use keyword argument radius to change the radius of the sphere (default 6371e3 meters, Earth's radius), use radius=1 to return the central angle in radians or radius=360/2π to return degrees.

source
SpeedyWeather.RingGrids.OctaHEALPixGridType

An OctaHEALPixGrid is an equal-area discretization of the sphere. It has 4 faces, each nlat_half x nlat_half in size, covering 90˚ in longitude, pole to pole. As part of the HEALPix family of grids, the grid points are equal area. They start with 4 longitude points on the northern-most ring, increase by 4 points per ring towards the Equator with one ring on the Equator before reducing the number of points again towards the south pole by 4 per ring. There is no equatorial belt for OctaHEALPix grids. The southern hemisphere is symmetric to the northern, mirrored around the Equator. OctaHEALPix grids have a ring on the Equator. For more details see Górski et al. 2005, DOI:10.1086/427976, the OctaHEALPix grid belongs to the family of HEALPix grids with Nθ = 1, Nφ = 4 but is not explicitly mentioned therein.

rings are the precomputed ring indices, for nlat_half = 3 (in contrast to HEALPix this can be odd) it is rings = [1:4, 5:12, 13:24, 25:32, 33:36]. For efficient looping see eachring and eachgrid. whichring is a precomputed vector of ring indices for each grid point ij, i.e. whichring[ij] gives the ring index j of grid point ij. Fields are

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.OctahedralClenshawGridType

An OctahedralClenshawGrid is a discretization of the sphere that uses equidistant latitudes for each latitude ring. The spherical harmonic transform on this grid uses the Clenshaw-Curtis quadrature, hence the name. As a reduced grid it has a different number of longitude points on every latitude ring. These grids are called octahedral because after starting with 20 points on the first ring around the north pole they increase the number of longitude points for each ring by 4, such that they can be conceptually thought of as lying on the 4 faces of an octahedron on each hemisphere. Hence, these grids have 20, 24, 28, ... longitude points for ring 1, 2, 3, ... There is a ring on the Equator with 16 + 4nlat_half longitude points before reducing the number of longitude points per ring by 4 towards the southern-most ring j = nlat. The first point on every ring is at longitude 0˚E, i.e. no offset is applied to the longitude values (in contrast to HEALPix grids).

The first dimension of data on this grid (a Field) represents the horizontal dimension, in ring order (0 to 360˚E, then north to south), other dimensions can be used for the vertical and/or time or other dimensions. Note that a Grid does not contain any data, it only describes the discretization of the space, see Field for a data on a Grid. But a "grid" only defines the two horizontal dimensions, two fields, one 2D and one 3D, possibly different ArrayTypes or element types, can share the same grid which just defines the discretization and the architecture (CPU/GPU) the grid is on.

The resolution parameter of the horizontal grid is nlat_half (number of latitude rings on one hemisphere, Equator included) rings are the precomputed ring indices, the the example above rings = [1:20, 21:44, 45:72, ...]. whichring is a precomputed vector of ring indices for each grid point ij, i.e. whichring[ij] gives the ring index j of grid point ij. For efficient looping see eachring and eachgrid. Fields are

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.OctahedralGaussianGridType

An OctahedralGaussianGrid is a discretization of the sphere that uses Gaussian latitudes for each latitude ring. As a reduced grid it has a different number of longitude points on every latitude ring. These grids are called octahedral because after starting with 20 points on the first ring around the north pole they increase the number of longitude points for each ring by 4, such that they can be conceptually thought of as lying on the 4 faces of an octahedron on each hemisphere. Hence, these grids have 20, 24, 28, ... longitude points for ring 1, 2, 3, ... There is no ring on the Equator and the two rings around it have 16 + 4nlat_half longitude points before reducing the number of longitude points per ring by 4 towards the southern-most ring j = nlat. The first point on every ring is at longitude 0˚E, i.e. no offset is applied to the longitude values (in contrast to HEALPix grids).

The first dimension of data on this grid (a Field) represents the horizontal dimension, in ring order (0 to 360˚E, then north to south), other dimensions can be used for the vertical and/or time or other dimensions. Note that a Grid does not contain any data, it only describes the discretization of the space, see Field for a data on a Grid. But a "grid" only defines the two horizontal dimensions, two fields, one 2D and one 3D, possibly different ArrayTypes or element types, can share the same grid which just defines the discretization and the architecture (CPU/GPU) the grid is on.

The resolution parameter of the horizontal grid is nlat_half (number of latitude rings on one hemisphere, Equator included) rings are the precomputed ring indices, the the example above rings = [1:20, 21:44, 45:72, ...]. whichring is a precomputed vector of ring indices for each grid point ij, i.e. whichring[ij] gives the ring index j of grid point ij. For efficient looping see eachring and eachgrid. Fields are

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.OctaminimalGaussianGridType

An OctaminimalGaussianGrid is a discretization of the sphere that uses Gaussian latitudes for each latitude ring. It is very similar to the OctahedralGaussianGrid, with a few differences:

  1. It starts with 4 longitude points around the poles, so 4, 8, 12, 16, ... on ring 1, 2, 3, 4, ... reducing the number

of total number of grid points over the OctahedralGaussianGrid, hence the name "octaminimal" (octahedral minimal).

  1. The first longitude points on every ring have an offset, such that the cell face between the first and last longitude point on every ring is at 0˚E (like the HEALPix grid)

Fields are

  • nlat_half::Int64

  • architecture::Any

  • rings::Any

  • whichring::Any

source
SpeedyWeather.RingGrids.anvil_averageMethod
anvil_average(a, b, c, d, Δab, Δcd, Δy) -> Any

The bilinear average of a, b, c, d which are values at grid points in an anvil-shaped configuration at location x, which is denoted by Δab, Δcd, Δy, the fraction of distances between a-b, c-d, and ab-cd, respectively. Note that a, c and b, d do not necessarily share the same longitude/x-coordinate. See schematic:

            0..............1    # fraction of distance Δab between a, b
            |<  Δab   >|

    0^      a -------- o - b    # anvil-shaped average of a, b, c, d at location x
    .Δy                |
    .                  |
    .v                 x 
    .                  |
    1         c ------ o ---- d

              |<  Δcd >|
              0...............1 # fraction of distance Δcd between c, d

^ fraction of distance Δy between a-b and c-d.

source
SpeedyWeather.RingGrids.average_on_polesMethod
average_on_poles(
    A::AbstractArray{NF<:AbstractFloat, 1},
    rings
) -> Tuple{Any, Any}

Computes the average at the North and South pole from a given grid A and it's precomputed ring indices rings. The North pole average is an equally weighted average of all grid points on the northern-most ring. Similar for the South pole.

source
SpeedyWeather.RingGrids.average_on_polesMethod
average_on_poles(
    A::AbstractArray{NF<:Integer, 1},
    rings
) -> Tuple{Any, Any}

Method for A::Abstract{T<:Integer} which rounds the averaged values to return the same number format NF.

source
SpeedyWeather.RingGrids.clenshaw_curtis_weightsMethod
clenshaw_curtis_weights(nlat_half::Integer) -> Any

The Clenshaw-Curtis weights for a Clenshaw grid (full or octahedral) of size nlathalf. Clenshaw-Curtis weights are of length nlat, i.e. a vector for every latitude ring, pole to pole. `sum(clenshawcurtisweights(nlathalf))is always2` as int0^π sin(x) dx = 2 (colatitudes), or equivalently int-pi/2^pi/2 cos(x) dx (latitudes).

Integration (and therefore the spectral transform) is exact (only rounding errors) when using Clenshaw grids provided that nlat >= 2(T + 1), meaning that a grid resolution of at least 128x64 (nlon x nlat) is sufficient for an exact transform with a T=31 spectral truncation.

source
SpeedyWeather.RingGrids.each_index_in_ring!Method
each_index_in_ring!(
    rings,
    Grid::Type{<:OctahedralGaussianGrid},
    nlat_half::Integer
)

precompute a Vector{UnitRange{Int}} to index grid points on every ringj(elements of the vector) ofGridat resolutionnlat_half. Seeeachringandeachgrid` for efficient looping over grid points.

source
SpeedyWeather.RingGrids.each_index_in_ring!Method
each_index_in_ring!(
    rings,
    Grid::Type{<:OctaminimalGaussianGrid},
    nlat_half::Integer
)

precompute a Vector{UnitRange{Int}} to index grid points on every ringj(elements of the vector) ofGridat resolutionnlat_half. Seeeachringandeachgrid` for efficient looping over grid points.

source
SpeedyWeather.RingGrids.each_index_in_ringMethod
each_index_in_ring(
    Grid::Type{<:AbstractFullGrid},
    j::Integer,
    nlat_half::Integer
) -> Any

UnitRange for every grid point of full grid Grid of resolution nlat_half on ring j (j=1 is closest ring around north pole, j=nlat around south pole).

source
SpeedyWeather.RingGrids.eachgridpointMethod
eachgridpoint(
    field1::AbstractField,
    fields::AbstractField...;
    horizontal_only,
    kwargs...
) -> Base.OneTo

Iterator over all 2D grid points of a field (or fields), i.e. the horizontal dimension only. Intended use is like

for ij in eachgridpoint(field)
    field[ij]

for a 2D field. For a 3D+ field, the iterator will only index and loop over the horizontal grid points. If horizontal_only is set to true (default), the function will only check whether the horizontal dimensions match.

source
SpeedyWeather.RingGrids.eachgridpointMethod
eachgridpoint(grid::AbstractGrid) -> Base.OneTo

UnitRange to access each horizontal grid point on grid grid. For a NxM (N horizontal grid points, M vertical layers) OneTo(N) is returned.

source
SpeedyWeather.RingGrids.eachlayerMethod
eachlayer(
    field1::AbstractField,
    fields::AbstractField...;
    vertical_only,
    kwargs...
) -> Any

CartesianIndices for the 2nd to last dimension of a field (or fields), e.g. the vertical layer (and possibly a time dimension, etc). E.g. for a Nx2x3 field, with N horizontal grid points k iterates over (1, 1) to (2, 3), meaning both the 2nd and 3rd dimension. To be used like

for k in eachlayer(field)
    for (j, ring) in enumerate(eachring(field))
        for ij in ring
            field[ij, k]

With vertical_only=true (default) only checks whether the non-horizontal dimensions of the fields match. E.g. one can loop over two fields of each n layers on different grids.

source
SpeedyWeather.RingGrids.eachringMethod
eachring(
    field1::AbstractField,
    fields::AbstractField...;
    horizontal_only,
    kwargs...
) -> Any

Return an iterator over the rings of a field. These are precomputed ranges like [1:20, 21:44, ...] stored in field.grid.rings. Every element are the unravellend indices ij of all 2D grid points that lie on that ring. Intended use is like

for (j, ring) in enumerate(eachring(field))
    for ij in ring
        field[ij, k]

with j being the ring index. j=1 around the north pole, j=nlathalf around the Equator or just north of it (for even nlathalf). Several fields can be passed on to check for matching grids, e.g. for a 2D and a 3D field. If horizontal_only is set to true, the function will only check the horizontal dimension.

source
SpeedyWeather.RingGrids.eachringMethod
eachring(grid1::AbstractGrid, grids::AbstractGrid...) -> Any

Same as eachring(grid) but performs a bounds check to assess that all grids according to grids_match (non-parametric grid type, nlat_half and length).

source
SpeedyWeather.RingGrids.eachringMethod
eachring(grid::AbstractGrid) -> Any

Vector{UnitRange} rings to loop over every ring of grid and then each grid point per ring. To be used like

rings = eachring(grid)
for ring in rings
    for ij in ring
        field[ij]

Accesses precomputed grid.rings.

source
SpeedyWeather.RingGrids.eachringMethod
eachring(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer
) -> Any

Computes the ring indices i0:i1 for start and end of every longitudinal point on a given ring j of Grid at resolution nlat_half. Used to loop over rings of a grid. These indices are also precomputed in every grid.rings.

source
SpeedyWeather.RingGrids.equal_area_weightsMethod
equal_area_weights(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer
) -> Any

The equal-area weights used for the HEALPix grids (original or OctaHEALPix) of size nlathalf. The weights are of length nlat, i.e. a vector for every latitude ring, pole to pole. `sum(equalareaweights(nlathalf))is always2` as int0^π sin(x) dx = 2 (colatitudes), or equivalently int-pi/2^pi/2 cos(x) dx (latitudes). Integration (and therefore the spectral transform) is not exact with these grids but errors reduce for higher resolution.

source
SpeedyWeather.RingGrids.fields_matchMethod
fields_match(
    A::AbstractField,
    B::AbstractField;
    horizontal_only,
    vertical_only
) -> Any

True if both A and B are of the same nonparametric grid type (e.g. OctahedralGaussianArray, regardless type parameter T or underyling array type ArrayType) and of same resolution (nlat_half) and total grid points (length). Sizes of (4,) and (4,1) would match for example, but (8,1) and (4,2) would not (nlat_half not identical).

source
SpeedyWeather.RingGrids.gaussian_weightsMethod
gaussian_weights(nlat_half::Integer) -> Any

The Gaussian weights for a Gaussian grid (full or octahedral) of size nlathalf. Gaussian weights are of length nlat, i.e. a vector for every latitude ring, pole to pole. `sum(gaussianweights(nlathalf))is always2` as int0^π sin(x) dx = 2 (colatitudes), or equivalently int_-pi/2^pi/2 cos(x) dx (latitudes).

Integration (and therefore the spectral transform) is exact (only rounding errors) when using Gaussian grids provided that nlat >= 3(T + 1)/2, meaning that a grid resolution of at least 96x48 (nlon x nlat) is sufficient for an exact transform with a T=31 spectral truncation.

source
SpeedyWeather.RingGrids.get_gridcell_polygonsMethod
get_gridcell_polygons(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer;
    add_nan
) -> Matrix{Tuple{Float64, Float64}}

Return a 5xN matrix polygons (or grid cells) of NTuple{2, Float64} where the first 4 rows are the vertices (E, S, W, N) of every grid points ij in 1:N, row 5 is duplicated north vertex to close the grid cell. Use keyword arguemnt add_nan=true (default false) to add a 6th row with (NaN, NaN) to separate grid cells when drawing them as a continuous line with vec(polygons).

source
SpeedyWeather.RingGrids.get_latdMethod
get_latd(_::Type{<:HEALPixGrid}, nlat_half::Integer) -> Any

Latitudes [90˚N to -90˚N] for the HEALPixGrid with resolution parameter nlat_half.

source
SpeedyWeather.RingGrids.get_loncolatsMethod
get_loncolats(grid::AbstractGrid) -> Tuple{Any, Any}

Longitudes (radians, 0-2π), colatitudes (degrees, 0 to π) for every (horizontal) grid point in grid in ring order (0-360˚E then north to south).

source
SpeedyWeather.RingGrids.get_lond_per_ringMethod
get_lond_per_ring(
    Grid::Type{<:HEALPixGrid},
    nlat_half::Integer,
    j::Integer
) -> Any

Longitudes [0˚E to 360˚E] for the HEALPixGrid with resolution parameter nlat_half on ring j (north to south).

source
SpeedyWeather.RingGrids.get_londlatdsMethod
get_londlatds(grid::AbstractGrid) -> Tuple{Any, Any}

Longitudes (degrees, 0-360˚E), latitudes (degrees, 90˚N to -90˚N) for every (horizontal) grid point in grid in ring order (0-360˚E then north to south).

source
SpeedyWeather.RingGrids.get_londlatdsMethod
get_londlatds(
    Grid::Type{<:AbstractReducedGrid},
    nlat_half::Integer
) -> Tuple{Any, Any}

Return vectors of londs, latds, of longitudes (degrees, 0-360˚E) and latitudes (degrees, -90˚ to 90˚N) for reduced grids for all grid points in order of the running index ij.

source
SpeedyWeather.RingGrids.get_lonlatsMethod
get_lonlats(grid::AbstractGrid) -> Tuple{Any, Any}

Longitudes (radians, 0-2π), latitudes (degrees, π/2 to -π/2) for every (horizontal) grid point in grid in ring order (0-360˚E then north to south).

source
SpeedyWeather.RingGrids.get_nlonsMethod
get_nlons(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer;
    both_hemispheres
) -> Any

Returns a vector nlons for the number of longitude points per latitude ring, north to south. Provide grid Grid and its resolution parameter nlat_half. For keyword argument both_hemispheres=false only the northern hemisphere (incl Equator) is returned.

source
SpeedyWeather.RingGrids.get_npointsMethod
get_npoints(grid::AbstractGrid, args...) -> Any

Total number of grid points in all dimensions of grid. Equivalent to length of the underlying data array.

source
SpeedyWeather.RingGrids.get_verticesMethod
get_vertices(
    Grid::Type{<:AbstractFullGrid},
    nlat_half::Integer
) -> NTuple{4, Any}

Vertices for full grids, other definition than for reduced grids to prevent a diamond shape of the cells. Use default rectangular instead. Effectively rotating the vertices clockwise by 45˚, making east south-east etc.

source
SpeedyWeather.RingGrids.get_verticesMethod
get_vertices(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer
) -> NTuple{4, Any}

Vertices are defined for every grid point on a ring grid through 4 points: east, south, west, north.

- east: longitude mid-point with the next grid point east
- south: longitude mid-point between the two closest grid points on one ring to the south
- west: longitude mid-point with the next grid point west
- north: longitude mid-point between the two closest grid points on one ring to the north

Example

   o ----- n ------ o

o --- w --- c --- e --- o

     o ----- s ------ o

with cell center c (the grid point), e, s, w, n the vertices and o the surrounding grid points. Returns 2xnpoints arrays for east, south, west, north each containing the longitude and latitude of the vertices.

source
SpeedyWeather.RingGrids.grid_cell_average!Method
grid_cell_average!(
    output::AbstractField,
    input::AbstractField{T, N, ArrayType, Grid} where {T, N, ArrayType, Grid<:AbstractFullGrid}
) -> AbstractField

Averages all grid points in input that are within one grid cell of output with coslat-weighting. The output grid cell boundaries are assumed to be rectangles spanning half way to adjacent longitude and latitude points.

source
SpeedyWeather.RingGrids.grid_cell_averageMethod
grid_cell_average(
    Grid::Type{<:AbstractGrid},
    nlat_half::Integer,
    input::AbstractFullGrid
)

Averages all grid points in input that are within one grid cell of output with coslat-weighting. The output grid cell boundaries are assumed to be rectangles spanning half way to adjacent longitude and latitude points.

source
SpeedyWeather.RingGrids.grids_matchMethod
grids_match(A::AbstractGrid, B::AbstractGrid) -> Any

True if both A and B are of the same nonparametric grid type (e.g. OctahedralGaussianArray, regardless type parameter T or underyling array type ArrayType) and of same resolution (nlat_half) and total grid points (length). Sizes of (4,) and (4,1) would match for example, but (8,1) and (4,2) would not (nlat_half not identical).

source
SpeedyWeather.RingGrids.grids_matchMethod
grids_match(A::AbstractGrid, Bs::AbstractGrid...) -> Any

True if all grids A, B, C, ... provided as arguments match according to grids_match wrt to A (and therefore all).

source
SpeedyWeather.RingGrids.nonparametric_typeMethod
nonparametric_type(grid::AbstractGrid) -> Any

For any instance of AbstractGrid type its n-dimensional type (*Grid{T, N, ...} returns *Array) but without any parameters {T, N, ArrayType}

source
SpeedyWeather.RingGrids.nside_healpixMethod
nside_healpix(nlat_half::Integer) -> Any

The original Nside resolution parameter of the HEALPix grids. The number of grid points on one side of each (square) face. While we use nlat_half across all ring grids, this function translates this to Nside. Even nlat_half only.

source
SpeedyWeather.RingGrids.spherical_distanceMethod
spherical_distance(
    Formula::Type{<:SpeedyWeather.RingGrids.AbstractSphericalDistance},
    args...;
    kwargs...
) -> Any

Spherical distance, or great-circle distance, between two points lonlat1 and lonlat2 using the Formula (default Haversine).

source