LES Models API
Types
Abstract Types
abstract type SGSModel end
abstract type EddyViscosityModel <: SGSModel endSmagorinskyModel
Tarang.SmagorinskyModel — Type
SmagorinskyModel{T, N, A, Arch}Classic Smagorinsky (1963) subgrid-scale model.
Mathematical Formulation
The eddy viscosity is:
νₑ = (Cₛ Δ)² |S̄|where:
- Cₛ is the Smagorinsky constant (typically 0.1-0.2)
- Δ is the filter width (grid spacing)
- |S̄| = √(2 S̄ᵢⱼ S̄ᵢⱼ) is the strain rate magnitude
Fields
C_s::T: Smagorinsky constantfilter_width::NTuple{N, T}: Filter width in each direction (Δx, Δy, ...)eddy_viscosity::A: Cached eddy viscosity field (Array or CuArray)strain_magnitude::A: Cached |S̄| fieldarchitecture::Arch: CPU() or GPU() architecture
Example
# Create model for 256³ domain with Δ = 2π/256
model = SmagorinskyModel(
C_s = 0.17,
filter_width = (2π/256, 2π/256, 2π/256),
field_size = (256, 256, 256)
)
# Create GPU model
model_gpu = SmagorinskyModel(
C_s = 0.17,
filter_width = (2π/256, 2π/256, 2π/256),
field_size = (256, 256, 256),
architecture = GPU()
)
# Compute eddy viscosity from velocity gradients
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂u∂z, ∂v∂x, ∂v∂y, ∂v∂z, ∂w∂x, ∂w∂y, ∂w∂z)
# Access the result
νₑ = get_eddy_viscosity(model)Classic Smagorinsky (1963) subgrid-scale model.
Type signature:
mutable struct SmagorinskyModel{T<:AbstractFloat, N} <: EddyViscosityModelFields:
| Field | Type | Description |
|---|---|---|
C_s | T | Smagorinsky constant |
filter_width | NTuple{N, T} | Filter width (Δx, Δy, Δz) |
effective_delta | T | Effective Δ = (Δx Δy Δz)^(1/N) |
eddy_viscosity | Array{T, N} | νₑ field |
strain_magnitude | Array{T, N} | |S̄| field |
field_size | NTuple{N, Int} | Grid dimensions |
Constructor:
SmagorinskyModel(;
C_s = 0.17,
filter_width::NTuple{N, Real},
field_size::NTuple{N, Int},
dtype = Float64
)AMDModel
Tarang.AMDModel — Type
AMDModel{T, N, A, Arch}Anisotropic Minimum Dissipation model (Rozema et al., 2015).
Mathematical Formulation
The eddy viscosity is:
νₑ = max(0, νₑ†)where the predictor is:
νₑ† = -C (Δₖ² ∂uᵢ/∂xₖ ∂uⱼ/∂xₖ Sᵢⱼ) / (∂uₘ/∂xₙ ∂uₘ/∂xₙ)Key features:
- Uses anisotropic filter widths Δₖ in each direction
- Automatically switches off in laminar/transitional regions
- Provides minimum dissipation required for subgrid energy transfer
- No explicit filtering or test-filtering required
Fields
C::T: Poincaré constant (model constant)filter_width::NTuple{N, T}: Anisotropic filter widths (Δx, Δy, Δz)eddy_viscosity::A: Cached eddy viscosity field (Array or CuArray)eddy_diffusivity::A: Cached eddy diffusivity (for scalars)architecture::Arch: CPU() or GPU() architecture
Model Constant Recommendations
| Discretization | C |
|---|---|
| Spectral methods | 1/12 ≈ 0.0833 |
| 4th-order finite difference | 0.212 |
| 2nd-order finite difference | 0.3 |
Example
# Create AMD model for anisotropic grid
model = AMDModel(
C = 1/12, # Spectral method
filter_width = (2π/256, 2π/256, 2π/64), # Anisotropic
field_size = (256, 256, 64)
)
# Create GPU AMD model
model_gpu = AMDModel(
C = 1/12,
filter_width = (2π/256, 2π/256, 2π/64),
field_size = (256, 256, 64),
architecture = GPU()
)
# Compute eddy viscosity
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂u∂z, ∂v∂x, ∂v∂y, ∂v∂z, ∂w∂x, ∂w∂y, ∂w∂z)References
Rozema, W., Bae, H.J., Moin, P., Verstappen, R. (2015). "Minimum-dissipation models for large-eddy simulation", Physics of Fluids 27, 085107.
Anisotropic Minimum Dissipation model (Rozema et al., 2015).
Type signature:
mutable struct AMDModel{T<:AbstractFloat, N} <: EddyViscosityModelFields:
| Field | Type | Description |
|---|---|---|
C | T | Poincaré constant |
filter_width | NTuple{N, T} | Anisotropic filter widths |
filter_width_sq | NTuple{N, T} | Δₖ² for each direction |
eddy_viscosity | Array{T, N} | νₑ field |
eddy_diffusivity | Array{T, N} | κₑ field (for scalars) |
field_size | NTuple{N, Int} | Grid dimensions |
clip_negative | Bool | Whether to clip νₑ < 0 |
Constructor:
AMDModel(;
C = 1/12,
filter_width::NTuple{N, Real},
field_size::NTuple{N, Int},
clip_negative = true,
dtype = Float64
)Eddy Viscosity Computation
computeeddyviscosity!
Tarang.compute_eddy_viscosity! — Function
compute_eddy_viscosity!(model::SmagorinskyModel, velocity_gradients...)Compute eddy viscosity from velocity gradient components.
GPU-aware: Uses broadcasting for GPU arrays, optimized SIMD loops for CPU.
2D Case
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂v∂x, ∂v∂y)3D Case
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂u∂z, ∂v∂x, ∂v∂y, ∂v∂z, ∂w∂x, ∂w∂y, ∂w∂z)compute_eddy_viscosity!(model::AMDModel, velocity_gradients...)Compute AMD eddy viscosity from velocity gradient components.
GPU-aware: Uses broadcasting for GPU arrays, optimized SIMD loops for CPU.
2D Case
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂v∂x, ∂v∂y)3D Case
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂u∂z, ∂v∂x, ∂v∂y, ∂v∂z, ∂w∂x, ∂w∂y, ∂w∂z)The AMD formula uses anisotropic scaling: νₑ† = -C (Δₖ² ∂uᵢ/∂xₖ ∂uⱼ/∂xₖ Sᵢⱼ) / (∂uₘ/∂xₙ ∂uₘ/∂xₙ)
Compute eddy viscosity from velocity gradient components.
2D Signature:
compute_eddy_viscosity!(model, ∂u∂x, ∂u∂y, ∂v∂x, ∂v∂y)3D Signature:
compute_eddy_viscosity!(model,
∂u∂x, ∂u∂y, ∂u∂z,
∂v∂x, ∂v∂y, ∂v∂z,
∂w∂x, ∂w∂y, ∂w∂z
)Returns: The eddy viscosity array model.eddy_viscosity
computeeddydiffusivity!
Tarang.compute_eddy_diffusivity! — Function
compute_eddy_diffusivity!(model::AMDModel, velocity_gradients..., scalar_gradients...)Compute eddy diffusivity for scalar transport using AMD model.
GPU-aware: Uses broadcasting for GPU arrays, optimized SIMD loops for CPU.
For a scalar field b with gradient ∇b, the eddy diffusivity is:
κₑ = max(0, κₑ†)where: κₑ† = -C (Δₖ² ∂v/∂xₖ ∂b/∂xₖ) / (∂b/∂xₙ ∂b/∂xₙ)
For 2D flows, v is the vertical velocity component. For 3D flows (buoyancy-driven), w is the vertical velocity.
Compute eddy diffusivity for scalar transport (AMD model only).
compute_eddy_diffusivity!(model::AMDModel,
∂w∂x, ∂w∂y, ∂w∂z,
∂b∂x, ∂b∂y, ∂b∂z
)Returns: The eddy diffusivity array model.eddy_diffusivity
Subgrid Stress
computesgsstress
Tarang.compute_sgs_stress — Function
compute_sgs_stress(model::EddyViscosityModel, strain_components...)Compute the deviatoric subgrid stress tensor:
τᵢⱼᵈ = -2 νₑ S̄ᵢⱼGPU-aware: Uses broadcasting which works for both CPU and GPU arrays.
2D Output
Returns (τ11, τ12, τ22).
3D Output
Returns (τ11, τ12, τ13, τ22, τ23, τ33).
Compute deviatoric SGS stress tensor τᵢⱼ = -2 νₑ S̄ᵢⱼ.
2D Signature:
compute_sgs_stress(model, S11, S12, S22) -> (τ11, τ12, τ22)3D Signature:
compute_sgs_stress(model, S11, S12, S13, S22, S23, S33)
-> (τ11, τ12, τ13, τ22, τ23, τ33)Accessors
geteddyviscosity
Tarang.get_eddy_viscosity — Function
get_eddy_viscosity(model::EddyViscosityModel)Return the current eddy viscosity field.
Return the current eddy viscosity field.
get_eddy_viscosity(model::EddyViscosityModel) -> Array{T, N}geteddydiffusivity
Tarang.get_eddy_diffusivity — Function
get_eddy_diffusivity(model::AMDModel)Return the current eddy diffusivity field (AMD model only).
Return the current eddy diffusivity field (AMD only).
get_eddy_diffusivity(model::AMDModel) -> Array{T, N}getfilterwidth
Tarang.get_filter_width — Function
get_filter_width(model::EddyViscosityModel)Return the filter width(s).
Return the filter width tuple.
get_filter_width(model::EddyViscosityModel) -> NTuple{N, T}Statistics
meaneddyviscosity
Tarang.mean_eddy_viscosity — Function
mean_eddy_viscosity(model::EddyViscosityModel)Compute the domain-averaged eddy viscosity.
Compute domain-averaged eddy viscosity.
mean_eddy_viscosity(model::EddyViscosityModel) -> Tmaxeddyviscosity
Tarang.max_eddy_viscosity — Function
max_eddy_viscosity(model::EddyViscosityModel)Return the maximum eddy viscosity in the domain.
Return maximum eddy viscosity in the domain.
max_eddy_viscosity(model::EddyViscosityModel) -> TDissipation Rate
sgs_dissipation
Tarang.sgs_dissipation — Function
sgs_dissipation(model::EddyViscosityModel, strain_magnitude::AbstractArray)Compute the subgrid-scale dissipation rate:
εₛₛ = 2 νₑ |S̄|²GPU-aware: Uses broadcasting which works for both CPU and GPU arrays. Returns the dissipation field.
Compute SGS dissipation rate field: εₛₛ = 2 νₑ |S̄|²
sgs_dissipation(model::EddyViscosityModel, strain_magnitude) -> Array{T, N}meansgsdissipation
Tarang.mean_sgs_dissipation — Function
mean_sgs_dissipation(model::EddyViscosityModel, strain_magnitude::AbstractArray)Compute domain-averaged SGS dissipation rate. GPU-aware: Uses broadcasting and sum() which work for both CPU and GPU arrays.
Compute domain-averaged SGS dissipation rate.
mean_sgs_dissipation(model::EddyViscosityModel, strain_magnitude) -> TConfiguration
set_constant!
Tarang.set_constant! — Function
set_constant!(model::SmagorinskyModel, C_s::Real)Update the Smagorinsky constant.
set_constant!(model::AMDModel, C::Real)Update the AMD Poincaré constant.
Update the model constant.
set_constant!(model::SmagorinskyModel, C_s::Real)
set_constant!(model::AMDModel, C::Real)reset!
Reset eddy viscosity (and diffusivity for AMD) to zero.
reset!(model::EddyViscosityModel)
reset!(model::AMDModel) # Also resets eddy_diffusivityExports
export SGSModel, EddyViscosityModel
export SmagorinskyModel, AMDModel
export compute_eddy_viscosity!, compute_eddy_diffusivity!
export compute_sgs_stress
export get_eddy_viscosity, get_eddy_diffusivity, get_filter_width
export mean_eddy_viscosity, max_eddy_viscosity
export reset!, set_constant!
export sgs_dissipation, mean_sgs_dissipationIndex
Tarang.AMDModelTarang.SmagorinskyModelTarang.compute_eddy_diffusivity!Tarang.compute_eddy_viscosity!Tarang.compute_sgs_stressTarang.get_eddy_diffusivityTarang.get_eddy_viscosityTarang.get_filter_widthTarang.max_eddy_viscosityTarang.mean_eddy_viscosityTarang.mean_sgs_dissipationTarang.set_constant!Tarang.sgs_dissipation