Forcing

Forcing types

VortexPasta.Forcing.NormalFluidForcingType
NormalFluidForcing <: AbstractForcing
NormalFluidForcing(vn::Function; α, α′ = 0)

Forcing due to mutual friction with a normal fluid.

The normal fluid is represented by a function vn which should take a position x⃗::SVector{N, T} and return a velocity v⃗::SVector{N, T} (N is the number of dimensions, usually N = 3).

In particular, the function could be a synthetic velocity field from the SyntheticFields module (see below for examples).

This type of forcing defines an external velocity $\bm{v}_{\text{f}}$ affecting vortex motion, so that the actual vortex velocity $\bm{v}_{\text{L}}$ is

\[\frac{\mathrm{d}\bm{s}}{\mathrm{d}t} = \bm{v}_{\text{L}} = \bm{v}_{\text{s}} + \bm{v}_{\text{f}}.\]

Here $\bm{v}_{\text{s}}$ is the self-induced velocity obtained by applying Biot–Savart's law.

The forcing velocity is of the form:

\[\bm{v}_{\text{f}} = α \bm{s}' × \bm{v}_{\text{ns}} - α' \bm{s}' × \left( \bm{s}' × \bm{v}_{\text{ns}} \right)\]

where $\bm{s}'$ is the local unit tangent vector, $\bm{v}_{\text{ns}} = \bm{v}_{\text{n}} - \bm{v}_{\text{s}}$ is the local slip velocity, and $α$ and $α'$ are non-dimensional coefficients representing the intensity of Magnus and drag forces.

Note

This "forcing" generally affects all lengthscales, even when $\bm{v}_{\text{n}}$ is a large-scale flow. This may be unwanted for turbulence simulations. In that case, the alternative FourierBandForcing method can be more relevant.

Example

Define a mutual friction forcing based on a large-scale normal fluid velocity field (see SyntheticFields.FourierBandVectorField):

julia> using VortexPasta.Forcing: NormalFluidForcing

julia> using VortexPasta.SyntheticFields: SyntheticFields, FourierBandVectorField

julia> using Random: Xoshiro

julia> rng = Xoshiro(42);  # initialise random number generator (optional, but recommended)

julia> Ls = (2π, 2π, 2π);  # domain dimensions

julia> vn_rms = 1.0;  # typical magnitude (rms value) of normal fluid velocity components

julia> vn = FourierBandVectorField(undef, Ls; kmin = 0.1, kmax = 1.5)  # create field with non-zero Fourier wavevectors kmin ≤ |k⃗| ≤ kmax
FourierBandVectorField{Float64, 3} with 9 independent Fourier coefficients in |k⃗| ∈ [1.0, 1.4142]

julia> SyntheticFields.init_coefficients!(rng, vn, vn_rms);  # randomly set non-zero Fourier coefficients of the velocity field

julia> forcing = NormalFluidForcing(vn; α = 0.8, α′ = 0)
NormalFluidForcing{Float64} with:
 ├─ Normal velocity field: FourierBandVectorField{Float64, 3} with 9 independent Fourier coefficients in |k⃗| ∈ [1.0, 1.4142]
 └─ Friction coefficients: α = 0.8 and α′ = 0.0
source
VortexPasta.Forcing.FourierBandForcingType
FourierBandForcing <: AbstractForcing
FourierBandForcing(vn::FourierBandVectorField; α, α′ = 0, filtered_vorticity = false)

Forcing due to mutual friction of a normal fluid with a Fourier-filtered superfluid velocity.

This forcing is similar to NormalFluidForcing, but tries to only affect scales within a given band [kmin, kmax] in Fourier space. This is achieved by a normal fluid velocity field represented by a FourierBandVectorField, and by a modified Schwarz's equation in which only a coarse-grained superfluid flow is taken into account in the estimation of the mutual friction term.

Concretely, the vortex line velocity according to this forcing type is:

\[\frac{\mathrm{d}\bm{s}}{\mathrm{d}t} = \bm{v}_{\text{L}} = \bm{v}_{\text{s}} + \bm{v}_{\text{f}}\]

The forcing velocity is of the form:

\[\bm{v}_{\text{f}} = α \bm{s}' × \bm{v}_{\text{ns}}^{>} - α' \bm{s}' × \left( \bm{s}' × \bm{v}_{\text{ns}}^{>} \right)\]

where $\bm{v}_{\text{ns}}^{>} = \bm{v}_{\text{n}} - \bm{v}_{\text{s}}^{>}$ is a filtered slip velocity. In practice, the filtered velocity is active within the same wavenumber range [kmin, kmax] where vn is defined. See NormalFluidForcing for other definitions.

Using a filtered vorticity field

To further ensure that this forcing only affects the chosen range of scales, one can pass filtered_vorticity = true, which will replace the local unit tangent $\bm{s}'$ with a normalised coarse-grained vorticity. This corresponds to setting $\bm{s}' = \bm{ω}^{>} / |\bm{ω}^{>}|$ where $\bm{ω}^{>}$ is the Fourier-filtered vorticity field.

source
VortexPasta.Forcing.FourierBandForcingBSType
FourierBandForcingBS <: AbstractForcing
FourierBandForcingBS(; kmin, kmax, α, ε_target)

Forcing based on Biot–Savart energetics within a given range of wavenumbers.

This type of forcing does not rely on an imposed normal fluid velocity. Instead, it starts from the functional derivative of the energy at a given wavevector $\bm{k}$ with respect to the vortex positions (according to the Biot–Savart law), and applies a velocity that ensures energy to increase (if $α > 0$ or $ε_{\text{target}} > 0$) at those wavevectors.

