From c58d4674ed45a3fa4e3ae0eedc1f28fe466155fc Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Fri, 4 Aug 2023 21:53:31 +0000 Subject: [PATCH] build based on c4eb2ac --- previews/PR363/barotropic/index.html | 2 +- previews/PR363/conventions/index.html | 2 +- previews/PR363/development/index.html | 2 +- previews/PR363/extending/index.html | 2 +- previews/PR363/functions/index.html | 284 +++++------ previews/PR363/grids/index.html | 4 +- previews/PR363/how_to_run_speedy/index.html | 2 +- previews/PR363/index.html | 2 +- previews/PR363/installation/index.html | 2 +- .../PR363/lowertriangularmatrices/index.html | 4 +- previews/PR363/output/index.html | 2 +- previews/PR363/parameterizations/index.html | 2 +- previews/PR363/primitiveequation/index.html | 2 +- previews/PR363/ringgrids/index.html | 460 +++++++++--------- previews/PR363/search/index.html | 2 +- previews/PR363/search_index.js | 2 +- previews/PR363/shallowwater/index.html | 2 +- previews/PR363/spectral_transform/index.html | 2 +- previews/PR363/speedytransforms/index.html | 249 ++++++++-- previews/PR363/time_integration/index.html | 2 - 20 files changed, 600 insertions(+), 431 deletions(-) delete mode 100644 previews/PR363/time_integration/index.html diff --git a/previews/PR363/barotropic/index.html b/previews/PR363/barotropic/index.html index 434cb4616..cef9a3154 100644 --- a/previews/PR363/barotropic/index.html +++ b/previews/PR363/barotropic/index.html @@ -9,4 +9,4 @@ w_{i+1} &= u_{i-1} + 2\Delta tF(v_i) \\ u_i &= v_i + \frac{\nu\alpha}{2}(w_{i+1} - 2v_i + u_{i-1}) \\ v_{i+1} &= w_{i+1} - \frac{\nu(1-\alpha)}{2}(w_{i+1} - 2v_i + u_{i-1}) -\end{aligned}\]

with the Williams filter parameter $\alpha \in [0.5,1]$. For $\alpha=1$ we're back with the Robert-Asselin filter (the first two lines).

The Laplacian in the parentheses is often called a displacement, meaning that the filtered value is displaced (or corrected) in the direction of the two surrounding time steps. The Williams filter now also applies the same displacement, but in the opposite direction to the next time step $i+1$ as a correction step (line 3 above) for a once-filtered value $v_{i+1}$ which will then be twice-filtered by the Robert-Asselin filter on the next iteration. For more details see the referenced publications.

The initial Euler step (see Time integration, Table) is not filtered. Both the the Robert-Asselin and Williams filter are then switched on for all following leapfrog time steps.

References

+\end{aligned}\]

with the Williams filter parameter $\alpha \in [0.5,1]$. For $\alpha=1$ we're back with the Robert-Asselin filter (the first two lines).

The Laplacian in the parentheses is often called a displacement, meaning that the filtered value is displaced (or corrected) in the direction of the two surrounding time steps. The Williams filter now also applies the same displacement, but in the opposite direction to the next time step $i+1$ as a correction step (line 3 above) for a once-filtered value $v_{i+1}$ which will then be twice-filtered by the Robert-Asselin filter on the next iteration. For more details see the referenced publications.

The initial Euler step (see Time integration, Table) is not filtered. Both the the Robert-Asselin and Williams filter are then switched on for all following leapfrog time steps.

References

diff --git a/previews/PR363/conventions/index.html b/previews/PR363/conventions/index.html index 13b6f0155..f15aedf07 100644 --- a/previews/PR363/conventions/index.html +++ b/previews/PR363/conventions/index.html @@ -9,4 +9,4 @@ ...

Preallocation

All arrays representing variables are preallocated and grouped into two structs

    Prog::PrognosticVariables
     Diag::DiagnosticVariables

The Diag struct contains further structs which represent the grid-point transformations of the prognostic variables and their tendencies.

    gridvars::GridVariables
     tendencies::Tendencies
-    ...

Constant arrays are grouped into several structs

Boundaries

Julian conventions

We follow Julia's style guide and highlight here some important aspects of it.

Hence, func! is often the in-place version of func, avoiding as much memory allocation as possible and often changing its first argument, e.g. func!(out,in) so that argument in is used to calculate out which has been preallocated before function call.

but avoided throughout the code to obtain a fully number format-flexible package using the number format NF as a compile-time variable throughout the code. This often leads to overly specific code whereas a Real would generally suffice. However, this is done to avoid any implicit type conversions.

+ ...

Constant arrays are grouped into several structs

Boundaries

Julian conventions

We follow Julia's style guide and highlight here some important aspects of it.

Hence, func! is often the in-place version of func, avoiding as much memory allocation as possible and often changing its first argument, e.g. func!(out,in) so that argument in is used to calculate out which has been preallocated before function call.

but avoided throughout the code to obtain a fully number format-flexible package using the number format NF as a compile-time variable throughout the code. This often leads to overly specific code whereas a Real would generally suffice. However, this is done to avoid any implicit type conversions.

diff --git a/previews/PR363/development/index.html b/previews/PR363/development/index.html index 468d5fcfb..6bec81b3e 100644 --- a/previews/PR363/development/index.html +++ b/previews/PR363/development/index.html @@ -1,3 +1,3 @@ Development notes · SpeedyWeather.jl

Development notes

To run tests, from the path of your local clone of the repository do:

julia --project=. -e 'import Pkg; Pkg.test()'

To install dependencies:

julia --project -e 'import Pkg; Pkg.instantiate()`

then opening:

julia --project

you are able to using SpeedyWeather.

To generate the docs:

julia --project=docs -e 'import Pkg; Pkg.develop(path="."); Pkg.instantiate()'
-julia --project=docs docs/make.jl

If the docs are generated successfully, you view them by opening docs/build/index.html in your favorite browser.

+julia --project=docs docs/make.jl

If the docs are generated successfully, you view them by opening docs/build/index.html in your favorite browser.

diff --git a/previews/PR363/extending/index.html b/previews/PR363/extending/index.html index 2c19cc37b..a97de0555 100644 --- a/previews/PR363/extending/index.html +++ b/previews/PR363/extending/index.html @@ -1,2 +1,2 @@ -Extending SpeedyWeather · SpeedyWeather.jl
+Extending SpeedyWeather · SpeedyWeather.jl
diff --git a/previews/PR363/functions/index.html b/previews/PR363/functions/index.html index 449036d27..68baca5e9 100644 --- a/previews/PR363/functions/index.html +++ b/previews/PR363/functions/index.html @@ -1,93 +1,93 @@ -Function and type index · SpeedyWeather.jl

Function and type index

SpeedyWeather.BarotropicModelType

The BarotropicModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • forcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat

  • initial_conditions::SpeedyWeather.InitialConditions

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.ClockType

Clock struct keeps track of the model time, how many days to integrate for and how many time steps this takes

  • time::Dates.DateTime: current model time

  • n_days::Float64: number of days to integrate for, set in run!(::Simulation)

  • n_timesteps::Int64: number of time steps to integrate for, set in initialize!(::Clock,::TimeStepper)

.

source
SpeedyWeather.ColumnVariablesType

Mutable struct that contains all prognostic (copies thereof) and diagnostic variables in a single column needed to evaluate the physical parametrizations. For now the struct is mutable as we will reuse the struct to iterate over horizontal grid points. Every column vector has nlev entries, from [1] at the top to [end] at the lowermost model level at the planetary boundary layer.

  • nlev::Int64

  • nband::Int64

  • n_stratosphere_levels::Int64

  • jring::Int64

  • lond::AbstractFloat

  • latd::AbstractFloat

  • u::Vector{NF} where NF<:AbstractFloat

  • v::Vector{NF} where NF<:AbstractFloat

  • temp::Vector{NF} where NF<:AbstractFloat

  • humid::Vector{NF} where NF<:AbstractFloat

  • ln_pres::Vector{NF} where NF<:AbstractFloat

  • pres::Vector{NF} where NF<:AbstractFloat

  • u_tend::Vector{NF} where NF<:AbstractFloat

  • v_tend::Vector{NF} where NF<:AbstractFloat

  • temp_tend::Vector{NF} where NF<:AbstractFloat

  • humid_tend::Vector{NF} where NF<:AbstractFloat

  • geopot::Vector{NF} where NF<:AbstractFloat

  • flux_u_upward::Vector{NF} where NF<:AbstractFloat

  • flux_u_downward::Vector{NF} where NF<:AbstractFloat

  • flux_v_upward::Vector{NF} where NF<:AbstractFloat

  • flux_v_downward::Vector{NF} where NF<:AbstractFloat

  • flux_temp_upward::Vector{NF} where NF<:AbstractFloat

  • flux_temp_downward::Vector{NF} where NF<:AbstractFloat

  • flux_humid_upward::Vector{NF} where NF<:AbstractFloat

  • flux_humid_downward::Vector{NF} where NF<:AbstractFloat

  • sat_humid::Vector{NF} where NF<:AbstractFloat

  • sat_vap_pres::Vector{NF} where NF<:AbstractFloat

  • dry_static_energy::Vector{NF} where NF<:AbstractFloat

  • moist_static_energy::Vector{NF} where NF<:AbstractFloat

  • humid_half::Vector{NF} where NF<:AbstractFloat

  • sat_humid_half::Vector{NF} where NF<:AbstractFloat

  • sat_moist_static_energy::Vector{NF} where NF<:AbstractFloat

  • dry_static_energy_half::Vector{NF} where NF<:AbstractFloat

  • sat_moist_static_energy_half::Vector{NF} where NF<:AbstractFloat

  • conditional_instability::Bool

  • activate_convection::Bool

  • cloud_top::Int64

  • excess_humidity::AbstractFloat

  • cloud_base_mass_flux::AbstractFloat

  • precip_convection::AbstractFloat

  • net_flux_humid::Vector{NF} where NF<:AbstractFloat

  • net_flux_dry_static_energy::Vector{NF} where NF<:AbstractFloat

  • entrainment_profile::Vector{NF} where NF<:AbstractFloat

  • precip_large_scale::AbstractFloat

  • wvi::Matrix{NF} where NF<:AbstractFloat

  • tau2::Matrix{NF} where NF<:AbstractFloat

  • dfabs::Vector{NF} where NF<:AbstractFloat

  • fsfcd::AbstractFloat

  • st4a::Matrix{NF} where NF<:AbstractFloat

  • flux::Vector{NF} where NF<:AbstractFloat

  • fsfcu::AbstractFloat

  • ts::AbstractFloat

  • fsfc::AbstractFloat

  • ftop::AbstractFloat

  • stratc::Vector{NF} where NF<:AbstractFloat

  • tyear::AbstractFloat

  • csol::AbstractFloat

  • topsr::AbstractFloat

  • fsol::AbstractFloat

  • ozupp::AbstractFloat

  • ozone::AbstractFloat

  • zenit::AbstractFloat

  • stratz::AbstractFloat

  • albsfc::AbstractFloat

  • ssrd::AbstractFloat

  • ssr::AbstractFloat

  • tsr::AbstractFloat

  • tend_t_rsw::Vector{NF} where NF<:AbstractFloat

  • norm_pres::AbstractFloat

  • icltop::Int64

  • cloudc::AbstractFloat

  • clstr::AbstractFloat

  • qcloud::AbstractFloat

  • fmask::AbstractFloat

  • rel_hum::Vector{NF} where NF<:AbstractFloat

  • grad_dry_static_energy::AbstractFloat

source
SpeedyWeather.DeviceSetupType
DeviceSetup{S<:AbstractDevice}

Holds information about the device the model is running on and workgroup size.

  • device::AbstractDevice: Device the model is running on
  • device_KA::KernelAbstractions.Device: Device for use with KernelAbstractions
  • n: workgroup size
source
SpeedyWeather.DynamicsConstantsType

Struct holding constants needed at runtime for the dynamical core in number format NF.

  • radius::AbstractFloat: Radius of Planet [m]

  • rotation::AbstractFloat: Angular frequency of Planet's rotation [1/s]

  • gravity::AbstractFloat: Gravitational acceleration [m/s^2]

  • layer_thickness::AbstractFloat: shallow water layer thickness [m]

  • R_dry::AbstractFloat: specific gas constant for dry air [J/kg/K]

  • R_vapour::AbstractFloat: specific gas constant for water vapour [J/kg/K]

  • μ_virt_temp::AbstractFloat: used in Tv = T(1+μq) for virt temp Tv(T,q) calculation

  • cₚ::AbstractFloat: specific heat at constant pressure [J/K/kg]

  • κ::AbstractFloat: = R_dry/cₚ, gas const for air over heat capacity

  • water_density::AbstractFloat: water density [kg/m³]

  • f_coriolis::Vector{NF} where NF<:AbstractFloat: coriolis frequency 1/s = 2Ωsin(lat)radius

  • σ_lnp_A::Vector{NF} where NF<:AbstractFloat: σ-related factor A needed for adiabatic terms

  • σ_lnp_B::Vector{NF} where NF<:AbstractFloat: σ-related factor B needed for adiabatic terms

  • Δp_geopot_half::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1) - ln(pk+1/2)), for half level geopotential

  • Δp_geopot_full::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1/2) - ln(pk)), for full level geopotential

  • temp_ref_profile::Vector{NF} where NF<:AbstractFloat: reference temperature profile

source
SpeedyWeather.DynamicsConstantsMethod
DynamicsConstants(
+Function and type index · SpeedyWeather.jl

Function and type index

SpeedyWeather.BarotropicModelType

The BarotropicModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • forcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat

  • initial_conditions::SpeedyWeather.InitialConditions

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.ClockType

Clock struct keeps track of the model time, how many days to integrate for and how many time steps this takes

  • time::Dates.DateTime: current model time

  • n_days::Float64: number of days to integrate for, set in run!(::Simulation)

  • n_timesteps::Int64: number of time steps to integrate for, set in initialize!(::Clock,::TimeStepper)

.

source
SpeedyWeather.ColumnVariablesType

Mutable struct that contains all prognostic (copies thereof) and diagnostic variables in a single column needed to evaluate the physical parametrizations. For now the struct is mutable as we will reuse the struct to iterate over horizontal grid points. Every column vector has nlev entries, from [1] at the top to [end] at the lowermost model level at the planetary boundary layer.

  • nlev::Int64

  • nband::Int64

  • n_stratosphere_levels::Int64

  • jring::Int64

  • lond::AbstractFloat

  • latd::AbstractFloat

  • u::Vector{NF} where NF<:AbstractFloat

  • v::Vector{NF} where NF<:AbstractFloat

  • temp::Vector{NF} where NF<:AbstractFloat

  • humid::Vector{NF} where NF<:AbstractFloat

  • ln_pres::Vector{NF} where NF<:AbstractFloat

  • pres::Vector{NF} where NF<:AbstractFloat

  • u_tend::Vector{NF} where NF<:AbstractFloat

  • v_tend::Vector{NF} where NF<:AbstractFloat

  • temp_tend::Vector{NF} where NF<:AbstractFloat

  • humid_tend::Vector{NF} where NF<:AbstractFloat

  • geopot::Vector{NF} where NF<:AbstractFloat

  • flux_u_upward::Vector{NF} where NF<:AbstractFloat

  • flux_u_downward::Vector{NF} where NF<:AbstractFloat

  • flux_v_upward::Vector{NF} where NF<:AbstractFloat

  • flux_v_downward::Vector{NF} where NF<:AbstractFloat

  • flux_temp_upward::Vector{NF} where NF<:AbstractFloat

  • flux_temp_downward::Vector{NF} where NF<:AbstractFloat

  • flux_humid_upward::Vector{NF} where NF<:AbstractFloat

  • flux_humid_downward::Vector{NF} where NF<:AbstractFloat

  • sat_humid::Vector{NF} where NF<:AbstractFloat

  • sat_vap_pres::Vector{NF} where NF<:AbstractFloat

  • dry_static_energy::Vector{NF} where NF<:AbstractFloat

  • moist_static_energy::Vector{NF} where NF<:AbstractFloat

  • humid_half::Vector{NF} where NF<:AbstractFloat

  • sat_humid_half::Vector{NF} where NF<:AbstractFloat

  • sat_moist_static_energy::Vector{NF} where NF<:AbstractFloat

  • dry_static_energy_half::Vector{NF} where NF<:AbstractFloat

  • sat_moist_static_energy_half::Vector{NF} where NF<:AbstractFloat

  • conditional_instability::Bool

  • activate_convection::Bool

  • cloud_top::Int64

  • excess_humidity::AbstractFloat

  • cloud_base_mass_flux::AbstractFloat

  • precip_convection::AbstractFloat

  • net_flux_humid::Vector{NF} where NF<:AbstractFloat

  • net_flux_dry_static_energy::Vector{NF} where NF<:AbstractFloat

  • entrainment_profile::Vector{NF} where NF<:AbstractFloat

  • precip_large_scale::AbstractFloat

  • wvi::Matrix{NF} where NF<:AbstractFloat

  • tau2::Matrix{NF} where NF<:AbstractFloat

  • dfabs::Vector{NF} where NF<:AbstractFloat

  • fsfcd::AbstractFloat

  • st4a::Matrix{NF} where NF<:AbstractFloat

  • flux::Vector{NF} where NF<:AbstractFloat

  • fsfcu::AbstractFloat

  • ts::AbstractFloat

  • fsfc::AbstractFloat

  • ftop::AbstractFloat

  • stratc::Vector{NF} where NF<:AbstractFloat

  • tyear::AbstractFloat

  • csol::AbstractFloat

  • topsr::AbstractFloat

  • fsol::AbstractFloat

  • ozupp::AbstractFloat

  • ozone::AbstractFloat

  • zenit::AbstractFloat

  • stratz::AbstractFloat

  • albsfc::AbstractFloat

  • ssrd::AbstractFloat

  • ssr::AbstractFloat

  • tsr::AbstractFloat

  • tend_t_rsw::Vector{NF} where NF<:AbstractFloat

  • norm_pres::AbstractFloat

  • icltop::Int64

  • cloudc::AbstractFloat

  • clstr::AbstractFloat

  • qcloud::AbstractFloat

  • fmask::AbstractFloat

  • rel_hum::Vector{NF} where NF<:AbstractFloat

  • grad_dry_static_energy::AbstractFloat

source
SpeedyWeather.DeviceSetupType
DeviceSetup{S<:AbstractDevice}

Holds information about the device the model is running on and workgroup size.

  • device::AbstractDevice: Device the model is running on
  • device_KA::KernelAbstractions.Device: Device for use with KernelAbstractions
  • n: workgroup size
source
SpeedyWeather.DynamicsConstantsType

Struct holding constants needed at runtime for the dynamical core in number format NF.

  • radius::AbstractFloat: Radius of Planet [m]

  • rotation::AbstractFloat: Angular frequency of Planet's rotation [1/s]

  • gravity::AbstractFloat: Gravitational acceleration [m/s^2]

  • layer_thickness::AbstractFloat: shallow water layer thickness [m]

  • R_dry::AbstractFloat: specific gas constant for dry air [J/kg/K]

  • R_vapour::AbstractFloat: specific gas constant for water vapour [J/kg/K]

  • μ_virt_temp::AbstractFloat: used in Tv = T(1+μq) for virt temp Tv(T,q) calculation

  • cₚ::AbstractFloat: specific heat at constant pressure [J/K/kg]

  • κ::AbstractFloat: = R_dry/cₚ, gas const for air over heat capacity

  • water_density::AbstractFloat: water density [kg/m³]

  • f_coriolis::Vector{NF} where NF<:AbstractFloat: coriolis frequency 1/s = 2Ωsin(lat)radius

  • σ_lnp_A::Vector{NF} where NF<:AbstractFloat: σ-related factor A needed for adiabatic terms

  • σ_lnp_B::Vector{NF} where NF<:AbstractFloat: σ-related factor B needed for adiabatic terms

  • Δp_geopot_half::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1) - ln(pk+1/2)), for half level geopotential

  • Δp_geopot_full::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1/2) - ln(pk)), for full level geopotential

  • temp_ref_profile::Vector{NF} where NF<:AbstractFloat: reference temperature profile

source
SpeedyWeather.DynamicsConstantsMethod
DynamicsConstants(
     spectral_grid::SpectralGrid,
     planet::SpeedyWeather.AbstractPlanet,
     atmosphere::SpeedyWeather.AbstractAtmosphere,
     geometry::Geometry
 ) -> Any
-

Generator function for a DynamicsConstants struct.

source
SpeedyWeather.EarthType

Create a struct Earth<:AbstractPlanet, with the following physical/orbital characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are

  • rotation::Float64: angular frequency of Earth's rotation [rad/s]

  • gravity::Float64: gravitational acceleration [m/s^2]

  • daily_cycle::Bool: switch on/off daily cycle

  • length_of_day::Float64: [hrs] in a day

  • seasonal_cycle::Bool: switch on/off seasonal cycle

  • length_of_year::Float64: [days] in a year

  • equinox::Dates.DateTime: time of spring equinox (year irrelevant)

  • axial_tilt::Float64: angle [˚] rotation axis tilt wrt to orbit

source
SpeedyWeather.EarthAtmosphereType

Create a struct EarthAtmosphere<:AbstractPlanet, with the following physical/chemical characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are

  • mol_mass_dry_air::Float64: molar mass of dry air [g/mol]

  • mol_mass_vapour::Float64: molar mass of water vapour [g/mol]

  • cₚ::Float64: specific heat at constant pressure [J/K/kg]

  • R_gas::Float64: universal gas constant [J/K/mol]

  • R_dry::Float64: specific gas constant for dry air [J/kg/K]

  • R_vapour::Float64: specific gas constant for water vapour [J/kg/K]

  • water_density::Float64: water density [kg/m³]

  • latent_heat_condensation::Float64: latent heat of condensation [J/g] for consistency with specific humidity [g/Kg], also called alhc

  • latent_heat_sublimation::Float64: latent heat of sublimation [J/g], also called alhs

  • stefan_boltzmann::Float64: stefan-Boltzmann constant [W/m²/K⁴]

  • lapse_rate::Float64: moist adiabatic temperature lapse rate $-dT/dz$ [K/km]

  • temp_ref::Float64: absolute temperature at surface $z=0$ [K]

  • temp_top::Float64: absolute temperature in stratosphere [K]

  • ΔT_stratosphere::Float64: for stratospheric lapse rate [K] after Jablonowski

  • σ_tropopause::Float64: start of the stratosphere in sigma coordinates

  • σ_boundary_layer::Float64: top of the planetary boundary layer in sigma coordinates

  • scale_height::Float64: scale height for pressure [km]

  • pres_ref::Float64: surface pressure [hPa]

  • scale_height_humid::Float64: scale height for specific humidity [km]

  • relhumid_ref::Float64: relative humidity of near-surface air [1]

  • water_pres_ref::Float64: saturation water vapour pressure [Pa]

  • layer_thickness::Float64: layer thickness for the shallow water model [km]

source
SpeedyWeather.EarthOrographyType

Earth's orography read from file, with smoothing.

  • path::String: path to the folder containing the orography file, pkg path default

  • file::String: filename of orography

  • file_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: Grid the orography file comes on

  • scale::Float64: scale orography by a factor

  • smoothing::Bool: smooth the orography field?

  • smoothing_power::Float64: power of Laplacian for smoothing

  • smoothing_strength::Float64: highest degree l is multiplied by

  • smoothing_truncation::Int64: resolution of orography in spectral trunc

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.EarthType

Create a struct Earth<:AbstractPlanet, with the following physical/orbital characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are

  • rotation::Float64: angular frequency of Earth's rotation [rad/s]

  • gravity::Float64: gravitational acceleration [m/s^2]

  • daily_cycle::Bool: switch on/off daily cycle

  • length_of_day::Float64: [hrs] in a day

  • seasonal_cycle::Bool: switch on/off seasonal cycle

  • length_of_year::Float64: [days] in a year

  • equinox::Dates.DateTime: time of spring equinox (year irrelevant)

  • axial_tilt::Float64: angle [˚] rotation axis tilt wrt to orbit

source
SpeedyWeather.EarthAtmosphereType

Create a struct EarthAtmosphere<:AbstractPlanet, with the following physical/chemical characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are

  • mol_mass_dry_air::Float64: molar mass of dry air [g/mol]

  • mol_mass_vapour::Float64: molar mass of water vapour [g/mol]

  • cₚ::Float64: specific heat at constant pressure [J/K/kg]

  • R_gas::Float64: universal gas constant [J/K/mol]

  • R_dry::Float64: specific gas constant for dry air [J/kg/K]

  • R_vapour::Float64: specific gas constant for water vapour [J/kg/K]

  • water_density::Float64: water density [kg/m³]

  • latent_heat_condensation::Float64: latent heat of condensation [J/g] for consistency with specific humidity [g/Kg], also called alhc

  • latent_heat_sublimation::Float64: latent heat of sublimation [J/g], also called alhs

  • stefan_boltzmann::Float64: stefan-Boltzmann constant [W/m²/K⁴]

  • lapse_rate::Float64: moist adiabatic temperature lapse rate $-dT/dz$ [K/km]

  • temp_ref::Float64: absolute temperature at surface $z=0$ [K]

  • temp_top::Float64: absolute temperature in stratosphere [K]

  • ΔT_stratosphere::Float64: for stratospheric lapse rate [K] after Jablonowski

  • σ_tropopause::Float64: start of the stratosphere in sigma coordinates

  • σ_boundary_layer::Float64: top of the planetary boundary layer in sigma coordinates

  • scale_height::Float64: scale height for pressure [km]

  • pres_ref::Float64: surface pressure [hPa]

  • scale_height_humid::Float64: scale height for specific humidity [km]

  • relhumid_ref::Float64: relative humidity of near-surface air [1]

  • water_pres_ref::Float64: saturation water vapour pressure [Pa]

  • layer_thickness::Float64: layer thickness for the shallow water model [km]

source
SpeedyWeather.EarthOrographyType

Earth's orography read from file, with smoothing.

  • path::String: path to the folder containing the orography file, pkg path default

  • file::String: filename of orography

  • file_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: Grid the orography file comes on

  • scale::Float64: scale orography by a factor

  • smoothing::Bool: smooth the orography field?

  • smoothing_power::Float64: power of Laplacian for smoothing

  • smoothing_strength::Float64: highest degree l is multiplied by

  • smoothing_truncation::Int64: resolution of orography in spectral trunc

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.EarthOrographyMethod
EarthOrography(
     spectral_grid::SpectralGrid;
     kwargs...
 ) -> Any
-

Generator function pulling the resolution information from spectral_grid.

source
SpeedyWeather.FeedbackType
Feedback() -> Feedback
 Feedback(verbose::Bool) -> Feedback
 Feedback(verbose::Bool, debug::Bool) -> Feedback
-

Generator function for a Feedback struct.

source
SpeedyWeather.FeedbackType

Feedback struct that contains options and object for command-line feedback like the progress meter.

  • verbose::Bool: print feedback to REPL?

  • debug::Bool: check for NaRs in the prognostic variables

  • output::Bool: write a progress.txt file? State synced with OutputWriter.output

  • id::Union{Int64, String}: identification of run, taken from ::OutputWriter

  • run_path::String: path to run folder, taken from ::OutputWriter

  • progress_meter::ProgressMeter.Progress: struct containing everything progress related

  • progress_txt::Union{Nothing, IOStream}: txt is a Nothing in case of no output

  • nars_detected::Bool: did Infs/NaNs occur in the simulation?

source
SpeedyWeather.GeometryType

Construct Geometry struct containing parameters and arrays describing an iso-latitude grid <:AbstractGrid and the vertical levels. Pass on SpectralGrid to calculate the following fields

  • spectral_grid::SpectralGrid: SpectralGrid that defines spectral and grid resolution

  • Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: grid of the dynamical core

  • nlat_half::Int64: resolution parameter nlat_half of Grid, # of latitudes on one hemisphere (incl Equator)

  • nlon_max::Int64: maximum number of longitudes (at/around Equator)

  • nlon::Int64: =nlon_max, same (used for compatibility), TODO: still needed?

  • nlat::Int64: number of latitude rings

  • nlev::Int64: number of vertical levels

  • npoints::Int64: total number of grid points

  • radius::AbstractFloat: Planet's radius [m]

  • latd::Vector{Float64}: array of latitudes in degrees (90˚...-90˚)

  • lond::Vector{Float64}: array of longitudes in degrees (0...360˚), empty for non-full grids

  • londs::Vector{NF} where NF<:AbstractFloat: longitude (-180˚...180˚) for each grid point in ring order

  • latds::Vector{NF} where NF<:AbstractFloat: latitude (-90˚...˚90) for each grid point in ring order

  • sinlat::Vector{NF} where NF<:AbstractFloat: sin of latitudes

  • coslat::Vector{NF} where NF<:AbstractFloat: cos of latitudes

  • coslat⁻¹::Vector{NF} where NF<:AbstractFloat: = 1/cos(lat)

  • coslat²::Vector{NF} where NF<:AbstractFloat: = cos²(lat)

  • coslat⁻²::Vector{NF} where NF<:AbstractFloat: # = 1/cos²(lat)

  • σ_levels_half::Vector{NF} where NF<:AbstractFloat: σ at half levels, σ_k+1/2

  • σ_levels_full::Vector{NF} where NF<:AbstractFloat: σ at full levels, σₖ

  • σ_levels_thick::Vector{NF} where NF<:AbstractFloat: σ level thicknesses, σₖ₊₁ - σₖ

  • ln_σ_levels_full::Vector{NF} where NF<:AbstractFloat: log of σ at full levels, include surface (σ=1) as last element

source
SpeedyWeather.GeometryMethod
Geometry(spectral_grid::SpectralGrid) -> Any
-

Generator function for Geometry struct based on spectral_grid.

source
SpeedyWeather.HeldSuarezType

Struct that defines the temperature relaxation from Held and Suarez, 1996 BAMS

  • nlat::Int64: number of latitude rings

  • nlev::Int64: number of vertical levels

  • σb::Float64: sigma coordinate below which faster surface relaxation is applied

  • relax_time_slow::Float64: time scale [hrs] for slow global relaxation

  • relax_time_fast::Float64: time scale [hrs] for faster tropical surface relaxation

  • Tmin::Float64: minimum equilibrium temperature [K]

  • Tmax::Float64: maximum equilibrium temperature [K]

  • ΔTy::Float64: meridional temperature gradient [K]

  • Δθz::Float64: vertical temperature gradient [K]

  • κ::Base.RefValue{NF} where NF<:AbstractFloat

  • p₀::Base.RefValue{NF} where NF<:AbstractFloat

  • temp_relax_freq::Matrix{NF} where NF<:AbstractFloat

  • temp_equil_a::Vector{NF} where NF<:AbstractFloat

  • temp_equil_b::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.HeldSuarezMethod
HeldSuarez(SG::SpectralGrid; kwargs...) -> Any
-

create a HeldSuarez temperature relaxation with arrays allocated given spectral_grid

source
SpeedyWeather.HyperDiffusionType

Struct for horizontal hyper diffusion of vor, div, temp; implicitly in spectral space with a power of the Laplacian (default=4) and the strength controlled by time_scale. Options exist to scale the diffusion by resolution, and adaptive depending on the current vorticity maximum to increase diffusion in active layers. Furthermore the power can be decreased above the tapering_σ to power_stratosphere (default 2). For Barotropic, ShallowWater, the default non-adaptive constant-time scale hyper diffusion is used. Options are

  • trunc::Int64: spectral resolution

  • nlev::Int64: number of vertical levels

  • power::Float64: power of Laplacian

  • time_scale::Float64: diffusion time scales [hrs]

  • resolution_scaling::Float64: stronger diffusion with resolution? 0: constant with trunc, 1: (inverse) linear with trunc, etc

  • power_stratosphere::Float64: different power for tropopause/stratosphere

  • tapering_σ::Float64: linearly scale towards power_stratosphere above this σ

  • adaptive::Bool: adaptive = higher diffusion for layers with higher vorticity levels.

  • vor_max::Float64: above this (absolute) vorticity level [1/s], diffusion is increased

  • adaptive_strength::Float64: increase strength above vor_max by this factor times max(abs(vor))/vor_max

  • ∇²ⁿ_2D::Vector

  • ∇²ⁿ_2D_implicit::Vector

  • ∇²ⁿ::Array{Vector{NF}, 1} where NF

  • ∇²ⁿ_implicit::Array{Vector{NF}, 1} where NF

source
SpeedyWeather.FeedbackType

Feedback struct that contains options and object for command-line feedback like the progress meter.

  • verbose::Bool: print feedback to REPL?

  • debug::Bool: check for NaRs in the prognostic variables

  • output::Bool: write a progress.txt file? State synced with OutputWriter.output

  • id::Union{Int64, String}: identification of run, taken from ::OutputWriter

  • run_path::String: path to run folder, taken from ::OutputWriter

  • progress_meter::ProgressMeter.Progress: struct containing everything progress related

  • progress_txt::Union{Nothing, IOStream}: txt is a Nothing in case of no output

  • nars_detected::Bool: did Infs/NaNs occur in the simulation?

source
SpeedyWeather.GeometryType

Construct Geometry struct containing parameters and arrays describing an iso-latitude grid <:AbstractGrid and the vertical levels. Pass on SpectralGrid to calculate the following fields

  • spectral_grid::SpectralGrid: SpectralGrid that defines spectral and grid resolution

  • Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: grid of the dynamical core

  • nlat_half::Int64: resolution parameter nlat_half of Grid, # of latitudes on one hemisphere (incl Equator)

  • nlon_max::Int64: maximum number of longitudes (at/around Equator)

  • nlon::Int64: =nlon_max, same (used for compatibility), TODO: still needed?

  • nlat::Int64: number of latitude rings

  • nlev::Int64: number of vertical levels

  • npoints::Int64: total number of grid points

  • radius::AbstractFloat: Planet's radius [m]

  • latd::Vector{Float64}: array of latitudes in degrees (90˚...-90˚)

  • lond::Vector{Float64}: array of longitudes in degrees (0...360˚), empty for non-full grids

  • londs::Vector{NF} where NF<:AbstractFloat: longitude (-180˚...180˚) for each grid point in ring order

  • latds::Vector{NF} where NF<:AbstractFloat: latitude (-90˚...˚90) for each grid point in ring order

  • sinlat::Vector{NF} where NF<:AbstractFloat: sin of latitudes

  • coslat::Vector{NF} where NF<:AbstractFloat: cos of latitudes

  • coslat⁻¹::Vector{NF} where NF<:AbstractFloat: = 1/cos(lat)

  • coslat²::Vector{NF} where NF<:AbstractFloat: = cos²(lat)

  • coslat⁻²::Vector{NF} where NF<:AbstractFloat: # = 1/cos²(lat)

  • σ_levels_half::Vector{NF} where NF<:AbstractFloat: σ at half levels, σ_k+1/2

  • σ_levels_full::Vector{NF} where NF<:AbstractFloat: σ at full levels, σₖ

  • σ_levels_thick::Vector{NF} where NF<:AbstractFloat: σ level thicknesses, σₖ₊₁ - σₖ

  • ln_σ_levels_full::Vector{NF} where NF<:AbstractFloat: log of σ at full levels, include surface (σ=1) as last element

source
SpeedyWeather.GeometryMethod
Geometry(spectral_grid::SpectralGrid) -> Any
+

Generator function for Geometry struct based on spectral_grid.

source
SpeedyWeather.HeldSuarezType

Struct that defines the temperature relaxation from Held and Suarez, 1996 BAMS

  • nlat::Int64: number of latitude rings

  • nlev::Int64: number of vertical levels

  • σb::Float64: sigma coordinate below which faster surface relaxation is applied

  • relax_time_slow::Float64: time scale [hrs] for slow global relaxation

  • relax_time_fast::Float64: time scale [hrs] for faster tropical surface relaxation

  • Tmin::Float64: minimum equilibrium temperature [K]

  • Tmax::Float64: maximum equilibrium temperature [K]

  • ΔTy::Float64: meridional temperature gradient [K]

  • Δθz::Float64: vertical temperature gradient [K]

  • κ::Base.RefValue{NF} where NF<:AbstractFloat

  • p₀::Base.RefValue{NF} where NF<:AbstractFloat

  • temp_relax_freq::Matrix{NF} where NF<:AbstractFloat

  • temp_equil_a::Vector{NF} where NF<:AbstractFloat

  • temp_equil_b::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.HeldSuarezMethod
HeldSuarez(SG::SpectralGrid; kwargs...) -> Any
+

create a HeldSuarez temperature relaxation with arrays allocated given spectral_grid

source
SpeedyWeather.HyperDiffusionType

Struct for horizontal hyper diffusion of vor, div, temp; implicitly in spectral space with a power of the Laplacian (default=4) and the strength controlled by time_scale. Options exist to scale the diffusion by resolution, and adaptive depending on the current vorticity maximum to increase diffusion in active layers. Furthermore the power can be decreased above the tapering_σ to power_stratosphere (default 2). For Barotropic, ShallowWater, the default non-adaptive constant-time scale hyper diffusion is used. Options are

  • trunc::Int64: spectral resolution

  • nlev::Int64: number of vertical levels

  • power::Float64: power of Laplacian

  • time_scale::Float64: diffusion time scales [hrs]

  • resolution_scaling::Float64: stronger diffusion with resolution? 0: constant with trunc, 1: (inverse) linear with trunc, etc

  • power_stratosphere::Float64: different power for tropopause/stratosphere

  • tapering_σ::Float64: linearly scale towards power_stratosphere above this σ

  • adaptive::Bool: adaptive = higher diffusion for layers with higher vorticity levels.

  • vor_max::Float64: above this (absolute) vorticity level [1/s], diffusion is increased

  • adaptive_strength::Float64: increase strength above vor_max by this factor times max(abs(vor))/vor_max

  • ∇²ⁿ_2D::Vector

  • ∇²ⁿ_2D_implicit::Vector

  • ∇²ⁿ::Array{Vector{NF}, 1} where NF

  • ∇²ⁿ_implicit::Array{Vector{NF}, 1} where NF

source
SpeedyWeather.HyperDiffusionMethod
HyperDiffusion(
     spectral_grid::SpectralGrid;
     kwargs...
 ) -> Any
-

Generator function based on the resolutin in spectral_grid. Passes on keyword arguments.

source
SpeedyWeather.ImplicitPrimitiveEqType

Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the primitive equation model.

  • trunc::Int64: spectral resolution

  • nlev::Int64: number of vertical levels

  • α::Float64: time-step coefficient: 0=explicit, 0.5=centred implicit, 1=backward implicit

  • temp_profile::Vector{NF} where NF<:AbstractFloat: vertical temperature profile, obtained from diagn

  • ξ::Base.RefValue{NF} where NF<:AbstractFloat: time step 2α*Δt packed in RefValue for mutability

  • R::Matrix{NF} where NF<:AbstractFloat: divergence: operator for the geopotential calculation

  • U::Vector{NF} where NF<:AbstractFloat: divergence: the -RdTₖ∇² term excl the eigenvalues from ∇² for divergence

  • L::Matrix{NF} where NF<:AbstractFloat: temperature: operator for the TₖD + κTₖDlnps/Dt term

  • W::Vector{NF} where NF<:AbstractFloat: pressure: vertical averaging of the -D̄ term in the log surface pres equation

  • L0::Vector{NF} where NF<:AbstractFloat: components to construct L, 1/ 2Δσ

  • L1::Matrix{NF} where NF<:AbstractFloat: vert advection term in the temperature equation (below+above)

  • L2::Vector{NF} where NF<:AbstractFloat: factor in front of the divsumabove term

  • L3::Matrix{NF} where NF<:AbstractFloat: sumabove operator itself

  • L4::Vector{NF} where NF<:AbstractFloat: factor in front of div term in Dlnps/Dt

  • S::Matrix{NF} where NF<:AbstractFloat: for every l the matrix to be inverted

  • S⁻¹::Array{NF, 3} where NF<:AbstractFloat: combined inverted operator: S = 1 - ξ²(RL + UW)

source
SpeedyWeather.ImplicitPrimitiveEqType

Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the primitive equation model.

  • trunc::Int64: spectral resolution

  • nlev::Int64: number of vertical levels

  • α::Float64: time-step coefficient: 0=explicit, 0.5=centred implicit, 1=backward implicit

  • temp_profile::Vector{NF} where NF<:AbstractFloat: vertical temperature profile, obtained from diagn

  • ξ::Base.RefValue{NF} where NF<:AbstractFloat: time step 2α*Δt packed in RefValue for mutability

  • R::Matrix{NF} where NF<:AbstractFloat: divergence: operator for the geopotential calculation

  • U::Vector{NF} where NF<:AbstractFloat: divergence: the -RdTₖ∇² term excl the eigenvalues from ∇² for divergence

  • L::Matrix{NF} where NF<:AbstractFloat: temperature: operator for the TₖD + κTₖDlnps/Dt term

  • W::Vector{NF} where NF<:AbstractFloat: pressure: vertical averaging of the -D̄ term in the log surface pres equation

  • L0::Vector{NF} where NF<:AbstractFloat: components to construct L, 1/ 2Δσ

  • L1::Matrix{NF} where NF<:AbstractFloat: vert advection term in the temperature equation (below+above)

  • L2::Vector{NF} where NF<:AbstractFloat: factor in front of the divsumabove term

  • L3::Matrix{NF} where NF<:AbstractFloat: sumabove operator itself

  • L4::Vector{NF} where NF<:AbstractFloat: factor in front of div term in Dlnps/Dt

  • S::Matrix{NF} where NF<:AbstractFloat: for every l the matrix to be inverted

  • S⁻¹::Array{NF, 3} where NF<:AbstractFloat: combined inverted operator: S = 1 - ξ²(RL + UW)

source
SpeedyWeather.ImplicitShallowWaterType

Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the shallow water model.

  • trunc::Int64

  • α::Float64: coefficient for semi-implicit computations to filter gravity waves

  • H::Base.RefValue{NF} where NF<:AbstractFloat

  • ξH::Base.RefValue{NF} where NF<:AbstractFloat

  • g∇²::Vector{NF} where NF<:AbstractFloat

  • ξg∇²::Vector{NF} where NF<:AbstractFloat

  • S⁻¹::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.ImplicitShallowWaterType

Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the shallow water model.

  • trunc::Int64

  • α::Float64: coefficient for semi-implicit computations to filter gravity waves

  • H::Base.RefValue{NF} where NF<:AbstractFloat

  • ξH::Base.RefValue{NF} where NF<:AbstractFloat

  • g∇²::Vector{NF} where NF<:AbstractFloat

  • ξg∇²::Vector{NF} where NF<:AbstractFloat

  • S⁻¹::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.JablonowskiRelaxationMethod
JablonowskiRelaxation(SG::SpectralGrid; kwargs...) -> Any
-

create a JablonowskiRelaxation temperature relaxation with arrays allocated given spectral_grid

source
SpeedyWeather.KeepbitsType

Number of mantissa bits to keep for each prognostic variable when compressed for netCDF and .jld2 data output.

  • u::Int64

  • v::Int64

  • vor::Int64

  • div::Int64

  • temp::Int64

  • pres::Int64

  • humid::Int64

  • precip_cond::Int64

  • precip_conv::Int64

source
SpeedyWeather.LeapfrogType

Leapfrog time stepping defined by the following fields

  • trunc::Int64: spectral resolution (max degree of spherical harmonics)

  • Δt_at_T31::Float64: time step in minutes for T31, scale linearly to trunc

  • radius::Any: radius of sphere [m], used for scaling

  • robert_filter::Any: Robert (1966) time filter coefficeint to suppress comput. mode

  • williams_filter::Any: Williams time filter (Amezcua 2011) coefficient for 3rd order acc

  • Δt_sec::Int64: time step Δt [s] at specified resolution

  • Δt::Any: time step Δt [s/m] at specified resolution, scaled by 1/radius

  • Δt_hrs::Float64: convert time step Δt from minutes to hours

source
SpeedyWeather.LeapfrogMethod
Leapfrog(spectral_grid::SpectralGrid; kwargs...) -> Any
-

Generator function for a Leapfrog struct using spectral_grid for the resolution information.

source
SpeedyWeather.LinearDragType

Linear boundary layer drag Following Held and Suarez, 1996 BAMS

  • σb::Float64

  • time_scale::Float64

  • nlev::Int64

  • drag_coefs::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.MagnusCoefsType

Parameters for computing saturation vapour pressure using the August-Roche-Magnus formula,

eᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),

where T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively.

  • e₀::AbstractFloat: Saturation vapour pressure at 0°C [Pa]

  • T₀::AbstractFloat: 0°C in Kelvin

  • T₁::AbstractFloat

  • T₂::AbstractFloat

  • C₁::AbstractFloat

  • C₂::AbstractFloat

source
SpeedyWeather.NoOrographyType

Orography with zero height in orography and zero surface geopotential geopot_surf.

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.NoOrographyMethod
NoOrography(spectral_grid::SpectralGrid) -> NoOrography
-

Generator function pulling the resolution information from spectral_grid.

source
SpeedyWeather.OutputWriterType

NetCDF output writer. Contains all output options and auxiliary fields for output interpolation. To be initialised with OutputWriter(::SpectralGrid,::Type{<:ModelSetup},kwargs...) to pass on the resolution information and the model type which chooses which variables to output. Options include

  • spectral_grid::SpectralGrid

  • output::Bool

  • path::String: [OPTION] path to output folder, run_???? will be created within

  • id::String: [OPTION] run identification number/string

  • run_path::String

  • filename::String: [OPTION] name of the output netcdf file

  • write_restart::Bool: [OPTION] also write restart file if output==true?

  • pkg_version::VersionNumber

  • startdate::Dates.DateTime

  • output_dt::Float64: [OPTION] output frequency, time step [hrs]

  • output_dt_sec::Int64: actual output time step [sec]

  • output_vars::Vector{Symbol}: [OPTION] which variables to output, u, v, vor, div, pres, temp, humid

  • missing_value::Union{Float32, Float64}: [OPTION] missing value to be used in netcdf output

  • compression_level::Int64: [OPTION] lossless compression level; 1=low but fast, 9=high but slow

  • keepbits::SpeedyWeather.Keepbits: [OPTION] mantissa bits to keep for every variable

  • output_every_n_steps::Int64

  • timestep_counter::Int64

  • output_counter::Int64

  • netcdf_file::Union{Nothing, NetCDF.NcFile}

  • input_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}

  • as_matrix::Bool: [OPTION] sort grid points into a matrix (interpolation-free), for OctahedralClenshawGrid, OctaHEALPixGrid only

  • quadrant_rotation::NTuple{4, Int64}

  • matrix_quadrant::NTuple{4, Tuple{Int64, Int64}}

  • output_Grid::Type{<:SpeedyWeather.RingGrids.AbstractFullGrid}: [OPTION] the grid used for output, full grids only

  • nlat_half::Int64: [OPTION] the resolution of the output grid, default: same nlat_half as in the dynamical core

  • nlon::Int64

  • nlat::Int64

  • npoints::Int64

  • nlev::Int64

  • interpolator::SpeedyWeather.RingGrids.AbstractInterpolator

  • u::Matrix{NF} where NF<:Union{Float32, Float64}

  • v::Matrix{NF} where NF<:Union{Float32, Float64}

  • vor::Matrix{NF} where NF<:Union{Float32, Float64}

  • div::Matrix{NF} where NF<:Union{Float32, Float64}

  • temp::Matrix{NF} where NF<:Union{Float32, Float64}

  • pres::Matrix{NF} where NF<:Union{Float32, Float64}

  • humid::Matrix{NF} where NF<:Union{Float32, Float64}

  • precip_cond::Matrix{NF} where NF<:Union{Float32, Float64}

  • precip_conv::Matrix{NF} where NF<:Union{Float32, Float64}

source
SpeedyWeather.PrimitiveDryModelType

The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • physics::Bool

  • boundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat

  • temperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat

  • static_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.PrimitiveWetModelType

The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • physics::Bool

  • thermodynamics::SpeedyWeather.Thermodynamics{NF} where NF<:AbstractFloat

  • boundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat

  • temperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat

  • static_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat

  • large_scale_condensation::SpeedyWeather.AbstractCondensation{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.ShallowWaterModelType

The ShallowWaterModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • forcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.SimulationType

Simulation is a container struct to be used with run!(::Simulation). It contains

  • prognostic_variables::PrognosticVariables: define the current state of the model

  • diagnostic_variables::DiagnosticVariables: contain the tendencies and auxiliary arrays to compute them

  • model::SpeedyWeather.ModelSetup: all parameters, constant at runtime

source
SpeedyWeather.SpectralGridType

Defines the horizontal spectral resolution and corresponding grid and the vertical coordinate for SpeedyWeather.jl. Options are

  • NF::Type{<:AbstractFloat}: number format used throughout the model

  • trunc::Int64: horizontal resolution as the maximum degree of spherical harmonics

  • Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: horizontal grid used for calculations in grid-point space

  • dealiasing::Float64: how to match spectral with grid resolution: dealiasing factor, 1=linear, 2=quadratic, 3=cubic grid

  • radius::Float64: radius of the sphere [m]

  • nlat_half::Int64: number of latitude rings on one hemisphere (Equator incl)

  • npoints::Int64: total number of grid points in the horizontal

  • nlev::Int64: number of vertical levels

  • vertical_coordinates::SpeedyWeather.VerticalCoordinates: coordinates used to discretize the vertical

nlat_half and npoints should not be chosen but are derived from trunc, Grid and dealiasing.

source
SpeedyWeather.SpeedyCondensationType

Large scale condensation as in Fortran SPEEDY with default values from therein.

  • nlev::Int64: number of vertical levels

  • threshold_boundary_layer::Float64: Relative humidity threshold for boundary layer

  • threshold_range::Float64: Vertical range of relative humidity threshold

  • threshold_max::Float64: Maximum relative humidity threshold [1]

  • time_scale::Float64: Relaxation time for humidity [hrs]

  • n_stratosphere_levels::Base.RefValue{Int64}

  • humid_tend_max::Vector{NF} where NF<:AbstractFloat

  • relative_threshold::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.JablonowskiRelaxationMethod
JablonowskiRelaxation(SG::SpectralGrid; kwargs...) -> Any
+

create a JablonowskiRelaxation temperature relaxation with arrays allocated given spectral_grid

source
SpeedyWeather.KeepbitsType

Number of mantissa bits to keep for each prognostic variable when compressed for netCDF and .jld2 data output.

  • u::Int64

  • v::Int64

  • vor::Int64

  • div::Int64

  • temp::Int64

  • pres::Int64

  • humid::Int64

  • precip_cond::Int64

  • precip_conv::Int64

source
SpeedyWeather.LeapfrogType

Leapfrog time stepping defined by the following fields

  • trunc::Int64: spectral resolution (max degree of spherical harmonics)

  • Δt_at_T31::Float64: time step in minutes for T31, scale linearly to trunc

  • radius::Any: radius of sphere [m], used for scaling

  • robert_filter::Any: Robert (1966) time filter coefficeint to suppress comput. mode

  • williams_filter::Any: Williams time filter (Amezcua 2011) coefficient for 3rd order acc

  • Δt_sec::Int64: time step Δt [s] at specified resolution

  • Δt::Any: time step Δt [s/m] at specified resolution, scaled by 1/radius

  • Δt_hrs::Float64: convert time step Δt from minutes to hours

source
SpeedyWeather.LeapfrogMethod
Leapfrog(spectral_grid::SpectralGrid; kwargs...) -> Any
+

Generator function for a Leapfrog struct using spectral_grid for the resolution information.

source
SpeedyWeather.LinearDragType

Linear boundary layer drag Following Held and Suarez, 1996 BAMS

  • σb::Float64

  • time_scale::Float64

  • nlev::Int64

  • drag_coefs::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.MagnusCoefsType

Parameters for computing saturation vapour pressure using the August-Roche-Magnus formula,

eᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),

where T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively.

  • e₀::AbstractFloat: Saturation vapour pressure at 0°C [Pa]

  • T₀::AbstractFloat: 0°C in Kelvin

  • T₁::AbstractFloat

  • T₂::AbstractFloat

  • C₁::AbstractFloat

  • C₂::AbstractFloat

source
SpeedyWeather.NoOrographyType

Orography with zero height in orography and zero surface geopotential geopot_surf.

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.NoOrographyMethod
NoOrography(spectral_grid::SpectralGrid) -> NoOrography
+

Generator function pulling the resolution information from spectral_grid.

source
SpeedyWeather.OutputWriterType

NetCDF output writer. Contains all output options and auxiliary fields for output interpolation. To be initialised with OutputWriter(::SpectralGrid,::Type{<:ModelSetup},kwargs...) to pass on the resolution information and the model type which chooses which variables to output. Options include

  • spectral_grid::SpectralGrid

  • output::Bool

  • path::String: [OPTION] path to output folder, run_???? will be created within

  • id::String: [OPTION] run identification number/string

  • run_path::String

  • filename::String: [OPTION] name of the output netcdf file

  • write_restart::Bool: [OPTION] also write restart file if output==true?

  • pkg_version::VersionNumber

  • startdate::Dates.DateTime

  • output_dt::Float64: [OPTION] output frequency, time step [hrs]

  • output_dt_sec::Int64: actual output time step [sec]

  • output_vars::Vector{Symbol}: [OPTION] which variables to output, u, v, vor, div, pres, temp, humid

  • missing_value::Union{Float32, Float64}: [OPTION] missing value to be used in netcdf output

  • compression_level::Int64: [OPTION] lossless compression level; 1=low but fast, 9=high but slow

  • keepbits::SpeedyWeather.Keepbits: [OPTION] mantissa bits to keep for every variable

  • output_every_n_steps::Int64

  • timestep_counter::Int64

  • output_counter::Int64

  • netcdf_file::Union{Nothing, NetCDF.NcFile}

  • input_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}

  • as_matrix::Bool: [OPTION] sort grid points into a matrix (interpolation-free), for OctahedralClenshawGrid, OctaHEALPixGrid only

  • quadrant_rotation::NTuple{4, Int64}

  • matrix_quadrant::NTuple{4, Tuple{Int64, Int64}}

  • output_Grid::Type{<:SpeedyWeather.RingGrids.AbstractFullGrid}: [OPTION] the grid used for output, full grids only

  • nlat_half::Int64: [OPTION] the resolution of the output grid, default: same nlat_half as in the dynamical core

  • nlon::Int64

  • nlat::Int64

  • npoints::Int64

  • nlev::Int64

  • interpolator::SpeedyWeather.RingGrids.AbstractInterpolator

  • u::Matrix{NF} where NF<:Union{Float32, Float64}

  • v::Matrix{NF} where NF<:Union{Float32, Float64}

  • vor::Matrix{NF} where NF<:Union{Float32, Float64}

  • div::Matrix{NF} where NF<:Union{Float32, Float64}

  • temp::Matrix{NF} where NF<:Union{Float32, Float64}

  • pres::Matrix{NF} where NF<:Union{Float32, Float64}

  • humid::Matrix{NF} where NF<:Union{Float32, Float64}

  • precip_cond::Matrix{NF} where NF<:Union{Float32, Float64}

  • precip_conv::Matrix{NF} where NF<:Union{Float32, Float64}

source
SpeedyWeather.PrimitiveDryModelType

The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • physics::Bool

  • boundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat

  • temperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat

  • static_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.PrimitiveWetModelType

The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • physics::Bool

  • thermodynamics::SpeedyWeather.Thermodynamics{NF} where NF<:AbstractFloat

  • boundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat

  • temperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat

  • static_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat

  • large_scale_condensation::SpeedyWeather.AbstractCondensation{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.ShallowWaterModelType

The ShallowWaterModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.

  • spectral_grid::SpectralGrid: dictates resolution for many other components

  • planet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics

  • atmosphere::SpeedyWeather.AbstractAtmosphere

  • forcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat

  • initial_conditions::SpeedyWeather.InitialConditions

  • orography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat

  • time_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat

  • spectral_transform::SpectralTransform

  • horizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat

  • implicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat

  • geometry::Geometry

  • constants::DynamicsConstants

  • device_setup::SpeedyWeather.DeviceSetup

  • output::SpeedyWeather.AbstractOutputWriter

  • feedback::SpeedyWeather.AbstractFeedback

source
SpeedyWeather.SimulationType

Simulation is a container struct to be used with run!(::Simulation). It contains

  • prognostic_variables::PrognosticVariables: define the current state of the model

  • diagnostic_variables::DiagnosticVariables: contain the tendencies and auxiliary arrays to compute them

  • model::SpeedyWeather.ModelSetup: all parameters, constant at runtime

source
SpeedyWeather.SpectralGridType

Defines the horizontal spectral resolution and corresponding grid and the vertical coordinate for SpeedyWeather.jl. Options are

  • NF::Type{<:AbstractFloat}: number format used throughout the model

  • trunc::Int64: horizontal resolution as the maximum degree of spherical harmonics

  • Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: horizontal grid used for calculations in grid-point space

  • dealiasing::Float64: how to match spectral with grid resolution: dealiasing factor, 1=linear, 2=quadratic, 3=cubic grid

  • radius::Float64: radius of the sphere [m]

  • nlat_half::Int64: number of latitude rings on one hemisphere (Equator incl)

  • npoints::Int64: total number of grid points in the horizontal

  • nlev::Int64: number of vertical levels

  • vertical_coordinates::SpeedyWeather.VerticalCoordinates: coordinates used to discretize the vertical

nlat_half and npoints should not be chosen but are derived from trunc, Grid and dealiasing.

source
SpeedyWeather.SpeedyCondensationType

Large scale condensation as in Fortran SPEEDY with default values from therein.

  • nlev::Int64: number of vertical levels

  • threshold_boundary_layer::Float64: Relative humidity threshold for boundary layer

  • threshold_range::Float64: Vertical range of relative humidity threshold

  • threshold_max::Float64: Maximum relative humidity threshold [1]

  • time_scale::Float64: Relaxation time for humidity [hrs]

  • n_stratosphere_levels::Base.RefValue{Int64}

  • humid_tend_max::Vector{NF} where NF<:AbstractFloat

  • relative_threshold::Vector{NF} where NF<:AbstractFloat

source
SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
SpectralTransform(
     spectral_grid::SpectralGrid;
     recompute_legendre,
     one_more_degree,
     kwargs...
 ) -> SpectralTransform
-

Generator function for a SpectralTransform struct pulling in parameters from a SpectralGrid struct.

source
SpeedyWeather.StartFromFileType

Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical. restart.jld2 is identified by

  • path::String: path for restart file

  • id::Union{Int64, String}: run_id of restart file in run_????/restart.jld2

source
SpeedyWeather.StartWithRandomVorticityType

Start with random vorticity as initial conditions

  • power::Float64: Power of the spectral distribution k^power

  • amplitude::Float64: (approximate) amplitude in [1/s], used as standard deviation of spherical harmonic coefficients

source
SpeedyWeather.StaticEnergyDiffusionType

Diffusion of dry static energy: A relaxation towards a reference gradient of static energy wrt to geopotential, see Fortran SPEEDY documentation.

  • time_scale::Float64: time scale [hrs] for strength

  • static_energy_lapse_rate::Float64: [1] ∂SE/∂Φ, vertical gradient of static energy SE with geopotential Φ

  • Fstar::Base.RefValue{NF} where NF<:AbstractFloat

source
SpeedyWeather.TendenciesType
Tendencies{Grid<:AbstractGrid,NF<:AbstractFloat}

Struct holding the tendencies of the prognostic spectral variables for a given layer.

source
SpeedyWeather.ZonalJetType

Create a struct that contains all parameters for the Galewsky et al, 2004 zonal jet intitial conditions for the shallow water model. Default values as in Galewsky.

  • latitude::Float64: jet latitude [˚N]

  • width::Float64: jet width [˚], default ≈ 19.29˚

  • umax::Float64: jet maximum velocity [m/s]

  • perturb_lat::Float64: perturbation latitude [˚N], position in jet by default

  • perturb_lon::Float64: perturbation longitude [˚E]

  • perturb_xwidth::Float64: perturbation zonal extent [˚], default ≈ 19.1˚

  • perturb_ywidth::Float64: perturbation meridinoal extent [˚], default ≈ 3.8˚

  • perturb_height::Float64: perturbation amplitude [m]

source
SpeedyWeather.ZonalRidgeType

Zonal ridge orography after Jablonowski and Williamson, 2006.

  • η₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates

  • u₀::Float64: max amplitude of zonal wind [m/s] that scales orography height

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.ZonalRidgeMethod
ZonalRidge(spectral_grid::SpectralGrid; kwargs...) -> Any
-

Generator function pulling the resolution information from spectral_grid.

source
SpeedyWeather.ZonalWindType

Create a struct that contains all parameters for the Jablonowski and Williamson, 2006 intitial conditions for the primitive equation model. Default values as in Jablonowski.

  • η₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates

  • u₀::Float64: max amplitude of zonal wind [m/s]

  • perturb_lat::Float64: perturbation centred at [˚N]

  • perturb_lon::Float64: perturbation centred at [˚E]

  • perturb_uₚ::Float64: perturbation strength [m/s]

  • perturb_radius::Float64: radius of Gaussian perturbation in units of Earth's radius [1]

  • ΔT::Float64: temperature difference used for stratospheric lapse rate [K], Jablonowski uses ΔT = 4.8e5 [K]

  • Tmin::Float64: minimum temperature [K] of profile

  • pressure_on_orography::Bool: initialize pressure given the atmosphere.lapse_rate on orography?

source
Base.copy!Method
copy!(progn_new::PrognosticVariables, progn_old::PrognosticVariables)

Copies entries of progn_old into progn_new. Only copies those variables that are present in the model of both progn_new and progn_old.

source
SpeedyWeather.DeviceMethod
Device()

Return default used device for internal purposes, either CPUDevice or GPUDevice if a GPU is available.

source
SpeedyWeather.DeviceArrayMethod
DeviceArray(device::AbstractDevice, x)

Adapts x to a CuArray when device<:GPUDevice is used, otherwise a regular Array. Uses adapt, thus also can return SubArrays etc.

source
SpeedyWeather.DeviceArrayNotAdaptMethod
DeviceArrayNotAdapt(device::AbstractDevice, x)

Returns a CuArray when device<:GPUDevice is used, otherwise a regular Array. Doesn't uses adapt, therefore always returns CuArray/Array

source
SpeedyWeather.StartFromFileType

Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical. restart.jld2 is identified by

  • path::String: path for restart file

  • id::Union{Int64, String}: run_id of restart file in run_????/restart.jld2

source
SpeedyWeather.StartWithRandomVorticityType

Start with random vorticity as initial conditions

  • power::Float64: Power of the spectral distribution k^power

  • amplitude::Float64: (approximate) amplitude in [1/s], used as standard deviation of spherical harmonic coefficients

source
SpeedyWeather.StaticEnergyDiffusionType

Diffusion of dry static energy: A relaxation towards a reference gradient of static energy wrt to geopotential, see Fortran SPEEDY documentation.

  • time_scale::Float64: time scale [hrs] for strength

  • static_energy_lapse_rate::Float64: [1] ∂SE/∂Φ, vertical gradient of static energy SE with geopotential Φ

  • Fstar::Base.RefValue{NF} where NF<:AbstractFloat

source
SpeedyWeather.TendenciesType
Tendencies{Grid<:AbstractGrid,NF<:AbstractFloat}

Struct holding the tendencies of the prognostic spectral variables for a given layer.

source
SpeedyWeather.ZonalJetType

Create a struct that contains all parameters for the Galewsky et al, 2004 zonal jet intitial conditions for the shallow water model. Default values as in Galewsky.

  • latitude::Float64: jet latitude [˚N]

  • width::Float64: jet width [˚], default ≈ 19.29˚

  • umax::Float64: jet maximum velocity [m/s]

  • perturb_lat::Float64: perturbation latitude [˚N], position in jet by default

  • perturb_lon::Float64: perturbation longitude [˚E]

  • perturb_xwidth::Float64: perturbation zonal extent [˚], default ≈ 19.1˚

  • perturb_ywidth::Float64: perturbation meridinoal extent [˚], default ≈ 3.8˚

  • perturb_height::Float64: perturbation amplitude [m]

source
SpeedyWeather.ZonalRidgeType

Zonal ridge orography after Jablonowski and Williamson, 2006.

  • η₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates

  • u₀::Float64: max amplitude of zonal wind [m/s] that scales orography height

  • orography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.

  • geopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]

source
SpeedyWeather.ZonalRidgeMethod
ZonalRidge(spectral_grid::SpectralGrid; kwargs...) -> Any
+

Generator function pulling the resolution information from spectral_grid.

source
SpeedyWeather.ZonalWindType

Create a struct that contains all parameters for the Jablonowski and Williamson, 2006 intitial conditions for the primitive equation model. Default values as in Jablonowski.

  • η₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates

  • u₀::Float64: max amplitude of zonal wind [m/s]

  • perturb_lat::Float64: perturbation centred at [˚N]

  • perturb_lon::Float64: perturbation centred at [˚E]

  • perturb_uₚ::Float64: perturbation strength [m/s]

  • perturb_radius::Float64: radius of Gaussian perturbation in units of Earth's radius [1]

  • ΔT::Float64: temperature difference used for stratospheric lapse rate [K], Jablonowski uses ΔT = 4.8e5 [K]

  • Tmin::Float64: minimum temperature [K] of profile

  • pressure_on_orography::Bool: initialize pressure given the atmosphere.lapse_rate on orography?

source
Base.copy!Method
copy!(progn_new::PrognosticVariables, progn_old::PrognosticVariables)

Copies entries of progn_old into progn_new. Only copies those variables that are present in the model of both progn_new and progn_old.

source
SpeedyWeather.DeviceMethod
Device()

Return default used device for internal purposes, either CPUDevice or GPUDevice if a GPU is available.

source
SpeedyWeather.DeviceArrayMethod
DeviceArray(device::AbstractDevice, x)

Adapts x to a CuArray when device<:GPUDevice is used, otherwise a regular Array. Uses adapt, thus also can return SubArrays etc.

source
SpeedyWeather.DeviceArrayNotAdaptMethod
DeviceArrayNotAdapt(device::AbstractDevice, x)

Returns a CuArray when device<:GPUDevice is used, otherwise a regular Array. Doesn't uses adapt, therefore always returns CuArray/Array

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
     diagn::DiagnosticVariables,
     progn::PrognosticVariables,
     lf::Int64,
     model::SpeedyWeather.ModelSetup
 )
-

Propagate the spectral state of progn to diagn using time step/leapfrog index lf. Function barrier that calls gridded! for the respective model.

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     lf::Int64,
     model::Barotropic
 )
-

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the barotropic vorticity model. Updates grid vorticity, spectral stream function and spectral and grid velocities u,v.

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
+

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the barotropic vorticity model. Updates grid vorticity, spectral stream function and spectral and grid velocities u,v.

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     lf::Int64,
     model::PrimitiveEquation
 )
-

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for primitive equation models. Updates grid vorticity, grid divergence, grid temperature, pressure (pres_grid) and the velocities u,v.

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
+

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for primitive equation models. Updates grid vorticity, grid divergence, grid temperature, pressure (pres_grid) and the velocities u,v.

source
SpeedyWeather.SpeedyTransforms.gridded!Method
gridded!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     lf::Int64,
     model::ShallowWater
 )
-

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the shallow water model. Updates grid vorticity, grid divergence, grid interface displacement (pres_grid) and the velocities u,v.

source
SpeedyWeather._scale_lat!Method
_scale_lat!(
+

Propagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the shallow water model. Updates grid vorticity, grid divergence, grid interface displacement (pres_grid) and the velocities u,v.

source
SpeedyWeather._scale_lat!Method
_scale_lat!(
     A::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},
     v::AbstractVector
 )
-

Generic latitude scaling applied to A in-place with latitude-like vector v.

source
SpeedyWeather.allocateMethod
allocate(
     _::Type{PrognosticVariables},
     spectral_grid::SpectralGrid,
     _::Type{Model<:SpeedyWeather.ModelSetup}
 ) -> PrognosticVariables
-
source
SpeedyWeather.bernoulli_potential!Method
bernoulli_potential!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},
     S::SpectralTransform
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Computes the Laplace operator ∇² of the Bernoulli potential B in spectral space.

  1. computes the kinetic energy KE = ½(u²+v²) on the grid
  2. transforms KE to spectral space
  3. adds geopotential for the Bernoulli potential in spectral space
  4. takes the Laplace operator.

This version is used for both ShallowWater and PrimitiveEquation, only the geopotential calculation in geopotential! differs.

source
SpeedyWeather.boundary_layer_drag!Method
boundary_layer_drag!(
+

Computes the Laplace operator ∇² of the Bernoulli potential B in spectral space.

  1. computes the kinetic energy KE = ½(u²+v²) on the grid
  2. transforms KE to spectral space
  3. adds geopotential for the Bernoulli potential in spectral space
  4. takes the Laplace operator.

This version is used for both ShallowWater and PrimitiveEquation, only the geopotential calculation in geopotential! differs.

source
SpeedyWeather.boundary_layer_drag!Method
boundary_layer_drag!(
     column::ColumnVariables,
     scheme::LinearDrag
 )
-

Compute tendency for boundary layer drag of a column and add to its tendencies fields

source
SpeedyWeather.create_output_folderMethod
create_output_folder(
     path::String,
     id::Union{Int64, String}
 ) -> String
-

Creates a new folder run_* with the identification id. Also returns the full path run_path of that folder.

source
SpeedyWeather.default_sigma_coordinatesMethod
default_sigma_coordinates(nlev::Integer) -> Any
-

Vertical sigma coordinates defined by their nlev+1 half levels σ_levels_half. Sigma coordinates are fraction of surface pressure (p/p0) and are sorted from top (stratosphere) to bottom (surface). The first half level is at 0 the last at 1. Evaluate a generalised logistic function with coefficients in P for the distribution of values in between. Default coefficients follow the L31 configuration historically used at ECMWF.

source
SpeedyWeather.default_sigma_coordinatesMethod
default_sigma_coordinates(nlev::Integer) -> Any
+

Vertical sigma coordinates defined by their nlev+1 half levels σ_levels_half. Sigma coordinates are fraction of surface pressure (p/p0) and are sorted from top (stratosphere) to bottom (surface). The first half level is at 0 the last at 1. Evaluate a generalised logistic function with coefficients in P for the distribution of values in between. Default coefficients follow the L31 configuration historically used at ECMWF.

source
SpeedyWeather.dry_static_energy!Method
dry_static_energy!(
     column::ColumnVariables,
     constants::DynamicsConstants
 )
-

Compute the dry static energy SE = cₚT + Φ (latent heat times temperature plus geopotential) for the column.

source
SpeedyWeather.dynamics_tendencies!Function
dynamics_tendencies!(
     diagn::DiagnosticVariables,
     progn::PrognosticVariables,
     model::PrimitiveEquation
@@ -98,25 +98,25 @@
     model::PrimitiveEquation,
     lf::Int64
 ) -> Any
-

Calculate all tendencies for the PrimitiveEquation model (wet or dry).

source
SpeedyWeather.dynamics_tendencies!Method
dynamics_tendencies!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     time::Dates.DateTime,
     model::Barotropic
 )
-

Calculate all tendencies for the BarotropicModel.

source
SpeedyWeather.dynamics_tendencies!Method
dynamics_tendencies!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     surface::SpeedyWeather.SurfaceVariables,
     pres::LowerTriangularMatrix,
     time::Dates.DateTime,
     model::ShallowWater
 )
-

Calculate all tendencies for the ShallowWaterModel.

source
SpeedyWeather.first_timesteps!Method
first_timesteps!(
     progn::PrognosticVariables,
     diagn::DiagnosticVariables,
     model::SpeedyWeather.ModelSetup,
     output::SpeedyWeather.AbstractOutputWriter
 ) -> typeof(time)
-

Performs the first two initial time steps (Euler forward, unfiltered leapfrog) to populate the prognostic variables with two time steps (t=0,Δt) that can then be used in the normal leap frogging.

source
SpeedyWeather.flux_divergence!Method
flux_divergence!(
+

Performs the first two initial time steps (Euler forward, unfiltered leapfrog) to populate the prognostic variables with two time steps (t=0,Δt) that can then be used in the normal leap frogging.

source
SpeedyWeather.flux_divergence!Method
flux_divergence!(
     A_tend::LowerTriangularMatrix{Complex{NF}},
     A_grid::SpeedyWeather.RingGrids.AbstractGrid{NF},
     diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},
@@ -125,66 +125,66 @@
     add,
     flipsign
 )
-

Computes ∇⋅((u,v)*A) with the option to add/overwrite A_tend and to flip_sign of the flux divergence by doing so.

  • A_tend = ∇⋅((u,v)*A) for add=false, flip_sign=false
  • A_tend = -∇⋅((u,v)*A) for add=false, flip_sign=true
  • A_tend += ∇⋅((u,v)*A) for add=true, flip_sign=false
  • A_tend -= ∇⋅((u,v)*A) for add=true, flip_sign=true
source
SpeedyWeather.fluxes_to_tendencies!Method
fluxes_to_tendencies!(
+

Computes ∇⋅((u,v)*A) with the option to add/overwrite A_tend and to flip_sign of the flux divergence by doing so.

  • A_tend = ∇⋅((u,v)*A) for add=false, flip_sign=false
  • A_tend = -∇⋅((u,v)*A) for add=false, flip_sign=true
  • A_tend += ∇⋅((u,v)*A) for add=true, flip_sign=false
  • A_tend -= ∇⋅((u,v)*A) for add=true, flip_sign=true
source
SpeedyWeather.fluxes_to_tendencies!Method
fluxes_to_tendencies!(
     column::ColumnVariables,
     geometry::Geometry,
     constants::DynamicsConstants
 )
-

Convert the fluxes on half levels to tendencies on full levels.

source
SpeedyWeather.geopotential!Method
geopotential!(
     diagn::DiagnosticVariables,
     O::SpeedyWeather.AbstractOrography,
     C::DynamicsConstants
 )
-

Compute spectral geopotential geopot from spectral temperature temp and spectral surface geopotential geopot_surf (orography*gravity).

source
SpeedyWeather.geopotential!Method
geopotential!(
+

Compute spectral geopotential geopot from spectral temperature temp and spectral surface geopotential geopot_surf (orography*gravity).

source
SpeedyWeather.geopotential!Method
geopotential!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     pres::LowerTriangularMatrix,
     C::DynamicsConstants
 ) -> Any
-

calculates the geopotential in the ShallowWaterModel as g*η, i.e. gravity times the interface displacement (field pres)

source
SpeedyWeather.geopotential!Method
geopotential!(temp::Vector, C::DynamicsConstants) -> Vector
-

Calculate the geopotential based on temp in a single column. This exclues the surface geopotential that would need to be added to the returned vector. Function not used in the dynamical core but for post-processing and analysis.

source
SpeedyWeather.get_column!Method
get_column!(
+

calculates the geopotential in the ShallowWaterModel as g*η, i.e. gravity times the interface displacement (field pres)

source
SpeedyWeather.geopotential!Method
geopotential!(temp::Vector, C::DynamicsConstants) -> Vector
+

Calculate the geopotential based on temp in a single column. This exclues the surface geopotential that would need to be added to the returned vector. Function not used in the dynamical core but for post-processing and analysis.

source
SpeedyWeather.get_column!Method
get_column!(
     C::ColumnVariables,
     D::DiagnosticVariables,
     ij::Integer,
     jring::Integer,
     G::Geometry
 )
-

Update C::ColumnVariables by copying the prognostic variables from D::DiagnosticVariables at gridpoint index ij. Provide G::Geometry for coordinate information.

source
SpeedyWeather.get_run_idMethod
get_run_id(path::String, id::String) -> String
-

Checks existing run_???? folders in path to determine a 4-digit id number by counting up. E.g. if folder run_0001 exists it will return the string "0002". Does not create a folder for the returned run id.

source
SpeedyWeather.get_thermodynamics!Method
get_thermodynamics!(
+

Update C::ColumnVariables by copying the prognostic variables from D::DiagnosticVariables at gridpoint index ij. Provide G::Geometry for coordinate information.

source
SpeedyWeather.get_run_idMethod
get_run_id(path::String, id::String) -> String
+

Checks existing run_???? folders in path to determine a 4-digit id number by counting up. E.g. if folder run_0001 exists it will return the string "0002". Does not create a folder for the returned run id.

source
SpeedyWeather.get_thermodynamics!Method
get_thermodynamics!(
     column::ColumnVariables,
     model::PrimitiveWet
 )
-

Calculate thermodynamic quantities like saturation vapour pressure, saturation specific humidity, dry static energy, moist static energy and saturation moist static energy from the prognostic column variables.

source
SpeedyWeather.get_varMethod
get_var(progn::PrognosticVariables, var_name::Symbol; lf::Integer=1)

Returns the prognostic variable var_name at leapfrog index lf as a Vector{LowerTriangularMatrices}.

source
SpeedyWeather.hasMethod
has(
+

Calculate thermodynamic quantities like saturation vapour pressure, saturation specific humidity, dry static energy, moist static energy and saturation moist static energy from the prognostic column variables.

source
SpeedyWeather.get_varMethod
get_var(progn::PrognosticVariables, var_name::Symbol; lf::Integer=1)

Returns the prognostic variable var_name at leapfrog index lf as a Vector{LowerTriangularMatrices}.

source
SpeedyWeather.hasMethod
has(
     M::Type{<:SpeedyWeather.ModelSetup},
     var_name::Symbol
 ) -> Bool
-

Returns true if the model M has a prognostic variable var_name, false otherwise. The default fallback is that all variables are included.

source
SpeedyWeather.horizontal_diffusion!Function
horizontal_diffusion!(
+

Returns true if the model M has a prognostic variable var_name, false otherwise. The default fallback is that all variables are included.

source
SpeedyWeather.horizontal_diffusion!Function
horizontal_diffusion!(
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
-    model::ShallowWater
-)
+    model::PrimitiveEquation
+) -> Union{Nothing, Bool}
 horizontal_diffusion!(
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
-    model::ShallowWater,
+    model::PrimitiveEquation,
     lf::Int64
-)
-

Apply horizontal diffusion to vorticity and diffusion in the ShallowWater models.

source
SpeedyWeather.horizontal_diffusion!Function
horizontal_diffusion!(
+) -> Union{Nothing, Bool}
+

Apply horizontal diffusion applied to vorticity, diffusion and temperature in the PrimitiveEquation models. Uses the constant diffusion for temperature but possibly adaptive diffusion for vorticity and divergence.

source
SpeedyWeather.horizontal_diffusion!Function
horizontal_diffusion!(
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
-    model::PrimitiveEquation
-) -> Union{Nothing, Bool}
+    model::ShallowWater
+)
 horizontal_diffusion!(
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
-    model::PrimitiveEquation,
+    model::ShallowWater,
     lf::Int64
-) -> Union{Nothing, Bool}
-

Apply horizontal diffusion applied to vorticity, diffusion and temperature in the PrimitiveEquation models. Uses the constant diffusion for temperature but possibly adaptive diffusion for vorticity and divergence.

source
SpeedyWeather.horizontal_diffusion!Function
horizontal_diffusion!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     model::Barotropic
@@ -195,46 +195,46 @@
     model::Barotropic,
     lf::Int64
 )
-

Apply horizontal diffusion to vorticity in the Barotropic models.

source
SpeedyWeather.horizontal_diffusion!Method
horizontal_diffusion!(
     tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},
     A::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},
     ∇²ⁿ_expl::AbstractArray{NF<:AbstractFloat, 1},
     ∇²ⁿ_impl::AbstractArray{NF<:AbstractFloat, 1}
 )
-

Apply horizontal diffusion to a 2D field A in spectral space by updating its tendency tendency with an implicitly calculated diffusion term. The implicit diffusion of the next time step is split into an explicit part ∇²ⁿ_expl and an implicit part ∇²ⁿ_impl, such that both can be calculated in a single forward step by using A as well as its tendency tendency.

source
SpeedyWeather.implicit_correction!Method
implicit_correction!(
+

Apply horizontal diffusion to a 2D field A in spectral space by updating its tendency tendency with an implicitly calculated diffusion term. The implicit diffusion of the next time step is split into an explicit part ∇²ⁿ_expl and an implicit part ∇²ⁿ_impl, such that both can be calculated in a single forward step by using A as well as its tendency tendency.

source
SpeedyWeather.implicit_correction!Method
implicit_correction!(
     diagn::DiagnosticVariables,
     implicit::SpeedyWeather.ImplicitPrimitiveEq,
     progn::PrognosticVariables
 ) -> Any
-

Apply the implicit corrections to dampen gravity waves in the primitive equation models.

source
SpeedyWeather.implicit_correction!Method
implicit_correction!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},
     progn::SpeedyWeather.PrognosticLayerTimesteps{NF},
     diagn_surface::SpeedyWeather.SurfaceVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},
     progn_surface::SpeedyWeather.PrognosticSurfaceTimesteps{NF},
     implicit::SpeedyWeather.ImplicitShallowWater
 )
-

Apply correction to the tendencies in diagn to prevent the gravity waves from amplifying. The correction is implicitly evaluated using the parameter implicit.α to switch between forward, centered implicit or backward evaluation of the gravity wave terms.

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
+

Apply correction to the tendencies in diagn to prevent the gravity waves from amplifying. The correction is implicitly evaluated using the parameter implicit.α to switch between forward, centered implicit or backward evaluation of the gravity wave terms.

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
     progn_new::PrognosticVariables,
     initial_conditions::StartFromFile,
     model::SpeedyWeather.ModelSetup
 ) -> PrognosticVariables
-

Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical.

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
+

Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical.

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
     progn::PrognosticVariables,
     initial_conditions::ZonalJet,
     model::ShallowWater
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Initial conditions from Galewsky, 2004, Tellus

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
     progn::PrognosticVariables{NF},
     initial_conditions::StartWithRandomVorticity,
     model::SpeedyWeather.ModelSetup
 )
-

Start with random vorticity as initial conditions

source
SpeedyWeather.initial_conditions!Method
initial_conditions!(
     progn::PrognosticVariables{NF},
     initial_conditions::ZonalWind,
     model::PrimitiveEquation
 )
-

Initial conditions from Jablonowski and Williamson, 2006, QJR Meteorol. Soc

source
SpeedyWeather.initialize!Function
initialize!(
     scheme::HyperDiffusion,
     k::Int64,
     G::Geometry,
@@ -247,54 +247,54 @@
     L::SpeedyWeather.TimeStepper,
     vor_max::Real
 )
-

Precomputes the hyper diffusion terms in scheme for layer k based on the model time step in L, the vertical level sigma level in G, and the current (absolute) vorticity maximum level vor_max

source
SpeedyWeather.initialize!Method
initialize!(model::Barotropic) -> SpeedyWeather.Simulation
-

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping!.

source
SpeedyWeather.initialize!Method
initialize!(
+

Precomputes the hyper diffusion terms in scheme for layer k based on the model time step in L, the vertical level sigma level in G, and the current (absolute) vorticity maximum level vor_max

source
SpeedyWeather.initialize!Method
initialize!(model::Barotropic) -> SpeedyWeather.Simulation
+

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping!.

source
SpeedyWeather.initialize!Method
initialize!(
     orog::EarthOrography,
     P::SpeedyWeather.AbstractPlanet,
     S::SpectralTransform,
     G::Geometry
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Initialize the arrays orography,geopot_surf in orog by reading the orography field from file.

source
SpeedyWeather.initialize!Method
initialize!(
     feedback::Feedback,
     clock::SpeedyWeather.Clock,
     model::SpeedyWeather.ModelSetup
 ) -> Union{Nothing, IOStream}
-

Initializes the a Feedback struct.

source
SpeedyWeather.initialize!Method
initialize!(scheme::HeldSuarez, model::PrimitiveEquation)
-

initialize the HeldSuarez temperature relaxation by precomputing terms for the equilibrium temperature Teq.

source
SpeedyWeather.initialize!Method
initialize!(scheme::HeldSuarez, model::PrimitiveEquation)
+

initialize the HeldSuarez temperature relaxation by precomputing terms for the equilibrium temperature Teq.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::HyperDiffusion,
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     G::Geometry,
     L::SpeedyWeather.TimeStepper
 )
-

Pre-function to other initialize!(::HyperDiffusion) initialisors that calculates the (absolute) vorticity maximum for the layer of diagn.

source
SpeedyWeather.initialize!Method
initialize!(
+

Pre-function to other initialize!(::HyperDiffusion) initialisors that calculates the (absolute) vorticity maximum for the layer of diagn.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::HyperDiffusion,
     model::SpeedyWeather.ModelSetup
 )
-

Precomputes the hyper diffusion terms in scheme based on the model time step, and possibly with a changing strength/power in the vertical.

source
SpeedyWeather.initialize!Method
initialize!(
+

Precomputes the hyper diffusion terms in scheme based on the model time step, and possibly with a changing strength/power in the vertical.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::HyperDiffusion,
     L::SpeedyWeather.TimeStepper
 )
-

Precomputes the 2D hyper diffusion terms in scheme based on the model time step.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::JablonowskiRelaxation,
     model::PrimitiveEquation
 )
-

initialize the JablonowskiRelaxation temperature relaxation by precomputing terms for the equilibrium temperature Teq and the frequency (strength of relaxation).

source
SpeedyWeather.initialize!Method
initialize!(scheme::LinearDrag, model::PrimitiveEquation)
-

Precomputes the drag coefficients for this BoundaryLayerDrag scheme.

source
SpeedyWeather.initialize!Method
initialize!(
+

initialize the JablonowskiRelaxation temperature relaxation by precomputing terms for the equilibrium temperature Teq and the frequency (strength of relaxation).

source
SpeedyWeather.initialize!Method
initialize!(scheme::LinearDrag, model::PrimitiveEquation)
+

Precomputes the drag coefficients for this BoundaryLayerDrag scheme.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::NoTemperatureRelaxation,
     model::PrimitiveEquation
 )
-

just passes, does not need any initialization.

source
SpeedyWeather.initialize!Method
initialize!(model::PrimitiveDry) -> SpeedyWeather.Simulation
-

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(model::PrimitiveWet) -> SpeedyWeather.Simulation
-

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(model::ShallowWater) -> SpeedyWeather.Simulation
-

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(model::PrimitiveDry) -> SpeedyWeather.Simulation
+

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(model::PrimitiveWet) -> SpeedyWeather.Simulation
+

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(model::ShallowWater) -> SpeedyWeather.Simulation
+

Calls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.

source
SpeedyWeather.initialize!Method
initialize!(
     clock::SpeedyWeather.Clock,
     time_stepping::SpeedyWeather.TimeStepper
 ) -> SpeedyWeather.Clock
-

Initialize the clock with the time step Δt in the time_stepping.

source
SpeedyWeather.initialize!Method
initialize!(
     implicit::SpeedyWeather.ImplicitPrimitiveEq,
     i::Integer,
     dt::Real,
@@ -302,45 +302,45 @@
     geometry::Geometry,
     constants::DynamicsConstants
 )
-

Reinitialize implicit occasionally based on time step i and implicit.recalculate.

source
SpeedyWeather.initialize!Method
initialize!(
     implicit::SpeedyWeather.ImplicitPrimitiveEq,
     dt::Real,
     diagn::DiagnosticVariables,
     geometry::Geometry,
     constants::DynamicsConstants
 )
-

Initialize the implicit terms for the PrimitiveEquation models.

source
SpeedyWeather.initialize!Method
initialize!(
     implicit::SpeedyWeather.ImplicitShallowWater,
     dt::Real,
     constants::DynamicsConstants
 )
-

Update the implicit terms in implicit for the shallow water model as they depend on the time step dt.

source
SpeedyWeather.initialize!Method
initialize!(
+

Update the implicit terms in implicit for the shallow water model as they depend on the time step dt.

source
SpeedyWeather.initialize!Method
initialize!(
     orog::ZonalRidge,
     P::SpeedyWeather.AbstractPlanet,
     S::SpectralTransform,
     G::Geometry
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Initialize the arrays orography,geopot_surf in orog following Jablonowski and Williamson, 2006.

source
SpeedyWeather.initialize!Method
initialize!(
     output::OutputWriter{output_NF, Model},
     feedback::SpeedyWeather.AbstractFeedback,
     time_stepping::SpeedyWeather.TimeStepper,
     diagn::DiagnosticVariables,
     model
 )
-

Creates a netcdf file on disk and the corresponding netcdf_file object preallocated with output variables and dimensions. write_output! then writes consecuitive time steps into this file.

source
SpeedyWeather.initialize!Method
initialize!(
+

Creates a netcdf file on disk and the corresponding netcdf_file object preallocated with output variables and dimensions. write_output! then writes consecuitive time steps into this file.

source
SpeedyWeather.initialize!Method
initialize!(
     scheme::SpeedyWeather.StaticEnergyDiffusion{NF},
     model::PrimitiveEquation
 ) -> Any
-

Initialize dry static energy diffusion.

source
SpeedyWeather.initialize_geopotentialMethod
initialize_geopotential(
     σ_levels_full::Vector,
     σ_levels_half::Vector,
     R_dry::Real
 ) -> Tuple{Vector{Float64}, Vector{Float64}}
-

Precomputes constants for the vertical integration of the geopotential, defined as

Φ_{k+1/2} = Φ_{k+1} + R*T_{k+1}*(ln(p_{k+1}) - ln(p_{k+1/2})) (half levels) Φ_k = Φ_{k+1/2} + R*T_k*(ln(p_{k+1/2}) - ln(p_k)) (full levels)

Same formula but k → k-1/2.

source
SpeedyWeather.large_scale_condensation!Method
large_scale_condensation!(
+

Precomputes constants for the vertical integration of the geopotential, defined as

Φ_{k+1/2} = Φ_{k+1} + R*T_{k+1}*(ln(p_{k+1}) - ln(p_{k+1/2})) (half levels) Φ_k = Φ_{k+1/2} + R*T_k*(ln(p_{k+1/2}) - ln(p_k)) (full levels)

Same formula but k → k-1/2.

source
SpeedyWeather.large_scale_condensation!Method
large_scale_condensation!(
     column::ColumnVariables{NF},
     scheme::SpeedyCondensation,
     geometry::Geometry,
@@ -348,7 +348,7 @@
     atmosphere::SpeedyWeather.AbstractAtmosphere,
     time_stepping::SpeedyWeather.TimeStepper
 )
-

Large-scale condensation for a column by relaxation back to a reference relative humidity if larger than that. Calculates the tendencies for specific humidity and temperature and integrates the large-scale precipitation vertically for output.

source
SpeedyWeather.launch_kernel!Method
launch_kernel!(device_setup::DeviceSetup, kernel!, ndrange, kernel_args...)

Launches the kernel! on the device_setup with ndrange computations over the kernel and arguments kernel_args

source
SpeedyWeather.leapfrog!Method
leapfrog!(
+

Large-scale condensation for a column by relaxation back to a reference relative humidity if larger than that. Calculates the tendencies for specific humidity and temperature and integrates the large-scale precipitation vertically for output.

source
SpeedyWeather.launch_kernel!Method
launch_kernel!(device_setup::DeviceSetup, kernel!, ndrange, kernel_args...)

Launches the kernel! on the device_setup with ndrange computations over the kernel and arguments kernel_args

source
SpeedyWeather.leapfrog!Method
leapfrog!(
     A_old::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},
     A_new::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},
     tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},
@@ -356,139 +356,139 @@
     lf::Int64,
     L::Leapfrog{NF<:AbstractFloat}
 )
-

Performs one leapfrog time step with (lf=2) or without (lf=1) Robert+Williams filter (see Williams (2009), Montly Weather Review, Eq. 7-9).

source
SpeedyWeather.linear_pressure_gradient!Method
linear_pressure_gradient!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     surface::SpeedyWeather.PrognosticSurfaceTimesteps,
     lf::Int64,
     C::DynamicsConstants,
     I::SpeedyWeather.ImplicitPrimitiveEq
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Add the linear contribution of the pressure gradient to the geopotential. The pressure gradient in the divergence equation takes the form

-∇⋅(Rd*Tᵥ*∇lnpₛ) = -∇⋅(Rd*Tᵥ'*∇lnpₛ) - ∇²(Rd*Tₖ*lnpₛ)

So that the second term inside the Laplace operator can be added to the geopotential. Rd is the gas constant, Tᵥ the virtual temperature and Tᵥ' its anomaly wrt to the average or reference temperature Tₖ, lnpₛ is the logarithm of surface pressure.

source
SpeedyWeather.linear_virtual_temperature!Method
linear_virtual_temperature!(
+

Add the linear contribution of the pressure gradient to the geopotential. The pressure gradient in the divergence equation takes the form

-∇⋅(Rd*Tᵥ*∇lnpₛ) = -∇⋅(Rd*Tᵥ'*∇lnpₛ) - ∇²(Rd*Tₖ*lnpₛ)

So that the second term inside the Laplace operator can be added to the geopotential. Rd is the gas constant, Tᵥ the virtual temperature and Tᵥ' its anomaly wrt to the average or reference temperature Tₖ, lnpₛ is the logarithm of surface pressure.

source
SpeedyWeather.linear_virtual_temperature!Method
linear_virtual_temperature!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     constants::DynamicsConstants,
     lf::Int64
 ) -> Any
-

Calculates a linearised virtual temperature Tᵥ as

Tᵥ = T + Tₖμq

With absolute temperature T, layer-average temperarture Tₖ (computed in temperature_average!), specific humidity q and

μ = (1-ξ)/ξ, ξ = R_dry/R_vapour.

in spectral space.

source
SpeedyWeather.linear_virtual_temperature!Method
linear_virtual_temperature!(
+

Calculates a linearised virtual temperature Tᵥ as

Tᵥ = T + Tₖμq

With absolute temperature T, layer-average temperarture Tₖ (computed in temperature_average!), specific humidity q and

μ = (1-ξ)/ξ, ξ = R_dry/R_vapour.

in spectral space.

source
SpeedyWeather.linear_virtual_temperature!Method
linear_virtual_temperature!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     progn::SpeedyWeather.PrognosticLayerTimesteps,
     model::PrimitiveDry,
     lf::Integer
 ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
-

Linear virtual temperature for model::PrimitiveDry: Just copy over arrays from temp to temp_virt at timestep lf in spectral space as humidity is zero in this model.

source
SpeedyWeather.load_trajectoryMethod
load_trajectory(
+

Linear virtual temperature for model::PrimitiveDry: Just copy over arrays from temp to temp_virt at timestep lf in spectral space as humidity is zero in this model.

source
SpeedyWeather.load_trajectoryMethod
load_trajectory(
     var_name::Union{String, Symbol},
     model::SpeedyWeather.ModelSetup
 ) -> Any
-

Loads a var_name trajectory of the model M that has been saved in a netCDF file during the time stepping.

source
SpeedyWeather.moist_static_energy!Method
moist_static_energy!(
     column::ColumnVariables,
     thermodynamics::SpeedyWeather.Thermodynamics
 )
-

Compute the moist static energy

MSE = SE + Lc*Q = cₚT + Φ + Lc*Q

with the static energy SE, the latent heat of condensation Lc, the geopotential Φ. As well as the saturation moist static energy which replaces Q with Q_sat

source
SpeedyWeather.nansMethod
A = nans(T,dims...)

Allocate array A with NaNs of type T. Similar to zeros(T,dims...).

source
SpeedyWeather.nar_detection!Method
nar_detection!(
+

Compute the moist static energy

MSE = SE + Lc*Q = cₚT + Φ + Lc*Q

with the static energy SE, the latent heat of condensation Lc, the geopotential Φ. As well as the saturation moist static energy which replaces Q with Q_sat

source
SpeedyWeather.nansMethod
A = nans(T,dims...)

Allocate array A with NaNs of type T. Similar to zeros(T,dims...).

source
SpeedyWeather.nar_detection!Method
nar_detection!(
     feedback::Feedback,
     progn::PrognosticVariables
 ) -> Union{Nothing, Bool}
-

Detect NaR (Not-a-Real) in the prognostic variables.

source
SpeedyWeather.parameterization_tendencies!Method
parameterization_tendencies!(
     diagn::DiagnosticVariables,
     time::Dates.DateTime,
     model::PrimitiveEquation
 ) -> Any
-

Compute tendencies for u,v,temp,humid from physical parametrizations. Extract for each vertical atmospheric column the prognostic variables (stored in diagn as they are grid-point transformed), loop over all grid-points, compute all parametrizations on a single-column basis, then write the tendencies back into a horizontal field of tendencies.

source
SpeedyWeather.pressure_on_orography!Method
pressure_on_orography!(
+

Compute tendencies for u,v,temp,humid from physical parametrizations. Extract for each vertical atmospheric column the prognostic variables (stored in diagn as they are grid-point transformed), loop over all grid-points, compute all parametrizations on a single-column basis, then write the tendencies back into a horizontal field of tendencies.

source
SpeedyWeather.pressure_on_orography!Method
pressure_on_orography!(
     progn::PrognosticVariables,
     model::PrimitiveEquation
 )
-

Initialize surface pressure on orography by integrating the hydrostatic equation with the reference temperature lapse rate.

source
SpeedyWeather.readable_secsMethod
readable_secs(secs::Real) -> Dates.CompoundPeriod
+

Initialize surface pressure on orography by integrating the hydrostatic equation with the reference temperature lapse rate.

source
SpeedyWeather.readable_secsMethod
readable_secs(secs::Real) -> Dates.CompoundPeriod
 

Returns Dates.CompoundPeriod rounding to either (days, hours), (hours, minutes), (minutes, seconds), or seconds with 1 decimal place accuracy for >10s and two for less. E.g.

julia> readable_secs(12345)
-3 hours, 26 minutes
source
SpeedyWeather.remaining_timeMethod
remaining_time(p::ProgressMeter.Progress) -> String
-

Estimates the remaining time from a ProgresssMeter.Progress. Adapted from ProgressMeter.jl

source
SpeedyWeather.reset_column!Method
reset_column!(column::ColumnVariables{NF})
-

Set the accumulators (tendencies but also vertical sums and similar) back to zero for column to be reused at other grid points.

source
SpeedyWeather.remaining_timeMethod
remaining_time(p::ProgressMeter.Progress) -> String
+

Estimates the remaining time from a ProgresssMeter.Progress. Adapted from ProgressMeter.jl

source
SpeedyWeather.reset_column!Method
reset_column!(column::ColumnVariables{NF})
+

Set the accumulators (tendencies but also vertical sums and similar) back to zero for column to be reused at other grid points.

source
SpeedyWeather.run!Method
run!(
     simulation::SpeedyWeather.Simulation;
     initialize,
     n_days,
     startdate,
     output
 ) -> PrognosticVariables
-

Run a SpeedyWeather.jl simulation. The simulation.model is assumed to be initialized, otherwise use initialize=true as keyword argument.

source
SpeedyWeather.saturation_humidity!Method
saturation_humidity!(
+

Run a SpeedyWeather.jl simulation. The simulation.model is assumed to be initialized, otherwise use initialize=true as keyword argument.

source
SpeedyWeather.saturation_humidity!Method
saturation_humidity!(
     column::ColumnVariables,
     thermodynamics::SpeedyWeather.Thermodynamics
 )
-

Compute (1) the saturation vapour pressure as a function of temperature using the August-Roche-Magnus formula,

eᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),

where T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively. And (2) the saturation specific humidity according to the formula,

0.622 * e / (p - (1 - 0.622) * e),

where e is the saturation vapour pressure, p is the pressure, and 0.622 is the ratio of the molecular weight of water to dry air.

source
SpeedyWeather.scale!Method
scale!(progn::PrognosticVariables, scale::Real) -> Real
-

Scales the prognostic variables vorticity and divergence with the Earth's radius which is used in the dynamical core.

source
SpeedyWeather.scale!Method
scale!(
+

Compute (1) the saturation vapour pressure as a function of temperature using the August-Roche-Magnus formula,

eᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),

where T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively. And (2) the saturation specific humidity according to the formula,

0.622 * e / (p - (1 - 0.622) * e),

where e is the saturation vapour pressure, p is the pressure, and 0.622 is the ratio of the molecular weight of water to dry air.

source
SpeedyWeather.scale!Method
scale!(progn::PrognosticVariables, scale::Real) -> Real
+

Scales the prognostic variables vorticity and divergence with the Earth's radius which is used in the dynamical core.

source
SpeedyWeather.scale!Method
scale!(
     progn::PrognosticVariables{NF},
     var::Symbol,
     scale::Real
 )
-

Scale the variable var inside progn with scalar scale.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
               pressure::AbstractMatrix, 
               Grid::Type{<:AbstractGrid}, 
-              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
+              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
               pressure::LowerTriangularMatrix;
-              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in spectral space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
+              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in spectral space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
               pressure::AbstractGrid, 
               M::ModelSetup;
-              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
+              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_pressure!Method
set_pressure!(progn::PrognosticVariables{NF}, 
               pressure::AbstractGrid, 
-              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_var!Method
function set_var!(progn::PrognosticVariables{NF}, 
+              lf::Integer=1) where NF

Sets the prognostic variable with the surface pressure in grid space at leapfrog index lf.

source
SpeedyWeather.set_var!Method
function set_var!(progn::PrognosticVariables{NF}, 
                   varname::Symbol, 
                   s::Number;
-                  lf::Integer=1) where NF

Sets all values of prognostic variable varname at leapfrog index lf to the scalar s.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF}, 
+                  lf::Integer=1) where NF

Sets all values of prognostic variable varname at leapfrog index lf to the scalar s.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF}, 
          varname::Symbol, 
          var::Vector{<:AbstractMatrix}, 
          Grid::Type{<:AbstractGrid}=FullGaussianGrid;
-         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF},        
+         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF},        
          varname::Symbol, 
          var::Vector{<:LowerTriangularMatrix};
-         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in spectral space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF}, 
+         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in spectral space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF}, 
          varname::Symbol, 
          var::Vector{<:AbstractGrid}, 
          M::ModelSetup;
-         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF},        
+         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.set_var!Method
set_var!(progn::PrognosticVariables{NF},        
          varname::Symbol, 
          var::Vector{<:AbstractGrid};
-         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.speedstringMethod
speedstring(sec_per_iter, dt_in_sec) -> String
-

define a ProgressMeter.speedstring method that also takes a time step dt_in_sec to translate sec/iteration to days/days-like speeds.

source
SpeedyWeather.static_energy_diffusion!Method
static_energy_diffusion!(
+         lf::Integer=1) where NF

Sets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.

source
SpeedyWeather.speedstringMethod
speedstring(sec_per_iter, dt_in_sec) -> String
+

define a ProgressMeter.speedstring method that also takes a time step dt_in_sec to translate sec/iteration to days/days-like speeds.

source
SpeedyWeather.surface_pressure_tendency!Method
surface_pressure_tendency!( Prog::PrognosticVariables,
                             Diag::DiagnosticVariables,
                             lf::Int,
-                            M::PrimitiveEquation)

Computes the tendency of the logarithm of surface pressure as

-(ū*px + v̄*py) - D̄

with ū,v̄ being the vertically averaged velocities; px, py the gradients of the logarithm of surface pressure ln(p_s) and D̄ the vertically averaged divergence.

  1. Calculate ∇ln(p_s) in spectral space, convert to grid.
  2. Multiply ū,v̄ with ∇ln(p_s) in grid-point space, convert to spectral.
  3. D̄ is subtracted in spectral space.
  4. Set tendency of the l=m=0 mode to 0 for better mass conservation.
source
SpeedyWeather.temperature_average!Method
temperature_average!(
+                            M::PrimitiveEquation)

Computes the tendency of the logarithm of surface pressure as

-(ū*px + v̄*py) - D̄

with ū,v̄ being the vertically averaged velocities; px, py the gradients of the logarithm of surface pressure ln(p_s) and D̄ the vertically averaged divergence.

  1. Calculate ∇ln(p_s) in spectral space, convert to grid.
  2. Multiply ū,v̄ with ∇ln(p_s) in grid-point space, convert to spectral.
  3. D̄ is subtracted in spectral space.
  4. Set tendency of the l=m=0 mode to 0 for better mass conservation.
source
SpeedyWeather.temperature_average!Method
temperature_average!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     temp::LowerTriangularMatrix,
     S::SpectralTransform
 ) -> Any
-

Calculates the average temperature of a layer from the l=m=0 harmonic and stores the result in diagn.temp_average

source
SpeedyWeather.temperature_relaxation!Method
temperature_relaxation!(
     column::ColumnVariables,
     scheme::JablonowskiRelaxation
 )
-

Apply HeldSuarez-like temperature relaxation to the Jablonowski and Williamson vertical profile.

source
SpeedyWeather.temperature_tendency!Method
temperature_tendency!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     C::DynamicsConstants,
     G::Geometry,
     S::SpectralTransform,
     I::SpeedyWeather.ImplicitPrimitiveEq
 )
-

Compute the temperature tendency

∂T/∂t += -∇⋅((u,v)*T') + T'D + κTᵥ*Dlnp/Dt

+= because the tendencies already contain parameterizations and vertical advection. T' is the anomaly with respect to the reference/average temperature. Tᵥ is the virtual temperature used in the adiabatic term κTᵥ*Dlnp/Dt.

source
SpeedyWeather.temperature_tendency!Method
temperature_tendency!(
+

Compute the temperature tendency

∂T/∂t += -∇⋅((u,v)*T') + T'D + κTᵥ*Dlnp/Dt

+= because the tendencies already contain parameterizations and vertical advection. T' is the anomaly with respect to the reference/average temperature. Tᵥ is the virtual temperature used in the adiabatic term κTᵥ*Dlnp/Dt.

source
SpeedyWeather.time_stepping!Method
time_stepping!(
     progn::PrognosticVariables,
     diagn::DiagnosticVariables,
     model::SpeedyWeather.ModelSetup
 ) -> PrognosticVariables
-

Main time loop that that initializes output and feedback, loops over all time steps and calls the output and feedback functions.

source
SpeedyWeather.timestep!Function
timestep!(
+

Main time loop that that initializes output and feedback, loops over all time steps and calls the output and feedback functions.

source
SpeedyWeather.timestep!Function
timestep!(
     progn::PrognosticVariables,
     diagn::DiagnosticVariables,
     dt::Real,
@@ -512,7 +512,7 @@
     lf1::Int64,
     lf2::Int64
 )
-

Calculate a single time step for the model <: Barotropic.

source
SpeedyWeather.timestep!Method
timestep!(
     progn::PrognosticVariables{NF<:AbstractFloat},
     diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},
     dt::Real,
@@ -536,7 +536,7 @@
     lf1::Int64,
     lf2::Int64
 ) -> Any
-

Calculate a single time step for the model<:PrimitiveEquation

source
SpeedyWeather.timestep!Method
timestep!(
     progn::PrognosticVariables{NF<:AbstractFloat},
     diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},
     dt::Real,
@@ -560,19 +560,19 @@
     lf1::Int64,
     lf2::Int64
 ) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}
-

Calculate a single time step for the model <: ShallowWater.

source
SpeedyWeather.unscale!Method
unscale!(variable::AbstractArray, scale::Real) -> Any
-

Undo the radius-scaling for any variable. Method used for netcdf output.

source
SpeedyWeather.unscale!Method
unscale!(progn::PrognosticVariables) -> Int64
-

Undo the radius-scaling of vorticity and divergence from scale!(progn,scale::Real).

source
SpeedyWeather.vertical_integration!Method
vertical_integration!(Diag::DiagnosticVariables,G::Geometry)

Calculates the vertically averaged (weighted by the thickness of the σ level) velocities (*coslat) and divergence. E.g.

u_mean = ∑_k=1^nlev Δσ_k * u_k

u,v are averaged in grid-point space, divergence in spectral space.

source
SpeedyWeather.unscale!Method
unscale!(variable::AbstractArray, scale::Real) -> Any
+

Undo the radius-scaling for any variable. Method used for netcdf output.

source
SpeedyWeather.unscale!Method
unscale!(progn::PrognosticVariables) -> Int64
+

Undo the radius-scaling of vorticity and divergence from scale!(progn,scale::Real).

source
SpeedyWeather.vertical_integration!Method
vertical_integration!(Diag::DiagnosticVariables,G::Geometry)

Calculates the vertically averaged (weighted by the thickness of the σ level) velocities (*coslat) and divergence. E.g.

u_mean = ∑_k=1^nlev Δσ_k * u_k

u,v are averaged in grid-point space, divergence in spectral space.

source
SpeedyWeather.virtual_temperature!Method
virtual_temperature!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     temp::LowerTriangularMatrix,
     constants::DynamicsConstants
 )
-

Calculates the virtual temperature Tᵥ as

Tᵥ = T(1+μq)

With absolute temperature T, specific humidity q and

μ = (1-ξ)/ξ, ξ = R_dry/R_vapour.

in grid-point space.

source
SpeedyWeather.virtual_temperature!Method
virtual_temperature!(
+

Calculates the virtual temperature Tᵥ as

Tᵥ = T(1+μq)

With absolute temperature T, specific humidity q and

μ = (1-ξ)/ξ, ξ = R_dry/R_vapour.

in grid-point space.

source
SpeedyWeather.virtual_temperature!Method
virtual_temperature!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     temp::LowerTriangularMatrix,
     model::PrimitiveDry
 ) -> SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat
-

Virtual temperature in grid-point space: For the PrimitiveDry temperature and virtual temperature are the same (humidity=0). Just copy over the arrays.

source
SpeedyWeather.volume_flux_divergence!Method
volume_flux_divergence!(
+

Virtual temperature in grid-point space: For the PrimitiveDry temperature and virtual temperature are the same (humidity=0). Just copy over the arrays.

source
SpeedyWeather.volume_flux_divergence!Method
volume_flux_divergence!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     surface::SpeedyWeather.SurfaceVariables,
     orog::SpeedyWeather.AbstractOrography,
@@ -580,7 +580,7 @@
     G::Geometry,
     S::SpectralTransform
 )
-

Computes the (negative) divergence of the volume fluxes uh,vh for the continuity equation, -∇⋅(uh,vh).

source
SpeedyWeather.vordiv_tendencies!Method
vordiv_tendencies!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     surf::SpeedyWeather.SurfaceVariables,
     C::DynamicsConstants,
@@ -589,47 +589,47 @@
 )
 

Tendencies for vorticity and divergence. Excluding Bernoulli potential with geopotential and linear pressure gradient inside the Laplace operator, which are added later in spectral space.

u_tend +=  v*(f+ζ) - RTᵥ'*∇lnp_x
 v_tend += -u*(f+ζ) - RTᵥ'*∇lnp_y

+= because the tendencies already contain the parameterizations and vertical advection. f is coriolis, ζ relative vorticity, R the gas constant Tᵥ' the virtual temperature anomaly, ∇lnp the gradient of surface pressure and _x and _y its zonal/meridional components. The tendencies are then curled/dived to get the tendencies for vorticity/divergence in spectral space

∂ζ/∂t = ∇×(u_tend,v_tend)
-∂D/∂t = ∇⋅(u_tend,v_tend) + ...

+ ... because there's more terms added later for divergence.

source
SpeedyWeather.vordiv_tendencies!Method
vordiv_tendencies!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     surf::SpeedyWeather.SurfaceVariables,
     model::PrimitiveEquation
 )
-

Function barrier to unpack model.

source
SpeedyWeather.vorticity_flux!Method
vorticity_flux!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     model::Barotropic
 )
-

Vorticity flux tendency in the barotropic vorticity equation

∂ζ/∂t = ∇×(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.

source
SpeedyWeather.vorticity_flux!Method
vorticity_flux!(
+

Vorticity flux tendency in the barotropic vorticity equation

∂ζ/∂t = ∇×(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.

source
SpeedyWeather.vorticity_flux!Method
vorticity_flux!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     model::ShallowWater
 )
-

Vorticity flux tendency in the shallow water equations

∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.

source
SpeedyWeather.vorticity_flux_curldiv!Method
vorticity_flux_curldiv!(
+

Vorticity flux tendency in the shallow water equations

∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.

source
SpeedyWeather.vorticity_flux_curldiv!Method
vorticity_flux_curldiv!(
     diagn::SpeedyWeather.DiagnosticVariablesLayer,
     C::DynamicsConstants,
     G::Geometry,
     S::SpectralTransform;
     div
 )
-

Compute the vorticity advection as the curl/div of the vorticity fluxes

∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ from u_tend_grid/v_tend_grid that are assumed to be alread set in forcing!. Set div=false for the BarotropicModel which doesn't require the divergence tendency.

source
SpeedyWeather.workgroup_sizeMethod
workgroup_size(dev::AbstractDevice)

Returns a workgroup size depending on dev. WIP: Will be expanded in the future to also include grid information.

source
SpeedyWeather.write_column_tendencies!Method
write_column_tendencies!(
+

Compute the vorticity advection as the curl/div of the vorticity fluxes

∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)

with

u_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)

with Fᵤ,Fᵥ from u_tend_grid/v_tend_grid that are assumed to be alread set in forcing!. Set div=false for the BarotropicModel which doesn't require the divergence tendency.

source
SpeedyWeather.workgroup_sizeMethod
workgroup_size(dev::AbstractDevice)

Returns a workgroup size depending on dev. WIP: Will be expanded in the future to also include grid information.

source
SpeedyWeather.write_column_tendencies!Method
write_column_tendencies!(
     D::DiagnosticVariables,
     C::ColumnVariables,
     ij::Int64
 )
-

Write the parametrization tendencies from C::ColumnVariables into the horizontal fields of tendencies stored in D::DiagnosticVariables at gridpoint index ij.

source
SpeedyWeather.write_netcdf_time!Method
write_netcdf_time!(
+

Write the parametrization tendencies from C::ColumnVariables into the horizontal fields of tendencies stored in D::DiagnosticVariables at gridpoint index ij.

source
SpeedyWeather.write_netcdf_time!Method
write_netcdf_time!(
     output::OutputWriter,
     time::Dates.DateTime
 )
-

Write the current time time::DateTime to the netCDF file in output::OutputWriter.

source
SpeedyWeather.write_netcdf_variables!Method
write_netcdf_variables!(
     output::OutputWriter,
     diagn::DiagnosticVariables{NF, Grid, Model}
 )
-

Write diagnostic variables from diagn to the netCDF file in output::OutputWriter.

source
SpeedyWeather.write_output!Method
write_output!(
     outputter::OutputWriter,
     time::Dates.DateTime,
     diagn::DiagnosticVariables
 )
-

Writes the variables from diagn of time step i at time time into outputter.netcdf_file. Simply escapes for no netcdf output of if output shouldn't be written on this time step. Interpolates onto output grid and resolution as specified in outputter, converts to output number format, truncates the mantissa for higher compression and applies lossless compression.

source
SpeedyWeather.write_restart_fileMethod
write_restart_file(
+

Writes the variables from diagn of time step i at time time into outputter.netcdf_file. Simply escapes for no netcdf output of if output shouldn't be written on this time step. Interpolates onto output grid and resolution as specified in outputter, converts to output number format, truncates the mantissa for higher compression and applies lossless compression.

source
SpeedyWeather.write_restart_fileMethod
write_restart_file(
     progn::PrognosticVariables,
     output::OutputWriter
 ) -> Union{Nothing, String}
-

A restart file restart.jld2 with the prognostic variables is written to the output folder (or current path) that can be used to restart the model. restart.jld2 will then be used as initial conditions. The prognostic variables are bitrounded for compression and the 2nd leapfrog time step is discarded. Variables in restart file are unscaled.

source
+

A restart file restart.jld2 with the prognostic variables is written to the output folder (or current path) that can be used to restart the model. restart.jld2 will then be used as initial conditions. The prognostic variables are bitrounded for compression and the 2nd leapfrog time step is discarded. Variables in restart file are unscaled.

source
diff --git a/previews/PR363/grids/index.html b/previews/PR363/grids/index.html index c51da0d90..ab29218fa 100644 --- a/previews/PR363/grids/index.html +++ b/previews/PR363/grids/index.html @@ -1,7 +1,7 @@ -Grids · SpeedyWeather.jl

Grids

The spectral transform (the Spherical Harmonic Transform) in SpeedyWeather.jl supports any ring-based equi-longitude grid. Several grids are already implemented but other can be added. The following pages will describe an overview of these grids and but let's start but how they can be used

julia> spectral_grid = SpectralGrid(Grid = FullGaussianGrid)
+Grids · SpeedyWeather.jl

Grids

The spectral transform (the Spherical Harmonic Transform) in SpeedyWeather.jl supports any ring-based equi-longitude grid. Several grids are already implemented but other can be added. The following pages will describe an overview of these grids and but let's start but how they can be used

julia> spectral_grid = SpectralGrid(Grid = FullGaussianGrid)
 SpectralGrid:
  Spectral:   T31 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m
  Grid:       4608-element, 48-ring FullGaussianGrid{Float32} (quadratic)
  Resolution: 333km (average)
- Vertical:   8-level SigmaCoordinates

The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object which defines the resolution in spectral and in grid-point space. The generator SpectralGrid() can take as a keyword argument Grid which can be any of the grids described below. The resolution of the grid, however, is not directly chosen, but determined from the spectral resolution trunc and the dealiasing factor. More in Matching spectral and grid resolution.

RingGrids is a module too!

While RingGrids is the underlying module that SpeedyWeather.jl uses for data structs on the sphere, the module can also be used independently of SpeedyWeather, for example to interpolate between data on different grids. See RingGrids

Ring-based equi-longitude grids

SpeedyWeather.jl's spectral transform supports all ring-based equi-longitude grids. These grids have their grid points located on rings with constant latitude and on these rings the points are equi-spaced in longitude. There is technically no constrain on the spacing of the latitude rings, but the Legendre transform requires a quadrature to map those to spectral space and back. Common choices for latitudes are the Gaussian latitudes which use the Gaussian quadrature, or equi-angle latitudes (i.e. just regular latitudes but excluding the poles) that use the Clenshaw-Curtis quadrature. The longitudes have to be equi-spaced on every ring, which is necessary for the fast Fourier transform, as one would otherwise need to use a non-uniform Fourier transform. In SpeedyWeather.jl the first grid point on any ring can have a longitudinal offset though, for example by spacing 4 points around the globe at 45˚E, 135˚E, 225˚E, and 315˚E. In this case the offset is 45˚E as the first point is not at 0˚E.

Is the FullClenshawGrid a longitude-latitude grid?

Short answer: Yes. The FullClenshawGrid is a specific longitude-latitude grid with equi-angle spacing. The most common grids for geoscientific data use regular spacings for 0-360˚E in longitude and 90˚N-90˚S. The FullClenshawGrid does that too, but it does not have a point on the North or South pole, and the central latitude ring sits exactly on the Equator. We name it Clenshaw following the Clenshaw-Curtis quadrature that is used in the Legendre transfrom in the same way as Gaussian refers to the Gaussian quadrature.

Implemented grids

All grids in SpeedyWeather.jl are a subtype of AbstractGrid, i.e. <: AbstractGrid. We further distinguish between full, and reduced grids. Full grids have the same number of longitude points on every latitude ring (i.e. points converge towards the poles) and reduced grids reduce the number of points towards the poles to have them more evenly spread out across the globe. More evenly does not necessarily mean that a grid is equal-area, meaning that every grid cell covers exactly the same area (although the shape changes).

Currently the following full grids <: AbstractFullGrid are implemented

  • FullGaussianGrid, a full grid with Gaussian latitudes
  • FullClenshawGrid, a full grid with equi-angle latitudes

and additionally we have FullHEALPixGrid and FullOctaHEALPixGrid which are the full grid equivalents to the HEALPix grid and the OctaHEALPix grid discussed below. Full grid equivalent means that they have the same latitude rings, but no reduction in the number of points per ring towards the poles and no longitude offset. Other implemented reduced grids are

  • OctahedralGaussianGrid, a reduced grid with Gaussian latitudes based on an octahedron
  • OctahedralClenshawGrid, similar but based on equi-angle latitudes
  • HEALPixGrid, an equal-area grid based on a dodecahedron with 12 faces
  • OctaHEALPixGrid, an equal-area grid from the class of HEALPix grids but based on an octahedron.

An overview of these grids is visualised here

Overview of implemented grids in SpeedyWeather.jl

Visualised are each grid's grid points (white dots) and grid faces (white lines). All grids shown have 16 latitude rings on one hemisphere, Equator included. The total number of grid points is denoted in the top left of every subplot. The sphere is shaded with grey, orange and turquoise regions to denote the hemispheres in a and b, the 8 octahedral faces c, d,f and the 12 dodecahedral faces (or base pixels) in e. Coastlines are added for orientation.

Grid resolution

All grids use the same resolution parameter nlat_half, i.e. the number of rings on one hemisphere, Equator included. The Gaussian grids (full and reduced) do not have a ring on the equator, so their total number of rings nlat is always even and twice nlat_half. Clenshaw-Curtis grids and the HEALPix grids have a ring on the equator such their total number of rings is always odd and one less than the Gaussian grids at the same nlat_half.

HEALPix grids do not use Nside as resolution parameter

The original formulation for HEALPix grids use $N_{side}$, the number of grid points along the edges of each basepixel (8 in the figure above), SpeedyWeather.jl uses nlat_half, the number of rings on one hemisphere, Equator included, for all grids. This is done for consistency across grids. We may use $N_{side}$ for the documentation or within functions though.

Related: Effective grid resolution and Available horizontal resolutions.

Matching spectral and grid resolution

A given spectral resolution can be matched to a variety of grid resolutions. A cubic grid, for example, combines a spectral truncation $T$ with a grid resolution $N$ (=nlat_half) such that $T + 1 = N$. Using T31 and an O32 is therefore often abbreviated as Tco31 meaning that the spherical harmonics are truncated at $l_{max}=31$ in combination with N=32, i.e. 64 latitude rings in total on an octahedral Gaussian grid. In SpeedyWeather.jl the choice of the order of truncation is controlled with the dealiasing parameter in the SpectralGrid construction.

Let J be the total number of rings. Then we have

  • $T \approx J$ for linear truncation, i.e. dealiasing = 1
  • $\frac{3}{2}T \approx J$ for quadratic truncation, i.e. dealiasing = 2
  • $2T \approx J$ for cubic truncation, , i.e. dealiasing = 3

and in general $\frac{m+1}{2}T \approx J$ for m-th order truncation. So the higher the truncation order the more grid points are used in combination with the same spectral resolution. A higher truncation order therefore makes all grid-point calculations more expensive, but can represent products of terms on the grid (which will have higher wavenumber components) to a higher accuracy as more grid points are available within a given wavelength. Using a sufficiently high truncation is therefore one way to avoid aliasing. A quick overview of how the grid resolution changes when dealiasing is passed onto SpectralGrid on the FullGaussianGrid

truncdealiasingFullGaussianGrid size
31164x32
31296x48
313128x64
42196x48
422128x64
423192x96
.........

You will obtain this information every time you create a SpectralGrid(;Grid,trunc,dealiasing).

Full Gaussian grid

...

Full Clenshaw-Curtis grid

...

Octahedral Gaussian grid

...

HEALPix grid

Technically, HEALPix grids are a class of grids that tessalate the sphere into faces that are often called basepixels. For each member of this class there are $N_\varphi$ basepixels in zonal direction and $N_\theta$ basepixels in meridional direction. For $N_\varphi = 4$ and $N_\theta = 3$ we obtain the classical HEALPix grid with $N_\varphi N_\theta = 12$ basepixels shown above in Implemented grids. Each basepixel has a quadratic number of grid points in them. There's an equatorial zone where the number of zonal grid points is constant (always $2N$, so 32 at $N=16$) and there are polar caps above and below the equatorial zone with the border at $\cos(\theta) = 2/3$ ($\theta$ in colatitudes).

Following Górski, 2004[1], the $z=cos(\theta)$ colatitude of the $j$-th ring in the north polar cap, $j=1,...,N_{side}$ with $2N_{side} = N$ is

\[z = 1 - \frac{j^2}{3N_{side}^2}\]

and on that ring, the longitude $\phi$ of the $i$-th point ($i$ is the in-ring-index) is at

\[\phi = \frac{\pi}{2j}(i-\tfrac{1}{2})\]

The in-ring index $i$ goes from $i=1,...,4$ for the first (i.e. northern-most) ring, $i=1,...,8$ for the second ring and $i = 1,...,4j$ for the $j$-th ring in the northern polar cap.

In the north equatorial belt $j=N_{side},...,2N_{side}$ this changes to

\[z = \frac{4}{3} - \frac{2j}{3N_{side}}\]

and the longitudes change to ($i$ is always $i = 1,...,4N_{side}$ in the equatorial belt meaning the number of longitude points is constant here)

\[\phi = \frac{\pi}{2N_{side}}(i - \frac{s}{2}), \quad s = (j - N_{side} + 1) \mod 2\]

The modulo function comes in as there is an alternating longitudinal offset from the prime meridian (see Implemented grids). For the southern hemisphere the grid point locations can be obtained by mirror symmetry.

Grid cell boundaries

The cell boundaries are obtained by setting $i = k + 1/2$ or $i = k + 1/2 + j$ (half indices) into the equations above, such that $z(\phi,k)$, a function for the cosine of colatitude $z$ of index $k$ and the longitude $\phi$ is obtained. These are then (northern polar cap)

\[z = 1 - \frac{k^2}{3N_{side}^2}\left(\frac{\pi}{2\phi_t}\right)^2, \quad z = 1 - \frac{k^2}{3N_{side}^2}\left(\frac{\pi}{2\phi_t - \pi}\right)^2\]

with $\phi_t = \phi \mod \tfrac{\pi}{2}$ and in the equatorial belt

\[z = \frac{2}{3}-\frac{4k}{3N_{side}} \pm \frac{8\phi}{3\pi}\]

OctaHEALPix grid

While the classic HEALPix grid is based on a dodecahedron, other choices for $N_\varphi$ and $N_\theta$ in the class of HEALPix grids will change the number of faces there are in zonal/meridional direction. With $N_\varphi = 4$ and $N_\theta = 1$ we obtain a HEALPix grid that is based on an octahedron, which has the convenient property that there are twice as many longitude points around the equator than there are latitude rings between the poles. This is a desirable for truncation as this matches the distances too, $2\pi$ around the Equator versus $\pi$ between the poles. $N_\varphi = 6, N_\theta = 2$ or $N_\varphi = 8, N_\theta = 3$ are other possible choices for this, but also more complicated. See Górski, 2004[1] for further examples and visualizations of these grids.

We call the $N_\varphi = 4, N_\theta = 1$ HEALPix grid the OctaHEALPix grid, which combines the equal-area property of the HEALPix grids with the octahedron that's also used in the OctahedralGaussianGrid or the OctahedralClenshawGrid. As $N_\theta = 1$ there is no equatorial belt which simplifies the grid. The latitude of the $j$-th isolatitude ring on the OctaHEALPixGrid is defined by

\[z = 1 - \frac{j^2}{N^2},\]

with $j=1,...,N$, and similarly for the southern hemisphere by symmetry. On this grid $N_{side} = N$ where $N$= nlat_half, the number of latitude rings on one hemisphere, Equator included, because each of the 4 basepixels spans from pole to pole and covers a quarter of the sphere. The longitudes with in-ring- index $i = 1,...,4j$ are

\[\phi = \frac{\pi}{2j}(i - \tfrac{1}{2})\]

and again, the southern hemisphere grid points are obtained by symmetry.

Grid cell boundaries

Similar to the grid cell boundaries for the HEALPix grid, the OctaHEALPix grid's boundaries are

\[z = 1 - \frac{k^2}{N^2}\left(\frac{\pi}{2\phi_t}\right)^2, \quad z = 1 - \frac{k^2}{N^2}\left(\frac{\pi}{2\phi_t - \pi}\right)^2\]

The $3N_{side}^2$ in the denominator of the HEALPix grid came simply $N^2$ for the OctaHEALPix grid and there's no separate equation for the equatorial belt (which doesn't exist in the OctaHEALPix grid).

References

  • 1Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976
+ Vertical: 8-level SigmaCoordinates

The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object which defines the resolution in spectral and in grid-point space. The generator SpectralGrid() can take as a keyword argument Grid which can be any of the grids described below. The resolution of the grid, however, is not directly chosen, but determined from the spectral resolution trunc and the dealiasing factor. More in Matching spectral and grid resolution.

RingGrids is a module too!

While RingGrids is the underlying module that SpeedyWeather.jl uses for data structs on the sphere, the module can also be used independently of SpeedyWeather, for example to interpolate between data on different grids. See RingGrids

Ring-based equi-longitude grids

SpeedyWeather.jl's spectral transform supports all ring-based equi-longitude grids. These grids have their grid points located on rings with constant latitude and on these rings the points are equi-spaced in longitude. There is technically no constrain on the spacing of the latitude rings, but the Legendre transform requires a quadrature to map those to spectral space and back. Common choices for latitudes are the Gaussian latitudes which use the Gaussian quadrature, or equi-angle latitudes (i.e. just regular latitudes but excluding the poles) that use the Clenshaw-Curtis quadrature. The longitudes have to be equi-spaced on every ring, which is necessary for the fast Fourier transform, as one would otherwise need to use a non-uniform Fourier transform. In SpeedyWeather.jl the first grid point on any ring can have a longitudinal offset though, for example by spacing 4 points around the globe at 45˚E, 135˚E, 225˚E, and 315˚E. In this case the offset is 45˚E as the first point is not at 0˚E.

Is the FullClenshawGrid a longitude-latitude grid?

Short answer: Yes. The FullClenshawGrid is a specific longitude-latitude grid with equi-angle spacing. The most common grids for geoscientific data use regular spacings for 0-360˚E in longitude and 90˚N-90˚S. The FullClenshawGrid does that too, but it does not have a point on the North or South pole, and the central latitude ring sits exactly on the Equator. We name it Clenshaw following the Clenshaw-Curtis quadrature that is used in the Legendre transfrom in the same way as Gaussian refers to the Gaussian quadrature.

Implemented grids

All grids in SpeedyWeather.jl are a subtype of AbstractGrid, i.e. <: AbstractGrid. We further distinguish between full, and reduced grids. Full grids have the same number of longitude points on every latitude ring (i.e. points converge towards the poles) and reduced grids reduce the number of points towards the poles to have them more evenly spread out across the globe. More evenly does not necessarily mean that a grid is equal-area, meaning that every grid cell covers exactly the same area (although the shape changes).

Currently the following full grids <: AbstractFullGrid are implemented

  • FullGaussianGrid, a full grid with Gaussian latitudes
  • FullClenshawGrid, a full grid with equi-angle latitudes

and additionally we have FullHEALPixGrid and FullOctaHEALPixGrid which are the full grid equivalents to the HEALPix grid and the OctaHEALPix grid discussed below. Full grid equivalent means that they have the same latitude rings, but no reduction in the number of points per ring towards the poles and no longitude offset. Other implemented reduced grids are

  • OctahedralGaussianGrid, a reduced grid with Gaussian latitudes based on an octahedron
  • OctahedralClenshawGrid, similar but based on equi-angle latitudes
  • HEALPixGrid, an equal-area grid based on a dodecahedron with 12 faces
  • OctaHEALPixGrid, an equal-area grid from the class of HEALPix grids but based on an octahedron.

An overview of these grids is visualised here

Overview of implemented grids in SpeedyWeather.jl

Visualised are each grid's grid points (white dots) and grid faces (white lines). All grids shown have 16 latitude rings on one hemisphere, Equator included. The total number of grid points is denoted in the top left of every subplot. The sphere is shaded with grey, orange and turquoise regions to denote the hemispheres in a and b, the 8 octahedral faces c, d,f and the 12 dodecahedral faces (or base pixels) in e. Coastlines are added for orientation.

Grid resolution

All grids use the same resolution parameter nlat_half, i.e. the number of rings on one hemisphere, Equator included. The Gaussian grids (full and reduced) do not have a ring on the equator, so their total number of rings nlat is always even and twice nlat_half. Clenshaw-Curtis grids and the HEALPix grids have a ring on the equator such their total number of rings is always odd and one less than the Gaussian grids at the same nlat_half.

HEALPix grids do not use Nside as resolution parameter

The original formulation for HEALPix grids use $N_{side}$, the number of grid points along the edges of each basepixel (8 in the figure above), SpeedyWeather.jl uses nlat_half, the number of rings on one hemisphere, Equator included, for all grids. This is done for consistency across grids. We may use $N_{side}$ for the documentation or within functions though.

Related: Effective grid resolution and Available horizontal resolutions.

Matching spectral and grid resolution

A given spectral resolution can be matched to a variety of grid resolutions. A cubic grid, for example, combines a spectral truncation $T$ with a grid resolution $N$ (=nlat_half) such that $T + 1 = N$. Using T31 and an O32 is therefore often abbreviated as Tco31 meaning that the spherical harmonics are truncated at $l_{max}=31$ in combination with N=32, i.e. 64 latitude rings in total on an octahedral Gaussian grid. In SpeedyWeather.jl the choice of the order of truncation is controlled with the dealiasing parameter in the SpectralGrid construction.

Let J be the total number of rings. Then we have

  • $T \approx J$ for linear truncation, i.e. dealiasing = 1
  • $\frac{3}{2}T \approx J$ for quadratic truncation, i.e. dealiasing = 2
  • $2T \approx J$ for cubic truncation, , i.e. dealiasing = 3

and in general $\frac{m+1}{2}T \approx J$ for m-th order truncation. So the higher the truncation order the more grid points are used in combination with the same spectral resolution. A higher truncation order therefore makes all grid-point calculations more expensive, but can represent products of terms on the grid (which will have higher wavenumber components) to a higher accuracy as more grid points are available within a given wavelength. Using a sufficiently high truncation is therefore one way to avoid aliasing. A quick overview of how the grid resolution changes when dealiasing is passed onto SpectralGrid on the FullGaussianGrid

truncdealiasingFullGaussianGrid size
31164x32
31296x48
313128x64
42196x48
422128x64
423192x96
.........

You will obtain this information every time you create a SpectralGrid(;Grid,trunc,dealiasing).

Full Gaussian grid

...

Full Clenshaw-Curtis grid

...

Octahedral Gaussian grid

...

HEALPix grid

Technically, HEALPix grids are a class of grids that tessalate the sphere into faces that are often called basepixels. For each member of this class there are $N_\varphi$ basepixels in zonal direction and $N_\theta$ basepixels in meridional direction. For $N_\varphi = 4$ and $N_\theta = 3$ we obtain the classical HEALPix grid with $N_\varphi N_\theta = 12$ basepixels shown above in Implemented grids. Each basepixel has a quadratic number of grid points in them. There's an equatorial zone where the number of zonal grid points is constant (always $2N$, so 32 at $N=16$) and there are polar caps above and below the equatorial zone with the border at $\cos(\theta) = 2/3$ ($\theta$ in colatitudes).

Following Górski, 2004[1], the $z=cos(\theta)$ colatitude of the $j$-th ring in the north polar cap, $j=1,...,N_{side}$ with $2N_{side} = N$ is

\[z = 1 - \frac{j^2}{3N_{side}^2}\]

and on that ring, the longitude $\phi$ of the $i$-th point ($i$ is the in-ring-index) is at

\[\phi = \frac{\pi}{2j}(i-\tfrac{1}{2})\]

The in-ring index $i$ goes from $i=1,...,4$ for the first (i.e. northern-most) ring, $i=1,...,8$ for the second ring and $i = 1,...,4j$ for the $j$-th ring in the northern polar cap.

In the north equatorial belt $j=N_{side},...,2N_{side}$ this changes to

\[z = \frac{4}{3} - \frac{2j}{3N_{side}}\]

and the longitudes change to ($i$ is always $i = 1,...,4N_{side}$ in the equatorial belt meaning the number of longitude points is constant here)

\[\phi = \frac{\pi}{2N_{side}}(i - \frac{s}{2}), \quad s = (j - N_{side} + 1) \mod 2\]

The modulo function comes in as there is an alternating longitudinal offset from the prime meridian (see Implemented grids). For the southern hemisphere the grid point locations can be obtained by mirror symmetry.

Grid cell boundaries

The cell boundaries are obtained by setting $i = k + 1/2$ or $i = k + 1/2 + j$ (half indices) into the equations above, such that $z(\phi,k)$, a function for the cosine of colatitude $z$ of index $k$ and the longitude $\phi$ is obtained. These are then (northern polar cap)

\[z = 1 - \frac{k^2}{3N_{side}^2}\left(\frac{\pi}{2\phi_t}\right)^2, \quad z = 1 - \frac{k^2}{3N_{side}^2}\left(\frac{\pi}{2\phi_t - \pi}\right)^2\]

with $\phi_t = \phi \mod \tfrac{\pi}{2}$ and in the equatorial belt

\[z = \frac{2}{3}-\frac{4k}{3N_{side}} \pm \frac{8\phi}{3\pi}\]

OctaHEALPix grid

While the classic HEALPix grid is based on a dodecahedron, other choices for $N_\varphi$ and $N_\theta$ in the class of HEALPix grids will change the number of faces there are in zonal/meridional direction. With $N_\varphi = 4$ and $N_\theta = 1$ we obtain a HEALPix grid that is based on an octahedron, which has the convenient property that there are twice as many longitude points around the equator than there are latitude rings between the poles. This is a desirable for truncation as this matches the distances too, $2\pi$ around the Equator versus $\pi$ between the poles. $N_\varphi = 6, N_\theta = 2$ or $N_\varphi = 8, N_\theta = 3$ are other possible choices for this, but also more complicated. See Górski, 2004[1] for further examples and visualizations of these grids.

We call the $N_\varphi = 4, N_\theta = 1$ HEALPix grid the OctaHEALPix grid, which combines the equal-area property of the HEALPix grids with the octahedron that's also used in the OctahedralGaussianGrid or the OctahedralClenshawGrid. As $N_\theta = 1$ there is no equatorial belt which simplifies the grid. The latitude of the $j$-th isolatitude ring on the OctaHEALPixGrid is defined by

\[z = 1 - \frac{j^2}{N^2},\]

with $j=1,...,N$, and similarly for the southern hemisphere by symmetry. On this grid $N_{side} = N$ where $N$= nlat_half, the number of latitude rings on one hemisphere, Equator included, because each of the 4 basepixels spans from pole to pole and covers a quarter of the sphere. The longitudes with in-ring- index $i = 1,...,4j$ are

\[\phi = \frac{\pi}{2j}(i - \tfrac{1}{2})\]

and again, the southern hemisphere grid points are obtained by symmetry.

Grid cell boundaries

Similar to the grid cell boundaries for the HEALPix grid, the OctaHEALPix grid's boundaries are

\[z = 1 - \frac{k^2}{N^2}\left(\frac{\pi}{2\phi_t}\right)^2, \quad z = 1 - \frac{k^2}{N^2}\left(\frac{\pi}{2\phi_t - \pi}\right)^2\]

The $3N_{side}^2$ in the denominator of the HEALPix grid came simply $N^2$ for the OctaHEALPix grid and there's no separate equation for the equatorial belt (which doesn't exist in the OctaHEALPix grid).

References

  • 1Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976
diff --git a/previews/PR363/how_to_run_speedy/index.html b/previews/PR363/how_to_run_speedy/index.html index d51f789e4..4c8b06ee9 100644 --- a/previews/PR363/how_to_run_speedy/index.html +++ b/previews/PR363/how_to_run_speedy/index.html @@ -54,4 +54,4 @@ smoothing_truncation::Int64 = 85

It will read the orography from file as shown, and there are some smoothing options too, but let's not change them. Same as before, create a model, initialize into a simulation, run. This time directly for 12 days so that we can compare with the last plot

julia> model = ShallowWaterModel(;spectral_grid, orography, initial_conditions);
 julia> simulation = initialize!(model);
 julia> run!(simulation,n_days=12,output=true)
-Weather is speedy: run 0003 100%|███████████████████████| Time: 0:00:35 (79.16 years/day)

This time the run got the id "0003", but otherwise we do as before.

Galewsky jet pyplot

Interesting! The initial conditions have zero velocity in the southern hemisphere, but still, one can see some imprint of the orography on vorticity. You can spot the coastline of Antarctica; the Andes and Greenland are somewhat visible too. Mountains also completely changed the flow after 12 days, probably not surprising!

SpectralGrid

The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object. We have seen some examples above, now let's look into the details

Missing docstring.

Missing docstring for SpectralGrid. Check Documenter's build log for details.

References

[1] Galewsky, Scott, Polvani, 2004. An initial-value problem for testing numerical models of the global shallow-water equations, Tellus A. DOI: 10.3402/tellusa.v56i5.14436

+Weather is speedy: run 0003 100%|███████████████████████| Time: 0:00:35 (79.16 years/day)

This time the run got the id "0003", but otherwise we do as before.

Galewsky jet pyplot

Interesting! The initial conditions have zero velocity in the southern hemisphere, but still, one can see some imprint of the orography on vorticity. You can spot the coastline of Antarctica; the Andes and Greenland are somewhat visible too. Mountains also completely changed the flow after 12 days, probably not surprising!

SpectralGrid

The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object. We have seen some examples above, now let's look into the details

Missing docstring.

Missing docstring for SpectralGrid. Check Documenter's build log for details.

References

[1] Galewsky, Scott, Polvani, 2004. An initial-value problem for testing numerical models of the global shallow-water equations, Tellus A. DOI: 10.3402/tellusa.v56i5.14436

diff --git a/previews/PR363/index.html b/previews/PR363/index.html index aa4154003..ede8723d3 100644 --- a/previews/PR363/index.html +++ b/previews/PR363/index.html @@ -1,2 +1,2 @@ -Home · SpeedyWeather.jl

SpeedyWeather.jl documentation

Welcome to the documentation for SpeedyWeather.jl a global atmospheric circulation model with simple parametrizations to represent physical processes such as clouds, precipitation and radiation.

Overview

SpeedyWeather.jl is a global spectral model that uses a spherical harmonic transform to simulate the general circulation of the atmosphere. The prognostic variables used are vorticity, divergence, temperature, surface pressure and specific humidity. Simple parameterizations represent various climate processes: Radiation, clouds, precipitation, surface fluxes, among others.

SpeedyWeather.jl defines

  • BarotropicModel for the 2D barotropic vorticity equation
  • ShallowWaterModel for the 2D shallow water equations
  • PrimitiveDryModel for the 3D primitive equations without humidity
  • PrimitiveWetModel for the 3D primitive equations with humidity

and solves these equations in spherical coordinates as described in this documentation.

Manual outline

See the following pages of the documentation for more details

and the submodules

and the original documentation by Molteni and Kucharski.

Developers

The development of SpeedyWeather.jl is lead by Milan Klöwer and current and past contributors include

Any contributions are always welcome!

Funding

MK received funding by the European Research Council under Horizon 2020 within the ITHACA project, grant agreement number 741112 from 2021-2022. Since 2023 this project is also funded by the National Science Foundation NSF.

+Home · SpeedyWeather.jl

SpeedyWeather.jl documentation

Welcome to the documentation for SpeedyWeather.jl a global atmospheric circulation model with simple parametrizations to represent physical processes such as clouds, precipitation and radiation.

Overview

SpeedyWeather.jl is a global spectral model that uses a spherical harmonic transform to simulate the general circulation of the atmosphere. The prognostic variables used are vorticity, divergence, temperature, surface pressure and specific humidity. Simple parameterizations represent various climate processes: Radiation, clouds, precipitation, surface fluxes, among others.

SpeedyWeather.jl defines

  • BarotropicModel for the 2D barotropic vorticity equation
  • ShallowWaterModel for the 2D shallow water equations
  • PrimitiveDryModel for the 3D primitive equations without humidity
  • PrimitiveWetModel for the 3D primitive equations with humidity

and solves these equations in spherical coordinates as described in this documentation.

Manual outline

See the following pages of the documentation for more details

and the submodules

and the original documentation by Molteni and Kucharski.

Developers

The development of SpeedyWeather.jl is lead by Milan Klöwer and current and past contributors include

Any contributions are always welcome!

Funding

MK received funding by the European Research Council under Horizon 2020 within the ITHACA project, grant agreement number 741112 from 2021-2022. Since 2023 this project is also funded by the National Science Foundation NSF.

diff --git a/previews/PR363/installation/index.html b/previews/PR363/installation/index.html index 3761887a2..6049e8174 100644 --- a/previews/PR363/installation/index.html +++ b/previews/PR363/installation/index.html @@ -1,3 +1,3 @@ Installation · SpeedyWeather.jl

Installation

SpeedyWeather.jl is registered in the Julia Registry. In most cases just open the Julia REPL and type

julia> using Pkg
-julia> Pkg.add("SpeedyWeather")

or, equivalently, (] opens the package manager)

julia>] add SpeedyWeather

which will automatically install the latest release and all necessary dependencies. If you run into any troubles please raise an issue.

However, you may want to make use of the latest features, then install directly from the main branch with

julia> Pkg.add(url="https://github.com/SpeedyWeather/SpeedyWeather.jl",rev="main")

other branches than main can be similarly installed. You can also type, equivalently,

julia>] add https://github.com/SpeedyWeather/SpeedyWeather.jl#main

Compatibility with Julia versions

SpeedyWeather.jl usually lives on the latest minor release and/or its predecessor. At the moment (June 2023) this means

  • Julia v1.8
  • Julia v1.9

are supported, but we dropped the support of earlier versions.

+julia> Pkg.add("SpeedyWeather")

or, equivalently, (] opens the package manager)

julia>] add SpeedyWeather

which will automatically install the latest release and all necessary dependencies. If you run into any troubles please raise an issue.

However, you may want to make use of the latest features, then install directly from the main branch with

julia> Pkg.add(url="https://github.com/SpeedyWeather/SpeedyWeather.jl",rev="main")

other branches than main can be similarly installed. You can also type, equivalently,

julia>] add https://github.com/SpeedyWeather/SpeedyWeather.jl#main

Compatibility with Julia versions

SpeedyWeather.jl usually lives on the latest minor release and/or its predecessor. At the moment (June 2023) this means

are supported, but we dropped the support of earlier versions.

diff --git a/previews/PR363/lowertriangularmatrices/index.html b/previews/PR363/lowertriangularmatrices/index.html index 496d08cda..03fc006d6 100644 --- a/previews/PR363/lowertriangularmatrices/index.html +++ b/previews/PR363/lowertriangularmatrices/index.html @@ -55,6 +55,6 @@ 3×3 Matrix{Float32}: 0.332341 0.0 0.0 0.506243 0.766275 0.0 - 1.68542 1.59366 0.996616

Note, however, that the latter includes a conversion to Matrix, which is true for many operations, including inv or \. Hence when trying to do more sophisticated linear algebra with LowerTriangularMatrix we quickly leave lower triangular-land and go back to normal matrix-land.

Function and type index

SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrixType
L = LowerTriangularMatrix{T}(v::Vector{T},m::Int,n::Int)

A lower triangular matrix implementation that only stores the non-zero entries explicitly. L<:AbstractMatrix although in general we have L[i] != Matrix(L)[i], the former skips zero entries, tha latter includes them.

source
SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrixMethod
L = LowerTriangularMatrix(M)

Create a LowerTriangularMatrix L from Matrix M by copying over the non-zero elements in M.

source
Base.fill!Method
fill!(L::LowerTriangularMatrix,x)

Fills the elements of L with x. Faster than fill!(::AbstractArray,x) as only the non-zero elements in L are assigned with x.

source
SpeedyWeather.LowerTriangularMatrices.eachharmonicMethod
unit_range = eachharmonic(L::LowerTriangular)

creates unit_range::UnitRange to loop over all non-zeros in a LowerTriangularMatrix L. Like eachindex but skips the upper triangle with zeros in L.

source
SpeedyWeather.LowerTriangularMatrices.eachharmonicMethod
unit_range = eachharmonic(Ls::LowerTriangularMatrix...)

creates unit_range::UnitRange to loop over all non-zeros in the LowerTriangularMatrices provided as arguments. Checks bounds first. All LowerTriangularMatrix's need to be of the same size. Like eachindex but skips the upper triangle with zeros in L.

source
SpeedyWeather.LowerTriangularMatrices.ij2kMethod
k = ij2k(   i::Integer,     # row index of matrix
+ 1.68542   1.59366   0.996616

Note, however, that the latter includes a conversion to Matrix, which is true for many operations, including inv or \. Hence when trying to do more sophisticated linear algebra with LowerTriangularMatrix we quickly leave lower triangular-land and go back to normal matrix-land.

Function and type index

SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrixType
L = LowerTriangularMatrix{T}(v::Vector{T},m::Int,n::Int)

A lower triangular matrix implementation that only stores the non-zero entries explicitly. L<:AbstractMatrix although in general we have L[i] != Matrix(L)[i], the former skips zero entries, tha latter includes them.

source
Base.fill!Method
fill!(L::LowerTriangularMatrix,x)

Fills the elements of L with x. Faster than fill!(::AbstractArray,x) as only the non-zero elements in L are assigned with x.

source
SpeedyWeather.LowerTriangularMatrices.eachharmonicMethod
unit_range = eachharmonic(Ls::LowerTriangularMatrix...)

creates unit_range::UnitRange to loop over all non-zeros in the LowerTriangularMatrices provided as arguments. Checks bounds first. All LowerTriangularMatrix's need to be of the same size. Like eachindex but skips the upper triangle with zeros in L.

source
SpeedyWeather.LowerTriangularMatrices.ij2kMethod
k = ij2k(   i::Integer,     # row index of matrix
             j::Integer,     # column index of matrix
-            m::Integer)     # number of rows in matrix

Converts the index pair i,j of an mxn LowerTriangularMatrix L to a single index k that indexes the same element in the corresponding vector that stores only the lower triangle (the non-zero entries) of L.

source
+ m::Integer) # number of rows in matrix

Converts the index pair i,j of an mxn LowerTriangularMatrix L to a single index k that indexes the same element in the corresponding vector that stores only the lower triangle (the non-zero entries) of L.

source diff --git a/previews/PR363/output/index.html b/previews/PR363/output/index.html index 729de50b6..917ce850b 100644 --- a/previews/PR363/output/index.html +++ b/previews/PR363/output/index.html @@ -29,4 +29,4 @@ julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, path=path)

This folder must already exist. If you want to give your run a name/identification you can pass on id

julia> my_output_writer = OutputWriter(spectral_grid,PrimitiveDry,id="diffusion_test");

which will be used instead of a 4 digit number like 0001, 0002 which is automatically determined if id is not provided. You will see the id of the run in the progress bar

Weather is speedy: run diffusion_test 100%|███████████████████████| Time: 0:00:12 (19.20 years/day)

and the run folder, here run_diffusion_test, is also named accordingly

shell> ls
 ...
 run_diffusion_test
-...

Further options

Further options are described in the OutputWriter docstring, (also accessible via julia>?OutputWriter for example). Note that some fields are actual options, but others are derived from the options you provided or are arrays/objects the output writer needs, but shouldn't be passed on by the user. The actual options are declared as [OPTION] in the following

Missing docstring.

Missing docstring for OutputWriter. Check Documenter's build log for details.

+...

Further options

Further options are described in the OutputWriter docstring, (also accessible via julia>?OutputWriter for example). Note that some fields are actual options, but others are derived from the options you provided or are arrays/objects the output writer needs, but shouldn't be passed on by the user. The actual options are declared as [OPTION] in the following

Missing docstring.

Missing docstring for OutputWriter. Check Documenter's build log for details.

diff --git a/previews/PR363/parameterizations/index.html b/previews/PR363/parameterizations/index.html index d1712691d..c7c27bd4f 100644 --- a/previews/PR363/parameterizations/index.html +++ b/previews/PR363/parameterizations/index.html @@ -1,2 +1,2 @@ -Parameterizations · SpeedyWeather.jl
+Parameterizations · SpeedyWeather.jl
diff --git a/previews/PR363/primitiveequation/index.html b/previews/PR363/primitiveequation/index.html index 4a68138a9..6297f430a 100644 --- a/previews/PR363/primitiveequation/index.html +++ b/previews/PR363/primitiveequation/index.html @@ -11,4 +11,4 @@ p_d &= \rho_d R_d T \\ p_w &= \rho_w R_w T \\ \end{aligned}\]

with the respective specific gas constants $R_d = R/m_d$ and $R_w = R/m_w$ obtained from the univeral gas constant $R$ divided by the molecular masses of the gas. The total pressure $p$ in the air parcel is

\[p = p_d + p_w = (\rho_d R_d + \rho_w R_w)T\]

We ultimately want to replace the density $\rho = \rho_w + \rho_d$ in the dynamical core, using the ideal gas law, with the temperature $T$, so that we never have to calculate the density explicitly. However, in order to not deal with two densities (dry air and water vapour) we would like to replace temperature with a virtual temperature that includes the effect of humidity on the density. So, whereever we use the ideal gas law to replace density with temperature, we would use the virtual temperature, which is a function of the absolute temperature and specific humidity, instead. A higher specific humidity in an air parcel lowers the density as water vapour is lighter than dry air. Consequently, the virtual temperature of moist air is higher than its absolute temperature because warmer air is lighter too at constant pressure. We therefore think of the virtual temperature as the temperature dry air would need to have to be as light as moist air.

Starting with the last equation, with some manipulation we can write the ideal gas law as total density $rho$ times a gas constant times the virtual temperature that is supposed to be a function of absolute temperature, humidity and some constants

\[p = (\rho R_d + \rho_w (R_w - R_d)) T = \rho R_d (1 + -\frac{1 - \tfrac{R_d}{R_w}}{\tfrac{R_d}{R_w}} \frac{\rho_w}{\rho_w + \rho_d})T\]

Now we identify

\[\mu = \frac{1 - \tfrac{R_d}{R_w}}{\tfrac{R_d}{R_w}}\]

as some constant that is positive for water vapour being lighter than dry air ($\tfrac{R_d}{R_w} = \tfrac{m_w}{m_d} < 1$) and

\[q = \frac{\rho_w}{\rho_w + \rho_d}\]

as the specific humidity. Given temperature $T$ and specific humidity $q$, we can therefore calculate the virtual temperature $T_v$ as

\[T_v = (1 + \mu q)T\]

For completeness we want to mention here that the above product, because it is a product of two variables $q,T$ has to be computed in grid-point space, see [Spectral Transform]. To obtain an approximation to the virtual temperature in spectral space without expensive transforms one can linearize

\[T_v = T + \mu q\bar{T}\]

With a global constant temperature $\bar{T}$, for example obtained from the $l=m=0$ mode, $\bar{T} = T_{0,0}\frac{1}{\sqrt{4\pi}}$ but depending on the normalization of the spherical harmonics that factor needs adjustment.

Vertical coordinates

General

Let $\Psi(x,y,z,t)$

SpeedyWeather.jl currently uses sigma coordinates for the vertical.

\[\sigma = \frac{p}{p_s}\]

\[p_k = \sigma_kp_s\]

\[\Delta p_k = p_{k+1} - p_k = \Delta \sigma_k p_s\]

Geopotential

In the hydrostatic approximation the vertical momentum equation becomes

\[\frac{\partial p}{\partial z} = -\rho g,\]

meaning that the (negative) vertical pressure gradient is given by the density in that layer times the gravitational acceleration. The heavier the fluid the more the pressure will increase below. Inserting the ideal gas law

\[\frac{\partial gz}{\partial p} = -\frac{R_dT_v}{p},\]

with the geopotential $\Phi = gz$ we can write this in terms of the logarithm of pressure

\[\frac{\partial \Phi}{\partial \ln p} = -R_dT_v.\]

Note that we use the Virtual temperature here as we replaced the density through the ideal gas law with temperature. Given a vertical temperature profile $T_v$ and the (constant) surface geopotential $\Phi_s = gz_s$ where $z_s$ is the orography, we can integrate this equation from the surface to the top to obtain $\Phi_k$ on every layer $k$. The surface is at $k = N+\tfrac{1}{2}$ (see Vertical coordinates) with $N$ vertical levels. We can integrate the geopotential onto half levels as

\[\Phi_{k-\tfrac{1}{2}} = \Phi_{k+\tfrac{1}{2}} + R_dT^v_k(\ln p_{k+1/2} - \ln p_{k-1/2})\]

Surface pressure tendency

Vertical advection

Pressure gradient force

Temperature equation

Semi-implicit time stepping

Horizontal diffusion

Algorithm

Scaled primitive equations

References

+\frac{1 - \tfrac{R_d}{R_w}}{\tfrac{R_d}{R_w}} \frac{\rho_w}{\rho_w + \rho_d})T\]

Now we identify

\[\mu = \frac{1 - \tfrac{R_d}{R_w}}{\tfrac{R_d}{R_w}}\]

as some constant that is positive for water vapour being lighter than dry air ($\tfrac{R_d}{R_w} = \tfrac{m_w}{m_d} < 1$) and

\[q = \frac{\rho_w}{\rho_w + \rho_d}\]

as the specific humidity. Given temperature $T$ and specific humidity $q$, we can therefore calculate the virtual temperature $T_v$ as

\[T_v = (1 + \mu q)T\]

For completeness we want to mention here that the above product, because it is a product of two variables $q,T$ has to be computed in grid-point space, see [Spectral Transform]. To obtain an approximation to the virtual temperature in spectral space without expensive transforms one can linearize

\[T_v = T + \mu q\bar{T}\]

With a global constant temperature $\bar{T}$, for example obtained from the $l=m=0$ mode, $\bar{T} = T_{0,0}\frac{1}{\sqrt{4\pi}}$ but depending on the normalization of the spherical harmonics that factor needs adjustment.

Vertical coordinates

General

Let $\Psi(x,y,z,t)$

SpeedyWeather.jl currently uses sigma coordinates for the vertical.

\[\sigma = \frac{p}{p_s}\]

\[p_k = \sigma_kp_s\]

\[\Delta p_k = p_{k+1} - p_k = \Delta \sigma_k p_s\]

Geopotential

In the hydrostatic approximation the vertical momentum equation becomes

\[\frac{\partial p}{\partial z} = -\rho g,\]

meaning that the (negative) vertical pressure gradient is given by the density in that layer times the gravitational acceleration. The heavier the fluid the more the pressure will increase below. Inserting the ideal gas law

\[\frac{\partial gz}{\partial p} = -\frac{R_dT_v}{p},\]

with the geopotential $\Phi = gz$ we can write this in terms of the logarithm of pressure

\[\frac{\partial \Phi}{\partial \ln p} = -R_dT_v.\]

Note that we use the Virtual temperature here as we replaced the density through the ideal gas law with temperature. Given a vertical temperature profile $T_v$ and the (constant) surface geopotential $\Phi_s = gz_s$ where $z_s$ is the orography, we can integrate this equation from the surface to the top to obtain $\Phi_k$ on every layer $k$. The surface is at $k = N+\tfrac{1}{2}$ (see Vertical coordinates) with $N$ vertical levels. We can integrate the geopotential onto half levels as

\[\Phi_{k-\tfrac{1}{2}} = \Phi_{k+\tfrac{1}{2}} + R_dT^v_k(\ln p_{k+1/2} - \ln p_{k-1/2})\]

Surface pressure tendency

Vertical advection

Pressure gradient force

Temperature equation

Semi-implicit time stepping

Horizontal diffusion

Algorithm

Scaled primitive equations

References

diff --git a/previews/PR363/ringgrids/index.html b/previews/PR363/ringgrids/index.html index 0d6c2c90c..61384bf45 100644 --- a/previews/PR363/ringgrids/index.html +++ b/previews/PR363/ringgrids/index.html @@ -1,93 +1,93 @@ Submodule: RingGrids · SpeedyWeather.jl

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.

RingGrids defines and exports the following grids:

  • full grids: FullClenshawGrid, FullGaussianGrid, FullHEALPix, and FullOctaHEALPix
  • reduced grids: OctahedralGaussianGrid, OctahedralClenshawGrid, OctaHEALPixGrid and HEALPixGrid

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.

Creating data on a RingGrid

Every grid in RingGrids has a grid.data field, which is a vector containing the data on the grid. The grid points 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

using SpeedyWeather.RingGrids
 map = randn(Float32,8,4)
8×4 Matrix{Float32}:
-  1.45034   -0.769137   0.828825   1.24541
-  0.19498    2.17499   -1.06768    0.76814
- -0.147889  -1.10494    0.331278   2.76177
- -0.895345  -0.622672   0.297936  -1.07024
-  0.865572  -2.50509    0.822997  -1.06688
-  0.164673  -0.304     -2.03339   -1.86122
- -0.889738  -1.60382    0.472076   2.35863
-  0.84931    0.880966   0.11251    0.742577
grid = FullGaussianGrid(map)
32-element, 4-ring FullGaussianGrid{Float32}:
-  1.4503442
-  0.1949801
- -0.14788927
- -0.8953451
-  0.86557204
-  0.16467273
- -0.8897381
-  0.84930986
- -0.7691368
-  2.174987
+  0.172402  -0.574972   -0.623875  -0.874485
+  0.174117  -0.367367   -1.27495    0.766234
+ -0.631197  -1.41164     0.476643   0.481081
+ -1.16043    0.2979      0.66429   -0.354935
+  1.38484   -0.935798    0.627388  -0.286711
+ -1.63413    0.473669    1.31514   -1.04983
+ -0.119153  -0.0344194   1.98238    1.09886
+  1.22802    0.942186   -1.20831    0.0220523
grid = FullGaussianGrid(map)
32-element, 4-ring FullGaussianGrid{Float32}:
+  0.17240234
+  0.17411742
+ -0.6311972
+ -1.160433
+  1.3848385
+ -1.6341302
+ -0.11915335
+  1.2280228
+ -0.57497185
+ -0.36736703
   ⋮
-  0.11251031
-  1.2454102
-  0.76814044
-  2.7617674
- -1.0702449
- -1.0668834
- -1.8612213
-  2.358628
-  0.74257654

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. To reobtain the data from a grid, you can access its data field which returns a normal Vector

grid.data
32-element Vector{Float32}:
-  1.4503442
-  0.1949801
- -0.14788927
- -0.8953451
-  0.86557204
-  0.16467273
- -0.8897381
-  0.84930986
- -0.7691368
-  2.174987
+ -1.2083124
+ -0.8744849
+  0.76623416
+  0.48108116
+ -0.35493526
+ -0.2867113
+ -1.0498278
+  1.0988615
+  0.022052327

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. To reobtain the data from a grid, you can access its data field which returns a normal Vector

grid.data
32-element Vector{Float32}:
+  0.17240234
+  0.17411742
+ -0.6311972
+ -1.160433
+  1.3848385
+ -1.6341302
+ -0.11915335
+  1.2280228
+ -0.57497185
+ -0.36736703
   ⋮
-  0.11251031
-  1.2454102
-  0.76814044
-  2.7617674
- -1.0702449
- -1.0668834
- -1.8612213
-  2.358628
-  0.74257654

Which can be reshaped to reobtain map from above. Alternatively you can Matrix(grid) to do this in one step

map == Matrix(FullGaussianGrid(map))
true

You can also use zeros,ones,rand,randn to create a grid, whereby nlat_half, i.e. the number of latitude rings on one hemisphere, Equator included, is used as a resolution parameter and here as a second argument.

nlat_half = 4
+ -1.2083124
+ -0.8744849
+  0.76623416
+  0.48108116
+ -0.35493526
+ -0.2867113
+ -1.0498278
+  1.0988615
+  0.022052327

Which can be reshaped to reobtain map from above. Alternatively you can Matrix(grid) to do this in one step

map == Matrix(FullGaussianGrid(map))
true

You can also use zeros,ones,rand,randn to create a grid, whereby nlat_half, i.e. the number of latitude rings on one hemisphere, Equator included, is used as a resolution parameter and here as a second argument.

nlat_half = 4
 grid = randn(OctahedralGaussianGrid{Float16},nlat_half)
208-element, 8-ring OctahedralGaussianGrid{Float16}:
-  1.242
- -0.251
-  0.104
- -0.3623
-  1.071
- -2.492
- -1.808
-  1.164
- -0.2117
- -0.4324
+ -0.5547
+ -0.681
+  0.376
+ -1.488
+ -0.3816
+ -0.8984
+ -1.304
+  1.147
+ -0.1565
+  0.9653
   ⋮
-  0.1971
-  0.4397
- -1.727
-  0.4604
-  0.2238
-  0.517
- -0.482
- -1.107
-  1.169

and any element type T can be used for OctahedralGaussianGrid{T} and similar for other grid types.

Visualising RingGrid data

As only the full grids can be reshaped into a matrix, the underlying data structure of any AbstractGrid is a vector. As shown in the examples above, one can therefore inspect the data as if it was a vector. But as that data has, through its <:AbstractGrid type, all the geometric information available to plot it on a map, RingGrids also exports plot function, based on UnicodePlots' heatmap.

nlat_half = 24
+ -0.0683
+  0.2224
+ -1.512
+  0.875
+  0.07904
+ -0.895
+  0.2206
+ -1.048
+  1.322

and any element type T can be used for OctahedralGaussianGrid{T} and similar for other grid types.

Visualising RingGrid data

As only the full grids can be reshaped into a matrix, the underlying data structure of any AbstractGrid is a vector. As shown in the examples above, one can therefore inspect the data as if it was a vector. But as that data has, through its <:AbstractGrid type, all the geometric information available to plot it on a map, RingGrids also exports plot function, based on UnicodePlots' heatmap.

nlat_half = 24
 grid = randn(OctahedralGaussianGrid,nlat_half)
 plot(grid)
                   48-ring OctahedralGaussianGrid{Float64}                
        ┌────────────────────────────────────────────────────────────┐  3  
-    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
-       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄ ▄▄
-    ˚N ▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
-       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
-   -90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ └──┘
+    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄ ▄▄
+    ˚N ▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
+   -90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ └──┘
        └────────────────────────────────────────────────────────────┘ -4  
         0                           ˚E                           360      

Indexing RingGrids

All RingGrids 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 grid.

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_latdlonds for latitudes, longitudes per grid point not per ring)

grid = randn(OctahedralClenshawGrid,5)
 latd = get_latd(grid)
9-element Vector{Float64}:
@@ -111,161 +111,161 @@
 end

eachring creates a 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 grid-points like so

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

or use eachindex instead.

Interpolation on RingGrids

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 grid to another or to request an interpolated value on some coordinates. Using our data on grid which is an OctahedralGaussianGrid from above we can use the interpolate function to get it onto a FullGaussianGrid (or any other grid for purpose)

grid = randn(OctahedralGaussianGrid{Float32},4)
208-element, 8-ring OctahedralGaussianGrid{Float32}:
- -0.023611624
- -1.4215742
-  1.2625729
- -1.9099227
-  0.31232515
-  2.0914702
-  2.3564715
-  0.95933044
- -0.2039135
- -0.91697276
+  0.29091457
+ -1.9666979
+ -1.4992069
+ -0.43289363
+  0.6838523
+  0.14736961
+ -0.8463378
+  0.8591311
+  1.1511147
+ -1.2971116
   ⋮
-  0.7031553
- -0.6101837
- -2.6762547
- -0.11765983
-  0.059759904
- -0.5353389
- -1.774335
- -1.1087712
-  0.14376055
interpolate(FullGaussianGrid,grid)
128-element, 8-ring FullGaussianGrid{Float64}:
- -0.02361162379384041
- -0.7505374550819397
- -0.32367491722106934
- -0.24323683977127075
-  2.091470241546631
-  2.0071862637996674
-  0.3777084946632385
- -0.7387079298496246
- -0.06339944154024124
-  0.5023508667945862
+  0.14200644
+ -1.5352894
+  0.7011455
+ -0.47692725
+  1.0956415
+ -0.26189387
+ -0.04311793
+  0.24494652
+  0.3473296
interpolate(FullGaussianGrid,grid)
128-element, 8-ring FullGaussianGrid{Float64}:
+  0.2909145653247833
+ -1.8498251736164093
+ -0.9660502672195435
+  0.40466582775115967
+  0.1473696082830429
+ -0.4199705719947815
+  1.0051229000091553
+ -0.685055136680603
+ -1.0968680381774902
+  0.1900143027305603
   ⋮
-  0.7547551840543747
- -0.47378021478652954
-  0.3748205304145813
- -1.643219232559204
- -0.7573085427284285
-  0.05975990369915962
- -0.8450879156589508
- -1.4415531158447266
- -0.16937237977981567

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 nlat_half directly as 2nd argument

interpolate(FullGaussianGrid,6,grid)
288-element, 12-ring FullGaussianGrid{Float64}:
-  0.10575161086778878
- -0.6866738703330613
-  0.3720332927606863
- -0.09835496945565475
- -0.6734730055470701
-  0.5359589926531362
-  1.5444551647347322
-  1.6946693298129485
-  1.0911442941204417
-  0.3787342741509234
+ -0.14807027578353882
+  1.505887508392334
+ -0.27731750905513763
+ -0.4170719385147095
+ -0.18240907788276461
+  1.0956414937973022
+ -0.20719988271594048
+  0.10091429576277733
+  0.32173382118344307

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 nlat_half directly as 2nd argument

interpolate(FullGaussianGrid,6,grid)
288-element, 12-ring FullGaussianGrid{Float64}:
+  0.04729650207668812
+ -1.2324156186383521
+ -1.2763627991722943
+ -0.8077057563707345
+ -0.19183843716639554
+  0.25375707370610023
+ -0.05034446549994315
+ -0.6136206905023845
+  0.04711073723308179
+  0.5331094089668864
   ⋮
- -1.1937496836433894
- -1.3163038006978405
- -0.13593240837941628
- -0.03536325158830185
- -0.3726909153341882
- -1.0020096058278158
- -1.0565740198706985
- -0.5462162395515344
- -0.08645258643347672

So we got from an 8-ring OctahedralGaussianGrid{Float16} to a 12-ring FullGaussianGrid{Float64}, so it did a conversion from Float16 to Float64 on the fly too, because the default precision is Float64 unless specified. interpolate(FullGaussianGrid{Float16},6,grid) would have interpolated onto a grid with element type Float16.

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

interpolate(30.0,10.0,grid)
-0.4852893f0

we interpolated the data from grid 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],grid)
3-element Vector{Float32}:
- -0.4852893
- -0.22279498
-  0.14524831

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

Performance for RingGrid interpolation

Every time an interpolation like interpolate(30.0,10.0,grid) 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 vector
  • input grid
  • interpolator

The output vector 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. The input grid 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 the data is coming on 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 grid 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 grid. So in the case you want to interpolate from grid A to grid B many times, you can just reuse the same interpolator. If you want to change the coordinates of the output grid but its total number of points remain constants 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 an want to interpolate between them

grid_in = rand(HEALPixGrid,4)
+ -0.2939270404929439
+  0.19958463697565426
+ -0.15636136582656207
+  0.7350384226000093
+ -0.034471173444871245
+ -0.08916378016346517
+  0.0584132865275526
+  0.17959975629290142
+  0.2813753312738281

So we got from an 8-ring OctahedralGaussianGrid{Float16} to a 12-ring FullGaussianGrid{Float64}, so it did a conversion from Float16 to Float64 on the fly too, because the default precision is Float64 unless specified. interpolate(FullGaussianGrid{Float16},6,grid) would have interpolated onto a grid with element type Float16.

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

interpolate(30.0,10.0,grid)
0.6073423f0

we interpolated the data from grid 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],grid)
3-element Vector{Float32}:
+  0.6073423
+  0.27539527
+ -0.16804916

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

Performance for RingGrid interpolation

Every time an interpolation like interpolate(30.0,10.0,grid) 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 vector
  • input grid
  • interpolator

The output vector 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. The input grid 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 the data is coming on 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 grid 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 grid. So in the case you want to interpolate from grid A to grid B many times, you can just reuse the same interpolator. If you want to change the coordinates of the output grid but its total number of points remain constants 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 an want to interpolate between them

grid_in = rand(HEALPixGrid,4)
 grid_out = zeros(FullClenshawGrid,6)
 interp = RingGrids.interpolator(grid_out,grid_in)
SpeedyWeather.RingGrids.AnvilInterpolator{Float64, HEALPixGrid{Float64}}(SpeedyWeather.RingGrids.GridGeometry{HEALPixGrid{Float64}}(4, 7, 48, [90.0, 66.44353569089876, 41.8103148957786, 19.471220634490685, 0.0, -19.47122063449071, -41.81031489577862, -66.44353569089876, -90.00000000000001], [45.0, 135.0, 225.0, 315.0, 22.5, 67.5, 112.5, 157.5, 202.5, 247.49999999999997  …  112.5, 157.5, 202.5, 247.49999999999997, 292.5, 337.5, 45.0, 135.0, 225.0, 315.0], UnitRange{Int64}[1:4, 5:12, 13:20, 21:28, 29:36, 37:44, 45:48], [4, 8, 8, 8, 8, 8, 4], [45.0, 22.5, 0.0, 22.5, 0.0, 22.5, 45.0]), SpeedyWeather.RingGrids.AnvilLocator{Float64}(264, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0  …  7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0  …  46, 46, 47, 47, 47, 47, 47, 48, 48, 48], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0  …  47, 47, 48, 48, 48, 48, 48, 45, 45, 45], [4, 4, 4, 1, 1, 1, 1, 1, 1, 2  …  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 1, 1, 2, 2, 2, 2, 2, 2, 3  …  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251, 0.6367678868600251  …  0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741, 0.3632321131399741], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  …  0.8333333333333333, 0.9999999999999998, 0.16666666666666652, 0.33333333333333304, 0.5, 0.6666666666666665, 0.8333333333333326, 0.0, 0.16666666666666652, 0.3333333333333326], [0.5, 0.6666666666666667, 0.8333333333333333, 0.0, 0.16666666666666657, 0.33333333333333315, 0.5, 0.6666666666666666, 0.8333333333333331, 0.0  …  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))

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 of grid_in (and neither of grid_out which will be overwritten anyway). We can now do

interpolate!(grid_out,grid_in,interp)
 grid_out
264-element, 11-ring FullClenshawGrid{Float64}:
- 0.7192416833469395
- 0.7186014562266299
- 0.7179612291063203
- 0.7173210019860106
- 0.7039533999287401
- 0.6905857978714696
- 0.6772181958141991
- 0.6638505937569286
- 0.650482991699658
- 0.6371153896423875
+ 0.2513527816513096
+ 0.24919800411690873
+ 0.24704322658250794
+ 0.24488844904810708
+ 0.23503908949640107
+ 0.225189729944695
+ 0.21534037039298895
+ 0.2054910108412829
+ 0.19564165128957686
+ 0.1857922917378708
  ⋮
- 0.8262206083431115
- 0.7977633524442787
- 0.7693060965454458
- 0.7408488406466129
- 0.7123915847477801
- 0.6839343288489473
- 0.6554770729501143
- 0.69130052378784
- 0.7271239746255656

which is identical to interpolate(grid_out,grid_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)

grid_out = zeros(FullClenshawGrid{Float16},6);
+ 0.7620974001445889
+ 0.6739754700758476
+ 0.5858535400071062
+ 0.4977316099383645
+ 0.4096096798696231
+ 0.32148774980088185
+ 0.23336581973214
+ 0.2530129574047921
+ 0.2726600950774442

which is identical to interpolate(grid_out,grid_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)

grid_out = zeros(FullClenshawGrid{Float16},6);
 interpolate!(grid_out,grid_in,interp)
 grid_out
264-element, 11-ring FullClenshawGrid{Float16}:
- 0.719
- 0.7188
- 0.718
- 0.7173
- 0.704
- 0.6904
- 0.6772
- 0.664
- 0.6504
- 0.637
+ 0.2515
+ 0.2491
+ 0.2471
+ 0.2449
+ 0.235
+ 0.2252
+ 0.2153
+ 0.2054
+ 0.1957
+ 0.1858
  ⋮
- 0.826
- 0.798
- 0.7695
- 0.7407
- 0.7124
- 0.684
- 0.6553
- 0.6914
- 0.727

and we have converted data from a HEALPixGrid{Float64} (Float64 is always default if not specified) to a FullClenshawGrid{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

grid_in = randn(OctahedralGaussianGrid{Float16},24)
+ 0.762
+ 0.674
+ 0.586
+ 0.4978
+ 0.4097
+ 0.3215
+ 0.2334
+ 0.253
+ 0.2727

and we have converted data from a HEALPixGrid{Float64} (Float64 is always default if not specified) to a FullClenshawGrid{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

grid_in = randn(OctahedralGaussianGrid{Float16},24)
 grid_out = zeros(FullClenshawGrid{Float16},24)
 interp = RingGrids.interpolator(Float32,grid_out,grid_in)
 interpolate!(grid_out,grid_in,interp)
 grid_out
4512-element, 47-ring FullClenshawGrid{Float16}:
-  0.5845
-  0.558
-  0.5312
-  0.505
-  0.4783
-  0.4343
-  0.1938
- -0.04672
- -0.2874
- -0.659
+  0.0477
+  0.1415
+  0.2354
+  0.329
+  0.423
+  0.7705
+  0.804
+  0.838
+  0.8716
+  0.6377
   ⋮
-  0.919
-  0.4824
-  0.0865
- -0.3093
- -0.7056
- -0.848
- -0.792
- -0.736
- -0.68

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
+  0.502
+  0.263
+ -0.1031
+ -0.469
+ -0.835
+ -0.9624
+ -0.879
+ -0.7954
+ -0.7114

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
 interp = AnvilInterpolator(Float32,HEALPixGrid,24,npoints)
SpeedyWeather.RingGrids.AnvilInterpolator{Float32, HEALPixGrid}(SpeedyWeather.RingGrids.GridGeometry{HEALPixGrid}(24, 47, 1728, [90.0, 86.10076357950555, 82.19700324028634, 78.28414760510762, 74.35752898700072, 70.41233167174659, 66.44353569089876, 62.445854167002665, 58.41366190347208, 54.34091230386124  …  -54.340912303861266, -58.41366190347208, -62.445854167002665, -66.44353569089876, -70.41233167174661, -74.35752898700072, -78.28414760510763, -82.19700324028634, -86.10076357950557, -90.00000000000001], [45.0, 135.0, 225.0, 315.0, 22.5, 67.5, 112.5, 157.5, 202.5, 247.49999999999997  …  112.5, 157.5, 202.5, 247.49999999999997, 292.5, 337.5, 45.0, 135.0, 225.0, 315.0], UnitRange{Int64}[1:4, 5:12, 13:24, 25:40, 41:60, 61:84, 85:112, 113:144, 145:180, 181:220  …  1509:1548, 1549:1584, 1585:1616, 1617:1644, 1645:1668, 1669:1688, 1689:1704, 1705:1716, 1717:1724, 1725:1728], [4, 8, 12, 16, 20, 24, 28, 32, 36, 40  …  40, 36, 32, 28, 24, 20, 16, 12, 8, 4], [45.0, 22.5, 14.999999999999998, 11.25, 9.0, 7.499999999999999, 6.428571428571429, 5.625, 5.0, 4.5  …  4.5, 5.0, 5.625, 6.428571428571429, 7.499999999999999, 9.0, 11.25, 14.999999999999998, 22.5, 45.0]), SpeedyWeather.RingGrids.AnvilLocator{Float32}(10, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], Float32[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))

with the first argument being the number format used during interpolation, then the input grid type, its resolution in terms of nlat_half and then the number of points to interpolate onto. 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.

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

now we can update the locator inside our interpolator as follows

RingGrids.update_locator!(interp,latds,londs)

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

output_vec = zeros(10)
 grid_input = rand(HEALPixGrid,24)

we can use the interpolator as follows

interpolate!(output_vec,grid_input,interp)
10-element Vector{Float64}:
- 0.8970239089759661
- 0.5838913796400415
- 0.4799569743665579
- 0.4500436260041095
- 0.7113474721472308
- 0.5150504297427775
- 0.6706116923700589
- 0.8479604686163988
- 0.38892843699555785
- 0.45722166347976034

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

interpolate(latds,londs,grid_input)
10-element Vector{Float64}:
- 0.8970239094368069
- 0.5838913807280777
- 0.479956977984175
- 0.4500436197028597
- 0.7113474675240532
- 0.5150504246611989
- 0.6706116938754196
- 0.8479604625317156
- 0.3889284351729363
- 0.45722166369800477

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
+ 0.592285795164255
+ 0.676927249512242
+ 0.16786825639692987
+ 0.6212595677681279
+ 0.5793884662594403
+ 0.4192855790669207
+ 0.47954025880845086
+ 0.8344316587299363
+ 0.5813190101317496
+ 0.32499617558151006

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

interpolate(latds,londs,grid_input)
10-element Vector{Float64}:
+ 0.5922857941182887
+ 0.6769272511711661
+ 0.16786824754128132
+ 0.6212595690560092
+ 0.5793884677058145
+ 0.4192855792049245
+ 0.47954026041325837
+ 0.8344316468802933
+ 0.5813190085982898
+ 0.3249961757596744

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
@@ -278,22 +278,22 @@
           |<  Δ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

SpeedyWeather.RingGrids.AbstractFullGridType
abstract type AbstractFullGrid{T} <: AbstractGrid{T} end

An AbstractFullGrid is a horizontal grid with a constant number of longitude points across latitude rings. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.

source
SpeedyWeather.RingGrids.AbstractGridType
abstract type AbstractGrid{T} <: AbstractVector{T} end

The abstract supertype for all spatial grids on the sphere supported by SpeedyWeather.jl. Every new grid has to be of the form

abstract type AbstractGridClass{T} <: AbstractGrid{T} end
+^ 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

SpeedyWeather.RingGrids.AbstractFullGridType
abstract type AbstractFullGrid{T} <: AbstractGrid{T} end

An AbstractFullGrid is a horizontal grid with a constant number of longitude points across latitude rings. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.

source
SpeedyWeather.RingGrids.AbstractGridType
abstract type AbstractGrid{T} <: AbstractVector{T} end

The abstract supertype for all spatial grids on the sphere supported by SpeedyWeather.jl. Every new grid has to be of the form

abstract type AbstractGridClass{T} <: AbstractGrid{T} end
 struct MyNewGrid{T} <: AbstractGridClass{T}
     data::Vector{T}     # all grid points unravelled into a vector
     nlat_half::Int      # resolution: latitude rings on one hemisphere (Equator incl)
-end

MyNewGrid should belong to a grid class like AbstractFullGrid, AbstractOctahedralGrid or AbstractHEALPixGrid (that already exist but you may introduce a new class of grids) that share certain features such as the number of longitude points per latitude ring and indexing, but may have different latitudes or offset rotations. Each new grid Grid (or grid class) then has to implement the following methods (as an example, see octahedral.jl)

Fundamental grid properties getnpoints # total number of grid points nlatodd # does the grid have an odd number of latitude rings? getnlat # total number of latitude rings getnlat_half # number of latitude rings on one hemisphere incl Equator

Indexing getnlonmax # maximum number of longitudes points (at the Equator) getnlonperring # number of longitudes on ring j eachindexinring # a unit range that indexes all longitude points on a ring

Coordinates getcolat # vector of colatitudes (radians) getcolatlon # vectors of colatitudes, longitudes (both radians)

Spectral truncation truncationorder # linear, quadratic, cubic = 1,2,3 for grid gettruncation # spectral truncation given a grid resolution get_resolution # grid resolution given a spectral truncation

Quadrature weights and solid angles getquadratureweights # = sinθ Δθ for grid points on ring j for meridional integration getsolidangle # = sinθ Δθ Δϕ, solid angle of grid points on ring j

source
SpeedyWeather.RingGrids.AbstractHEALPixGridType
abstract type AbstractHEALPixGrid{T} <: AbstractGrid{T} end

An AbstractHEALPixGrid is a horizontal grid similar to the standard HEALPixGrid, but different latitudes can be used, the default HEALPix latitudes or others.

source
SpeedyWeather.RingGrids.AbstractInterpolatorType
abstract type AbstractInterpolator{NF,G} 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
AbstractLocator{NF}

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.AbstractOctaHEALPixGridType
abstract type AbstractOctaHEALPixGrid{T} <: AbstractGrid{T} end

An AbstractOctaHEALPixGrid is a horizontal grid similar to the standard OctahedralGrid, but the number of points in the ring closest to the Poles starts from 4 instead of 20, and the longitude of the first point in each ring is shifted as in HEALPixGrid. Also, different latitudes can be used.

source
SpeedyWeather.RingGrids.AbstractOctahedralGridType
abstract type AbstractOctahedralGrid{T} <: AbstractGrid{T} end

An AbstractOctahedralGrid is a horizontal grid with 16+4i longitude points on the latitude ring i starting with i=1 around the pole. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.

source
SpeedyWeather.RingGrids.AnvilLocatorType
AnvilLocator{NF<:AbstractFloat} <: AbtractLocator

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.AnvilLocatorMethod
L = AnvilLocator(   ::Type{NF},         # number format used for the interpolation
+end

MyNewGrid should belong to a grid class like AbstractFullGrid, AbstractOctahedralGrid or AbstractHEALPixGrid (that already exist but you may introduce a new class of grids) that share certain features such as the number of longitude points per latitude ring and indexing, but may have different latitudes or offset rotations. Each new grid Grid (or grid class) then has to implement the following methods (as an example, see octahedral.jl)

Fundamental grid properties getnpoints # total number of grid points nlatodd # does the grid have an odd number of latitude rings? getnlat # total number of latitude rings getnlat_half # number of latitude rings on one hemisphere incl Equator

Indexing getnlonmax # maximum number of longitudes points (at the Equator) getnlonperring # number of longitudes on ring j eachindexinring # a unit range that indexes all longitude points on a ring

Coordinates getcolat # vector of colatitudes (radians) getcolatlon # vectors of colatitudes, longitudes (both radians)

Spectral truncation truncationorder # linear, quadratic, cubic = 1,2,3 for grid gettruncation # spectral truncation given a grid resolution get_resolution # grid resolution given a spectral truncation

Quadrature weights and solid angles getquadratureweights # = sinθ Δθ for grid points on ring j for meridional integration getsolidangle # = sinθ Δθ Δϕ, solid angle of grid points on ring j

source
SpeedyWeather.RingGrids.AbstractHEALPixGridType
abstract type AbstractHEALPixGrid{T} <: AbstractGrid{T} end

An AbstractHEALPixGrid is a horizontal grid similar to the standard HEALPixGrid, but different latitudes can be used, the default HEALPix latitudes or others.

source
SpeedyWeather.RingGrids.AbstractInterpolatorType
abstract type AbstractInterpolator{NF,G} 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
AbstractLocator{NF}

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.AbstractOctaHEALPixGridType
abstract type AbstractOctaHEALPixGrid{T} <: AbstractGrid{T} end

An AbstractOctaHEALPixGrid is a horizontal grid similar to the standard OctahedralGrid, but the number of points in the ring closest to the Poles starts from 4 instead of 20, and the longitude of the first point in each ring is shifted as in HEALPixGrid. Also, different latitudes can be used.

source
SpeedyWeather.RingGrids.AbstractOctahedralGridType
abstract type AbstractOctahedralGrid{T} <: AbstractGrid{T} end

An AbstractOctahedralGrid is a horizontal grid with 16+4i longitude points on the latitude ring i starting with i=1 around the pole. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.

source
SpeedyWeather.RingGrids.AnvilLocatorType
AnvilLocator{NF<:AbstractFloat} <: AbtractLocator

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.AnvilLocatorMethod
L = AnvilLocator(   ::Type{NF},         # number format used for the interpolation
                     npoints::Integer    # number of points to interpolate onto
-                    ) where {NF<:AbstractFloat}

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.FullClenshawGridType
G = FullClenshawGrid{T}

A FullClenshawGrid is a regular latitude-longitude grid with an odd number of nlat equi-spaced latitudes, the central latitude ring is on the Equator. The same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullGaussianGridType
G = FullGaussianGrid{T}

A full Gaussian grid is a regular latitude-longitude grid that uses nlat Gaussian latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullHEALPixGridType
G = FullHEALPixGrid{T}

A full HEALPix grid is a regular latitude-longitude grid that uses nlat latitudes from the HEALPix grid, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullOctaHEALPixGridType
G = FullOctaHEALPixGrid{T}

A full OctaHEALPix grid is a regular latitude-longitude grid that uses nlat OctaHEALPix latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.GridGeometryMethod
G = GridGeometry(   Grid::Type{<:AbstractGrid},
-                    nlat_half::Integer)

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

source
SpeedyWeather.RingGrids.HEALPixGridType
H = HEALPixGrid{T}

A HEALPix grid with 12 faces, each nsidexnside grid points, each covering the same area. The number of latitude rings on one hemisphere (incl Equator) nlat_half is used as resolution parameter. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctaHEALPixGridType
H = OctaHEALPixGrid{T}

A OctaHEALPix grid with 4 base faces, each nlat_halfxnlat_half grid points, each covering the same area. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctahedralClenshawGridType
G = OctahedralClenshawGrid{T}

An Octahedral Clenshaw grid that uses nlat equi-spaced latitudes. Like FullClenshawGrid, the central latitude ring is on the Equator. Like OctahedralGaussianGrid, the number of longitude points per latitude ring decreases towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctahedralGaussianGridType
G = OctahedralGaussianGrid{T}

An Octahedral Gaussian grid that uses nlat Gaussian latitudes, but a decreasing number of longitude points per latitude ring towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(M::AbstractMatrix,
+                    ) where {NF<:AbstractFloat}

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.FullClenshawGridType
G = FullClenshawGrid{T}

A FullClenshawGrid is a regular latitude-longitude grid with an odd number of nlat equi-spaced latitudes, the central latitude ring is on the Equator. The same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullGaussianGridType
G = FullGaussianGrid{T}

A full Gaussian grid is a regular latitude-longitude grid that uses nlat Gaussian latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullHEALPixGridType
G = FullHEALPixGrid{T}

A full HEALPix grid is a regular latitude-longitude grid that uses nlat latitudes from the HEALPix grid, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.FullOctaHEALPixGridType
G = FullOctaHEALPixGrid{T}

A full OctaHEALPix grid is a regular latitude-longitude grid that uses nlat OctaHEALPix latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.GridGeometryMethod
G = GridGeometry(   Grid::Type{<:AbstractGrid},
+                    nlat_half::Integer)

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

source
SpeedyWeather.RingGrids.HEALPixGridType
H = HEALPixGrid{T}

A HEALPix grid with 12 faces, each nsidexnside grid points, each covering the same area. The number of latitude rings on one hemisphere (incl Equator) nlat_half is used as resolution parameter. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctaHEALPixGridType
H = OctaHEALPixGrid{T}

A OctaHEALPix grid with 4 base faces, each nlat_halfxnlat_half grid points, each covering the same area. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctahedralClenshawGridType
G = OctahedralClenshawGrid{T}

An Octahedral Clenshaw grid that uses nlat equi-spaced latitudes. Like FullClenshawGrid, the central latitude ring is on the Equator. Like OctahedralGaussianGrid, the number of longitude points per latitude ring decreases towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.OctahedralGaussianGridType
G = OctahedralGaussianGrid{T}

An Octahedral Gaussian grid that uses nlat Gaussian latitudes, but a decreasing number of longitude points per latitude ring towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(M::AbstractMatrix,
         G::OctaHEALPixGrid;
         quadrant_rotation=(0,1,2,3),
         matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),
-        )

Sorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(M::AbstractMatrix,
+        )

Sorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(M::AbstractMatrix,
         G::OctahedralClenshawGrid;
         quadrant_rotation=(0,1,2,3),
         matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),
-        )

Sorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(MGs::Tuple{AbstractMatrix{T},OctaHEALPixGrid}...;kwargs...)

Like Matrix!(::AbstractMatrix,::OctaHEALPixGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(MGs::Tuple{AbstractMatrix{T},OctahedralClenshawGrid}...;kwargs...)

Like Matrix!(::AbstractMatrix,::OctahedralClenshawGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.

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

Sorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(MGs::Tuple{AbstractMatrix{T},OctaHEALPixGrid}...;kwargs...)

Like Matrix!(::AbstractMatrix,::OctaHEALPixGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.

source
SpeedyWeather.RingGrids.Matrix!Method
Matrix!(MGs::Tuple{AbstractMatrix{T},OctahedralClenshawGrid}...;kwargs...)

Like Matrix!(::AbstractMatrix,::OctahedralClenshawGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.

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   >|
 
@@ -305,29 +305,29 @@
     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::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},
     rings::Vector{<:UnitRange{<:Integer}}
 ) -> 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(
+

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::SpeedyWeather.RingGrids.AbstractGrid{NF<:Integer},
     rings::Vector{<:UnitRange{<:Integer}}
 ) -> Tuple{Any, Any}
-

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

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

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

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

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

rings = eachring(grid)
 for ring in rings
     for ij in ring
-        grid[ij]
source
SpeedyWeather.RingGrids.eachringMethod
eachring(
     grid1::SpeedyWeather.RingGrids.AbstractGrid,
     grids::Grid<:SpeedyWeather.RingGrids.AbstractGrid...
 ) -> Any
-

Same as eachring(grid) but performs a bounds check to assess that all grids in grids are of same size.

source
SpeedyWeather.RingGrids.get_nlonsMethod
get_nlons(
     Grid::Type{<:SpeedyWeather.RingGrids.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 both_hemisphere==false only the northern hemisphere (incl Equator) is returned.

source
SpeedyWeather.RingGrids.whichringMethod
whichring(
+

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 both_hemisphere==false only the northern hemisphere (incl Equator) is returned.

source
SpeedyWeather.RingGrids.whichringMethod
whichring(
     ij::Integer,
     rings::Vector{UnitRange{Int64}}
 ) -> Int64
-

Obtain ring index j from gridpoint ij and Vector{UnitRange} describing rind indices as obtained from eachring(::Grid)

source
+

Obtain ring index j from gridpoint ij and Vector{UnitRange} describing rind indices as obtained from eachring(::Grid)

source diff --git a/previews/PR363/search/index.html b/previews/PR363/search/index.html index 6de583e57..2140f8c5d 100644 --- a/previews/PR363/search/index.html +++ b/previews/PR363/search/index.html @@ -1,2 +1,2 @@ -Search · SpeedyWeather.jl

Loading search...

    +Search · SpeedyWeather.jl

    Loading search...

      diff --git a/previews/PR363/search_index.js b/previews/PR363/search_index.js index f472f34d2..ff0ca222d 100644 --- a/previews/PR363/search_index.js +++ b/previews/PR363/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"parameterizations/#parameterizations","page":"Parameterizations","title":"Parameterizations","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"This page describes the mathematical formulation of the parameterizations used in SpeedyWeather.jl to represent physical processes in the atmosphere. Every section is followed by a brief description of implementation details.","category":"page"},{"location":"parameterizations/#Convection","page":"Parameterizations","title":"Convection","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Large-scale-condensation","page":"Parameterizations","title":"Large-scale condensation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Clouds","page":"Parameterizations","title":"Clouds","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Short-wave-radiation","page":"Parameterizations","title":"Short-wave radiation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Long-wave-radiation","page":"Parameterizations","title":"Long-wave radiation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Surface-fluxes-of-momentum-and-energy","page":"Parameterizations","title":"Surface fluxes of momentum and energy","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Vertical-diffusion","page":"Parameterizations","title":"Vertical diffusion","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"development/#Development-notes","page":"Development notes","title":"Development notes","text":"","category":"section"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To run tests, from the path of your local clone of the repository do:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project=. -e 'import Pkg; Pkg.test()'","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To install dependencies:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project -e 'import Pkg; Pkg.instantiate()`","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"then opening:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"you are able to using SpeedyWeather.","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To generate the docs:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project=docs -e 'import Pkg; Pkg.develop(path=\".\"); Pkg.instantiate()'\njulia --project=docs docs/make.jl","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"If the docs are generated successfully, you view them by opening docs/build/index.html in your favorite browser.","category":"page"},{"location":"barotropic/#Barotropic-vorticity-model","page":"Barotropic model","title":"Barotropic vorticity model","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The barotropic vorticity model describes the evolution of a 2D non-divergent flow with velocity components mathbfu = (uv) through self-advection, forces and dissipation. Due to the non-divergent nature of the flow, it can be described by (the vertical component) of the relative vorticity zeta = nabla times mathbfu.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The dynamical core presented here to solve the barotropic vorticity equations largely follows the idealized models with spectral dynamics developed at the Geophysical Fluid Dynamics Laboratory[1]: A barotropic vorticity model[2].","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Many concepts of the Shallow water model and the Primitive equation model are similar, such that for example horizontal diffusion and the Time integration are only explained here.","category":"page"},{"location":"barotropic/#Barotropic-vorticity-equation","page":"Barotropic model","title":"Barotropic vorticity equation","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The barotropic vorticity equation is the prognostic equation that describes the time evolution of relative vorticity zeta with advection, Coriolis force, forcing and diffusion in a single global layer on the sphere.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fracpartial zetapartial t + nabla cdot (mathbfu(zeta + f)) =\nnabla times mathbfF + (-1)^n+1nunabla^2nzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"We denote timet, velocity vector mathbfu = (u v), Coriolis parameter f, and hyperdiffusion (-1)^n+1 nu nabla^2n zeta (n is the hyperdiffusion order, see Horizontal diffusion). We also include a forcing vector mathbfF = (F_uF_v) which acts on the zonal velocity u and the meridional velocity v and hence its curl nabla times mathbfF is a tendency for relative vorticity zeta.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Starting with some relative vorticity zeta, the Laplacian is inverted to obtain the stream function Psi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Psi = nabla^-2zeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The zonal velocity u and meridional velocity v are then the (negative) meridional gradient and zonal gradient of Psi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"beginaligned\nu = -frac1R fracpartial Psipartial theta \nv = frac1Rcos(theta) fracpartial Psipartial phi \nendaligned","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"which is described in Derivatives in spherical coordinates. Using u and v we can then advect the absolute vorticity zeta + f. In order to avoid to calculate both the curl and the divergence of a flux we rewrite the barotropic vorticity equation as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fracpartial zetapartial t =\nnabla times (mathbfF + mathbfu_perp(zeta + f)) + (-1)^n+1nunabla^2nzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with mathbfu_perp = (v-u) the rotated velocity vector, because -nablacdotmathbfu = nabla times mathbfu_perp. This is the form that is solved in the BarotropicModel, as outlined in the following section.","category":"page"},{"location":"barotropic/#Algorithm","page":"Barotropic model","title":"Algorithm","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"We briefly outline the algorithm that SpeedyWeather.jl uses in order to integrate the barotropic vorticity equation. As an initial step","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"0. Start with initial conditions of zeta_lm in spectral space and transform this model state to grid-point space:","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Invert the Laplacian of vorticity zeta_lm to obtain the stream function Psi_lm in spectral space\nobtain zonal velocity (cos(theta)u)_lm through a Meridional derivative\nobtain meridional velocity (cos(theta)v)_lm through a Zonal derivative\nTransform zonal and meridional velocity (cos(theta)u)_lm, (cos(theta)v)_lm to grid-point space\nUnscale the cos(theta) factor to obtain uv\nTransform zeta_lm to zeta in grid-point space","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Now loop over","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Compute the forcing vector mathbfF = (F_uF_v) for u and v\nMultiply uv with zeta+f in grid-point space\nAdd A = F_u + v(zeta + f) and B = F_v - u(zeta + f)\nTransform these vector components to spectral space A_lm, B_lm\nCompute the curl of (AB)_lm in spectral space which is the tendency of zeta_lm\nCompute the horizontal diffusion based on that tendency\nCompute a leapfrog time step as described in Time integration with a Robert-Asselin and Williams filter\nTransform the new spectral state of zeta_lm to grid-point uvzeta as described in 0.\nPossibly do some output\nRepeat from 1.","category":"page"},{"location":"barotropic/#diffusion","page":"Barotropic model","title":"Horizontal diffusion","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In SpeedyWeather.jl we use hyerdiffusion through an n-th power Laplacian (-1)^n+1nabla^2n (hyper when n1) which can be implemented as a multiplication of the spectral coefficients Psi_lm with (-l(l+1))^nR^-2n (see spectral Laplacian) It is therefore computationally not more expensive to apply hyperdiffusion over diffusion as the (-l(l+1))^nR^-2n can be precomputed. Note the sign change (-1)^n+1 here is such that the dissipative nature of the diffusion operator is retained for n odd and even.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In SpeedyWeather.jl the diffusion is applied implicitly. For that, consider a leapfrog scheme with time step Delta t of variable zeta to obtain from time steps i-1 and i, the next time step i+1","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t dzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with dzeta being some tendency evaluated from zeta_i. Now we want to add a diffusion term (-1)^n+1nu nabla^2nzeta with coefficient nu, which however, is implicitly calculated from zeta_i+1, then","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t (dzeta + (-1)^n+1 nunabla^2nzeta_i+1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"As the application of (-1)^n+1nunabla^2n is, for every spectral mode, equivalent to a multiplication of a constant, we can rewrite this to","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = fraczeta_i-1 + 2Delta t dzeta1 - 2Delta (-1)^n+1nunabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and expand the numerator to","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t fracdzeta + (-1)^n+1 nunabla^2nzeta_i-11 - 2Delta t (-1)^n+1nu nabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Hence the diffusion can be applied implicitly by updating the tendency dzeta as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"dzeta to fracdzeta + (-1)^n+1nunabla^2nzeta_i-11 - 2Delta t nu nabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"which only depends on zeta_i-1. Now let D_textexplicit = (-1)^n+1nunabla^2n be the explicit part and D_textimplicit = 1 - (-1)^n+1 2Delta t nunabla^2n the implicit part. Both parts can be precomputed and are D_textimplicit = 1 - 2Delta t nunabla^2n the implicit part. Both parts can be precomputed and are only an element-wise multiplication in spectral space. For every spectral harmonic lm we do","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"dzeta to D_textimplicit^-1(dzeta + D_textexplicitzeta_i-1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Hence 2 multiplications and 1 subtraction with precomputed constants. However, we will normalize the (hyper-)Laplacians as described in the following. This also will take care of the alternating sign such that the diffusion operation is dissipative regardless the power n.","category":"page"},{"location":"barotropic/#Normalization-of-diffusion","page":"Barotropic model","title":"Normalization of diffusion","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In physics, the Laplace operator nabla^2 is often used to represent diffusion due to viscosity in a fluid or diffusion that needs to be added to retain numerical stability. In both cases, the coefficient is nu of units textm^2texts^-1 and the full operator reads as nu nabla^2 with units (textm^2texts^-1)(textm^-2) = texts^-1. This motivates us to normalize the Laplace operator by a constant of units textm^-2 and the coefficient by its inverse such that it becomes a damping timescale of unit texts^-1. Given the application in spectral space we decide to normalize by the largest eigenvalue -l_textmax(l_textmax+1) such that all entries in the discrete spectral Laplace operator are in 01. This also has the effect that the alternating sign drops out, such that higher wavenumbers are always dampened and not amplified. The normalized coefficient nu^* = l_textmax(l_textmax+1)nu (always positive) is therefore reinterpreted as the (inverse) time scale at which the highest wavenumber is dampened to zero due to diffusion. Together we have ","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"D^textexplicit_lm = -nu^* fracl(l+1)l_textmax(l_textmax+1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and the hyper-Laplacian of power n follows as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"D^textexplicitn_lm = -nu^* left(fracl(l+1)l_textmax(l_textmax+1)right)^n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and the implicit part is accordingly D^textimplicitn_lm = 1 - 2Delta t D^textexplicitn_lm. Note that the diffusion time scale nu^* is then also scaled by the radius, see next section.","category":"page"},{"location":"barotropic/#scaling","page":"Barotropic model","title":"Radius scaling","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Similar to a non-dimensionalization of the equations, SpeedyWeather.jl scales the barotropic vorticity equation with R^2 to obtain normalized gradient operators as follows. A scaling for vorticity zeta and stream function Psi is used that is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildezeta = zeta R tildePsi = Psi R^-1","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"This is also convenient as vorticity is often 10^-5text s^-1 in the atmosphere, but the streamfunction more like 10^5text m^2text s^-1 and so this scaling brings both closer to 1 with a typical radius of the Earth of 6371km. The inversion of the Laplacians in order to obtain Psi from zeta therefore becomes","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildezeta = tildenabla^2 tildePsi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"where the dimensionless gradients simply omit the scaling with 1R, tildenabla = Rnabla. The Barotropic vorticity equation scaled with R^2 is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"partial_tildettildezeta + tildenabla cdot (mathbfu(tildezeta + tildef)) =\nnabla times tildemathbfF + (-1)^n+1tildenutildenabla^2ntildezeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildet = tR^-1, the scaled time t\nmathbfu = (uv), the velocity vector (no scaling applied)\ntildef = fR, the scaled Coriolis parameter f\ntildemathbfF = RmathbfF, the scaled forcing vector mathbfF\ntildenu = nu^* R, the scaled diffusion coefficient nu^*, which itself is normalized to a damping time scale, see Normalization of diffusion.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"So scaling with the radius squared means we can use dimensionless operators, however, this comes at the cost of needing to deal with both a time step in seconds as well as a scaled time step in seconds per meter, which can be confusing. Furthermore, some constants like Coriolis or the diffusion coefficient need to be scaled too during initialisation, which may be confusing too because values are not what users expect them to be. SpeedyWeather.jl follows the logic that the scaling to the prognostic variables is only applied just before the time integration and variables are unscaled for output and after the time integration finished. That way, the scaling is hidden as much as possible from the user. In hopefully many other cases it is clearly denoted that a variable or constant is scaled.","category":"page"},{"location":"barotropic/#leapfrog","page":"Barotropic model","title":"Time integration","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"SpeedyWeather.jl is based on the Leapfrog time integration, which, for relative vorticity zeta, is in its simplest form","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fraczeta_i+1 - zeta_i-12Delta t = RHS(zeta_i)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"meaning we step from the previous time step i-1, leapfrogging over the current time stepi to the next time step i+1 by evaluating the tendencies on the right-hand side RHS at the current time step i. The time stepping is done in spectral space. Once the right-hand side RHS is evaluated, leapfrogging is a linear operation, meaning that its simply applied to every spectral coefficient zeta_lm as one would evaluate it on every grid point in grid-point models.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"For the Leapfrog time integration two time steps of the prognostic variables have to be stored, i-1 and i. Time step i is used to evaluate the tendencies which are then added to i-1 in a step that also swaps the indices for the next time step i to i-1 and i+1 to i, so that no additional memory than two time steps have to be stored at the same time.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The Leapfrog time integration has to be initialised with an Euler forward step in order to have a second time step i+1 available when starting from i to actually leapfrog over. SpeedyWeather.jl therefore does two initial time steps that are different from the leapfrog time steps that follow and that have been described above.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"an Euler forward step with Delta t2, then\none leapfrog time step with Delta t, then\nleapfrog with 2 Delta t till the end","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"This is particularly done in a way that after 2. we have t=0 at i-1 and t=Delta t at i available so that 3. can start the leapfrogging without any offset from the intuitive spacing 0Delta t 2Delta t 3Delta t. The following schematic can be useful","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":" time at step i-1 time at step i time step at i+1\nInitial conditions t = 0 \n1: Euler (T) quad t = 0 t=Delta t2 \n2: Leapfrog with Delta t t = 0 (T) quad t = Delta t2 t = Delta t\n3 to n: Leapfrog with 2Delta t t-Delta t (T) qquad quad quad t t+Delta t","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The time step that is used to evaluate the tendencies is denoted with (T). It is always the time step furthest in time that is available.","category":"page"},{"location":"barotropic/#Robert-Asselin-and-Williams-filter","page":"Barotropic model","title":"Robert-Asselin and Williams filter","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The standard leapfrog time integration is often combined with a Robert-Asselin filter[Robert66][Asselin72] to dampen a computational mode. The idea is to start with a standard leapfrog step to obtain the next time step i+1 but then to correct the current time step i by applying a filter which dampens the computational mode. The filter looks like a discrete Laplacian in time with a (1 -2 1) stencil, and so, maybe unsurprisingly, is efficient to filter out a \"grid-scale oscillation\" in time, aka the computational mode. Let v be the unfiltered variable and u be the filtered variable, F the right-hand side tendency, then the standard leapfrog step is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"v_i+1 = u_i-1 + 2Delta tF(v_i)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Meaning we start with a filtered variable u at the previous time step i-1, evaluate the tendency F(v_i) based on the current time step i to obtain an unfiltered next time step v_i+1. We then filter the current time step i (which will become i-1 on the next iteration)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"u_i = v_i + fracnu2(v_i+1 - 2v_i + u_i-1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"by adding a discrete Laplacian with coefficient tfracnu2 to it, evaluated from the available filtered and unfiltered time steps centred around i: v_i-1 is not available anymore because it was overwritten by the filtering at the previous iteration, u_i u_i+1 are not filtered yet when applying the Laplacian. The filter parameter nu is typically chosen between 0.01-0.2, with stronger filtering for higher values.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Williams[Williams2009] then proposed an additional filter step to regain accuracy that is otherwise lost with a strong Robert-Asselin filter[Amezcua2011][Williams2011]. Now let w be unfiltered, v be once filtered, and u twice filtered, then","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"beginaligned\nw_i+1 = u_i-1 + 2Delta tF(v_i) \nu_i = v_i + fracnualpha2(w_i+1 - 2v_i + u_i-1) \nv_i+1 = w_i+1 - fracnu(1-alpha)2(w_i+1 - 2v_i + u_i-1)\nendaligned","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with the Williams filter parameter alpha in 051. For alpha=1 we're back with the Robert-Asselin filter (the first two lines).","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The Laplacian in the parentheses is often called a displacement, meaning that the filtered value is displaced (or corrected) in the direction of the two surrounding time steps. The Williams filter now also applies the same displacement, but in the opposite direction to the next time step i+1 as a correction step (line 3 above) for a once-filtered value v_i+1 which will then be twice-filtered by the Robert-Asselin filter on the next iteration. For more details see the referenced publications.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The initial Euler step (see Time integration, Table) is not filtered. Both the the Robert-Asselin and Williams filter are then switched on for all following leapfrog time steps.","category":"page"},{"location":"barotropic/#References","page":"Barotropic model","title":"References","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The barotropic vorticity equation.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Robert66]: Robert, André. “The Integration of a Low Order Spectral Form of the Primitive Meteorological Equations.” Journal of the Meteorological Society of Japan 44 (1966): 237-245.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Asselin72]: ASSELIN, R., 1972: Frequency Filter for Time Integrations. Mon. Wea. Rev., 100, 487–490, doi:10.1175/1520-0493(1972)100<0487:FFFTI>2.3.CO;2","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Williams2009]: Williams, P. D., 2009: A Proposed Modification to the Robert–Asselin Time Filter. Mon. Wea. Rev., 137, 2538–2546, 10.1175/2009MWR2724.1.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Amezcua2011]: Amezcua, J., E. Kalnay, and P. D. Williams, 2011: The Effects of the RAW Filter on the Climatology and Forecast Skill of the SPEEDY Model. Mon. Wea. Rev., 139, 608–619, doi:10.1175/2010MWR3530.1. ","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Williams2011]: Williams, P. D., 2011: The RAW Filter: An Improvement to the Robert–Asselin Filter in Semi-Implicit Integrations. Mon. Wea. Rev., 139, 1996–2007, doi:10.1175/2010MWR3601.1. ","category":"page"},{"location":"installation/#Installation","page":"Installation","title":"Installation","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"SpeedyWeather.jl is registered in the Julia Registry. In most cases just open the Julia REPL and type","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia> using Pkg\njulia> Pkg.add(\"SpeedyWeather\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"or, equivalently, (] opens the package manager)","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia>] add SpeedyWeather","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"which will automatically install the latest release and all necessary dependencies. If you run into any troubles please raise an issue.","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"However, you may want to make use of the latest features, then install directly from the main branch with","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia> Pkg.add(url=\"https://github.com/SpeedyWeather/SpeedyWeather.jl\",rev=\"main\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"other branches than main can be similarly installed. You can also type, equivalently,","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia>] add https://github.com/SpeedyWeather/SpeedyWeather.jl#main","category":"page"},{"location":"installation/#Compatibility-with-Julia-versions","page":"Installation","title":"Compatibility with Julia versions","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"SpeedyWeather.jl usually lives on the latest minor release and/or its predecessor. At the moment (June 2023) this means ","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"Julia v1.8\nJulia v1.9","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"are supported, but we dropped the support of earlier versions.","category":"page"},{"location":"output/#NetCDF-output","page":"NetCDF output","title":"NetCDF output","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"SpeedyWeather.jl uses NetCDF to output the data of a simulation. The following describes the details of this and how to change the way in which the NetCDF output is written. There are many options to this available.","category":"page"},{"location":"output/#Accessing-the-NetCDF-output-writer","page":"NetCDF output","title":"Accessing the NetCDF output writer","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"The output writer is a component of every Model, i.e. BarotropicModel, ShallowWaterModel, PrimitiveDryModel and PrimitiveWetModel, hence a non-default output writer can be passed on as a keyword argument to the model constructor","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> using SpeedyWeather\njulia> spectral_grid = SpectralGrid()\njulia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry)\njulia> model = PrimitiveDryModel(;spectral_grid, output=my_output_writer)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"So after we have defined the grid through the SpectralGrid object we can use and change the implemented OutputWriter by passing on the following arguments","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, kwargs...)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"the spectral_grid has to be the first argument then the model type (Barotropic, ShallowWater, PrimitiveDry, PrimitiveWet) which helps the output writer to make default choices on which variables to output. However, we can also pass on further keyword arguments. So let's start with an example.","category":"page"},{"location":"output/#Example-1:-NetCDF-output-every-hour","page":"NetCDF output","title":"Example 1: NetCDF output every hour","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"If we want to increase the frequency of the output we can choose output_dt (default =6 in hours) like so","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, output_dt=1)\njulia> model = PrimitiveDryModel(;spectral_grid, output=my_output_writer)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"which will now output every hour. It is important to pass on the new output writer my_output_writer to the model constructor, otherwise it will not be part of your model and the default is used instead. Note that output_dt has to be understood as the minimum frequency or maximum output time step. Example, we run the model at a resolution of T85 and the time step is going to be 670s","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> spectral_grid = SpectralGrid(trunc=85)\njulia> time_stepper = Leapfrog(spectral_grid)\nLeapfrog{Float32}:\n...\n Δt_sec::Int64 = 670\n...","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This means that after 32 time steps 5h 57min and 20s will have passed where output will happen as the next time step would be >6h. The time axis of the NetCDF output will look like","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> using NCDatasets\njulia> ds = NCDataset(\"run_0001/output.nc\");\njulia> ds[\"time\"][:]\n5-element Vector{Dates.DateTime}:\n 2000-01-01T00:00:00\n 2000-01-01T05:57:20\n 2000-01-01T11:54:40\n 2000-01-01T17:52:00\n 2000-01-01T23:49:20\n\njulia> diff(ds[\"time\"][:])\n4-element Vector{Dates.Millisecond}:\n 21440000 milliseconds\n 21440000 milliseconds\n 21440000 milliseconds\n 21440000 milliseconds","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This is so that we don't interpolate in time during output to hit exactly every 6 hours, but at the same time have a constant spacing in time between output time steps.","category":"page"},{"location":"output/#Example-2:-Output-onto-a-higher/lower-resolution-grid","page":"NetCDF output","title":"Example 2: Output onto a higher/lower resolution grid","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Say we want to run the model at a given horizontal resolution but want to output on another resolution, the OutputWriter takes as argument output_Grid<:AbstractFullGrid and nlat_half::Int. So for example output_Grid=FullClenshawGrid and nlat_half=48 will always interpolate onto a regular 192x95 longitude-latitude grid of 1.875˚ resolution, regardless the grid and resolution used for the model integration.","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, output_Grid=FullClenshawGrid, nlat_half=48)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Note that by default the output is on the corresponding full of the grid used in the dynamical core so that interpolation only happens at most in the zonal direction as they share the location of the latitude rings. You can check this by","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> RingGrids.full_grid(OctahedralGaussianGrid)\nFullGaussianGrid","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"So the corresponding full grid of an OctahedralGaussianGrid is the FullGaussiangrid and the same resolution nlat_half is chosen by default in the output writer (which you can change though as shown above). Overview of the corresponding full grids","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Grid Corresponding full grid\nFullGaussianGrid FullGaussianGrid\nFullClenshawGrid FullClenshawGrid\nOctahadralGaussianGrid FullGaussianGrid\nOctahedralClensawhGrid FullClenshawGrid\nHEALPixGrid FullHEALPixGrid\nOctaHEALPixGrid FullOctaHEALPixGrid","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"The grids FullHEALPixGrid, FullOctaHEALPixGrid share the same latitude rings as their reduced grids, but have always as many longitude points as they are at most around the equator. These grids are not tested in the dynamical core (but you may use them experimentally) and mostly designed for output purposes.","category":"page"},{"location":"output/#Example-3:-Changing-the-output-path-or-identification","page":"NetCDF output","title":"Example 3: Changing the output path or identification","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"That's easy by passing on path=\"/my/favourite/path/\" and the folder run_* with * the identification of the run (that's the id keyword, which can be manually set but is also automatically determined as a number counting up depending on which folders already exist) will be created within.","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> path = pwd()\n\"/Users/milan\"\njulia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, path=path)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This folder must already exist. If you want to give your run a name/identification you can pass on id","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid,PrimitiveDry,id=\"diffusion_test\");","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"which will be used instead of a 4 digit number like 0001, 0002 which is automatically determined if id is not provided. You will see the id of the run in the progress bar","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Weather is speedy: run diffusion_test 100%|███████████████████████| Time: 0:00:12 (19.20 years/day)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"and the run folder, here run_diffusion_test, is also named accordingly","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"shell> ls\n...\nrun_diffusion_test\n...","category":"page"},{"location":"output/#Further-options","page":"NetCDF output","title":"Further options","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Further options are described in the OutputWriter docstring, (also accessible via julia>?OutputWriter for example). Note that some fields are actual options, but others are derived from the options you provided or are arrays/objects the output writer needs, but shouldn't be passed on by the user. The actual options are declared as [OPTION] in the following","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"OutputWriter","category":"page"},{"location":"functions/#Function-and-type-index","page":"Function and type index","title":"Function and type index","text":"","category":"section"},{"location":"functions/","page":"Function and type index","title":"Function and type index","text":"Modules = [SpeedyWeather]","category":"page"},{"location":"functions/#SpeedyWeather.AbstractDevice","page":"Function and type index","title":"SpeedyWeather.AbstractDevice","text":"abstract type AbstractDevice\n\nSupertype of all devices SpeedyWeather.jl can ran on\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.BarotropicModel","page":"Function and type index","title":"SpeedyWeather.BarotropicModel","text":"The BarotropicModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\nforcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat\ninitial_conditions::SpeedyWeather.InitialConditions\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.CPUDevice","page":"Function and type index","title":"SpeedyWeather.CPUDevice","text":"CPUDevice <: AbstractDevice\n\nIndicates that SpeedyWeather.jl runs on a single CPU \n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Clock","page":"Function and type index","title":"SpeedyWeather.Clock","text":"Clock struct keeps track of the model time, how many days to integrate for and how many time steps this takes\n\ntime::Dates.DateTime: current model time\nn_days::Float64: number of days to integrate for, set in run!(::Simulation)\nn_timesteps::Int64: number of time steps to integrate for, set in initialize!(::Clock,::TimeStepper)\n\n.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ColumnVariables","page":"Function and type index","title":"SpeedyWeather.ColumnVariables","text":"Mutable struct that contains all prognostic (copies thereof) and diagnostic variables in a single column needed to evaluate the physical parametrizations. For now the struct is mutable as we will reuse the struct to iterate over horizontal grid points. Every column vector has nlev entries, from [1] at the top to [end] at the lowermost model level at the planetary boundary layer.\n\nnlev::Int64\nnband::Int64\nn_stratosphere_levels::Int64\njring::Int64\nlond::AbstractFloat\nlatd::AbstractFloat\nu::Vector{NF} where NF<:AbstractFloat\nv::Vector{NF} where NF<:AbstractFloat\ntemp::Vector{NF} where NF<:AbstractFloat\nhumid::Vector{NF} where NF<:AbstractFloat\nln_pres::Vector{NF} where NF<:AbstractFloat\npres::Vector{NF} where NF<:AbstractFloat\nu_tend::Vector{NF} where NF<:AbstractFloat\nv_tend::Vector{NF} where NF<:AbstractFloat\ntemp_tend::Vector{NF} where NF<:AbstractFloat\nhumid_tend::Vector{NF} where NF<:AbstractFloat\ngeopot::Vector{NF} where NF<:AbstractFloat\nflux_u_upward::Vector{NF} where NF<:AbstractFloat\nflux_u_downward::Vector{NF} where NF<:AbstractFloat\nflux_v_upward::Vector{NF} where NF<:AbstractFloat\nflux_v_downward::Vector{NF} where NF<:AbstractFloat\nflux_temp_upward::Vector{NF} where NF<:AbstractFloat\nflux_temp_downward::Vector{NF} where NF<:AbstractFloat\nflux_humid_upward::Vector{NF} where NF<:AbstractFloat\nflux_humid_downward::Vector{NF} where NF<:AbstractFloat\nsat_humid::Vector{NF} where NF<:AbstractFloat\nsat_vap_pres::Vector{NF} where NF<:AbstractFloat\ndry_static_energy::Vector{NF} where NF<:AbstractFloat\nmoist_static_energy::Vector{NF} where NF<:AbstractFloat\nhumid_half::Vector{NF} where NF<:AbstractFloat\nsat_humid_half::Vector{NF} where NF<:AbstractFloat\nsat_moist_static_energy::Vector{NF} where NF<:AbstractFloat\ndry_static_energy_half::Vector{NF} where NF<:AbstractFloat\nsat_moist_static_energy_half::Vector{NF} where NF<:AbstractFloat\nconditional_instability::Bool\nactivate_convection::Bool\ncloud_top::Int64\nexcess_humidity::AbstractFloat\ncloud_base_mass_flux::AbstractFloat\nprecip_convection::AbstractFloat\nnet_flux_humid::Vector{NF} where NF<:AbstractFloat\nnet_flux_dry_static_energy::Vector{NF} where NF<:AbstractFloat\nentrainment_profile::Vector{NF} where NF<:AbstractFloat\nprecip_large_scale::AbstractFloat\nwvi::Matrix{NF} where NF<:AbstractFloat\ntau2::Matrix{NF} where NF<:AbstractFloat\ndfabs::Vector{NF} where NF<:AbstractFloat\nfsfcd::AbstractFloat\nst4a::Matrix{NF} where NF<:AbstractFloat\nflux::Vector{NF} where NF<:AbstractFloat\nfsfcu::AbstractFloat\nts::AbstractFloat\nfsfc::AbstractFloat\nftop::AbstractFloat\nstratc::Vector{NF} where NF<:AbstractFloat\ntyear::AbstractFloat\ncsol::AbstractFloat\ntopsr::AbstractFloat\nfsol::AbstractFloat\nozupp::AbstractFloat\nozone::AbstractFloat\nzenit::AbstractFloat\nstratz::AbstractFloat\nalbsfc::AbstractFloat\nssrd::AbstractFloat\nssr::AbstractFloat\ntsr::AbstractFloat\ntend_t_rsw::Vector{NF} where NF<:AbstractFloat\nnorm_pres::AbstractFloat\nicltop::Int64\ncloudc::AbstractFloat\nclstr::AbstractFloat\nqcloud::AbstractFloat\nfmask::AbstractFloat\nrel_hum::Vector{NF} where NF<:AbstractFloat\ngrad_dry_static_energy::AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DeviceSetup","page":"Function and type index","title":"SpeedyWeather.DeviceSetup","text":"DeviceSetup{S<:AbstractDevice}\n\nHolds information about the device the model is running on and workgroup size. \n\ndevice::AbstractDevice: Device the model is running on \ndevice_KA::KernelAbstractions.Device: Device for use with KernelAbstractions\nn: workgroup size \n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DiagnosticVariables","page":"Function and type index","title":"SpeedyWeather.DiagnosticVariables","text":"DiagnosticVariables{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding the diagnostic variables.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DynamicsConstants","page":"Function and type index","title":"SpeedyWeather.DynamicsConstants","text":"Struct holding constants needed at runtime for the dynamical core in number format NF.\n\nradius::AbstractFloat: Radius of Planet [m]\nrotation::AbstractFloat: Angular frequency of Planet's rotation [1/s]\ngravity::AbstractFloat: Gravitational acceleration [m/s^2]\nlayer_thickness::AbstractFloat: shallow water layer thickness [m]\nR_dry::AbstractFloat: specific gas constant for dry air [J/kg/K]\nR_vapour::AbstractFloat: specific gas constant for water vapour [J/kg/K]\nμ_virt_temp::AbstractFloat: used in Tv = T(1+μq) for virt temp Tv(T,q) calculation\ncₚ::AbstractFloat: specific heat at constant pressure [J/K/kg]\nκ::AbstractFloat: = R_dry/cₚ, gas const for air over heat capacity\nwater_density::AbstractFloat: water density [kg/m³]\nf_coriolis::Vector{NF} where NF<:AbstractFloat: coriolis frequency 1/s = 2Ωsin(lat)radius\nσ_lnp_A::Vector{NF} where NF<:AbstractFloat: σ-related factor A needed for adiabatic terms\nσ_lnp_B::Vector{NF} where NF<:AbstractFloat: σ-related factor B needed for adiabatic terms\nΔp_geopot_half::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1) - ln(pk+1/2)), for half level geopotential\nΔp_geopot_full::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1/2) - ln(pk)), for full level geopotential\ntemp_ref_profile::Vector{NF} where NF<:AbstractFloat: reference temperature profile\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DynamicsConstants-Tuple{SpectralGrid, SpeedyWeather.AbstractPlanet, SpeedyWeather.AbstractAtmosphere, Geometry}","page":"Function and type index","title":"SpeedyWeather.DynamicsConstants","text":"DynamicsConstants(\n spectral_grid::SpectralGrid,\n planet::SpeedyWeather.AbstractPlanet,\n atmosphere::SpeedyWeather.AbstractAtmosphere,\n geometry::Geometry\n) -> Any\n\n\nGenerator function for a DynamicsConstants struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DynamicsVariables","page":"Function and type index","title":"SpeedyWeather.DynamicsVariables","text":"DynamicsVariables{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding intermediate quantities for the dynamics of a given layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Earth","page":"Function and type index","title":"SpeedyWeather.Earth","text":"Create a struct Earth<:AbstractPlanet, with the following physical/orbital characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are\n\nrotation::Float64: angular frequency of Earth's rotation [rad/s]\ngravity::Float64: gravitational acceleration [m/s^2]\ndaily_cycle::Bool: switch on/off daily cycle\nlength_of_day::Float64: [hrs] in a day\nseasonal_cycle::Bool: switch on/off seasonal cycle\nlength_of_year::Float64: [days] in a year\nequinox::Dates.DateTime: time of spring equinox (year irrelevant)\naxial_tilt::Float64: angle [˚] rotation axis tilt wrt to orbit\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthAtmosphere","page":"Function and type index","title":"SpeedyWeather.EarthAtmosphere","text":"Create a struct EarthAtmosphere<:AbstractPlanet, with the following physical/chemical characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are\n\nmol_mass_dry_air::Float64: molar mass of dry air [g/mol]\nmol_mass_vapour::Float64: molar mass of water vapour [g/mol]\ncₚ::Float64: specific heat at constant pressure [J/K/kg]\nR_gas::Float64: universal gas constant [J/K/mol]\nR_dry::Float64: specific gas constant for dry air [J/kg/K]\nR_vapour::Float64: specific gas constant for water vapour [J/kg/K]\nwater_density::Float64: water density [kg/m³]\nlatent_heat_condensation::Float64: latent heat of condensation [J/g] for consistency with specific humidity [g/Kg], also called alhc\nlatent_heat_sublimation::Float64: latent heat of sublimation [J/g], also called alhs\nstefan_boltzmann::Float64: stefan-Boltzmann constant [W/m²/K⁴]\nlapse_rate::Float64: moist adiabatic temperature lapse rate -dTdz [K/km]\ntemp_ref::Float64: absolute temperature at surface z=0 [K]\ntemp_top::Float64: absolute temperature in stratosphere [K]\nΔT_stratosphere::Float64: for stratospheric lapse rate [K] after Jablonowski\nσ_tropopause::Float64: start of the stratosphere in sigma coordinates\nσ_boundary_layer::Float64: top of the planetary boundary layer in sigma coordinates\nscale_height::Float64: scale height for pressure [km]\npres_ref::Float64: surface pressure [hPa]\nscale_height_humid::Float64: scale height for specific humidity [km]\nrelhumid_ref::Float64: relative humidity of near-surface air [1]\nwater_pres_ref::Float64: saturation water vapour pressure [Pa]\nlayer_thickness::Float64: layer thickness for the shallow water model [km]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthOrography","page":"Function and type index","title":"SpeedyWeather.EarthOrography","text":"Earth's orography read from file, with smoothing.\n\npath::String: path to the folder containing the orography file, pkg path default\nfile::String: filename of orography\nfile_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: Grid the orography file comes on\nscale::Float64: scale orography by a factor\nsmoothing::Bool: smooth the orography field?\nsmoothing_power::Float64: power of Laplacian for smoothing\nsmoothing_strength::Float64: highest degree l is multiplied by\nsmoothing_truncation::Int64: resolution of orography in spectral trunc\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthOrography-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.EarthOrography","text":"EarthOrography(\n spectral_grid::SpectralGrid;\n kwargs...\n) -> Any\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Feedback","page":"Function and type index","title":"SpeedyWeather.Feedback","text":"Feedback() -> Feedback\nFeedback(verbose::Bool) -> Feedback\nFeedback(verbose::Bool, debug::Bool) -> Feedback\n\n\nGenerator function for a Feedback struct.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Feedback-2","page":"Function and type index","title":"SpeedyWeather.Feedback","text":"Feedback struct that contains options and object for command-line feedback like the progress meter.\n\nverbose::Bool: print feedback to REPL?\ndebug::Bool: check for NaRs in the prognostic variables\noutput::Bool: write a progress.txt file? State synced with OutputWriter.output\nid::Union{Int64, String}: identification of run, taken from ::OutputWriter\nrun_path::String: path to run folder, taken from ::OutputWriter\nprogress_meter::ProgressMeter.Progress: struct containing everything progress related\nprogress_txt::Union{Nothing, IOStream}: txt is a Nothing in case of no output\nnars_detected::Bool: did Infs/NaNs occur in the simulation?\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.GPUDevice","page":"Function and type index","title":"SpeedyWeather.GPUDevice","text":"GPUDevice <: AbstractDevice\n\nIndicates that SpeedyWeather.jl runs on a single GPU\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.GenLogisticCoefs","page":"Function and type index","title":"SpeedyWeather.GenLogisticCoefs","text":"Coefficients of the generalised logistic function to describe the vertical coordinate. Default coefficients A,K,C,Q,B,M,ν are fitted to the old L31 configuration at ECMWF.\n\nFollowing the notation of https://en.wikipedia.org/wiki/Generalisedlogisticfunction (Dec 15 2021).\n\nChange default parameters for more/fewer levels in the stratosphere vs troposphere vs boundary layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Geometry","page":"Function and type index","title":"SpeedyWeather.Geometry","text":"Construct Geometry struct containing parameters and arrays describing an iso-latitude grid <:AbstractGrid and the vertical levels. Pass on SpectralGrid to calculate the following fields\n\nspectral_grid::SpectralGrid: SpectralGrid that defines spectral and grid resolution\nGrid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: grid of the dynamical core\nnlat_half::Int64: resolution parameter nlat_half of Grid, # of latitudes on one hemisphere (incl Equator)\nnlon_max::Int64: maximum number of longitudes (at/around Equator)\nnlon::Int64: =nlon_max, same (used for compatibility), TODO: still needed?\nnlat::Int64: number of latitude rings\nnlev::Int64: number of vertical levels\nnpoints::Int64: total number of grid points\nradius::AbstractFloat: Planet's radius [m]\nlatd::Vector{Float64}: array of latitudes in degrees (90˚...-90˚)\nlond::Vector{Float64}: array of longitudes in degrees (0...360˚), empty for non-full grids\nlonds::Vector{NF} where NF<:AbstractFloat: longitude (-180˚...180˚) for each grid point in ring order\nlatds::Vector{NF} where NF<:AbstractFloat: latitude (-90˚...˚90) for each grid point in ring order\nsinlat::Vector{NF} where NF<:AbstractFloat: sin of latitudes\ncoslat::Vector{NF} where NF<:AbstractFloat: cos of latitudes\ncoslat⁻¹::Vector{NF} where NF<:AbstractFloat: = 1/cos(lat)\ncoslat²::Vector{NF} where NF<:AbstractFloat: = cos²(lat)\ncoslat⁻²::Vector{NF} where NF<:AbstractFloat: # = 1/cos²(lat)\nσ_levels_half::Vector{NF} where NF<:AbstractFloat: σ at half levels, σ_k+1/2\nσ_levels_full::Vector{NF} where NF<:AbstractFloat: σ at full levels, σₖ\nσ_levels_thick::Vector{NF} where NF<:AbstractFloat: σ level thicknesses, σₖ₊₁ - σₖ\nln_σ_levels_full::Vector{NF} where NF<:AbstractFloat: log of σ at full levels, include surface (σ=1) as last element\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Geometry-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.Geometry","text":"Geometry(spectral_grid::SpectralGrid) -> Any\n\n\nGenerator function for Geometry struct based on spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.GridVariables","page":"Function and type index","title":"SpeedyWeather.GridVariables","text":"GridVariables{NF<:AbstractFloat}\n\nStruct holding the prognostic spectral variables of a given layer in grid point space.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HeldSuarez","page":"Function and type index","title":"SpeedyWeather.HeldSuarez","text":"Struct that defines the temperature relaxation from Held and Suarez, 1996 BAMS\n\nnlat::Int64: number of latitude rings\nnlev::Int64: number of vertical levels\nσb::Float64: sigma coordinate below which faster surface relaxation is applied\nrelax_time_slow::Float64: time scale [hrs] for slow global relaxation\nrelax_time_fast::Float64: time scale [hrs] for faster tropical surface relaxation\nTmin::Float64: minimum equilibrium temperature [K]\nTmax::Float64: maximum equilibrium temperature [K]\nΔTy::Float64: meridional temperature gradient [K]\nΔθz::Float64: vertical temperature gradient [K]\nκ::Base.RefValue{NF} where NF<:AbstractFloat\np₀::Base.RefValue{NF} where NF<:AbstractFloat\ntemp_relax_freq::Matrix{NF} where NF<:AbstractFloat\ntemp_equil_a::Vector{NF} where NF<:AbstractFloat\ntemp_equil_b::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HeldSuarez-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.HeldSuarez","text":"HeldSuarez(SG::SpectralGrid; kwargs...) -> Any\n\n\ncreate a HeldSuarez temperature relaxation with arrays allocated given spectral_grid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.HyperDiffusion","page":"Function and type index","title":"SpeedyWeather.HyperDiffusion","text":"Struct for horizontal hyper diffusion of vor, div, temp; implicitly in spectral space with a power of the Laplacian (default=4) and the strength controlled by time_scale. Options exist to scale the diffusion by resolution, and adaptive depending on the current vorticity maximum to increase diffusion in active layers. Furthermore the power can be decreased above the tapering_σ to power_stratosphere (default 2). For Barotropic, ShallowWater, the default non-adaptive constant-time scale hyper diffusion is used. Options are\n\ntrunc::Int64: spectral resolution\nnlev::Int64: number of vertical levels\npower::Float64: power of Laplacian\ntime_scale::Float64: diffusion time scales [hrs]\nresolution_scaling::Float64: stronger diffusion with resolution? 0: constant with trunc, 1: (inverse) linear with trunc, etc\npower_stratosphere::Float64: different power for tropopause/stratosphere\ntapering_σ::Float64: linearly scale towards power_stratosphere above this σ\nadaptive::Bool: adaptive = higher diffusion for layers with higher vorticity levels.\nvor_max::Float64: above this (absolute) vorticity level [1/s], diffusion is increased\nadaptive_strength::Float64: increase strength above vor_max by this factor times max(abs(vor))/vor_max\n∇²ⁿ_2D::Vector\n∇²ⁿ_2D_implicit::Vector\n∇²ⁿ::Array{Vector{NF}, 1} where NF\n∇²ⁿ_implicit::Array{Vector{NF}, 1} where NF\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HyperDiffusion-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.HyperDiffusion","text":"HyperDiffusion(\n spectral_grid::SpectralGrid;\n kwargs...\n) -> Any\n\n\nGenerator function based on the resolutin in spectral_grid. Passes on keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ImplicitPrimitiveEq","page":"Function and type index","title":"SpeedyWeather.ImplicitPrimitiveEq","text":"Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the primitive equation model.\n\ntrunc::Int64: spectral resolution\nnlev::Int64: number of vertical levels\nα::Float64: time-step coefficient: 0=explicit, 0.5=centred implicit, 1=backward implicit\ntemp_profile::Vector{NF} where NF<:AbstractFloat: vertical temperature profile, obtained from diagn\nξ::Base.RefValue{NF} where NF<:AbstractFloat: time step 2α*Δt packed in RefValue for mutability\nR::Matrix{NF} where NF<:AbstractFloat: divergence: operator for the geopotential calculation\nU::Vector{NF} where NF<:AbstractFloat: divergence: the -RdTₖ∇² term excl the eigenvalues from ∇² for divergence\nL::Matrix{NF} where NF<:AbstractFloat: temperature: operator for the TₖD + κTₖDlnps/Dt term\nW::Vector{NF} where NF<:AbstractFloat: pressure: vertical averaging of the -D̄ term in the log surface pres equation\nL0::Vector{NF} where NF<:AbstractFloat: components to construct L, 1/ 2Δσ\nL1::Matrix{NF} where NF<:AbstractFloat: vert advection term in the temperature equation (below+above)\nL2::Vector{NF} where NF<:AbstractFloat: factor in front of the divsumabove term\nL3::Matrix{NF} where NF<:AbstractFloat: sumabove operator itself\nL4::Vector{NF} where NF<:AbstractFloat: factor in front of div term in Dlnps/Dt\nS::Matrix{NF} where NF<:AbstractFloat: for every l the matrix to be inverted\nS⁻¹::Array{NF, 3} where NF<:AbstractFloat: combined inverted operator: S = 1 - ξ²(RL + UW)\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ImplicitPrimitiveEq-Tuple{SpectralGrid, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.ImplicitPrimitiveEq","text":"ImplicitPrimitiveEq(\n spectral_grid::SpectralGrid,\n kwargs...\n) -> Any\n\n\nGenerator using the resolution from SpectralGrid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ImplicitShallowWater","page":"Function and type index","title":"SpeedyWeather.ImplicitShallowWater","text":"Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the shallow water model.\n\ntrunc::Int64\nα::Float64: coefficient for semi-implicit computations to filter gravity waves\nH::Base.RefValue{NF} where NF<:AbstractFloat\nξH::Base.RefValue{NF} where NF<:AbstractFloat\ng∇²::Vector{NF} where NF<:AbstractFloat\nξg∇²::Vector{NF} where NF<:AbstractFloat\nS⁻¹::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ImplicitShallowWater-Tuple{SpectralGrid, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.ImplicitShallowWater","text":"ImplicitShallowWater(\n spectral_grid::SpectralGrid,\n kwargs...\n) -> Any\n\n\nGenerator using the resolution from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.JablonowskiRelaxation","page":"Function and type index","title":"SpeedyWeather.JablonowskiRelaxation","text":"HeldSuarez-like temperature relaxation, but towards the Jablonowski temperature profile with increasing temperatures in the stratosphere.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.JablonowskiRelaxation-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.JablonowskiRelaxation","text":"JablonowskiRelaxation(SG::SpectralGrid; kwargs...) -> Any\n\n\ncreate a JablonowskiRelaxation temperature relaxation with arrays allocated given spectral_grid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Keepbits","page":"Function and type index","title":"SpeedyWeather.Keepbits","text":"Number of mantissa bits to keep for each prognostic variable when compressed for netCDF and .jld2 data output.\n\nu::Int64\nv::Int64\nvor::Int64\ndiv::Int64\ntemp::Int64\npres::Int64\nhumid::Int64\nprecip_cond::Int64\nprecip_conv::Int64\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Leapfrog","page":"Function and type index","title":"SpeedyWeather.Leapfrog","text":"Leapfrog time stepping defined by the following fields\n\ntrunc::Int64: spectral resolution (max degree of spherical harmonics)\nΔt_at_T31::Float64: time step in minutes for T31, scale linearly to trunc\nradius::Any: radius of sphere [m], used for scaling\nrobert_filter::Any: Robert (1966) time filter coefficeint to suppress comput. mode\nwilliams_filter::Any: Williams time filter (Amezcua 2011) coefficient for 3rd order acc\nΔt_sec::Int64: time step Δt [s] at specified resolution\nΔt::Any: time step Δt [s/m] at specified resolution, scaled by 1/radius\nΔt_hrs::Float64: convert time step Δt from minutes to hours\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Leapfrog-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.Leapfrog","text":"Leapfrog(spectral_grid::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function for a Leapfrog struct using spectral_grid for the resolution information.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.LinearDrag","page":"Function and type index","title":"SpeedyWeather.LinearDrag","text":"Linear boundary layer drag Following Held and Suarez, 1996 BAMS\n\nσb::Float64\ntime_scale::Float64\nnlev::Int64\ndrag_coefs::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.LinearDrag-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.LinearDrag","text":"LinearDrag(SG::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function using nlev from SG::SpectralGrid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.MagnusCoefs","page":"Function and type index","title":"SpeedyWeather.MagnusCoefs","text":"Parameters for computing saturation vapour pressure using the August-Roche-Magnus formula,\n\neᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),\n\nwhere T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively.\n\ne₀::AbstractFloat: Saturation vapour pressure at 0°C [Pa]\nT₀::AbstractFloat: 0°C in Kelvin\nT₁::AbstractFloat\nT₂::AbstractFloat\nC₁::AbstractFloat\nC₂::AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoBoundaryLayerDrag","page":"Function and type index","title":"SpeedyWeather.NoBoundaryLayerDrag","text":"Concrete type that disables the boundary layer drag scheme.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoOrography","page":"Function and type index","title":"SpeedyWeather.NoOrography","text":"Orography with zero height in orography and zero surface geopotential geopot_surf.\n\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoOrography-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.NoOrography","text":"NoOrography(spectral_grid::SpectralGrid) -> NoOrography\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.OutputWriter","page":"Function and type index","title":"SpeedyWeather.OutputWriter","text":"NetCDF output writer. Contains all output options and auxiliary fields for output interpolation. To be initialised with OutputWriter(::SpectralGrid,::Type{<:ModelSetup},kwargs...) to pass on the resolution information and the model type which chooses which variables to output. Options include\n\nspectral_grid::SpectralGrid\noutput::Bool\npath::String: [OPTION] path to output folder, run_???? will be created within\nid::String: [OPTION] run identification number/string\nrun_path::String\nfilename::String: [OPTION] name of the output netcdf file\nwrite_restart::Bool: [OPTION] also write restart file if output==true?\npkg_version::VersionNumber\nstartdate::Dates.DateTime\noutput_dt::Float64: [OPTION] output frequency, time step [hrs]\noutput_dt_sec::Int64: actual output time step [sec]\noutput_vars::Vector{Symbol}: [OPTION] which variables to output, u, v, vor, div, pres, temp, humid\nmissing_value::Union{Float32, Float64}: [OPTION] missing value to be used in netcdf output\ncompression_level::Int64: [OPTION] lossless compression level; 1=low but fast, 9=high but slow\nkeepbits::SpeedyWeather.Keepbits: [OPTION] mantissa bits to keep for every variable\noutput_every_n_steps::Int64\ntimestep_counter::Int64\noutput_counter::Int64\nnetcdf_file::Union{Nothing, NetCDF.NcFile}\ninput_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}\nas_matrix::Bool: [OPTION] sort grid points into a matrix (interpolation-free), for OctahedralClenshawGrid, OctaHEALPixGrid only\nquadrant_rotation::NTuple{4, Int64}\nmatrix_quadrant::NTuple{4, Tuple{Int64, Int64}}\noutput_Grid::Type{<:SpeedyWeather.RingGrids.AbstractFullGrid}: [OPTION] the grid used for output, full grids only\nnlat_half::Int64: [OPTION] the resolution of the output grid, default: same nlat_half as in the dynamical core\nnlon::Int64\nnlat::Int64\nnpoints::Int64\nnlev::Int64\ninterpolator::SpeedyWeather.RingGrids.AbstractInterpolator\nu::Matrix{NF} where NF<:Union{Float32, Float64}\nv::Matrix{NF} where NF<:Union{Float32, Float64}\nvor::Matrix{NF} where NF<:Union{Float32, Float64}\ndiv::Matrix{NF} where NF<:Union{Float32, Float64}\ntemp::Matrix{NF} where NF<:Union{Float32, Float64}\npres::Matrix{NF} where NF<:Union{Float32, Float64}\nhumid::Matrix{NF} where NF<:Union{Float32, Float64}\nprecip_cond::Matrix{NF} where NF<:Union{Float32, Float64}\nprecip_conv::Matrix{NF} where NF<:Union{Float32, Float64}\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.PrimitiveDryModel","page":"Function and type index","title":"SpeedyWeather.PrimitiveDryModel","text":"The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\nphysics::Bool\nboundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat\ntemperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat\nstatic_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.PrimitiveWetModel","page":"Function and type index","title":"SpeedyWeather.PrimitiveWetModel","text":"The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\nphysics::Bool\nthermodynamics::SpeedyWeather.Thermodynamics{NF} where NF<:AbstractFloat\nboundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat\ntemperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat\nstatic_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat\nlarge_scale_condensation::SpeedyWeather.AbstractCondensation{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ShallowWaterModel","page":"Function and type index","title":"SpeedyWeather.ShallowWaterModel","text":"The ShallowWaterModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\nforcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Simulation","page":"Function and type index","title":"SpeedyWeather.Simulation","text":"Simulation is a container struct to be used with run!(::Simulation). It contains\n\nprognostic_variables::PrognosticVariables: define the current state of the model\ndiagnostic_variables::DiagnosticVariables: contain the tendencies and auxiliary arrays to compute them\nmodel::SpeedyWeather.ModelSetup: all parameters, constant at runtime\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpectralGrid","page":"Function and type index","title":"SpeedyWeather.SpectralGrid","text":"Defines the horizontal spectral resolution and corresponding grid and the vertical coordinate for SpeedyWeather.jl. Options are\n\nNF::Type{<:AbstractFloat}: number format used throughout the model\ntrunc::Int64: horizontal resolution as the maximum degree of spherical harmonics\nGrid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: horizontal grid used for calculations in grid-point space\ndealiasing::Float64: how to match spectral with grid resolution: dealiasing factor, 1=linear, 2=quadratic, 3=cubic grid\nradius::Float64: radius of the sphere [m]\nnlat_half::Int64: number of latitude rings on one hemisphere (Equator incl)\nnpoints::Int64: total number of grid points in the horizontal\nnlev::Int64: number of vertical levels\nvertical_coordinates::SpeedyWeather.VerticalCoordinates: coordinates used to discretize the vertical\n\nnlat_half and npoints should not be chosen but are derived from trunc, Grid and dealiasing.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpeedyCondensation","page":"Function and type index","title":"SpeedyWeather.SpeedyCondensation","text":"Large scale condensation as in Fortran SPEEDY with default values from therein.\n\nnlev::Int64: number of vertical levels\nthreshold_boundary_layer::Float64: Relative humidity threshold for boundary layer\nthreshold_range::Float64: Vertical range of relative humidity threshold\nthreshold_max::Float64: Maximum relative humidity threshold [1]\ntime_scale::Float64: Relaxation time for humidity [hrs]\nn_stratosphere_levels::Base.RefValue{Int64}\nhumid_tend_max::Vector{NF} where NF<:AbstractFloat\nrelative_threshold::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"SpectralTransform(\n spectral_grid::SpectralGrid;\n recompute_legendre,\n one_more_degree,\n kwargs...\n) -> SpectralTransform\n\n\nGenerator function for a SpectralTransform struct pulling in parameters from a SpectralGrid struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.StartFromFile","page":"Function and type index","title":"SpeedyWeather.StartFromFile","text":"Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical. restart.jld2 is identified by\n\npath::String: path for restart file\nid::Union{Int64, String}: run_id of restart file in run_????/restart.jld2\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.StartWithRandomVorticity","page":"Function and type index","title":"SpeedyWeather.StartWithRandomVorticity","text":"Start with random vorticity as initial conditions\n\npower::Float64: Power of the spectral distribution k^power\namplitude::Float64: (approximate) amplitude in [1/s], used as standard deviation of spherical harmonic coefficients\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.StaticEnergyDiffusion","page":"Function and type index","title":"SpeedyWeather.StaticEnergyDiffusion","text":"Diffusion of dry static energy: A relaxation towards a reference gradient of static energy wrt to geopotential, see Fortran SPEEDY documentation.\n\ntime_scale::Float64: time scale [hrs] for strength\nstatic_energy_lapse_rate::Float64: [1] ∂SE/∂Φ, vertical gradient of static energy SE with geopotential Φ\nFstar::Base.RefValue{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Tendencies","page":"Function and type index","title":"SpeedyWeather.Tendencies","text":"Tendencies{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding the tendencies of the prognostic spectral variables for a given layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalJet","page":"Function and type index","title":"SpeedyWeather.ZonalJet","text":"Create a struct that contains all parameters for the Galewsky et al, 2004 zonal jet intitial conditions for the shallow water model. Default values as in Galewsky.\n\nlatitude::Float64: jet latitude [˚N]\nwidth::Float64: jet width [˚], default ≈ 19.29˚\numax::Float64: jet maximum velocity [m/s]\nperturb_lat::Float64: perturbation latitude [˚N], position in jet by default\nperturb_lon::Float64: perturbation longitude [˚E]\nperturb_xwidth::Float64: perturbation zonal extent [˚], default ≈ 19.1˚\nperturb_ywidth::Float64: perturbation meridinoal extent [˚], default ≈ 3.8˚\nperturb_height::Float64: perturbation amplitude [m]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalRidge","page":"Function and type index","title":"SpeedyWeather.ZonalRidge","text":"Zonal ridge orography after Jablonowski and Williamson, 2006.\n\nη₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates\nu₀::Float64: max amplitude of zonal wind [m/s] that scales orography height\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalRidge-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.ZonalRidge","text":"ZonalRidge(spectral_grid::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ZonalWind","page":"Function and type index","title":"SpeedyWeather.ZonalWind","text":"Create a struct that contains all parameters for the Jablonowski and Williamson, 2006 intitial conditions for the primitive equation model. Default values as in Jablonowski.\n\nη₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates\nu₀::Float64: max amplitude of zonal wind [m/s]\nperturb_lat::Float64: perturbation centred at [˚N]\nperturb_lon::Float64: perturbation centred at [˚E]\nperturb_uₚ::Float64: perturbation strength [m/s]\nperturb_radius::Float64: radius of Gaussian perturbation in units of Earth's radius [1]\nΔT::Float64: temperature difference used for stratospheric lapse rate [K], Jablonowski uses ΔT = 4.8e5 [K]\nTmin::Float64: minimum temperature [K] of profile\npressure_on_orography::Bool: initialize pressure given the atmosphere.lapse_rate on orography?\n\n\n\n\n\n","category":"type"},{"location":"functions/#Base.copy!-Tuple{PrognosticVariables, PrognosticVariables}","page":"Function and type index","title":"Base.copy!","text":"copy!(progn_new::PrognosticVariables, progn_old::PrognosticVariables)\n\nCopies entries of progn_old into progn_new. Only copies those variables that are present in the model of both progn_new and progn_old.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device-Tuple{}","page":"Function and type index","title":"SpeedyWeather.Device","text":"Device()\n\nReturn default used device for internal purposes, either CPUDevice or GPUDevice if a GPU is available.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DeviceArray-Tuple{SpeedyWeather.GPUDevice, Any}","page":"Function and type index","title":"SpeedyWeather.DeviceArray","text":"DeviceArray(device::AbstractDevice, x)\n\nAdapts x to a CuArray when device<:GPUDevice is used, otherwise a regular Array. Uses adapt, thus also can return SubArrays etc.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DeviceArrayNotAdapt-Tuple{SpeedyWeather.GPUDevice, Any}","page":"Function and type index","title":"SpeedyWeather.DeviceArrayNotAdapt","text":"DeviceArrayNotAdapt(device::AbstractDevice, x)\n\nReturns a CuArray when device<:GPUDevice is used, otherwise a regular Array. Doesn't uses adapt, therefore always returns CuArray/Array\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device_KernelAbstractions-Tuple{SpeedyWeather.CPUDevice}","page":"Function and type index","title":"SpeedyWeather.Device_KernelAbstractions","text":"Device_KernelAbstractions(::AbstractDevice)\n\nReturn used device for use with KernelAbstractions\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device_KernelAbstractions-Tuple{}","page":"Function and type index","title":"SpeedyWeather.Device_KernelAbstractions","text":"Device_KernelAbstractions()\n\nReturn default used device for KernelAbstractions, either CPU or CUDADevice if a GPU is available\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{DiagnosticVariables, PrognosticVariables, Int64, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n lf::Int64,\n model::SpeedyWeather.ModelSetup\n)\n\n\nPropagate the spectral state of progn to diagn using time step/leapfrog index lf. Function barrier that calls gridded! for the respective model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, Barotropic}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::Barotropic\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the barotropic vorticity model. Updates grid vorticity, spectral stream function and spectral and grid velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::PrimitiveEquation\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for primitive equation models. Updates grid vorticity, grid divergence, grid temperature, pressure (pres_grid) and the velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::ShallowWater\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the shallow water model. Updates grid vorticity, grid divergence, grid interface displacement (pres_grid) and the velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather._scale_lat!-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, AbstractVector}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather._scale_lat!","text":"_scale_lat!(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n v::AbstractVector\n)\n\n\nGeneric latitude scaling applied to A in-place with latitude-like vector v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.allocate-Union{Tuple{Model}, Tuple{Type{PrognosticVariables}, SpectralGrid, Type{Model}}} where Model<:SpeedyWeather.ModelSetup","page":"Function and type index","title":"SpeedyWeather.allocate","text":"allocate(\n _::Type{PrognosticVariables},\n spectral_grid::SpectralGrid,\n _::Type{Model<:SpeedyWeather.ModelSetup}\n) -> PrognosticVariables\n\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.bernoulli_potential!-Union{Tuple{NF}, Tuple{SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpectralTransform}} where NF","page":"Function and type index","title":"SpeedyWeather.bernoulli_potential!","text":"bernoulli_potential!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n S::SpectralTransform\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nComputes the Laplace operator ∇² of the Bernoulli potential B in spectral space.\n\ncomputes the kinetic energy KE = ½(u²+v²) on the grid\ntransforms KE to spectral space\nadds geopotential for the Bernoulli potential in spectral space\ntakes the Laplace operator.\n\nThis version is used for both ShallowWater and PrimitiveEquation, only the geopotential calculation in geopotential! differs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.boundary_layer_drag!-Tuple{ColumnVariables, LinearDrag}","page":"Function and type index","title":"SpeedyWeather.boundary_layer_drag!","text":"boundary_layer_drag!(\n column::ColumnVariables,\n scheme::LinearDrag\n)\n\n\nCompute tendency for boundary layer drag of a column and add to its tendencies fields\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.boundary_layer_drag!-Tuple{ColumnVariables, SpeedyWeather.NoBoundaryLayerDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.boundary_layer_drag!","text":"NoBoundaryLayer scheme just passes.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.clip_negatives!-Union{Tuple{AbstractArray{T}}, Tuple{T}} where T","page":"Function and type index","title":"SpeedyWeather.clip_negatives!","text":"clip_negatives!(A::AbstractArray)\n\nSet all negative entries a in A to zero.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.create_output_folder-Tuple{String, Union{Int64, String}}","page":"Function and type index","title":"SpeedyWeather.create_output_folder","text":"create_output_folder(\n path::String,\n id::Union{Int64, String}\n) -> String\n\n\nCreates a new folder run_* with the identification id. Also returns the full path run_path of that folder.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.default_sigma_coordinates-Tuple{Integer}","page":"Function and type index","title":"SpeedyWeather.default_sigma_coordinates","text":"default_sigma_coordinates(nlev::Integer) -> Any\n\n\nVertical sigma coordinates defined by their nlev+1 half levels σ_levels_half. Sigma coordinates are fraction of surface pressure (p/p0) and are sorted from top (stratosphere) to bottom (surface). The first half level is at 0 the last at 1. Evaluate a generalised logistic function with coefficients in P for the distribution of values in between. Default coefficients follow the L31 configuration historically used at ECMWF.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dry_static_energy!-Tuple{ColumnVariables, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.dry_static_energy!","text":"dry_static_energy!(\n column::ColumnVariables,\n constants::DynamicsConstants\n)\n\n\nCompute the dry static energy SE = cₚT + Φ (latent heat times temperature plus geopotential) for the column.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n model::PrimitiveEquation\n) -> Any\ndynamics_tendencies!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n model::PrimitiveEquation,\n lf::Int64\n) -> Any\n\n\nCalculate all tendencies for the PrimitiveEquation model (wet or dry).\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, Dates.DateTime, Barotropic}","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n time::Dates.DateTime,\n model::Barotropic\n)\n\n\nCalculate all tendencies for the BarotropicModel.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, LowerTriangularMatrix, Dates.DateTime, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.SurfaceVariables,\n pres::LowerTriangularMatrix,\n time::Dates.DateTime,\n model::ShallowWater\n)\n\n\nCalculate all tendencies for the ShallowWaterModel.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.first_timesteps!-Tuple{PrognosticVariables, DiagnosticVariables, SpeedyWeather.ModelSetup, SpeedyWeather.AbstractOutputWriter}","page":"Function and type index","title":"SpeedyWeather.first_timesteps!","text":"first_timesteps!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n model::SpeedyWeather.ModelSetup,\n output::SpeedyWeather.AbstractOutputWriter\n) -> typeof(time)\n\n\nPerforms the first two initial time steps (Euler forward, unfiltered leapfrog) to populate the prognostic variables with two time steps (t=0,Δt) that can then be used in the normal leap frogging.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.flipsign!-Tuple{AbstractArray}","page":"Function and type index","title":"SpeedyWeather.flipsign!","text":"flipgsign!(A::AbstractArray)\n\nLike -A but in-place.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.flux_divergence!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Geometry{NF}, SpectralTransform{NF}}} where NF","page":"Function and type index","title":"SpeedyWeather.flux_divergence!","text":"flux_divergence!(\n A_tend::LowerTriangularMatrix{Complex{NF}},\n A_grid::SpeedyWeather.RingGrids.AbstractGrid{NF},\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n G::Geometry{NF},\n S::SpectralTransform{NF};\n add,\n flipsign\n)\n\n\nComputes ∇⋅((u,v)*A) with the option to add/overwrite A_tend and to flip_sign of the flux divergence by doing so.\n\nA_tend = ∇⋅((u,v)*A) for add=false, flip_sign=false\nA_tend = -∇⋅((u,v)*A) for add=false, flip_sign=true\nA_tend += ∇⋅((u,v)*A) for add=true, flip_sign=false\nA_tend -= ∇⋅((u,v)*A) for add=true, flip_sign=true\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.fluxes_to_tendencies!-Tuple{ColumnVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.fluxes_to_tendencies!","text":"fluxes_to_tendencies!(\n column::ColumnVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nConvert the fluxes on half levels to tendencies on full levels.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.generalised_logistic-Tuple{Any, SpeedyWeather.GenLogisticCoefs}","page":"Function and type index","title":"SpeedyWeather.generalised_logistic","text":"Generalised logistic function based on the coefficients in coefs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{DiagnosticVariables, SpeedyWeather.AbstractOrography, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(\n diagn::DiagnosticVariables,\n O::SpeedyWeather.AbstractOrography,\n C::DynamicsConstants\n)\n\n\nCompute spectral geopotential geopot from spectral temperature temp and spectral surface geopotential geopot_surf (orography*gravity).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n pres::LowerTriangularMatrix,\n C::DynamicsConstants\n) -> Any\n\n\ncalculates the geopotential in the ShallowWaterModel as g*η, i.e. gravity times the interface displacement (field pres)\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{Vector, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(temp::Vector, C::DynamicsConstants) -> Vector\n\n\nCalculate the geopotential based on temp in a single column. This exclues the surface geopotential that would need to be added to the returned vector. Function not used in the dynamical core but for post-processing and analysis.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_column!-Tuple{ColumnVariables, DiagnosticVariables, Int64, Geometry}","page":"Function and type index","title":"SpeedyWeather.get_column!","text":"Recalculate ring index if not provided.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_column!-Tuple{ColumnVariables, DiagnosticVariables, Integer, Integer, Geometry}","page":"Function and type index","title":"SpeedyWeather.get_column!","text":"get_column!(\n C::ColumnVariables,\n D::DiagnosticVariables,\n ij::Integer,\n jring::Integer,\n G::Geometry\n)\n\n\nUpdate C::ColumnVariables by copying the prognostic variables from D::DiagnosticVariables at gridpoint index ij. Provide G::Geometry for coordinate information.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_full_output_file_path-Tuple{OutputWriter}","page":"Function and type index","title":"SpeedyWeather.get_full_output_file_path","text":"get_full_output_file_path(output::OutputWriter) -> String\n\n\nReturns the full path of the output file after it was created.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_run_id-Tuple{String, String}","page":"Function and type index","title":"SpeedyWeather.get_run_id","text":"get_run_id(path::String, id::String) -> String\n\n\nChecks existing run_???? folders in path to determine a 4-digit id number by counting up. E.g. if folder run_0001 exists it will return the string \"0002\". Does not create a folder for the returned run id.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_thermodynamics!-Tuple{ColumnVariables, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.get_thermodynamics!","text":"get_thermodynamics!(\n column::ColumnVariables,\n model::PrimitiveDry\n)\n\n\nCalculate the dry static energy for the primitive dry model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_thermodynamics!-Tuple{ColumnVariables, PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.get_thermodynamics!","text":"get_thermodynamics!(\n column::ColumnVariables,\n model::PrimitiveWet\n)\n\n\nCalculate thermodynamic quantities like saturation vapour pressure, saturation specific humidity, dry static energy, moist static energy and saturation moist static energy from the prognostic column variables.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_var-Tuple{PrognosticVariables, Symbol}","page":"Function and type index","title":"SpeedyWeather.get_var","text":"get_var(progn::PrognosticVariables, var_name::Symbol; lf::Integer=1)\n\nReturns the prognostic variable var_name at leapfrog index lf as a Vector{LowerTriangularMatrices}.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.has-Tuple{Type{<:SpeedyWeather.ModelSetup}, Symbol}","page":"Function and type index","title":"SpeedyWeather.has","text":"has(\n M::Type{<:SpeedyWeather.ModelSetup},\n var_name::Symbol\n) -> Bool\n\n\nReturns true if the model M has a prognostic variable var_name, false otherwise. The default fallback is that all variables are included. \n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater\n)\nhorizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater,\n lf::Int64\n)\n\n\nApply horizontal diffusion to vorticity and diffusion in the ShallowWater models.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-2","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation\n) -> Union{Nothing, Bool}\nhorizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation,\n lf::Int64\n) -> Union{Nothing, Bool}\n\n\nApply horizontal diffusion applied to vorticity, diffusion and temperature in the PrimitiveEquation models. Uses the constant diffusion for temperature but possibly adaptive diffusion for vorticity and divergence.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-3","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::Barotropic\n)\nhorizontal_diffusion!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::Barotropic,\n lf::Int64\n)\n\n\nApply horizontal diffusion to vorticity in the Barotropic models.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, AbstractVector{NF}, AbstractVector{NF}}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n A::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n ∇²ⁿ_expl::AbstractArray{NF<:AbstractFloat, 1},\n ∇²ⁿ_impl::AbstractArray{NF<:AbstractFloat, 1}\n)\n\n\nApply horizontal diffusion to a 2D field A in spectral space by updating its tendency tendency with an implicitly calculated diffusion term. The implicit diffusion of the next time step is split into an explicit part ∇²ⁿ_expl and an implicit part ∇²ⁿ_impl, such that both can be calculated in a single forward step by using A as well as its tendency tendency.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.implicit_correction!-Tuple{DiagnosticVariables, SpeedyWeather.ImplicitPrimitiveEq, PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.implicit_correction!","text":"implicit_correction!(\n diagn::DiagnosticVariables,\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n progn::PrognosticVariables\n) -> Any\n\n\nApply the implicit corrections to dampen gravity waves in the primitive equation models.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.implicit_correction!-Union{Tuple{NF}, Tuple{SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.PrognosticLayerTimesteps{NF}, SpeedyWeather.SurfaceVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.PrognosticSurfaceTimesteps{NF}, SpeedyWeather.ImplicitShallowWater}} where NF","page":"Function and type index","title":"SpeedyWeather.implicit_correction!","text":"implicit_correction!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n progn::SpeedyWeather.PrognosticLayerTimesteps{NF},\n diagn_surface::SpeedyWeather.SurfaceVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n progn_surface::SpeedyWeather.PrognosticSurfaceTimesteps{NF},\n implicit::SpeedyWeather.ImplicitShallowWater\n)\n\n\nApply correction to the tendencies in diagn to prevent the gravity waves from amplifying. The correction is implicitly evaluated using the parameter implicit.α to switch between forward, centered implicit or backward evaluation of the gravity wave terms.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Tuple{PrognosticVariables, StartFromFile, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn_new::PrognosticVariables,\n initial_conditions::StartFromFile,\n model::SpeedyWeather.ModelSetup\n) -> PrognosticVariables\n\n\nRestart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Tuple{PrognosticVariables, ZonalJet, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables,\n initial_conditions::ZonalJet,\n model::ShallowWater\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitial conditions from Galewsky, 2004, Tellus\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, StartWithRandomVorticity, SpeedyWeather.ModelSetup}} where NF","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables{NF},\n initial_conditions::StartWithRandomVorticity,\n model::SpeedyWeather.ModelSetup\n)\n\n\nStart with random vorticity as initial conditions\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, ZonalWind, PrimitiveEquation}} where NF","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables{NF},\n initial_conditions::ZonalWind,\n model::PrimitiveEquation\n)\n\n\nInitial conditions from Jablonowski and Williamson, 2006, QJR Meteorol. Soc\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions-Tuple{Model} where Model","page":"Function and type index","title":"SpeedyWeather.initial_conditions","text":"initial_conditions(model) -> PrognosticVariables\n\n\nAllocate the prognostic variables and then set to initial conditions.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n k::Int64,\n G::Geometry,\n L::SpeedyWeather.TimeStepper\n)\ninitialize!(\n scheme::HyperDiffusion,\n k::Int64,\n G::Geometry,\n L::SpeedyWeather.TimeStepper,\n vor_max::Real\n)\n\n\nPrecomputes the hyper diffusion terms in scheme for layer k based on the model time step in L, the vertical level sigma level in G, and the current (absolute) vorticity maximum level vor_max\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{Barotropic}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::Barotropic) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{EarthOrography, SpeedyWeather.AbstractPlanet, SpectralTransform, Geometry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n orog::EarthOrography,\n P::SpeedyWeather.AbstractPlanet,\n S::SpectralTransform,\n G::Geometry\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitialize the arrays orography,geopot_surf in orog by reading the orography field from file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{Feedback, SpeedyWeather.Clock, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n feedback::Feedback,\n clock::SpeedyWeather.Clock,\n model::SpeedyWeather.ModelSetup\n) -> Union{Nothing, IOStream}\n\n\nInitializes the a Feedback struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HeldSuarez, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(scheme::HeldSuarez, model::PrimitiveEquation)\n\n\ninitialize the HeldSuarez temperature relaxation by precomputing terms for the equilibrium temperature Teq.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.DiagnosticVariablesLayer, Geometry, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n G::Geometry,\n L::SpeedyWeather.TimeStepper\n)\n\n\nPre-function to other initialize!(::HyperDiffusion) initialisors that calculates the (absolute) vorticity maximum for the layer of diagn.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n model::SpeedyWeather.ModelSetup\n)\n\n\nPrecomputes the hyper diffusion terms in scheme based on the model time step, and possibly with a changing strength/power in the vertical.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n L::SpeedyWeather.TimeStepper\n)\n\n\nPrecomputes the 2D hyper diffusion terms in scheme based on the model time step.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{JablonowskiRelaxation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::JablonowskiRelaxation,\n model::PrimitiveEquation\n)\n\n\ninitialize the JablonowskiRelaxation temperature relaxation by precomputing terms for the equilibrium temperature Teq and the frequency (strength of relaxation).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{LinearDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(scheme::LinearDrag, model::PrimitiveEquation)\n\n\nPrecomputes the drag coefficients for this BoundaryLayerDrag scheme.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{NoTemperatureRelaxation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::NoTemperatureRelaxation,\n model::PrimitiveEquation\n)\n\n\njust passes, does not need any initialization.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::PrimitiveDry) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::PrimitiveWet) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{ShallowWater}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::ShallowWater) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyCondensation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::SpeedyCondensation,\n model::PrimitiveEquation\n)\n\n\nInitialize the SpeedyCondensation scheme.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.Clock, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n clock::SpeedyWeather.Clock,\n time_stepping::SpeedyWeather.TimeStepper\n) -> SpeedyWeather.Clock\n\n\nInitialize the clock with the time step Δt in the time_stepping.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitPrimitiveEq, Integer, Real, DiagnosticVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n i::Integer,\n dt::Real,\n diagn::DiagnosticVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nReinitialize implicit occasionally based on time step i and implicit.recalculate.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitPrimitiveEq, Real, DiagnosticVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n dt::Real,\n diagn::DiagnosticVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nInitialize the implicit terms for the PrimitiveEquation models.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitShallowWater, Real, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitShallowWater,\n dt::Real,\n constants::DynamicsConstants\n)\n\n\nUpdate the implicit terms in implicit for the shallow water model as they depend on the time step dt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.NoBoundaryLayerDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"NoBoundaryLayer scheme does not need any initialisation.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{ZonalRidge, SpeedyWeather.AbstractPlanet, SpectralTransform, Geometry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n orog::ZonalRidge,\n P::SpeedyWeather.AbstractPlanet,\n S::SpectralTransform,\n G::Geometry\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitialize the arrays orography,geopot_surf in orog following Jablonowski and Williamson, 2006.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Union{Tuple{Model}, Tuple{output_NF}, Tuple{OutputWriter{output_NF, Model}, SpeedyWeather.AbstractFeedback, SpeedyWeather.TimeStepper, DiagnosticVariables, Model}} where {output_NF, Model}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n output::OutputWriter{output_NF, Model},\n feedback::SpeedyWeather.AbstractFeedback,\n time_stepping::SpeedyWeather.TimeStepper,\n diagn::DiagnosticVariables,\n model\n)\n\n\nCreates a netcdf file on disk and the corresponding netcdf_file object preallocated with output variables and dimensions. write_output! then writes consecuitive time steps into this file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Union{Tuple{NF}, Tuple{SpeedyWeather.StaticEnergyDiffusion{NF}, PrimitiveEquation}} where NF","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::SpeedyWeather.StaticEnergyDiffusion{NF},\n model::PrimitiveEquation\n) -> Any\n\n\nInitialize dry static energy diffusion.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize_geopotential-Tuple{Vector, Vector, Real}","page":"Function and type index","title":"SpeedyWeather.initialize_geopotential","text":"initialize_geopotential(\n σ_levels_full::Vector,\n σ_levels_half::Vector,\n R_dry::Real\n) -> Tuple{Vector{Float64}, Vector{Float64}}\n\n\nPrecomputes constants for the vertical integration of the geopotential, defined as\n\nΦ_{k+1/2} = Φ_{k+1} + R*T_{k+1}*(ln(p_{k+1}) - ln(p_{k+1/2})) (half levels) Φ_k = Φ_{k+1/2} + R*T_k*(ln(p_{k+1/2}) - ln(p_k)) (full levels)\n\nSame formula but k → k-1/2.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.isdecreasing-Tuple{Vector}","page":"Function and type index","title":"SpeedyWeather.isdecreasing","text":"true/false = isdecreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly decreasing.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.isincreasing-Tuple{Vector}","page":"Function and type index","title":"SpeedyWeather.isincreasing","text":"true/false = isincreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly increasing.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Tuple{ColumnVariables, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"large_scale_condensation!(\n column::ColumnVariables,\n model::PrimitiveDry\n)\n\n\nNo condensation in a PrimitiveDry model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Tuple{ColumnVariables, PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"Function barrier only.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, SpeedyCondensation, Geometry, DynamicsConstants, SpeedyWeather.AbstractAtmosphere, SpeedyWeather.TimeStepper}} where NF","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"large_scale_condensation!(\n column::ColumnVariables{NF},\n scheme::SpeedyCondensation,\n geometry::Geometry,\n constants::DynamicsConstants,\n atmosphere::SpeedyWeather.AbstractAtmosphere,\n time_stepping::SpeedyWeather.TimeStepper\n)\n\n\nLarge-scale condensation for a column by relaxation back to a reference relative humidity if larger than that. Calculates the tendencies for specific humidity and temperature and integrates the large-scale precipitation vertically for output.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.launch_kernel!-Tuple{SpeedyWeather.DeviceSetup, Any, Any, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.launch_kernel!","text":"launch_kernel!(device_setup::DeviceSetup, kernel!, ndrange, kernel_args...)\n\nLaunches the kernel! on the device_setup with ndrange computations over the kernel and arguments kernel_args\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.leapfrog!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, Real, Int64, Leapfrog{NF}}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.leapfrog!","text":"leapfrog!(\n A_old::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n A_new::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n dt::Real,\n lf::Int64,\n L::Leapfrog{NF<:AbstractFloat}\n)\n\n\nPerforms one leapfrog time step with (lf=2) or without (lf=1) Robert+Williams filter (see Williams (2009), Montly Weather Review, Eq. 7-9).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_pressure_gradient!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticSurfaceTimesteps, Int64, DynamicsConstants, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.linear_pressure_gradient!","text":"linear_pressure_gradient!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.PrognosticSurfaceTimesteps,\n lf::Int64,\n C::DynamicsConstants,\n I::SpeedyWeather.ImplicitPrimitiveEq\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nAdd the linear contribution of the pressure gradient to the geopotential. The pressure gradient in the divergence equation takes the form\n\n-∇⋅(Rd*Tᵥ*∇lnpₛ) = -∇⋅(Rd*Tᵥ'*∇lnpₛ) - ∇²(Rd*Tₖ*lnpₛ)\n\nSo that the second term inside the Laplace operator can be added to the geopotential. Rd is the gas constant, Tᵥ the virtual temperature and Tᵥ' its anomaly wrt to the average or reference temperature Tₖ, lnpₛ is the logarithm of surface pressure.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, DynamicsConstants, Int64}","page":"Function and type index","title":"SpeedyWeather.linear_virtual_temperature!","text":"linear_virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n constants::DynamicsConstants,\n lf::Int64\n) -> Any\n\n\nCalculates a linearised virtual temperature Tᵥ as\n\nTᵥ = T + Tₖμq\n\nWith absolute temperature T, layer-average temperarture Tₖ (computed in temperature_average!), specific humidity q and\n\nμ = (1-ξ)/ξ, ξ = R_dry/R_vapour.\n\nin spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, PrimitiveDry, Integer}","page":"Function and type index","title":"SpeedyWeather.linear_virtual_temperature!","text":"linear_virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::PrimitiveDry,\n lf::Integer\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nLinear virtual temperature for model::PrimitiveDry: Just copy over arrays from temp to temp_virt at timestep lf in spectral space as humidity is zero in this model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.load_trajectory-Tuple{Union{String, Symbol}, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.load_trajectory","text":"load_trajectory(\n var_name::Union{String, Symbol},\n model::SpeedyWeather.ModelSetup\n) -> Any\n\n\nLoads a var_name trajectory of the model M that has been saved in a netCDF file during the time stepping.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.moist_static_energy!-Tuple{ColumnVariables, SpeedyWeather.Thermodynamics}","page":"Function and type index","title":"SpeedyWeather.moist_static_energy!","text":"moist_static_energy!(\n column::ColumnVariables,\n thermodynamics::SpeedyWeather.Thermodynamics\n)\n\n\nCompute the moist static energy\n\nMSE = SE + Lc*Q = cₚT + Φ + Lc*Q\n\nwith the static energy SE, the latent heat of condensation Lc, the geopotential Φ. As well as the saturation moist static energy which replaces Q with Q_sat\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nans-Tuple","page":"Function and type index","title":"SpeedyWeather.nans","text":"A = nans(dims...)\n\nAllocate A::Array{Float64} with NaNs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nans-Union{Tuple{T}, Tuple{Type{T}, Vararg{Any}}} where T","page":"Function and type index","title":"SpeedyWeather.nans","text":"A = nans(T,dims...)\n\nAllocate array A with NaNs of type T. Similar to zeros(T,dims...).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nar_detection!-Tuple{Feedback, PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.nar_detection!","text":"nar_detection!(\n feedback::Feedback,\n progn::PrognosticVariables\n) -> Union{Nothing, Bool}\n\n\nDetect NaR (Not-a-Real) in the prognostic variables.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.parameterization_tendencies!-Tuple{DiagnosticVariables, Dates.DateTime, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.parameterization_tendencies!","text":"parameterization_tendencies!(\n diagn::DiagnosticVariables,\n time::Dates.DateTime,\n model::PrimitiveEquation\n) -> Any\n\n\nCompute tendencies for u,v,temp,humid from physical parametrizations. Extract for each vertical atmospheric column the prognostic variables (stored in diagn as they are grid-point transformed), loop over all grid-points, compute all parametrizations on a single-column basis, then write the tendencies back into a horizontal field of tendencies.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.pressure_on_orography!-Tuple{PrognosticVariables, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.pressure_on_orography!","text":"pressure_on_orography!(\n progn::PrognosticVariables,\n model::PrimitiveEquation\n)\n\n\nInitialize surface pressure on orography by integrating the hydrostatic equation with the reference temperature lapse rate.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.progress!-Tuple{Feedback}","page":"Function and type index","title":"SpeedyWeather.progress!","text":"progress!(feedback::Feedback)\n\n\nCalls the progress meter and writes every 5% progress increase to txt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.progress_finish!-Tuple{Feedback}","page":"Function and type index","title":"SpeedyWeather.progress_finish!","text":"progress_finish!(F::Feedback)\n\n\nFinalises the progress meter and the progress txt file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.readable_secs-Tuple{Real}","page":"Function and type index","title":"SpeedyWeather.readable_secs","text":"readable_secs(secs::Real) -> Dates.CompoundPeriod\n\n\nReturns Dates.CompoundPeriod rounding to either (days, hours), (hours, minutes), (minutes, seconds), or seconds with 1 decimal place accuracy for >10s and two for less. E.g.\n\njulia> readable_secs(12345)\n3 hours, 26 minutes\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.remaining_time-Tuple{ProgressMeter.Progress}","page":"Function and type index","title":"SpeedyWeather.remaining_time","text":"remaining_time(p::ProgressMeter.Progress) -> String\n\n\nEstimates the remaining time from a ProgresssMeter.Progress. Adapted from ProgressMeter.jl\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.reset_column!-Union{Tuple{ColumnVariables{NF}}, Tuple{NF}} where NF","page":"Function and type index","title":"SpeedyWeather.reset_column!","text":"reset_column!(column::ColumnVariables{NF})\n\n\nSet the accumulators (tendencies but also vertical sums and similar) back to zero for column to be reused at other grid points.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.run!-Tuple{SpeedyWeather.Simulation}","page":"Function and type index","title":"SpeedyWeather.run!","text":"run!(\n simulation::SpeedyWeather.Simulation;\n initialize,\n n_days,\n startdate,\n output\n) -> PrognosticVariables\n\n\nRun a SpeedyWeather.jl simulation. The simulation.model is assumed to be initialized, otherwise use initialize=true as keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.saturation_humidity!-Tuple{ColumnVariables, SpeedyWeather.Thermodynamics}","page":"Function and type index","title":"SpeedyWeather.saturation_humidity!","text":"saturation_humidity!(\n column::ColumnVariables,\n thermodynamics::SpeedyWeather.Thermodynamics\n)\n\n\nCompute (1) the saturation vapour pressure as a function of temperature using the August-Roche-Magnus formula,\n\neᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),\n\nwhere T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively. And (2) the saturation specific humidity according to the formula,\n\n0.622 * e / (p - (1 - 0.622) * e),\n\nwhere e is the saturation vapour pressure, p is the pressure, and 0.622 is the ratio of the molecular weight of water to dry air.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.scale!-Tuple{PrognosticVariables, Real}","page":"Function and type index","title":"SpeedyWeather.scale!","text":"scale!(progn::PrognosticVariables, scale::Real) -> Real\n\n\nScales the prognostic variables vorticity and divergence with the Earth's radius which is used in the dynamical core.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.scale!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Real}} where NF","page":"Function and type index","title":"SpeedyWeather.scale!","text":"scale!(\n progn::PrognosticVariables{NF},\n var::Symbol,\n scale::Real\n)\n\n\nScale the variable var inside progn with scalar scale.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_divergence!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_divergence!","text":"set_divergence!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_humidity!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_humidity!","text":"set_humidity!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, AbstractMatrix}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractMatrix, \n Grid::Type{<:AbstractGrid}, \n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, LowerTriangularMatrix}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::LowerTriangularMatrix;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in spectral space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, SpeedyWeather.RingGrids.AbstractGrid, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractGrid, \n M::ModelSetup;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, SpeedyWeather.RingGrids.AbstractGrid}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractGrid, \n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_temperature!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_temperature!","text":"set_temperature!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Number}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"function set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n s::Number;\n lf::Integer=1) where NF\n\nSets all values of prognostic variable varname at leapfrog index lf to the scalar s.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:AbstractMatrix}}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:AbstractMatrix}, Type{<:SpeedyWeather.RingGrids.AbstractGrid}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractMatrix}, \n Grid::Type{<:AbstractGrid}=FullGaussianGrid;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:LowerTriangularMatrix}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:LowerTriangularMatrix};\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:SpeedyWeather.RingGrids.AbstractGrid}, SpeedyWeather.ModelSetup}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractGrid}, \n M::ModelSetup;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:SpeedyWeather.RingGrids.AbstractGrid}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractGrid};\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_vorticity!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_vorticity!","text":"set_vorticity!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.sigma_okay-Tuple{Integer, AbstractVector}","page":"Function and type index","title":"SpeedyWeather.sigma_okay","text":"sigma_okay(nlev::Integer, σ_half::AbstractVector) -> Bool\n\n\nCheck that nlev and σ_half match.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.speedstring-Tuple{Any, Any}","page":"Function and type index","title":"SpeedyWeather.speedstring","text":"speedstring(sec_per_iter, dt_in_sec) -> String\n\n\ndefine a ProgressMeter.speedstring method that also takes a time step dt_in_sec to translate sec/iteration to days/days-like speeds.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.static_energy_diffusion!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, SpeedyWeather.StaticEnergyDiffusion}} where NF","page":"Function and type index","title":"SpeedyWeather.static_energy_diffusion!","text":"static_energy_diffusion!(\n column::ColumnVariables{NF},\n scheme::SpeedyWeather.StaticEnergyDiffusion\n)\n\n\nApply dry static energy diffusion.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.surface_pressure_tendency!-Tuple{SpeedyWeather.SurfaceVariables, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.surface_pressure_tendency!","text":"surface_pressure_tendency!( Prog::PrognosticVariables,\n Diag::DiagnosticVariables,\n lf::Int,\n M::PrimitiveEquation)\n\nComputes the tendency of the logarithm of surface pressure as\n\n-(ū*px + v̄*py) - D̄\n\nwith ū,v̄ being the vertically averaged velocities; px, py the gradients of the logarithm of surface pressure ln(p_s) and D̄ the vertically averaged divergence.\n\nCalculate ∇ln(p_s) in spectral space, convert to grid.\nMultiply ū,v̄ with ∇ln(p_s) in grid-point space, convert to spectral.\nD̄ is subtracted in spectral space.\nSet tendency of the l=m=0 mode to 0 for better mass conservation.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_anomaly!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.temperature_anomaly!","text":"Convert absolute and virtual temperature to anomalies wrt to the reference profile\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_average!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.temperature_average!","text":"temperature_average!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n S::SpectralTransform\n) -> Any\n\n\nCalculates the average temperature of a layer from the l=m=0 harmonic and stores the result in diagn.temp_average\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Tuple{ColumnVariables, JablonowskiRelaxation}","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables,\n scheme::JablonowskiRelaxation\n)\n\n\nApply HeldSuarez-like temperature relaxation to the Jablonowski and Williamson vertical profile.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Tuple{ColumnVariables, NoTemperatureRelaxation}","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables,\n scheme::NoTemperatureRelaxation\n)\n\n\njust passes.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, HeldSuarez}} where NF","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables{NF},\n scheme::HeldSuarez\n)\n\n\nApply temperature relaxation following Held and Suarez 1996, BAMS.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_tendency!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, DynamicsConstants, Geometry, SpectralTransform, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.temperature_tendency!","text":"temperature_tendency!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform,\n I::SpeedyWeather.ImplicitPrimitiveEq\n)\n\n\nCompute the temperature tendency\n\n∂T/∂t += -∇⋅((u,v)*T') + T'D + κTᵥ*Dlnp/Dt\n\n+= because the tendencies already contain parameterizations and vertical advection. T' is the anomaly with respect to the reference/average temperature. Tᵥ is the virtual temperature used in the adiabatic term κTᵥ*Dlnp/Dt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_tendency!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.temperature_tendency!","text":"temperature_tendency!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation\n)\n\n\nFunction barrier to unpack model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.time_stepping!-Tuple{PrognosticVariables, DiagnosticVariables, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.time_stepping!","text":"time_stepping!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n model::SpeedyWeather.ModelSetup\n) -> PrognosticVariables\n\n\nMain time loop that that initializes output and feedback, loops over all time steps and calls the output and feedback functions.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.timestep!","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic\n)\ntimestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic,\n lf1::Int64\n)\ntimestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic,\n lf1::Int64,\n lf2::Int64\n)\n\n\nCalculate a single time step for the model <: Barotropic.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.timestep!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation, Int64}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation, Int64, Int64}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation\n) -> Any\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation,\n lf1::Int64\n) -> Any\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation,\n lf1::Int64,\n lf2::Int64\n) -> Any\n\n\nCalculate a single time step for the model<:PrimitiveEquation\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.timestep!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater, Int64}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater, Int64, Int64}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater,\n lf1::Int64\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater,\n lf1::Int64,\n lf2::Int64\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\n\n\nCalculate a single time step for the model <: ShallowWater.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.underflow!-Union{Tuple{T}, Tuple{AbstractArray{T}, Real}} where T","page":"Function and type index","title":"SpeedyWeather.underflow!","text":"underflow!(A::AbstractArray,ϵ::Real)\n\nUnderflows element a in A to zero if abs(a) < ϵ.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.unscale!-Tuple{AbstractArray, Real}","page":"Function and type index","title":"SpeedyWeather.unscale!","text":"unscale!(variable::AbstractArray, scale::Real) -> Any\n\n\nUndo the radius-scaling for any variable. Method used for netcdf output.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.unscale!-Tuple{PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.unscale!","text":"unscale!(progn::PrognosticVariables) -> Int64\n\n\nUndo the radius-scaling of vorticity and divergence from scale!(progn,scale::Real).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vertical_integration!-Union{Tuple{NF}, Tuple{DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, PrognosticVariables{NF}, Int64, Geometry{NF}}} where NF","page":"Function and type index","title":"SpeedyWeather.vertical_integration!","text":"vertical_integration!(Diag::DiagnosticVariables,G::Geometry)\n\nCalculates the vertically averaged (weighted by the thickness of the σ level) velocities (*coslat) and divergence. E.g.\n\nu_mean = ∑_k=1^nlev Δσ_k * u_k\n\nu,v are averaged in grid-point space, divergence in spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.virtual_temperature!","text":"virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n constants::DynamicsConstants\n)\n\n\nCalculates the virtual temperature Tᵥ as\n\nTᵥ = T(1+μq)\n\nWith absolute temperature T, specific humidity q and\n\nμ = (1-ξ)/ξ, ξ = R_dry/R_vapour.\n\nin grid-point space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.virtual_temperature!","text":"virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n model::PrimitiveDry\n) -> SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat\n\n\nVirtual temperature in grid-point space: For the PrimitiveDry temperature and virtual temperature are the same (humidity=0). Just copy over the arrays.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.volume_flux_divergence!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, SpeedyWeather.AbstractOrography, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.volume_flux_divergence!","text":"volume_flux_divergence!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.SurfaceVariables,\n orog::SpeedyWeather.AbstractOrography,\n constants::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform\n)\n\n\nComputes the (negative) divergence of the volume fluxes uh,vh for the continuity equation, -∇⋅(uh,vh).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vordiv_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.vordiv_tendencies!","text":"vordiv_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surf::SpeedyWeather.SurfaceVariables,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform\n)\n\n\nTendencies for vorticity and divergence. Excluding Bernoulli potential with geopotential and linear pressure gradient inside the Laplace operator, which are added later in spectral space.\n\nu_tend += v*(f+ζ) - RTᵥ'*∇lnp_x\nv_tend += -u*(f+ζ) - RTᵥ'*∇lnp_y\n\n+= because the tendencies already contain the parameterizations and vertical advection. f is coriolis, ζ relative vorticity, R the gas constant Tᵥ' the virtual temperature anomaly, ∇lnp the gradient of surface pressure and _x and _y its zonal/meridional components. The tendencies are then curled/dived to get the tendencies for vorticity/divergence in spectral space\n\n∂ζ/∂t = ∇×(u_tend,v_tend)\n∂D/∂t = ∇⋅(u_tend,v_tend) + ...\n\n+ ... because there's more terms added later for divergence.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vordiv_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.vordiv_tendencies!","text":"vordiv_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surf::SpeedyWeather.SurfaceVariables,\n model::PrimitiveEquation\n)\n\n\nFunction barrier to unpack model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, Barotropic}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux!","text":"vorticity_flux!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::Barotropic\n)\n\n\nVorticity flux tendency in the barotropic vorticity equation\n\n∂ζ/∂t = ∇×(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux!","text":"vorticity_flux!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater\n)\n\n\nVorticity flux tendency in the shallow water equations\n\n∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux_curldiv!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux_curldiv!","text":"vorticity_flux_curldiv!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform;\n div\n)\n\n\nCompute the vorticity advection as the curl/div of the vorticity fluxes\n\n∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ from u_tend_grid/v_tend_grid that are assumed to be alread set in forcing!. Set div=false for the BarotropicModel which doesn't require the divergence tendency.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.workgroup_size-Tuple{SpeedyWeather.AbstractDevice}","page":"Function and type index","title":"SpeedyWeather.workgroup_size","text":"workgroup_size(dev::AbstractDevice)\n\nReturns a workgroup size depending on dev. WIP: Will be expanded in the future to also include grid information. \n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_column_tendencies!-Tuple{DiagnosticVariables, ColumnVariables, Int64}","page":"Function and type index","title":"SpeedyWeather.write_column_tendencies!","text":"write_column_tendencies!(\n D::DiagnosticVariables,\n C::ColumnVariables,\n ij::Int64\n)\n\n\nWrite the parametrization tendencies from C::ColumnVariables into the horizontal fields of tendencies stored in D::DiagnosticVariables at gridpoint index ij.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_netcdf_time!-Tuple{OutputWriter, Dates.DateTime}","page":"Function and type index","title":"SpeedyWeather.write_netcdf_time!","text":"write_netcdf_time!(\n output::OutputWriter,\n time::Dates.DateTime\n)\n\n\nWrite the current time time::DateTime to the netCDF file in output::OutputWriter.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_netcdf_variables!-Union{Tuple{Model}, Tuple{Grid}, Tuple{NF}, Tuple{OutputWriter, DiagnosticVariables{NF, Grid, Model}}} where {NF, Grid, Model}","page":"Function and type index","title":"SpeedyWeather.write_netcdf_variables!","text":"write_netcdf_variables!(\n output::OutputWriter,\n diagn::DiagnosticVariables{NF, Grid, Model}\n)\n\n\nWrite diagnostic variables from diagn to the netCDF file in output::OutputWriter.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_output!-Tuple{OutputWriter, Dates.DateTime, DiagnosticVariables}","page":"Function and type index","title":"SpeedyWeather.write_output!","text":"write_output!(\n outputter::OutputWriter,\n time::Dates.DateTime,\n diagn::DiagnosticVariables\n)\n\n\nWrites the variables from diagn of time step i at time time into outputter.netcdf_file. Simply escapes for no netcdf output of if output shouldn't be written on this time step. Interpolates onto output grid and resolution as specified in outputter, converts to output number format, truncates the mantissa for higher compression and applies lossless compression.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_restart_file-Tuple{PrognosticVariables, OutputWriter}","page":"Function and type index","title":"SpeedyWeather.write_restart_file","text":"write_restart_file(\n progn::PrognosticVariables,\n output::OutputWriter\n) -> Union{Nothing, String}\n\n\nA restart file restart.jld2 with the prognostic variables is written to the output folder (or current path) that can be used to restart the model. restart.jld2 will then be used as initial conditions. The prognostic variables are bitrounded for compression and the 2nd leapfrog time step is discarded. Variables in restart file are unscaled.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.zero_tendencies!-Tuple{DiagnosticVariables}","page":"Function and type index","title":"SpeedyWeather.zero_tendencies!","text":"zero_tendencies!(diagn::DiagnosticVariables)\n\n\nSet the tendencies in diagn to zero.\n\n\n\n\n\n","category":"method"},{"location":"how_to_run_speedy/#How-to-run-SpeedyWeather.jl","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Creating a SpeedyWeather.jl simulation and running it consists conceptually of 4 steps","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Create a SpectralGrid which defines the grid and spectral resolution\nCreate a model\nInitialize a model to obtain a Simulation.\nRun the simulation.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"In the following we will describe these steps in more detail, but let's start with some examples first.","category":"page"},{"location":"how_to_run_speedy/#Example-1:-2D-turbulence-on-a-non-rotating-sphere","page":"How to run SpeedyWeather.jl","title":"Example 1: 2D turbulence on a non-rotating sphere","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"We want to use the barotropic model to simulate some free-decaying 2D turbulence on the sphere without rotation. We start by defining the SpectralGrid object. To have a resolution of about 100km, we choose a spectral resolution of T127 (see Available horizontal resolutions) and nlev=1 vertical levels. The SpectralGrid object will provide us with some more information","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> spectral_grid = SpectralGrid(trunc=127,nlev=1)\nSpectralGrid:\n Spectral: T127 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m\n Grid: 40320-element, 192-ring OctahedralGaussianGrid{Float32} (quadratic)\n Resolution: 112km (average)\n Vertical: 1-level SigmaCoordinates","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"We could have specified further options, but let's ignore that for now. Next step we create a planet that's like Earth but not rotating","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> still_earth = Earth(rotation=0)\nMain.SpeedyWeather.Earth\n rotation: Float64 0.0\n gravity: Float64 9.81\n daily_cycle: Bool true\n length_of_day: Float64 24.0\n seasonal_cycle: Bool true\n length_of_year: Float64 365.25\n equinox: Dates.DateTime\n axial_tilt: Float64 23.4","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"There are other options to create a planet but they are irrelevant for the barotropic vorticity equations. We also want to specify the initial conditions, randomly distributed vorticity is already defined","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> initial_conditions = StartWithRandomVorticity()\nStartWithRandomVorticity\n power_law: Float64 -3.0\n amplitude: Float64 1.0e-5","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"By default, the power of vorticity is spectrally distributed with k^-3, k being the horizontal wavenumber, and the amplitude is 10^-5text s^-1.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Now we want to construct a BarotropicModel with these","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = BarotropicModel(;spectral_grid, initial_conditions, planet=still_earth);","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The model contains all the parameters, but isn't initialized yet, which we can do with and then run it.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> simulation = initialize!(model);\njulia> run!(simulation,n_days=30)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The run! command will always return the prognostic variables, which, by default, are plotted for surface relative vorticity with a unicode plot. The resolution of the plot is not necessarily representative but it lets us have a quick look at the result","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Barotropic vorticity unicode plot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Woohoo! I can see turbulence! You could pick up where this simulation stopped by simply doing run!(simulation,n_days=50) again. We didn't store any output, which you can do by run!(simulation,output=true), which will switch on NetCDF output with default settings. More options on output in NetCDF output.","category":"page"},{"location":"how_to_run_speedy/#Example-2:-Shallow-water-with-mountains","page":"How to run SpeedyWeather.jl","title":"Example 2: Shallow water with mountains","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"As a second example, let's investigate the Galewsky et al.[1] test case for the shallow water equations with and without mountains. As the shallow water system has also only one level, we can reuse the SpectralGrid from Example 1.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> spectral_grid = SpectralGrid(trunc=127,nlev=1)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Now as a first simulation, we want to disable any orography, so we create a NoOrography","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> orography = NoOrography(spectral_grid)\nNoOrography{Float32, OctahedralGaussianGrid{Float32}}","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Although the orography is zero, you have to pass on spectral_grid so that it can still initialize zero-arrays of the right size and element type. Awesome. This time the initial conditions should be set the the Galewsky et al.[1] zonal jet, which is already defined as","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> initial_conditions = ZonalJet()\nZonalJet\n latitude: Float64 45.0\n width: Float64 19.28571428571429\n umax: Float64 80.0\n perturb_lat: Float64 45.0\n perturb_lon: Float64 270.0\n perturb_xwidth: Float64 19.098593171027442\n perturb_ywidth: Float64 3.819718634205488\n perturb_height: Float64 120.0","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The jet sits at 45˚N with a maximum velocity of 80m/s and a perturbation as described in their paper. Now we construct a model, but this time a ShallowWaterModel","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = ShallowWaterModel(;spectral_grid, orography, initial_conditions);\njulia> simulation = initialize!(model);","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet unicode plot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Oh yeah. That looks like the wobbly jet in their paper. Let's run it again for another 6 days but this time also store NetCDF output.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> run!(simulation,n_days=6,output=true)\nWeather is speedy: run 0002 100%|███████████████████████| Time: 0:00:12 (115.37 years/day)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The progress bar tells us that the simulation run got the identification \"0002\", meaning that data is stored in the folder /run_0002, so let's plot that data properly (and not just using UnicodePlots).","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> using PyPlot, NCDatasets\njulia> ds = NCDataset(\"run_0002/output.nc\");\njulia> ds[\"vor\"]\nvor (384 × 192 × 1 × 25)\n Datatype: Float32\n Dimensions: lon × lat × lev × time\n Attributes:\n units = 1/s\n missing_value = NaN\n long_name = relative vorticity\n _FillValue = NaN","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Vorticity vor is stored as a 384x192x1x25 array, we may want to look at the first time step, which is the end of the previous simulation (time=6days) which we didn't store output for.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> vor = ds[\"vor\"][:,:,1,1];\njulia> lat = ds[\"lat\"][:];\njulia> lon = ds[\"lon\"][:];\njulia> pcolormesh(lon,lat,vor')","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Which looks like","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"You see that the unicode plot heavily coarse-grains the simulation, well it's unicode after all! And now the last time step, that means time=12days is","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> vor = ds[\"vor\"][:,:,1,25];\njulia> pcolormesh(lon,lat,vor')","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The jet broke up into many small eddies, but the turbulence is still confined to the northern hemisphere, cool! How this may change when we add mountains (we had NoOrography above!), say Earth's orography, you may ask? Let's try it out! We create an EarthOrography struct like so","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> orography = EarthOrography(spectral_grid)\nEarthOrography{Float32, OctahedralGaussianGrid{Float32}}:\n path::String = SpeedyWeather.jl/input_data\n file::String = orography_F512.nc\n scale::Float64 = 1.0\n smoothing::Bool = true\n smoothing_power::Float64 = 1.0\n smoothing_strength::Float64 = 0.1\n smoothing_truncation::Int64 = 85","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"It will read the orography from file as shown, and there are some smoothing options too, but let's not change them. Same as before, create a model, initialize into a simulation, run. This time directly for 12 days so that we can compare with the last plot","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = ShallowWaterModel(;spectral_grid, orography, initial_conditions);\njulia> simulation = initialize!(model);\njulia> run!(simulation,n_days=12,output=true)\nWeather is speedy: run 0003 100%|███████████████████████| Time: 0:00:35 (79.16 years/day)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"This time the run got the id \"0003\", but otherwise we do as before.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Interesting! The initial conditions have zero velocity in the southern hemisphere, but still, one can see some imprint of the orography on vorticity. You can spot the coastline of Antarctica; the Andes and Greenland are somewhat visible too. Mountains also completely changed the flow after 12 days, probably not surprising!","category":"page"},{"location":"how_to_run_speedy/#SpectralGrid","page":"How to run SpeedyWeather.jl","title":"SpectralGrid","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object. We have seen some examples above, now let's look into the details","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"SpectralGrid","category":"page"},{"location":"how_to_run_speedy/#References","page":"How to run SpeedyWeather.jl","title":"References","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"[1] Galewsky, Scott, Polvani, 2004. An initial-value problem for testing numerical models of the global shallow-water equations, Tellus A. DOI: 10.3402/tellusa.v56i5.14436","category":"page"},{"location":"speedytransforms/#SpeedyTransforms","page":"Submodule: SpeedyTransforms","title":"SpeedyTransforms","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"SpeedyTransforms is a submodule that has been developed for SpeedyWeather.jl which is technically independent (SpeedyWeather.jl however imports it) and can also be used without running simulations. It is just not put into its own respective repository.","category":"page"},{"location":"speedytransforms/#Example-transforms","page":"Submodule: SpeedyTransforms","title":"Example transforms","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"julia> using SpeedyWeather\njulia> alms = zeros(ComplexF64,3,3) # spectral coefficients\njulia> alms[2,2] = 1 # only l=1,m=1 harmonic\njulia> map = gridded(alms) # convert to grid space\n8×4 Matrix{Float64}:\n -0.324541 -0.600363 -0.600363 -0.324541\n -0.134429 -0.248678 -0.248678 -0.134429\n 0.134429 0.248678 0.248678 0.134429\n 0.324541 0.600363 0.600363 0.324541\n 0.324541 0.600363 0.600363 0.324541\n 0.134429 0.248678 0.248678 0.134429\n -0.134429 -0.248678 -0.248678 -0.134429\n -0.324541 -0.600363 -0.600363 -0.324541\n \njulia> spectral(map) # back to spectral space\n3×3 Matrix{ComplexF64}:\n 0.0+0.0im 0.0+0.0im 0.0+0.0im\n 0.0+0.0im 1.0+3.60727e-17im 0.0+0.0im\n 0.0+0.0im 0.0+0.0im 0.0+0.0im","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"and we have successfully reobtained the l=m=1 spherical harmonic.","category":"page"},{"location":"speedytransforms/#Functions-and-type-index","page":"Submodule: SpeedyTransforms","title":"Functions and type index","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Modules = [SpeedyWeather.SpeedyTransforms]","category":"page"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform{NF<:AbstractFloat}(...)\n\nSpectralTransform struct that contains all parameters and preallocated arrays for the spectral transform.\n\n\n\n\n\n","category":"type"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{AbstractArray{Complex{NF}, 2}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform( alms::AbstractMatrix{Complex{NF}};\n recompute_legendre::Bool=true,\n Grid::Type{<:AbstractGrid}=DEFAULT_GRID)\n\nGenerator function for a SpectralTransform struct based on the size of the spectral coefficients alms and the grid Grid. Recomputes the Legendre polynomials by default.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{NF}, Tuple{Type{NF}, Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Int64, Int64}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"SpectralTransform(\n ::Type{NF},\n Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid},\n lmax::Int64,\n mmax::Int64;\n recompute_legendre,\n legendre_shortcut,\n dealiasing\n) -> SpectralTransform\n\n\nGenerator function for a SpectralTransform struct. With NF the number format, Grid the grid type <:AbstractGrid and spectral truncation lmax,mmax this function sets up necessary constants for the spetral transform. Also plans the Fourier transforms, retrieves the colatitudes, and preallocates the Legendre polynomials (if recompute_legendre == false) and quadrature weights.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform( map::AbstractGrid;\n recompute_legendre::Bool=true)\n\nGenerator function for a SpectralTransform struct based on the size and grid type of gridded field map. Recomputes the Legendre polynomials by default.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.UV_from_vor!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.UV_from_vor!","text":"UV_from_vor!( U::LowerTriangularMatrix,\n V::LowerTriangularMatrix,\n vor::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGet U,V (=(u,v)*coslat) from vorticity ζ spectral space (divergence D=0) Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity. Then compute zonal and meridional gradients to get U,V.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.UV_from_vordiv!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.UV_from_vordiv!","text":"UV_from_vordiv!(U::LowerTriangularMatrix,\n V::LowerTriangularMatrix,\n vor::LowerTriangularMatrix,\n div::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGet U,V (=(u,v)*coslat) from vorticity ζ and divergence D in spectral space. Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity and velocity potential from divergence. Then compute zonal and meridional gradients to get U,V.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms._divergence!-Union{Tuple{NF}, Tuple{Any, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms._divergence!","text":"_divergence!( kernel,\n div::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGeneric divergence function of vector u,v that writes into the output into div. Generic as it uses the kernel kernel such that curl, div, add or flipsign options are provided through kernel, but otherwise a single function is used.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.curl!-Tuple{LowerTriangularMatrix, LowerTriangularMatrix, LowerTriangularMatrix, SpectralTransform}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.curl!","text":"curl!( curl::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform;\n flipsign::Bool=false,\n add::Bool=false,\n )\n\nCurl of a vector u,v written into curl, curl = ∇×(u,v). u,v are expected to have a 1/coslat-scaling included, then curl is not scaled. flipsign option calculates -∇×(u,v) instead. add option calculates curl += ∇×(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently with flipped u,v -> v,u for the curl.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.divergence!-Tuple{LowerTriangularMatrix, LowerTriangularMatrix, LowerTriangularMatrix, SpectralTransform}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.divergence!","text":"divergence!(div::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform{NF};\n flipsign::Bool=false,\n add::Bool=false,\n )\n\nDivergence of a vector u,v written into div, div = ∇⋅(u,v). u,v are expected to have a 1/coslat-scaling included, then div is not scaled. flipsign option calculates -∇⋅(u,v) instead. add option calculates div += ∇⋅(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.get_recursion_factors-Union{Tuple{NF}, Tuple{Type{NF}, Int64, Int64}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.get_recursion_factors","text":"get_recursion_factors( ::Type{NF}, # number format NF\n lmax::Int, # max degree l of spherical harmonics (0-based here)\n mmax::Int # max order m of spherical harmonics\n ) where {NF<:AbstractFloat}\n\nReturns a matrix of recursion factors ϵ up to degree lmax and order mmax of number format NF.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded!-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!( map::AbstractGrid,\n alms::LowerTriangularMatrix,\n S::SpectralTransform)\n\nSpectral transform (spectral to grid) of the spherical harmonic coefficients alms to a gridded field map. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded-Union{Tuple{AbstractMatrix{T}}, Tuple{T}, Tuple{NF}} where {NF, T<:Complex{NF}}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded","text":"gridded(\n alms::AbstractArray{T<:Complex{NF}, 2};\n recompute_legendre,\n Grid\n) -> Any\n\n\nSpectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map. Based on the size of alms the grid type grid, the spatial resolution is retrieved based on the truncation defined for grid. SpectralTransform struct S is allocated to execute gridded(alms,S).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded-Union{Tuple{NF}, Tuple{AbstractMatrix, SpectralTransform{NF}}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded","text":"gridded(\n alms::AbstractMatrix,\n S::SpectralTransform{NF}\n) -> Any\n\n\nSpectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map with precalculated properties based on the SpectralTransform struct S. alms is converted to a LowerTriangularMatrix to execute the in-place gridded!.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.is_power_2-Tuple{Integer}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.is_power_2","text":"true/false = is_power_2(i::Integer)\n\nChecks whether an integer i is a power of 2, i.e. i = 2^k, with k = 0,1,2,3,....\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.roundup_fft-Union{Tuple{Integer}, Tuple{T}} where T<:Integer","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.roundup_fft","text":"m = roundup_fft(n::Int;\n small_primes::Vector{Int}=[2,3,5])\n\nReturns an integer m >= n with only small prime factors 2, 3 (default, others can be specified with the keyword argument small_primes) to obtain an efficiently fourier-transformable number of longitudes, m = 2^i * 3^j * 5^k >= n, with i,j,k >=0.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, SpeedyWeather.RingGrids.AbstractGrid{NF}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral!","text":"spectral!( alms::LowerTriangularMatrix,\n map::AbstractGrid,\n S::SpectralTransform)\n\nSpectral transform (grid to spectral space) from the gridded field map on a grid<:AbstractGrid to a LowerTriangularMatrix of spherical harmonic coefficients alms. Uses FFT in the zonal direction, and a Legendre Transform in the meridional direction exploiting symmetries. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Tuple{AbstractMatrix}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::AbstractMatrix;\n Grid,\n kwargs...\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nConverts map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid, SpectralTransform{NF}}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::SpeedyWeather.RingGrids.AbstractGrid,\n S::SpectralTransform{NF}\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nSpectral transform (grid to spectral) map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Union{Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::SpeedyWeather.RingGrids.AbstractGrid{NF};\n recompute_legendre,\n one_more_degree\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nConverts map to Grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_interpolation-Union{Tuple{NF}, Tuple{Type{NF}, LowerTriangularMatrix, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_interpolation","text":"alms_interp = spectral_interpolation( ::Type{NF},\n alms::LowerTriangularMatrix,\n ltrunc::Integer,\n mtrunc::Integer\n ) where NF\n\nReturns a spectral coefficient matrix alms_interp that is alms padded with zeros to interpolate in spectral space. If trunc is smaller or equal to the implicit truncation in alms obtained from its size than spectral_truncation is automatically called instead, returning alms_trunc, a coefficient matrix that is smaller than alms, implicitly setting higher degrees and orders to zero.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_smoothing!-Tuple{LowerTriangularMatrix, Real}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_smoothing!","text":"spectral_smoothing!(A::LowerTriangularMatrix,c;power=1)\n\nSmooth the spectral field A following A = (1-(1-c)∇²ⁿ) with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c>1.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_smoothing-Tuple{LowerTriangularMatrix, Real}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_smoothing","text":"A_smooth = spectral_smoothing(A::LowerTriangularMatrix,c;power=1)\n\nSmooth the spectral field A following A_smooth = (1-c*∇²ⁿ)A with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c<0.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Tuple{AbstractMatrix, Int64}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms,trunc)\n\nTruncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation trunc.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Tuple{AbstractMatrix}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms)\n\nTruncate spectral coefficients alms in-place by setting the upper right triangle to zero. This is to enforce that all coefficients for which the degree l is larger than order m are zero.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Union{Tuple{NF}, Tuple{AbstractMatrix{NF}, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms::AbstractMatrix,ltrunc::Integer,mtrunc::Integer)\n\nTruncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{NF}, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms::LowerTriangularMatrix,ltrunc::Integer,mtrunc::Integer)\n\nTruncate spectral coefficients alms in-place by setting all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc. Similar to spectral_truncation!(::AbstractMatrix, ...) but skips the upper triangle which is zero by design for LowerTriangularMatrix.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation-Union{Tuple{NF}, Tuple{Type{NF}, LowerTriangularMatrix, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation","text":"alms_trunc = spectral_truncation(alms,trunc)\n\nReturns a spectral coefficient matrix alms_trunc that is truncated from alms to the size (trunc+1)². alms_trunc only contains those coefficient of alms for which m,l ≤ trunc, and l ≥ m are zero anyway. If trunc is larger than the implicit truncation in alms obtained from its size than spectral_interpolation is automatically called instead, returning alms_interp, a coefficient matrix that is larger than alms with padded zero coefficients.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.ϵlm-Tuple{Int64, Int64}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.ϵlm","text":"ϵ = ϵ(l,m)\n\nRecursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) with default number format Float64.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.ϵlm-Union{Tuple{NF}, Tuple{Type{NF}, Int64, Int64}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.ϵlm","text":"ϵ = ϵ(NF,l,m)\n\nRecursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) and then converted to number format NF.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.∇²!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.∇²!","text":"∇²!( ∇²alms::LowerTriangularMatrix,\n alms::LowerTriangularMatrix,\n S::SpectralTransform;\n add::Bool=false,\n flipsign::Bool=false,\n inverse::Bool=false)\n\nLaplace operator ∇² applied to the spectral coefficients alms in spherical coordinates. The radius R is omitted in the eigenvalues which are precomputed in S. ∇²! is the in-place version which directly stores the output in the first argument ∇²alms.\n\nKeyword arguments\n\nadd=true adds the ∇²(alms) to the output\nflipsign=true computes -∇²(alms) instead\ninverse=true computes ∇⁻²(alms) instead\n\nDefault is add=false, flipsign=false, inverse=false. These options can be combined.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.∇⁻²!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.∇⁻²!","text":"∇⁻²!( ∇⁻²alms::LowerTriangularMatrix,\n alms::LowerTriangularMatrix,\n S::SpectralTransform;\n add::Bool=false,\n flipsign::Bool=false)\n\nCalls ∇²!(∇⁻²alms, alms, S; add, flipsign, inverse=true).\n\n\n\n\n\n","category":"method"},{"location":"grids/#Grids","page":"Grids","title":"Grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"The spectral transform (the Spherical Harmonic Transform) in SpeedyWeather.jl supports any ring-based equi-longitude grid. Several grids are already implemented but other can be added. The following pages will describe an overview of these grids and but let's start but how they can be used","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"julia> spectral_grid = SpectralGrid(Grid = FullGaussianGrid)\nSpectralGrid:\n Spectral: T31 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m\n Grid: 4608-element, 48-ring FullGaussianGrid{Float32} (quadratic)\n Resolution: 333km (average)\n Vertical: 8-level SigmaCoordinates","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object which defines the resolution in spectral and in grid-point space. The generator SpectralGrid() can take as a keyword argument Grid which can be any of the grids described below. The resolution of the grid, however, is not directly chosen, but determined from the spectral resolution trunc and the dealiasing factor. More in Matching spectral and grid resolution.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: RingGrids is a module too!\nWhile RingGrids is the underlying module that SpeedyWeather.jl uses for data structs on the sphere, the module can also be used independently of SpeedyWeather, for example to interpolate between data on different grids. See RingGrids","category":"page"},{"location":"grids/#Ring-based-equi-longitude-grids","page":"Grids","title":"Ring-based equi-longitude grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"SpeedyWeather.jl's spectral transform supports all ring-based equi-longitude grids. These grids have their grid points located on rings with constant latitude and on these rings the points are equi-spaced in longitude. There is technically no constrain on the spacing of the latitude rings, but the Legendre transform requires a quadrature to map those to spectral space and back. Common choices for latitudes are the Gaussian latitudes which use the Gaussian quadrature, or equi-angle latitudes (i.e. just regular latitudes but excluding the poles) that use the Clenshaw-Curtis quadrature. The longitudes have to be equi-spaced on every ring, which is necessary for the fast Fourier transform, as one would otherwise need to use a non-uniform Fourier transform. In SpeedyWeather.jl the first grid point on any ring can have a longitudinal offset though, for example by spacing 4 points around the globe at 45˚E, 135˚E, 225˚E, and 315˚E. In this case the offset is 45˚E as the first point is not at 0˚E.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: Is the FullClenshawGrid a longitude-latitude grid?\nShort answer: Yes. The FullClenshawGrid is a specific longitude-latitude grid with equi-angle spacing. The most common grids for geoscientific data use regular spacings for 0-360˚E in longitude and 90˚N-90˚S. The FullClenshawGrid does that too, but it does not have a point on the North or South pole, and the central latitude ring sits exactly on the Equator. We name it Clenshaw following the Clenshaw-Curtis quadrature that is used in the Legendre transfrom in the same way as Gaussian refers to the Gaussian quadrature.","category":"page"},{"location":"grids/#Implemented-grids","page":"Grids","title":"Implemented grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"All grids in SpeedyWeather.jl are a subtype of AbstractGrid, i.e. <: AbstractGrid. We further distinguish between full, and reduced grids. Full grids have the same number of longitude points on every latitude ring (i.e. points converge towards the poles) and reduced grids reduce the number of points towards the poles to have them more evenly spread out across the globe. More evenly does not necessarily mean that a grid is equal-area, meaning that every grid cell covers exactly the same area (although the shape changes).","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Currently the following full grids <: AbstractFullGrid are implemented","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"FullGaussianGrid, a full grid with Gaussian latitudes\nFullClenshawGrid, a full grid with equi-angle latitudes","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and additionally we have FullHEALPixGrid and FullOctaHEALPixGrid which are the full grid equivalents to the HEALPix grid and the OctaHEALPix grid discussed below. Full grid equivalent means that they have the same latitude rings, but no reduction in the number of points per ring towards the poles and no longitude offset. Other implemented reduced grids are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"OctahedralGaussianGrid, a reduced grid with Gaussian latitudes based on an octahedron\nOctahedralClenshawGrid, similar but based on equi-angle latitudes\nHEALPixGrid, an equal-area grid based on a dodecahedron with 12 faces\nOctaHEALPixGrid, an equal-area grid from the class of HEALPix grids but based on an octahedron.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"An overview of these grids is visualised here","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"(Image: Overview of implemented grids in SpeedyWeather.jl)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Visualised are each grid's grid points (white dots) and grid faces (white lines). All grids shown have 16 latitude rings on one hemisphere, Equator included. The total number of grid points is denoted in the top left of every subplot. The sphere is shaded with grey, orange and turquoise regions to denote the hemispheres in a and b, the 8 octahedral faces c, d,f and the 12 dodecahedral faces (or base pixels) in e. Coastlines are added for orientation.","category":"page"},{"location":"grids/#Grid-resolution","page":"Grids","title":"Grid resolution","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"All grids use the same resolution parameter nlat_half, i.e. the number of rings on one hemisphere, Equator included. The Gaussian grids (full and reduced) do not have a ring on the equator, so their total number of rings nlat is always even and twice nlat_half. Clenshaw-Curtis grids and the HEALPix grids have a ring on the equator such their total number of rings is always odd and one less than the Gaussian grids at the same nlat_half. ","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: HEALPix grids do not use Nside as resolution parameter\nThe original formulation for HEALPix grids use N_side, the number of grid points along the edges of each basepixel (8 in the figure above), SpeedyWeather.jl uses nlat_half, the number of rings on one hemisphere, Equator included, for all grids. This is done for consistency across grids. We may use N_side for the documentation or within functions though.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Related: Effective grid resolution and Available horizontal resolutions.","category":"page"},{"location":"grids/#Matching-spectral-and-grid-resolution","page":"Grids","title":"Matching spectral and grid resolution","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"A given spectral resolution can be matched to a variety of grid resolutions. A cubic grid, for example, combines a spectral truncation T with a grid resolution N (=nlat_half) such that T + 1 = N. Using T31 and an O32 is therefore often abbreviated as Tco31 meaning that the spherical harmonics are truncated at l_max=31 in combination with N=32, i.e. 64 latitude rings in total on an octahedral Gaussian grid. In SpeedyWeather.jl the choice of the order of truncation is controlled with the dealiasing parameter in the SpectralGrid construction.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Let J be the total number of rings. Then we have","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"T approx J for linear truncation, i.e. dealiasing = 1\nfrac32T approx J for quadratic truncation, i.e. dealiasing = 2\n2T approx J for cubic truncation, , i.e. dealiasing = 3","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and in general fracm+12T approx J for m-th order truncation. So the higher the truncation order the more grid points are used in combination with the same spectral resolution. A higher truncation order therefore makes all grid-point calculations more expensive, but can represent products of terms on the grid (which will have higher wavenumber components) to a higher accuracy as more grid points are available within a given wavelength. Using a sufficiently high truncation is therefore one way to avoid aliasing. A quick overview of how the grid resolution changes when dealiasing is passed onto SpectralGrid on the FullGaussianGrid","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"trunc dealiasing FullGaussianGrid size\n31 1 64x32\n31 2 96x48\n31 3 128x64\n42 1 96x48\n42 2 128x64\n42 3 192x96\n... ... ...","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"You will obtain this information every time you create a SpectralGrid(;Grid,trunc,dealiasing).","category":"page"},{"location":"grids/#FullGaussianGrid","page":"Grids","title":"Full Gaussian grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#FullClenshawGrid","page":"Grids","title":"Full Clenshaw-Curtis grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#Octahedral-Gaussian-grid","page":"Grids","title":"Octahedral Gaussian grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#HEALPix-grid","page":"Grids","title":"HEALPix grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"Technically, HEALPix grids are a class of grids that tessalate the sphere into faces that are often called basepixels. For each member of this class there are N_varphi basepixels in zonal direction and N_theta basepixels in meridional direction. For N_varphi = 4 and N_theta = 3 we obtain the classical HEALPix grid with N_varphi N_theta = 12 basepixels shown above in Implemented grids. Each basepixel has a quadratic number of grid points in them. There's an equatorial zone where the number of zonal grid points is constant (always 2N, so 32 at N=16) and there are polar caps above and below the equatorial zone with the border at cos(theta) = 23 (theta in colatitudes).","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Following Górski, 2004[1], the z=cos(theta) colatitude of the j-th ring in the north polar cap, j=1N_side with 2N_side = N is ","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - fracj^23N_side^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and on that ring, the longitude phi of the i-th point (i is the in-ring-index) is at","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2j(i-tfrac12)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The in-ring index i goes from i=14 for the first (i.e. northern-most) ring, i=18 for the second ring and i = 14j for the j-th ring in the northern polar cap.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"In the north equatorial belt j=N_side2N_side this changes to","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = frac43 - frac2j3N_side","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and the longitudes change to (i is always i = 14N_side in the equatorial belt meaning the number of longitude points is constant here)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2N_side(i - fracs2) quad s = (j - N_side + 1) mod 2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The modulo function comes in as there is an alternating longitudinal offset from the prime meridian (see Implemented grids). For the southern hemisphere the grid point locations can be obtained by mirror symmetry.","category":"page"},{"location":"grids/#Grid-cell-boundaries","page":"Grids","title":"Grid cell boundaries","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"The cell boundaries are obtained by setting i = k + 12 or i = k + 12 + j (half indices) into the equations above, such that z(phik), a function for the cosine of colatitude z of index k and the longitude phi is obtained. These are then (northern polar cap)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - frack^23N_side^2left(fracpi2phi_tright)^2 quad z = 1 - frack^23N_side^2left(fracpi2phi_t - piright)^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"with phi_t = phi mod tfracpi2 and in the equatorial belt","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = frac23-frac4k3N_side pm frac8phi3pi","category":"page"},{"location":"grids/#OctaHEALPix-grid","page":"Grids","title":"OctaHEALPix grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"While the classic HEALPix grid is based on a dodecahedron, other choices for N_varphi and N_theta in the class of HEALPix grids will change the number of faces there are in zonal/meridional direction. With N_varphi = 4 and N_theta = 1 we obtain a HEALPix grid that is based on an octahedron, which has the convenient property that there are twice as many longitude points around the equator than there are latitude rings between the poles. This is a desirable for truncation as this matches the distances too, 2pi around the Equator versus pi between the poles. N_varphi = 6 N_theta = 2 or N_varphi = 8 N_theta = 3 are other possible choices for this, but also more complicated. See Górski, 2004[1] for further examples and visualizations of these grids.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"We call the N_varphi = 4 N_theta = 1 HEALPix grid the OctaHEALPix grid, which combines the equal-area property of the HEALPix grids with the octahedron that's also used in the OctahedralGaussianGrid or the OctahedralClenshawGrid. As N_theta = 1 there is no equatorial belt which simplifies the grid. The latitude of the j-th isolatitude ring on the OctaHEALPixGrid is defined by","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - fracj^2N^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"with j=1N, and similarly for the southern hemisphere by symmetry. On this grid N_side = N where N= nlat_half, the number of latitude rings on one hemisphere, Equator included, because each of the 4 basepixels spans from pole to pole and covers a quarter of the sphere. The longitudes with in-ring- index i = 14j are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2j(i - tfrac12)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and again, the southern hemisphere grid points are obtained by symmetry.","category":"page"},{"location":"grids/#Grid-cell-boundaries-2","page":"Grids","title":"Grid cell boundaries","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"Similar to the grid cell boundaries for the HEALPix grid, the OctaHEALPix grid's boundaries are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - frack^2N^2left(fracpi2phi_tright)^2 quad z = 1 - frack^2N^2left(fracpi2phi_t - piright)^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The 3N_side^2 in the denominator of the HEALPix grid came simply N^2 for the OctaHEALPix grid and there's no separate equation for the equatorial belt (which doesn't exist in the OctaHEALPix grid).","category":"page"},{"location":"grids/#References","page":"Grids","title":"References","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"[1]: Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976","category":"page"},{"location":"primitiveequation/#Primitive-equation-model","page":"Primitive equation model","title":"Primitive equation model","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The primitive equations are a hydrostatic approximation of the compressible Navier-Stokes equations for an ideal gas on a rotating sphere. We largely follow the idealised spectral dynamical core developed by GFDL[1] and documented therein[2].","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The primitive equations solved by SpeedyWeather.jl for relative vorticity zeta, divergence mathcalD, logarithm of surface pressure ln p_s, temperature T and specific humidity q are","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"beginaligned\nfracpartial zetapartial t = nabla times (mathbfmathcalP_mathbfu\n+ (f+zeta)mathbfu_perp - W(mathbfu) - R_dT_vnabla ln p_s) \nfracpartial mathcalDpartial t = nabla cdot (mathcalP_mathbfu\n+ (f+zeta)mathbfu_perp - W(mathbfu) - R_dT_vnabla ln p_s) - nabla^2(frac12(u^2 + v^2) + Phi) \nfracpartial ln p_spartial t = -frac1p_s nabla cdot int_0^p_s mathbfudp \nfracpartial Tpartial t = mathcalP_T -nablacdot(mathbfuT) + TmathcalD - W(T) + kappa T_v fracD ln pDt \nfracpartial qpartial t = mathcalP_q -nablacdot(mathbfuq) + qmathcalD - W(q)\nendaligned","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with velocity mathbfu = (uv), rotated velocity mathbfu_perp = (v-u), Coriolis parameter f, W the vertical advection operator, dry air gas constant R_d, virtual temperature T_v, geopotential Phi, pressure p, thermodynamic kappa = R_dc_p with c_p the heat capacity at constant pressure. Horizontal hyper diffusion of the form (-1)^n+1nunabla^2n with coefficient nu and power n is added for every variable that is advected, meaning zeta mathcalD T q, but left out here for clarity, see Horizontal diffusion.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The parameterizations for the tendencies of uvTq from physical processes are denoted as mathcalP_mathbfu = (mathcalP_u mathcalP_v) mathcalP_T mathcalP_q and are further described in the corresponding sections, see Parameterizations.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"SpeedyWeather.jl implements a PrimitiveWet and a PrimitiveDry dynamical core. For a dry atmosphere, we have q = 0 and the virtual temperature T_v = T equals the temperature (often called absolute to distinguish from the virtual temperature). The terms in the primitive equations and their discretizations are discussed in the following sections. ","category":"page"},{"location":"primitiveequation/#Virtual-temperature","page":"Primitive equation model","title":"Virtual temperature","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"info: In short: Virtual temperature\nVirtual temperature is the temperature dry air would need to have to be as light as moist air. It is used in the dynamical core to include the effect of humidity on the density while replacing density through the ideal gas law with temperature.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"We assume the atmosphere to be composed of two ideal gases: Dry air and water vapour. Given a specific humidity q both gases mix, their pressures p_d, p_w (d for dry, w for water vapour), and densities rho_d rho_w add in a given air parcel that has temperature T. The ideal gas law then holds for both gases","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"beginaligned\np_d = rho_d R_d T \np_w = rho_w R_w T \nendaligned","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with the respective specific gas constants R_d = Rm_d and R_w = Rm_w obtained from the univeral gas constant R divided by the molecular masses of the gas. The total pressure p in the air parcel is","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p = p_d + p_w = (rho_d R_d + rho_w R_w)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"We ultimately want to replace the density rho = rho_w + rho_d in the dynamical core, using the ideal gas law, with the temperature T, so that we never have to calculate the density explicitly. However, in order to not deal with two densities (dry air and water vapour) we would like to replace temperature with a virtual temperature that includes the effect of humidity on the density. So, whereever we use the ideal gas law to replace density with temperature, we would use the virtual temperature, which is a function of the absolute temperature and specific humidity, instead. A higher specific humidity in an air parcel lowers the density as water vapour is lighter than dry air. Consequently, the virtual temperature of moist air is higher than its absolute temperature because warmer air is lighter too at constant pressure. We therefore think of the virtual temperature as the temperature dry air would need to have to be as light as moist air.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Starting with the last equation, with some manipulation we can write the ideal gas law as total density rho times a gas constant times the virtual temperature that is supposed to be a function of absolute temperature, humidity and some constants","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p = (rho R_d + rho_w (R_w - R_d)) T = rho R_d (1 +\nfrac1 - tfracR_dR_wtfracR_dR_w fracrho_wrho_w + rho_d)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Now we identify","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"mu = frac1 - tfracR_dR_wtfracR_dR_w","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"as some constant that is positive for water vapour being lighter than dry air (tfracR_dR_w = tfracm_wm_d 1) and","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"q = fracrho_wrho_w + rho_d","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"as the specific humidity. Given temperature T and specific humidity q, we can therefore calculate the virtual temperature T_v as","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"T_v = (1 + mu q)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"For completeness we want to mention here that the above product, because it is a product of two variables qT has to be computed in grid-point space, see [Spectral Transform]. To obtain an approximation to the virtual temperature in spectral space without expensive transforms one can linearize","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"T_v = T + mu qbarT","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"With a global constant temperature barT, for example obtained from the l=m=0 mode, barT = T_00frac1sqrt4pi but depending on the normalization of the spherical harmonics that factor needs adjustment.","category":"page"},{"location":"primitiveequation/#Vertical-coordinates","page":"Primitive equation model","title":"Vertical coordinates","text":"","category":"section"},{"location":"primitiveequation/#General","page":"Primitive equation model","title":"General","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Let Psi(xyzt) ","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"SpeedyWeather.jl currently uses sigma coordinates for the vertical. ","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"sigma = fracpp_s","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p_k = sigma_kp_s","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Delta p_k = p_k+1 - p_k = Delta sigma_k p_s","category":"page"},{"location":"primitiveequation/#Geopotential","page":"Primitive equation model","title":"Geopotential","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"In the hydrostatic approximation the vertical momentum equation becomes","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial ppartial z = -rho g","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"meaning that the (negative) vertical pressure gradient is given by the density in that layer times the gravitational acceleration. The heavier the fluid the more the pressure will increase below. Inserting the ideal gas law","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial gzpartial p = -fracR_dT_vp","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with the geopotential Phi = gz we can write this in terms of the logarithm of pressure","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial Phipartial ln p = -R_dT_v","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Note that we use the Virtual temperature here as we replaced the density through the ideal gas law with temperature. Given a vertical temperature profile T_v and the (constant) surface geopotential Phi_s = gz_s where z_s is the orography, we can integrate this equation from the surface to the top to obtain Phi_k on every layer k. The surface is at k = N+tfrac12 (see Vertical coordinates) with N vertical levels. We can integrate the geopotential onto half levels as","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Phi_k-tfrac12 = Phi_k+tfrac12 + R_dT^v_k(ln p_k+12 - ln p_k-12)","category":"page"},{"location":"primitiveequation/#Surface-pressure-tendency","page":"Primitive equation model","title":"Surface pressure tendency","text":"","category":"section"},{"location":"primitiveequation/#Vertical-advection","page":"Primitive equation model","title":"Vertical advection","text":"","category":"section"},{"location":"primitiveequation/#Pressure-gradient-force","page":"Primitive equation model","title":"Pressure gradient force","text":"","category":"section"},{"location":"primitiveequation/#Temperature-equation","page":"Primitive equation model","title":"Temperature equation","text":"","category":"section"},{"location":"primitiveequation/#implicit_primitive","page":"Primitive equation model","title":"Semi-implicit time stepping","text":"","category":"section"},{"location":"primitiveequation/#Horizontal-diffusion","page":"Primitive equation model","title":"Horizontal diffusion","text":"","category":"section"},{"location":"primitiveequation/#Algorithm","page":"Primitive equation model","title":"Algorithm","text":"","category":"section"},{"location":"primitiveequation/#Scaled-primitive-equations","page":"Primitive equation model","title":"Scaled primitive equations","text":"","category":"section"},{"location":"primitiveequation/#References","page":"Primitive equation model","title":"References","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The Spectral Dynamical Core","category":"page"},{"location":"lowertriangularmatrices/#lowertriangularmatrices","page":"Submodule: LowerTriangularMatrices","title":"LowerTriangularMatrices","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"LowerTriangularMatrices 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.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"This module defines LowerTriangularMatrix, a lower triangular matrix, which in contrast to LinearAlgebra.LowerTriangular does not store the entries above the diagonal. SpeedyWeather.jl uses LowerTriangularMatrix which is defined as a subtype of AbstractMatrix to store the spherical harmonic coefficients (see Spectral packing). ","category":"page"},{"location":"lowertriangularmatrices/#Creation-of-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Creation of LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"A LowerTriangularMatrix can be created using zeros,ones,rand, or randn","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> using SpeedyWeather.LowerTriangularMatrices\n\njulia> L = rand(LowerTriangularMatrix{Float32},5,5)\n5×5 LowerTriangularMatrix{Float32}:\n 0.912744 0.0 0.0 0.0 0.0\n 0.0737592 0.230592 0.0 0.0 0.0\n 0.799679 0.0765255 0.888098 0.0 0.0\n 0.670835 0.997938 0.505276 0.492966 0.0\n 0.949321 0.193692 0.793623 0.152817 0.357968","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"or the undef initializor LowerTriangularMatrix{Float32}(undef,3,3). The element type is arbitrary though, you can use any type T too.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Alternatively, it can be created through conversion from Matrix, which drops the upper triangle entries and sets them to zero","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> M = rand(Float16,3,3)\n3×3 Matrix{Float16}:\n 0.2222 0.694 0.3452\n 0.2158 0.04443 0.274\n 0.9746 0.793 0.6294\n\njulia> LowerTriangularMatrix(M)\n3×3 LowerTriangularMatrix{Float16}:\n 0.2222 0.0 0.0\n 0.2158 0.04443 0.0\n 0.9746 0.793 0.6294","category":"page"},{"location":"lowertriangularmatrices/#Indexing-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Indexing LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"LowerTriangularMatrix supports two types of indexing: 1) by denoting two indices, column and row [l,m] or 2) by denoting a single index [lm]. The double index works as expected","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L\n3×3 LowerTriangularMatrix{Float16}:\n 0.1499 0.0 0.0\n 0.1177 0.478 0.0\n 0.1709 0.756 0.3223\n\njulia> L[2,2]\nFloat16(0.478)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"But the single index skips the zero entries in the upper triangle, i.e.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L[4]\nFloat16(0.478)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"which, important, is different from single indices of an AbstractMatrix","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> Matrix(L)[4]\nFloat16(0.0)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"In performance-critical code a single index should be used, as this directly maps to the index of the underlying data vector. The double index is somewhat slower as it first has to be converted to the corresponding single index.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Consequently, many loops in SpeedyWeather.jl are build with the following structure","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"n,m = size(L)\nij = 0\nfor j in 1:m\n for i in j:n\n ij += 1\n L[ij] = i+j\n end\nend","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"which loops over all lower triangle entries of L::LowerTriangularMatrix and the single index ij is simply counted up. However, one could also use [i,j] as indices in the loop body or to perform any calculation (i+j here). An iterator over all entries in the lower triangle can be created by","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"for ij in eachindex(L)\n # do something\nend","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"The setindex! functionality of matrixes will throw a BoundsError when trying to write into the upper triangle of a LowerTriangularMatrix, for example","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L[2,1] = 0 # valid index\n0\n\njulia> L[1,2] = 0 # invalid index in the upper triangle\nERROR: BoundsError: attempt to access 3×3 LowerTriangularMatrix{Float32} at index [1, 2]","category":"page"},{"location":"lowertriangularmatrices/#Linear-algebra-with-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Linear algebra with LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"The LowerTriangularMatrices module's main purpose is not linear algebra, and it's implementation may not be efficient, however, many operations work as expected","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L = rand(LowerTriangularMatrix{Float32},3,3)\n3×3 LowerTriangularMatrix{Float32}:\n 0.57649 0.0 0.0\n 0.348685 0.875371 0.0\n 0.881923 0.850552 0.998306\n\njulia> L + L\n3×3 LowerTriangularMatrix{Float32}:\n 1.15298 0.0 0.0\n 0.697371 1.75074 0.0\n 1.76385 1.7011 1.99661\n\njulia> L * L\n3×3 Matrix{Float32}:\n 0.332341 0.0 0.0\n 0.506243 0.766275 0.0\n 1.68542 1.59366 0.996616","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Note, however, that the latter includes a conversion to Matrix, which is true for many operations, including inv or \\. Hence when trying to do more sophisticated linear algebra with LowerTriangularMatrix we quickly leave lower triangular-land and go back to normal matrix-land.","category":"page"},{"location":"lowertriangularmatrices/#Function-and-type-index","page":"Submodule: LowerTriangularMatrices","title":"Function and type index","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Modules = [SpeedyWeather.LowerTriangularMatrices]","category":"page"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","text":"L = LowerTriangularMatrix{T}(v::Vector{T},m::Int,n::Int)\n\nA lower triangular matrix implementation that only stores the non-zero entries explicitly. L<:AbstractMatrix although in general we have L[i] != Matrix(L)[i], the former skips zero entries, tha latter includes them.\n\n\n\n\n\n","category":"type"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix-Union{Tuple{AbstractMatrix{T}}, Tuple{T}} where T","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","text":"L = LowerTriangularMatrix(M)\n\nCreate a LowerTriangularMatrix L from Matrix M by copying over the non-zero elements in M.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#Base.fill!-Union{Tuple{T}, Tuple{LowerTriangularMatrix{T}, Any}} where T","page":"Submodule: LowerTriangularMatrices","title":"Base.fill!","text":"fill!(L::LowerTriangularMatrix,x)\n\nFills the elements of L with x. Faster than fill!(::AbstractArray,x) as only the non-zero elements in L are assigned with x.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.eachharmonic-Tuple{LowerTriangularMatrix}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.eachharmonic","text":"unit_range = eachharmonic(L::LowerTriangular)\n\ncreates unit_range::UnitRange to loop over all non-zeros in a LowerTriangularMatrix L. Like eachindex but skips the upper triangle with zeros in L.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.eachharmonic-Tuple{Vararg{LowerTriangularMatrix}}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.eachharmonic","text":"unit_range = eachharmonic(Ls::LowerTriangularMatrix...)\n\ncreates unit_range::UnitRange to loop over all non-zeros in the LowerTriangularMatrices provided as arguments. Checks bounds first. All LowerTriangularMatrix's need to be of the same size. Like eachindex but skips the upper triangle with zeros in L.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.ij2k-Tuple{Integer, Integer, Integer}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.ij2k","text":"k = ij2k( i::Integer, # row index of matrix\n j::Integer, # column index of matrix\n m::Integer) # number of rows in matrix\n\nConverts the index pair i,j of an mxn LowerTriangularMatrix L to a single index k that indexes the same element in the corresponding vector that stores only the lower triangle (the non-zero entries) of L.\n\n\n\n\n\n","category":"method"},{"location":"conventions/#Style-and-convention-guide","page":"Style and convention guide","title":"Style and convention guide","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"In SpeedyWeather.jl we've been following the several conventions that are documented here.","category":"page"},{"location":"conventions/#Variable-naming","page":"Style and convention guide","title":"Variable naming","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"The prognostic variables in spectral space are called","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" vor # Vorticity of horizontal wind field\n div # Divergence of horizontal wind field\n temp # Absolute temperature [K]\n pres_surf # Logarithm of surface pressure [log(Pa)]\n humid # Specific humidity [g/kg]","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"their transforms into grid-point space get a _grid suffix, their tendencies a _tend suffix. Further derived diagnostic dynamic variables are","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" u\n v\n geopot\n ...","category":"page"},{"location":"conventions/#Preallocation","page":"Style and convention guide","title":"Preallocation","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"All arrays representing variables are preallocated and grouped into two structs","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" Prog::PrognosticVariables\n Diag::DiagnosticVariables","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"The Diag struct contains further structs which represent the grid-point transformations of the prognostic variables and their tendencies.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" gridvars::GridVariables\n tendencies::Tendencies\n ...","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Constant arrays are grouped into several structs","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Boundaries","category":"page"},{"location":"conventions/#Julian-conventions","page":"Style and convention guide","title":"Julian conventions","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"We follow Julia's style guide and highlight here some important aspects of it.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Bang (!) convention. A function func does not change its input arguments, however, func! does.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Hence, func! is often the in-place version of func, avoiding as much memory allocation as possible and often changing its first argument, e.g. func!(out,in) so that argument in is used to calculate out which has been preallocated before function call.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Number format flexibility. Numeric literals such as 2.0 or 1/3 are only used in the model setup","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"but avoided throughout the code to obtain a fully number format-flexible package using the number format NF as a compile-time variable throughout the code. This often leads to overly specific code whereas a Real would generally suffice. However, this is done to avoid any implicit type conversions.","category":"page"},{"location":"shallowwater/#Shallow-water-model","page":"Shallow water model","title":"Shallow water model","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The shallow water model describes the evolution of a 2D flow described by its velocity and an interface height that conceptually represents pressure. A divergent flow affects the interface height which in turn can impose a pressure gradient force onto the flow. The dynamics include advection, forces, dissipation, and continuity.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The following description of the shallow water model largely follows the idealized models with spectral dynamics developed at the Geophysical Fluid Dynamics Laboratory[1]: The Shallow Water Equations[2].","category":"page"},{"location":"shallowwater/#Shallow-water-equations","page":"Shallow water model","title":"Shallow water equations","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The shallow water equations of velocity mathbfu = (uv) and interface height eta (i.e. the deviation from the fluid's rest height H) are, formulated in terms of relative vorticity zeta = nabla times mathbfu, divergence mathcalD = nabla cdot mathbfu","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial zetapartial t + nabla cdot (mathbfu(zeta + f)) =\nnabla times mathbfF + (-1)^n+1nunabla^2nzeta \nfracpartial mathcalDpartial t - nabla times (mathbfu(zeta + f)) =\nnabla cdot mathbfF -nabla^2(tfrac12(u^2 + v^2) + geta) + (-1)^n+1nunabla^2nmathcalD \nfracpartial etapartial t + nabla cdot (mathbfuh) = F_eta\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"We denote timet, Coriolis parameter f, a forcing vector mathbfF = (F_uF_v), hyperdiffusion (-1)^n+1 nu nabla^2n (n is the hyperdiffusion order, see Horizontal diffusion), gravitational acceleration g, dynamic layer thickness h, and a forcing for the interface height F_eta. In the shallow water model the dynamics layer thickness h is","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"h = eta + H - H_b","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"that is, the layer thickness at rest H plus the interface height eta minus orography H_b.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"In the shallow water system the flow can be described through uv or zetamathcalD which are related through the stream function Psi and the velocity potential Phi (which is zero in the Barotropic vorticity equation).","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nzeta = nabla^2 Psi \nmathcalD = nabla^2 Phi \nmathbfu = nabla^perp Psi + nabla Phi\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"With nabla^perp being the rotated gradient operator, in cartesian coordinates xy: nabla^perp = (-partial_y partial_x). See Derivatives in spherical coordinates for further details. Especially because the inversion of the Laplacian and the gradients of Psi Phi can be computed in a single pass, see U,V from vorticity and divergence.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The divergence/curl of the vorticity flux mathbfu(zeta + f) are combined with the divergence/curl of the forcing vector mathbfF, as","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\n- nabla cdot (mathbfu(zeta + f)) + nabla times mathbfF =\nnabla times (mathbfF + mathbfu_perp(zeta + f)) \nnabla times (mathbfu(zeta + f)) + nabla cdot mathbfF =\nnabla cdot (mathbfF + mathbfu_perp(zeta + f))\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"equivalently to how this is done in the Barotropic vorticity equation with mathbfu_perp = (v-u).","category":"page"},{"location":"shallowwater/#Algorithm","page":"Shallow water model","title":"Algorithm","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"0. Start with initial conditions of relative vorticity zeta_lm, divergence D_lm, and interface height eta_lm in spectral space and transform this model state to grid-point space:","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Invert the Laplacian of zeta_lm to obtain the stream function Psi_lm in spectral space\nInvert the Laplacian of D_lm to obtain the velocity potential Phi_lm in spectral space\nobtain velocities U_lm = (cos(theta)u)_lm V_lm = (cos(theta)v)_lm from nabla^perpPsi_lm + nablaPhi_lm\nTransform velocities U_lm, V_lm to grid-point space UV\nUnscale the cos(theta) factor to obtain uv\nTransform zeta_lm, D_lm, eta_lm to zeta D eta in grid-point space","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Now loop over","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Compute the forcing vector mathbfF = (F_uF_v) for u and v\nMultiply uv with zeta+f in grid-point space\nAdd A = F_u + v(zeta + f) and B = F_v - u(zeta + f)\nTransform these vector components to spectral space A_lm, B_lm\nCompute the curl of (AB)_lm in spectral space which is the tendency of zeta_lm\nCompute the divergence of (AB)_lm in spectral space which is the tendency of mathcalD_lm\nCompute the kinetic energy frac12(u^2 + v^2) and transform to spectral space\nAdd to the kinetic energy the \"geopotential\" geta_lm in spectral space to obtain the Bernoulli potential\nTake the Laplacian of the Bernoulli potential and subtract from the divergence tendency\nCompute the volume fluxes uhvh in grid-point space via h = eta + H - H_b\nTransform to spectral space and take the divergence for -nabla cdot (mathbfuh) which is the tendency for eta\nAdd possibly forcing F_eta for eta in spectral space\nCorrect the tendencies following the semi-implicit time integration to prevent fast gravity waves from causing numerical instabilities\nCompute the horizontal diffusion based on the zetamathcalD tendencies\nCompute a leapfrog time step as described in Time integration with a Robert-Asselin and Williams filter\nTransform the new spectral state of zeta_lm, mathcalD_lm, eta_lm to grid-point uvzetamathcalDeta as described in 0.\nPossibly do some output\nRepeat from 1.","category":"page"},{"location":"shallowwater/#implicit_swm","page":"Shallow water model","title":"Semi-implicit time integration","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Probably the biggest advantage of a spectral model is its ability to solve (parts of) the equations implicitly a low computational cost. The reason is that a linear operator can be easily inverted in spectral space, removing the necessity to solve large equation systems. An operation like Psi = nabla^-2zeta in grid-point space is costly because it requires a global communication, coupling all grid points. In spectral space nabla^2 is a diagonal operator, meaning that there is no communication between harmonics and its inversion is therefore easily done on a mode-by-mode basis of the harmonics.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"This can be made use of when facing time stepping constraints with explicit schemes, where ridiculuously small time steps to resolve fast waves would otherwise result in a horribly slow simulation. In the shallow water system there are gravity waves that propagate at a wave speed of sqrtgH (typically 300m/s), which, in order to not violate the CFL criterion for explicit time stepping, would need to be resolved. Therefore, treating the terms that are responsible for gravity waves implicitly would remove that time stepping constraint and allows us to run the simulation at the time step needed to resolve the advective motion of the atmosphere, which is usually one or two orders of magnitude longer than gravity waves.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"In the following we will describe how the semi implicit time integration can be combined with the Leapfrog time stepping and the Robert-Asselin and Williams filter for a large increase in numerical stability with gravity waves. Let V_i be the model state of all prognostic variables at time step i, the leapfrog time stepping is then","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"fracV_i+1 - V_i-12Delta t = N(V_i)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"with the right-hand side operator N evaluated at the current time step i. Now the idea is to split the terms in N into non-linear terms that are evaluated explicitly in N_E and into the linear terms N_I, solved implicitly, that are responsible for the gravity waves. We could already assume to evaluate N_I at i+1, but in fact, we can introduce alpha in 01 so that for alpha=0 we use i-1 (i.e. explicit), for alpha=12 it is centred implicit tfrac12N_I(V_i-1) + tfrac12N_I(V_i+1), and for alpha=1 a fully backwards scheme N_I(V_i+1) evaluated at i+1.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"fracV_i+1 - V_i-12Delta t = N_E(V_i) + alpha N_I(V_i+1) + (1-alpha)N_I(V_i-1)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Let delta V = tfracV_i+1 - V_i-12Delta t be the tendency we need for the Leapfrog time stepping. Introducing xi = 2alphaDelta t we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta V = N_E(V_i) + N_I(V_i-1) + xi N_I(delta V)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"because N_I is a linear operator. This is done so that we can solve for delta V by inverting N_I, but let us gather the other terms as G first.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"G = N_E(V_i) + N_I(V_i-1) = N(V_i) + N_I(V_i-1 - V_i)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"For the shallow water equations we will only make use of the last formulation, meaning we first evaluate the whole right-hand side N(V_i) at the current time step as we would do with fully explicit time stepping but then add the implicit terms N_I(V_i-1 - V_i) afterwards to move those terms from i to i-1. Note that we could also directly evaluate the implicit terms at i-1 as it is suggested in the previous formulation N_E(V_i) + N_I(V_i-1), the result would be the same. But in general it can be more efficient to do it one or the other way, and in fact it is also possible to combine both ways. This will be discussed in the semi-implicit time stepping for the primitive equations.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"We can now implicitly solve for delta V by","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta V = (1-xi N_I)^-1G","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"So what is N_I? In the shallow water system the gravity waves are caused by","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial mathcalDpartial t = -gnabla^2eta \nfracpartial etapartial t = -HmathcalD\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"which is a linearization of the equations around a state of rest with uniform constant layer thickness h = H. The continuity equation with the -nabla(mathbfuh) term, for example, is linearized to -nabla(mathbfuH) = -HmathcalD. The divergence and continuity equations can now be written following the delta V = G + xi N_I(delta V) formulation from above as a coupled system (The vorticity equation is zero for the linear gravity wave equation in the shallow water equations, hence no semi-implicit correction has to be made to the vorticity tendency).","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\ndelta mathcalD = G_mathcalD - xi g nabla^2 delta eta \ndelta eta = G_mathcaleta - xi H deltamathcalD\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"with","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nG_mathcalD = N_mathcalD - xi g nabla^2 (eta_i-1 - eta_i) \nG_mathcaleta = N_eta - xi H (mathcalD_i-1 - mathcalD_i)\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Inserting the second equation into the first, we can first solve for delta mathcalD, and then for delta eta. Reminder that we do this in spectral space to every harmonic independently, so the Laplace operator nabla^2 = -l(l+1) takes the form of its eigenvalue -l(l+1) (normalized to unit sphere, as are the scaled shallow water equations) and its inversion is therefore just the inversion of this scalar.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta D = fracG_mathcalD - xi gnabla^2 G_eta1 - xi^2 H nabla^2 = S^-1(G_mathcalD - xi gnabla^2 G_eta) ","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Where the last formulation just makes it clear that S = 1 - xi^2 H nabla^2 is the operator to be inverted. delta eta is then obtained via insertion as written above. Equivalently, by adding a superscript l for every degree of the spherical harmonics, we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta mathcalD^l = fracG_mathcalD^l + xi g l(l+1) G_eta^l1 + xi^2 H l(l+1)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The idea of the semi-implicit time stepping is now as follows:","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Evaluate the right-hand side explicitly at time step i to obtain the explicit, preliminary tendencies N_mathcalDN_eta (and N_zeta without a need for semi-implicit correction)\nMove the implicit terms from i to i-1 when calculating G_mathcalD G_eta\nSolve for delta mathcalD, the new, corrected tendency for divergence.\nWith delta mathcalD obtain delta eta, the new, corrected tendency for eta.\nApply horizontal diffusion as a correction to N_zeta delta mathcalD as outlined in Horizontal diffusion.\nLeapfrog with tendencies that have been corrected for both semi-implicit and diffusion.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Some notes on the semi-implicit time stepping","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The inversion of the semi-implicit time stepping depends on delta t, that means every time the time step changes, the inversion has to be recalculated.\nYou may choose alpha = 12 to dampen gravity waves but initialisation shocks still usually kick off many gravity waves that propagate around the sphere for many days.\nWith increasing alpha 12 these waves are also slowed down, such that for alpha = 1 they quickly disappear in several hours.\nUsing the scaled shallow water equations the time step delta t has to be the scaled time step tildeDelta t = delta tR which is divided by the radius R. Then we use the normalized eigenvalues -l(l+1) which also omit the 1R^2 scaling, see scaled shallow water equations for more details.","category":"page"},{"location":"shallowwater/#scaled_swm","page":"Shallow water model","title":"Scaled shallow water equations","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Similar to the scaled barotropic vorticity equations, SpeedyWeather.jl scales in the shallow water equations. The vorticity and the divergence equation are scaled with R^2, the radius of the sphere squared, but the continuity equation is scaled with R. We also combine the vorticity flux and forcing into a single divergence/curl operation as mentioned in Shallow water equations above","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial tildezetapartial tildet =\ntildenabla times (tildemathbfF + mathbfu_perp(tildezeta + tildef)) +\n(-1)^n+1tildenutildenabla^2ntildezeta \nfracpartial tildemathcalDpartial tildet =\ntildenabla cdot (tildemathbfF + mathbfu_perp(tildezeta + tildef)) -\ntildenabla^2left(tfrac12(u^2 + v^2) + geta right) +\n(-1)^n+1tildenutildenabla^2ntildemathcalD \nfracpartial etapartial tildet =\n- tildenabla cdot (mathbfuh) + tildeF_eta\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"As in the scaled barotropic vorticity equations, one needs to scale the time step, the Coriolis force, the forcing and the diffusion coefficient, but then enjoys the luxury of working with dimensionless gradient operators. As before, SpeedyWeather.jl will scale vorticity and divergence just before the model integration starts and unscale them upon completion and for output. In the semi-implicit time integration we solve an equation that also has to be scaled. It is with radius squared scaling (because it is the tendency for the divergence equation which is also scaled with R^2)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"R^2 delta D = R^2fracG_mathcalD - xi gnabla^2 G_eta1 - xi^2 H nabla^2","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"As G_eta is only scaled with R we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"tildedelta D = fractildeG_mathcalD - tildexi gtildenabla^2 tildeG_eta1 - tildexi^2 H tildenabla^2","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The R^2 normalizes the Laplace operator in the numerator, but using the scaled G_eta we also scale xi (which is convenient, because the time step within is the one we use anyway). The denominator S does not actually change because xi^2nabla^2 = tildexi^2tildenabla^2 as xi^2 is scaled with 1R^2, but the Laplace operator with R^2. So overall we just have to use the scaled time step tildeDelta t and normalized eigenvalues for tildenabla^2.","category":"page"},{"location":"shallowwater/#References","page":"Shallow water model","title":"References","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The Shallow Water Equations.","category":"page"},{"location":"extending/#New-model-setups","page":"Extending SpeedyWeather","title":"New model setups","text":"","category":"section"},{"location":"extending/","page":"Extending SpeedyWeather","title":"Extending SpeedyWeather","text":"more to come...","category":"page"},{"location":"spectral_transform/#Spherical-Harmonic-Transform","page":"Spherical harmonic transform","title":"Spherical Harmonic Transform","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The following sections outline the implementation of the spherical harmonic transform (in short spectral transform) between the coefficients of the spherical harmonics (the spectral space) and the grid space which can be any of the Implemented grids as defined by RingGrids. This includes the classical full Gaussian grid, a regular longitude-latitude grid called the full Clenshaw grid (FullClenshawGrid), ECMWF's octahedral Gaussian grid[Malardel2016], and HEALPix grids[Gorski2004]. SpeedyWeather.jl's spectral transform module SpeedyTransforms is grid-flexible and can be used with any of these, see Grids.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: SpeedyTransforms is a module too!\nSpeedyTransform is the underlying module that SpeedyWeather imports to transform between spectral and grid-point space, which also implements Derivatives in spherical coordinates. You can use this module independently of SpeedyWeather for spectral transforms, see SpeedyTransforms.","category":"page"},{"location":"spectral_transform/#Inspiration","page":"Spherical harmonic transform","title":"Inspiration","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral transform implemented by SpeedyWeather.jl follows largely Justin Willmert's CMB.jl and SphericalHarmonicTransforms.jl package and makes use of AssociatedLegendrePolynomials.jl and FFTW.jl for the Fourier transform. Justin described his work in a Blog series [Willmert2020].","category":"page"},{"location":"spectral_transform/#Spherical-harmonics","page":"Spherical harmonic transform","title":"Spherical harmonics","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spherical harmonics Y_lm of degree l and order m over the longitude phi = (02pi) and colatitudes theta = (-pi2pi2), are","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Y_lm(phi theta) = lambda_l^m(sintheta) e^imphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with lambda_l^m being the pre-normalized associated Legendre polynomials, and e^imphi are the complex exponentials (the Fourier modes). Together they form a set of orthogonal basis functions on the sphere. For an interactive visualisation of the spherical harmonics, see here.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: Latitudes versus colatitudes\nThe implementation of the spectral transforms in SpeedyWeather.jl uses colatitudes theta = (0pi) (0 at the north pole) but the dynamical core uses latitudes theta = (-pi2pi2) (pi2 at the north pole). Note: We may also use latitudes in the spherical harmonic transform in the future for consistency. ","category":"page"},{"location":"spectral_transform/#synthesis","page":"Spherical harmonic transform","title":"Synthesis (spectral to grid)","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The synthesis (or inverse transform) takes the spectral coefficients a_lm and transforms them to grid-point values f(phitheta) (for the sake of simplicity first regarded as continuous). The synthesis is a linear combination of the spherical harmonics Y_lm with non-zero coefficients.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"f(phitheta) = sum_l=0^infty sum_m=-l^l a_lm Y_lm(phitheta)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"We obtain an approximation with a finite set of a_lm by truncating the series in both degree l and order m somehow. Most commonly, a triangular truncation is applied, such that all degrees after l = l_max are discarded. Triangular because the retained array of the coefficients a_lm looks like a triangle. Other truncations like rhomboidal have been studied[Daley78] but are rarely used since. Choosing l_max also constrains m_max and determines the (horizontal) spectral resolution. In SpeedyWeather.jl this resolution as chosen as trunc when creating the SpectralGrid.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For f being a real-valued there is a symmetry","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"a_l-m = (-1)^m a^*_l+m","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"meaning that the coefficients at -m and m are the same, but the sign of the real and imaginary component can be flipped, as denoted with the (-1)^m and the complex conjugate a_lm^*. As we are only dealing with real-valued fields anyway, we therefore never have to store the negative orders -m and end up with a lower triangular matrix of size (l_max+1) times (m_max+1) or technically (T+1)^2 where T is the truncation trunc. One is added here because the degree l and order m use 0-based indexing but sizes (and so is Julia's indexing) are 1-based.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For correctness we want to mention here that vector quantities require one more degree l due to the recurrence relation in the Meridional derivative. Hence for practical reasons all spectral fields are represented as a lower triangular matrix of size (m_max + 2) times (m_max +1). And the scalar quantities would just not make use of that last degree, and its entries would be simply zero. We will, however, for the following sections ignore this and only discuss it again in Meridional derivative.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Another consequence of the symmetry mentioned above is that the zonal harmonics, meaning a_lm=0 have no imaginary component. Because these harmonics are zonally constant, a non-zero imaginary component would rotate them around the Earth's axis, which, well, doesn't actually change a real-valued field. ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Following the notation of [Willmert2020] we can therefore write the truncated synthesis as","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"f(phitheta) = sum_l=0^l_max sum_m=0^l (2-delta_m0) a_lm Y_lm(phitheta)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The (2-delta_m0) factor using the Kronecker delta is used here because of the symmetry we have to count both the m-m order pairs (hence the 2) except for the zonal harmonics which do not have a pair.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Another symmetry arises from the fact that the spherical harmonics are either symmetric or anti-symmetric around the Equator. There is an even/odd combination of degrees and orders so that the sign flips like a checkerboard","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Y_lm(phipi-theta) = (-1)^l+mY_lm(phiphi)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This means that one only has to compute the Legendre polynomials for one hemisphere and the other one follows with this equality.","category":"page"},{"location":"spectral_transform/#analysis","page":"Spherical harmonic transform","title":"Analysis (grid to spectral)","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Starting in grid-point space we can transform a field f(lambdatheta) into the spectral space of the spherical harmonics by","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"a_lm = int_0^2pi int_0^pi f(phitheta) Y_lm(phitheta) sin theta dtheta dphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Note that this notation again uses colatitudes theta, for latitudes the sintheta becomes a costheta and the bounds have to be changed accordingly to (-fracpi2fracpi2). A discretization with N grid points at location (phi_itheta_i), indexed by i can be written as [Willmert2020]","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"hata_lm = sum_i f(phi_itheta_i) Y_lm(phi_itheta_i) sin theta_i Deltatheta Deltaphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The hat on a just means that it is an approximation, or an estimate of the true a_lm approx hata_lm. We can essentially make use of the same symmetries as already discussed in Synthesis. Splitting into the Fourier modes e^imphi and the Legendre polynomials lambda_l^m(costheta) (which are defined over -11 so the costheta argument maps them to colatitudes) we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"hata_lm = sum_j left sum_i f(phi_itheta_j) e^-imphi_i right lambda_lm(theta_j) sin theta_j Deltatheta Deltaphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"So the term in brackets can be separated out as long as the latitude theta_j is constant, which motivates us to restrict the spectral transform to grids with iso-latitude rings, see Grids. Furthermore, this term can be written as a fast Fourier transform, if the phi_i are equally spaced on the latitude ring j. Note that the in-ring index i can depend on the ring index j, so that one can have reduced grids, which have fewer grid points towards the poles, for example. Also the Legendre polynomials only have to be computed for the colatitudes theta_j (and in fact only one hemisphere, due to the north-south symmetry discussed in the Synthesis). It is therefore practical and efficient to design a spectral transform implementation for ring grids, but there is no need to hardcode a specific grid.","category":"page"},{"location":"spectral_transform/#Spectral-packing","page":"Spherical harmonic transform","title":"Spectral packing","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Spectral packing is the way how the coefficients a_lm of the spherical harmonics of a given spectral field are stored in an array. SpeedyWeather.jl uses the conventional spectral packing of degree l and order m as illustrated in the following image (Cyp, CC BY-SA 3.0, via Wikimedia Commons)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Every row represents an order l geq 0, starting from l=0 at the top. Every column represents an order m geq 0, starting from m=0 on the left. The coefficients of these spherical harmonics are directly mapped into a matrix a_lm as ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":" m \nl a_00 \n a_10 a_11 \n a_20 a_12 a_22 \n a_30 a_13 a_23 a_33","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which is consistently extended for higher degrees and orders. Consequently, all spectral fields are lower-triangular matrices with complex entries. The upper triangle excluding the diagonal are zero. Note that internally vector fields include an additional degree, such that l_max = m_max + 1 (see Derivatives in spherical coordinates for more information). The harmonics with a_l0 (the first column) are also called zonal harmonics as they are constant with longitude phi. The harmonics with a_ll (the main diagonal) are also called sectoral harmonics as they essentially split the sphere into 2l sectors in longitude phi without a zero-crossing in latitude.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For correctness it is mentioned here that SpeedyWeather.jl uses a LowerTriangularMatrix type to store the spherical harmonic coefficients. By doing so, the upper triangle is actually not explicitly stored and the data technically unravelled into a vector, but this is hidden as much as possible from the user. For more details see LowerTriangularMatrices.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: Array indices\nFor a spectral field a note that due to Julia's 1-based indexing the coefficient a_lm is obtained via a[l+1,m+1]. Alternatively, we may index over 1-based l,m but a comment is usually added for clarification.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Fortran SPEEDY does not use the same spectral packing as SpeedyWeather.jl. The alternative packing lm therein uses l=m and m=l-m as summarized in the following table.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"degree l order m l=m m=l-m\n0 0 0 0\n1 0 0 1\n1 1 1 0\n2 0 0 2\n2 1 1 1\n2 2 2 0\n3 0 0 3\n... ... ... ...","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This alternative packing uses the top-left triangle of a coefficient matrix, and the degrees and orders from above are stored at the following indices","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":" m \nl a_00 a_10 a_20 a_30\n a_11 a_21 a_31 \n a_22 a_32 \n a_33 ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This spectral packing is not used in SpeedyWeather.jl but illustrated here for completeness and comparison with Fortran SPEEDY.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"SpeedyWeather.jl uses triangular truncation such that only spherical harmonics with l leq l_max and m leq m_max are explicitly represented. This is usually described as Tm_max, with l_max = m_max (although in vector quantities require one more degree l in the recursion relation of meridional gradients). For example, T31 is the spectral resolution with l_max = m_max = 31. Note that the degree l and order m are mathematically 0-based, such that the corresponding coefficient matrix is of size 32x32.","category":"page"},{"location":"spectral_transform/#Available-horizontal-resolutions","page":"Spherical harmonic transform","title":"Available horizontal resolutions","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Technically, SpeedyWeather.jl supports arbitrarily chosen resolution parameter trunc when creating the SpectralGrid that refers to the highest non-zero degree l_max that is resolved in spectral space. SpeedyWeather.jl will always try to choose an easily-Fourier transformable[FFT] size of the grid, but as we use FFTW.jl there is quite some flexibility without performance sacrifice. However, this has traditionally lead to typical resolutions that we also use for testing we therefore recommend to use. They are as follows with more details below","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"trunc nlon nlat Delta x\n31 (default) 96 48 400 km\n42 128 64 312 km\n63 192 96 216 km\n85 256 128 165 km\n127 384 192 112 km\n170 512 256 85 km\n255 768 384 58 km\n341 1024 512 43 km\n511 1536 768 29 km\n682 2048 1024 22 km\n1024 3072 1536 14 km\n1365 4092 2048 11 km","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Some remarks on this table","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This assumes the default quadratic truncation, you can always adapt the grid resolution via the dealiasing option, see Matching spectral and grid resolution\nnlat refers to the total number of latitude rings, see Grids. With non-Gaussian grids, nlat will be one one less, e.g. 47 instead of 48 rings.\nnlon is the number of longitude points on the Full Gaussian Grid, for other grids there will be at most these number of points around the Equator.\nDelta x is the horizontal resolution. For a spectral model there are many ways of estimating this[9]. We use here the square root of the average area a grid cell covers, see Effective grid resolution","category":"page"},{"location":"spectral_transform/#Effective-grid-resolution","page":"Spherical harmonic transform","title":"Effective grid resolution","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"There are many ways to estimate the effective grid resolution of spectral models[9]. Some of them are based on the wavelength a given spectral resolution allows to represent, others on the total number of real variables per area. However, as many atmospheric models do represent a considerable amount of physics on the grid (see Parameterizations) there is also a good argument to include the actual grid resolution into this estimate and not just the spectral resolution. We therefore use the average grid cell area to estimate the resolution","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Delta x = sqrtfrac4pi R^2N","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with N number of grid points over a sphere with radius R. However, we have to acknowledge that this usually gives higher resolution compared to other methods of estimating the effective resolution, see [Randall2021] for a discussion. You may therefore need to be careful to make claims that, e.g. trunc=85 can resolve the atmospheric dynamics at a scale of 165km.","category":"page"},{"location":"spectral_transform/#Derivatives-in-spherical-coordinates","page":"Spherical harmonic transform","title":"Derivatives in spherical coordinates","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Horizontal gradients in spherical coordinates are defined for a scalar field A and the latitudes theta and longitudes lambda as","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla A = left(frac1Rcosthetafracpartial Apartial lambda frac1Rfracpartial Apartial theta right)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"However, the divergence of a vector field mathbfu = (uv) includes additional cos(theta) scalings","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla cdot mathbfu = frac1Rcosthetafracpartial upartial lambda +\nfrac1Rcosthetafracpartial (v costheta)partial theta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"and similar for the curl","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla times mathbfu = frac1Rcosthetafracpartial vpartial lambda -\nfrac1Rcosthetafracpartial (u costheta)partial theta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The radius of the sphere (i.e. Earth) is R. The zonal gradient scales with 1cos(theta) as the longitudes converge towards the poles (note that theta describes latitudes here, definitions using colatitudes replace the cos with a sin.)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Starting with a spectral field of vorticity zeta and divergence mathcalD one can obtain stream function Psi and velocity potential Phi by inverting the Laplace operator nabla^2:","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Psi = nabla^-2zeta quad Phi = nabla^-2mathcalD","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The velocities uv are then obtained from (uv) = nabla^botPsi + nablaPhi following the definition from above and nabla^bot = (-R^-1partial_theta (Rcostheta)^-1partial_lambda)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nu = -frac1Rpartial_thetaPsi + frac1Rcosthetapartial_lambdaPhi \nv = +frac1Rpartial_thetaPhi + frac1Rcosthetapartial_lambdaPsi\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Alternatively, we can use the velocities U = ucostheta V = vcostheta, which we do as the meridional gradient for spherical harmonics is easier implemented with a costheta-scaling included, and because the divergence and curl in spherical coordinates evaluates the meridional gradient with UV and not uv. From uv we can return to zeta mathcalD via","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nzeta = frac1Rcosthetapartial_lambda v - frac1Rcosthetapartial_theta (u costheta) \nmathcalD = frac1Rcosthetapartial_lambda u + frac1Rcosthetapartial_theta (v costheta)\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Equivalently, we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nU = -fraccosthetaRpartial_thetaPsi + frac1Rpartial_lambdaPhi \nV = +fraccosthetaRpartial_thetaPhi + frac1Rpartial_lambdaPsi \nzeta = frac1Rpartial_lambda left( fracVcos^2theta right) -\nfraccosthetaRpartial_theta left( fracUcos^2theta right) \nmathcalD = frac1Rpartial_lambda left( fracUcos^2theta right) +\nfraccosthetaRpartial_theta left( fracVcos^2theta right)\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which is a more convenient formulation because of the way how the Meridional derivative is implemented with a recursion relation, actually computing costheta partial_theta rather than partial_theta directly. The remaining cosine scalings in (UV)*cos^-2theta are done in grid-point space. If one wanted to get back to zeta mathcalD this is how it would be done, but it is often more convenient to unscale UV on the fly in the spectral transform to obtain uv and then divide again by costheta when any gradient (or divergence or curl) is taken. This is because other terms would need that single costheta unscaling too before a gradient is taken. How the operators nabla nabla times nabla cdot can be implemented with spherical harmonics is presented in the following sections.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Also note that SpeedyWeather.jl scales the equations with the radius R (see Radius scaling) such that the divisions by R drop out in this last formulation too.","category":"page"},{"location":"spectral_transform/#Zonal-derivative","page":"Spherical harmonic transform","title":"Zonal derivative","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The zonal derivative of a scalar field Psi in spectral space is the zonal derivative of all its respective spherical harmonics Psi_lm(phitheta) (now we use phi for longitudes to avoid confusion with the Legendre polynomials lambda_lm)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"v_lm = frac1R cos(theta) fracpartialpartial phi left( lambda_l^m(costheta) e^imphi right) =\nfracimR cos(theta) lambda_l^m(costheta) e^imphi = fracimR cos(theta) Psi_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"So for every spectral harmonic, cos(theta)v_lm is obtained from Psi_lm via a multiplication with imR. Unscaling the cos(theta)-factor is done after transforming the spectral coefficients v_lm into grid-point space. As discussed in Radius scaling, SpeedyWeather.jl scales the stream function as tildePsi = R^-1Psi such that the division by radius R in the gradients can be omitted. The zonal derivative becomes therefore effectively for each spherical harmonic a scaling with its (imaginary) order im. The spherical harmonics are essentially just a Fourier transform in zonal direction and the derivative a multiplication with the respective wave number m times imaginary i.","category":"page"},{"location":"spectral_transform/#Meridional-derivative","page":"Spherical harmonic transform","title":"Meridional derivative","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The meridional derivative of the spherical harmonics is a derivative of the Legendre polynomials for which the following recursion relation applies[10],[11]","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"costheta fracdP_lmdtheta = -lepsilon_l+1mP_l+1m + (l+1)epsilon_lmP_l-1m","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with recursion factors","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"epsilon_lm = sqrtfracl^2-m^24l^2-1","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"In the following we use the example of obtaining the zonal velocity u from the stream function Psi, which is through the negative meridional gradient. For the meridional derivative itself the leading minus sign has to be omitted. Starting with the spectral expansion","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Psi(lambdatheta) = sum_lmPsi_lmP_lm(sintheta)e^imlambda","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"we multiply with -R^-1costhetapartial_theta to obtain","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"costhetaleft(-frac1Rpartial_thetaPsi right) = -frac1Rsum_lmPsi_lme^imlambdacosthetapartial_theta P_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"at which point the recursion from above can be applied. Collecting terms proportional to P_lm then yields","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"(cos(theta)u)_lm = -frac1R(-(l-1)epsilon_lmPsi_l-1m + (l+2)epsilon_l+1mPsi_l+1m)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"To obtain the coefficient of each spherical harmonic lm of the meridional gradient of a spectral field, two coefficients at l-1m and l+1m have to be combined. This means that the coefficient of a gradient ((costheta) u)_lm is a linear combination of the coefficients of one higher and one lower degree Psi_l+1mPsi_l-1m. As the coefficient Psi_lm with ml are zero, the sectoral harmonics (l=m) of the gradients are obtained from the first off-diagonal only. However, the l=l_max harmonics of the gradients require the l_max-1 as well as the l_max+1 harmonics. As a consequence vector quantities like velocity components uv require one more degree l than scalar quantities like vorticity[Bourke72]. However, for easier compatibility all spectral fields in SpeedyWeather.jl use one more degree l, but scalar quantities should not make use of it. Equivalently, the last degree l is set to zero before the time integration, which only advances scalar quantities.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"In SpeedyWeather.jl vector quantities like uv use therefore one more meridional mode than scalar quantities such as vorticity zeta or stream function Psi. The meridional derivative in SpeedyWeather.jl also omits the 1R-scaling as explained for the Zonal derivative and in Radius scaling.","category":"page"},{"location":"spectral_transform/#Divergence-and-curl-in-spherical-harmonics","page":"Spherical harmonic transform","title":"Divergence and curl in spherical harmonics","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The meridional gradient as described above can be applied to scalars, such as Psi and Phi in the conversion to velocities (uv) = nabla^botPsi + nablaPhi, however, the operators curl nabla times and divergence nabla cdot in spherical coordinates involve a costheta scaling before the meridional gradient is applied. How to translate this to spectral coefficients has to be derived separately[10],[11].","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral transform of vorticity zeta is","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"zeta_lm = frac12piint_-tfracpi2^tfracpi2int_0^2pi zeta(lambdatheta)\nP_lm(sintheta) e^imlambda dlambda costheta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Given that Rzeta = cos^-1partial_lambda v - cos^-1partial_theta (u costheta), we therefore have to evaluate a meridional integral of the form","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"int P_lm frac1cos theta partial_theta(u costheta)) cos theta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which can be solved through integration by parts. As ucostheta = 0 at theta = pm tfracpi2 only the integral","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"= -int partial_theta P_lm (u costheta) dtheta = -int costheta partial_theta P_lm\n(fracucostheta) costheta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"remains. Inserting the recurrence relation from the Meridional derivative turns this into","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"= -int left(-l epsilon_l+1mP_l+1m + (l+1)epsilon_lm P_l-1m right) (fracucostheta)\ncos theta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Now we expand (tfracucostheta) but only the lm harmonic will project ontoP_lm. Let u^* = ucos^-1theta v^* = vcos^-1theta we then have in total","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nRzeta_lm = imv^*_lm + (l+1)epsilon_lmu^*_l-1m - lepsilon_l+1mu^*_l+1m \nRD_lm = imu^*_lm - (l+1)epsilon_lmv^*_l-1m + lepsilon_l+1mv^*_l+1m \nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"And the divergence D is similar, but (uv) to (-vu). We have moved the scaling with the radius R directly into zetaD as further described in Radius scaling.","category":"page"},{"location":"spectral_transform/#Laplacian","page":"Spherical harmonic transform","title":"Laplacian","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral Laplacian is easily applied to the coefficients Psi_lm of a spectral field as the spherical harmonics are eigenfunctions of the Laplace operator nabla^2 in spherical coordinates with eigenvalues -l(l+1) divided by the radius squared R^2, i.e. nabla^2 Psi becomes tfrac-l(l+1)R^2Psi_lm in spectral space. For example, vorticity zeta and streamfunction Psi are related by zeta = nabla^2Psi in the barotropic vorticity model. Hence, in spectral space this is equivalent for every spectral mode of degree l and order m to","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"zeta_lm = frac-l(l+1)R^2Psi_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This can be easily inverted to obtain the stream function Psi from vorticity zeta instead. In order to avoid division by zero, we set Psi_00 here, given that the stream function is only defined up to a constant anyway.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nPsi_lm = fracR^2-l(l+1)zeta_lm quad foralllm 0\nPsi_00 = 0\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"See also Horizontal diffusion and Normalization of diffusion.","category":"page"},{"location":"spectral_transform/#U,V-from-vorticity-and-divergence","page":"Spherical harmonic transform","title":"U,V from vorticity and divergence","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"After having discussed the zonal and meridional derivatives with spherical harmonics as well as the Laplace operator, we can derive the conversion from vorticity zeta and divergence D (which are prognostic variables) to U=ucostheta V=vcostheta. Both are linear operations that act either solely on a given harmonic (the zonal gradient and the Laplace operator) or are linear combinations between one lower and one higher degree l (the meridional gradient). It is therefore computationally more efficient to compute UV directly from zetaD instead of calculating stream function and velocity potential first. In total we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nU_lm = -fraciml(l+1)(RD)_lm + fracepsilon_l+1ml+1(Rzeta)_l+1m -\nfracepsilon_lml(Rzeta)_l-1m \nV_lm = -fraciml(l+1)(Rzeta)_lm - fracepsilon_l+1ml+1(RD)_l+1m +\nfracepsilon_lml(RD)_l-1m \nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"We have moved the scaling with the radius R directly into zetaD as further described in Radius scaling.","category":"page"},{"location":"spectral_transform/#References","page":"Spherical harmonic transform","title":"References","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Malardel2016]: Malardel S, Wedi N, Deconinck W, Diamantakis M, Kühnlein C, Mozdzynski G, Hamrud M, Smolarkiewicz P. A new grid for the IFS. ECMWF newsletter. 2016;146(23-28):321. doi: 10.21957/zwdu9u5i","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Gorski2004]: Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Willmert2020]: Justin Willmert, 2020. justinwillmert.comIntroduction to Associated Legendre Polynomials (Legendre.jl Series, Part I)\nCalculating Legendre Polynomials (Legendre.jl Series, Part II)\nPre-normalizing Legendre Polynomials (Legendre.jl Series, Part III)\nMaintaining numerical accuracy in the Legendre recurrences (Legendre.jl Series, Part IV)\nIntroducing Legendre.jl (Legendre.jl Series, Part V)\nNumerical Accuracy of the Spherical Harmonic Recurrence Coefficient (Legendre.jl Series Addendum)\nNotes on Calculating the Spherical Harmonics\nMore Notes on Calculating the Spherical Harmonics: Analysis of maps to harmonic coefficients","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Daley78]: Roger Daley & Yvon Bourassa (1978) Rhomboidal versus triangular spherical harmonic truncation: Some verification statistics, Atmosphere-Ocean, 16:2, 187-196, DOI: 10.1080/07055900.1978.9649026","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Randall2021]: David Randall, 2021. An Introduction to Numerical Modeling of the Atmosphere, Chapter 22.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Durran2010]: Dale Durran, 2010. Numerical Methods for Fluid Dynamics, Springer. In particular section 6.2, 6.4.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[GFDL]: Geophysical Fluid Dynamics Laboratory, The barotropic vorticity equation.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[FFT]: Depending on the implementation of the Fast Fourier Transform (Cooley-Tukey algorithm, or or the Bluestein algorithm) easily Fourier-transformable can mean different things: Vectors of the length n that is a power of two, i.e. n = 2^i is certainly easily Fourier-transformable, but for most FFT implementations so are n = 2^i3^j5^k with ijk some positive integers. In fact, FFTW uses O(n log n) algorithms even for prime sizes.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Bourke72]: Bourke, W. An Efficient, One-Level, Primitive-Equation Spectral Model. Mon. Wea. Rev. 100, 683–689 (1972). doi:10.1175/1520-0493(1972)100<0683:AEOPSM>2.3.CO;2","category":"page"},{"location":"ringgrids/#RingGrids","page":"Submodule: RingGrids","title":"RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"RingGrids defines and exports the following grids:","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"full grids: FullClenshawGrid, FullGaussianGrid, FullHEALPix, and FullOctaHEALPix\nreduced grids: OctahedralGaussianGrid, OctahedralClenshawGrid, OctaHEALPixGrid and HEALPixGrid","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"note: What is a ring?\nWe 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.","category":"page"},{"location":"ringgrids/#Creating-data-on-a-RingGrid","page":"Submodule: RingGrids","title":"Creating data on a RingGrid","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Every grid in RingGrids has a grid.data field, which is a vector containing the data on the grid. The grid points 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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Data in a Matrix which follows this ring order can be put on a FullGaussianGrid like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"using SpeedyWeather.RingGrids\nmap = randn(Float32,8,4)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = FullGaussianGrid(map)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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. To reobtain the data from a grid, you can access its data field which returns a normal Vector","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid.data","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Which can be reshaped to reobtain map from above. Alternatively you can Matrix(grid) to do this in one step","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"map == Matrix(FullGaussianGrid(map))","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"You can also use zeros,ones,rand,randn to create a grid, whereby nlat_half, i.e. the number of latitude rings on one hemisphere, Equator included, is used as a resolution parameter and here as a second argument.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"nlat_half = 4\ngrid = randn(OctahedralGaussianGrid{Float16},nlat_half)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"and any element type T can be used for OctahedralGaussianGrid{T} and similar for other grid types.","category":"page"},{"location":"ringgrids/#Visualising-RingGrid-data","page":"Submodule: RingGrids","title":"Visualising RingGrid data","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"As only the full grids can be reshaped into a matrix, the underlying data structure of any AbstractGrid is a vector. As shown in the examples above, one can therefore inspect the data as if it was a vector. But as that data has, through its <:AbstractGrid type, all the geometric information available to plot it on a map, RingGrids also exports plot function, based on UnicodePlots' heatmap.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"nlat_half = 24\ngrid = randn(OctahedralGaussianGrid,nlat_half)\nplot(grid)","category":"page"},{"location":"ringgrids/#Indexing-RingGrids","page":"Submodule: RingGrids","title":"Indexing RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"All RingGrids 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 grid.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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_latdlonds for latitudes, longitudes per grid point not per ring)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = randn(OctahedralClenshawGrid,5)\nlatd = get_latd(grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Now we could calculate Coriolis and add it on the grid as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"rotation = 7.29e-5 # angular frequency of Earth's rotation [rad/s]\ncoriolis = 2rotation*sind.(latd) # vector of coriolis parameters per latitude ring\n\nrings = eachring(grid)\nfor (j,ring) in enumerate(rings)\n f = coriolis[j]\n for ij in ring\n grid[ij] += f\n end\nend","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"eachring creates a 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 grid-points like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"for ij in eachgridpoint(grid)\n grid[ij]\nend","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"or use eachindex instead.","category":"page"},{"location":"ringgrids/#Interpolation-on-RingGrids","page":"Submodule: RingGrids","title":"Interpolation on RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 grid to another or to request an interpolated value on some coordinates. Using our data on grid which is an OctahedralGaussianGrid from above we can use the interpolate function to get it onto a FullGaussianGrid (or any other grid for purpose)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = randn(OctahedralGaussianGrid{Float32},4)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(FullGaussianGrid,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 nlat_half directly as 2nd argument","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(FullGaussianGrid,6,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"So we got from an 8-ring OctahedralGaussianGrid{Float16} to a 12-ring FullGaussianGrid{Float64}, so it did a conversion from Float16 to Float64 on the fly too, because the default precision is Float64 unless specified. interpolate(FullGaussianGrid{Float16},6,grid) would have interpolated onto a grid with element type Float16.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"One can also interpolate onto a given coordinate ˚N, ˚E like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(30.0,10.0,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"we interpolated the data from grid onto 30˚N, 10˚E. To do this simultaneously for many coordinates they can be packed into a vector too","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate([30.0,40.0,50.0],[10.0,10.0,10.0],grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which returns the data on grid at 30˚N, 40˚N, 50˚N, and 10˚E respectively. Note how the interpolation here retains the element type of grid.","category":"page"},{"location":"ringgrids/#Performance-for-RingGrid-interpolation","page":"Submodule: RingGrids","title":"Performance for RingGrid interpolation","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Every time an interpolation like interpolate(30.0,10.0,grid) 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","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"output vector\ninput grid\ninterpolator","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"The output vector 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. The input grid 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 the data is coming on 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 grid 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 grid. So in the case you want to interpolate from grid A to grid B many times, you can just reuse the same interpolator. If you want to change the coordinates of the output grid but its total number of points remain constants 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 an want to interpolate between them","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_in = rand(HEALPixGrid,4)\ngrid_out = zeros(FullClenshawGrid,6)\ninterp = RingGrids.interpolator(grid_out,grid_in)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 of grid_in (and neither of grid_out which will be overwritten anyway). We can now do","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which is identical to interpolate(grid_out,grid_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)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_out = zeros(FullClenshawGrid{Float16},6);\ninterpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"and we have converted data from a HEALPixGrid{Float64} (Float64 is always default if not specified) to a FullClenshawGrid{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","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_in = randn(OctahedralGaussianGrid{Float16},24)\ngrid_out = zeros(FullClenshawGrid{Float16},24)\ninterp = RingGrids.interpolator(Float32,grid_out,grid_in)\ninterpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"npoints = 10 # number of coordinates to interpolate onto\ninterp = AnvilInterpolator(Float32,HEALPixGrid,24,npoints)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"with the first argument being the number format used during interpolation, then the input grid type, its resolution in terms of nlat_half and then the number of points to interpolate onto. 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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"latds = collect(0.0:5.0:45.0)\nlonds = collect(-10.0:2.0:8.0)\nnothing # hide","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"now we can update the locator inside our interpolator as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"RingGrids.update_locator!(interp,latds,londs)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"With data matching the input from above, a nlat_half=24 HEALPixGrid, and allocate 10-element output vector","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"output_vec = zeros(10)\ngrid_input = rand(HEALPixGrid,24)\nnothing # hide","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"we can use the interpolator as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate!(output_vec,grid_input,interp)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which is the approximately the same as doing it directly without creating an interpolator first and updating its locator","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(latds,londs,grid_input)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/#Anvil-interpolator","page":"Submodule: RingGrids","title":"Anvil interpolator","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":" 0..............1 # fraction of distance Δab between a,b\n |< Δab >|\n\n0^ a -------- o - b # anvil-shaped average of a,b,c,d at location x\n.Δy |\n. |\n.v x \n. |\n1 c ------ o ---- d\n\n |< Δcd >|\n 0...............1 # fraction of distance Δcd between c,d\n\n^ fraction of distance Δy between a-b and c-d.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/#Function-index","page":"Submodule: RingGrids","title":"Function index","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Modules = [SpeedyWeather.RingGrids]","category":"page"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractFullGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractFullGrid","text":"abstract type AbstractFullGrid{T} <: AbstractGrid{T} end\n\nAn AbstractFullGrid is a horizontal grid with a constant number of longitude points across latitude rings. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractGrid","text":"abstract type AbstractGrid{T} <: AbstractVector{T} end\n\nThe abstract supertype for all spatial grids on the sphere supported by SpeedyWeather.jl. Every new grid has to be of the form\n\nabstract type AbstractGridClass{T} <: AbstractGrid{T} end\nstruct MyNewGrid{T} <: AbstractGridClass{T}\n data::Vector{T} # all grid points unravelled into a vector\n nlat_half::Int # resolution: latitude rings on one hemisphere (Equator incl)\nend\n\nMyNewGrid should belong to a grid class like AbstractFullGrid, AbstractOctahedralGrid or AbstractHEALPixGrid (that already exist but you may introduce a new class of grids) that share certain features such as the number of longitude points per latitude ring and indexing, but may have different latitudes or offset rotations. Each new grid Grid (or grid class) then has to implement the following methods (as an example, see octahedral.jl)\n\nFundamental grid properties getnpoints # total number of grid points nlatodd # does the grid have an odd number of latitude rings? getnlat # total number of latitude rings getnlat_half # number of latitude rings on one hemisphere incl Equator\n\nIndexing getnlonmax # maximum number of longitudes points (at the Equator) getnlonperring # number of longitudes on ring j eachindexinring # a unit range that indexes all longitude points on a ring\n\nCoordinates getcolat # vector of colatitudes (radians) getcolatlon # vectors of colatitudes, longitudes (both radians)\n\nSpectral truncation truncationorder # linear, quadratic, cubic = 1,2,3 for grid gettruncation # spectral truncation given a grid resolution get_resolution # grid resolution given a spectral truncation\n\nQuadrature weights and solid angles getquadratureweights # = sinθ Δθ for grid points on ring j for meridional integration getsolidangle # = sinθ Δθ Δϕ, solid angle of grid points on ring j\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractHEALPixGrid","text":"abstract type AbstractHEALPixGrid{T} <: AbstractGrid{T} end\n\nAn AbstractHEALPixGrid is a horizontal grid similar to the standard HEALPixGrid, but different latitudes can be used, the default HEALPix latitudes or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractInterpolator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractInterpolator","text":"abstract type AbstractInterpolator{NF,G} end\n\nSupertype for Interpolators. Every Interpolator <: AbstractInterpolator is expected to have two fields,\n\ngeometry, which describes the grid G to interpolate from\nlocator, which locates the indices on G and their weights to interpolate onto a new grid.\n\nNF 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractLocator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractLocator","text":"AbstractLocator{NF}\n\nSupertype 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractOctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractOctaHEALPixGrid","text":"abstract type AbstractOctaHEALPixGrid{T} <: AbstractGrid{T} end\n\nAn AbstractOctaHEALPixGrid is a horizontal grid similar to the standard OctahedralGrid, but the number of points in the ring closest to the Poles starts from 4 instead of 20, and the longitude of the first point in each ring is shifted as in HEALPixGrid. Also, different latitudes can be used.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractOctahedralGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractOctahedralGrid","text":"abstract type AbstractOctahedralGrid{T} <: AbstractGrid{T} end\n\nAn AbstractOctahedralGrid is a horizontal grid with 16+4i longitude points on the latitude ring i starting with i=1 around the pole. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AnvilLocator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AnvilLocator","text":"AnvilLocator{NF<:AbstractFloat} <: AbtractLocator\n\nContains 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AnvilLocator-Union{Tuple{Integer}, Tuple{NF}} where NF<:AbstractFloat","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AnvilLocator","text":"L = AnvilLocator( ::Type{NF}, # number format used for the interpolation\n npoints::Integer # number of points to interpolate onto\n ) where {NF<:AbstractFloat}\n\nZero 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.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullClenshawGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullClenshawGrid","text":"G = FullClenshawGrid{T}\n\nA FullClenshawGrid is a regular latitude-longitude grid with an odd number of nlat equi-spaced latitudes, the central latitude ring is on the Equator. The same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullGaussianGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullGaussianGrid","text":"G = FullGaussianGrid{T}\n\nA full Gaussian grid is a regular latitude-longitude grid that uses nlat Gaussian latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullHEALPixGrid","text":"G = FullHEALPixGrid{T}\n\nA full HEALPix grid is a regular latitude-longitude grid that uses nlat latitudes from the HEALPix grid, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullOctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullOctaHEALPixGrid","text":"G = FullOctaHEALPixGrid{T}\n\nA full OctaHEALPix grid is a regular latitude-longitude grid that uses nlat OctaHEALPix latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.GridGeometry","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.GridGeometry","text":"GridGeometry{G<:AbstractGrid}\n\ncontains general precomputed arrays describing the grid of G.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.GridGeometry-Tuple{Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.GridGeometry","text":"G = GridGeometry( Grid::Type{<:AbstractGrid},\n nlat_half::Integer)\n\nPrecomputed arrays describing the geometry of the Grid with resolution nlat_half. Contains latitudes and longitudes of grid points, their ring index j and their unravelled indices ij.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.HEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.HEALPixGrid","text":"H = HEALPixGrid{T}\n\nA HEALPix grid with 12 faces, each nsidexnside grid points, each covering the same area. The number of latitude rings on one hemisphere (incl Equator) nlat_half is used as resolution parameter. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctaHEALPixGrid","text":"H = OctaHEALPixGrid{T}\n\nA OctaHEALPix grid with 4 base faces, each nlat_halfxnlat_half grid points, each covering the same area. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctahedralClenshawGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctahedralClenshawGrid","text":"G = OctahedralClenshawGrid{T}\n\nAn Octahedral Clenshaw grid that uses nlat equi-spaced latitudes. Like FullClenshawGrid, the central latitude ring is on the Equator. Like OctahedralGaussianGrid, the number of longitude points per latitude ring decreases towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctahedralGaussianGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctahedralGaussianGrid","text":"G = OctahedralGaussianGrid{T}\n\nAn Octahedral Gaussian grid that uses nlat Gaussian latitudes, but a decreasing number of longitude points per latitude ring towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Tuple{AbstractMatrix, OctaHEALPixGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(M::AbstractMatrix,\n G::OctaHEALPixGrid;\n quadrant_rotation=(0,1,2,3),\n matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),\n )\n\nSorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Tuple{AbstractMatrix, OctahedralClenshawGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(M::AbstractMatrix,\n G::OctahedralClenshawGrid;\n quadrant_rotation=(0,1,2,3),\n matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),\n )\n\nSorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Union{Tuple{Vararg{Tuple{AbstractMatrix{T}, OctaHEALPixGrid}}}, Tuple{T}} where T","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(MGs::Tuple{AbstractMatrix{T},OctaHEALPixGrid}...;kwargs...)\n\nLike Matrix!(::AbstractMatrix,::OctaHEALPixGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Union{Tuple{Vararg{Tuple{AbstractMatrix{T}, OctahedralClenshawGrid}}}, Tuple{T}} where T","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(MGs::Tuple{AbstractMatrix{T},OctahedralClenshawGrid}...;kwargs...)\n\nLike Matrix!(::AbstractMatrix,::OctahedralClenshawGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.anvil_average-NTuple{7, Any}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.anvil_average","text":"anvil_average(a, b, c, d, Δab, Δcd, Δy) -> Any\n\n\nThe 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:\n\n 0..............1 # fraction of distance Δab between a,b\n |< Δab >|\n\n 0^ a -------- o - b # anvil-shaped average of a,b,c,d at location x\n .Δy |\n . |\n .v x \n . |\n 1 c ------ o ---- d\n\n |< Δcd >|\n 0...............1 # fraction of distance Δcd between c,d\n\n^ fraction of distance Δy between a-b and c-d.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.average_on_poles-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, Vector{<:UnitRange{<:Integer}}}} where NF<:AbstractFloat","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.average_on_poles","text":"average_on_poles(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n rings::Vector{<:UnitRange{<:Integer}}\n) -> Tuple{Any, Any}\n\n\nComputes 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.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.average_on_poles-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, Vector{<:UnitRange{<:Integer}}}} where NF<:Integer","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.average_on_poles","text":"average_on_poles(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:Integer},\n rings::Vector{<:UnitRange{<:Integer}}\n) -> Tuple{Any, Any}\n\n\nMethod for A::Abstract{T<:Integer} which rounds the averaged values to return the same number format NF.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.each_index_in_ring-Union{Tuple{Grid}, Tuple{Grid, Integer}} where Grid<:SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.each_index_in_ring","text":"i = each_index_in_ring(grid,j)\n\nUnitRange i to access data on grid grid on ring j.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachgridpoint-Tuple{SpeedyWeather.RingGrids.AbstractGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachgridpoint","text":"ijs = eachgridpoint(grid)\n\nUnitRange ijs to access each grid point on grid grid.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachring-Tuple{SpeedyWeather.RingGrids.AbstractGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachring","text":"eachring(grid::SpeedyWeather.RingGrids.AbstractGrid) -> Any\n\n\nVector{UnitRange} rings to loop over every ring of grid grid and then each grid point per ring. To be used like\n\nrings = eachring(grid)\nfor ring in rings\n for ij in ring\n grid[ij]\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachring-Union{Tuple{Grid}, Tuple{Grid, Vararg{Grid}}} where Grid<:SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachring","text":"eachring(\n grid1::SpeedyWeather.RingGrids.AbstractGrid,\n grids::Grid<:SpeedyWeather.RingGrids.AbstractGrid...\n) -> Any\n\n\nSame as eachring(grid) but performs a bounds check to assess that all grids in grids are of same size.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.extrema_in-Tuple{Vector, Real, Real}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.extrema_in","text":"true/false = extrema_in(v::Vector,a::Real,b::Real)\n\nFor every element vᵢ in v does a<=vi<=b hold?\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.get_nlons-Tuple{Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.get_nlons","text":"get_nlons(\n Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid},\n nlat_half::Integer;\n both_hemispheres\n) -> Any\n\n\nReturns 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 both_hemisphere==false only the northern hemisphere (incl Equator) is returned.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.isdecreasing-Tuple{Vector}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.isdecreasing","text":"true/false = isdecreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly decreasing.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.isincreasing-Tuple{Vector}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.isincreasing","text":"true/false = isincreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly increasing.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_180-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_180","text":"i_new,j_new = rotate_matrix_indices_180(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s by 180˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_270-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_270","text":"i_new,j_new = rotate_matrix_indices_270(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s anti-clockwise by 270˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_90-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_90","text":"i_new,j_new = rotate_matrix_indices_90(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s anti-clockwise by 90˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.whichring-Tuple{Integer, Vector{UnitRange{Int64}}}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.whichring","text":"whichring(\n ij::Integer,\n rings::Vector{UnitRange{Int64}}\n) -> Int64\n\n\nObtain ring index j from gridpoint ij and Vector{UnitRange} describing rind indices as obtained from eachring(::Grid)\n\n\n\n\n\n","category":"method"},{"location":"#SpeedyWeather.jl-documentation","page":"Home","title":"SpeedyWeather.jl documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Welcome to the documentation for SpeedyWeather.jl a global atmospheric circulation model with simple parametrizations to represent physical processes such as clouds, precipitation and radiation.","category":"page"},{"location":"#Overview","page":"Home","title":"Overview","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"SpeedyWeather.jl is a global spectral model that uses a spherical harmonic transform to simulate the general circulation of the atmosphere. The prognostic variables used are vorticity, divergence, temperature, surface pressure and specific humidity. Simple parameterizations represent various climate processes: Radiation, clouds, precipitation, surface fluxes, among others.","category":"page"},{"location":"","page":"Home","title":"Home","text":"SpeedyWeather.jl defines ","category":"page"},{"location":"","page":"Home","title":"Home","text":"BarotropicModel for the 2D barotropic vorticity equation\nShallowWaterModel for the 2D shallow water equations\nPrimitiveDryModel for the 3D primitive equations without humidity\nPrimitiveWetModel for the 3D primitive equations with humidity","category":"page"},{"location":"","page":"Home","title":"Home","text":"and solves these equations in spherical coordinates as described in this documentation.","category":"page"},{"location":"#Manual-outline","page":"Home","title":"Manual outline","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"See the following pages of the documentation for more details","category":"page"},{"location":"","page":"Home","title":"Home","text":"Installation\nHow to run SpeedyWeather.jl\nSpherical harmonic transform\nGrids\nBarotropic model\nShallow water model\nPrimitive equation model\nParameterizations\nExtending SpeedyWeather\nNetCDF output","category":"page"},{"location":"","page":"Home","title":"Home","text":"and the submodules","category":"page"},{"location":"","page":"Home","title":"Home","text":"RingGrids\nLowerTriangularMatrices \nSpeedyTransforms","category":"page"},{"location":"","page":"Home","title":"Home","text":"and the original documentation by Molteni and Kucharski.","category":"page"},{"location":"#Developers","page":"Home","title":"Developers","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The development of SpeedyWeather.jl is lead by Milan Klöwer and current and past contributors include","category":"page"},{"location":"","page":"Home","title":"Home","text":"Tom Kimpson\nAlistair White\nMaximilian Gelbrecht\nDavid Meyer\nDaisuke Hotta\nNavid Constantinou","category":"page"},{"location":"","page":"Home","title":"Home","text":"Any contributions are always welcome!","category":"page"},{"location":"#Funding","page":"Home","title":"Funding","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"MK received funding by the European Research Council under Horizon 2020 within the ITHACA project, grant agreement number 741112 from 2021-2022. Since 2023 this project is also funded by the National Science Foundation NSF.","category":"page"},{"location":"time_integration/#Time-integration","page":"Time integration","title":"Time integration","text":"","category":"section"},{"location":"time_integration/","page":"Time integration","title":"Time integration","text":"SpeedyWeather.jl uses a leapfrog time scheme with a Robert's and Williams filter to dampen the computational mode and achieve 3rd order accuracy.","category":"page"},{"location":"time_integration/#Oscillation-equation","page":"Time integration","title":"Oscillation equation","text":"","category":"section"},{"location":"time_integration/","page":"Time integration","title":"Time integration","text":"fracdFdt = iomega F","category":"page"},{"location":"time_integration/#Implementation-details","page":"Time integration","title":"Implementation details","text":"","category":"section"}] +[{"location":"parameterizations/#parameterizations","page":"Parameterizations","title":"Parameterizations","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"This page describes the mathematical formulation of the parameterizations used in SpeedyWeather.jl to represent physical processes in the atmosphere. Every section is followed by a brief description of implementation details.","category":"page"},{"location":"parameterizations/#Convection","page":"Parameterizations","title":"Convection","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Large-scale-condensation","page":"Parameterizations","title":"Large-scale condensation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Clouds","page":"Parameterizations","title":"Clouds","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Short-wave-radiation","page":"Parameterizations","title":"Short-wave radiation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Long-wave-radiation","page":"Parameterizations","title":"Long-wave radiation","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Surface-fluxes-of-momentum-and-energy","page":"Parameterizations","title":"Surface fluxes of momentum and energy","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"parameterizations/#Vertical-diffusion","page":"Parameterizations","title":"Vertical diffusion","text":"","category":"section"},{"location":"parameterizations/","page":"Parameterizations","title":"Parameterizations","text":"more to come ...","category":"page"},{"location":"development/#Development-notes","page":"Development notes","title":"Development notes","text":"","category":"section"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To run tests, from the path of your local clone of the repository do:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project=. -e 'import Pkg; Pkg.test()'","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To install dependencies:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project -e 'import Pkg; Pkg.instantiate()`","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"then opening:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"you are able to using SpeedyWeather.","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"To generate the docs:","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"julia --project=docs -e 'import Pkg; Pkg.develop(path=\".\"); Pkg.instantiate()'\njulia --project=docs docs/make.jl","category":"page"},{"location":"development/","page":"Development notes","title":"Development notes","text":"If the docs are generated successfully, you view them by opening docs/build/index.html in your favorite browser.","category":"page"},{"location":"barotropic/#Barotropic-vorticity-model","page":"Barotropic model","title":"Barotropic vorticity model","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The barotropic vorticity model describes the evolution of a 2D non-divergent flow with velocity components mathbfu = (uv) through self-advection, forces and dissipation. Due to the non-divergent nature of the flow, it can be described by (the vertical component) of the relative vorticity zeta = nabla times mathbfu.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The dynamical core presented here to solve the barotropic vorticity equations largely follows the idealized models with spectral dynamics developed at the Geophysical Fluid Dynamics Laboratory[1]: A barotropic vorticity model[2].","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Many concepts of the Shallow water model and the Primitive equation model are similar, such that for example horizontal diffusion and the Time integration are only explained here.","category":"page"},{"location":"barotropic/#Barotropic-vorticity-equation","page":"Barotropic model","title":"Barotropic vorticity equation","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The barotropic vorticity equation is the prognostic equation that describes the time evolution of relative vorticity zeta with advection, Coriolis force, forcing and diffusion in a single global layer on the sphere.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fracpartial zetapartial t + nabla cdot (mathbfu(zeta + f)) =\nnabla times mathbfF + (-1)^n+1nunabla^2nzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"We denote timet, velocity vector mathbfu = (u v), Coriolis parameter f, and hyperdiffusion (-1)^n+1 nu nabla^2n zeta (n is the hyperdiffusion order, see Horizontal diffusion). We also include a forcing vector mathbfF = (F_uF_v) which acts on the zonal velocity u and the meridional velocity v and hence its curl nabla times mathbfF is a tendency for relative vorticity zeta.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Starting with some relative vorticity zeta, the Laplacian is inverted to obtain the stream function Psi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Psi = nabla^-2zeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The zonal velocity u and meridional velocity v are then the (negative) meridional gradient and zonal gradient of Psi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"beginaligned\nu = -frac1R fracpartial Psipartial theta \nv = frac1Rcos(theta) fracpartial Psipartial phi \nendaligned","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"which is described in Derivatives in spherical coordinates. Using u and v we can then advect the absolute vorticity zeta + f. In order to avoid to calculate both the curl and the divergence of a flux we rewrite the barotropic vorticity equation as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fracpartial zetapartial t =\nnabla times (mathbfF + mathbfu_perp(zeta + f)) + (-1)^n+1nunabla^2nzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with mathbfu_perp = (v-u) the rotated velocity vector, because -nablacdotmathbfu = nabla times mathbfu_perp. This is the form that is solved in the BarotropicModel, as outlined in the following section.","category":"page"},{"location":"barotropic/#Algorithm","page":"Barotropic model","title":"Algorithm","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"We briefly outline the algorithm that SpeedyWeather.jl uses in order to integrate the barotropic vorticity equation. As an initial step","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"0. Start with initial conditions of zeta_lm in spectral space and transform this model state to grid-point space:","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Invert the Laplacian of vorticity zeta_lm to obtain the stream function Psi_lm in spectral space\nobtain zonal velocity (cos(theta)u)_lm through a Meridional derivative\nobtain meridional velocity (cos(theta)v)_lm through a Zonal derivative\nTransform zonal and meridional velocity (cos(theta)u)_lm, (cos(theta)v)_lm to grid-point space\nUnscale the cos(theta) factor to obtain uv\nTransform zeta_lm to zeta in grid-point space","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Now loop over","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Compute the forcing vector mathbfF = (F_uF_v) for u and v\nMultiply uv with zeta+f in grid-point space\nAdd A = F_u + v(zeta + f) and B = F_v - u(zeta + f)\nTransform these vector components to spectral space A_lm, B_lm\nCompute the curl of (AB)_lm in spectral space which is the tendency of zeta_lm\nCompute the horizontal diffusion based on that tendency\nCompute a leapfrog time step as described in Time integration with a Robert-Asselin and Williams filter\nTransform the new spectral state of zeta_lm to grid-point uvzeta as described in 0.\nPossibly do some output\nRepeat from 1.","category":"page"},{"location":"barotropic/#diffusion","page":"Barotropic model","title":"Horizontal diffusion","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In SpeedyWeather.jl we use hyerdiffusion through an n-th power Laplacian (-1)^n+1nabla^2n (hyper when n1) which can be implemented as a multiplication of the spectral coefficients Psi_lm with (-l(l+1))^nR^-2n (see spectral Laplacian) It is therefore computationally not more expensive to apply hyperdiffusion over diffusion as the (-l(l+1))^nR^-2n can be precomputed. Note the sign change (-1)^n+1 here is such that the dissipative nature of the diffusion operator is retained for n odd and even.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In SpeedyWeather.jl the diffusion is applied implicitly. For that, consider a leapfrog scheme with time step Delta t of variable zeta to obtain from time steps i-1 and i, the next time step i+1","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t dzeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with dzeta being some tendency evaluated from zeta_i. Now we want to add a diffusion term (-1)^n+1nu nabla^2nzeta with coefficient nu, which however, is implicitly calculated from zeta_i+1, then","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t (dzeta + (-1)^n+1 nunabla^2nzeta_i+1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"As the application of (-1)^n+1nunabla^2n is, for every spectral mode, equivalent to a multiplication of a constant, we can rewrite this to","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = fraczeta_i-1 + 2Delta t dzeta1 - 2Delta (-1)^n+1nunabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and expand the numerator to","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"zeta_i+1 = zeta_i-1 + 2Delta t fracdzeta + (-1)^n+1 nunabla^2nzeta_i-11 - 2Delta t (-1)^n+1nu nabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Hence the diffusion can be applied implicitly by updating the tendency dzeta as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"dzeta to fracdzeta + (-1)^n+1nunabla^2nzeta_i-11 - 2Delta t nu nabla^2n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"which only depends on zeta_i-1. Now let D_textexplicit = (-1)^n+1nunabla^2n be the explicit part and D_textimplicit = 1 - (-1)^n+1 2Delta t nunabla^2n the implicit part. Both parts can be precomputed and are D_textimplicit = 1 - 2Delta t nunabla^2n the implicit part. Both parts can be precomputed and are only an element-wise multiplication in spectral space. For every spectral harmonic lm we do","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"dzeta to D_textimplicit^-1(dzeta + D_textexplicitzeta_i-1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Hence 2 multiplications and 1 subtraction with precomputed constants. However, we will normalize the (hyper-)Laplacians as described in the following. This also will take care of the alternating sign such that the diffusion operation is dissipative regardless the power n.","category":"page"},{"location":"barotropic/#Normalization-of-diffusion","page":"Barotropic model","title":"Normalization of diffusion","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"In physics, the Laplace operator nabla^2 is often used to represent diffusion due to viscosity in a fluid or diffusion that needs to be added to retain numerical stability. In both cases, the coefficient is nu of units textm^2texts^-1 and the full operator reads as nu nabla^2 with units (textm^2texts^-1)(textm^-2) = texts^-1. This motivates us to normalize the Laplace operator by a constant of units textm^-2 and the coefficient by its inverse such that it becomes a damping timescale of unit texts^-1. Given the application in spectral space we decide to normalize by the largest eigenvalue -l_textmax(l_textmax+1) such that all entries in the discrete spectral Laplace operator are in 01. This also has the effect that the alternating sign drops out, such that higher wavenumbers are always dampened and not amplified. The normalized coefficient nu^* = l_textmax(l_textmax+1)nu (always positive) is therefore reinterpreted as the (inverse) time scale at which the highest wavenumber is dampened to zero due to diffusion. Together we have ","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"D^textexplicit_lm = -nu^* fracl(l+1)l_textmax(l_textmax+1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and the hyper-Laplacian of power n follows as","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"D^textexplicitn_lm = -nu^* left(fracl(l+1)l_textmax(l_textmax+1)right)^n","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"and the implicit part is accordingly D^textimplicitn_lm = 1 - 2Delta t D^textexplicitn_lm. Note that the diffusion time scale nu^* is then also scaled by the radius, see next section.","category":"page"},{"location":"barotropic/#scaling","page":"Barotropic model","title":"Radius scaling","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Similar to a non-dimensionalization of the equations, SpeedyWeather.jl scales the barotropic vorticity equation with R^2 to obtain normalized gradient operators as follows. A scaling for vorticity zeta and stream function Psi is used that is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildezeta = zeta R tildePsi = Psi R^-1","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"This is also convenient as vorticity is often 10^-5text s^-1 in the atmosphere, but the streamfunction more like 10^5text m^2text s^-1 and so this scaling brings both closer to 1 with a typical radius of the Earth of 6371km. The inversion of the Laplacians in order to obtain Psi from zeta therefore becomes","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildezeta = tildenabla^2 tildePsi","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"where the dimensionless gradients simply omit the scaling with 1R, tildenabla = Rnabla. The Barotropic vorticity equation scaled with R^2 is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"partial_tildettildezeta + tildenabla cdot (mathbfu(tildezeta + tildef)) =\nnabla times tildemathbfF + (-1)^n+1tildenutildenabla^2ntildezeta","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"tildet = tR^-1, the scaled time t\nmathbfu = (uv), the velocity vector (no scaling applied)\ntildef = fR, the scaled Coriolis parameter f\ntildemathbfF = RmathbfF, the scaled forcing vector mathbfF\ntildenu = nu^* R, the scaled diffusion coefficient nu^*, which itself is normalized to a damping time scale, see Normalization of diffusion.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"So scaling with the radius squared means we can use dimensionless operators, however, this comes at the cost of needing to deal with both a time step in seconds as well as a scaled time step in seconds per meter, which can be confusing. Furthermore, some constants like Coriolis or the diffusion coefficient need to be scaled too during initialisation, which may be confusing too because values are not what users expect them to be. SpeedyWeather.jl follows the logic that the scaling to the prognostic variables is only applied just before the time integration and variables are unscaled for output and after the time integration finished. That way, the scaling is hidden as much as possible from the user. In hopefully many other cases it is clearly denoted that a variable or constant is scaled.","category":"page"},{"location":"barotropic/#leapfrog","page":"Barotropic model","title":"Time integration","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"SpeedyWeather.jl is based on the Leapfrog time integration, which, for relative vorticity zeta, is in its simplest form","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"fraczeta_i+1 - zeta_i-12Delta t = RHS(zeta_i)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"meaning we step from the previous time step i-1, leapfrogging over the current time stepi to the next time step i+1 by evaluating the tendencies on the right-hand side RHS at the current time step i. The time stepping is done in spectral space. Once the right-hand side RHS is evaluated, leapfrogging is a linear operation, meaning that its simply applied to every spectral coefficient zeta_lm as one would evaluate it on every grid point in grid-point models.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"For the Leapfrog time integration two time steps of the prognostic variables have to be stored, i-1 and i. Time step i is used to evaluate the tendencies which are then added to i-1 in a step that also swaps the indices for the next time step i to i-1 and i+1 to i, so that no additional memory than two time steps have to be stored at the same time.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The Leapfrog time integration has to be initialised with an Euler forward step in order to have a second time step i+1 available when starting from i to actually leapfrog over. SpeedyWeather.jl therefore does two initial time steps that are different from the leapfrog time steps that follow and that have been described above.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"an Euler forward step with Delta t2, then\none leapfrog time step with Delta t, then\nleapfrog with 2 Delta t till the end","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"This is particularly done in a way that after 2. we have t=0 at i-1 and t=Delta t at i available so that 3. can start the leapfrogging without any offset from the intuitive spacing 0Delta t 2Delta t 3Delta t. The following schematic can be useful","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":" time at step i-1 time at step i time step at i+1\nInitial conditions t = 0 \n1: Euler (T) quad t = 0 t=Delta t2 \n2: Leapfrog with Delta t t = 0 (T) quad t = Delta t2 t = Delta t\n3 to n: Leapfrog with 2Delta t t-Delta t (T) qquad quad quad t t+Delta t","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The time step that is used to evaluate the tendencies is denoted with (T). It is always the time step furthest in time that is available.","category":"page"},{"location":"barotropic/#Robert-Asselin-and-Williams-filter","page":"Barotropic model","title":"Robert-Asselin and Williams filter","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The standard leapfrog time integration is often combined with a Robert-Asselin filter[Robert66][Asselin72] to dampen a computational mode. The idea is to start with a standard leapfrog step to obtain the next time step i+1 but then to correct the current time step i by applying a filter which dampens the computational mode. The filter looks like a discrete Laplacian in time with a (1 -2 1) stencil, and so, maybe unsurprisingly, is efficient to filter out a \"grid-scale oscillation\" in time, aka the computational mode. Let v be the unfiltered variable and u be the filtered variable, F the right-hand side tendency, then the standard leapfrog step is","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"v_i+1 = u_i-1 + 2Delta tF(v_i)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Meaning we start with a filtered variable u at the previous time step i-1, evaluate the tendency F(v_i) based on the current time step i to obtain an unfiltered next time step v_i+1. We then filter the current time step i (which will become i-1 on the next iteration)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"u_i = v_i + fracnu2(v_i+1 - 2v_i + u_i-1)","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"by adding a discrete Laplacian with coefficient tfracnu2 to it, evaluated from the available filtered and unfiltered time steps centred around i: v_i-1 is not available anymore because it was overwritten by the filtering at the previous iteration, u_i u_i+1 are not filtered yet when applying the Laplacian. The filter parameter nu is typically chosen between 0.01-0.2, with stronger filtering for higher values.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"Williams[Williams2009] then proposed an additional filter step to regain accuracy that is otherwise lost with a strong Robert-Asselin filter[Amezcua2011][Williams2011]. Now let w be unfiltered, v be once filtered, and u twice filtered, then","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"beginaligned\nw_i+1 = u_i-1 + 2Delta tF(v_i) \nu_i = v_i + fracnualpha2(w_i+1 - 2v_i + u_i-1) \nv_i+1 = w_i+1 - fracnu(1-alpha)2(w_i+1 - 2v_i + u_i-1)\nendaligned","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"with the Williams filter parameter alpha in 051. For alpha=1 we're back with the Robert-Asselin filter (the first two lines).","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The Laplacian in the parentheses is often called a displacement, meaning that the filtered value is displaced (or corrected) in the direction of the two surrounding time steps. The Williams filter now also applies the same displacement, but in the opposite direction to the next time step i+1 as a correction step (line 3 above) for a once-filtered value v_i+1 which will then be twice-filtered by the Robert-Asselin filter on the next iteration. For more details see the referenced publications.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"The initial Euler step (see Time integration, Table) is not filtered. Both the the Robert-Asselin and Williams filter are then switched on for all following leapfrog time steps.","category":"page"},{"location":"barotropic/#References","page":"Barotropic model","title":"References","text":"","category":"section"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The barotropic vorticity equation.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Robert66]: Robert, André. “The Integration of a Low Order Spectral Form of the Primitive Meteorological Equations.” Journal of the Meteorological Society of Japan 44 (1966): 237-245.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Asselin72]: ASSELIN, R., 1972: Frequency Filter for Time Integrations. Mon. Wea. Rev., 100, 487–490, doi:10.1175/1520-0493(1972)100<0487:FFFTI>2.3.CO;2","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Williams2009]: Williams, P. D., 2009: A Proposed Modification to the Robert–Asselin Time Filter. Mon. Wea. Rev., 137, 2538–2546, 10.1175/2009MWR2724.1.","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Amezcua2011]: Amezcua, J., E. Kalnay, and P. D. Williams, 2011: The Effects of the RAW Filter on the Climatology and Forecast Skill of the SPEEDY Model. Mon. Wea. Rev., 139, 608–619, doi:10.1175/2010MWR3530.1. ","category":"page"},{"location":"barotropic/","page":"Barotropic model","title":"Barotropic model","text":"[Williams2011]: Williams, P. D., 2011: The RAW Filter: An Improvement to the Robert–Asselin Filter in Semi-Implicit Integrations. Mon. Wea. Rev., 139, 1996–2007, doi:10.1175/2010MWR3601.1. ","category":"page"},{"location":"installation/#Installation","page":"Installation","title":"Installation","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"SpeedyWeather.jl is registered in the Julia Registry. In most cases just open the Julia REPL and type","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia> using Pkg\njulia> Pkg.add(\"SpeedyWeather\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"or, equivalently, (] opens the package manager)","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia>] add SpeedyWeather","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"which will automatically install the latest release and all necessary dependencies. If you run into any troubles please raise an issue.","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"However, you may want to make use of the latest features, then install directly from the main branch with","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia> Pkg.add(url=\"https://github.com/SpeedyWeather/SpeedyWeather.jl\",rev=\"main\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"other branches than main can be similarly installed. You can also type, equivalently,","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"julia>] add https://github.com/SpeedyWeather/SpeedyWeather.jl#main","category":"page"},{"location":"installation/#Compatibility-with-Julia-versions","page":"Installation","title":"Compatibility with Julia versions","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"SpeedyWeather.jl usually lives on the latest minor release and/or its predecessor. At the moment (June 2023) this means ","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"Julia v1.8\nJulia v1.9","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"are supported, but we dropped the support of earlier versions.","category":"page"},{"location":"output/#NetCDF-output","page":"NetCDF output","title":"NetCDF output","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"SpeedyWeather.jl uses NetCDF to output the data of a simulation. The following describes the details of this and how to change the way in which the NetCDF output is written. There are many options to this available.","category":"page"},{"location":"output/#Accessing-the-NetCDF-output-writer","page":"NetCDF output","title":"Accessing the NetCDF output writer","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"The output writer is a component of every Model, i.e. BarotropicModel, ShallowWaterModel, PrimitiveDryModel and PrimitiveWetModel, hence a non-default output writer can be passed on as a keyword argument to the model constructor","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> using SpeedyWeather\njulia> spectral_grid = SpectralGrid()\njulia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry)\njulia> model = PrimitiveDryModel(;spectral_grid, output=my_output_writer)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"So after we have defined the grid through the SpectralGrid object we can use and change the implemented OutputWriter by passing on the following arguments","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, kwargs...)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"the spectral_grid has to be the first argument then the model type (Barotropic, ShallowWater, PrimitiveDry, PrimitiveWet) which helps the output writer to make default choices on which variables to output. However, we can also pass on further keyword arguments. So let's start with an example.","category":"page"},{"location":"output/#Example-1:-NetCDF-output-every-hour","page":"NetCDF output","title":"Example 1: NetCDF output every hour","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"If we want to increase the frequency of the output we can choose output_dt (default =6 in hours) like so","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, output_dt=1)\njulia> model = PrimitiveDryModel(;spectral_grid, output=my_output_writer)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"which will now output every hour. It is important to pass on the new output writer my_output_writer to the model constructor, otherwise it will not be part of your model and the default is used instead. Note that output_dt has to be understood as the minimum frequency or maximum output time step. Example, we run the model at a resolution of T85 and the time step is going to be 670s","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> spectral_grid = SpectralGrid(trunc=85)\njulia> time_stepper = Leapfrog(spectral_grid)\nLeapfrog{Float32}:\n...\n Δt_sec::Int64 = 670\n...","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This means that after 32 time steps 5h 57min and 20s will have passed where output will happen as the next time step would be >6h. The time axis of the NetCDF output will look like","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> using NCDatasets\njulia> ds = NCDataset(\"run_0001/output.nc\");\njulia> ds[\"time\"][:]\n5-element Vector{Dates.DateTime}:\n 2000-01-01T00:00:00\n 2000-01-01T05:57:20\n 2000-01-01T11:54:40\n 2000-01-01T17:52:00\n 2000-01-01T23:49:20\n\njulia> diff(ds[\"time\"][:])\n4-element Vector{Dates.Millisecond}:\n 21440000 milliseconds\n 21440000 milliseconds\n 21440000 milliseconds\n 21440000 milliseconds","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This is so that we don't interpolate in time during output to hit exactly every 6 hours, but at the same time have a constant spacing in time between output time steps.","category":"page"},{"location":"output/#Example-2:-Output-onto-a-higher/lower-resolution-grid","page":"NetCDF output","title":"Example 2: Output onto a higher/lower resolution grid","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Say we want to run the model at a given horizontal resolution but want to output on another resolution, the OutputWriter takes as argument output_Grid<:AbstractFullGrid and nlat_half::Int. So for example output_Grid=FullClenshawGrid and nlat_half=48 will always interpolate onto a regular 192x95 longitude-latitude grid of 1.875˚ resolution, regardless the grid and resolution used for the model integration.","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, output_Grid=FullClenshawGrid, nlat_half=48)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Note that by default the output is on the corresponding full of the grid used in the dynamical core so that interpolation only happens at most in the zonal direction as they share the location of the latitude rings. You can check this by","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> RingGrids.full_grid(OctahedralGaussianGrid)\nFullGaussianGrid","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"So the corresponding full grid of an OctahedralGaussianGrid is the FullGaussiangrid and the same resolution nlat_half is chosen by default in the output writer (which you can change though as shown above). Overview of the corresponding full grids","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Grid Corresponding full grid\nFullGaussianGrid FullGaussianGrid\nFullClenshawGrid FullClenshawGrid\nOctahadralGaussianGrid FullGaussianGrid\nOctahedralClensawhGrid FullClenshawGrid\nHEALPixGrid FullHEALPixGrid\nOctaHEALPixGrid FullOctaHEALPixGrid","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"The grids FullHEALPixGrid, FullOctaHEALPixGrid share the same latitude rings as their reduced grids, but have always as many longitude points as they are at most around the equator. These grids are not tested in the dynamical core (but you may use them experimentally) and mostly designed for output purposes.","category":"page"},{"location":"output/#Example-3:-Changing-the-output-path-or-identification","page":"NetCDF output","title":"Example 3: Changing the output path or identification","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"That's easy by passing on path=\"/my/favourite/path/\" and the folder run_* with * the identification of the run (that's the id keyword, which can be manually set but is also automatically determined as a number counting up depending on which folders already exist) will be created within.","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> path = pwd()\n\"/Users/milan\"\njulia> my_output_writer = OutputWriter(spectral_grid, PrimitiveDry, path=path)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"This folder must already exist. If you want to give your run a name/identification you can pass on id","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"julia> my_output_writer = OutputWriter(spectral_grid,PrimitiveDry,id=\"diffusion_test\");","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"which will be used instead of a 4 digit number like 0001, 0002 which is automatically determined if id is not provided. You will see the id of the run in the progress bar","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Weather is speedy: run diffusion_test 100%|███████████████████████| Time: 0:00:12 (19.20 years/day)","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"and the run folder, here run_diffusion_test, is also named accordingly","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"shell> ls\n...\nrun_diffusion_test\n...","category":"page"},{"location":"output/#Further-options","page":"NetCDF output","title":"Further options","text":"","category":"section"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"Further options are described in the OutputWriter docstring, (also accessible via julia>?OutputWriter for example). Note that some fields are actual options, but others are derived from the options you provided or are arrays/objects the output writer needs, but shouldn't be passed on by the user. The actual options are declared as [OPTION] in the following","category":"page"},{"location":"output/","page":"NetCDF output","title":"NetCDF output","text":"OutputWriter","category":"page"},{"location":"functions/#Function-and-type-index","page":"Function and type index","title":"Function and type index","text":"","category":"section"},{"location":"functions/","page":"Function and type index","title":"Function and type index","text":"Modules = [SpeedyWeather]","category":"page"},{"location":"functions/#SpeedyWeather.AbstractDevice","page":"Function and type index","title":"SpeedyWeather.AbstractDevice","text":"abstract type AbstractDevice\n\nSupertype of all devices SpeedyWeather.jl can ran on\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.BarotropicModel","page":"Function and type index","title":"SpeedyWeather.BarotropicModel","text":"The BarotropicModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\nforcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat\ninitial_conditions::SpeedyWeather.InitialConditions\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.CPUDevice","page":"Function and type index","title":"SpeedyWeather.CPUDevice","text":"CPUDevice <: AbstractDevice\n\nIndicates that SpeedyWeather.jl runs on a single CPU \n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Clock","page":"Function and type index","title":"SpeedyWeather.Clock","text":"Clock struct keeps track of the model time, how many days to integrate for and how many time steps this takes\n\ntime::Dates.DateTime: current model time\nn_days::Float64: number of days to integrate for, set in run!(::Simulation)\nn_timesteps::Int64: number of time steps to integrate for, set in initialize!(::Clock,::TimeStepper)\n\n.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ColumnVariables","page":"Function and type index","title":"SpeedyWeather.ColumnVariables","text":"Mutable struct that contains all prognostic (copies thereof) and diagnostic variables in a single column needed to evaluate the physical parametrizations. For now the struct is mutable as we will reuse the struct to iterate over horizontal grid points. Every column vector has nlev entries, from [1] at the top to [end] at the lowermost model level at the planetary boundary layer.\n\nnlev::Int64\nnband::Int64\nn_stratosphere_levels::Int64\njring::Int64\nlond::AbstractFloat\nlatd::AbstractFloat\nu::Vector{NF} where NF<:AbstractFloat\nv::Vector{NF} where NF<:AbstractFloat\ntemp::Vector{NF} where NF<:AbstractFloat\nhumid::Vector{NF} where NF<:AbstractFloat\nln_pres::Vector{NF} where NF<:AbstractFloat\npres::Vector{NF} where NF<:AbstractFloat\nu_tend::Vector{NF} where NF<:AbstractFloat\nv_tend::Vector{NF} where NF<:AbstractFloat\ntemp_tend::Vector{NF} where NF<:AbstractFloat\nhumid_tend::Vector{NF} where NF<:AbstractFloat\ngeopot::Vector{NF} where NF<:AbstractFloat\nflux_u_upward::Vector{NF} where NF<:AbstractFloat\nflux_u_downward::Vector{NF} where NF<:AbstractFloat\nflux_v_upward::Vector{NF} where NF<:AbstractFloat\nflux_v_downward::Vector{NF} where NF<:AbstractFloat\nflux_temp_upward::Vector{NF} where NF<:AbstractFloat\nflux_temp_downward::Vector{NF} where NF<:AbstractFloat\nflux_humid_upward::Vector{NF} where NF<:AbstractFloat\nflux_humid_downward::Vector{NF} where NF<:AbstractFloat\nsat_humid::Vector{NF} where NF<:AbstractFloat\nsat_vap_pres::Vector{NF} where NF<:AbstractFloat\ndry_static_energy::Vector{NF} where NF<:AbstractFloat\nmoist_static_energy::Vector{NF} where NF<:AbstractFloat\nhumid_half::Vector{NF} where NF<:AbstractFloat\nsat_humid_half::Vector{NF} where NF<:AbstractFloat\nsat_moist_static_energy::Vector{NF} where NF<:AbstractFloat\ndry_static_energy_half::Vector{NF} where NF<:AbstractFloat\nsat_moist_static_energy_half::Vector{NF} where NF<:AbstractFloat\nconditional_instability::Bool\nactivate_convection::Bool\ncloud_top::Int64\nexcess_humidity::AbstractFloat\ncloud_base_mass_flux::AbstractFloat\nprecip_convection::AbstractFloat\nnet_flux_humid::Vector{NF} where NF<:AbstractFloat\nnet_flux_dry_static_energy::Vector{NF} where NF<:AbstractFloat\nentrainment_profile::Vector{NF} where NF<:AbstractFloat\nprecip_large_scale::AbstractFloat\nwvi::Matrix{NF} where NF<:AbstractFloat\ntau2::Matrix{NF} where NF<:AbstractFloat\ndfabs::Vector{NF} where NF<:AbstractFloat\nfsfcd::AbstractFloat\nst4a::Matrix{NF} where NF<:AbstractFloat\nflux::Vector{NF} where NF<:AbstractFloat\nfsfcu::AbstractFloat\nts::AbstractFloat\nfsfc::AbstractFloat\nftop::AbstractFloat\nstratc::Vector{NF} where NF<:AbstractFloat\ntyear::AbstractFloat\ncsol::AbstractFloat\ntopsr::AbstractFloat\nfsol::AbstractFloat\nozupp::AbstractFloat\nozone::AbstractFloat\nzenit::AbstractFloat\nstratz::AbstractFloat\nalbsfc::AbstractFloat\nssrd::AbstractFloat\nssr::AbstractFloat\ntsr::AbstractFloat\ntend_t_rsw::Vector{NF} where NF<:AbstractFloat\nnorm_pres::AbstractFloat\nicltop::Int64\ncloudc::AbstractFloat\nclstr::AbstractFloat\nqcloud::AbstractFloat\nfmask::AbstractFloat\nrel_hum::Vector{NF} where NF<:AbstractFloat\ngrad_dry_static_energy::AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DeviceSetup","page":"Function and type index","title":"SpeedyWeather.DeviceSetup","text":"DeviceSetup{S<:AbstractDevice}\n\nHolds information about the device the model is running on and workgroup size. \n\ndevice::AbstractDevice: Device the model is running on \ndevice_KA::KernelAbstractions.Device: Device for use with KernelAbstractions\nn: workgroup size \n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DiagnosticVariables","page":"Function and type index","title":"SpeedyWeather.DiagnosticVariables","text":"DiagnosticVariables{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding the diagnostic variables.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DynamicsConstants","page":"Function and type index","title":"SpeedyWeather.DynamicsConstants","text":"Struct holding constants needed at runtime for the dynamical core in number format NF.\n\nradius::AbstractFloat: Radius of Planet [m]\nrotation::AbstractFloat: Angular frequency of Planet's rotation [1/s]\ngravity::AbstractFloat: Gravitational acceleration [m/s^2]\nlayer_thickness::AbstractFloat: shallow water layer thickness [m]\nR_dry::AbstractFloat: specific gas constant for dry air [J/kg/K]\nR_vapour::AbstractFloat: specific gas constant for water vapour [J/kg/K]\nμ_virt_temp::AbstractFloat: used in Tv = T(1+μq) for virt temp Tv(T,q) calculation\ncₚ::AbstractFloat: specific heat at constant pressure [J/K/kg]\nκ::AbstractFloat: = R_dry/cₚ, gas const for air over heat capacity\nwater_density::AbstractFloat: water density [kg/m³]\nf_coriolis::Vector{NF} where NF<:AbstractFloat: coriolis frequency 1/s = 2Ωsin(lat)radius\nσ_lnp_A::Vector{NF} where NF<:AbstractFloat: σ-related factor A needed for adiabatic terms\nσ_lnp_B::Vector{NF} where NF<:AbstractFloat: σ-related factor B needed for adiabatic terms\nΔp_geopot_half::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1) - ln(pk+1/2)), for half level geopotential\nΔp_geopot_full::Vector{NF} where NF<:AbstractFloat: = R*(ln(pk+1/2) - ln(pk)), for full level geopotential\ntemp_ref_profile::Vector{NF} where NF<:AbstractFloat: reference temperature profile\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.DynamicsConstants-Tuple{SpectralGrid, SpeedyWeather.AbstractPlanet, SpeedyWeather.AbstractAtmosphere, Geometry}","page":"Function and type index","title":"SpeedyWeather.DynamicsConstants","text":"DynamicsConstants(\n spectral_grid::SpectralGrid,\n planet::SpeedyWeather.AbstractPlanet,\n atmosphere::SpeedyWeather.AbstractAtmosphere,\n geometry::Geometry\n) -> Any\n\n\nGenerator function for a DynamicsConstants struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DynamicsVariables","page":"Function and type index","title":"SpeedyWeather.DynamicsVariables","text":"DynamicsVariables{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding intermediate quantities for the dynamics of a given layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Earth","page":"Function and type index","title":"SpeedyWeather.Earth","text":"Create a struct Earth<:AbstractPlanet, with the following physical/orbital characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are\n\nrotation::Float64: angular frequency of Earth's rotation [rad/s]\ngravity::Float64: gravitational acceleration [m/s^2]\ndaily_cycle::Bool: switch on/off daily cycle\nlength_of_day::Float64: [hrs] in a day\nseasonal_cycle::Bool: switch on/off seasonal cycle\nlength_of_year::Float64: [days] in a year\nequinox::Dates.DateTime: time of spring equinox (year irrelevant)\naxial_tilt::Float64: angle [˚] rotation axis tilt wrt to orbit\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthAtmosphere","page":"Function and type index","title":"SpeedyWeather.EarthAtmosphere","text":"Create a struct EarthAtmosphere<:AbstractPlanet, with the following physical/chemical characteristics. Note that radius is not part of it as this should be chosen in SpectralGrid. Keyword arguments are\n\nmol_mass_dry_air::Float64: molar mass of dry air [g/mol]\nmol_mass_vapour::Float64: molar mass of water vapour [g/mol]\ncₚ::Float64: specific heat at constant pressure [J/K/kg]\nR_gas::Float64: universal gas constant [J/K/mol]\nR_dry::Float64: specific gas constant for dry air [J/kg/K]\nR_vapour::Float64: specific gas constant for water vapour [J/kg/K]\nwater_density::Float64: water density [kg/m³]\nlatent_heat_condensation::Float64: latent heat of condensation [J/g] for consistency with specific humidity [g/Kg], also called alhc\nlatent_heat_sublimation::Float64: latent heat of sublimation [J/g], also called alhs\nstefan_boltzmann::Float64: stefan-Boltzmann constant [W/m²/K⁴]\nlapse_rate::Float64: moist adiabatic temperature lapse rate -dTdz [K/km]\ntemp_ref::Float64: absolute temperature at surface z=0 [K]\ntemp_top::Float64: absolute temperature in stratosphere [K]\nΔT_stratosphere::Float64: for stratospheric lapse rate [K] after Jablonowski\nσ_tropopause::Float64: start of the stratosphere in sigma coordinates\nσ_boundary_layer::Float64: top of the planetary boundary layer in sigma coordinates\nscale_height::Float64: scale height for pressure [km]\npres_ref::Float64: surface pressure [hPa]\nscale_height_humid::Float64: scale height for specific humidity [km]\nrelhumid_ref::Float64: relative humidity of near-surface air [1]\nwater_pres_ref::Float64: saturation water vapour pressure [Pa]\nlayer_thickness::Float64: layer thickness for the shallow water model [km]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthOrography","page":"Function and type index","title":"SpeedyWeather.EarthOrography","text":"Earth's orography read from file, with smoothing.\n\npath::String: path to the folder containing the orography file, pkg path default\nfile::String: filename of orography\nfile_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: Grid the orography file comes on\nscale::Float64: scale orography by a factor\nsmoothing::Bool: smooth the orography field?\nsmoothing_power::Float64: power of Laplacian for smoothing\nsmoothing_strength::Float64: highest degree l is multiplied by\nsmoothing_truncation::Int64: resolution of orography in spectral trunc\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.EarthOrography-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.EarthOrography","text":"EarthOrography(\n spectral_grid::SpectralGrid;\n kwargs...\n) -> Any\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Feedback","page":"Function and type index","title":"SpeedyWeather.Feedback","text":"Feedback() -> Feedback\nFeedback(verbose::Bool) -> Feedback\nFeedback(verbose::Bool, debug::Bool) -> Feedback\n\n\nGenerator function for a Feedback struct.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Feedback-2","page":"Function and type index","title":"SpeedyWeather.Feedback","text":"Feedback struct that contains options and object for command-line feedback like the progress meter.\n\nverbose::Bool: print feedback to REPL?\ndebug::Bool: check for NaRs in the prognostic variables\noutput::Bool: write a progress.txt file? State synced with OutputWriter.output\nid::Union{Int64, String}: identification of run, taken from ::OutputWriter\nrun_path::String: path to run folder, taken from ::OutputWriter\nprogress_meter::ProgressMeter.Progress: struct containing everything progress related\nprogress_txt::Union{Nothing, IOStream}: txt is a Nothing in case of no output\nnars_detected::Bool: did Infs/NaNs occur in the simulation?\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.GPUDevice","page":"Function and type index","title":"SpeedyWeather.GPUDevice","text":"GPUDevice <: AbstractDevice\n\nIndicates that SpeedyWeather.jl runs on a single GPU\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.GenLogisticCoefs","page":"Function and type index","title":"SpeedyWeather.GenLogisticCoefs","text":"Coefficients of the generalised logistic function to describe the vertical coordinate. Default coefficients A,K,C,Q,B,M,ν are fitted to the old L31 configuration at ECMWF.\n\nFollowing the notation of https://en.wikipedia.org/wiki/Generalisedlogisticfunction (Dec 15 2021).\n\nChange default parameters for more/fewer levels in the stratosphere vs troposphere vs boundary layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Geometry","page":"Function and type index","title":"SpeedyWeather.Geometry","text":"Construct Geometry struct containing parameters and arrays describing an iso-latitude grid <:AbstractGrid and the vertical levels. Pass on SpectralGrid to calculate the following fields\n\nspectral_grid::SpectralGrid: SpectralGrid that defines spectral and grid resolution\nGrid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: grid of the dynamical core\nnlat_half::Int64: resolution parameter nlat_half of Grid, # of latitudes on one hemisphere (incl Equator)\nnlon_max::Int64: maximum number of longitudes (at/around Equator)\nnlon::Int64: =nlon_max, same (used for compatibility), TODO: still needed?\nnlat::Int64: number of latitude rings\nnlev::Int64: number of vertical levels\nnpoints::Int64: total number of grid points\nradius::AbstractFloat: Planet's radius [m]\nlatd::Vector{Float64}: array of latitudes in degrees (90˚...-90˚)\nlond::Vector{Float64}: array of longitudes in degrees (0...360˚), empty for non-full grids\nlonds::Vector{NF} where NF<:AbstractFloat: longitude (-180˚...180˚) for each grid point in ring order\nlatds::Vector{NF} where NF<:AbstractFloat: latitude (-90˚...˚90) for each grid point in ring order\nsinlat::Vector{NF} where NF<:AbstractFloat: sin of latitudes\ncoslat::Vector{NF} where NF<:AbstractFloat: cos of latitudes\ncoslat⁻¹::Vector{NF} where NF<:AbstractFloat: = 1/cos(lat)\ncoslat²::Vector{NF} where NF<:AbstractFloat: = cos²(lat)\ncoslat⁻²::Vector{NF} where NF<:AbstractFloat: # = 1/cos²(lat)\nσ_levels_half::Vector{NF} where NF<:AbstractFloat: σ at half levels, σ_k+1/2\nσ_levels_full::Vector{NF} where NF<:AbstractFloat: σ at full levels, σₖ\nσ_levels_thick::Vector{NF} where NF<:AbstractFloat: σ level thicknesses, σₖ₊₁ - σₖ\nln_σ_levels_full::Vector{NF} where NF<:AbstractFloat: log of σ at full levels, include surface (σ=1) as last element\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Geometry-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.Geometry","text":"Geometry(spectral_grid::SpectralGrid) -> Any\n\n\nGenerator function for Geometry struct based on spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.GridVariables","page":"Function and type index","title":"SpeedyWeather.GridVariables","text":"GridVariables{NF<:AbstractFloat}\n\nStruct holding the prognostic spectral variables of a given layer in grid point space.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HeldSuarez","page":"Function and type index","title":"SpeedyWeather.HeldSuarez","text":"Struct that defines the temperature relaxation from Held and Suarez, 1996 BAMS\n\nnlat::Int64: number of latitude rings\nnlev::Int64: number of vertical levels\nσb::Float64: sigma coordinate below which faster surface relaxation is applied\nrelax_time_slow::Float64: time scale [hrs] for slow global relaxation\nrelax_time_fast::Float64: time scale [hrs] for faster tropical surface relaxation\nTmin::Float64: minimum equilibrium temperature [K]\nTmax::Float64: maximum equilibrium temperature [K]\nΔTy::Float64: meridional temperature gradient [K]\nΔθz::Float64: vertical temperature gradient [K]\nκ::Base.RefValue{NF} where NF<:AbstractFloat\np₀::Base.RefValue{NF} where NF<:AbstractFloat\ntemp_relax_freq::Matrix{NF} where NF<:AbstractFloat\ntemp_equil_a::Vector{NF} where NF<:AbstractFloat\ntemp_equil_b::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HeldSuarez-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.HeldSuarez","text":"HeldSuarez(SG::SpectralGrid; kwargs...) -> Any\n\n\ncreate a HeldSuarez temperature relaxation with arrays allocated given spectral_grid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.HyperDiffusion","page":"Function and type index","title":"SpeedyWeather.HyperDiffusion","text":"Struct for horizontal hyper diffusion of vor, div, temp; implicitly in spectral space with a power of the Laplacian (default=4) and the strength controlled by time_scale. Options exist to scale the diffusion by resolution, and adaptive depending on the current vorticity maximum to increase diffusion in active layers. Furthermore the power can be decreased above the tapering_σ to power_stratosphere (default 2). For Barotropic, ShallowWater, the default non-adaptive constant-time scale hyper diffusion is used. Options are\n\ntrunc::Int64: spectral resolution\nnlev::Int64: number of vertical levels\npower::Float64: power of Laplacian\ntime_scale::Float64: diffusion time scales [hrs]\nresolution_scaling::Float64: stronger diffusion with resolution? 0: constant with trunc, 1: (inverse) linear with trunc, etc\npower_stratosphere::Float64: different power for tropopause/stratosphere\ntapering_σ::Float64: linearly scale towards power_stratosphere above this σ\nadaptive::Bool: adaptive = higher diffusion for layers with higher vorticity levels.\nvor_max::Float64: above this (absolute) vorticity level [1/s], diffusion is increased\nadaptive_strength::Float64: increase strength above vor_max by this factor times max(abs(vor))/vor_max\n∇²ⁿ_2D::Vector\n∇²ⁿ_2D_implicit::Vector\n∇²ⁿ::Array{Vector{NF}, 1} where NF\n∇²ⁿ_implicit::Array{Vector{NF}, 1} where NF\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.HyperDiffusion-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.HyperDiffusion","text":"HyperDiffusion(\n spectral_grid::SpectralGrid;\n kwargs...\n) -> Any\n\n\nGenerator function based on the resolutin in spectral_grid. Passes on keyword arguments.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ImplicitPrimitiveEq","page":"Function and type index","title":"SpeedyWeather.ImplicitPrimitiveEq","text":"Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the primitive equation model.\n\ntrunc::Int64: spectral resolution\nnlev::Int64: number of vertical levels\nα::Float64: time-step coefficient: 0=explicit, 0.5=centred implicit, 1=backward implicit\ntemp_profile::Vector{NF} where NF<:AbstractFloat: vertical temperature profile, obtained from diagn\nξ::Base.RefValue{NF} where NF<:AbstractFloat: time step 2α*Δt packed in RefValue for mutability\nR::Matrix{NF} where NF<:AbstractFloat: divergence: operator for the geopotential calculation\nU::Vector{NF} where NF<:AbstractFloat: divergence: the -RdTₖ∇² term excl the eigenvalues from ∇² for divergence\nL::Matrix{NF} where NF<:AbstractFloat: temperature: operator for the TₖD + κTₖDlnps/Dt term\nW::Vector{NF} where NF<:AbstractFloat: pressure: vertical averaging of the -D̄ term in the log surface pres equation\nL0::Vector{NF} where NF<:AbstractFloat: components to construct L, 1/ 2Δσ\nL1::Matrix{NF} where NF<:AbstractFloat: vert advection term in the temperature equation (below+above)\nL2::Vector{NF} where NF<:AbstractFloat: factor in front of the divsumabove term\nL3::Matrix{NF} where NF<:AbstractFloat: sumabove operator itself\nL4::Vector{NF} where NF<:AbstractFloat: factor in front of div term in Dlnps/Dt\nS::Matrix{NF} where NF<:AbstractFloat: for every l the matrix to be inverted\nS⁻¹::Array{NF, 3} where NF<:AbstractFloat: combined inverted operator: S = 1 - ξ²(RL + UW)\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ImplicitPrimitiveEq-Tuple{SpectralGrid, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.ImplicitPrimitiveEq","text":"ImplicitPrimitiveEq(\n spectral_grid::SpectralGrid,\n kwargs...\n) -> Any\n\n\nGenerator using the resolution from SpectralGrid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ImplicitShallowWater","page":"Function and type index","title":"SpeedyWeather.ImplicitShallowWater","text":"Struct that holds various precomputed arrays for the semi-implicit correction to prevent gravity waves from amplifying in the shallow water model.\n\ntrunc::Int64\nα::Float64: coefficient for semi-implicit computations to filter gravity waves\nH::Base.RefValue{NF} where NF<:AbstractFloat\nξH::Base.RefValue{NF} where NF<:AbstractFloat\ng∇²::Vector{NF} where NF<:AbstractFloat\nξg∇²::Vector{NF} where NF<:AbstractFloat\nS⁻¹::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ImplicitShallowWater-Tuple{SpectralGrid, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.ImplicitShallowWater","text":"ImplicitShallowWater(\n spectral_grid::SpectralGrid,\n kwargs...\n) -> Any\n\n\nGenerator using the resolution from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.JablonowskiRelaxation","page":"Function and type index","title":"SpeedyWeather.JablonowskiRelaxation","text":"HeldSuarez-like temperature relaxation, but towards the Jablonowski temperature profile with increasing temperatures in the stratosphere.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.JablonowskiRelaxation-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.JablonowskiRelaxation","text":"JablonowskiRelaxation(SG::SpectralGrid; kwargs...) -> Any\n\n\ncreate a JablonowskiRelaxation temperature relaxation with arrays allocated given spectral_grid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Keepbits","page":"Function and type index","title":"SpeedyWeather.Keepbits","text":"Number of mantissa bits to keep for each prognostic variable when compressed for netCDF and .jld2 data output.\n\nu::Int64\nv::Int64\nvor::Int64\ndiv::Int64\ntemp::Int64\npres::Int64\nhumid::Int64\nprecip_cond::Int64\nprecip_conv::Int64\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Leapfrog","page":"Function and type index","title":"SpeedyWeather.Leapfrog","text":"Leapfrog time stepping defined by the following fields\n\ntrunc::Int64: spectral resolution (max degree of spherical harmonics)\nΔt_at_T31::Float64: time step in minutes for T31, scale linearly to trunc\nradius::Any: radius of sphere [m], used for scaling\nrobert_filter::Any: Robert (1966) time filter coefficeint to suppress comput. mode\nwilliams_filter::Any: Williams time filter (Amezcua 2011) coefficient for 3rd order acc\nΔt_sec::Int64: time step Δt [s] at specified resolution\nΔt::Any: time step Δt [s/m] at specified resolution, scaled by 1/radius\nΔt_hrs::Float64: convert time step Δt from minutes to hours\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Leapfrog-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.Leapfrog","text":"Leapfrog(spectral_grid::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function for a Leapfrog struct using spectral_grid for the resolution information.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.LinearDrag","page":"Function and type index","title":"SpeedyWeather.LinearDrag","text":"Linear boundary layer drag Following Held and Suarez, 1996 BAMS\n\nσb::Float64\ntime_scale::Float64\nnlev::Int64\ndrag_coefs::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.LinearDrag-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.LinearDrag","text":"LinearDrag(SG::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function using nlev from SG::SpectralGrid\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.MagnusCoefs","page":"Function and type index","title":"SpeedyWeather.MagnusCoefs","text":"Parameters for computing saturation vapour pressure using the August-Roche-Magnus formula,\n\neᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),\n\nwhere T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively.\n\ne₀::AbstractFloat: Saturation vapour pressure at 0°C [Pa]\nT₀::AbstractFloat: 0°C in Kelvin\nT₁::AbstractFloat\nT₂::AbstractFloat\nC₁::AbstractFloat\nC₂::AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoBoundaryLayerDrag","page":"Function and type index","title":"SpeedyWeather.NoBoundaryLayerDrag","text":"Concrete type that disables the boundary layer drag scheme.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoOrography","page":"Function and type index","title":"SpeedyWeather.NoOrography","text":"Orography with zero height in orography and zero surface geopotential geopot_surf.\n\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.NoOrography-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.NoOrography","text":"NoOrography(spectral_grid::SpectralGrid) -> NoOrography\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.OutputWriter","page":"Function and type index","title":"SpeedyWeather.OutputWriter","text":"NetCDF output writer. Contains all output options and auxiliary fields for output interpolation. To be initialised with OutputWriter(::SpectralGrid,::Type{<:ModelSetup},kwargs...) to pass on the resolution information and the model type which chooses which variables to output. Options include\n\nspectral_grid::SpectralGrid\noutput::Bool\npath::String: [OPTION] path to output folder, run_???? will be created within\nid::String: [OPTION] run identification number/string\nrun_path::String\nfilename::String: [OPTION] name of the output netcdf file\nwrite_restart::Bool: [OPTION] also write restart file if output==true?\npkg_version::VersionNumber\nstartdate::Dates.DateTime\noutput_dt::Float64: [OPTION] output frequency, time step [hrs]\noutput_dt_sec::Int64: actual output time step [sec]\noutput_vars::Vector{Symbol}: [OPTION] which variables to output, u, v, vor, div, pres, temp, humid\nmissing_value::Union{Float32, Float64}: [OPTION] missing value to be used in netcdf output\ncompression_level::Int64: [OPTION] lossless compression level; 1=low but fast, 9=high but slow\nkeepbits::SpeedyWeather.Keepbits: [OPTION] mantissa bits to keep for every variable\noutput_every_n_steps::Int64\ntimestep_counter::Int64\noutput_counter::Int64\nnetcdf_file::Union{Nothing, NetCDF.NcFile}\ninput_Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}\nas_matrix::Bool: [OPTION] sort grid points into a matrix (interpolation-free), for OctahedralClenshawGrid, OctaHEALPixGrid only\nquadrant_rotation::NTuple{4, Int64}\nmatrix_quadrant::NTuple{4, Tuple{Int64, Int64}}\noutput_Grid::Type{<:SpeedyWeather.RingGrids.AbstractFullGrid}: [OPTION] the grid used for output, full grids only\nnlat_half::Int64: [OPTION] the resolution of the output grid, default: same nlat_half as in the dynamical core\nnlon::Int64\nnlat::Int64\nnpoints::Int64\nnlev::Int64\ninterpolator::SpeedyWeather.RingGrids.AbstractInterpolator\nu::Matrix{NF} where NF<:Union{Float32, Float64}\nv::Matrix{NF} where NF<:Union{Float32, Float64}\nvor::Matrix{NF} where NF<:Union{Float32, Float64}\ndiv::Matrix{NF} where NF<:Union{Float32, Float64}\ntemp::Matrix{NF} where NF<:Union{Float32, Float64}\npres::Matrix{NF} where NF<:Union{Float32, Float64}\nhumid::Matrix{NF} where NF<:Union{Float32, Float64}\nprecip_cond::Matrix{NF} where NF<:Union{Float32, Float64}\nprecip_conv::Matrix{NF} where NF<:Union{Float32, Float64}\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.PrimitiveDryModel","page":"Function and type index","title":"SpeedyWeather.PrimitiveDryModel","text":"The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\nphysics::Bool\nboundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat\ntemperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat\nstatic_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.PrimitiveWetModel","page":"Function and type index","title":"SpeedyWeather.PrimitiveWetModel","text":"The PrimitiveDryModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\nphysics::Bool\nthermodynamics::SpeedyWeather.Thermodynamics{NF} where NF<:AbstractFloat\nboundary_layer_drag::SpeedyWeather.BoundaryLayerDrag{NF} where NF<:AbstractFloat\ntemperature_relaxation::SpeedyWeather.TemperatureRelaxation{NF} where NF<:AbstractFloat\nstatic_energy_diffusion::SpeedyWeather.VerticalDiffusion{NF} where NF<:AbstractFloat\nlarge_scale_condensation::SpeedyWeather.AbstractCondensation{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ShallowWaterModel","page":"Function and type index","title":"SpeedyWeather.ShallowWaterModel","text":"The ShallowWaterModel struct holds all other structs that contain precalculated constants, whether scalars or arrays that do not change throughout model integration.\n\nspectral_grid::SpectralGrid: dictates resolution for many other components\nplanet::SpeedyWeather.AbstractPlanet: contains physical and orbital characteristics\natmosphere::SpeedyWeather.AbstractAtmosphere\nforcing::SpeedyWeather.AbstractForcing{NF} where NF<:AbstractFloat\ninitial_conditions::SpeedyWeather.InitialConditions\norography::SpeedyWeather.AbstractOrography{NF} where NF<:AbstractFloat\ntime_stepping::SpeedyWeather.TimeStepper{NF} where NF<:AbstractFloat\nspectral_transform::SpectralTransform\nhorizontal_diffusion::SpeedyWeather.HorizontalDiffusion{NF} where NF<:AbstractFloat\nimplicit::SpeedyWeather.AbstractImplicit{NF} where NF<:AbstractFloat\ngeometry::Geometry\nconstants::DynamicsConstants\ndevice_setup::SpeedyWeather.DeviceSetup\noutput::SpeedyWeather.AbstractOutputWriter\nfeedback::SpeedyWeather.AbstractFeedback\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Simulation","page":"Function and type index","title":"SpeedyWeather.Simulation","text":"Simulation is a container struct to be used with run!(::Simulation). It contains\n\nprognostic_variables::PrognosticVariables: define the current state of the model\ndiagnostic_variables::DiagnosticVariables: contain the tendencies and auxiliary arrays to compute them\nmodel::SpeedyWeather.ModelSetup: all parameters, constant at runtime\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpectralGrid","page":"Function and type index","title":"SpeedyWeather.SpectralGrid","text":"Defines the horizontal spectral resolution and corresponding grid and the vertical coordinate for SpeedyWeather.jl. Options are\n\nNF::Type{<:AbstractFloat}: number format used throughout the model\ntrunc::Int64: horizontal resolution as the maximum degree of spherical harmonics\nGrid::Type{<:SpeedyWeather.RingGrids.AbstractGrid}: horizontal grid used for calculations in grid-point space\ndealiasing::Float64: how to match spectral with grid resolution: dealiasing factor, 1=linear, 2=quadratic, 3=cubic grid\nradius::Float64: radius of the sphere [m]\nnlat_half::Int64: number of latitude rings on one hemisphere (Equator incl)\nnpoints::Int64: total number of grid points in the horizontal\nnlev::Int64: number of vertical levels\nvertical_coordinates::SpeedyWeather.VerticalCoordinates: coordinates used to discretize the vertical\n\nnlat_half and npoints should not be chosen but are derived from trunc, Grid and dealiasing.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpeedyCondensation","page":"Function and type index","title":"SpeedyWeather.SpeedyCondensation","text":"Large scale condensation as in Fortran SPEEDY with default values from therein.\n\nnlev::Int64: number of vertical levels\nthreshold_boundary_layer::Float64: Relative humidity threshold for boundary layer\nthreshold_range::Float64: Vertical range of relative humidity threshold\nthreshold_max::Float64: Maximum relative humidity threshold [1]\ntime_scale::Float64: Relaxation time for humidity [hrs]\nn_stratosphere_levels::Base.RefValue{Int64}\nhumid_tend_max::Vector{NF} where NF<:AbstractFloat\nrelative_threshold::Vector{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"SpectralTransform(\n spectral_grid::SpectralGrid;\n recompute_legendre,\n one_more_degree,\n kwargs...\n) -> SpectralTransform\n\n\nGenerator function for a SpectralTransform struct pulling in parameters from a SpectralGrid struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.StartFromFile","page":"Function and type index","title":"SpeedyWeather.StartFromFile","text":"Restart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical. restart.jld2 is identified by\n\npath::String: path for restart file\nid::Union{Int64, String}: run_id of restart file in run_????/restart.jld2\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.StartWithRandomVorticity","page":"Function and type index","title":"SpeedyWeather.StartWithRandomVorticity","text":"Start with random vorticity as initial conditions\n\npower::Float64: Power of the spectral distribution k^power\namplitude::Float64: (approximate) amplitude in [1/s], used as standard deviation of spherical harmonic coefficients\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.StaticEnergyDiffusion","page":"Function and type index","title":"SpeedyWeather.StaticEnergyDiffusion","text":"Diffusion of dry static energy: A relaxation towards a reference gradient of static energy wrt to geopotential, see Fortran SPEEDY documentation.\n\ntime_scale::Float64: time scale [hrs] for strength\nstatic_energy_lapse_rate::Float64: [1] ∂SE/∂Φ, vertical gradient of static energy SE with geopotential Φ\nFstar::Base.RefValue{NF} where NF<:AbstractFloat\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.Tendencies","page":"Function and type index","title":"SpeedyWeather.Tendencies","text":"Tendencies{Grid<:AbstractGrid,NF<:AbstractFloat}\n\nStruct holding the tendencies of the prognostic spectral variables for a given layer.\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalJet","page":"Function and type index","title":"SpeedyWeather.ZonalJet","text":"Create a struct that contains all parameters for the Galewsky et al, 2004 zonal jet intitial conditions for the shallow water model. Default values as in Galewsky.\n\nlatitude::Float64: jet latitude [˚N]\nwidth::Float64: jet width [˚], default ≈ 19.29˚\numax::Float64: jet maximum velocity [m/s]\nperturb_lat::Float64: perturbation latitude [˚N], position in jet by default\nperturb_lon::Float64: perturbation longitude [˚E]\nperturb_xwidth::Float64: perturbation zonal extent [˚], default ≈ 19.1˚\nperturb_ywidth::Float64: perturbation meridinoal extent [˚], default ≈ 3.8˚\nperturb_height::Float64: perturbation amplitude [m]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalRidge","page":"Function and type index","title":"SpeedyWeather.ZonalRidge","text":"Zonal ridge orography after Jablonowski and Williamson, 2006.\n\nη₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates\nu₀::Float64: max amplitude of zonal wind [m/s] that scales orography height\norography::SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat: height [m] on grid-point space.\ngeopot_surf::LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat: surface geopotential, height*gravity [m²/s²]\n\n\n\n\n\n","category":"type"},{"location":"functions/#SpeedyWeather.ZonalRidge-Tuple{SpectralGrid}","page":"Function and type index","title":"SpeedyWeather.ZonalRidge","text":"ZonalRidge(spectral_grid::SpectralGrid; kwargs...) -> Any\n\n\nGenerator function pulling the resolution information from spectral_grid.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.ZonalWind","page":"Function and type index","title":"SpeedyWeather.ZonalWind","text":"Create a struct that contains all parameters for the Jablonowski and Williamson, 2006 intitial conditions for the primitive equation model. Default values as in Jablonowski.\n\nη₀::Float64: conversion from σ to Jablonowski's ηᵥ-coordinates\nu₀::Float64: max amplitude of zonal wind [m/s]\nperturb_lat::Float64: perturbation centred at [˚N]\nperturb_lon::Float64: perturbation centred at [˚E]\nperturb_uₚ::Float64: perturbation strength [m/s]\nperturb_radius::Float64: radius of Gaussian perturbation in units of Earth's radius [1]\nΔT::Float64: temperature difference used for stratospheric lapse rate [K], Jablonowski uses ΔT = 4.8e5 [K]\nTmin::Float64: minimum temperature [K] of profile\npressure_on_orography::Bool: initialize pressure given the atmosphere.lapse_rate on orography?\n\n\n\n\n\n","category":"type"},{"location":"functions/#Base.copy!-Tuple{PrognosticVariables, PrognosticVariables}","page":"Function and type index","title":"Base.copy!","text":"copy!(progn_new::PrognosticVariables, progn_old::PrognosticVariables)\n\nCopies entries of progn_old into progn_new. Only copies those variables that are present in the model of both progn_new and progn_old.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device-Tuple{}","page":"Function and type index","title":"SpeedyWeather.Device","text":"Device()\n\nReturn default used device for internal purposes, either CPUDevice or GPUDevice if a GPU is available.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DeviceArray-Tuple{SpeedyWeather.GPUDevice, Any}","page":"Function and type index","title":"SpeedyWeather.DeviceArray","text":"DeviceArray(device::AbstractDevice, x)\n\nAdapts x to a CuArray when device<:GPUDevice is used, otherwise a regular Array. Uses adapt, thus also can return SubArrays etc.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.DeviceArrayNotAdapt-Tuple{SpeedyWeather.GPUDevice, Any}","page":"Function and type index","title":"SpeedyWeather.DeviceArrayNotAdapt","text":"DeviceArrayNotAdapt(device::AbstractDevice, x)\n\nReturns a CuArray when device<:GPUDevice is used, otherwise a regular Array. Doesn't uses adapt, therefore always returns CuArray/Array\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device_KernelAbstractions-Tuple{SpeedyWeather.CPUDevice}","page":"Function and type index","title":"SpeedyWeather.Device_KernelAbstractions","text":"Device_KernelAbstractions(::AbstractDevice)\n\nReturn used device for use with KernelAbstractions\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.Device_KernelAbstractions-Tuple{}","page":"Function and type index","title":"SpeedyWeather.Device_KernelAbstractions","text":"Device_KernelAbstractions()\n\nReturn default used device for KernelAbstractions, either CPU or CUDADevice if a GPU is available\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{DiagnosticVariables, PrognosticVariables, Int64, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n lf::Int64,\n model::SpeedyWeather.ModelSetup\n)\n\n\nPropagate the spectral state of progn to diagn using time step/leapfrog index lf. Function barrier that calls gridded! for the respective model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, Barotropic}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::Barotropic\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the barotropic vorticity model. Updates grid vorticity, spectral stream function and spectral and grid velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::PrimitiveEquation\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for primitive equation models. Updates grid vorticity, grid divergence, grid temperature, pressure (pres_grid) and the velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.SpeedyTransforms.gridded!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, Int64, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n lf::Int64,\n model::ShallowWater\n)\n\n\nPropagate the spectral state of the prognostic variables progn to the diagnostic variables in diagn for the shallow water model. Updates grid vorticity, grid divergence, grid interface displacement (pres_grid) and the velocities u,v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather._scale_lat!-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, AbstractVector}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather._scale_lat!","text":"_scale_lat!(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n v::AbstractVector\n)\n\n\nGeneric latitude scaling applied to A in-place with latitude-like vector v.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.allocate-Union{Tuple{Model}, Tuple{Type{PrognosticVariables}, SpectralGrid, Type{Model}}} where Model<:SpeedyWeather.ModelSetup","page":"Function and type index","title":"SpeedyWeather.allocate","text":"allocate(\n _::Type{PrognosticVariables},\n spectral_grid::SpectralGrid,\n _::Type{Model<:SpeedyWeather.ModelSetup}\n) -> PrognosticVariables\n\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.bernoulli_potential!-Union{Tuple{NF}, Tuple{SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpectralTransform}} where NF","page":"Function and type index","title":"SpeedyWeather.bernoulli_potential!","text":"bernoulli_potential!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n S::SpectralTransform\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nComputes the Laplace operator ∇² of the Bernoulli potential B in spectral space.\n\ncomputes the kinetic energy KE = ½(u²+v²) on the grid\ntransforms KE to spectral space\nadds geopotential for the Bernoulli potential in spectral space\ntakes the Laplace operator.\n\nThis version is used for both ShallowWater and PrimitiveEquation, only the geopotential calculation in geopotential! differs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.boundary_layer_drag!-Tuple{ColumnVariables, LinearDrag}","page":"Function and type index","title":"SpeedyWeather.boundary_layer_drag!","text":"boundary_layer_drag!(\n column::ColumnVariables,\n scheme::LinearDrag\n)\n\n\nCompute tendency for boundary layer drag of a column and add to its tendencies fields\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.boundary_layer_drag!-Tuple{ColumnVariables, SpeedyWeather.NoBoundaryLayerDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.boundary_layer_drag!","text":"NoBoundaryLayer scheme just passes.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.clip_negatives!-Union{Tuple{AbstractArray{T}}, Tuple{T}} where T","page":"Function and type index","title":"SpeedyWeather.clip_negatives!","text":"clip_negatives!(A::AbstractArray)\n\nSet all negative entries a in A to zero.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.create_output_folder-Tuple{String, Union{Int64, String}}","page":"Function and type index","title":"SpeedyWeather.create_output_folder","text":"create_output_folder(\n path::String,\n id::Union{Int64, String}\n) -> String\n\n\nCreates a new folder run_* with the identification id. Also returns the full path run_path of that folder.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.default_sigma_coordinates-Tuple{Integer}","page":"Function and type index","title":"SpeedyWeather.default_sigma_coordinates","text":"default_sigma_coordinates(nlev::Integer) -> Any\n\n\nVertical sigma coordinates defined by their nlev+1 half levels σ_levels_half. Sigma coordinates are fraction of surface pressure (p/p0) and are sorted from top (stratosphere) to bottom (surface). The first half level is at 0 the last at 1. Evaluate a generalised logistic function with coefficients in P for the distribution of values in between. Default coefficients follow the L31 configuration historically used at ECMWF.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dry_static_energy!-Tuple{ColumnVariables, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.dry_static_energy!","text":"dry_static_energy!(\n column::ColumnVariables,\n constants::DynamicsConstants\n)\n\n\nCompute the dry static energy SE = cₚT + Φ (latent heat times temperature plus geopotential) for the column.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n model::PrimitiveEquation\n) -> Any\ndynamics_tendencies!(\n diagn::DiagnosticVariables,\n progn::PrognosticVariables,\n model::PrimitiveEquation,\n lf::Int64\n) -> Any\n\n\nCalculate all tendencies for the PrimitiveEquation model (wet or dry).\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, Dates.DateTime, Barotropic}","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n time::Dates.DateTime,\n model::Barotropic\n)\n\n\nCalculate all tendencies for the BarotropicModel.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.dynamics_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, LowerTriangularMatrix, Dates.DateTime, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.dynamics_tendencies!","text":"dynamics_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.SurfaceVariables,\n pres::LowerTriangularMatrix,\n time::Dates.DateTime,\n model::ShallowWater\n)\n\n\nCalculate all tendencies for the ShallowWaterModel.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.first_timesteps!-Tuple{PrognosticVariables, DiagnosticVariables, SpeedyWeather.ModelSetup, SpeedyWeather.AbstractOutputWriter}","page":"Function and type index","title":"SpeedyWeather.first_timesteps!","text":"first_timesteps!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n model::SpeedyWeather.ModelSetup,\n output::SpeedyWeather.AbstractOutputWriter\n) -> typeof(time)\n\n\nPerforms the first two initial time steps (Euler forward, unfiltered leapfrog) to populate the prognostic variables with two time steps (t=0,Δt) that can then be used in the normal leap frogging.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.flipsign!-Tuple{AbstractArray}","page":"Function and type index","title":"SpeedyWeather.flipsign!","text":"flipgsign!(A::AbstractArray)\n\nLike -A but in-place.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.flux_divergence!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Geometry{NF}, SpectralTransform{NF}}} where NF","page":"Function and type index","title":"SpeedyWeather.flux_divergence!","text":"flux_divergence!(\n A_tend::LowerTriangularMatrix{Complex{NF}},\n A_grid::SpeedyWeather.RingGrids.AbstractGrid{NF},\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n G::Geometry{NF},\n S::SpectralTransform{NF};\n add,\n flipsign\n)\n\n\nComputes ∇⋅((u,v)*A) with the option to add/overwrite A_tend and to flip_sign of the flux divergence by doing so.\n\nA_tend = ∇⋅((u,v)*A) for add=false, flip_sign=false\nA_tend = -∇⋅((u,v)*A) for add=false, flip_sign=true\nA_tend += ∇⋅((u,v)*A) for add=true, flip_sign=false\nA_tend -= ∇⋅((u,v)*A) for add=true, flip_sign=true\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.fluxes_to_tendencies!-Tuple{ColumnVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.fluxes_to_tendencies!","text":"fluxes_to_tendencies!(\n column::ColumnVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nConvert the fluxes on half levels to tendencies on full levels.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.generalised_logistic-Tuple{Any, SpeedyWeather.GenLogisticCoefs}","page":"Function and type index","title":"SpeedyWeather.generalised_logistic","text":"Generalised logistic function based on the coefficients in coefs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{DiagnosticVariables, SpeedyWeather.AbstractOrography, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(\n diagn::DiagnosticVariables,\n O::SpeedyWeather.AbstractOrography,\n C::DynamicsConstants\n)\n\n\nCompute spectral geopotential geopot from spectral temperature temp and spectral surface geopotential geopot_surf (orography*gravity).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n pres::LowerTriangularMatrix,\n C::DynamicsConstants\n) -> Any\n\n\ncalculates the geopotential in the ShallowWaterModel as g*η, i.e. gravity times the interface displacement (field pres)\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.geopotential!-Tuple{Vector, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.geopotential!","text":"geopotential!(temp::Vector, C::DynamicsConstants) -> Vector\n\n\nCalculate the geopotential based on temp in a single column. This exclues the surface geopotential that would need to be added to the returned vector. Function not used in the dynamical core but for post-processing and analysis.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_column!-Tuple{ColumnVariables, DiagnosticVariables, Int64, Geometry}","page":"Function and type index","title":"SpeedyWeather.get_column!","text":"Recalculate ring index if not provided.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_column!-Tuple{ColumnVariables, DiagnosticVariables, Integer, Integer, Geometry}","page":"Function and type index","title":"SpeedyWeather.get_column!","text":"get_column!(\n C::ColumnVariables,\n D::DiagnosticVariables,\n ij::Integer,\n jring::Integer,\n G::Geometry\n)\n\n\nUpdate C::ColumnVariables by copying the prognostic variables from D::DiagnosticVariables at gridpoint index ij. Provide G::Geometry for coordinate information.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_full_output_file_path-Tuple{OutputWriter}","page":"Function and type index","title":"SpeedyWeather.get_full_output_file_path","text":"get_full_output_file_path(output::OutputWriter) -> String\n\n\nReturns the full path of the output file after it was created.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_run_id-Tuple{String, String}","page":"Function and type index","title":"SpeedyWeather.get_run_id","text":"get_run_id(path::String, id::String) -> String\n\n\nChecks existing run_???? folders in path to determine a 4-digit id number by counting up. E.g. if folder run_0001 exists it will return the string \"0002\". Does not create a folder for the returned run id.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_thermodynamics!-Tuple{ColumnVariables, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.get_thermodynamics!","text":"get_thermodynamics!(\n column::ColumnVariables,\n model::PrimitiveDry\n)\n\n\nCalculate the dry static energy for the primitive dry model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_thermodynamics!-Tuple{ColumnVariables, PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.get_thermodynamics!","text":"get_thermodynamics!(\n column::ColumnVariables,\n model::PrimitiveWet\n)\n\n\nCalculate thermodynamic quantities like saturation vapour pressure, saturation specific humidity, dry static energy, moist static energy and saturation moist static energy from the prognostic column variables.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.get_var-Tuple{PrognosticVariables, Symbol}","page":"Function and type index","title":"SpeedyWeather.get_var","text":"get_var(progn::PrognosticVariables, var_name::Symbol; lf::Integer=1)\n\nReturns the prognostic variable var_name at leapfrog index lf as a Vector{LowerTriangularMatrices}.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.has-Tuple{Type{<:SpeedyWeather.ModelSetup}, Symbol}","page":"Function and type index","title":"SpeedyWeather.has","text":"has(\n M::Type{<:SpeedyWeather.ModelSetup},\n var_name::Symbol\n) -> Bool\n\n\nReturns true if the model M has a prognostic variable var_name, false otherwise. The default fallback is that all variables are included. \n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation\n) -> Union{Nothing, Bool}\nhorizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation,\n lf::Int64\n) -> Union{Nothing, Bool}\n\n\nApply horizontal diffusion applied to vorticity, diffusion and temperature in the PrimitiveEquation models. Uses the constant diffusion for temperature but possibly adaptive diffusion for vorticity and divergence.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-2","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater\n)\nhorizontal_diffusion!(\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater,\n lf::Int64\n)\n\n\nApply horizontal diffusion to vorticity and diffusion in the ShallowWater models.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-3","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::Barotropic\n)\nhorizontal_diffusion!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::Barotropic,\n lf::Int64\n)\n\n\nApply horizontal diffusion to vorticity in the Barotropic models.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.horizontal_diffusion!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, AbstractVector{NF}, AbstractVector{NF}}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.horizontal_diffusion!","text":"horizontal_diffusion!(\n tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n A::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n ∇²ⁿ_expl::AbstractArray{NF<:AbstractFloat, 1},\n ∇²ⁿ_impl::AbstractArray{NF<:AbstractFloat, 1}\n)\n\n\nApply horizontal diffusion to a 2D field A in spectral space by updating its tendency tendency with an implicitly calculated diffusion term. The implicit diffusion of the next time step is split into an explicit part ∇²ⁿ_expl and an implicit part ∇²ⁿ_impl, such that both can be calculated in a single forward step by using A as well as its tendency tendency.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.implicit_correction!-Tuple{DiagnosticVariables, SpeedyWeather.ImplicitPrimitiveEq, PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.implicit_correction!","text":"implicit_correction!(\n diagn::DiagnosticVariables,\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n progn::PrognosticVariables\n) -> Any\n\n\nApply the implicit corrections to dampen gravity waves in the primitive equation models.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.implicit_correction!-Union{Tuple{NF}, Tuple{SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.PrognosticLayerTimesteps{NF}, SpeedyWeather.SurfaceVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, SpeedyWeather.PrognosticSurfaceTimesteps{NF}, SpeedyWeather.ImplicitShallowWater}} where NF","page":"Function and type index","title":"SpeedyWeather.implicit_correction!","text":"implicit_correction!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n progn::SpeedyWeather.PrognosticLayerTimesteps{NF},\n diagn_surface::SpeedyWeather.SurfaceVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF},\n progn_surface::SpeedyWeather.PrognosticSurfaceTimesteps{NF},\n implicit::SpeedyWeather.ImplicitShallowWater\n)\n\n\nApply correction to the tendencies in diagn to prevent the gravity waves from amplifying. The correction is implicitly evaluated using the parameter implicit.α to switch between forward, centered implicit or backward evaluation of the gravity wave terms.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Tuple{PrognosticVariables, StartFromFile, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn_new::PrognosticVariables,\n initial_conditions::StartFromFile,\n model::SpeedyWeather.ModelSetup\n) -> PrognosticVariables\n\n\nRestart from a previous SpeedyWeather.jl simulation via the restart file restart.jld2 Applies interpolation in the horizontal but not in the vertical.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Tuple{PrognosticVariables, ZonalJet, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables,\n initial_conditions::ZonalJet,\n model::ShallowWater\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitial conditions from Galewsky, 2004, Tellus\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, StartWithRandomVorticity, SpeedyWeather.ModelSetup}} where NF","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables{NF},\n initial_conditions::StartWithRandomVorticity,\n model::SpeedyWeather.ModelSetup\n)\n\n\nStart with random vorticity as initial conditions\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, ZonalWind, PrimitiveEquation}} where NF","page":"Function and type index","title":"SpeedyWeather.initial_conditions!","text":"initial_conditions!(\n progn::PrognosticVariables{NF},\n initial_conditions::ZonalWind,\n model::PrimitiveEquation\n)\n\n\nInitial conditions from Jablonowski and Williamson, 2006, QJR Meteorol. Soc\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initial_conditions-Tuple{Model} where Model","page":"Function and type index","title":"SpeedyWeather.initial_conditions","text":"initial_conditions(model) -> PrognosticVariables\n\n\nAllocate the prognostic variables and then set to initial conditions.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n k::Int64,\n G::Geometry,\n L::SpeedyWeather.TimeStepper\n)\ninitialize!(\n scheme::HyperDiffusion,\n k::Int64,\n G::Geometry,\n L::SpeedyWeather.TimeStepper,\n vor_max::Real\n)\n\n\nPrecomputes the hyper diffusion terms in scheme for layer k based on the model time step in L, the vertical level sigma level in G, and the current (absolute) vorticity maximum level vor_max\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{Barotropic}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::Barotropic) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{EarthOrography, SpeedyWeather.AbstractPlanet, SpectralTransform, Geometry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n orog::EarthOrography,\n P::SpeedyWeather.AbstractPlanet,\n S::SpectralTransform,\n G::Geometry\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitialize the arrays orography,geopot_surf in orog by reading the orography field from file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{Feedback, SpeedyWeather.Clock, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n feedback::Feedback,\n clock::SpeedyWeather.Clock,\n model::SpeedyWeather.ModelSetup\n) -> Union{Nothing, IOStream}\n\n\nInitializes the a Feedback struct.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HeldSuarez, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(scheme::HeldSuarez, model::PrimitiveEquation)\n\n\ninitialize the HeldSuarez temperature relaxation by precomputing terms for the equilibrium temperature Teq.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.DiagnosticVariablesLayer, Geometry, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n G::Geometry,\n L::SpeedyWeather.TimeStepper\n)\n\n\nPre-function to other initialize!(::HyperDiffusion) initialisors that calculates the (absolute) vorticity maximum for the layer of diagn.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n model::SpeedyWeather.ModelSetup\n)\n\n\nPrecomputes the hyper diffusion terms in scheme based on the model time step, and possibly with a changing strength/power in the vertical.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{HyperDiffusion, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::HyperDiffusion,\n L::SpeedyWeather.TimeStepper\n)\n\n\nPrecomputes the 2D hyper diffusion terms in scheme based on the model time step.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{JablonowskiRelaxation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::JablonowskiRelaxation,\n model::PrimitiveEquation\n)\n\n\ninitialize the JablonowskiRelaxation temperature relaxation by precomputing terms for the equilibrium temperature Teq and the frequency (strength of relaxation).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{LinearDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(scheme::LinearDrag, model::PrimitiveEquation)\n\n\nPrecomputes the drag coefficients for this BoundaryLayerDrag scheme.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{NoTemperatureRelaxation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::NoTemperatureRelaxation,\n model::PrimitiveEquation\n)\n\n\njust passes, does not need any initialization.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::PrimitiveDry) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::PrimitiveWet) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{ShallowWater}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(model::ShallowWater) -> SpeedyWeather.Simulation\n\n\nCalls all initialize! functions for components of model, except for model.output and model.feedback which are always called at in time_stepping! and model.implicit which is done in first_timesteps!.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyCondensation, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::SpeedyCondensation,\n model::PrimitiveEquation\n)\n\n\nInitialize the SpeedyCondensation scheme.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.Clock, SpeedyWeather.TimeStepper}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n clock::SpeedyWeather.Clock,\n time_stepping::SpeedyWeather.TimeStepper\n) -> SpeedyWeather.Clock\n\n\nInitialize the clock with the time step Δt in the time_stepping.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitPrimitiveEq, Integer, Real, DiagnosticVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n i::Integer,\n dt::Real,\n diagn::DiagnosticVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nReinitialize implicit occasionally based on time step i and implicit.recalculate.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitPrimitiveEq, Real, DiagnosticVariables, Geometry, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitPrimitiveEq,\n dt::Real,\n diagn::DiagnosticVariables,\n geometry::Geometry,\n constants::DynamicsConstants\n)\n\n\nInitialize the implicit terms for the PrimitiveEquation models.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.ImplicitShallowWater, Real, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n implicit::SpeedyWeather.ImplicitShallowWater,\n dt::Real,\n constants::DynamicsConstants\n)\n\n\nUpdate the implicit terms in implicit for the shallow water model as they depend on the time step dt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{SpeedyWeather.NoBoundaryLayerDrag, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"NoBoundaryLayer scheme does not need any initialisation.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Tuple{ZonalRidge, SpeedyWeather.AbstractPlanet, SpectralTransform, Geometry}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n orog::ZonalRidge,\n P::SpeedyWeather.AbstractPlanet,\n S::SpectralTransform,\n G::Geometry\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nInitialize the arrays orography,geopot_surf in orog following Jablonowski and Williamson, 2006.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Union{Tuple{Model}, Tuple{output_NF}, Tuple{OutputWriter{output_NF, Model}, SpeedyWeather.AbstractFeedback, SpeedyWeather.TimeStepper, DiagnosticVariables, Model}} where {output_NF, Model}","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n output::OutputWriter{output_NF, Model},\n feedback::SpeedyWeather.AbstractFeedback,\n time_stepping::SpeedyWeather.TimeStepper,\n diagn::DiagnosticVariables,\n model\n)\n\n\nCreates a netcdf file on disk and the corresponding netcdf_file object preallocated with output variables and dimensions. write_output! then writes consecuitive time steps into this file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize!-Union{Tuple{NF}, Tuple{SpeedyWeather.StaticEnergyDiffusion{NF}, PrimitiveEquation}} where NF","page":"Function and type index","title":"SpeedyWeather.initialize!","text":"initialize!(\n scheme::SpeedyWeather.StaticEnergyDiffusion{NF},\n model::PrimitiveEquation\n) -> Any\n\n\nInitialize dry static energy diffusion.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.initialize_geopotential-Tuple{Vector, Vector, Real}","page":"Function and type index","title":"SpeedyWeather.initialize_geopotential","text":"initialize_geopotential(\n σ_levels_full::Vector,\n σ_levels_half::Vector,\n R_dry::Real\n) -> Tuple{Vector{Float64}, Vector{Float64}}\n\n\nPrecomputes constants for the vertical integration of the geopotential, defined as\n\nΦ_{k+1/2} = Φ_{k+1} + R*T_{k+1}*(ln(p_{k+1}) - ln(p_{k+1/2})) (half levels) Φ_k = Φ_{k+1/2} + R*T_k*(ln(p_{k+1/2}) - ln(p_k)) (full levels)\n\nSame formula but k → k-1/2.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.isdecreasing-Tuple{Vector}","page":"Function and type index","title":"SpeedyWeather.isdecreasing","text":"true/false = isdecreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly decreasing.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.isincreasing-Tuple{Vector}","page":"Function and type index","title":"SpeedyWeather.isincreasing","text":"true/false = isincreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly increasing.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Tuple{ColumnVariables, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"large_scale_condensation!(\n column::ColumnVariables,\n model::PrimitiveDry\n)\n\n\nNo condensation in a PrimitiveDry model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Tuple{ColumnVariables, PrimitiveWet}","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"Function barrier only.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.large_scale_condensation!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, SpeedyCondensation, Geometry, DynamicsConstants, SpeedyWeather.AbstractAtmosphere, SpeedyWeather.TimeStepper}} where NF","page":"Function and type index","title":"SpeedyWeather.large_scale_condensation!","text":"large_scale_condensation!(\n column::ColumnVariables{NF},\n scheme::SpeedyCondensation,\n geometry::Geometry,\n constants::DynamicsConstants,\n atmosphere::SpeedyWeather.AbstractAtmosphere,\n time_stepping::SpeedyWeather.TimeStepper\n)\n\n\nLarge-scale condensation for a column by relaxation back to a reference relative humidity if larger than that. Calculates the tendencies for specific humidity and temperature and integrates the large-scale precipitation vertically for output.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.launch_kernel!-Tuple{SpeedyWeather.DeviceSetup, Any, Any, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.launch_kernel!","text":"launch_kernel!(device_setup::DeviceSetup, kernel!, ndrange, kernel_args...)\n\nLaunches the kernel! on the device_setup with ndrange computations over the kernel and arguments kernel_args\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.leapfrog!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, Real, Int64, Leapfrog{NF}}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.leapfrog!","text":"leapfrog!(\n A_old::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n A_new::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n tendency::LowerTriangularMatrix{Complex{NF<:AbstractFloat}},\n dt::Real,\n lf::Int64,\n L::Leapfrog{NF<:AbstractFloat}\n)\n\n\nPerforms one leapfrog time step with (lf=2) or without (lf=1) Robert+Williams filter (see Williams (2009), Montly Weather Review, Eq. 7-9).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_pressure_gradient!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticSurfaceTimesteps, Int64, DynamicsConstants, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.linear_pressure_gradient!","text":"linear_pressure_gradient!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.PrognosticSurfaceTimesteps,\n lf::Int64,\n C::DynamicsConstants,\n I::SpeedyWeather.ImplicitPrimitiveEq\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nAdd the linear contribution of the pressure gradient to the geopotential. The pressure gradient in the divergence equation takes the form\n\n-∇⋅(Rd*Tᵥ*∇lnpₛ) = -∇⋅(Rd*Tᵥ'*∇lnpₛ) - ∇²(Rd*Tₖ*lnpₛ)\n\nSo that the second term inside the Laplace operator can be added to the geopotential. Rd is the gas constant, Tᵥ the virtual temperature and Tᵥ' its anomaly wrt to the average or reference temperature Tₖ, lnpₛ is the logarithm of surface pressure.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, DynamicsConstants, Int64}","page":"Function and type index","title":"SpeedyWeather.linear_virtual_temperature!","text":"linear_virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n constants::DynamicsConstants,\n lf::Int64\n) -> Any\n\n\nCalculates a linearised virtual temperature Tᵥ as\n\nTᵥ = T + Tₖμq\n\nWith absolute temperature T, layer-average temperarture Tₖ (computed in temperature_average!), specific humidity q and\n\nμ = (1-ξ)/ξ, ξ = R_dry/R_vapour.\n\nin spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.linear_virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.PrognosticLayerTimesteps, PrimitiveDry, Integer}","page":"Function and type index","title":"SpeedyWeather.linear_virtual_temperature!","text":"linear_virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n progn::SpeedyWeather.PrognosticLayerTimesteps,\n model::PrimitiveDry,\n lf::Integer\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nLinear virtual temperature for model::PrimitiveDry: Just copy over arrays from temp to temp_virt at timestep lf in spectral space as humidity is zero in this model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.load_trajectory-Tuple{Union{String, Symbol}, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.load_trajectory","text":"load_trajectory(\n var_name::Union{String, Symbol},\n model::SpeedyWeather.ModelSetup\n) -> Any\n\n\nLoads a var_name trajectory of the model M that has been saved in a netCDF file during the time stepping.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.moist_static_energy!-Tuple{ColumnVariables, SpeedyWeather.Thermodynamics}","page":"Function and type index","title":"SpeedyWeather.moist_static_energy!","text":"moist_static_energy!(\n column::ColumnVariables,\n thermodynamics::SpeedyWeather.Thermodynamics\n)\n\n\nCompute the moist static energy\n\nMSE = SE + Lc*Q = cₚT + Φ + Lc*Q\n\nwith the static energy SE, the latent heat of condensation Lc, the geopotential Φ. As well as the saturation moist static energy which replaces Q with Q_sat\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nans-Tuple","page":"Function and type index","title":"SpeedyWeather.nans","text":"A = nans(dims...)\n\nAllocate A::Array{Float64} with NaNs.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nans-Union{Tuple{T}, Tuple{Type{T}, Vararg{Any}}} where T","page":"Function and type index","title":"SpeedyWeather.nans","text":"A = nans(T,dims...)\n\nAllocate array A with NaNs of type T. Similar to zeros(T,dims...).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.nar_detection!-Tuple{Feedback, PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.nar_detection!","text":"nar_detection!(\n feedback::Feedback,\n progn::PrognosticVariables\n) -> Union{Nothing, Bool}\n\n\nDetect NaR (Not-a-Real) in the prognostic variables.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.parameterization_tendencies!-Tuple{DiagnosticVariables, Dates.DateTime, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.parameterization_tendencies!","text":"parameterization_tendencies!(\n diagn::DiagnosticVariables,\n time::Dates.DateTime,\n model::PrimitiveEquation\n) -> Any\n\n\nCompute tendencies for u,v,temp,humid from physical parametrizations. Extract for each vertical atmospheric column the prognostic variables (stored in diagn as they are grid-point transformed), loop over all grid-points, compute all parametrizations on a single-column basis, then write the tendencies back into a horizontal field of tendencies.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.pressure_on_orography!-Tuple{PrognosticVariables, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.pressure_on_orography!","text":"pressure_on_orography!(\n progn::PrognosticVariables,\n model::PrimitiveEquation\n)\n\n\nInitialize surface pressure on orography by integrating the hydrostatic equation with the reference temperature lapse rate.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.progress!-Tuple{Feedback}","page":"Function and type index","title":"SpeedyWeather.progress!","text":"progress!(feedback::Feedback)\n\n\nCalls the progress meter and writes every 5% progress increase to txt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.progress_finish!-Tuple{Feedback}","page":"Function and type index","title":"SpeedyWeather.progress_finish!","text":"progress_finish!(F::Feedback)\n\n\nFinalises the progress meter and the progress txt file.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.readable_secs-Tuple{Real}","page":"Function and type index","title":"SpeedyWeather.readable_secs","text":"readable_secs(secs::Real) -> Dates.CompoundPeriod\n\n\nReturns Dates.CompoundPeriod rounding to either (days, hours), (hours, minutes), (minutes, seconds), or seconds with 1 decimal place accuracy for >10s and two for less. E.g.\n\njulia> readable_secs(12345)\n3 hours, 26 minutes\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.remaining_time-Tuple{ProgressMeter.Progress}","page":"Function and type index","title":"SpeedyWeather.remaining_time","text":"remaining_time(p::ProgressMeter.Progress) -> String\n\n\nEstimates the remaining time from a ProgresssMeter.Progress. Adapted from ProgressMeter.jl\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.reset_column!-Union{Tuple{ColumnVariables{NF}}, Tuple{NF}} where NF","page":"Function and type index","title":"SpeedyWeather.reset_column!","text":"reset_column!(column::ColumnVariables{NF})\n\n\nSet the accumulators (tendencies but also vertical sums and similar) back to zero for column to be reused at other grid points.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.run!-Tuple{SpeedyWeather.Simulation}","page":"Function and type index","title":"SpeedyWeather.run!","text":"run!(\n simulation::SpeedyWeather.Simulation;\n initialize,\n n_days,\n startdate,\n output\n) -> PrognosticVariables\n\n\nRun a SpeedyWeather.jl simulation. The simulation.model is assumed to be initialized, otherwise use initialize=true as keyword argument.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.saturation_humidity!-Tuple{ColumnVariables, SpeedyWeather.Thermodynamics}","page":"Function and type index","title":"SpeedyWeather.saturation_humidity!","text":"saturation_humidity!(\n column::ColumnVariables,\n thermodynamics::SpeedyWeather.Thermodynamics\n)\n\n\nCompute (1) the saturation vapour pressure as a function of temperature using the August-Roche-Magnus formula,\n\neᵢ(T) = e₀ * exp(Cᵢ * (T - T₀) / (T - Tᵢ)),\n\nwhere T is in Kelvin and i = 1,2 for saturation with respect to water and ice, respectively. And (2) the saturation specific humidity according to the formula,\n\n0.622 * e / (p - (1 - 0.622) * e),\n\nwhere e is the saturation vapour pressure, p is the pressure, and 0.622 is the ratio of the molecular weight of water to dry air.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.scale!-Tuple{PrognosticVariables, Real}","page":"Function and type index","title":"SpeedyWeather.scale!","text":"scale!(progn::PrognosticVariables, scale::Real) -> Real\n\n\nScales the prognostic variables vorticity and divergence with the Earth's radius which is used in the dynamical core.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.scale!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Real}} where NF","page":"Function and type index","title":"SpeedyWeather.scale!","text":"scale!(\n progn::PrognosticVariables{NF},\n var::Symbol,\n scale::Real\n)\n\n\nScale the variable var inside progn with scalar scale.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_divergence!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_divergence!","text":"set_divergence!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_humidity!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_humidity!","text":"set_humidity!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, AbstractMatrix}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractMatrix, \n Grid::Type{<:AbstractGrid}, \n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, LowerTriangularMatrix}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::LowerTriangularMatrix;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in spectral space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, SpeedyWeather.RingGrids.AbstractGrid, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractGrid, \n M::ModelSetup;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_pressure!-Tuple{PrognosticVariables, SpeedyWeather.RingGrids.AbstractGrid}","page":"Function and type index","title":"SpeedyWeather.set_pressure!","text":"set_pressure!(progn::PrognosticVariables{NF}, \n pressure::AbstractGrid, \n lf::Integer=1) where NF\n\nSets the prognostic variable with the surface pressure in grid space at leapfrog index lf.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_temperature!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_temperature!","text":"set_temperature!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Number}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"function set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n s::Number;\n lf::Integer=1) where NF\n\nSets all values of prognostic variable varname at leapfrog index lf to the scalar s.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:AbstractMatrix}}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:AbstractMatrix}, Type{<:SpeedyWeather.RingGrids.AbstractGrid}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractMatrix}, \n Grid::Type{<:AbstractGrid}=FullGaussianGrid;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:LowerTriangularMatrix}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:LowerTriangularMatrix};\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:SpeedyWeather.RingGrids.AbstractGrid}, SpeedyWeather.ModelSetup}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractGrid}, \n M::ModelSetup;\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_var!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, Symbol, Vector{<:SpeedyWeather.RingGrids.AbstractGrid}}} where NF","page":"Function and type index","title":"SpeedyWeather.set_var!","text":"set_var!(progn::PrognosticVariables{NF}, \n varname::Symbol, \n var::Vector{<:AbstractGrid};\n lf::Integer=1) where NF\n\nSets the prognostic variable with the name varname in all layers at leapfrog index lf with values given in var a vector with all information for all layers in grid space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.set_vorticity!-Tuple{PrognosticVariables, Vararg{Any}}","page":"Function and type index","title":"SpeedyWeather.set_vorticity!","text":"set_vorticity!(progn::PrognosticVariables, varargs...; kwargs...)\n\nSee set_var!\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.sigma_okay-Tuple{Integer, AbstractVector}","page":"Function and type index","title":"SpeedyWeather.sigma_okay","text":"sigma_okay(nlev::Integer, σ_half::AbstractVector) -> Bool\n\n\nCheck that nlev and σ_half match.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.speedstring-Tuple{Any, Any}","page":"Function and type index","title":"SpeedyWeather.speedstring","text":"speedstring(sec_per_iter, dt_in_sec) -> String\n\n\ndefine a ProgressMeter.speedstring method that also takes a time step dt_in_sec to translate sec/iteration to days/days-like speeds.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.static_energy_diffusion!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, SpeedyWeather.StaticEnergyDiffusion}} where NF","page":"Function and type index","title":"SpeedyWeather.static_energy_diffusion!","text":"static_energy_diffusion!(\n column::ColumnVariables{NF},\n scheme::SpeedyWeather.StaticEnergyDiffusion\n)\n\n\nApply dry static energy diffusion.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.surface_pressure_tendency!-Tuple{SpeedyWeather.SurfaceVariables, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.surface_pressure_tendency!","text":"surface_pressure_tendency!( Prog::PrognosticVariables,\n Diag::DiagnosticVariables,\n lf::Int,\n M::PrimitiveEquation)\n\nComputes the tendency of the logarithm of surface pressure as\n\n-(ū*px + v̄*py) - D̄\n\nwith ū,v̄ being the vertically averaged velocities; px, py the gradients of the logarithm of surface pressure ln(p_s) and D̄ the vertically averaged divergence.\n\nCalculate ∇ln(p_s) in spectral space, convert to grid.\nMultiply ū,v̄ with ∇ln(p_s) in grid-point space, convert to spectral.\nD̄ is subtracted in spectral space.\nSet tendency of the l=m=0 mode to 0 for better mass conservation.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_anomaly!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.temperature_anomaly!","text":"Convert absolute and virtual temperature to anomalies wrt to the reference profile\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_average!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.temperature_average!","text":"temperature_average!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n S::SpectralTransform\n) -> Any\n\n\nCalculates the average temperature of a layer from the l=m=0 harmonic and stores the result in diagn.temp_average\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Tuple{ColumnVariables, JablonowskiRelaxation}","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables,\n scheme::JablonowskiRelaxation\n)\n\n\nApply HeldSuarez-like temperature relaxation to the Jablonowski and Williamson vertical profile.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Tuple{ColumnVariables, NoTemperatureRelaxation}","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables,\n scheme::NoTemperatureRelaxation\n)\n\n\njust passes.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_relaxation!-Union{Tuple{NF}, Tuple{ColumnVariables{NF}, HeldSuarez}} where NF","page":"Function and type index","title":"SpeedyWeather.temperature_relaxation!","text":"temperature_relaxation!(\n column::ColumnVariables{NF},\n scheme::HeldSuarez\n)\n\n\nApply temperature relaxation following Held and Suarez 1996, BAMS.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_tendency!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, DynamicsConstants, Geometry, SpectralTransform, SpeedyWeather.ImplicitPrimitiveEq}","page":"Function and type index","title":"SpeedyWeather.temperature_tendency!","text":"temperature_tendency!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform,\n I::SpeedyWeather.ImplicitPrimitiveEq\n)\n\n\nCompute the temperature tendency\n\n∂T/∂t += -∇⋅((u,v)*T') + T'D + κTᵥ*Dlnp/Dt\n\n+= because the tendencies already contain parameterizations and vertical advection. T' is the anomaly with respect to the reference/average temperature. Tᵥ is the virtual temperature used in the adiabatic term κTᵥ*Dlnp/Dt.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.temperature_tendency!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.temperature_tendency!","text":"temperature_tendency!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::PrimitiveEquation\n)\n\n\nFunction barrier to unpack model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.time_stepping!-Tuple{PrognosticVariables, DiagnosticVariables, SpeedyWeather.ModelSetup}","page":"Function and type index","title":"SpeedyWeather.time_stepping!","text":"time_stepping!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n model::SpeedyWeather.ModelSetup\n) -> PrognosticVariables\n\n\nMain time loop that that initializes output and feedback, loops over all time steps and calls the output and feedback functions.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.timestep!","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic\n)\ntimestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic,\n lf1::Int64\n)\ntimestep!(\n progn::PrognosticVariables,\n diagn::DiagnosticVariables,\n dt::Real,\n i::Integer,\n model::Barotropic,\n lf1::Int64,\n lf2::Int64\n)\n\n\nCalculate a single time step for the model <: Barotropic.\n\n\n\n\n\n","category":"function"},{"location":"functions/#SpeedyWeather.timestep!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation, Int64}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, PrimitiveEquation, Int64, Int64}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation\n) -> Any\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation,\n lf1::Int64\n) -> Any\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::PrimitiveEquation,\n lf1::Int64,\n lf2::Int64\n) -> Any\n\n\nCalculate a single time step for the model<:PrimitiveEquation\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.timestep!-Union{Tuple{NF}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater, Int64}, Tuple{PrognosticVariables{NF}, DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, Real, Integer, ShallowWater, Int64, Int64}} where NF<:AbstractFloat","page":"Function and type index","title":"SpeedyWeather.timestep!","text":"timestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater,\n lf1::Int64\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\ntimestep!(\n progn::PrognosticVariables{NF<:AbstractFloat},\n diagn::DiagnosticVariables{NF<:AbstractFloat, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n dt::Real,\n i::Integer,\n model::ShallowWater,\n lf1::Int64,\n lf2::Int64\n) -> Union{Nothing, SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat}\n\n\nCalculate a single time step for the model <: ShallowWater.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.underflow!-Union{Tuple{T}, Tuple{AbstractArray{T}, Real}} where T","page":"Function and type index","title":"SpeedyWeather.underflow!","text":"underflow!(A::AbstractArray,ϵ::Real)\n\nUnderflows element a in A to zero if abs(a) < ϵ.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.unscale!-Tuple{AbstractArray, Real}","page":"Function and type index","title":"SpeedyWeather.unscale!","text":"unscale!(variable::AbstractArray, scale::Real) -> Any\n\n\nUndo the radius-scaling for any variable. Method used for netcdf output.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.unscale!-Tuple{PrognosticVariables}","page":"Function and type index","title":"SpeedyWeather.unscale!","text":"unscale!(progn::PrognosticVariables) -> Int64\n\n\nUndo the radius-scaling of vorticity and divergence from scale!(progn,scale::Real).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vertical_integration!-Union{Tuple{NF}, Tuple{DiagnosticVariables{NF, Grid} where Grid<:SpeedyWeather.RingGrids.AbstractGrid{NF}, PrognosticVariables{NF}, Int64, Geometry{NF}}} where NF","page":"Function and type index","title":"SpeedyWeather.vertical_integration!","text":"vertical_integration!(Diag::DiagnosticVariables,G::Geometry)\n\nCalculates the vertically averaged (weighted by the thickness of the σ level) velocities (*coslat) and divergence. E.g.\n\nu_mean = ∑_k=1^nlev Δσ_k * u_k\n\nu,v are averaged in grid-point space, divergence in spectral space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, DynamicsConstants}","page":"Function and type index","title":"SpeedyWeather.virtual_temperature!","text":"virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n constants::DynamicsConstants\n)\n\n\nCalculates the virtual temperature Tᵥ as\n\nTᵥ = T(1+μq)\n\nWith absolute temperature T, specific humidity q and\n\nμ = (1-ξ)/ξ, ξ = R_dry/R_vapour.\n\nin grid-point space.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.virtual_temperature!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, LowerTriangularMatrix, PrimitiveDry}","page":"Function and type index","title":"SpeedyWeather.virtual_temperature!","text":"virtual_temperature!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n temp::LowerTriangularMatrix,\n model::PrimitiveDry\n) -> SpeedyWeather.RingGrids.AbstractGrid{NF} where NF<:AbstractFloat\n\n\nVirtual temperature in grid-point space: For the PrimitiveDry temperature and virtual temperature are the same (humidity=0). Just copy over the arrays.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.volume_flux_divergence!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, SpeedyWeather.AbstractOrography, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.volume_flux_divergence!","text":"volume_flux_divergence!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surface::SpeedyWeather.SurfaceVariables,\n orog::SpeedyWeather.AbstractOrography,\n constants::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform\n)\n\n\nComputes the (negative) divergence of the volume fluxes uh,vh for the continuity equation, -∇⋅(uh,vh).\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vordiv_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.vordiv_tendencies!","text":"vordiv_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surf::SpeedyWeather.SurfaceVariables,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform\n)\n\n\nTendencies for vorticity and divergence. Excluding Bernoulli potential with geopotential and linear pressure gradient inside the Laplace operator, which are added later in spectral space.\n\nu_tend += v*(f+ζ) - RTᵥ'*∇lnp_x\nv_tend += -u*(f+ζ) - RTᵥ'*∇lnp_y\n\n+= because the tendencies already contain the parameterizations and vertical advection. f is coriolis, ζ relative vorticity, R the gas constant Tᵥ' the virtual temperature anomaly, ∇lnp the gradient of surface pressure and _x and _y its zonal/meridional components. The tendencies are then curled/dived to get the tendencies for vorticity/divergence in spectral space\n\n∂ζ/∂t = ∇×(u_tend,v_tend)\n∂D/∂t = ∇⋅(u_tend,v_tend) + ...\n\n+ ... because there's more terms added later for divergence.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vordiv_tendencies!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, SpeedyWeather.SurfaceVariables, PrimitiveEquation}","page":"Function and type index","title":"SpeedyWeather.vordiv_tendencies!","text":"vordiv_tendencies!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n surf::SpeedyWeather.SurfaceVariables,\n model::PrimitiveEquation\n)\n\n\nFunction barrier to unpack model.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, Barotropic}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux!","text":"vorticity_flux!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::Barotropic\n)\n\n\nVorticity flux tendency in the barotropic vorticity equation\n\n∂ζ/∂t = ∇×(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, ShallowWater}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux!","text":"vorticity_flux!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n model::ShallowWater\n)\n\n\nVorticity flux tendency in the shallow water equations\n\n∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ the forcing from forcing! already in u_tend_grid/v_tend_grid and vorticity ζ, coriolis f.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.vorticity_flux_curldiv!-Tuple{SpeedyWeather.DiagnosticVariablesLayer, DynamicsConstants, Geometry, SpectralTransform}","page":"Function and type index","title":"SpeedyWeather.vorticity_flux_curldiv!","text":"vorticity_flux_curldiv!(\n diagn::SpeedyWeather.DiagnosticVariablesLayer,\n C::DynamicsConstants,\n G::Geometry,\n S::SpectralTransform;\n div\n)\n\n\nCompute the vorticity advection as the curl/div of the vorticity fluxes\n\n∂ζ/∂t = ∇×(u_tend,v_tend) ∂D/∂t = ∇⋅(u_tend,v_tend)\n\nwith\n\nu_tend = Fᵤ + v*(ζ+f) v_tend = Fᵥ - u*(ζ+f)\n\nwith Fᵤ,Fᵥ from u_tend_grid/v_tend_grid that are assumed to be alread set in forcing!. Set div=false for the BarotropicModel which doesn't require the divergence tendency.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.workgroup_size-Tuple{SpeedyWeather.AbstractDevice}","page":"Function and type index","title":"SpeedyWeather.workgroup_size","text":"workgroup_size(dev::AbstractDevice)\n\nReturns a workgroup size depending on dev. WIP: Will be expanded in the future to also include grid information. \n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_column_tendencies!-Tuple{DiagnosticVariables, ColumnVariables, Int64}","page":"Function and type index","title":"SpeedyWeather.write_column_tendencies!","text":"write_column_tendencies!(\n D::DiagnosticVariables,\n C::ColumnVariables,\n ij::Int64\n)\n\n\nWrite the parametrization tendencies from C::ColumnVariables into the horizontal fields of tendencies stored in D::DiagnosticVariables at gridpoint index ij.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_netcdf_time!-Tuple{OutputWriter, Dates.DateTime}","page":"Function and type index","title":"SpeedyWeather.write_netcdf_time!","text":"write_netcdf_time!(\n output::OutputWriter,\n time::Dates.DateTime\n)\n\n\nWrite the current time time::DateTime to the netCDF file in output::OutputWriter.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_netcdf_variables!-Union{Tuple{Model}, Tuple{Grid}, Tuple{NF}, Tuple{OutputWriter, DiagnosticVariables{NF, Grid, Model}}} where {NF, Grid, Model}","page":"Function and type index","title":"SpeedyWeather.write_netcdf_variables!","text":"write_netcdf_variables!(\n output::OutputWriter,\n diagn::DiagnosticVariables{NF, Grid, Model}\n)\n\n\nWrite diagnostic variables from diagn to the netCDF file in output::OutputWriter.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_output!-Tuple{OutputWriter, Dates.DateTime, DiagnosticVariables}","page":"Function and type index","title":"SpeedyWeather.write_output!","text":"write_output!(\n outputter::OutputWriter,\n time::Dates.DateTime,\n diagn::DiagnosticVariables\n)\n\n\nWrites the variables from diagn of time step i at time time into outputter.netcdf_file. Simply escapes for no netcdf output of if output shouldn't be written on this time step. Interpolates onto output grid and resolution as specified in outputter, converts to output number format, truncates the mantissa for higher compression and applies lossless compression.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.write_restart_file-Tuple{PrognosticVariables, OutputWriter}","page":"Function and type index","title":"SpeedyWeather.write_restart_file","text":"write_restart_file(\n progn::PrognosticVariables,\n output::OutputWriter\n) -> Union{Nothing, String}\n\n\nA restart file restart.jld2 with the prognostic variables is written to the output folder (or current path) that can be used to restart the model. restart.jld2 will then be used as initial conditions. The prognostic variables are bitrounded for compression and the 2nd leapfrog time step is discarded. Variables in restart file are unscaled.\n\n\n\n\n\n","category":"method"},{"location":"functions/#SpeedyWeather.zero_tendencies!-Tuple{DiagnosticVariables}","page":"Function and type index","title":"SpeedyWeather.zero_tendencies!","text":"zero_tendencies!(diagn::DiagnosticVariables)\n\n\nSet the tendencies in diagn to zero.\n\n\n\n\n\n","category":"method"},{"location":"how_to_run_speedy/#How-to-run-SpeedyWeather.jl","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Creating a SpeedyWeather.jl simulation and running it consists conceptually of 4 steps","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Create a SpectralGrid which defines the grid and spectral resolution\nCreate a model\nInitialize a model to obtain a Simulation.\nRun the simulation.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"In the following we will describe these steps in more detail, but let's start with some examples first.","category":"page"},{"location":"how_to_run_speedy/#Example-1:-2D-turbulence-on-a-non-rotating-sphere","page":"How to run SpeedyWeather.jl","title":"Example 1: 2D turbulence on a non-rotating sphere","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"We want to use the barotropic model to simulate some free-decaying 2D turbulence on the sphere without rotation. We start by defining the SpectralGrid object. To have a resolution of about 100km, we choose a spectral resolution of T127 (see Available horizontal resolutions) and nlev=1 vertical levels. The SpectralGrid object will provide us with some more information","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> spectral_grid = SpectralGrid(trunc=127,nlev=1)\nSpectralGrid:\n Spectral: T127 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m\n Grid: 40320-element, 192-ring OctahedralGaussianGrid{Float32} (quadratic)\n Resolution: 112km (average)\n Vertical: 1-level SigmaCoordinates","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"We could have specified further options, but let's ignore that for now. Next step we create a planet that's like Earth but not rotating","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> still_earth = Earth(rotation=0)\nMain.SpeedyWeather.Earth\n rotation: Float64 0.0\n gravity: Float64 9.81\n daily_cycle: Bool true\n length_of_day: Float64 24.0\n seasonal_cycle: Bool true\n length_of_year: Float64 365.25\n equinox: Dates.DateTime\n axial_tilt: Float64 23.4","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"There are other options to create a planet but they are irrelevant for the barotropic vorticity equations. We also want to specify the initial conditions, randomly distributed vorticity is already defined","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> initial_conditions = StartWithRandomVorticity()\nStartWithRandomVorticity\n power_law: Float64 -3.0\n amplitude: Float64 1.0e-5","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"By default, the power of vorticity is spectrally distributed with k^-3, k being the horizontal wavenumber, and the amplitude is 10^-5text s^-1.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Now we want to construct a BarotropicModel with these","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = BarotropicModel(;spectral_grid, initial_conditions, planet=still_earth);","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The model contains all the parameters, but isn't initialized yet, which we can do with and then run it.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> simulation = initialize!(model);\njulia> run!(simulation,n_days=30)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The run! command will always return the prognostic variables, which, by default, are plotted for surface relative vorticity with a unicode plot. The resolution of the plot is not necessarily representative but it lets us have a quick look at the result","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Barotropic vorticity unicode plot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Woohoo! I can see turbulence! You could pick up where this simulation stopped by simply doing run!(simulation,n_days=50) again. We didn't store any output, which you can do by run!(simulation,output=true), which will switch on NetCDF output with default settings. More options on output in NetCDF output.","category":"page"},{"location":"how_to_run_speedy/#Example-2:-Shallow-water-with-mountains","page":"How to run SpeedyWeather.jl","title":"Example 2: Shallow water with mountains","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"As a second example, let's investigate the Galewsky et al.[1] test case for the shallow water equations with and without mountains. As the shallow water system has also only one level, we can reuse the SpectralGrid from Example 1.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> spectral_grid = SpectralGrid(trunc=127,nlev=1)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Now as a first simulation, we want to disable any orography, so we create a NoOrography","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> orography = NoOrography(spectral_grid)\nNoOrography{Float32, OctahedralGaussianGrid{Float32}}","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Although the orography is zero, you have to pass on spectral_grid so that it can still initialize zero-arrays of the right size and element type. Awesome. This time the initial conditions should be set the the Galewsky et al.[1] zonal jet, which is already defined as","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> initial_conditions = ZonalJet()\nZonalJet\n latitude: Float64 45.0\n width: Float64 19.28571428571429\n umax: Float64 80.0\n perturb_lat: Float64 45.0\n perturb_lon: Float64 270.0\n perturb_xwidth: Float64 19.098593171027442\n perturb_ywidth: Float64 3.819718634205488\n perturb_height: Float64 120.0","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The jet sits at 45˚N with a maximum velocity of 80m/s and a perturbation as described in their paper. Now we construct a model, but this time a ShallowWaterModel","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = ShallowWaterModel(;spectral_grid, orography, initial_conditions);\njulia> simulation = initialize!(model);","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet unicode plot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Oh yeah. That looks like the wobbly jet in their paper. Let's run it again for another 6 days but this time also store NetCDF output.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> run!(simulation,n_days=6,output=true)\nWeather is speedy: run 0002 100%|███████████████████████| Time: 0:00:12 (115.37 years/day)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The progress bar tells us that the simulation run got the identification \"0002\", meaning that data is stored in the folder /run_0002, so let's plot that data properly (and not just using UnicodePlots).","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> using PyPlot, NCDatasets\njulia> ds = NCDataset(\"run_0002/output.nc\");\njulia> ds[\"vor\"]\nvor (384 × 192 × 1 × 25)\n Datatype: Float32\n Dimensions: lon × lat × lev × time\n Attributes:\n units = 1/s\n missing_value = NaN\n long_name = relative vorticity\n _FillValue = NaN","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Vorticity vor is stored as a 384x192x1x25 array, we may want to look at the first time step, which is the end of the previous simulation (time=6days) which we didn't store output for.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> vor = ds[\"vor\"][:,:,1,1];\njulia> lat = ds[\"lat\"][:];\njulia> lon = ds[\"lon\"][:];\njulia> pcolormesh(lon,lat,vor')","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Which looks like","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"You see that the unicode plot heavily coarse-grains the simulation, well it's unicode after all! And now the last time step, that means time=12days is","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> vor = ds[\"vor\"][:,:,1,25];\njulia> pcolormesh(lon,lat,vor')","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The jet broke up into many small eddies, but the turbulence is still confined to the northern hemisphere, cool! How this may change when we add mountains (we had NoOrography above!), say Earth's orography, you may ask? Let's try it out! We create an EarthOrography struct like so","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> orography = EarthOrography(spectral_grid)\nEarthOrography{Float32, OctahedralGaussianGrid{Float32}}:\n path::String = SpeedyWeather.jl/input_data\n file::String = orography_F512.nc\n scale::Float64 = 1.0\n smoothing::Bool = true\n smoothing_power::Float64 = 1.0\n smoothing_strength::Float64 = 0.1\n smoothing_truncation::Int64 = 85","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"It will read the orography from file as shown, and there are some smoothing options too, but let's not change them. Same as before, create a model, initialize into a simulation, run. This time directly for 12 days so that we can compare with the last plot","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"julia> model = ShallowWaterModel(;spectral_grid, orography, initial_conditions);\njulia> simulation = initialize!(model);\njulia> run!(simulation,n_days=12,output=true)\nWeather is speedy: run 0003 100%|███████████████████████| Time: 0:00:35 (79.16 years/day)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"This time the run got the id \"0003\", but otherwise we do as before.","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"(Image: Galewsky jet pyplot)","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"Interesting! The initial conditions have zero velocity in the southern hemisphere, but still, one can see some imprint of the orography on vorticity. You can spot the coastline of Antarctica; the Andes and Greenland are somewhat visible too. Mountains also completely changed the flow after 12 days, probably not surprising!","category":"page"},{"location":"how_to_run_speedy/#SpectralGrid","page":"How to run SpeedyWeather.jl","title":"SpectralGrid","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object. We have seen some examples above, now let's look into the details","category":"page"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"SpectralGrid","category":"page"},{"location":"how_to_run_speedy/#References","page":"How to run SpeedyWeather.jl","title":"References","text":"","category":"section"},{"location":"how_to_run_speedy/","page":"How to run SpeedyWeather.jl","title":"How to run SpeedyWeather.jl","text":"[1] Galewsky, Scott, Polvani, 2004. An initial-value problem for testing numerical models of the global shallow-water equations, Tellus A. DOI: 10.3402/tellusa.v56i5.14436","category":"page"},{"location":"speedytransforms/#SpeedyTransforms","page":"Submodule: SpeedyTransforms","title":"SpeedyTransforms","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"SpeedyTransforms is a submodule that has been developed for SpeedyWeather.jl which is technically independent (SpeedyWeather.jl however imports it) and can also be used without running simulations. It is just not put into its own respective repository for now.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"The SpeedyTransforms are based on RingGrids and LowerTriangularMatrices to hold data in either grid-point space or in spectral space. So you want to read these sections first for clarifications how to work with these. We will also not discuss mathematical details of the Spherical Harmonic Transform here, but will focus on the usage of the SpeedyTransforms module.","category":"page"},{"location":"speedytransforms/#Example-transform","page":"Submodule: SpeedyTransforms","title":"Example transform","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Lets start with a simple transform. We could be using SpeedyWeather but to be more verbose these are the modules required to load","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"using SpeedyWeather.RingGrids\nusing SpeedyWeather.LowerTriangularMatrices\nusing SpeedyWeather.SpeedyTransforms","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"As an example, we want to transform the l=m=1 spherical harmonic from spectral space in alms to grid-point space.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms = zeros(LowerTriangularMatrix{ComplexF64},6,6) # spectral coefficients\nalms[2,2] = 1 # only l=1,m=1 harmonic\nalms","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Now gridded is the function that takes spectral coefficients alms and converts them a grid-point space map","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"map = gridded(alms)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"By default, the gridded transforms onto a FullGaussianGrid unravelled here into a vector west to east, starting at the prime meridian, then north to south, see RingGrids. We can visualize map quickly with a unicodeplot via plot (see Visualising RingGrid data)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"plot(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Yay! This is the what the l=m=1 spherical harmonic is supposed to look like! Now let's go back to spectral space with spectral","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms2 = spectral(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Comparing with alms from above you can see that the transform is exact up to a typical rounding error from Float64. ","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms ≈ alms2","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"YAY! The transform is typically idempotent, meaning that either space may hold information that is not exactly representable in the other but the first two-way transform will remove that so that subsequent transforms do not change this any further. However, also note here that the default FullGaussianGrid is an exact grid, inexact grids usually have a transform error that is larger than the rounding error from floating-point arithmetic.","category":"page"},{"location":"speedytransforms/#Transform-onto-another-grid","page":"Submodule: SpeedyTransforms","title":"Transform onto another grid","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"While the default grid for SpeedyTransforms is the FullGaussianGrid we can transform onto other grids by specifying Grid too","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"map = gridded(alms,Grid=HEALPixGrid)\nplot(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"which, if transformed back, however, can yield a larger transform error as discussed above","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"spectral(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"On such a coarse grid the transform error (absolute and relative) is about 10^-2, this decreases for higher resolution. The gridded and spectral functions will choose a corresponding grid-spectral resolution (see Matching spectral and grid resolution) following quadratic truncation, but you can always truncate/interpolate in spectral space with spectral_truncation, spectral_interpolation which takes trunc = l_max = m_max as second argument","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"spectral_truncation(alms,2)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Yay, we just chopped off l 2 from alms which contained the harmonics up to degree and order 5 before. If the second argument in spectral_truncation is larger than alms then it will automatically call spectral_interpolation and vice versa. Also see Interpolation on RingGrids to interpolate directly between grids. If you want to control directly the resolution of the grid gridded is supposed to transform onto you have to provide a SpectralTransform instance. More on that now.","category":"page"},{"location":"speedytransforms/#The-SpectralTransform-struct","page":"Submodule: SpeedyTransforms","title":"The SpectralTransform struct","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Both spectral and gridded create an instance of SpectralTransform under the hood. This object contains all precomputed information that is required for the transform, either way: The Legendre polynomials, pre-planned Fourier transforms, precomputed gradient, divergence and curl operators, the spherical harmonic eigenvalues among others. Maybe the most intuitive way to create a SpectralTransform is to start with a SpectralGrid, which already defines which spectral resolution is supposed to be combined with a given grid.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"using SpeedyWeather\nspectral_grid = SpectralGrid(Float32,trunc=5,Grid=OctahedralGaussianGrid,dealiasing=3)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"(We using SpeedyWeather here as SpectralGrid is exported therein). We also specify the number format Float32 here to be used for the transform although this is the default anyway. From spectral_grid we now construct a SpectralTransform as follows","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"S = SpectralTransform(spectral_grid)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Note that because we chose dealiasing=3 (cubic truncation) we now match a T5 spectral field with a 12-ring octahedral Gaussian grid, instead of the 8 rings as above. So going from dealiasing=2 (default) to dealiasing=3 increased our resolution on the grid while the spectral resolution remains the same. The SpectralTransform also has options for the recomputation or precomputation of the Legendre polynomials, fore more information see (P)recompute Legendre polynomials.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Passing on S the SpectralTransform now allows us to transform directly on the grid defined therein.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"map = gridded(alms,S)\nplot(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Yay, this is again the l=m=1 harmonic, but this time on a slightly higher resolution OctahedralGaussianGrid as specified in the SpectralTransform S. Note that also the number format was converted on the fly to Float32 because that is the number format we specified in S! And from grid to spectral","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms2 = spectral(map,S)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"As you can see the rounding error is now more like 10^-8 as we are using Float32 (the OctahedralGaussianGrid is another exact grid). Note, however, that the returned LowerTriangularMatrix is of size 7x6, not 6x6 what we started from. We may change this in the future, but the underlying reason is that internally SpeedyWeather uses LowerTriangularMatrixs of size l_max + 2 times m_max + 1. One +1 on both degree and order for 0-based harmonics versus 1-based matrix sizes, but an additional +1 for the degrees which is required by the meridional derivative. For consistency, all LowerTriangularMatrixs in SpeedyWeather.jl carry this additional degree but only the vector quantities explicitly make use of it. See Meridional derivative for details.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"You can, however, always truncate this additional degree, say to T5 (hence matrix size is 6x6)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"spectral_truncation(alms2,5,5)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"spectral_truncation(alms2,5) would have returned the same, a single argument is then assumed equal for both degrees and orders. Alternatively, you can also pass on the one_more_degree=false argument to the SpectralTransform constructor","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"S = SpectralTransform(spectral_grid,one_more_degree=false)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"As you can see the 7x6 LowerTriangularMatrix in the description above dropped down to 6x6 LowerTriangularMatrix, this is the size of the input that is expected (otherwise you will get a BoundsError).","category":"page"},{"location":"speedytransforms/#Power-spectrum","page":"Submodule: SpeedyTransforms","title":"Power spectrum","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"How to take some data and compute a power spectrum with SpeedyTransforms you may ask. Say you have some global data in a matrix m that looks, for example, like","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms = randn(LowerTriangularMatrix{Complex{Float32}},32,32) # hide\nspectral_truncation!(alms,10) # hide\nmap = gridded(alms,Grid=FullClenshawGrid) # hide\nm = Matrix(map) # hide\nm","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"You hopefully know which grid this data comes on, let us assume it is a regular latitde-longitude grid, which we call the FullClenshawGrid. We now wrap this matrix therefore to associate it with the necessary grid information","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"map = FullClenshawGrid(m)\nplot(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Now we transform into spectral space and call power_spectrum(::LowerTriangularMatrix)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"alms = spectral(map)\np = SpeedyTransforms.power_spectrum(alms)\nnothing # hide","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Which returns a vector of power at every wavenumber. By default this is normalized as average power per degree, you can change that with the keyword argument normalize=false. Plotting this yields","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"import PyPlot: PyPlot, savefig, tight_layout # hide\nPyPlot.ioff() # hide\nimport PyPlot: semilogy, xlabel, ylabel\nsemilogy(p)\nxlabel(\"wavenumber\")\nylabel(\"power\")\ntight_layout() # hide\nsavefig(\"spectrum.svg\"); close() # hide","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"(Image: )","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"The power spectrum of our data is about 1 up to wavenumber 10 and then close to zero for higher wavenumbers (which is in fact how we constructed this fake data). Let us turn this around and use SpeedyTransforms to create random noise in spectral space to be used in grid-point space!","category":"page"},{"location":"speedytransforms/#Example:-Creating-kn-distributed-noise","page":"Submodule: SpeedyTransforms","title":"Example: Creating k^n-distributed noise","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"How would be construct random noise in spectral space that follows a certain power law and transform it back into grid-point space? Define the wavenumber k for T31, the spectral resolution we are interested in. (We start from 1 instead of 0 to avoid zero to the power of something negative). Now create some normally distributed spectral coefficients but scale them down for higher wavenumbers with k^-2","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"k = 1:32\nalms = randn(LowerTriangularMatrix{Complex{Float32}},32,32)\nalms .*= k.^-2","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Awesome. For higher degrees and orders the amplitude clearly decreases! Now to grid-point space and let us visualize the result","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"map = gridded(alms)\nplot(map)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"(Image: )","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"You can always access the underlying data in map via map.data in case you need to get rid of the wrapping into a grid again!","category":"page"},{"location":"speedytransforms/#(P)recompute-Legendre-polynomials","page":"Submodule: SpeedyTransforms","title":"(P)recompute Legendre polynomials","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"The spectral transform uses a Legendre transform in meridional direction. For this the Legendre polynomials are required, at each latitude ring this is a l_max times m_max lower triangular matrix. Storing precomputed Legendre polynomials therefore quickly increase in size with resolution. One can recompute them to save memory, but that uses more arithmetic operations. There is therefore a memory-compute tradeoff.","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"For a single transform, there is no need to precompute the polynomials as the SpectralTransform object will be garbage collected again anyway. For low resolution simulations with many repeated small transforms it makes sense to precompute the polynomials and SpeedyWeather.jl does that automatically anyway. At very high resolution the polynomials may, however, become prohibitively large. An example at T127, about 100km resolution","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"spectral_grid = SpectralGrid(trunc=127)\nSpectralTransform(spectral_grid,recompute_legendre=false)","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"the polynomials are about 3MB in size. Easy that is not much. But at T1023 on the O1536 octahedral Gaussian grid, this is already 1.5GB, cubically increasing with the spectral truncation T. recompute_legendre=true (default false when constructing a SpectralTransform object which may be reused) would lower this to kilobytes","category":"page"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"SpectralTransform(spectral_grid,recompute_legendre=true)","category":"page"},{"location":"speedytransforms/#Functions-and-type-index","page":"Submodule: SpeedyTransforms","title":"Functions and type index","text":"","category":"section"},{"location":"speedytransforms/","page":"Submodule: SpeedyTransforms","title":"Submodule: SpeedyTransforms","text":"Modules = [SpeedyWeather.SpeedyTransforms]","category":"page"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform{NF<:AbstractFloat}(...)\n\nSpectralTransform struct that contains all parameters and preallocated arrays for the spectral transform.\n\n\n\n\n\n","category":"type"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{AbstractArray{Complex{NF}, 2}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform( alms::AbstractMatrix{Complex{NF}};\n recompute_legendre::Bool=true,\n Grid::Type{<:AbstractGrid}=DEFAULT_GRID)\n\nGenerator function for a SpectralTransform struct based on the size of the spectral coefficients alms and the grid Grid. Recomputes the Legendre polynomials by default.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{NF}, Tuple{Type{NF}, Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Int64, Int64}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"SpectralTransform(\n ::Type{NF},\n Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid},\n lmax::Int64,\n mmax::Int64;\n recompute_legendre,\n legendre_shortcut,\n dealiasing\n) -> SpectralTransform\n\n\nGenerator function for a SpectralTransform struct. With NF the number format, Grid the grid type <:AbstractGrid and spectral truncation lmax,mmax this function sets up necessary constants for the spetral transform. Also plans the Fourier transforms, retrieves the colatitudes, and preallocates the Legendre polynomials (if recompute_legendre == false) and quadrature weights.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.SpectralTransform-Union{Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.SpectralTransform","text":"S = SpectralTransform( map::AbstractGrid;\n recompute_legendre::Bool=true)\n\nGenerator function for a SpectralTransform struct based on the size and grid type of gridded field map. Recomputes the Legendre polynomials by default.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.UV_from_vor!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.UV_from_vor!","text":"UV_from_vor!( U::LowerTriangularMatrix,\n V::LowerTriangularMatrix,\n vor::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGet U,V (=(u,v)*coslat) from vorticity ζ spectral space (divergence D=0) Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity. Then compute zonal and meridional gradients to get U,V.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.UV_from_vordiv!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.UV_from_vordiv!","text":"UV_from_vordiv!(U::LowerTriangularMatrix,\n V::LowerTriangularMatrix,\n vor::LowerTriangularMatrix,\n div::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGet U,V (=(u,v)*coslat) from vorticity ζ and divergence D in spectral space. Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity and velocity potential from divergence. Then compute zonal and meridional gradients to get U,V.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms._divergence!-Union{Tuple{NF}, Tuple{Any, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms._divergence!","text":"_divergence!( kernel,\n div::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform)\n\nGeneric divergence function of vector u,v that writes into the output into div. Generic as it uses the kernel kernel such that curl, div, add or flipsign options are provided through kernel, but otherwise a single function is used.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.curl!-Tuple{LowerTriangularMatrix, LowerTriangularMatrix, LowerTriangularMatrix, SpectralTransform}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.curl!","text":"curl!( curl::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform;\n flipsign::Bool=false,\n add::Bool=false,\n )\n\nCurl of a vector u,v written into curl, curl = ∇×(u,v). u,v are expected to have a 1/coslat-scaling included, then curl is not scaled. flipsign option calculates -∇×(u,v) instead. add option calculates curl += ∇×(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently with flipped u,v -> v,u for the curl.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.divergence!-Tuple{LowerTriangularMatrix, LowerTriangularMatrix, LowerTriangularMatrix, SpectralTransform}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.divergence!","text":"divergence!(div::LowerTriangularMatrix,\n u::LowerTriangularMatrix,\n v::LowerTriangularMatrix,\n S::SpectralTransform{NF};\n flipsign::Bool=false,\n add::Bool=false,\n )\n\nDivergence of a vector u,v written into div, div = ∇⋅(u,v). u,v are expected to have a 1/coslat-scaling included, then div is not scaled. flipsign option calculates -∇⋅(u,v) instead. add option calculates div += ∇⋅(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.get_recursion_factors-Union{Tuple{NF}, Tuple{Type{NF}, Int64, Int64}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.get_recursion_factors","text":"get_recursion_factors( ::Type{NF}, # number format NF\n lmax::Int, # max degree l of spherical harmonics (0-based here)\n mmax::Int # max order m of spherical harmonics\n ) where {NF<:AbstractFloat}\n\nReturns a matrix of recursion factors ϵ up to degree lmax and order mmax of number format NF.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded!-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded!","text":"gridded!( map::AbstractGrid,\n alms::LowerTriangularMatrix,\n S::SpectralTransform)\n\nSpectral transform (spectral to grid) of the spherical harmonic coefficients alms to a gridded field map. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded-Union{Tuple{AbstractMatrix{T}}, Tuple{T}, Tuple{NF}} where {NF, T<:Complex{NF}}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded","text":"gridded(\n alms::AbstractArray{T<:Complex{NF}, 2};\n recompute_legendre,\n Grid\n) -> Any\n\n\nSpectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map. Based on the size of alms the grid type grid, the spatial resolution is retrieved based on the truncation defined for grid. SpectralTransform struct S is allocated to execute gridded(alms,S).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.gridded-Union{Tuple{NF}, Tuple{AbstractMatrix, SpectralTransform{NF}}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.gridded","text":"gridded(\n alms::AbstractMatrix,\n S::SpectralTransform{NF}\n) -> Any\n\n\nSpectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map with precalculated properties based on the SpectralTransform struct S. alms is converted to a LowerTriangularMatrix to execute the in-place gridded!.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.is_power_2-Tuple{Integer}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.is_power_2","text":"true/false = is_power_2(i::Integer)\n\nChecks whether an integer i is a power of 2, i.e. i = 2^k, with k = 0,1,2,3,....\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.roundup_fft-Union{Tuple{Integer}, Tuple{T}} where T<:Integer","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.roundup_fft","text":"m = roundup_fft(n::Int;\n small_primes::Vector{Int}=[2,3,5])\n\nReturns an integer m >= n with only small prime factors 2, 3 (default, others can be specified with the keyword argument small_primes) to obtain an efficiently fourier-transformable number of longitudes, m = 2^i * 3^j * 5^k >= n, with i,j,k >=0.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, SpeedyWeather.RingGrids.AbstractGrid{NF}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral!","text":"spectral!( alms::LowerTriangularMatrix,\n map::AbstractGrid,\n S::SpectralTransform)\n\nSpectral transform (grid to spectral space) from the gridded field map on a grid<:AbstractGrid to a LowerTriangularMatrix of spherical harmonic coefficients alms. Uses FFT in the zonal direction, and a Legendre Transform in the meridional direction exploiting symmetries. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Tuple{AbstractMatrix}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::AbstractMatrix;\n Grid,\n kwargs...\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nConverts map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid, SpectralTransform{NF}}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::SpeedyWeather.RingGrids.AbstractGrid,\n S::SpectralTransform{NF}\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nSpectral transform (grid to spectral) map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral-Union{Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}}, Tuple{NF}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral","text":"spectral(\n map::SpeedyWeather.RingGrids.AbstractGrid{NF};\n recompute_legendre,\n one_more_degree\n) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat\n\n\nConverts map to Grid(map) to execute spectral(map::AbstractGrid;kwargs...).\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_interpolation-Union{Tuple{NF}, Tuple{Type{NF}, LowerTriangularMatrix, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_interpolation","text":"alms_interp = spectral_interpolation( ::Type{NF},\n alms::LowerTriangularMatrix,\n ltrunc::Integer,\n mtrunc::Integer\n ) where NF\n\nReturns a spectral coefficient matrix alms_interp that is alms padded with zeros to interpolate in spectral space. If trunc is smaller or equal to the implicit truncation in alms obtained from its size than spectral_truncation is automatically called instead, returning alms_trunc, a coefficient matrix that is smaller than alms, implicitly setting higher degrees and orders to zero.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_smoothing!-Tuple{LowerTriangularMatrix, Real}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_smoothing!","text":"spectral_smoothing!(A::LowerTriangularMatrix,c;power=1)\n\nSmooth the spectral field A following A = (1-(1-c)∇²ⁿ) with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c>1.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_smoothing-Tuple{LowerTriangularMatrix, Real}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_smoothing","text":"A_smooth = spectral_smoothing(A::LowerTriangularMatrix,c;power=1)\n\nSmooth the spectral field A following A_smooth = (1-c*∇²ⁿ)A with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c<0.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Tuple{AbstractMatrix, Int64}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms,trunc)\n\nTruncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation trunc.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Tuple{AbstractMatrix}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms)\n\nTruncate spectral coefficients alms in-place by setting the upper right triangle to zero. This is to enforce that all coefficients for which the degree l is larger than order m are zero.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Union{Tuple{NF}, Tuple{AbstractMatrix{NF}, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms::AbstractMatrix,ltrunc::Integer,mtrunc::Integer)\n\nTruncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{NF}, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation!","text":"spectral_truncation!(alms::LowerTriangularMatrix,ltrunc::Integer,mtrunc::Integer)\n\nTruncate spectral coefficients alms in-place by setting all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc. Similar to spectral_truncation!(::AbstractMatrix, ...) but skips the upper triangle which is zero by design for LowerTriangularMatrix.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.spectral_truncation-Union{Tuple{NF}, Tuple{Type{NF}, LowerTriangularMatrix, Integer, Integer}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.spectral_truncation","text":"alms_trunc = spectral_truncation(alms,trunc)\n\nReturns a spectral coefficient matrix alms_trunc that is truncated from alms to the size (trunc+1)². alms_trunc only contains those coefficient of alms for which m,l ≤ trunc, and l ≥ m are zero anyway. If trunc is larger than the implicit truncation in alms obtained from its size than spectral_interpolation is automatically called instead, returning alms_interp, a coefficient matrix that is larger than alms with padded zero coefficients.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.ϵlm-Tuple{Int64, Int64}","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.ϵlm","text":"ϵ = ϵ(l,m)\n\nRecursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) with default number format Float64.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.ϵlm-Union{Tuple{NF}, Tuple{Type{NF}, Int64, Int64}} where NF","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.ϵlm","text":"ϵ = ϵ(NF,l,m)\n\nRecursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) and then converted to number format NF.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.∇²!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.∇²!","text":"∇²!( ∇²alms::LowerTriangularMatrix,\n alms::LowerTriangularMatrix,\n S::SpectralTransform;\n add::Bool=false,\n flipsign::Bool=false,\n inverse::Bool=false)\n\nLaplace operator ∇² applied to the spectral coefficients alms in spherical coordinates. The radius R is omitted in the eigenvalues which are precomputed in S. ∇²! is the in-place version which directly stores the output in the first argument ∇²alms.\n\nKeyword arguments\n\nadd=true adds the ∇²(alms) to the output\nflipsign=true computes -∇²(alms) instead\ninverse=true computes ∇⁻²(alms) instead\n\nDefault is add=false, flipsign=false, inverse=false. These options can be combined.\n\n\n\n\n\n","category":"method"},{"location":"speedytransforms/#SpeedyWeather.SpeedyTransforms.∇⁻²!-Union{Tuple{NF}, Tuple{LowerTriangularMatrix{Complex{NF}}, LowerTriangularMatrix{Complex{NF}}, SpectralTransform{NF}}} where NF<:AbstractFloat","page":"Submodule: SpeedyTransforms","title":"SpeedyWeather.SpeedyTransforms.∇⁻²!","text":"∇⁻²!( ∇⁻²alms::LowerTriangularMatrix,\n alms::LowerTriangularMatrix,\n S::SpectralTransform;\n add::Bool=false,\n flipsign::Bool=false)\n\nCalls ∇²!(∇⁻²alms, alms, S; add, flipsign, inverse=true).\n\n\n\n\n\n","category":"method"},{"location":"grids/#Grids","page":"Grids","title":"Grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"The spectral transform (the Spherical Harmonic Transform) in SpeedyWeather.jl supports any ring-based equi-longitude grid. Several grids are already implemented but other can be added. The following pages will describe an overview of these grids and but let's start but how they can be used","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"julia> spectral_grid = SpectralGrid(Grid = FullGaussianGrid)\nSpectralGrid:\n Spectral: T31 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m\n Grid: 4608-element, 48-ring FullGaussianGrid{Float32} (quadratic)\n Resolution: 333km (average)\n Vertical: 8-level SigmaCoordinates","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The life of every SpeedyWeather.jl simulation starts with a SpectralGrid object which defines the resolution in spectral and in grid-point space. The generator SpectralGrid() can take as a keyword argument Grid which can be any of the grids described below. The resolution of the grid, however, is not directly chosen, but determined from the spectral resolution trunc and the dealiasing factor. More in Matching spectral and grid resolution.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: RingGrids is a module too!\nWhile RingGrids is the underlying module that SpeedyWeather.jl uses for data structs on the sphere, the module can also be used independently of SpeedyWeather, for example to interpolate between data on different grids. See RingGrids","category":"page"},{"location":"grids/#Ring-based-equi-longitude-grids","page":"Grids","title":"Ring-based equi-longitude grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"SpeedyWeather.jl's spectral transform supports all ring-based equi-longitude grids. These grids have their grid points located on rings with constant latitude and on these rings the points are equi-spaced in longitude. There is technically no constrain on the spacing of the latitude rings, but the Legendre transform requires a quadrature to map those to spectral space and back. Common choices for latitudes are the Gaussian latitudes which use the Gaussian quadrature, or equi-angle latitudes (i.e. just regular latitudes but excluding the poles) that use the Clenshaw-Curtis quadrature. The longitudes have to be equi-spaced on every ring, which is necessary for the fast Fourier transform, as one would otherwise need to use a non-uniform Fourier transform. In SpeedyWeather.jl the first grid point on any ring can have a longitudinal offset though, for example by spacing 4 points around the globe at 45˚E, 135˚E, 225˚E, and 315˚E. In this case the offset is 45˚E as the first point is not at 0˚E.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: Is the FullClenshawGrid a longitude-latitude grid?\nShort answer: Yes. The FullClenshawGrid is a specific longitude-latitude grid with equi-angle spacing. The most common grids for geoscientific data use regular spacings for 0-360˚E in longitude and 90˚N-90˚S. The FullClenshawGrid does that too, but it does not have a point on the North or South pole, and the central latitude ring sits exactly on the Equator. We name it Clenshaw following the Clenshaw-Curtis quadrature that is used in the Legendre transfrom in the same way as Gaussian refers to the Gaussian quadrature.","category":"page"},{"location":"grids/#Implemented-grids","page":"Grids","title":"Implemented grids","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"All grids in SpeedyWeather.jl are a subtype of AbstractGrid, i.e. <: AbstractGrid. We further distinguish between full, and reduced grids. Full grids have the same number of longitude points on every latitude ring (i.e. points converge towards the poles) and reduced grids reduce the number of points towards the poles to have them more evenly spread out across the globe. More evenly does not necessarily mean that a grid is equal-area, meaning that every grid cell covers exactly the same area (although the shape changes).","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Currently the following full grids <: AbstractFullGrid are implemented","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"FullGaussianGrid, a full grid with Gaussian latitudes\nFullClenshawGrid, a full grid with equi-angle latitudes","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and additionally we have FullHEALPixGrid and FullOctaHEALPixGrid which are the full grid equivalents to the HEALPix grid and the OctaHEALPix grid discussed below. Full grid equivalent means that they have the same latitude rings, but no reduction in the number of points per ring towards the poles and no longitude offset. Other implemented reduced grids are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"OctahedralGaussianGrid, a reduced grid with Gaussian latitudes based on an octahedron\nOctahedralClenshawGrid, similar but based on equi-angle latitudes\nHEALPixGrid, an equal-area grid based on a dodecahedron with 12 faces\nOctaHEALPixGrid, an equal-area grid from the class of HEALPix grids but based on an octahedron.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"An overview of these grids is visualised here","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"(Image: Overview of implemented grids in SpeedyWeather.jl)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Visualised are each grid's grid points (white dots) and grid faces (white lines). All grids shown have 16 latitude rings on one hemisphere, Equator included. The total number of grid points is denoted in the top left of every subplot. The sphere is shaded with grey, orange and turquoise regions to denote the hemispheres in a and b, the 8 octahedral faces c, d,f and the 12 dodecahedral faces (or base pixels) in e. Coastlines are added for orientation.","category":"page"},{"location":"grids/#Grid-resolution","page":"Grids","title":"Grid resolution","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"All grids use the same resolution parameter nlat_half, i.e. the number of rings on one hemisphere, Equator included. The Gaussian grids (full and reduced) do not have a ring on the equator, so their total number of rings nlat is always even and twice nlat_half. Clenshaw-Curtis grids and the HEALPix grids have a ring on the equator such their total number of rings is always odd and one less than the Gaussian grids at the same nlat_half. ","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"info: HEALPix grids do not use Nside as resolution parameter\nThe original formulation for HEALPix grids use N_side, the number of grid points along the edges of each basepixel (8 in the figure above), SpeedyWeather.jl uses nlat_half, the number of rings on one hemisphere, Equator included, for all grids. This is done for consistency across grids. We may use N_side for the documentation or within functions though.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Related: Effective grid resolution and Available horizontal resolutions.","category":"page"},{"location":"grids/#Matching-spectral-and-grid-resolution","page":"Grids","title":"Matching spectral and grid resolution","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"A given spectral resolution can be matched to a variety of grid resolutions. A cubic grid, for example, combines a spectral truncation T with a grid resolution N (=nlat_half) such that T + 1 = N. Using T31 and an O32 is therefore often abbreviated as Tco31 meaning that the spherical harmonics are truncated at l_max=31 in combination with N=32, i.e. 64 latitude rings in total on an octahedral Gaussian grid. In SpeedyWeather.jl the choice of the order of truncation is controlled with the dealiasing parameter in the SpectralGrid construction.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Let J be the total number of rings. Then we have","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"T approx J for linear truncation, i.e. dealiasing = 1\nfrac32T approx J for quadratic truncation, i.e. dealiasing = 2\n2T approx J for cubic truncation, , i.e. dealiasing = 3","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and in general fracm+12T approx J for m-th order truncation. So the higher the truncation order the more grid points are used in combination with the same spectral resolution. A higher truncation order therefore makes all grid-point calculations more expensive, but can represent products of terms on the grid (which will have higher wavenumber components) to a higher accuracy as more grid points are available within a given wavelength. Using a sufficiently high truncation is therefore one way to avoid aliasing. A quick overview of how the grid resolution changes when dealiasing is passed onto SpectralGrid on the FullGaussianGrid","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"trunc dealiasing FullGaussianGrid size\n31 1 64x32\n31 2 96x48\n31 3 128x64\n42 1 96x48\n42 2 128x64\n42 3 192x96\n... ... ...","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"You will obtain this information every time you create a SpectralGrid(;Grid,trunc,dealiasing).","category":"page"},{"location":"grids/#FullGaussianGrid","page":"Grids","title":"Full Gaussian grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#FullClenshawGrid","page":"Grids","title":"Full Clenshaw-Curtis grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#OctahedralGaussianGrid","page":"Grids","title":"Octahedral Gaussian grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"...","category":"page"},{"location":"grids/#HEALPixGrid","page":"Grids","title":"HEALPix grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"Technically, HEALPix grids are a class of grids that tessalate the sphere into faces that are often called basepixels. For each member of this class there are N_varphi basepixels in zonal direction and N_theta basepixels in meridional direction. For N_varphi = 4 and N_theta = 3 we obtain the classical HEALPix grid with N_varphi N_theta = 12 basepixels shown above in Implemented grids. Each basepixel has a quadratic number of grid points in them. There's an equatorial zone where the number of zonal grid points is constant (always 2N, so 32 at N=16) and there are polar caps above and below the equatorial zone with the border at cos(theta) = 23 (theta in colatitudes).","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"Following Górski, 2004[1], the z=cos(theta) colatitude of the j-th ring in the north polar cap, j=1N_side with 2N_side = N is ","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - fracj^23N_side^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and on that ring, the longitude phi of the i-th point (i is the in-ring-index) is at","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2j(i-tfrac12)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The in-ring index i goes from i=14 for the first (i.e. northern-most) ring, i=18 for the second ring and i = 14j for the j-th ring in the northern polar cap.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"In the north equatorial belt j=N_side2N_side this changes to","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = frac43 - frac2j3N_side","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and the longitudes change to (i is always i = 14N_side in the equatorial belt meaning the number of longitude points is constant here)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2N_side(i - fracs2) quad s = (j - N_side + 1) mod 2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The modulo function comes in as there is an alternating longitudinal offset from the prime meridian (see Implemented grids). For the southern hemisphere the grid point locations can be obtained by mirror symmetry.","category":"page"},{"location":"grids/#Grid-cell-boundaries","page":"Grids","title":"Grid cell boundaries","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"The cell boundaries are obtained by setting i = k + 12 or i = k + 12 + j (half indices) into the equations above, such that z(phik), a function for the cosine of colatitude z of index k and the longitude phi is obtained. These are then (northern polar cap)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - frack^23N_side^2left(fracpi2phi_tright)^2 quad z = 1 - frack^23N_side^2left(fracpi2phi_t - piright)^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"with phi_t = phi mod tfracpi2 and in the equatorial belt","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = frac23-frac4k3N_side pm frac8phi3pi","category":"page"},{"location":"grids/#OctaHEALPixGrid","page":"Grids","title":"OctaHEALPix grid","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"While the classic HEALPix grid is based on a dodecahedron, other choices for N_varphi and N_theta in the class of HEALPix grids will change the number of faces there are in zonal/meridional direction. With N_varphi = 4 and N_theta = 1 we obtain a HEALPix grid that is based on an octahedron, which has the convenient property that there are twice as many longitude points around the equator than there are latitude rings between the poles. This is a desirable for truncation as this matches the distances too, 2pi around the Equator versus pi between the poles. N_varphi = 6 N_theta = 2 or N_varphi = 8 N_theta = 3 are other possible choices for this, but also more complicated. See Górski, 2004[1] for further examples and visualizations of these grids.","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"We call the N_varphi = 4 N_theta = 1 HEALPix grid the OctaHEALPix grid, which combines the equal-area property of the HEALPix grids with the octahedron that's also used in the OctahedralGaussianGrid or the OctahedralClenshawGrid. As N_theta = 1 there is no equatorial belt which simplifies the grid. The latitude of the j-th isolatitude ring on the OctaHEALPixGrid is defined by","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - fracj^2N^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"with j=1N, and similarly for the southern hemisphere by symmetry. On this grid N_side = N where N= nlat_half, the number of latitude rings on one hemisphere, Equator included, because each of the 4 basepixels spans from pole to pole and covers a quarter of the sphere. The longitudes with in-ring- index i = 14j are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"phi = fracpi2j(i - tfrac12)","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"and again, the southern hemisphere grid points are obtained by symmetry.","category":"page"},{"location":"grids/#Grid-cell-boundaries-2","page":"Grids","title":"Grid cell boundaries","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"Similar to the grid cell boundaries for the HEALPix grid, the OctaHEALPix grid's boundaries are","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"z = 1 - frack^2N^2left(fracpi2phi_tright)^2 quad z = 1 - frack^2N^2left(fracpi2phi_t - piright)^2","category":"page"},{"location":"grids/","page":"Grids","title":"Grids","text":"The 3N_side^2 in the denominator of the HEALPix grid came simply N^2 for the OctaHEALPix grid and there's no separate equation for the equatorial belt (which doesn't exist in the OctaHEALPix grid).","category":"page"},{"location":"grids/#References","page":"Grids","title":"References","text":"","category":"section"},{"location":"grids/","page":"Grids","title":"Grids","text":"[1]: Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976","category":"page"},{"location":"primitiveequation/#Primitive-equation-model","page":"Primitive equation model","title":"Primitive equation model","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The primitive equations are a hydrostatic approximation of the compressible Navier-Stokes equations for an ideal gas on a rotating sphere. We largely follow the idealised spectral dynamical core developed by GFDL[1] and documented therein[2].","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The primitive equations solved by SpeedyWeather.jl for relative vorticity zeta, divergence mathcalD, logarithm of surface pressure ln p_s, temperature T and specific humidity q are","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"beginaligned\nfracpartial zetapartial t = nabla times (mathbfmathcalP_mathbfu\n+ (f+zeta)mathbfu_perp - W(mathbfu) - R_dT_vnabla ln p_s) \nfracpartial mathcalDpartial t = nabla cdot (mathcalP_mathbfu\n+ (f+zeta)mathbfu_perp - W(mathbfu) - R_dT_vnabla ln p_s) - nabla^2(frac12(u^2 + v^2) + Phi) \nfracpartial ln p_spartial t = -frac1p_s nabla cdot int_0^p_s mathbfudp \nfracpartial Tpartial t = mathcalP_T -nablacdot(mathbfuT) + TmathcalD - W(T) + kappa T_v fracD ln pDt \nfracpartial qpartial t = mathcalP_q -nablacdot(mathbfuq) + qmathcalD - W(q)\nendaligned","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with velocity mathbfu = (uv), rotated velocity mathbfu_perp = (v-u), Coriolis parameter f, W the vertical advection operator, dry air gas constant R_d, virtual temperature T_v, geopotential Phi, pressure p, thermodynamic kappa = R_dc_p with c_p the heat capacity at constant pressure. Horizontal hyper diffusion of the form (-1)^n+1nunabla^2n with coefficient nu and power n is added for every variable that is advected, meaning zeta mathcalD T q, but left out here for clarity, see Horizontal diffusion.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"The parameterizations for the tendencies of uvTq from physical processes are denoted as mathcalP_mathbfu = (mathcalP_u mathcalP_v) mathcalP_T mathcalP_q and are further described in the corresponding sections, see Parameterizations.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"SpeedyWeather.jl implements a PrimitiveWet and a PrimitiveDry dynamical core. For a dry atmosphere, we have q = 0 and the virtual temperature T_v = T equals the temperature (often called absolute to distinguish from the virtual temperature). The terms in the primitive equations and their discretizations are discussed in the following sections. ","category":"page"},{"location":"primitiveequation/#Virtual-temperature","page":"Primitive equation model","title":"Virtual temperature","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"info: In short: Virtual temperature\nVirtual temperature is the temperature dry air would need to have to be as light as moist air. It is used in the dynamical core to include the effect of humidity on the density while replacing density through the ideal gas law with temperature.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"We assume the atmosphere to be composed of two ideal gases: Dry air and water vapour. Given a specific humidity q both gases mix, their pressures p_d, p_w (d for dry, w for water vapour), and densities rho_d rho_w add in a given air parcel that has temperature T. The ideal gas law then holds for both gases","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"beginaligned\np_d = rho_d R_d T \np_w = rho_w R_w T \nendaligned","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with the respective specific gas constants R_d = Rm_d and R_w = Rm_w obtained from the univeral gas constant R divided by the molecular masses of the gas. The total pressure p in the air parcel is","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p = p_d + p_w = (rho_d R_d + rho_w R_w)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"We ultimately want to replace the density rho = rho_w + rho_d in the dynamical core, using the ideal gas law, with the temperature T, so that we never have to calculate the density explicitly. However, in order to not deal with two densities (dry air and water vapour) we would like to replace temperature with a virtual temperature that includes the effect of humidity on the density. So, whereever we use the ideal gas law to replace density with temperature, we would use the virtual temperature, which is a function of the absolute temperature and specific humidity, instead. A higher specific humidity in an air parcel lowers the density as water vapour is lighter than dry air. Consequently, the virtual temperature of moist air is higher than its absolute temperature because warmer air is lighter too at constant pressure. We therefore think of the virtual temperature as the temperature dry air would need to have to be as light as moist air.","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Starting with the last equation, with some manipulation we can write the ideal gas law as total density rho times a gas constant times the virtual temperature that is supposed to be a function of absolute temperature, humidity and some constants","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p = (rho R_d + rho_w (R_w - R_d)) T = rho R_d (1 +\nfrac1 - tfracR_dR_wtfracR_dR_w fracrho_wrho_w + rho_d)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Now we identify","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"mu = frac1 - tfracR_dR_wtfracR_dR_w","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"as some constant that is positive for water vapour being lighter than dry air (tfracR_dR_w = tfracm_wm_d 1) and","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"q = fracrho_wrho_w + rho_d","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"as the specific humidity. Given temperature T and specific humidity q, we can therefore calculate the virtual temperature T_v as","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"T_v = (1 + mu q)T","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"For completeness we want to mention here that the above product, because it is a product of two variables qT has to be computed in grid-point space, see [Spectral Transform]. To obtain an approximation to the virtual temperature in spectral space without expensive transforms one can linearize","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"T_v = T + mu qbarT","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"With a global constant temperature barT, for example obtained from the l=m=0 mode, barT = T_00frac1sqrt4pi but depending on the normalization of the spherical harmonics that factor needs adjustment.","category":"page"},{"location":"primitiveequation/#Vertical-coordinates","page":"Primitive equation model","title":"Vertical coordinates","text":"","category":"section"},{"location":"primitiveequation/#General","page":"Primitive equation model","title":"General","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Let Psi(xyzt) ","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"SpeedyWeather.jl currently uses sigma coordinates for the vertical. ","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"sigma = fracpp_s","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"p_k = sigma_kp_s","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Delta p_k = p_k+1 - p_k = Delta sigma_k p_s","category":"page"},{"location":"primitiveequation/#Geopotential","page":"Primitive equation model","title":"Geopotential","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"In the hydrostatic approximation the vertical momentum equation becomes","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial ppartial z = -rho g","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"meaning that the (negative) vertical pressure gradient is given by the density in that layer times the gravitational acceleration. The heavier the fluid the more the pressure will increase below. Inserting the ideal gas law","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial gzpartial p = -fracR_dT_vp","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"with the geopotential Phi = gz we can write this in terms of the logarithm of pressure","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"fracpartial Phipartial ln p = -R_dT_v","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Note that we use the Virtual temperature here as we replaced the density through the ideal gas law with temperature. Given a vertical temperature profile T_v and the (constant) surface geopotential Phi_s = gz_s where z_s is the orography, we can integrate this equation from the surface to the top to obtain Phi_k on every layer k. The surface is at k = N+tfrac12 (see Vertical coordinates) with N vertical levels. We can integrate the geopotential onto half levels as","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"Phi_k-tfrac12 = Phi_k+tfrac12 + R_dT^v_k(ln p_k+12 - ln p_k-12)","category":"page"},{"location":"primitiveequation/#Surface-pressure-tendency","page":"Primitive equation model","title":"Surface pressure tendency","text":"","category":"section"},{"location":"primitiveequation/#Vertical-advection","page":"Primitive equation model","title":"Vertical advection","text":"","category":"section"},{"location":"primitiveequation/#Pressure-gradient-force","page":"Primitive equation model","title":"Pressure gradient force","text":"","category":"section"},{"location":"primitiveequation/#Temperature-equation","page":"Primitive equation model","title":"Temperature equation","text":"","category":"section"},{"location":"primitiveequation/#implicit_primitive","page":"Primitive equation model","title":"Semi-implicit time stepping","text":"","category":"section"},{"location":"primitiveequation/#Horizontal-diffusion","page":"Primitive equation model","title":"Horizontal diffusion","text":"","category":"section"},{"location":"primitiveequation/#Algorithm","page":"Primitive equation model","title":"Algorithm","text":"","category":"section"},{"location":"primitiveequation/#Scaled-primitive-equations","page":"Primitive equation model","title":"Scaled primitive equations","text":"","category":"section"},{"location":"primitiveequation/#References","page":"Primitive equation model","title":"References","text":"","category":"section"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"primitiveequation/","page":"Primitive equation model","title":"Primitive equation model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The Spectral Dynamical Core","category":"page"},{"location":"lowertriangularmatrices/#lowertriangularmatrices","page":"Submodule: LowerTriangularMatrices","title":"LowerTriangularMatrices","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"LowerTriangularMatrices 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.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"This module defines LowerTriangularMatrix, a lower triangular matrix, which in contrast to LinearAlgebra.LowerTriangular does not store the entries above the diagonal. SpeedyWeather.jl uses LowerTriangularMatrix which is defined as a subtype of AbstractMatrix to store the spherical harmonic coefficients (see Spectral packing). ","category":"page"},{"location":"lowertriangularmatrices/#Creation-of-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Creation of LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"A LowerTriangularMatrix can be created using zeros,ones,rand, or randn","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> using SpeedyWeather.LowerTriangularMatrices\n\njulia> L = rand(LowerTriangularMatrix{Float32},5,5)\n5×5 LowerTriangularMatrix{Float32}:\n 0.912744 0.0 0.0 0.0 0.0\n 0.0737592 0.230592 0.0 0.0 0.0\n 0.799679 0.0765255 0.888098 0.0 0.0\n 0.670835 0.997938 0.505276 0.492966 0.0\n 0.949321 0.193692 0.793623 0.152817 0.357968","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"or the undef initializor LowerTriangularMatrix{Float32}(undef,3,3). The element type is arbitrary though, you can use any type T too.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Alternatively, it can be created through conversion from Matrix, which drops the upper triangle entries and sets them to zero","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> M = rand(Float16,3,3)\n3×3 Matrix{Float16}:\n 0.2222 0.694 0.3452\n 0.2158 0.04443 0.274\n 0.9746 0.793 0.6294\n\njulia> LowerTriangularMatrix(M)\n3×3 LowerTriangularMatrix{Float16}:\n 0.2222 0.0 0.0\n 0.2158 0.04443 0.0\n 0.9746 0.793 0.6294","category":"page"},{"location":"lowertriangularmatrices/#Indexing-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Indexing LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"LowerTriangularMatrix supports two types of indexing: 1) by denoting two indices, column and row [l,m] or 2) by denoting a single index [lm]. The double index works as expected","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L\n3×3 LowerTriangularMatrix{Float16}:\n 0.1499 0.0 0.0\n 0.1177 0.478 0.0\n 0.1709 0.756 0.3223\n\njulia> L[2,2]\nFloat16(0.478)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"But the single index skips the zero entries in the upper triangle, i.e.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L[4]\nFloat16(0.478)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"which, important, is different from single indices of an AbstractMatrix","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> Matrix(L)[4]\nFloat16(0.0)","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"In performance-critical code a single index should be used, as this directly maps to the index of the underlying data vector. The double index is somewhat slower as it first has to be converted to the corresponding single index.","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Consequently, many loops in SpeedyWeather.jl are build with the following structure","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"n,m = size(L)\nij = 0\nfor j in 1:m\n for i in j:n\n ij += 1\n L[ij] = i+j\n end\nend","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"which loops over all lower triangle entries of L::LowerTriangularMatrix and the single index ij is simply counted up. However, one could also use [i,j] as indices in the loop body or to perform any calculation (i+j here). An iterator over all entries in the lower triangle can be created by","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"for ij in eachindex(L)\n # do something\nend","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"The setindex! functionality of matrixes will throw a BoundsError when trying to write into the upper triangle of a LowerTriangularMatrix, for example","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L[2,1] = 0 # valid index\n0\n\njulia> L[1,2] = 0 # invalid index in the upper triangle\nERROR: BoundsError: attempt to access 3×3 LowerTriangularMatrix{Float32} at index [1, 2]","category":"page"},{"location":"lowertriangularmatrices/#Linear-algebra-with-LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"Linear algebra with LowerTriangularMatrix","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"The LowerTriangularMatrices module's main purpose is not linear algebra, and it's implementation may not be efficient, however, many operations work as expected","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"julia> L = rand(LowerTriangularMatrix{Float32},3,3)\n3×3 LowerTriangularMatrix{Float32}:\n 0.57649 0.0 0.0\n 0.348685 0.875371 0.0\n 0.881923 0.850552 0.998306\n\njulia> L + L\n3×3 LowerTriangularMatrix{Float32}:\n 1.15298 0.0 0.0\n 0.697371 1.75074 0.0\n 1.76385 1.7011 1.99661\n\njulia> L * L\n3×3 Matrix{Float32}:\n 0.332341 0.0 0.0\n 0.506243 0.766275 0.0\n 1.68542 1.59366 0.996616","category":"page"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Note, however, that the latter includes a conversion to Matrix, which is true for many operations, including inv or \\. Hence when trying to do more sophisticated linear algebra with LowerTriangularMatrix we quickly leave lower triangular-land and go back to normal matrix-land.","category":"page"},{"location":"lowertriangularmatrices/#Function-and-type-index","page":"Submodule: LowerTriangularMatrices","title":"Function and type index","text":"","category":"section"},{"location":"lowertriangularmatrices/","page":"Submodule: LowerTriangularMatrices","title":"Submodule: LowerTriangularMatrices","text":"Modules = [SpeedyWeather.LowerTriangularMatrices]","category":"page"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","text":"L = LowerTriangularMatrix{T}(v::Vector{T},m::Int,n::Int)\n\nA lower triangular matrix implementation that only stores the non-zero entries explicitly. L<:AbstractMatrix although in general we have L[i] != Matrix(L)[i], the former skips zero entries, tha latter includes them.\n\n\n\n\n\n","category":"type"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix-Union{Tuple{AbstractMatrix{T}}, Tuple{T}} where T","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.LowerTriangularMatrix","text":"L = LowerTriangularMatrix(M)\n\nCreate a LowerTriangularMatrix L from Matrix M by copying over the non-zero elements in M.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#Base.fill!-Union{Tuple{T}, Tuple{LowerTriangularMatrix{T}, Any}} where T","page":"Submodule: LowerTriangularMatrices","title":"Base.fill!","text":"fill!(L::LowerTriangularMatrix,x)\n\nFills the elements of L with x. Faster than fill!(::AbstractArray,x) as only the non-zero elements in L are assigned with x.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.eachharmonic-Tuple{LowerTriangularMatrix}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.eachharmonic","text":"unit_range = eachharmonic(L::LowerTriangular)\n\ncreates unit_range::UnitRange to loop over all non-zeros in a LowerTriangularMatrix L. Like eachindex but skips the upper triangle with zeros in L.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.eachharmonic-Tuple{Vararg{LowerTriangularMatrix}}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.eachharmonic","text":"unit_range = eachharmonic(Ls::LowerTriangularMatrix...)\n\ncreates unit_range::UnitRange to loop over all non-zeros in the LowerTriangularMatrices provided as arguments. Checks bounds first. All LowerTriangularMatrix's need to be of the same size. Like eachindex but skips the upper triangle with zeros in L.\n\n\n\n\n\n","category":"method"},{"location":"lowertriangularmatrices/#SpeedyWeather.LowerTriangularMatrices.ij2k-Tuple{Integer, Integer, Integer}","page":"Submodule: LowerTriangularMatrices","title":"SpeedyWeather.LowerTriangularMatrices.ij2k","text":"k = ij2k( i::Integer, # row index of matrix\n j::Integer, # column index of matrix\n m::Integer) # number of rows in matrix\n\nConverts the index pair i,j of an mxn LowerTriangularMatrix L to a single index k that indexes the same element in the corresponding vector that stores only the lower triangle (the non-zero entries) of L.\n\n\n\n\n\n","category":"method"},{"location":"conventions/#Style-and-convention-guide","page":"Style and convention guide","title":"Style and convention guide","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"In SpeedyWeather.jl we've been following the several conventions that are documented here.","category":"page"},{"location":"conventions/#Variable-naming","page":"Style and convention guide","title":"Variable naming","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"The prognostic variables in spectral space are called","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" vor # Vorticity of horizontal wind field\n div # Divergence of horizontal wind field\n temp # Absolute temperature [K]\n pres_surf # Logarithm of surface pressure [log(Pa)]\n humid # Specific humidity [g/kg]","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"their transforms into grid-point space get a _grid suffix, their tendencies a _tend suffix. Further derived diagnostic dynamic variables are","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" u\n v\n geopot\n ...","category":"page"},{"location":"conventions/#Preallocation","page":"Style and convention guide","title":"Preallocation","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"All arrays representing variables are preallocated and grouped into two structs","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" Prog::PrognosticVariables\n Diag::DiagnosticVariables","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"The Diag struct contains further structs which represent the grid-point transformations of the prognostic variables and their tendencies.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":" gridvars::GridVariables\n tendencies::Tendencies\n ...","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Constant arrays are grouped into several structs","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Boundaries","category":"page"},{"location":"conventions/#Julian-conventions","page":"Style and convention guide","title":"Julian conventions","text":"","category":"section"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"We follow Julia's style guide and highlight here some important aspects of it.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Bang (!) convention. A function func does not change its input arguments, however, func! does.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Hence, func! is often the in-place version of func, avoiding as much memory allocation as possible and often changing its first argument, e.g. func!(out,in) so that argument in is used to calculate out which has been preallocated before function call.","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"Number format flexibility. Numeric literals such as 2.0 or 1/3 are only used in the model setup","category":"page"},{"location":"conventions/","page":"Style and convention guide","title":"Style and convention guide","text":"but avoided throughout the code to obtain a fully number format-flexible package using the number format NF as a compile-time variable throughout the code. This often leads to overly specific code whereas a Real would generally suffice. However, this is done to avoid any implicit type conversions.","category":"page"},{"location":"shallowwater/#Shallow-water-model","page":"Shallow water model","title":"Shallow water model","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The shallow water model describes the evolution of a 2D flow described by its velocity and an interface height that conceptually represents pressure. A divergent flow affects the interface height which in turn can impose a pressure gradient force onto the flow. The dynamics include advection, forces, dissipation, and continuity.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The following description of the shallow water model largely follows the idealized models with spectral dynamics developed at the Geophysical Fluid Dynamics Laboratory[1]: The Shallow Water Equations[2].","category":"page"},{"location":"shallowwater/#Shallow-water-equations","page":"Shallow water model","title":"Shallow water equations","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The shallow water equations of velocity mathbfu = (uv) and interface height eta (i.e. the deviation from the fluid's rest height H) are, formulated in terms of relative vorticity zeta = nabla times mathbfu, divergence mathcalD = nabla cdot mathbfu","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial zetapartial t + nabla cdot (mathbfu(zeta + f)) =\nnabla times mathbfF + (-1)^n+1nunabla^2nzeta \nfracpartial mathcalDpartial t - nabla times (mathbfu(zeta + f)) =\nnabla cdot mathbfF -nabla^2(tfrac12(u^2 + v^2) + geta) + (-1)^n+1nunabla^2nmathcalD \nfracpartial etapartial t + nabla cdot (mathbfuh) = F_eta\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"We denote timet, Coriolis parameter f, a forcing vector mathbfF = (F_uF_v), hyperdiffusion (-1)^n+1 nu nabla^2n (n is the hyperdiffusion order, see Horizontal diffusion), gravitational acceleration g, dynamic layer thickness h, and a forcing for the interface height F_eta. In the shallow water model the dynamics layer thickness h is","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"h = eta + H - H_b","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"that is, the layer thickness at rest H plus the interface height eta minus orography H_b.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"In the shallow water system the flow can be described through uv or zetamathcalD which are related through the stream function Psi and the velocity potential Phi (which is zero in the Barotropic vorticity equation).","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nzeta = nabla^2 Psi \nmathcalD = nabla^2 Phi \nmathbfu = nabla^perp Psi + nabla Phi\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"With nabla^perp being the rotated gradient operator, in cartesian coordinates xy: nabla^perp = (-partial_y partial_x). See Derivatives in spherical coordinates for further details. Especially because the inversion of the Laplacian and the gradients of Psi Phi can be computed in a single pass, see U,V from vorticity and divergence.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The divergence/curl of the vorticity flux mathbfu(zeta + f) are combined with the divergence/curl of the forcing vector mathbfF, as","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\n- nabla cdot (mathbfu(zeta + f)) + nabla times mathbfF =\nnabla times (mathbfF + mathbfu_perp(zeta + f)) \nnabla times (mathbfu(zeta + f)) + nabla cdot mathbfF =\nnabla cdot (mathbfF + mathbfu_perp(zeta + f))\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"equivalently to how this is done in the Barotropic vorticity equation with mathbfu_perp = (v-u).","category":"page"},{"location":"shallowwater/#Algorithm","page":"Shallow water model","title":"Algorithm","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"0. Start with initial conditions of relative vorticity zeta_lm, divergence D_lm, and interface height eta_lm in spectral space and transform this model state to grid-point space:","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Invert the Laplacian of zeta_lm to obtain the stream function Psi_lm in spectral space\nInvert the Laplacian of D_lm to obtain the velocity potential Phi_lm in spectral space\nobtain velocities U_lm = (cos(theta)u)_lm V_lm = (cos(theta)v)_lm from nabla^perpPsi_lm + nablaPhi_lm\nTransform velocities U_lm, V_lm to grid-point space UV\nUnscale the cos(theta) factor to obtain uv\nTransform zeta_lm, D_lm, eta_lm to zeta D eta in grid-point space","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Now loop over","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Compute the forcing vector mathbfF = (F_uF_v) for u and v\nMultiply uv with zeta+f in grid-point space\nAdd A = F_u + v(zeta + f) and B = F_v - u(zeta + f)\nTransform these vector components to spectral space A_lm, B_lm\nCompute the curl of (AB)_lm in spectral space which is the tendency of zeta_lm\nCompute the divergence of (AB)_lm in spectral space which is the tendency of mathcalD_lm\nCompute the kinetic energy frac12(u^2 + v^2) and transform to spectral space\nAdd to the kinetic energy the \"geopotential\" geta_lm in spectral space to obtain the Bernoulli potential\nTake the Laplacian of the Bernoulli potential and subtract from the divergence tendency\nCompute the volume fluxes uhvh in grid-point space via h = eta + H - H_b\nTransform to spectral space and take the divergence for -nabla cdot (mathbfuh) which is the tendency for eta\nAdd possibly forcing F_eta for eta in spectral space\nCorrect the tendencies following the semi-implicit time integration to prevent fast gravity waves from causing numerical instabilities\nCompute the horizontal diffusion based on the zetamathcalD tendencies\nCompute a leapfrog time step as described in Time integration with a Robert-Asselin and Williams filter\nTransform the new spectral state of zeta_lm, mathcalD_lm, eta_lm to grid-point uvzetamathcalDeta as described in 0.\nPossibly do some output\nRepeat from 1.","category":"page"},{"location":"shallowwater/#implicit_swm","page":"Shallow water model","title":"Semi-implicit time integration","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Probably the biggest advantage of a spectral model is its ability to solve (parts of) the equations implicitly a low computational cost. The reason is that a linear operator can be easily inverted in spectral space, removing the necessity to solve large equation systems. An operation like Psi = nabla^-2zeta in grid-point space is costly because it requires a global communication, coupling all grid points. In spectral space nabla^2 is a diagonal operator, meaning that there is no communication between harmonics and its inversion is therefore easily done on a mode-by-mode basis of the harmonics.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"This can be made use of when facing time stepping constraints with explicit schemes, where ridiculuously small time steps to resolve fast waves would otherwise result in a horribly slow simulation. In the shallow water system there are gravity waves that propagate at a wave speed of sqrtgH (typically 300m/s), which, in order to not violate the CFL criterion for explicit time stepping, would need to be resolved. Therefore, treating the terms that are responsible for gravity waves implicitly would remove that time stepping constraint and allows us to run the simulation at the time step needed to resolve the advective motion of the atmosphere, which is usually one or two orders of magnitude longer than gravity waves.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"In the following we will describe how the semi implicit time integration can be combined with the Leapfrog time stepping and the Robert-Asselin and Williams filter for a large increase in numerical stability with gravity waves. Let V_i be the model state of all prognostic variables at time step i, the leapfrog time stepping is then","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"fracV_i+1 - V_i-12Delta t = N(V_i)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"with the right-hand side operator N evaluated at the current time step i. Now the idea is to split the terms in N into non-linear terms that are evaluated explicitly in N_E and into the linear terms N_I, solved implicitly, that are responsible for the gravity waves. We could already assume to evaluate N_I at i+1, but in fact, we can introduce alpha in 01 so that for alpha=0 we use i-1 (i.e. explicit), for alpha=12 it is centred implicit tfrac12N_I(V_i-1) + tfrac12N_I(V_i+1), and for alpha=1 a fully backwards scheme N_I(V_i+1) evaluated at i+1.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"fracV_i+1 - V_i-12Delta t = N_E(V_i) + alpha N_I(V_i+1) + (1-alpha)N_I(V_i-1)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Let delta V = tfracV_i+1 - V_i-12Delta t be the tendency we need for the Leapfrog time stepping. Introducing xi = 2alphaDelta t we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta V = N_E(V_i) + N_I(V_i-1) + xi N_I(delta V)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"because N_I is a linear operator. This is done so that we can solve for delta V by inverting N_I, but let us gather the other terms as G first.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"G = N_E(V_i) + N_I(V_i-1) = N(V_i) + N_I(V_i-1 - V_i)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"For the shallow water equations we will only make use of the last formulation, meaning we first evaluate the whole right-hand side N(V_i) at the current time step as we would do with fully explicit time stepping but then add the implicit terms N_I(V_i-1 - V_i) afterwards to move those terms from i to i-1. Note that we could also directly evaluate the implicit terms at i-1 as it is suggested in the previous formulation N_E(V_i) + N_I(V_i-1), the result would be the same. But in general it can be more efficient to do it one or the other way, and in fact it is also possible to combine both ways. This will be discussed in the semi-implicit time stepping for the primitive equations.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"We can now implicitly solve for delta V by","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta V = (1-xi N_I)^-1G","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"So what is N_I? In the shallow water system the gravity waves are caused by","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial mathcalDpartial t = -gnabla^2eta \nfracpartial etapartial t = -HmathcalD\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"which is a linearization of the equations around a state of rest with uniform constant layer thickness h = H. The continuity equation with the -nabla(mathbfuh) term, for example, is linearized to -nabla(mathbfuH) = -HmathcalD. The divergence and continuity equations can now be written following the delta V = G + xi N_I(delta V) formulation from above as a coupled system (The vorticity equation is zero for the linear gravity wave equation in the shallow water equations, hence no semi-implicit correction has to be made to the vorticity tendency).","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\ndelta mathcalD = G_mathcalD - xi g nabla^2 delta eta \ndelta eta = G_mathcaleta - xi H deltamathcalD\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"with","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nG_mathcalD = N_mathcalD - xi g nabla^2 (eta_i-1 - eta_i) \nG_mathcaleta = N_eta - xi H (mathcalD_i-1 - mathcalD_i)\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Inserting the second equation into the first, we can first solve for delta mathcalD, and then for delta eta. Reminder that we do this in spectral space to every harmonic independently, so the Laplace operator nabla^2 = -l(l+1) takes the form of its eigenvalue -l(l+1) (normalized to unit sphere, as are the scaled shallow water equations) and its inversion is therefore just the inversion of this scalar.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta D = fracG_mathcalD - xi gnabla^2 G_eta1 - xi^2 H nabla^2 = S^-1(G_mathcalD - xi gnabla^2 G_eta) ","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Where the last formulation just makes it clear that S = 1 - xi^2 H nabla^2 is the operator to be inverted. delta eta is then obtained via insertion as written above. Equivalently, by adding a superscript l for every degree of the spherical harmonics, we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"delta mathcalD^l = fracG_mathcalD^l + xi g l(l+1) G_eta^l1 + xi^2 H l(l+1)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The idea of the semi-implicit time stepping is now as follows:","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Evaluate the right-hand side explicitly at time step i to obtain the explicit, preliminary tendencies N_mathcalDN_eta (and N_zeta without a need for semi-implicit correction)\nMove the implicit terms from i to i-1 when calculating G_mathcalD G_eta\nSolve for delta mathcalD, the new, corrected tendency for divergence.\nWith delta mathcalD obtain delta eta, the new, corrected tendency for eta.\nApply horizontal diffusion as a correction to N_zeta delta mathcalD as outlined in Horizontal diffusion.\nLeapfrog with tendencies that have been corrected for both semi-implicit and diffusion.","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Some notes on the semi-implicit time stepping","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The inversion of the semi-implicit time stepping depends on delta t, that means every time the time step changes, the inversion has to be recalculated.\nYou may choose alpha = 12 to dampen gravity waves but initialisation shocks still usually kick off many gravity waves that propagate around the sphere for many days.\nWith increasing alpha 12 these waves are also slowed down, such that for alpha = 1 they quickly disappear in several hours.\nUsing the scaled shallow water equations the time step delta t has to be the scaled time step tildeDelta t = delta tR which is divided by the radius R. Then we use the normalized eigenvalues -l(l+1) which also omit the 1R^2 scaling, see scaled shallow water equations for more details.","category":"page"},{"location":"shallowwater/#scaled_swm","page":"Shallow water model","title":"Scaled shallow water equations","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"Similar to the scaled barotropic vorticity equations, SpeedyWeather.jl scales in the shallow water equations. The vorticity and the divergence equation are scaled with R^2, the radius of the sphere squared, but the continuity equation is scaled with R. We also combine the vorticity flux and forcing into a single divergence/curl operation as mentioned in Shallow water equations above","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"beginaligned\nfracpartial tildezetapartial tildet =\ntildenabla times (tildemathbfF + mathbfu_perp(tildezeta + tildef)) +\n(-1)^n+1tildenutildenabla^2ntildezeta \nfracpartial tildemathcalDpartial tildet =\ntildenabla cdot (tildemathbfF + mathbfu_perp(tildezeta + tildef)) -\ntildenabla^2left(tfrac12(u^2 + v^2) + geta right) +\n(-1)^n+1tildenutildenabla^2ntildemathcalD \nfracpartial etapartial tildet =\n- tildenabla cdot (mathbfuh) + tildeF_eta\nendaligned","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"As in the scaled barotropic vorticity equations, one needs to scale the time step, the Coriolis force, the forcing and the diffusion coefficient, but then enjoys the luxury of working with dimensionless gradient operators. As before, SpeedyWeather.jl will scale vorticity and divergence just before the model integration starts and unscale them upon completion and for output. In the semi-implicit time integration we solve an equation that also has to be scaled. It is with radius squared scaling (because it is the tendency for the divergence equation which is also scaled with R^2)","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"R^2 delta D = R^2fracG_mathcalD - xi gnabla^2 G_eta1 - xi^2 H nabla^2","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"As G_eta is only scaled with R we have","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"tildedelta D = fractildeG_mathcalD - tildexi gtildenabla^2 tildeG_eta1 - tildexi^2 H tildenabla^2","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"The R^2 normalizes the Laplace operator in the numerator, but using the scaled G_eta we also scale xi (which is convenient, because the time step within is the one we use anyway). The denominator S does not actually change because xi^2nabla^2 = tildexi^2tildenabla^2 as xi^2 is scaled with 1R^2, but the Laplace operator with R^2. So overall we just have to use the scaled time step tildeDelta t and normalized eigenvalues for tildenabla^2.","category":"page"},{"location":"shallowwater/#References","page":"Shallow water model","title":"References","text":"","category":"section"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"[1]: Geophysical Fluid Dynamics Laboratory, Idealized models with spectral dynamics","category":"page"},{"location":"shallowwater/","page":"Shallow water model","title":"Shallow water model","text":"[2]: Geophysical Fluid Dynamics Laboratory, The Shallow Water Equations.","category":"page"},{"location":"extending/#New-model-setups","page":"Extending SpeedyWeather","title":"New model setups","text":"","category":"section"},{"location":"extending/","page":"Extending SpeedyWeather","title":"Extending SpeedyWeather","text":"more to come...","category":"page"},{"location":"spectral_transform/#Spherical-Harmonic-Transform","page":"Spherical harmonic transform","title":"Spherical Harmonic Transform","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The following sections outline the implementation of the spherical harmonic transform (in short spectral transform) between the coefficients of the spherical harmonics (the spectral space) and the grid space which can be any of the Implemented grids as defined by RingGrids. This includes the classical full Gaussian grid, a regular longitude-latitude grid called the full Clenshaw grid (FullClenshawGrid), ECMWF's octahedral Gaussian grid[Malardel2016], and HEALPix grids[Gorski2004]. SpeedyWeather.jl's spectral transform module SpeedyTransforms is grid-flexible and can be used with any of these, see Grids.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: SpeedyTransforms is a module too!\nSpeedyTransform is the underlying module that SpeedyWeather imports to transform between spectral and grid-point space, which also implements Derivatives in spherical coordinates. You can use this module independently of SpeedyWeather for spectral transforms, see SpeedyTransforms.","category":"page"},{"location":"spectral_transform/#Inspiration","page":"Spherical harmonic transform","title":"Inspiration","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral transform implemented by SpeedyWeather.jl follows largely Justin Willmert's CMB.jl and SphericalHarmonicTransforms.jl package and makes use of AssociatedLegendrePolynomials.jl and FFTW.jl for the Fourier transform. Justin described his work in a Blog series [Willmert2020].","category":"page"},{"location":"spectral_transform/#Spherical-harmonics","page":"Spherical harmonic transform","title":"Spherical harmonics","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spherical harmonics Y_lm of degree l and order m over the longitude phi = (02pi) and colatitudes theta = (-pi2pi2), are","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Y_lm(phi theta) = lambda_l^m(sintheta) e^imphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with lambda_l^m being the pre-normalized associated Legendre polynomials, and e^imphi are the complex exponentials (the Fourier modes). Together they form a set of orthogonal basis functions on the sphere. For an interactive visualisation of the spherical harmonics, see here.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: Latitudes versus colatitudes\nThe implementation of the spectral transforms in SpeedyWeather.jl uses colatitudes theta = (0pi) (0 at the north pole) but the dynamical core uses latitudes theta = (-pi2pi2) (pi2 at the north pole). Note: We may also use latitudes in the spherical harmonic transform in the future for consistency. ","category":"page"},{"location":"spectral_transform/#synthesis","page":"Spherical harmonic transform","title":"Synthesis (spectral to grid)","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The synthesis (or inverse transform) takes the spectral coefficients a_lm and transforms them to grid-point values f(phitheta) (for the sake of simplicity first regarded as continuous). The synthesis is a linear combination of the spherical harmonics Y_lm with non-zero coefficients.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"f(phitheta) = sum_l=0^infty sum_m=-l^l a_lm Y_lm(phitheta)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"We obtain an approximation with a finite set of a_lm by truncating the series in both degree l and order m somehow. Most commonly, a triangular truncation is applied, such that all degrees after l = l_max are discarded. Triangular because the retained array of the coefficients a_lm looks like a triangle. Other truncations like rhomboidal have been studied[Daley78] but are rarely used since. Choosing l_max also constrains m_max and determines the (horizontal) spectral resolution. In SpeedyWeather.jl this resolution as chosen as trunc when creating the SpectralGrid.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For f being a real-valued there is a symmetry","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"a_l-m = (-1)^m a^*_l+m","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"meaning that the coefficients at -m and m are the same, but the sign of the real and imaginary component can be flipped, as denoted with the (-1)^m and the complex conjugate a_lm^*. As we are only dealing with real-valued fields anyway, we therefore never have to store the negative orders -m and end up with a lower triangular matrix of size (l_max+1) times (m_max+1) or technically (T+1)^2 where T is the truncation trunc. One is added here because the degree l and order m use 0-based indexing but sizes (and so is Julia's indexing) are 1-based.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For correctness we want to mention here that vector quantities require one more degree l due to the recurrence relation in the Meridional derivative. Hence for practical reasons all spectral fields are represented as a lower triangular matrix of size (m_max + 2) times (m_max +1). And the scalar quantities would just not make use of that last degree, and its entries would be simply zero. We will, however, for the following sections ignore this and only discuss it again in Meridional derivative.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Another consequence of the symmetry mentioned above is that the zonal harmonics, meaning a_lm=0 have no imaginary component. Because these harmonics are zonally constant, a non-zero imaginary component would rotate them around the Earth's axis, which, well, doesn't actually change a real-valued field. ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Following the notation of [Willmert2020] we can therefore write the truncated synthesis as","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"f(phitheta) = sum_l=0^l_max sum_m=0^l (2-delta_m0) a_lm Y_lm(phitheta)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The (2-delta_m0) factor using the Kronecker delta is used here because of the symmetry we have to count both the m-m order pairs (hence the 2) except for the zonal harmonics which do not have a pair.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Another symmetry arises from the fact that the spherical harmonics are either symmetric or anti-symmetric around the Equator. There is an even/odd combination of degrees and orders so that the sign flips like a checkerboard","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Y_lm(phipi-theta) = (-1)^l+mY_lm(phiphi)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This means that one only has to compute the Legendre polynomials for one hemisphere and the other one follows with this equality.","category":"page"},{"location":"spectral_transform/#analysis","page":"Spherical harmonic transform","title":"Analysis (grid to spectral)","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Starting in grid-point space we can transform a field f(lambdatheta) into the spectral space of the spherical harmonics by","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"a_lm = int_0^2pi int_0^pi f(phitheta) Y_lm(phitheta) sin theta dtheta dphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Note that this notation again uses colatitudes theta, for latitudes the sintheta becomes a costheta and the bounds have to be changed accordingly to (-fracpi2fracpi2). A discretization with N grid points at location (phi_itheta_i), indexed by i can be written as [Willmert2020]","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"hata_lm = sum_i f(phi_itheta_i) Y_lm(phi_itheta_i) sin theta_i Deltatheta Deltaphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The hat on a just means that it is an approximation, or an estimate of the true a_lm approx hata_lm. We can essentially make use of the same symmetries as already discussed in Synthesis. Splitting into the Fourier modes e^imphi and the Legendre polynomials lambda_l^m(costheta) (which are defined over -11 so the costheta argument maps them to colatitudes) we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"hata_lm = sum_j left sum_i f(phi_itheta_j) e^-imphi_i right lambda_lm(theta_j) sin theta_j Deltatheta Deltaphi","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"So the term in brackets can be separated out as long as the latitude theta_j is constant, which motivates us to restrict the spectral transform to grids with iso-latitude rings, see Grids. Furthermore, this term can be written as a fast Fourier transform, if the phi_i are equally spaced on the latitude ring j. Note that the in-ring index i can depend on the ring index j, so that one can have reduced grids, which have fewer grid points towards the poles, for example. Also the Legendre polynomials only have to be computed for the colatitudes theta_j (and in fact only one hemisphere, due to the north-south symmetry discussed in the Synthesis). It is therefore practical and efficient to design a spectral transform implementation for ring grids, but there is no need to hardcode a specific grid.","category":"page"},{"location":"spectral_transform/#Spectral-packing","page":"Spherical harmonic transform","title":"Spectral packing","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Spectral packing is the way how the coefficients a_lm of the spherical harmonics of a given spectral field are stored in an array. SpeedyWeather.jl uses the conventional spectral packing of degree l and order m as illustrated in the following image (Cyp, CC BY-SA 3.0, via Wikimedia Commons)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Every row represents an order l geq 0, starting from l=0 at the top. Every column represents an order m geq 0, starting from m=0 on the left. The coefficients of these spherical harmonics are directly mapped into a matrix a_lm as ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":" m \nl a_00 \n a_10 a_11 \n a_20 a_12 a_22 \n a_30 a_13 a_23 a_33","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which is consistently extended for higher degrees and orders. Consequently, all spectral fields are lower-triangular matrices with complex entries. The upper triangle excluding the diagonal are zero. Note that internally vector fields include an additional degree, such that l_max = m_max + 1 (see Derivatives in spherical coordinates for more information). The harmonics with a_l0 (the first column) are also called zonal harmonics as they are constant with longitude phi. The harmonics with a_ll (the main diagonal) are also called sectoral harmonics as they essentially split the sphere into 2l sectors in longitude phi without a zero-crossing in latitude.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"For correctness it is mentioned here that SpeedyWeather.jl uses a LowerTriangularMatrix type to store the spherical harmonic coefficients. By doing so, the upper triangle is actually not explicitly stored and the data technically unravelled into a vector, but this is hidden as much as possible from the user. For more details see LowerTriangularMatrices.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"info: Array indices\nFor a spectral field a note that due to Julia's 1-based indexing the coefficient a_lm is obtained via a[l+1,m+1]. Alternatively, we may index over 1-based l,m but a comment is usually added for clarification.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Fortran SPEEDY does not use the same spectral packing as SpeedyWeather.jl. The alternative packing lm therein uses l=m and m=l-m as summarized in the following table.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"degree l order m l=m m=l-m\n0 0 0 0\n1 0 0 1\n1 1 1 0\n2 0 0 2\n2 1 1 1\n2 2 2 0\n3 0 0 3\n... ... ... ...","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This alternative packing uses the top-left triangle of a coefficient matrix, and the degrees and orders from above are stored at the following indices","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":" m \nl a_00 a_10 a_20 a_30\n a_11 a_21 a_31 \n a_22 a_32 \n a_33 ","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This spectral packing is not used in SpeedyWeather.jl but illustrated here for completeness and comparison with Fortran SPEEDY.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"SpeedyWeather.jl uses triangular truncation such that only spherical harmonics with l leq l_max and m leq m_max are explicitly represented. This is usually described as Tm_max, with l_max = m_max (although in vector quantities require one more degree l in the recursion relation of meridional gradients). For example, T31 is the spectral resolution with l_max = m_max = 31. Note that the degree l and order m are mathematically 0-based, such that the corresponding coefficient matrix is of size 32x32.","category":"page"},{"location":"spectral_transform/#Available-horizontal-resolutions","page":"Spherical harmonic transform","title":"Available horizontal resolutions","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Technically, SpeedyWeather.jl supports arbitrarily chosen resolution parameter trunc when creating the SpectralGrid that refers to the highest non-zero degree l_max that is resolved in spectral space. SpeedyWeather.jl will always try to choose an easily-Fourier transformable[FFT] size of the grid, but as we use FFTW.jl there is quite some flexibility without performance sacrifice. However, this has traditionally lead to typical resolutions that we also use for testing we therefore recommend to use. They are as follows with more details below","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"trunc nlon nlat Delta x\n31 (default) 96 48 400 km\n42 128 64 312 km\n63 192 96 216 km\n85 256 128 165 km\n127 384 192 112 km\n170 512 256 85 km\n255 768 384 58 km\n341 1024 512 43 km\n511 1536 768 29 km\n682 2048 1024 22 km\n1024 3072 1536 14 km\n1365 4092 2048 11 km","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Some remarks on this table","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This assumes the default quadratic truncation, you can always adapt the grid resolution via the dealiasing option, see Matching spectral and grid resolution\nnlat refers to the total number of latitude rings, see Grids. With non-Gaussian grids, nlat will be one one less, e.g. 47 instead of 48 rings.\nnlon is the number of longitude points on the Full Gaussian Grid, for other grids there will be at most these number of points around the Equator.\nDelta x is the horizontal resolution. For a spectral model there are many ways of estimating this[9]. We use here the square root of the average area a grid cell covers, see Effective grid resolution","category":"page"},{"location":"spectral_transform/#Effective-grid-resolution","page":"Spherical harmonic transform","title":"Effective grid resolution","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"There are many ways to estimate the effective grid resolution of spectral models[9]. Some of them are based on the wavelength a given spectral resolution allows to represent, others on the total number of real variables per area. However, as many atmospheric models do represent a considerable amount of physics on the grid (see Parameterizations) there is also a good argument to include the actual grid resolution into this estimate and not just the spectral resolution. We therefore use the average grid cell area to estimate the resolution","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Delta x = sqrtfrac4pi R^2N","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with N number of grid points over a sphere with radius R. However, we have to acknowledge that this usually gives higher resolution compared to other methods of estimating the effective resolution, see [Randall2021] for a discussion. You may therefore need to be careful to make claims that, e.g. trunc=85 can resolve the atmospheric dynamics at a scale of 165km.","category":"page"},{"location":"spectral_transform/#Derivatives-in-spherical-coordinates","page":"Spherical harmonic transform","title":"Derivatives in spherical coordinates","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Horizontal gradients in spherical coordinates are defined for a scalar field A and the latitudes theta and longitudes lambda as","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla A = left(frac1Rcosthetafracpartial Apartial lambda frac1Rfracpartial Apartial theta right)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"However, the divergence of a vector field mathbfu = (uv) includes additional cos(theta) scalings","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla cdot mathbfu = frac1Rcosthetafracpartial upartial lambda +\nfrac1Rcosthetafracpartial (v costheta)partial theta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"and similar for the curl","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"nabla times mathbfu = frac1Rcosthetafracpartial vpartial lambda -\nfrac1Rcosthetafracpartial (u costheta)partial theta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The radius of the sphere (i.e. Earth) is R. The zonal gradient scales with 1cos(theta) as the longitudes converge towards the poles (note that theta describes latitudes here, definitions using colatitudes replace the cos with a sin.)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Starting with a spectral field of vorticity zeta and divergence mathcalD one can obtain stream function Psi and velocity potential Phi by inverting the Laplace operator nabla^2:","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Psi = nabla^-2zeta quad Phi = nabla^-2mathcalD","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The velocities uv are then obtained from (uv) = nabla^botPsi + nablaPhi following the definition from above and nabla^bot = (-R^-1partial_theta (Rcostheta)^-1partial_lambda)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nu = -frac1Rpartial_thetaPsi + frac1Rcosthetapartial_lambdaPhi \nv = +frac1Rpartial_thetaPhi + frac1Rcosthetapartial_lambdaPsi\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Alternatively, we can use the velocities U = ucostheta V = vcostheta, which we do as the meridional gradient for spherical harmonics is easier implemented with a costheta-scaling included, and because the divergence and curl in spherical coordinates evaluates the meridional gradient with UV and not uv. From uv we can return to zeta mathcalD via","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nzeta = frac1Rcosthetapartial_lambda v - frac1Rcosthetapartial_theta (u costheta) \nmathcalD = frac1Rcosthetapartial_lambda u + frac1Rcosthetapartial_theta (v costheta)\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Equivalently, we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nU = -fraccosthetaRpartial_thetaPsi + frac1Rpartial_lambdaPhi \nV = +fraccosthetaRpartial_thetaPhi + frac1Rpartial_lambdaPsi \nzeta = frac1Rpartial_lambda left( fracVcos^2theta right) -\nfraccosthetaRpartial_theta left( fracUcos^2theta right) \nmathcalD = frac1Rpartial_lambda left( fracUcos^2theta right) +\nfraccosthetaRpartial_theta left( fracVcos^2theta right)\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which is a more convenient formulation because of the way how the Meridional derivative is implemented with a recursion relation, actually computing costheta partial_theta rather than partial_theta directly. The remaining cosine scalings in (UV)*cos^-2theta are done in grid-point space. If one wanted to get back to zeta mathcalD this is how it would be done, but it is often more convenient to unscale UV on the fly in the spectral transform to obtain uv and then divide again by costheta when any gradient (or divergence or curl) is taken. This is because other terms would need that single costheta unscaling too before a gradient is taken. How the operators nabla nabla times nabla cdot can be implemented with spherical harmonics is presented in the following sections.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Also note that SpeedyWeather.jl scales the equations with the radius R (see Radius scaling) such that the divisions by R drop out in this last formulation too.","category":"page"},{"location":"spectral_transform/#Zonal-derivative","page":"Spherical harmonic transform","title":"Zonal derivative","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The zonal derivative of a scalar field Psi in spectral space is the zonal derivative of all its respective spherical harmonics Psi_lm(phitheta) (now we use phi for longitudes to avoid confusion with the Legendre polynomials lambda_lm)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"v_lm = frac1R cos(theta) fracpartialpartial phi left( lambda_l^m(costheta) e^imphi right) =\nfracimR cos(theta) lambda_l^m(costheta) e^imphi = fracimR cos(theta) Psi_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"So for every spectral harmonic, cos(theta)v_lm is obtained from Psi_lm via a multiplication with imR. Unscaling the cos(theta)-factor is done after transforming the spectral coefficients v_lm into grid-point space. As discussed in Radius scaling, SpeedyWeather.jl scales the stream function as tildePsi = R^-1Psi such that the division by radius R in the gradients can be omitted. The zonal derivative becomes therefore effectively for each spherical harmonic a scaling with its (imaginary) order im. The spherical harmonics are essentially just a Fourier transform in zonal direction and the derivative a multiplication with the respective wave number m times imaginary i.","category":"page"},{"location":"spectral_transform/#Meridional-derivative","page":"Spherical harmonic transform","title":"Meridional derivative","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The meridional derivative of the spherical harmonics is a derivative of the Legendre polynomials for which the following recursion relation applies[10],[11]","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"costheta fracdP_lmdtheta = -lepsilon_l+1mP_l+1m + (l+1)epsilon_lmP_l-1m","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"with recursion factors","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"epsilon_lm = sqrtfracl^2-m^24l^2-1","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"In the following we use the example of obtaining the zonal velocity u from the stream function Psi, which is through the negative meridional gradient. For the meridional derivative itself the leading minus sign has to be omitted. Starting with the spectral expansion","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Psi(lambdatheta) = sum_lmPsi_lmP_lm(sintheta)e^imlambda","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"we multiply with -R^-1costhetapartial_theta to obtain","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"costhetaleft(-frac1Rpartial_thetaPsi right) = -frac1Rsum_lmPsi_lme^imlambdacosthetapartial_theta P_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"at which point the recursion from above can be applied. Collecting terms proportional to P_lm then yields","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"(cos(theta)u)_lm = -frac1R(-(l-1)epsilon_lmPsi_l-1m + (l+2)epsilon_l+1mPsi_l+1m)","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"To obtain the coefficient of each spherical harmonic lm of the meridional gradient of a spectral field, two coefficients at l-1m and l+1m have to be combined. This means that the coefficient of a gradient ((costheta) u)_lm is a linear combination of the coefficients of one higher and one lower degree Psi_l+1mPsi_l-1m. As the coefficient Psi_lm with ml are zero, the sectoral harmonics (l=m) of the gradients are obtained from the first off-diagonal only. However, the l=l_max harmonics of the gradients require the l_max-1 as well as the l_max+1 harmonics. As a consequence vector quantities like velocity components uv require one more degree l than scalar quantities like vorticity[Bourke72]. However, for easier compatibility all spectral fields in SpeedyWeather.jl use one more degree l, but scalar quantities should not make use of it. Equivalently, the last degree l is set to zero before the time integration, which only advances scalar quantities.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"In SpeedyWeather.jl vector quantities like uv use therefore one more meridional mode than scalar quantities such as vorticity zeta or stream function Psi. The meridional derivative in SpeedyWeather.jl also omits the 1R-scaling as explained for the Zonal derivative and in Radius scaling.","category":"page"},{"location":"spectral_transform/#Divergence-and-curl-in-spherical-harmonics","page":"Spherical harmonic transform","title":"Divergence and curl in spherical harmonics","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The meridional gradient as described above can be applied to scalars, such as Psi and Phi in the conversion to velocities (uv) = nabla^botPsi + nablaPhi, however, the operators curl nabla times and divergence nabla cdot in spherical coordinates involve a costheta scaling before the meridional gradient is applied. How to translate this to spectral coefficients has to be derived separately[10],[11].","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral transform of vorticity zeta is","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"zeta_lm = frac12piint_-tfracpi2^tfracpi2int_0^2pi zeta(lambdatheta)\nP_lm(sintheta) e^imlambda dlambda costheta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Given that Rzeta = cos^-1partial_lambda v - cos^-1partial_theta (u costheta), we therefore have to evaluate a meridional integral of the form","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"int P_lm frac1cos theta partial_theta(u costheta)) cos theta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"which can be solved through integration by parts. As ucostheta = 0 at theta = pm tfracpi2 only the integral","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"= -int partial_theta P_lm (u costheta) dtheta = -int costheta partial_theta P_lm\n(fracucostheta) costheta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"remains. Inserting the recurrence relation from the Meridional derivative turns this into","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"= -int left(-l epsilon_l+1mP_l+1m + (l+1)epsilon_lm P_l-1m right) (fracucostheta)\ncos theta dtheta","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"Now we expand (tfracucostheta) but only the lm harmonic will project ontoP_lm. Let u^* = ucos^-1theta v^* = vcos^-1theta we then have in total","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nRzeta_lm = imv^*_lm + (l+1)epsilon_lmu^*_l-1m - lepsilon_l+1mu^*_l+1m \nRD_lm = imu^*_lm - (l+1)epsilon_lmv^*_l-1m + lepsilon_l+1mv^*_l+1m \nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"And the divergence D is similar, but (uv) to (-vu). We have moved the scaling with the radius R directly into zetaD as further described in Radius scaling.","category":"page"},{"location":"spectral_transform/#Laplacian","page":"Spherical harmonic transform","title":"Laplacian","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"The spectral Laplacian is easily applied to the coefficients Psi_lm of a spectral field as the spherical harmonics are eigenfunctions of the Laplace operator nabla^2 in spherical coordinates with eigenvalues -l(l+1) divided by the radius squared R^2, i.e. nabla^2 Psi becomes tfrac-l(l+1)R^2Psi_lm in spectral space. For example, vorticity zeta and streamfunction Psi are related by zeta = nabla^2Psi in the barotropic vorticity model. Hence, in spectral space this is equivalent for every spectral mode of degree l and order m to","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"zeta_lm = frac-l(l+1)R^2Psi_lm","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"This can be easily inverted to obtain the stream function Psi from vorticity zeta instead. In order to avoid division by zero, we set Psi_00 here, given that the stream function is only defined up to a constant anyway.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nPsi_lm = fracR^2-l(l+1)zeta_lm quad foralllm 0\nPsi_00 = 0\nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"See also Horizontal diffusion and Normalization of diffusion.","category":"page"},{"location":"spectral_transform/#U,V-from-vorticity-and-divergence","page":"Spherical harmonic transform","title":"U,V from vorticity and divergence","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"After having discussed the zonal and meridional derivatives with spherical harmonics as well as the Laplace operator, we can derive the conversion from vorticity zeta and divergence D (which are prognostic variables) to U=ucostheta V=vcostheta. Both are linear operations that act either solely on a given harmonic (the zonal gradient and the Laplace operator) or are linear combinations between one lower and one higher degree l (the meridional gradient). It is therefore computationally more efficient to compute UV directly from zetaD instead of calculating stream function and velocity potential first. In total we have","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"beginaligned\nU_lm = -fraciml(l+1)(RD)_lm + fracepsilon_l+1ml+1(Rzeta)_l+1m -\nfracepsilon_lml(Rzeta)_l-1m \nV_lm = -fraciml(l+1)(Rzeta)_lm - fracepsilon_l+1ml+1(RD)_l+1m +\nfracepsilon_lml(RD)_l-1m \nendaligned","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"We have moved the scaling with the radius R directly into zetaD as further described in Radius scaling.","category":"page"},{"location":"spectral_transform/#References","page":"Spherical harmonic transform","title":"References","text":"","category":"section"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Malardel2016]: Malardel S, Wedi N, Deconinck W, Diamantakis M, Kühnlein C, Mozdzynski G, Hamrud M, Smolarkiewicz P. A new grid for the IFS. ECMWF newsletter. 2016;146(23-28):321. doi: 10.21957/zwdu9u5i","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Gorski2004]: Górski, Hivon, Banday, Wandelt, Hansen, Reinecke, Bartelmann, 2004. HEALPix: A FRAMEWORK FOR HIGH-RESOLUTION DISCRETIZATION AND FAST ANALYSIS OF DATA DISTRIBUTED ON THE SPHERE, The Astrophysical Journal. doi:10.1086/427976","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Willmert2020]: Justin Willmert, 2020. justinwillmert.comIntroduction to Associated Legendre Polynomials (Legendre.jl Series, Part I)\nCalculating Legendre Polynomials (Legendre.jl Series, Part II)\nPre-normalizing Legendre Polynomials (Legendre.jl Series, Part III)\nMaintaining numerical accuracy in the Legendre recurrences (Legendre.jl Series, Part IV)\nIntroducing Legendre.jl (Legendre.jl Series, Part V)\nNumerical Accuracy of the Spherical Harmonic Recurrence Coefficient (Legendre.jl Series Addendum)\nNotes on Calculating the Spherical Harmonics\nMore Notes on Calculating the Spherical Harmonics: Analysis of maps to harmonic coefficients","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Daley78]: Roger Daley & Yvon Bourassa (1978) Rhomboidal versus triangular spherical harmonic truncation: Some verification statistics, Atmosphere-Ocean, 16:2, 187-196, DOI: 10.1080/07055900.1978.9649026","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Randall2021]: David Randall, 2021. An Introduction to Numerical Modeling of the Atmosphere, Chapter 22.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Durran2010]: Dale Durran, 2010. Numerical Methods for Fluid Dynamics, Springer. In particular section 6.2, 6.4.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[GFDL]: Geophysical Fluid Dynamics Laboratory, The barotropic vorticity equation.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[FFT]: Depending on the implementation of the Fast Fourier Transform (Cooley-Tukey algorithm, or or the Bluestein algorithm) easily Fourier-transformable can mean different things: Vectors of the length n that is a power of two, i.e. n = 2^i is certainly easily Fourier-transformable, but for most FFT implementations so are n = 2^i3^j5^k with ijk some positive integers. In fact, FFTW uses O(n log n) algorithms even for prime sizes.","category":"page"},{"location":"spectral_transform/","page":"Spherical harmonic transform","title":"Spherical harmonic transform","text":"[Bourke72]: Bourke, W. An Efficient, One-Level, Primitive-Equation Spectral Model. Mon. Wea. Rev. 100, 683–689 (1972). doi:10.1175/1520-0493(1972)100<0683:AEOPSM>2.3.CO;2","category":"page"},{"location":"ringgrids/#RingGrids","page":"Submodule: RingGrids","title":"RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"RingGrids defines and exports the following grids:","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"full grids: FullClenshawGrid, FullGaussianGrid, FullHEALPix, and FullOctaHEALPix\nreduced grids: OctahedralGaussianGrid, OctahedralClenshawGrid, OctaHEALPixGrid and HEALPixGrid","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"note: What is a ring?\nWe 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.","category":"page"},{"location":"ringgrids/#Creating-data-on-a-RingGrid","page":"Submodule: RingGrids","title":"Creating data on a RingGrid","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Every grid in RingGrids has a grid.data field, which is a vector containing the data on the grid. The grid points 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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Data in a Matrix which follows this ring order can be put on a FullGaussianGrid like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"using SpeedyWeather.RingGrids\nmap = randn(Float32,8,4)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = FullGaussianGrid(map)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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. To reobtain the data from a grid, you can access its data field which returns a normal Vector","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid.data","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Which can be reshaped to reobtain map from above. Alternatively you can Matrix(grid) to do this in one step","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"map == Matrix(FullGaussianGrid(map))","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"You can also use zeros,ones,rand,randn to create a grid, whereby nlat_half, i.e. the number of latitude rings on one hemisphere, Equator included, is used as a resolution parameter and here as a second argument.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"nlat_half = 4\ngrid = randn(OctahedralGaussianGrid{Float16},nlat_half)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"and any element type T can be used for OctahedralGaussianGrid{T} and similar for other grid types.","category":"page"},{"location":"ringgrids/#Visualising-RingGrid-data","page":"Submodule: RingGrids","title":"Visualising RingGrid data","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"As only the full grids can be reshaped into a matrix, the underlying data structure of any AbstractGrid is a vector. As shown in the examples above, one can therefore inspect the data as if it was a vector. But as that data has, through its <:AbstractGrid type, all the geometric information available to plot it on a map, RingGrids also exports plot function, based on UnicodePlots' heatmap.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"nlat_half = 24\ngrid = randn(OctahedralGaussianGrid,nlat_half)\nplot(grid)","category":"page"},{"location":"ringgrids/#Indexing-RingGrids","page":"Submodule: RingGrids","title":"Indexing RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"All RingGrids 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 grid.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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_latdlonds for latitudes, longitudes per grid point not per ring)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = randn(OctahedralClenshawGrid,5)\nlatd = get_latd(grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Now we could calculate Coriolis and add it on the grid as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"rotation = 7.29e-5 # angular frequency of Earth's rotation [rad/s]\ncoriolis = 2rotation*sind.(latd) # vector of coriolis parameters per latitude ring\n\nrings = eachring(grid)\nfor (j,ring) in enumerate(rings)\n f = coriolis[j]\n for ij in ring\n grid[ij] += f\n end\nend","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"eachring creates a 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 grid-points like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"for ij in eachgridpoint(grid)\n grid[ij]\nend","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"or use eachindex instead.","category":"page"},{"location":"ringgrids/#Interpolation-on-RingGrids","page":"Submodule: RingGrids","title":"Interpolation on RingGrids","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 grid to another or to request an interpolated value on some coordinates. Using our data on grid which is an OctahedralGaussianGrid from above we can use the interpolate function to get it onto a FullGaussianGrid (or any other grid for purpose)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid = randn(OctahedralGaussianGrid{Float32},4)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(FullGaussianGrid,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 nlat_half directly as 2nd argument","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(FullGaussianGrid,6,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"So we got from an 8-ring OctahedralGaussianGrid{Float16} to a 12-ring FullGaussianGrid{Float64}, so it did a conversion from Float16 to Float64 on the fly too, because the default precision is Float64 unless specified. interpolate(FullGaussianGrid{Float16},6,grid) would have interpolated onto a grid with element type Float16.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"One can also interpolate onto a given coordinate ˚N, ˚E like so","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(30.0,10.0,grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"we interpolated the data from grid onto 30˚N, 10˚E. To do this simultaneously for many coordinates they can be packed into a vector too","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate([30.0,40.0,50.0],[10.0,10.0,10.0],grid)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which returns the data on grid at 30˚N, 40˚N, 50˚N, and 10˚E respectively. Note how the interpolation here retains the element type of grid.","category":"page"},{"location":"ringgrids/#Performance-for-RingGrid-interpolation","page":"Submodule: RingGrids","title":"Performance for RingGrid interpolation","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Every time an interpolation like interpolate(30.0,10.0,grid) 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","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"output vector\ninput grid\ninterpolator","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"The output vector 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. The input grid 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 the data is coming on 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 grid 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 grid. So in the case you want to interpolate from grid A to grid B many times, you can just reuse the same interpolator. If you want to change the coordinates of the output grid but its total number of points remain constants 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 an want to interpolate between them","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_in = rand(HEALPixGrid,4)\ngrid_out = zeros(FullClenshawGrid,6)\ninterp = RingGrids.interpolator(grid_out,grid_in)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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 of grid_in (and neither of grid_out which will be overwritten anyway). We can now do","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which is identical to interpolate(grid_out,grid_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)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_out = zeros(FullClenshawGrid{Float16},6);\ninterpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"and we have converted data from a HEALPixGrid{Float64} (Float64 is always default if not specified) to a FullClenshawGrid{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","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"grid_in = randn(OctahedralGaussianGrid{Float16},24)\ngrid_out = zeros(FullClenshawGrid{Float16},24)\ninterp = RingGrids.interpolator(Float32,grid_out,grid_in)\ninterpolate!(grid_out,grid_in,interp)\ngrid_out","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"npoints = 10 # number of coordinates to interpolate onto\ninterp = AnvilInterpolator(Float32,HEALPixGrid,24,npoints)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"with the first argument being the number format used during interpolation, then the input grid type, its resolution in terms of nlat_half and then the number of points to interpolate onto. 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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"latds = collect(0.0:5.0:45.0)\nlonds = collect(-10.0:2.0:8.0)\nnothing # hide","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"now we can update the locator inside our interpolator as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"RingGrids.update_locator!(interp,latds,londs)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"With data matching the input from above, a nlat_half=24 HEALPixGrid, and allocate 10-element output vector","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"output_vec = zeros(10)\ngrid_input = rand(HEALPixGrid,24)\nnothing # hide","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"we can use the interpolator as follows","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate!(output_vec,grid_input,interp)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"which is the approximately the same as doing it directly without creating an interpolator first and updating its locator","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"interpolate(latds,londs,grid_input)","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/#Anvil-interpolator","page":"Submodule: RingGrids","title":"Anvil interpolator","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":" 0..............1 # fraction of distance Δab between a,b\n |< Δab >|\n\n0^ a -------- o - b # anvil-shaped average of a,b,c,d at location x\n.Δy |\n. |\n.v x \n. |\n1 c ------ o ---- d\n\n |< Δcd >|\n 0...............1 # fraction of distance Δcd between c,d\n\n^ fraction of distance Δy between a-b and c-d.","category":"page"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"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.","category":"page"},{"location":"ringgrids/#Function-index","page":"Submodule: RingGrids","title":"Function index","text":"","category":"section"},{"location":"ringgrids/","page":"Submodule: RingGrids","title":"Submodule: RingGrids","text":"Modules = [SpeedyWeather.RingGrids]","category":"page"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractFullGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractFullGrid","text":"abstract type AbstractFullGrid{T} <: AbstractGrid{T} end\n\nAn AbstractFullGrid is a horizontal grid with a constant number of longitude points across latitude rings. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractGrid","text":"abstract type AbstractGrid{T} <: AbstractVector{T} end\n\nThe abstract supertype for all spatial grids on the sphere supported by SpeedyWeather.jl. Every new grid has to be of the form\n\nabstract type AbstractGridClass{T} <: AbstractGrid{T} end\nstruct MyNewGrid{T} <: AbstractGridClass{T}\n data::Vector{T} # all grid points unravelled into a vector\n nlat_half::Int # resolution: latitude rings on one hemisphere (Equator incl)\nend\n\nMyNewGrid should belong to a grid class like AbstractFullGrid, AbstractOctahedralGrid or AbstractHEALPixGrid (that already exist but you may introduce a new class of grids) that share certain features such as the number of longitude points per latitude ring and indexing, but may have different latitudes or offset rotations. Each new grid Grid (or grid class) then has to implement the following methods (as an example, see octahedral.jl)\n\nFundamental grid properties getnpoints # total number of grid points nlatodd # does the grid have an odd number of latitude rings? getnlat # total number of latitude rings getnlat_half # number of latitude rings on one hemisphere incl Equator\n\nIndexing getnlonmax # maximum number of longitudes points (at the Equator) getnlonperring # number of longitudes on ring j eachindexinring # a unit range that indexes all longitude points on a ring\n\nCoordinates getcolat # vector of colatitudes (radians) getcolatlon # vectors of colatitudes, longitudes (both radians)\n\nSpectral truncation truncationorder # linear, quadratic, cubic = 1,2,3 for grid gettruncation # spectral truncation given a grid resolution get_resolution # grid resolution given a spectral truncation\n\nQuadrature weights and solid angles getquadratureweights # = sinθ Δθ for grid points on ring j for meridional integration getsolidangle # = sinθ Δθ Δϕ, solid angle of grid points on ring j\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractHEALPixGrid","text":"abstract type AbstractHEALPixGrid{T} <: AbstractGrid{T} end\n\nAn AbstractHEALPixGrid is a horizontal grid similar to the standard HEALPixGrid, but different latitudes can be used, the default HEALPix latitudes or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractInterpolator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractInterpolator","text":"abstract type AbstractInterpolator{NF,G} end\n\nSupertype for Interpolators. Every Interpolator <: AbstractInterpolator is expected to have two fields,\n\ngeometry, which describes the grid G to interpolate from\nlocator, which locates the indices on G and their weights to interpolate onto a new grid.\n\nNF 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractLocator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractLocator","text":"AbstractLocator{NF}\n\nSupertype 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractOctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractOctaHEALPixGrid","text":"abstract type AbstractOctaHEALPixGrid{T} <: AbstractGrid{T} end\n\nAn AbstractOctaHEALPixGrid is a horizontal grid similar to the standard OctahedralGrid, but the number of points in the ring closest to the Poles starts from 4 instead of 20, and the longitude of the first point in each ring is shifted as in HEALPixGrid. Also, different latitudes can be used.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AbstractOctahedralGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AbstractOctahedralGrid","text":"abstract type AbstractOctahedralGrid{T} <: AbstractGrid{T} end\n\nAn AbstractOctahedralGrid is a horizontal grid with 16+4i longitude points on the latitude ring i starting with i=1 around the pole. Different latitudes can be used, Gaussian latitudes, equi-angle latitdes, or others.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AnvilLocator","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AnvilLocator","text":"AnvilLocator{NF<:AbstractFloat} <: AbtractLocator\n\nContains 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.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.AnvilLocator-Union{Tuple{Integer}, Tuple{NF}} where NF<:AbstractFloat","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.AnvilLocator","text":"L = AnvilLocator( ::Type{NF}, # number format used for the interpolation\n npoints::Integer # number of points to interpolate onto\n ) where {NF<:AbstractFloat}\n\nZero 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.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullClenshawGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullClenshawGrid","text":"G = FullClenshawGrid{T}\n\nA FullClenshawGrid is a regular latitude-longitude grid with an odd number of nlat equi-spaced latitudes, the central latitude ring is on the Equator. The same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullGaussianGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullGaussianGrid","text":"G = FullGaussianGrid{T}\n\nA full Gaussian grid is a regular latitude-longitude grid that uses nlat Gaussian latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullHEALPixGrid","text":"G = FullHEALPixGrid{T}\n\nA full HEALPix grid is a regular latitude-longitude grid that uses nlat latitudes from the HEALPix grid, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.FullOctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.FullOctaHEALPixGrid","text":"G = FullOctaHEALPixGrid{T}\n\nA full OctaHEALPix grid is a regular latitude-longitude grid that uses nlat OctaHEALPix latitudes, and the same nlon longitudes for every latitude ring. The grid points are closer in zonal direction around the poles. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.GridGeometry","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.GridGeometry","text":"GridGeometry{G<:AbstractGrid}\n\ncontains general precomputed arrays describing the grid of G.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.GridGeometry-Tuple{Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.GridGeometry","text":"G = GridGeometry( Grid::Type{<:AbstractGrid},\n nlat_half::Integer)\n\nPrecomputed arrays describing the geometry of the Grid with resolution nlat_half. Contains latitudes and longitudes of grid points, their ring index j and their unravelled indices ij.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.HEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.HEALPixGrid","text":"H = HEALPixGrid{T}\n\nA HEALPix grid with 12 faces, each nsidexnside grid points, each covering the same area. The number of latitude rings on one hemisphere (incl Equator) nlat_half is used as resolution parameter. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctaHEALPixGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctaHEALPixGrid","text":"H = OctaHEALPixGrid{T}\n\nA OctaHEALPix grid with 4 base faces, each nlat_halfxnlat_half grid points, each covering the same area. The values of all grid points are stored in a vector field data that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctahedralClenshawGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctahedralClenshawGrid","text":"G = OctahedralClenshawGrid{T}\n\nAn Octahedral Clenshaw grid that uses nlat equi-spaced latitudes. Like FullClenshawGrid, the central latitude ring is on the Equator. Like OctahedralGaussianGrid, the number of longitude points per latitude ring decreases towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.OctahedralGaussianGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.OctahedralGaussianGrid","text":"G = OctahedralGaussianGrid{T}\n\nAn Octahedral Gaussian grid that uses nlat Gaussian latitudes, but a decreasing number of longitude points per latitude ring towards the poles. Starting with 20 equi-spaced longitude points (starting at 0˚E) on the rings around the poles, each latitude ring towards the equator has consecuitively 4 more points, one for each face of the octahedron. E.g. 20,24,28,32,...nlon-4,nlon,nlon,nlon-4,...,32,28,24,20. The maximum number of longitue points is nlon. The values of all grid points are stored in a vector field v that unravels the data 0 to 360˚, then ring by ring, which are sorted north to south.\n\n\n\n\n\n","category":"type"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Tuple{AbstractMatrix, OctaHEALPixGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(M::AbstractMatrix,\n G::OctaHEALPixGrid;\n quadrant_rotation=(0,1,2,3),\n matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),\n )\n\nSorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Tuple{AbstractMatrix, OctahedralClenshawGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(M::AbstractMatrix,\n G::OctahedralClenshawGrid;\n quadrant_rotation=(0,1,2,3),\n matrix_quadrant=((2,2),(1,2),(1,1),(2,1)),\n )\n\nSorts the gridpoints in G into the matrix M without interpolation. Every quadrant of the grid G is rotated as specified in quadrant_rotation, 0 is no rotation, 1 is 90˚ clockwise, 2 is 180˚ etc. Grid quadrants are counted eastward starting from 0˚E. The grid quadrants are moved into the matrix quadrant (i,j) as specified. Defaults are equivalent to centered at 0˚E and a rotation such that the North Pole is at M's midpoint.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Union{Tuple{Vararg{Tuple{AbstractMatrix{T}, OctaHEALPixGrid}}}, Tuple{T}} where T","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(MGs::Tuple{AbstractMatrix{T},OctaHEALPixGrid}...;kwargs...)\n\nLike Matrix!(::AbstractMatrix,::OctaHEALPixGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.Matrix!-Union{Tuple{Vararg{Tuple{AbstractMatrix{T}, OctahedralClenshawGrid}}}, Tuple{T}} where T","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.Matrix!","text":"Matrix!(MGs::Tuple{AbstractMatrix{T},OctahedralClenshawGrid}...;kwargs...)\n\nLike Matrix!(::AbstractMatrix,::OctahedralClenshawGrid) but for simultaneous processing of tuples ((M1,G1),(M2,G2),...) with matrices Mi and grids Gi. All matrices and grids have to be of the same size respectively.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.anvil_average-NTuple{7, Any}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.anvil_average","text":"anvil_average(a, b, c, d, Δab, Δcd, Δy) -> Any\n\n\nThe 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:\n\n 0..............1 # fraction of distance Δab between a,b\n |< Δab >|\n\n 0^ a -------- o - b # anvil-shaped average of a,b,c,d at location x\n .Δy |\n . |\n .v x \n . |\n 1 c ------ o ---- d\n\n |< Δcd >|\n 0...............1 # fraction of distance Δcd between c,d\n\n^ fraction of distance Δy between a-b and c-d.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.average_on_poles-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, Vector{<:UnitRange{<:Integer}}}} where NF<:AbstractFloat","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.average_on_poles","text":"average_on_poles(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:AbstractFloat},\n rings::Vector{<:UnitRange{<:Integer}}\n) -> Tuple{Any, Any}\n\n\nComputes 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.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.average_on_poles-Union{Tuple{NF}, Tuple{SpeedyWeather.RingGrids.AbstractGrid{NF}, Vector{<:UnitRange{<:Integer}}}} where NF<:Integer","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.average_on_poles","text":"average_on_poles(\n A::SpeedyWeather.RingGrids.AbstractGrid{NF<:Integer},\n rings::Vector{<:UnitRange{<:Integer}}\n) -> Tuple{Any, Any}\n\n\nMethod for A::Abstract{T<:Integer} which rounds the averaged values to return the same number format NF.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.each_index_in_ring-Union{Tuple{Grid}, Tuple{Grid, Integer}} where Grid<:SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.each_index_in_ring","text":"i = each_index_in_ring(grid,j)\n\nUnitRange i to access data on grid grid on ring j.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachgridpoint-Tuple{SpeedyWeather.RingGrids.AbstractGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachgridpoint","text":"ijs = eachgridpoint(grid)\n\nUnitRange ijs to access each grid point on grid grid.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachring-Tuple{SpeedyWeather.RingGrids.AbstractGrid}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachring","text":"eachring(grid::SpeedyWeather.RingGrids.AbstractGrid) -> Any\n\n\nVector{UnitRange} rings to loop over every ring of grid grid and then each grid point per ring. To be used like\n\nrings = eachring(grid)\nfor ring in rings\n for ij in ring\n grid[ij]\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.eachring-Union{Tuple{Grid}, Tuple{Grid, Vararg{Grid}}} where Grid<:SpeedyWeather.RingGrids.AbstractGrid","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.eachring","text":"eachring(\n grid1::SpeedyWeather.RingGrids.AbstractGrid,\n grids::Grid<:SpeedyWeather.RingGrids.AbstractGrid...\n) -> Any\n\n\nSame as eachring(grid) but performs a bounds check to assess that all grids in grids are of same size.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.extrema_in-Tuple{Vector, Real, Real}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.extrema_in","text":"true/false = extrema_in(v::Vector,a::Real,b::Real)\n\nFor every element vᵢ in v does a<=vi<=b hold?\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.get_nlons-Tuple{Type{<:SpeedyWeather.RingGrids.AbstractGrid}, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.get_nlons","text":"get_nlons(\n Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid},\n nlat_half::Integer;\n both_hemispheres\n) -> Any\n\n\nReturns 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 both_hemisphere==false only the northern hemisphere (incl Equator) is returned.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.isdecreasing-Tuple{Vector}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.isdecreasing","text":"true/false = isdecreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly decreasing.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.isincreasing-Tuple{Vector}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.isincreasing","text":"true/false = isincreasing(v::Vector)\n\nCheck whether elements of a vector v are strictly increasing.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_180-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_180","text":"i_new,j_new = rotate_matrix_indices_180(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s by 180˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_270-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_270","text":"i_new,j_new = rotate_matrix_indices_270(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s anti-clockwise by 270˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.rotate_matrix_indices_90-Tuple{Integer, Integer, Integer}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.rotate_matrix_indices_90","text":"i_new,j_new = rotate_matrix_indices_90(i,j,s)\n\nRotate indices i,j of a square matrix of size s x s anti-clockwise by 90˚.\n\n\n\n\n\n","category":"method"},{"location":"ringgrids/#SpeedyWeather.RingGrids.whichring-Tuple{Integer, Vector{UnitRange{Int64}}}","page":"Submodule: RingGrids","title":"SpeedyWeather.RingGrids.whichring","text":"whichring(\n ij::Integer,\n rings::Vector{UnitRange{Int64}}\n) -> Int64\n\n\nObtain ring index j from gridpoint ij and Vector{UnitRange} describing rind indices as obtained from eachring(::Grid)\n\n\n\n\n\n","category":"method"},{"location":"#SpeedyWeather.jl-documentation","page":"Home","title":"SpeedyWeather.jl documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Welcome to the documentation for SpeedyWeather.jl a global atmospheric circulation model with simple parametrizations to represent physical processes such as clouds, precipitation and radiation.","category":"page"},{"location":"#Overview","page":"Home","title":"Overview","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"SpeedyWeather.jl is a global spectral model that uses a spherical harmonic transform to simulate the general circulation of the atmosphere. The prognostic variables used are vorticity, divergence, temperature, surface pressure and specific humidity. Simple parameterizations represent various climate processes: Radiation, clouds, precipitation, surface fluxes, among others.","category":"page"},{"location":"","page":"Home","title":"Home","text":"SpeedyWeather.jl defines ","category":"page"},{"location":"","page":"Home","title":"Home","text":"BarotropicModel for the 2D barotropic vorticity equation\nShallowWaterModel for the 2D shallow water equations\nPrimitiveDryModel for the 3D primitive equations without humidity\nPrimitiveWetModel for the 3D primitive equations with humidity","category":"page"},{"location":"","page":"Home","title":"Home","text":"and solves these equations in spherical coordinates as described in this documentation.","category":"page"},{"location":"#Manual-outline","page":"Home","title":"Manual outline","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"See the following pages of the documentation for more details","category":"page"},{"location":"","page":"Home","title":"Home","text":"Installation\nHow to run SpeedyWeather.jl\nSpherical harmonic transform\nGrids\nBarotropic model\nShallow water model\nPrimitive equation model\nParameterizations\nExtending SpeedyWeather\nNetCDF output","category":"page"},{"location":"","page":"Home","title":"Home","text":"and the submodules","category":"page"},{"location":"","page":"Home","title":"Home","text":"RingGrids\nLowerTriangularMatrices \nSpeedyTransforms","category":"page"},{"location":"","page":"Home","title":"Home","text":"and the original documentation by Molteni and Kucharski.","category":"page"},{"location":"#Developers","page":"Home","title":"Developers","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The development of SpeedyWeather.jl is lead by Milan Klöwer and current and past contributors include","category":"page"},{"location":"","page":"Home","title":"Home","text":"Tom Kimpson\nAlistair White\nMaximilian Gelbrecht\nDavid Meyer\nDaisuke Hotta\nNavid Constantinou","category":"page"},{"location":"","page":"Home","title":"Home","text":"Any contributions are always welcome!","category":"page"},{"location":"#Funding","page":"Home","title":"Funding","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"MK received funding by the European Research Council under Horizon 2020 within the ITHACA project, grant agreement number 741112 from 2021-2022. Since 2023 this project is also funded by the National Science Foundation NSF.","category":"page"}] } diff --git a/previews/PR363/shallowwater/index.html b/previews/PR363/shallowwater/index.html index d1f89cde8..e26afbf59 100644 --- a/previews/PR363/shallowwater/index.html +++ b/previews/PR363/shallowwater/index.html @@ -33,4 +33,4 @@ (-1)^{n+1}\tilde{\nu}\tilde{\nabla}^{2n}\tilde{\mathcal{D}} \\ \frac{\partial \eta}{\partial \tilde{t}} &= - \tilde{\nabla} \cdot (\mathbf{u}h) + \tilde{F}_\eta. -\end{aligned}\]

      As in the scaled barotropic vorticity equations, one needs to scale the time step, the Coriolis force, the forcing and the diffusion coefficient, but then enjoys the luxury of working with dimensionless gradient operators. As before, SpeedyWeather.jl will scale vorticity and divergence just before the model integration starts and unscale them upon completion and for output. In the semi-implicit time integration we solve an equation that also has to be scaled. It is with radius squared scaling (because it is the tendency for the divergence equation which is also scaled with $R^2$)

      \[R^2 \delta D = R^2\frac{G_\mathcal{D} - \xi g\nabla^2 G_\eta}{1 - \xi^2 H \nabla^2}\]

      As $G_\eta$ is only scaled with $R$ we have

      \[\tilde{\delta D} = \frac{\tilde{G_\mathcal{D}} - \tilde{\xi} g\tilde{\nabla}^2 \tilde{G_\eta}}{1 - \tilde{\xi}^2 H \tilde{\nabla}^2}\]

      The $R^2$ normalizes the Laplace operator in the numerator, but using the scaled $G_\eta$ we also scale $\xi$ (which is convenient, because the time step within is the one we use anyway). The denominator $S$ does not actually change because $\xi^2\nabla^2 = \tilde{\xi}^2\tilde{\nabla}^2$ as $\xi^2$ is scaled with $1/R^2$, but the Laplace operator with $R^2$. So overall we just have to use the scaled time step $\tilde{\Delta t}$ and normalized eigenvalues for $\tilde{\nabla}^2$.

      References

      +\end{aligned}\]

      As in the scaled barotropic vorticity equations, one needs to scale the time step, the Coriolis force, the forcing and the diffusion coefficient, but then enjoys the luxury of working with dimensionless gradient operators. As before, SpeedyWeather.jl will scale vorticity and divergence just before the model integration starts and unscale them upon completion and for output. In the semi-implicit time integration we solve an equation that also has to be scaled. It is with radius squared scaling (because it is the tendency for the divergence equation which is also scaled with $R^2$)

      \[R^2 \delta D = R^2\frac{G_\mathcal{D} - \xi g\nabla^2 G_\eta}{1 - \xi^2 H \nabla^2}\]

      As $G_\eta$ is only scaled with $R$ we have

      \[\tilde{\delta D} = \frac{\tilde{G_\mathcal{D}} - \tilde{\xi} g\tilde{\nabla}^2 \tilde{G_\eta}}{1 - \tilde{\xi}^2 H \tilde{\nabla}^2}\]

      The $R^2$ normalizes the Laplace operator in the numerator, but using the scaled $G_\eta$ we also scale $\xi$ (which is convenient, because the time step within is the one we use anyway). The denominator $S$ does not actually change because $\xi^2\nabla^2 = \tilde{\xi}^2\tilde{\nabla}^2$ as $\xi^2$ is scaled with $1/R^2$, but the Laplace operator with $R^2$. So overall we just have to use the scaled time step $\tilde{\Delta t}$ and normalized eigenvalues for $\tilde{\nabla}^2$.

      References

      diff --git a/previews/PR363/spectral_transform/index.html b/previews/PR363/spectral_transform/index.html index 90b9a5e00..24f12970f 100644 --- a/previews/PR363/spectral_transform/index.html +++ b/previews/PR363/spectral_transform/index.html @@ -29,4 +29,4 @@ \frac{\epsilon_{l,m}}{l}(R\zeta)_{l-1,m} \\ V_{l,m} &= -\frac{im}{l(l+1)}(R\zeta)_{l,m} - \frac{\epsilon_{l+1,m}}{l+1}(RD)_{l+1,m} + \frac{\epsilon_{l,m}}{l}(RD)_{l-1,m} \\ -\end{aligned}\]

      We have moved the scaling with the radius $R$ directly into $\zeta,D$ as further described in Radius scaling.

      References

      +\end{aligned}\]

      We have moved the scaling with the radius $R$ directly into $\zeta,D$ as further described in Radius scaling.

      References

      diff --git a/previews/PR363/speedytransforms/index.html b/previews/PR363/speedytransforms/index.html index 27de367ef..554992773 100644 --- a/previews/PR363/speedytransforms/index.html +++ b/previews/PR363/speedytransforms/index.html @@ -1,25 +1,196 @@ -Submodule: SpeedyTransforms · SpeedyWeather.jl

      SpeedyTransforms

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

      Example transforms

      julia> using SpeedyWeather
      -julia> alms = zeros(ComplexF64,3,3)    # spectral coefficients
      -julia> alms[2,2] = 1                   # only l=1,m=1 harmonic
      -julia> map = gridded(alms)             # convert to grid space
      -8×4 Matrix{Float64}:
      - -0.324541  -0.600363  -0.600363  -0.324541
      - -0.134429  -0.248678  -0.248678  -0.134429
      -  0.134429   0.248678   0.248678   0.134429
      -  0.324541   0.600363   0.600363   0.324541
      -  0.324541   0.600363   0.600363   0.324541
      -  0.134429   0.248678   0.248678   0.134429
      - -0.134429  -0.248678  -0.248678  -0.134429
      - -0.324541  -0.600363  -0.600363  -0.324541
      - 
      -julia> spectral(map)                   # back to spectral space
      -3×3 Matrix{ComplexF64}:
      - 0.0+0.0im  0.0+0.0im          0.0+0.0im
      - 0.0+0.0im  1.0+3.60727e-17im  0.0+0.0im
      - 0.0+0.0im  0.0+0.0im          0.0+0.0im

      and we have successfully reobtained the $l=m=1$ spherical harmonic.

      Functions and type index

      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      S = SpectralTransform(  alms::AbstractMatrix{Complex{NF}};
      +Submodule: SpeedyTransforms · SpeedyWeather.jl

      SpeedyTransforms

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

      The SpeedyTransforms are based on RingGrids and LowerTriangularMatrices to hold data in either grid-point space or in spectral space. So you want to read these sections first for clarifications how to work with these. We will also not discuss mathematical details of the Spherical Harmonic Transform here, but will focus on the usage of the SpeedyTransforms module.

      Example transform

      Lets start with a simple transform. We could be using SpeedyWeather but to be more verbose these are the modules required to load

      using SpeedyWeather.RingGrids
      +using SpeedyWeather.LowerTriangularMatrices
      +using SpeedyWeather.SpeedyTransforms

      As an example, we want to transform the $l=m=1$ spherical harmonic from spectral space in alms to grid-point space.

      alms = zeros(LowerTriangularMatrix{ComplexF64},6,6)     # spectral coefficients
      +alms[2,2] = 1                                           # only l=1,m=1 harmonic
      +alms
      6×6 LowerTriangularMatrix{ComplexF64}:
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  1.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im  0.0+0.0im

      Now gridded is the function that takes spectral coefficients alms and converts them a grid-point space map

      map = gridded(alms)
      128-element, 8-ring FullGaussianGrid{Float64}:
      + -0.19278869685896918
      + -0.17811353112752462
      + -0.13632219488509478
      + -0.07377704023518313
      +  0.0
      +  0.07377704023518313
      +  0.13632219488509478
      +  0.17811353112752462
      +  0.19278869685896918
      +  0.17811353112752462
      +  ⋮
      +  0.17811353112752462
      +  0.19278869685896918
      +  0.17811353112752462
      +  0.13632219488509478
      +  0.07377704023518313
      +  0.0
      + -0.07377704023518313
      + -0.13632219488509478
      + -0.17811353112752462

      By default, the gridded transforms onto a FullGaussianGrid unravelled here into a vector west to east, starting at the prime meridian, then north to south, see RingGrids. We can visualize map quickly with a unicodeplot via plot (see Visualising RingGrid data)

      plot(map)
             8-ring FullGaussianGrid{Float64}     
      +       ┌────────────────┐  0.7
      +    90 ▄▄▄▄▄▄ ┌──┐
      +    ˚N ▄▄▄▄ ▄▄
      +       ▄▄▄▄ ▄▄
      +   -90 ▄▄▄▄▄▄ └──┘
      +       └────────────────┘ -0.7
      +        0     ˚E     360      

      Yay! This is the what the $l=m=1$ spherical harmonic is supposed to look like! Now let's go back to spectral space with spectral

      alms2 = spectral(map)
      6×6 LowerTriangularMatrix{ComplexF64}:
      + 0.0+0.0im           0.0+0.0im  0.0+0.0im  …  0.0+0.0im           0.0+0.0im
      + 0.0+0.0im           1.0+0.0im  0.0+0.0im     0.0+0.0im           0.0+0.0im
      + 0.0+0.0im           0.0+0.0im  0.0+0.0im     0.0+0.0im           0.0+0.0im
      + 0.0+0.0im   3.75734e-16+0.0im  0.0+0.0im     0.0+0.0im           0.0+0.0im
      + 0.0+0.0im           0.0+0.0im  0.0+0.0im     0.0+0.0im           0.0+0.0im
      + 0.0+0.0im  -1.63058e-17+0.0im  0.0+0.0im  …  0.0+0.0im  -2.47957e-17+0.0im

      Comparing with alms from above you can see that the transform is exact up to a typical rounding error from Float64.

      alms ≈ alms2
      true

      YAY! The transform is typically idempotent, meaning that either space may hold information that is not exactly representable in the other but the first two-way transform will remove that so that subsequent transforms do not change this any further. However, also note here that the default FullGaussianGrid is an exact grid, inexact grids usually have a transform error that is larger than the rounding error from floating-point arithmetic.

      Transform onto another grid

      While the default grid for SpeedyTransforms is the FullGaussianGrid we can transform onto other grids by specifying Grid too

      map = gridded(alms,Grid=HEALPixGrid)
      +plot(map)
             7-ring HEALPixGrid{Float64}     
      +       ┌──────────────┐  0.7
      +    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
      +    ˚N  ▄▄
      +       ▄▄ ▄▄
      +   -90 ▄▄▄▄▄ └──┘
      +       └──────────────┘ -0.7
      +        0    ˚E    360      

      which, if transformed back, however, can yield a larger transform error as discussed above

      spectral(map)
      6×6 LowerTriangularMatrix{ComplexF64}:
      + 0.0+0.0im           0.0+0.0im          0.0+0.0im  …  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im       1.01215-1.4295e-17im   0.0+0.0im     0.0+0.0im  0.0+0.0im
      + 0.0+0.0im   3.42299e-17+0.0im          0.0+0.0im     0.0+0.0im  0.0+0.0im
      + 0.0+0.0im     0.0185292-1.63433e-17im  0.0+0.0im     0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  -6.28844e-17+0.0im          0.0+0.0im     0.0+0.0im  0.0+0.0im
      + 0.0+0.0im    -0.0164851+1.42335e-17im  0.0+0.0im  …  0.0+0.0im  0.0+0.0im

      On such a coarse grid the transform error (absolute and relative) is about $10^{-2}$, this decreases for higher resolution. The gridded and spectral functions will choose a corresponding grid-spectral resolution (see Matching spectral and grid resolution) following quadratic truncation, but you can always truncate/interpolate in spectral space with spectral_truncation, spectral_interpolation which takes trunc = $l_{max} = m_{max}$ as second argument

      spectral_truncation(alms,2)
      3×3 LowerTriangularMatrix{ComplexF64}:
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im
      + 0.0+0.0im  1.0+0.0im  0.0+0.0im
      + 0.0+0.0im  0.0+0.0im  0.0+0.0im

      Yay, we just chopped off $l > 2$ from alms which contained the harmonics up to degree and order 5 before. If the second argument in spectral_truncation is larger than alms then it will automatically call spectral_interpolation and vice versa. Also see Interpolation on RingGrids to interpolate directly between grids. If you want to control directly the resolution of the grid gridded is supposed to transform onto you have to provide a SpectralTransform instance. More on that now.

      The SpectralTransform struct

      Both spectral and gridded create an instance of SpectralTransform under the hood. This object contains all precomputed information that is required for the transform, either way: The Legendre polynomials, pre-planned Fourier transforms, precomputed gradient, divergence and curl operators, the spherical harmonic eigenvalues among others. Maybe the most intuitive way to create a SpectralTransform is to start with a SpectralGrid, which already defines which spectral resolution is supposed to be combined with a given grid.

      using SpeedyWeather
      +spectral_grid = SpectralGrid(Float32,trunc=5,Grid=OctahedralGaussianGrid,dealiasing=3)
      SpectralGrid:
      + Spectral:   T5 LowerTriangularMatrix{Complex{Float32}}, radius = 6.371e6 m
      + Grid:       360-element, 12-ring OctahedralGaussianGrid{Float32} (cubic)
      + Resolution: 1.19e+03km (average)
      + Vertical:   8-level SigmaCoordinates

      (We using SpeedyWeather here as SpectralGrid is exported therein). We also specify the number format Float32 here to be used for the transform although this is the default anyway. From spectral_grid we now construct a SpectralTransform as follows

      S = SpectralTransform(spectral_grid)
      SpectralTransform{Float32}(
      +  Spectral: T5, 7x6 LowerTriangularMatrix{Complex{Float32}}
      +  Grid:     12-ring OctahedralGaussianGrid{Float32}
      +  Legendre: recompute polynomials false, 1.19 KiB)

      Note that because we chose dealiasing=3 (cubic truncation) we now match a T5 spectral field with a 12-ring octahedral Gaussian grid, instead of the 8 rings as above. So going from dealiasing=2 (default) to dealiasing=3 increased our resolution on the grid while the spectral resolution remains the same. The SpectralTransform also has options for the recomputation or precomputation of the Legendre polynomials, fore more information see (P)recompute Legendre polynomials.

      Passing on S the SpectralTransform now allows us to transform directly on the grid defined therein.

      map = gridded(alms,S)
      +plot(map)
             12-ring OctahedralGaussianGrid{Float32}     
      +       ┌────────────────────────┐  0.7
      +    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +    ˚N ▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +   -90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ └──┘
      +       └────────────────────────┘ -0.7
      +        0         ˚E         360      

      Yay, this is again the $l=m=1$ harmonic, but this time on a slightly higher resolution OctahedralGaussianGrid as specified in the SpectralTransform S. Note that also the number format was converted on the fly to Float32 because that is the number format we specified in S! And from grid to spectral

      alms2 = spectral(map,S)
      7×6 LowerTriangularMatrix{ComplexF32}:
      +   2.05564f-9+0.0im          0.0+0.0im          …         0.0+0.0im
      +          0.0+0.0im          1.0-2.14344f-8im             0.0+0.0im
      +   -1.3654f-9+0.0im          0.0+0.0im                    0.0+0.0im
      +          0.0+0.0im  -2.66275f-8-6.93167f-11im            0.0+0.0im
      + -3.22443f-10+0.0im          0.0+0.0im                    0.0+0.0im
      +          0.0+0.0im  -4.58858f-8-8.19443f-9im   …  6.58519f-9+4.79414f-9im
      +   1.85859f-9+0.0im          0.0+0.0im                    0.0+0.0im

      As you can see the rounding error is now more like $10^{-8}$ as we are using Float32 (the OctahedralGaussianGrid is another exact grid). Note, however, that the returned LowerTriangularMatrix is of size 7x6, not 6x6 what we started from. We may change this in the future, but the underlying reason is that internally SpeedyWeather uses LowerTriangularMatrixs of size $l_{max} + 2 \times m_{max} + 1$. One $+1$ on both degree and order for 0-based harmonics versus 1-based matrix sizes, but an additional $+1$ for the degrees which is required by the meridional derivative. For consistency, all LowerTriangularMatrixs in SpeedyWeather.jl carry this additional degree but only the vector quantities explicitly make use of it. See Meridional derivative for details.

      You can, however, always truncate this additional degree, say to T5 (hence matrix size is 6x6)

      spectral_truncation(alms2,5,5)
      6×6 LowerTriangularMatrix{ComplexF32}:
      +   2.05564f-9+0.0im          0.0+0.0im          …         0.0+0.0im
      +          0.0+0.0im          1.0-2.14344f-8im             0.0+0.0im
      +   -1.3654f-9+0.0im          0.0+0.0im                    0.0+0.0im
      +          0.0+0.0im  -2.66275f-8-6.93167f-11im            0.0+0.0im
      + -3.22443f-10+0.0im          0.0+0.0im                    0.0+0.0im
      +          0.0+0.0im  -4.58858f-8-8.19443f-9im   …  6.58519f-9+4.79414f-9im

      spectral_truncation(alms2,5) would have returned the same, a single argument is then assumed equal for both degrees and orders. Alternatively, you can also pass on the one_more_degree=false argument to the SpectralTransform constructor

      S = SpectralTransform(spectral_grid,one_more_degree=false)
      SpectralTransform{Float32}(
      +  Spectral: T5, 6x6 LowerTriangularMatrix{Complex{Float32}}
      +  Grid:     12-ring OctahedralGaussianGrid{Float32}
      +  Legendre: recompute polynomials false, 1.05 KiB)

      As you can see the 7x6 LowerTriangularMatrix in the description above dropped down to 6x6 LowerTriangularMatrix, this is the size of the input that is expected (otherwise you will get a BoundsError).

      Power spectrum

      How to take some data and compute a power spectrum with SpeedyTransforms you may ask. Say you have some global data in a matrix m that looks, for example, like

      m
      96×47 Matrix{Float32}:
      + -0.161541   0.0583441    0.0966358   …  -6.62512  -5.85038  -3.76395
      + -0.17059    0.0404233    0.0668784      -6.6666   -5.89805  -3.79059
      + -0.180987   0.021871     0.0363343      -6.68273  -5.92231  -3.80432
      + -0.192675   0.00300103   0.00633705     -6.67557  -5.92362  -3.80509
      + -0.20561   -0.0159075   -0.0217592      -6.64705  -5.90252  -3.79294
      + -0.219757  -0.0346295   -0.0466931   …  -6.59885  -5.85958  -3.76797
      + -0.235097  -0.0530111   -0.0674059      -6.53234  -5.79533  -3.73033
      + -0.251619  -0.0709851   -0.0831351      -6.4485   -5.71034  -3.68021
      + -0.269328  -0.0885815   -0.0934836      -6.34792  -5.60511  -3.6179
      + -0.288238  -0.105934    -0.0984595      -6.23074  -5.4801   -3.54368
      +  ⋮                                   ⋱             ⋮        
      + -0.153189   0.139852     0.213263       -4.85176  -4.35923  -2.9828
      + -0.146613   0.141151     0.214904       -5.1803   -4.61374  -3.11259
      + -0.142111   0.139301     0.213487       -5.47715  -4.84828  -3.23297
      + -0.139599   0.134528     0.208647    …  -5.74085  -5.06149  -3.34326
      + -0.138995   0.127059     0.200002       -5.97062  -5.25229  -3.44285
      + -0.140209   0.117133     0.187252       -6.16632  -5.41986  -3.53119
      + -0.143155   0.105008     0.170272       -6.32842  -5.56365  -3.60783
      + -0.147748   0.0909637    0.149185       -6.45791  -5.68336  -3.67236
      + -0.153902   0.0753019    0.124401    …  -6.55622  -5.77891  -3.72448

      You hopefully know which grid this data comes on, let us assume it is a regular latitde-longitude grid, which we call the FullClenshawGrid. We now wrap this matrix therefore to associate it with the necessary grid information

      map = FullClenshawGrid(m)
      +plot(map)
                            47-ring FullClenshawGrid{Float32}                   
      +       ┌────────────────────────────────────────────────────────────┐  10 
      +    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +    ˚N ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +   -90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ └──┘
      +       └────────────────────────────────────────────────────────────┘ -9  
      +        0                           ˚E                           360      

      Now we transform into spectral space and call power_spectrum(::LowerTriangularMatrix)

      alms = spectral(map)
      +p = SpeedyTransforms.power_spectrum(alms)

      Which returns a vector of power at every wavenumber. By default this is normalized as average power per degree, you can change that with the keyword argument normalize=false. Plotting this yields

      import PyPlot: PyPlot, savefig, tight_layout # hide
      +PyPlot.ioff() # hide
      +import PyPlot: semilogy, xlabel, ylabel
      +semilogy(p)
      +xlabel("wavenumber")
      +ylabel("power")
      +tight_layout() # hide
      +savefig("spectrum.svg"); close() # hide

      The power spectrum of our data is about 1 up to wavenumber 10 and then close to zero for higher wavenumbers (which is in fact how we constructed this fake data). Let us turn this around and use SpeedyTransforms to create random noise in spectral space to be used in grid-point space!

      Example: Creating k^n-distributed noise

      How would be construct random noise in spectral space that follows a certain power law and transform it back into grid-point space? Define the wavenumber $k$ for T31, the spectral resolution we are interested in. (We start from 1 instead of 0 to avoid zero to the power of something negative). Now create some normally distributed spectral coefficients but scale them down for higher wavenumbers with $k^{-2}$

      k = 1:32
      +alms = randn(LowerTriangularMatrix{Complex{Float32}},32,32)
      +alms .*= k.^-2
      32×32 LowerTriangularMatrix{ComplexF32}:
      +    -0.894222+0.728777im     …           0.0+0.0im
      +    -0.194325-0.099566im                 0.0+0.0im
      +    -0.166356-0.0140627im                0.0+0.0im
      +   -0.0210624+0.0127401im                0.0+0.0im
      +    0.0175568+0.0112754im                0.0+0.0im
      +   -0.0198723+0.00708971im   …           0.0+0.0im
      +   0.00800025-0.0138774im                0.0+0.0im
      +    0.0144086+0.00443996im               0.0+0.0im
      +   0.00936721+0.0142166im                0.0+0.0im
      +  -0.00185984-0.0088685im                0.0+0.0im
      +             ⋮               ⋱  
      +  -0.00174126+0.000736087im              0.0+0.0im
      +  -0.00139923+3.19595f-5im               0.0+0.0im
      + -0.000889243+0.00106929im   …           0.0+0.0im
      +  -0.00121749+0.000144758im              0.0+0.0im
      + -0.000637536+0.00039281im               0.0+0.0im
      +   0.00183306+0.000548263im              0.0+0.0im
      +  -2.76594f-5-6.01397f-5im               0.0+0.0im
      +  0.000445154-0.000842817im  …           0.0+0.0im
      +   7.31837f-5-0.00063749im      -0.000704275-0.00081931im

      Awesome. For higher degrees and orders the amplitude clearly decreases! Now to grid-point space and let us visualize the result

      map = gridded(alms)
      +plot(map)
                            48-ring FullGaussianGrid{Float32}                   
      +       ┌────────────────────────────────────────────────────────────┐  0.1
      +    90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ┌──┐
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +    ˚N ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄
      +   -90 ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ └──┘
      +       └────────────────────────────────────────────────────────────┘ -0.7
      +        0                           ˚E                           360      

      You can always access the underlying data in map via map.data in case you need to get rid of the wrapping into a grid again!

      (P)recompute Legendre polynomials

      The spectral transform uses a Legendre transform in meridional direction. For this the Legendre polynomials are required, at each latitude ring this is a $l_{max} \times m_{max}$ lower triangular matrix. Storing precomputed Legendre polynomials therefore quickly increase in size with resolution. One can recompute them to save memory, but that uses more arithmetic operations. There is therefore a memory-compute tradeoff.

      For a single transform, there is no need to precompute the polynomials as the SpectralTransform object will be garbage collected again anyway. For low resolution simulations with many repeated small transforms it makes sense to precompute the polynomials and SpeedyWeather.jl does that automatically anyway. At very high resolution the polynomials may, however, become prohibitively large. An example at T127, about 100km resolution

      spectral_grid = SpectralGrid(trunc=127)
      +SpectralTransform(spectral_grid,recompute_legendre=false)
      SpectralTransform{Float32}(
      +  Spectral: T127, 129x128 LowerTriangularMatrix{Complex{Float32}}
      +  Grid:     192-ring OctahedralGaussianGrid{Float32}
      +  Legendre: recompute polynomials false, 3.08 MiB)

      the polynomials are about 3MB in size. Easy that is not much. But at T1023 on the O1536 octahedral Gaussian grid, this is already 1.5GB, cubically increasing with the spectral truncation T. recompute_legendre=true (default false when constructing a SpectralTransform object which may be reused) would lower this to kilobytes

      SpectralTransform(spectral_grid,recompute_legendre=true)
      SpectralTransform{Float32}(
      +  Spectral: T127, 129x128 LowerTriangularMatrix{Complex{Float32}}
      +  Grid:     192-ring OctahedralGaussianGrid{Float32}
      +  Legendre: recompute polynomials true, 32.81 KiB)

      Functions and type index

      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      S = SpectralTransform(  alms::AbstractMatrix{Complex{NF}};
                               recompute_legendre::Bool=true,
      -                        Grid::Type{<:AbstractGrid}=DEFAULT_GRID)

      Generator function for a SpectralTransform struct based on the size of the spectral coefficients alms and the grid Grid. Recomputes the Legendre polynomials by default.

      source
      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      SpectralTransform(
      +                        Grid::Type{<:AbstractGrid}=DEFAULT_GRID)

      Generator function for a SpectralTransform struct based on the size of the spectral coefficients alms and the grid Grid. Recomputes the Legendre polynomials by default.

      source
      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      SpectralTransform(
           ::Type{NF},
           Grid::Type{<:SpeedyWeather.RingGrids.AbstractGrid},
           lmax::Int64,
      @@ -28,72 +199,72 @@
           legendre_shortcut,
           dealiasing
       ) -> SpectralTransform
      -

      Generator function for a SpectralTransform struct. With NF the number format, Grid the grid type <:AbstractGrid and spectral truncation lmax,mmax this function sets up necessary constants for the spetral transform. Also plans the Fourier transforms, retrieves the colatitudes, and preallocates the Legendre polynomials (if recompute_legendre == false) and quadrature weights.

      source
      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      S = SpectralTransform(  map::AbstractGrid;
      -                        recompute_legendre::Bool=true)

      Generator function for a SpectralTransform struct based on the size and grid type of gridded field map. Recomputes the Legendre polynomials by default.

      source
      SpeedyWeather.SpeedyTransforms.UV_from_vor!Method
      UV_from_vor!(   U::LowerTriangularMatrix,
      +

      Generator function for a SpectralTransform struct. With NF the number format, Grid the grid type <:AbstractGrid and spectral truncation lmax,mmax this function sets up necessary constants for the spetral transform. Also plans the Fourier transforms, retrieves the colatitudes, and preallocates the Legendre polynomials (if recompute_legendre == false) and quadrature weights.

      source
      SpeedyWeather.SpeedyTransforms.SpectralTransformMethod
      S = SpectralTransform(  map::AbstractGrid;
      +                        recompute_legendre::Bool=true)

      Generator function for a SpectralTransform struct based on the size and grid type of gridded field map. Recomputes the Legendre polynomials by default.

      source
      SpeedyWeather.SpeedyTransforms.UV_from_vor!Method
      UV_from_vor!(   U::LowerTriangularMatrix,
                       V::LowerTriangularMatrix,
                       vor::LowerTriangularMatrix,
      -                S::SpectralTransform)

      Get U,V (=(u,v)*coslat) from vorticity ζ spectral space (divergence D=0) Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity. Then compute zonal and meridional gradients to get U,V.

      source
      SpeedyWeather.SpeedyTransforms.UV_from_vordiv!Method
      UV_from_vordiv!(U::LowerTriangularMatrix,
      +                S::SpectralTransform)

      Get U,V (=(u,v)*coslat) from vorticity ζ spectral space (divergence D=0) Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity. Then compute zonal and meridional gradients to get U,V.

      source
      SpeedyWeather.SpeedyTransforms.UV_from_vordiv!Method
      UV_from_vordiv!(U::LowerTriangularMatrix,
                       V::LowerTriangularMatrix,
                       vor::LowerTriangularMatrix,
                       div::LowerTriangularMatrix,
      -                S::SpectralTransform)

      Get U,V (=(u,v)*coslat) from vorticity ζ and divergence D in spectral space. Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity and velocity potential from divergence. Then compute zonal and meridional gradients to get U,V.

      source
      SpeedyWeather.SpeedyTransforms._divergence!Method
      _divergence!(   kernel,
      +                S::SpectralTransform)

      Get U,V (=(u,v)*coslat) from vorticity ζ and divergence D in spectral space. Two operations are combined into a single linear operation. First, invert the spherical Laplace ∇² operator to get stream function from vorticity and velocity potential from divergence. Then compute zonal and meridional gradients to get U,V.

      source
      SpeedyWeather.SpeedyTransforms._divergence!Method
      _divergence!(   kernel,
                       div::LowerTriangularMatrix,
                       u::LowerTriangularMatrix,
                       v::LowerTriangularMatrix,
      -                S::SpectralTransform)

      Generic divergence function of vector u,v that writes into the output into div. Generic as it uses the kernel kernel such that curl, div, add or flipsign options are provided through kernel, but otherwise a single function is used.

      source
      SpeedyWeather.SpeedyTransforms.curl!Method
      curl!(  curl::LowerTriangularMatrix,
      +                S::SpectralTransform)

      Generic divergence function of vector u,v that writes into the output into div. Generic as it uses the kernel kernel such that curl, div, add or flipsign options are provided through kernel, but otherwise a single function is used.

      source
      SpeedyWeather.SpeedyTransforms.curl!Method
      curl!(  curl::LowerTriangularMatrix,
               u::LowerTriangularMatrix,
               v::LowerTriangularMatrix,
               S::SpectralTransform;
               flipsign::Bool=false,
               add::Bool=false,
      -        )

      Curl of a vector u,v written into curl, curl = ∇×(u,v). u,v are expected to have a 1/coslat-scaling included, then curl is not scaled. flipsign option calculates -∇×(u,v) instead. add option calculates curl += ∇×(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently with flipped u,v -> v,u for the curl.

      source
      SpeedyWeather.SpeedyTransforms.divergence!Method
      divergence!(div::LowerTriangularMatrix,
      +        )

      Curl of a vector u,v written into curl, curl = ∇×(u,v). u,v are expected to have a 1/coslat-scaling included, then curl is not scaled. flipsign option calculates -∇×(u,v) instead. add option calculates curl += ∇×(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently with flipped u,v -> v,u for the curl.

      source
      SpeedyWeather.SpeedyTransforms.divergence!Method
      divergence!(div::LowerTriangularMatrix,
                   u::LowerTriangularMatrix,
                   v::LowerTriangularMatrix,
                   S::SpectralTransform{NF};
                   flipsign::Bool=false,
                   add::Bool=false,
      -            )

      Divergence of a vector u,v written into div, div = ∇⋅(u,v). u,v are expected to have a 1/coslat-scaling included, then div is not scaled. flipsign option calculates -∇⋅(u,v) instead. add option calculates div += ∇⋅(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently.

      source
      SpeedyWeather.SpeedyTransforms.get_recursion_factorsMethod
      get_recursion_factors(  ::Type{NF}, # number format NF
      +            )

      Divergence of a vector u,v written into div, div = ∇⋅(u,v). u,v are expected to have a 1/coslat-scaling included, then div is not scaled. flipsign option calculates -∇⋅(u,v) instead. add option calculates div += ∇⋅(u,v) instead. flipsign and add can be combined. This functions only creates the kernel and calls the generic divergence function _divergence! subsequently.

      source
      SpeedyWeather.SpeedyTransforms.get_recursion_factorsMethod
      get_recursion_factors(  ::Type{NF}, # number format NF
                               lmax::Int,  # max degree l of spherical harmonics (0-based here)
                               mmax::Int   # max order m of spherical harmonics
      -                        ) where {NF<:AbstractFloat}

      Returns a matrix of recursion factors ϵ up to degree lmax and order mmax of number format NF.

      source
      SpeedyWeather.SpeedyTransforms.gridded!Method
      gridded!(   map::AbstractGrid,
                   alms::LowerTriangularMatrix,
      -            S::SpectralTransform)

      Spectral transform (spectral to grid) of the spherical harmonic coefficients alms to a gridded field map. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.

      source
      SpeedyWeather.SpeedyTransforms.griddedMethod
      gridded(
      +            S::SpectralTransform)

      Spectral transform (spectral to grid) of the spherical harmonic coefficients alms to a gridded field map. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.

      source
      SpeedyWeather.SpeedyTransforms.griddedMethod
      gridded(
           alms::AbstractArray{T<:Complex{NF}, 2};
           recompute_legendre,
           Grid
       ) -> Any
      -

      Spectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map. Based on the size of alms the grid type grid, the spatial resolution is retrieved based on the truncation defined for grid. SpectralTransform struct S is allocated to execute gridded(alms,S).

      source
      SpeedyWeather.SpeedyTransforms.griddedMethod
      gridded(
      +

      Spectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map. Based on the size of alms the grid type grid, the spatial resolution is retrieved based on the truncation defined for grid. SpectralTransform struct S is allocated to execute gridded(alms,S).

      source
      SpeedyWeather.SpeedyTransforms.griddedMethod
      gridded(
           alms::AbstractMatrix,
           S::SpectralTransform{NF}
       ) -> Any
      -

      Spectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map with precalculated properties based on the SpectralTransform struct S. alms is converted to a LowerTriangularMatrix to execute the in-place gridded!.

      source
      SpeedyWeather.SpeedyTransforms.roundup_fftMethod
      m = roundup_fft(n::Int;
      -                small_primes::Vector{Int}=[2,3,5])

      Returns an integer m >= n with only small prime factors 2, 3 (default, others can be specified with the keyword argument small_primes) to obtain an efficiently fourier-transformable number of longitudes, m = 2^i * 3^j * 5^k >= n, with i,j,k >=0.

      source
      SpeedyWeather.SpeedyTransforms.spectral!Method
      spectral!(  alms::LowerTriangularMatrix,
      +

      Spectral transform (spectral to grid space) from spherical coefficients alms to a newly allocated gridded field map with precalculated properties based on the SpectralTransform struct S. alms is converted to a LowerTriangularMatrix to execute the in-place gridded!.

      source
      SpeedyWeather.SpeedyTransforms.roundup_fftMethod
      m = roundup_fft(n::Int;
      +                small_primes::Vector{Int}=[2,3,5])

      Returns an integer m >= n with only small prime factors 2, 3 (default, others can be specified with the keyword argument small_primes) to obtain an efficiently fourier-transformable number of longitudes, m = 2^i * 3^j * 5^k >= n, with i,j,k >=0.

      source
      SpeedyWeather.SpeedyTransforms.spectral!Method
      spectral!(  alms::LowerTriangularMatrix,
                   map::AbstractGrid,
      -            S::SpectralTransform)

      Spectral transform (grid to spectral space) from the gridded field map on a grid<:AbstractGrid to a LowerTriangularMatrix of spherical harmonic coefficients alms. Uses FFT in the zonal direction, and a Legendre Transform in the meridional direction exploiting symmetries. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.

      source
      SpeedyWeather.SpeedyTransforms.spectralMethod
      spectral(
      +            S::SpectralTransform)

      Spectral transform (grid to spectral space) from the gridded field map on a grid<:AbstractGrid to a LowerTriangularMatrix of spherical harmonic coefficients alms. Uses FFT in the zonal direction, and a Legendre Transform in the meridional direction exploiting symmetries. The spectral transform is number format-flexible as long as the parametric types of map, alms, S are identical. The spectral transform is grid-flexible as long as the typeof(map)<:AbstractGrid. Uses the precalculated arrays, FFT plans and other constants in the SpectralTransform struct S.

      source
      SpeedyWeather.SpeedyTransforms.spectralMethod
      spectral(
           map::AbstractMatrix;
           Grid,
           kwargs...
       ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
      -

      Converts map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).

      source
      SpeedyWeather.SpeedyTransforms.spectralMethod
      spectral(
           map::SpeedyWeather.RingGrids.AbstractGrid,
           S::SpectralTransform{NF}
       ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
      -

      Spectral transform (grid to spectral) map to grid(map) to execute spectral(map::AbstractGrid;kwargs...).

      source
      SpeedyWeather.SpeedyTransforms.spectralMethod
      spectral(
           map::SpeedyWeather.RingGrids.AbstractGrid{NF};
           recompute_legendre,
           one_more_degree
       ) -> LowerTriangularMatrix{Complex{NF}} where NF<:AbstractFloat
      -

      Converts map to Grid(map) to execute spectral(map::AbstractGrid;kwargs...).

      source
      SpeedyWeather.SpeedyTransforms.spectral_interpolationMethod
      alms_interp = spectral_interpolation(   ::Type{NF},
                                               alms::LowerTriangularMatrix,
                                               ltrunc::Integer,
                                               mtrunc::Integer
      -                                        ) where NF

      Returns a spectral coefficient matrix alms_interp that is alms padded with zeros to interpolate in spectral space. If trunc is smaller or equal to the implicit truncation in alms obtained from its size than spectral_truncation is automatically called instead, returning alms_trunc, a coefficient matrix that is smaller than alms, implicitly setting higher degrees and orders to zero.

      source
      SpeedyWeather.SpeedyTransforms.spectral_smoothing!Method
      spectral_smoothing!(A::LowerTriangularMatrix,c;power=1)

      Smooth the spectral field A following A = (1-(1-c)∇²ⁿ) with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c>1.

      source
      SpeedyWeather.SpeedyTransforms.spectral_smoothingMethod
      A_smooth = spectral_smoothing(A::LowerTriangularMatrix,c;power=1)

      Smooth the spectral field A following A_smooth = (1-c*∇²ⁿ)A with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c<0.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncation!Method
      spectral_truncation!(alms::AbstractMatrix,ltrunc::Integer,mtrunc::Integer)

      Truncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncation!Method
      spectral_truncation!(alms::LowerTriangularMatrix,ltrunc::Integer,mtrunc::Integer)

      Truncate spectral coefficients alms in-place by setting all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc. Similar to spectral_truncation!(::AbstractMatrix, ...) but skips the upper triangle which is zero by design for LowerTriangularMatrix.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncationMethod
      alms_trunc = spectral_truncation(alms,trunc)

      Returns a spectral coefficient matrix alms_trunc that is truncated from alms to the size (trunc+1)². alms_trunc only contains those coefficient of alms for which m,l ≤ trunc, and l ≥ m are zero anyway. If trunc is larger than the implicit truncation in alms obtained from its size than spectral_interpolation is automatically called instead, returning alms_interp, a coefficient matrix that is larger than alms with padded zero coefficients.

      source
      SpeedyWeather.SpeedyTransforms.ϵlmMethod
      ϵ = ϵ(l,m)

      Recursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) with default number format Float64.

      source
      SpeedyWeather.SpeedyTransforms.ϵlmMethod
      ϵ = ϵ(NF,l,m)

      Recursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) and then converted to number format NF.

      source
      SpeedyWeather.SpeedyTransforms.∇²!Method
      ∇²!(    ∇²alms::LowerTriangularMatrix,
      +                                        ) where NF

      Returns a spectral coefficient matrix alms_interp that is alms padded with zeros to interpolate in spectral space. If trunc is smaller or equal to the implicit truncation in alms obtained from its size than spectral_truncation is automatically called instead, returning alms_trunc, a coefficient matrix that is smaller than alms, implicitly setting higher degrees and orders to zero.

      source
      SpeedyWeather.SpeedyTransforms.spectral_smoothing!Method
      spectral_smoothing!(A::LowerTriangularMatrix,c;power=1)

      Smooth the spectral field A following A = (1-(1-c)∇²ⁿ) with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c>1.

      source
      SpeedyWeather.SpeedyTransforms.spectral_smoothingMethod
      A_smooth = spectral_smoothing(A::LowerTriangularMatrix,c;power=1)

      Smooth the spectral field A following A_smooth = (1-c*∇²ⁿ)A with power n of a normalised Laplacian so that the highest degree lmax is dampened by multiplication with c. Anti-diffusion for c<0.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncation!Method
      spectral_truncation!(alms::AbstractMatrix,ltrunc::Integer,mtrunc::Integer)

      Truncate spectral coefficients alms in-place by setting (a) the upper right triangle to zero and (b) all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncation!Method
      spectral_truncation!(alms::LowerTriangularMatrix,ltrunc::Integer,mtrunc::Integer)

      Truncate spectral coefficients alms in-place by setting all coefficients for which the degree l is larger than the truncation ltrunc or order m larger than the truncaction mtrunc. Similar to spectral_truncation!(::AbstractMatrix, ...) but skips the upper triangle which is zero by design for LowerTriangularMatrix.

      source
      SpeedyWeather.SpeedyTransforms.spectral_truncationMethod
      alms_trunc = spectral_truncation(alms,trunc)

      Returns a spectral coefficient matrix alms_trunc that is truncated from alms to the size (trunc+1)². alms_trunc only contains those coefficient of alms for which m,l ≤ trunc, and l ≥ m are zero anyway. If trunc is larger than the implicit truncation in alms obtained from its size than spectral_interpolation is automatically called instead, returning alms_interp, a coefficient matrix that is larger than alms with padded zero coefficients.

      source
      SpeedyWeather.SpeedyTransforms.ϵlmMethod
      ϵ = ϵ(l,m)

      Recursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) with default number format Float64.

      source
      SpeedyWeather.SpeedyTransforms.ϵlmMethod
      ϵ = ϵ(NF,l,m)

      Recursion factors ϵ as a function of degree l and order m (0-based) of the spherical harmonics. ϵ(l,m) = sqrt((l^2-m^2)/(4*l^2-1)) and then converted to number format NF.

      source
      SpeedyWeather.SpeedyTransforms.∇²!Method
      ∇²!(    ∇²alms::LowerTriangularMatrix,
               alms::LowerTriangularMatrix,
               S::SpectralTransform;
               add::Bool=false,
               flipsign::Bool=false,
      -        inverse::Bool=false)

      Laplace operator ∇² applied to the spectral coefficients alms in spherical coordinates. The radius R is omitted in the eigenvalues which are precomputed in S. ∇²! is the in-place version which directly stores the output in the first argument ∇²alms.

      Keyword arguments

      • add=true adds the ∇²(alms) to the output
      • flipsign=true computes -∇²(alms) instead
      • inverse=true computes ∇⁻²(alms) instead

      Default is add=false, flipsign=false, inverse=false. These options can be combined.

      source
      SpeedyWeather.SpeedyTransforms.∇⁻²!Method
      ∇⁻²!(   ∇⁻²alms::LowerTriangularMatrix,
      +        inverse::Bool=false)

      Laplace operator ∇² applied to the spectral coefficients alms in spherical coordinates. The radius R is omitted in the eigenvalues which are precomputed in S. ∇²! is the in-place version which directly stores the output in the first argument ∇²alms.

      Keyword arguments

      • add=true adds the ∇²(alms) to the output
      • flipsign=true computes -∇²(alms) instead
      • inverse=true computes ∇⁻²(alms) instead

      Default is add=false, flipsign=false, inverse=false. These options can be combined.

      source
      SpeedyWeather.SpeedyTransforms.∇⁻²!Method
      ∇⁻²!(   ∇⁻²alms::LowerTriangularMatrix,
               alms::LowerTriangularMatrix,
               S::SpectralTransform;
               add::Bool=false,
      -        flipsign::Bool=false)

      Calls ∇²!(∇⁻²alms, alms, S; add, flipsign, inverse=true).

      source
      + flipsign::Bool=false)

      Calls ∇²!(∇⁻²alms, alms, S; add, flipsign, inverse=true).

      source
      diff --git a/previews/PR363/time_integration/index.html b/previews/PR363/time_integration/index.html deleted file mode 100644 index fd55a7a0e..000000000 --- a/previews/PR363/time_integration/index.html +++ /dev/null @@ -1,2 +0,0 @@ - -Time integration · SpeedyWeather.jl