FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches

Velocity deficit fields behind nets and other porous structures. More...

+ Collaboration diagram for Wake Models:

Concepts

concept  marenv::wake::WakeBlendSnapshot
 

Classes

struct  marenv::wake::GriddedSnapshot
 
class  marenv::wake::GriddedWake
 
struct  marenv::wake::ImagePlanes
 
struct  marenv::wake::ImageMap
 
struct  marenv::wake::ImageSet
 
struct  marenv::wake::KernelCentreline
 
class  marenv::wake::KernelProfile
 
struct  marenv::wake::LineCoordinates
 
class  marenv::wake::LineKernelProfile
 
struct  marenv::wake::LumpedSourceInput
 
struct  marenv::wake::FlowSample
 
struct  marenv::wake::LumpedSourceResult
 
struct  marenv::wake::LumpedLineSourceInput
 
struct  marenv::wake::LumpedLineSourceResult
 
class  marenv::wake::SourceSetWake
 
class  marenv::wake::MomentumFluxSum
 
struct  marenv::wake::WakeComposition
 
class  marenv::wake::WakeAccumulator
 
class  marenv::wake::WakeBlend< S >
 
class  marenv::wake::WakeBuilder
 
struct  marenv::wake::WakeQueryRegion
 
class  marenv::wake::WakeField
 
struct  marenv::wake::WakeQuery
 
class  marenv::wake::WakeRegistry
 
struct  marenv::wake::WakeBlendSum
 
struct  marenv::wake::WakeBlendSamples
 
struct  marenv::wake::WakeSampleParts
 
struct  marenv::wake::WakeSample
 
struct  marenv::wake::ElementarySource
 
struct  marenv::wake::LineSource
 
struct  marenv::wake::WakeFrame
 
struct  marenv::wake::GridSpec
 
struct  marenv::wake::KernelParams
 
struct  marenv::wake::SourceSet
 

Enumerations

enum class  marenv::wake::Superposition { Superposition::Product , Superposition::MomentumFlux }
 

Functions

double marenv::wake::ElementaryDeficit (const ElementarySource &source, const KernelParams &params, const double pos[3])
 
void marenv::wake::Validate (const KernelParams &params)
 
ImagePlanes marenv::wake::MirrorPlanes (const KernelParams &params)
 
ImageSet marenv::wake::MirrorImages (const KernelParams &params)
 
double marenv::wake::ElementaryDeficit (const ElementarySource &source, const KernelProfile &profile, const double pos[3])
 
double marenv::wake::LineDeficit (const LineKernelProfile &profile, const double pos[3])
 
double marenv::wake::LineDeficit (const LineSource &source, const KernelParams &params, const double pos[3])
 
void marenv::wake::SetRelativeFlowFromSamples (const std::vector< FlowSample > &samples, LumpedSourceInput &input)
 
double marenv::wake::ReferenceSpeedSquared (const LumpedSourceInput &input)
 
LumpedSourceResult marenv::wake::MakeLumpedSource (const LumpedSourceInput &input)
 
LumpedSourceResult marenv::wake::RelaxLumpedSource (const LumpedSourceInput &input, const LumpedSourceResult &fresh, double previousMomentum, double alpha)
 
KernelParams marenv::wake::LumpedKernel (const KernelParams &user)
 
LumpedLineSourceResult marenv::wake::MakeLumpedLineSource (const LumpedLineSourceInput &input)
 
double marenv::wake::detail::DeficitFromMomentumFlux (double flux)
 
double marenv::wake::detail::MomentumFluxBound (double sumOfBounds)
 
double marenv::wake::BlendWeight (double t, double start, double time)
 

Variables

constexpr double marenv::wake::kMaxThrustCoefficient = 0.96
 
constexpr double marenv::wake::kEpsilonFactor = 0.2
 
constexpr double marenv::wake::kParallelAxisTolerance = 1e-9
 
constexpr double marenv::wake::kMinRelativeFlow = 1e-3
 
constexpr double marenv::wake::kMomentumFluxBranchDeficit = 0.45
 

Detailed Description

A wake field is the velocity deficit behind a net or a structure, defined in the frame of its source and composed with other wakes into the current that arrives downstream. The group holds the wake field interface, the elementary actuator-disc kernel and three evaluations of it: an analytic porous-disc wake, a direct sum over a set of sources and a gridded wake built from them. See the marenv_wake_manual for the definitions, the composition rule, the threading contract and the known limitations.

Enumeration Type Documentation

◆ Superposition

enum class marenv::wake::Superposition
strong

How a field composes the deficits of its sources and of their images (lead ruling R88, owner ruling R95).