One should pass either α or ε_target but never both. They should be positive for energy injection (negative values lead to energy dissipation):

  • α (\alpha) is a non-dimensional coefficient which directly sets the amplitude of the forcing velocity;

  • ε_target (\varepsilon_target) has the units of an energy injection rate. In this case, the amplitude $α$ will be adjusted over time in order to keep a roughly constant energy injection rate (which in general will not be equal to ε_target, see remarks below).

Extended help

Forcing definition

This forcing attempts to increase the kinetic energy at selected wavenumbers. Its definition starts from the expression for the kinetic energy at wavenumber $\bm{k}$:

\[E(\bm{k}) = \frac{1}{2} |\bm{v}(\bm{k})|^2 = \frac{1}{2k^2} |\bm{ω}(\bm{k})|^2\]

The idea is to translate the vortex positions by $\bm{s}(ξ) → \bm{s}(ξ) + δ\bm{s}(ξ)$ so that the energy $E(\bm{k})$ increases. To determine such a displacement, one can look at the functional derivative of $E(\bm{k})$ with respect to the positions $\bm{s}$:

\[\begin{align*} \frac{δE(\bm{k})}{δ\bm{s}} &= \frac{1}{2k^2} \bm{ω}(\bm{k}) ⋅ \frac{δ\bm{ω}^*(\bm{k})}{δ\bm{s}} + \text{c.c.}, \\ &= \frac{1}{2} \bm{ψ}(\bm{k}) ⋅ \frac{δ\bm{ω}^*(\bm{k})}{δ\bm{s}} + \text{c.c.}, \end{align*}\]

where $()^*$ denotes a complex conjugate and "c.c." means the complex conjugate of the first term. Here we have used $\bm{ω}(\bm{k}) = k^2 \bm{ψ}(\bm{k})$, which corresponds in physical space to $\bm{ω} = -∇² \bm{ψ}$.

The functional derivative of vorticity in Fourier space is:

\[\begin{align*} \frac{δ\bm{ω}^*(\bm{k})}{δ\bm{s}} &= \frac{Γ}{V} \frac{δ}{δ\bm{s}} ∮ e^{+i \bm{k} ⋅ \bm{s}(ξ)} \bm{s}(ξ)' \, \text{d}ξ \\ &= \frac{Γ}{V} \frac{δ}{δ\bm{s}} ∮ \bm{ℒ}[\bm{s}(ξ), \bm{s}(ξ)'] \, \text{d}ξ \\ &= \frac{Γ}{V} \left[ \frac{∂\bm{ℒ}}{∂\bm{s}} - \frac{\text{d}}{\text{d}ξ} \frac{∂\bm{ℒ}}{∂\bm{s}'} \right] \\ &= \frac{i Γ}{V} e^{+i \bm{k} ⋅ \bm{s}} \left[ \bm{k} ⊗ \bm{s}' - (\bm{k} ⋅ \bm{s}') I \right] = \frac{i Γ}{V} \bm{B}(\bm{k}, \bm{s}, \bm{s}') \end{align*}\]

where $\bm{B}$ is a $3×3$ complex matrix which has dimensions of an inverse length ($L^{-1}$).

The functional derivative of $E(\bm{k})$ can now be written as:

\[\begin{align*} \frac{δE(\bm{k})}{δ\bm{s}} &= \frac{Γ}{2V} i \bm{B} \bm{ψ}(\bm{k}) + \text{c.c.} \\ &= \frac{Γ}{2V} [\bm{s}' × \bm{v}(\bm{k})] e^{i \bm{k} ⋅ \bm{s}} + \text{c.c.} \\ &= ℜ \left\{ \frac{Γ}{V} [\bm{s}' × \bm{v}(\bm{k})] e^{i \bm{k} ⋅ \bm{s}} \right\} \end{align*}\]

Finally, the idea is to advect the filaments with a velocity which is parallel to this result for each forced $\bm{k}$. One can write this velocity as

\[\bm{v}_{\text{f}}(\bm{k}, \bm{s}) = α \, ℜ \left\{ [\bm{s}' × \bm{v}(\bm{k})] e^{i \bm{k} ⋅ \bm{s}} \right\} = α \, \bm{v}_0(\bm{k}, \bm{s})\]

where $α$ is a non-dimensional parameter setting the forcing amplitude.

Estimating the energy injection rate

One can also try to estimate an energy injection rate at wavevector $\bm{k}$ associated to this velocity:

\[\frac{\text{d}E(\bm{k})}{\text{d}t} = ∮ \frac{δE(\bm{k})}{δ\bm{s}} ⋅ \frac{\text{d}\bm{s}}{\text{d}t} \, \mathrm{d}ξ = α \frac{Γ}{V} ∮ |\bm{v}_0|^2 \, \mathrm{d}ξ\]

In general, this estimate may be quite inaccurate since the forcing can also affect the energy at wavevectors other than $\bm{k}$. But still, this estimate is the one used when $ε_{\text{target}}$ is given, and may allow to obtain a roughly constant energy injection rate (even if it's generally different than the "target" one).

source

Abstract types

Internals

VortexPasta.Forcing.apply!Function
Forcing.apply!(forcing::AbstractForcing, vs::AbstractVector{<:Vec3}, f::AbstractFilament; [scheduler])

Apply forcing to a single filament f with self-induced velocities vs.

At output, the vs vector is overwritten with the actual vortex line velocities.

The optional scheduler keyword can be used to parallelise computations using one of the schedulers defined in OhMyThreads.jl.


Forcing.apply!(forcing::NormalFluidForcing, vs, vn, tangents; [scheduler])

This variant can be used in the case of a NormalFluidForcing if one already has precomputed values of the normal fluid velocity and local unit tangents at filament points.

source