|
FhSim
3.1.0
Marine systems simulation
|
Velocity deficit fields behind nets and other porous structures. More...
Collaboration diagram for Wake Models:Concepts | |
| concept | marenv::wake::WakeBlendSnapshot |
Enumerations | |
| enum class | marenv::wake::Superposition { Superposition::Product , Superposition::MomentumFlux } |
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 |
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.
|
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(). |
|
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).
| double marenv::wake::detail::DeficitFromMomentumFlux | ( | double | flux | ) |
Returns the conserving deficit C(S) of a momentum-flux sum (R95).
| [in] | flux | S = sum d_i (1 - d_i). |
| 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.
| [in] | source | The elementary source; source.flowDir must be a unit vector. |
| [in] | params | The kernel parameters. |
| [in] | pos | Query position, m, world NED at the source's build time. |
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).
| 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.
| 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.
| [in] | profile | The profile of the source. |
| [in] | pos | Query position, m, world NED at the source's build time. |
| 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.
| std::invalid_argument | as LineKernelProfile. |
| 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.
| [in] | user | The caster's kernel parameters. |
| 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.
| std::invalid_argument | as MakeLumpedSource(), and if the length or the width is not positive. |
| LumpedSourceResult marenv::wake::MakeLumpedSource | ( | const LumpedSourceInput & | input | ) |
Returns the one elementary source a wake-casting object shows to every other object.
| [in] | input | The object's force, relative flow, density, rear-face centre and frontal area. |
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).
| std::invalid_argument | if 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. |
| 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.
| std::invalid_argument | if Validate(params) does. |
| ImagePlanes marenv::wake::MirrorPlanes | ( | const KernelParams & | params | ) |
Returns the mirror planes of params (owner ruling R53).
| std::invalid_argument | unless params.seabedDepth is positive (infinity included). |
| double marenv::wake::detail::MomentumFluxBound | ( | double | sumOfBounds | ) |
Returns an upper bound of the composed deficit of deficits whose sum is at most sumOfBounds (R95).
| [in] | sumOfBounds | Sum of upper bounds b_i >= d_i. |
| 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).
| 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).
| [in] | input | The input that made fresh, MakeLumpedSource(input). |
| [in] | fresh | The unrelaxed source of this rebuild. |
| [in] | previousMomentum | M_prev, the momentum deficit the caster published last, m^2; 0 when it cast none. |
| [in] | alpha | The relaxation alpha in (0, 1]. |
| std::invalid_argument | as MakeLumpedSource(). |
| 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).
| [in] | samples | The relative flows at the object's own panels or points and their weights. |
| [in,out] | input | Its 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). |
| std::invalid_argument | for no sample, a negative or non-finite weight, or weights that sum to 0. |
| 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.
| std::invalid_argument | naming the first setting that is invalid. |
|
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.
|
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.
|
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.
|
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).
|
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).