Enumerator
Product 

d = 1 - prod(1 - d_i), screens in series (KF2012 Eq. 15): for sources whose M is normalised by their local, shaded inflow, such as a net's private per-panel field.

MomentumFlux 

D (1 - D) = sum d_i (1 - d_i), the momentum flux kept point by point (R95, replacing R88's min(1, sum d_i); Superposition.h, MomentumFluxSum): for sources whose M is normalised by the ambient dynamic pressure (R87), such as the lumped sources of MakeLumpedSource().

Function Documentation

◆ BlendWeight()

double marenv::wake::BlendWeight ( double  t,
double  start,
double  time 
)
inline

The C1 smoothstep weight of the snapshot blended to at t: s = 3 tau^2 - 2 tau^3, tau = (t - start) / time, clamped to [0, 1]; 1 without blending (time <= 0 or NaN).

◆ DeficitFromMomentumFlux()

double marenv::wake::detail::DeficitFromMomentumFlux ( double  flux)

Returns the conserving deficit C(S) of a momentum-flux sum (R95).

Parameters
[in]fluxS = sum d_i (1 - d_i).
Returns
0 for S <= 0; 1/2 (1 - sqrt(1 - 4 S)) (evaluated as 2 S / (1 + sqrt(1 - 4 S)) to keep small deficits exact) for S <= d_b (1 - d_b); the tangent continuation d_b + (S - d_b (1 - d_b)) / (1 - 2 d_b) up to 1/2; 1/2 beyond. Continuous and non-decreasing, with slope at most 1 / (1 - 2 d_b).

◆ ElementaryDeficit() [1/2]

double marenv::wake::ElementaryDeficit ( const ElementarySource &  source,
const KernelParams &  params,
const double  pos[3] 
)

Returns the velocity deficit of one elementary source at a point.

Parameters
[in]sourceThe elementary source; source.flowDir must be a unit vector.
[in]paramsThe kernel parameters.
[in]posQuery position, m, world NED at the source's build time.
Returns
Deficit d in [0, 1]; 0 upstream of x_start, and 0 for a source with no area or no momentum deficit.

The pinned kernel of contract C4, an actuator-disc near wake that becomes the Gaussian far wake of Bastankhah and Porte-Agel (2014). C_T = min(M / area, 0.96) and D = sqrt(4 area / pi). Near wake a = (1 - sqrt(1 - C_T)) / 2 and d_near = 2 a. Far wake beta = (1 + sqrt(1 - C_T)) / (2 sqrt(1 - C_T)), epsilon = 0.2 sqrt(beta), sigma/D = k x/D + epsilon and C(x) = 1 - sqrt(1 - C_T / (8 (sigma/D)^2)). Then d = min(C, d_near) exp(-rho^2 / (2 sigma^2)) for x >= x_start = max(xStartFactor D, xStartMin), else 0, with x along flowDir and rho across it.

Self-similar far wake (owner ruling R57): from x_f = max(farWakeStartFactor D, x_p) on (k > 0), sigma = sigma_f (1 + 3 k (x - x_f) / sigma_f)^(1/3) with sigma_f the linear-growth sigma at x_f, so sigma and its slope are continuous there and, with C(x) unchanged, the momentum deficit is kept and the centreline decays as (x - x_0)^(-2/3), the classical axisymmetric wake (Tennekes and Lumley 1972, ch. 4; Pope 2000, ch. 5). farWakeStartFactor = infinity keeps the linear growth.

Close to the source the far-wake amplitude is undefined (C_T > 8 (sigma/D)^2); there C is taken as 1, so that the near-wake value d_near applies, which is the limit of min(C, d_near) as the radicand goes to zero. params.cutoff is not applied here; it truncates footprints in the gridded builder. Exposed for tests.

A porous source (source.solidity = Sn > 0) has the near wake of MF2022 Eq. 11, r = 1.08 - 0.97 Sn (contract C4, phase F amendment). With d_mom = d_near and the plateau d_m = clamp(0.97 Sn - 0.08, 0, d_mom), the centreline amplitude min(C, d_near) above becomes d_m for x_start <= x <= x_m = 0.579 D (MF2022's meter 0.715 m behind the centre of a 1.215 x 0.985 m panel, scaled with its D = 1.234 m), d_m + (d_mom - d_m) S(xi) with the smoothstep S(xi) = xi^2 (3 - 2 xi) and xi = (x - x_m) / (x_p - x_m) for x_m < x < x_p, and min(C, d_near) from x_p = (1 / sqrt(8) - epsilon) D / k on, where C(x_p) = d_mom, so the far wake and its momentum are those of the pinned kernel. sigma(x), the Gaussian across the axis and x_start are unchanged. Where x_p is not finite or not beyond x_m (k <= 0, or C_T close to the cap), and for Sn <= 0, the pinned kernel applies; Sn = 0 is the default.

Eq. 11 is written in MF2022's measured solidity Snm (digital image analysis, 2-27 % above the solidity estimated from twine thickness and mesh side, p. 041301-3) and was fitted for Snm in [0.18, 0.36], Rn about 2000 and flow normal to the panel (p. 041301-6); here it is applied to source.solidity at every solidity, angle and Reynolds number (QF3). Nets pass their calculated solidity Snc, from twine thickness and mesh side (owner ruling R56, MENV-0034); the caller is fhsim_marine_elements. At high solidity this near wake disagrees with KF2012 Eq. 15 (test W2 is disabled: r is +0.058 high for N36a against a tolerance of 0.05; MENV-0007, doc/wake.md section 10).

◆ ElementaryDeficit() [2/2]

double marenv::wake::ElementaryDeficit ( const ElementarySource &  source,
const KernelProfile &  profile,
const double  pos[3] 
)

Returns the velocity deficit of one elementary source at a point, from its precomputed profile.

Same result as ElementaryDeficit(source, params, pos) with profile built as KernelProfile(source, params). Used where the profile is built once per source and reused over many query points (SourceSetWake's snapshot, MENV-0036), instead of once per query.

◆ LineDeficit() [1/2]

double marenv::wake::LineDeficit ( const LineKernelProfile &  profile,
const double  pos[3] 
)

Returns the velocity deficit of one line source at a point, from its precomputed profile.

Parameters
[in]profileThe profile of the source.
[in]posQuery position, m, world NED at the source's build time.
Returns
Deficit d in [0, 1]; 0 upstream of x_start.

◆ LineDeficit() [2/2]

double marenv::wake::LineDeficit ( const LineSource &  source,
const KernelParams &  params,
const double  pos[3] 
)

Returns the velocity deficit of one line source at a point; see LineKernelProfile for the kernel.

Exceptions
std::invalid_argumentas LineKernelProfile.

◆ LumpedKernel()

KernelParams marenv::wake::LumpedKernel ( const KernelParams &  user)

Returns the kernel parameters of a field that holds lumped sources: the caller's kernel with the wake starting at the rear face and the momentum-flux composition.

Parameters
[in]userThe caster's kernel parameters.
Returns
user with xStartFactor = 0 and xStartMin = 0, so x_start = 0 (QF7), and superposition = Superposition::MomentumFlux (R95, consistent with the ambient normalisation of M, R87); the other members unchanged. The one rule that fhsim_environment's LumpedWakeCaster and fhsim_marine_elements' NetWakeCaster apply to their lumped fields (MENV-0057).

◆ MakeLumpedLineSource()

LumpedLineSourceResult marenv::wake::MakeLumpedLineSource ( const LumpedLineSourceInput &  input)

Returns the one line source a wake-casting slender body shows to every other object (MENV-0044).

M and the flow direction e_U are those of MakeLumpedSource(), with the same reference speed (R87, R55). With L the length projected on the plane normal to e_U (length times |axis x e_U|), the frontal area is L times the width. If M / (L width) > 0.96 the width is widened to M / (0.96 L) and widened is set (QF6), so the wake still carries F . e_U. The source sits at input.rearCentre and starts at the rear face (QF7) when the field is published with xStartFactor and xStartMin 0; the field composes it by the momentum-flux rule (R95).

When the axis is parallel to the relative flow, or the (widened) width is not smaller than the projected length, the body does not cast a plane wake: the result is the point source that MakeLumpedSource() would give for the frontal area L width (widened to M / 0.96 as there), with the same M, in LumpedLineSourceResult::point and pointFallback set (MENV-0048). widened is that of the point source then (WakeLine.LumpedLineSourceFallsBackToThePointSourceNearTheParallelLimit_MENV0048): a near-parallel body reports it at every call, because the projected frontal area goes to 0, so a caller logs the widening once per body (when the flag first turns true), not at every rebuild. The source is then never wider across the flow, nor of a larger frontal area, than that point source, and casts does not turn false as the body turns towards the flow while M > 0.

No source (casts = false) as MakeLumpedSource(), and none if the axis is zero or not finite, or the length or width is not finite; this never throws for them.

Exceptions
std::invalid_argumentas MakeLumpedSource(), and if the length or the width is not positive.

◆ MakeLumpedSource()

LumpedSourceResult marenv::wake::MakeLumpedSource ( const LumpedSourceInput &  input)

Returns the one elementary source a wake-casting object shows to every other object.

Parameters
[in]inputThe object's force, relative flow, density, rear-face centre and frontal area.
Returns
The source and the casts and widened flags.

With e_U = U_ref / |U_ref| the momentum deficit is M = max(0, F . e_U) / (0.5 rho q^2), m^2, with q^2 = ReferenceSpeedSquared(input): the mean of |U_amb - u_p|^2 over the object's samples when input.ambientMeanSquareFlow is set (SetRelativeFlowFromSamples(), lead ruling R87), so a shielded body's wake carries the drag it feels, but never less than the shaded value, the mean of |U_p|^2 when input.meanSquareFlow is set (R55), else |U_ref|^2 (R123); the part of F across e_U (lift) is dropped. The source sits at input.rearCentre with flowDir e_U, area A_f and momentum deficit M; its solidity keeps the default 0, the pinned momentum-theory near wake (QF4). No source (casts = false) if |U_ref| < kMinRelativeFlow = 1e-3 m/s or M = 0, since a source without momentum deficit casts nothing, and none if the force, the relative flow, the rear-face centre, the frontal area, the mean square flow, the ambient mean square flow or M is not finite (MENV-0020), so that one diverging object cannot turn every query NaN; this never throws.

If M / A_f > 0.96, the thrust-coefficient cap of the kernel (ElementaryDeficit()), the area is widened to A_f = M / 0.96 and widened is set (QF6), so the far wake still carries F . e_U; the kernel is unchanged. A frontal area of 0 is thereby widened as well.

The wake of a lumped source starts at the rear face (QF7): the field that holds it, a SourceSetWake, is published with LumpedKernel(), whose xStartFactor and xStartMin are 0, so x_start = max(0 D, 0) = 0. A compact body, whose reference point lies upstream of its rear face, then never samples its own source. The field composes the source and its images by the momentum-flux rule, KernelParams::superposition = MomentumFlux (R95, replacing R88's linear sum).

Exceptions
std::invalid_argumentif rho is not positive, the frontal area is negative or not a number, or the mean square flow or the ambient mean square flow is negative.

◆ MirrorImages()

ImageSet marenv::wake::MirrorImages ( const KernelParams &  params)

Returns the images of params (owner rulings R53, R98).

The first level is one mirror image of every source at each plane of MirrorPlanes(params): at the free surface z = 0 (QueryDepth -z) and at the seabed z = H (2 H - z). With both planes the second level adds the image of each first image at the other plane: the surface image mirrored at the seabed, the source shifted down by 2 H (QueryDepth z - 2 H), and the seabed image mirrored at the surface, the source shifted up by 2 H (z + 2 H). No further level: the series is truncated there (R98). With one plane only the first level exists.

Exceptions
std::invalid_argumentif Validate(params) does.

◆ MirrorPlanes()

ImagePlanes marenv::wake::MirrorPlanes ( const KernelParams &  params)

Returns the mirror planes of params (owner ruling R53).

Exceptions
std::invalid_argumentunless params.seabedDepth is positive (infinity included).

◆ MomentumFluxBound()

double marenv::wake::detail::MomentumFluxBound ( double  sumOfBounds)

Returns an upper bound of the composed deficit of deficits whose sum is at most sumOfBounds (R95).

Parameters
[in]sumOfBoundsSum of upper bounds b_i >= d_i.
Returns
max(DeficitFromMomentumFlux(sumOfBounds), min(1, sumOfBounds)) >= MomentumFluxSum::Deficit(), since d_i (1 - d_i) <= d_i <= b_i.

◆ ReferenceSpeedSquared()

double marenv::wake::ReferenceSpeedSquared ( const LumpedSourceInput &  input)

Returns the squared reference speed of the momentum deficit, q^2 in M = F . e_U / (0.5 rho q^2) (R87).

Returns
max(input.ambientMeanSquareFlow, q^2_shaded), with q^2_shaded = input.meanSquareFlow if it is positive (R55), else |input.relativeFlow|^2: the ambient dynamic pressure (R87) wherever shielding makes the shaded flow the smaller one, the shaded one where a moving wake makes it the larger (R123), so M stays bounded by about C_d A and is continuous as the ambient relative flow goes to 0. A caster that relaxes M (M -> alpha M + (1 - alpha) M_prev) does so with RelaxLumpedSource(), which rebuilds the force from M with it.

◆ RelaxLumpedSource()

LumpedSourceResult marenv::wake::RelaxLumpedSource ( const LumpedSourceInput &  input,
const LumpedSourceResult &  fresh,
double  previousMomentum,
double  alpha 
)

Returns the lumped source with its momentum deficit relaxed towards the previous one (WakeRelaxation, MENV-0061).

Parameters
[in]inputThe input that made fresh, MakeLumpedSource(input).
[in]freshThe unrelaxed source of this rebuild.
[in]previousMomentumM_prev, the momentum deficit the caster published last, m^2; 0 when it cast none.
[in]alphaThe relaxation alpha in (0, 1].
Returns
MakeLumpedSource() of input with the force along e_U that gives M = alpha M_fresh + (1 - alpha) M_prev at the reference speed of input (ReferenceSpeedSquared()), M_fresh 0 where fresh casts none; so the widening rule (QF6) applies to the relaxed value and the lift is dropped. fresh itself where |U_ref| < kMinRelativeFlow or U_ref is not finite: there is no flow direction to relax along, and fresh casts none there. The relaxation of fhsim_environment's LumpedWakeCaster and fhsim_marine_elements' NetWakeCaster (Periodic with alpha < 1).
Exceptions
std::invalid_argumentas MakeLumpedSource().

◆ SetRelativeFlowFromSamples()

void marenv::wake::SetRelativeFlowFromSamples ( const std::vector< FlowSample > &  samples,
LumpedSourceInput &  input 
)

Sets input.relativeFlow, input.meanSquareFlow and input.ambientMeanSquareFlow from an object's sampled points (owner rulings R55, R87).

Parameters
[in]samplesThe relative flows at the object's own panels or points and their weights.
[in,out]inputIts relativeFlow becomes the weighted mean of the samples' U_p (the free stream the object sees, less its velocity), its meanSquareFlow the weighted mean of |U_p|^2 and its ambientMeanSquareFlow the weighted mean of |ambientRelativeFlow|^2; the other members are left alone. A caster that leaves every ambientRelativeFlow at 0 gets ambientMeanSquareFlow 0, so M falls back to the shaded samples (R55).
Exceptions
std::invalid_argumentfor no sample, a negative or non-finite weight, or weights that sum to 0.

◆ Validate()

void marenv::wake::Validate ( const KernelParams &  params)

Checks the preconditions of KernelParams that the kernel and the fields rely on.

expansion is finite and positive, cutoff lies in (0, 1), xStartFactor and xStartMin are finite and not negative, farWakeStartFactor is not negative and not NaN (infinity keeps the linear growth), seabedDepth is positive (infinity: no seabed). MirrorImages() calls it, so every SourceSetWake::Publish() and the WakeBuilder constructor validate their parameters. ElementaryDeficit() and KernelProfile do not.

Exceptions
std::invalid_argumentnaming the first setting that is invalid.

Variable Documentation

◆ kEpsilonFactor

constexpr double marenv::wake::kEpsilonFactor = 0.2
inlineconstexpr

epsilon = kEpsilonFactor sqrt(beta), the initial wake width over D (or w) of Bastankhah and Porte-Agel (2014), as pinned by contract C4, for the axisymmetric and the line kernel.

◆ kMaxThrustCoefficient

constexpr double marenv::wake::kMaxThrustCoefficient = 0.96
inlineconstexpr

Thrust-coefficient cap C_T,max of the pinned kernel (contract C4): the axisymmetric kernel (ElementaryDeficit()) and the line kernel (LineDeficit()) use C_T = min(M / A, 0.96), and MakeLumpedSource() and MakeLumpedLineSource() widen the area to M / 0.96 above it (QF6), so the far wake keeps the momentum only while all of them use this one value.

◆ kMinRelativeFlow

constexpr double marenv::wake::kMinRelativeFlow = 1e-3
inlineconstexpr

Relative flow speed |U_ref| below which a lumped source casts no wake, m/s (MakeLumpedSource(), design ยง 1.1); the casters in fhsim_environment and fhsim_marine_elements use the same value.

◆ kMomentumFluxBranchDeficit

constexpr double marenv::wake::kMomentumFluxBranchDeficit = 0.45
inlineconstexpr

Branch deficit d_b of the momentum-flux rule (R95): below it the conserving root is exact; from it the root continues along its tangent, which bounds the slope dD/dd_i by 1 / (1 - 2 d_b) = 10 instead of the square root's infinite slope at D = 1/2. Between d_b and 1/2 the composed deficit is at most 0.025 below R95's root (Superposition.h).

◆ kParallelAxisTolerance

constexpr double marenv::wake::kParallelAxisTolerance = 1e-9
inlineconstexpr

|axis x flowDir| below which a line source's axis is taken as parallel to the flow (LineKernelProfile throws; MakeLumpedLineSource() falls back to the point source, MENV-0048).