FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
KF2012Common.h
1#pragma once
2
28#include "PanelFormulas.h"
29#include "PanelLoadTypes.h"
30#include "TwineFriction.h"
31
32#include <cmath>
33
34namespace hydrodynamics
35{
36namespace kf2012
37{
38
40const double kMinReynolds = 31.622776601683793;
42const double kMaxReynolds = 1.0e4;
43
45const double kMaxSolidity = 0.5;
52const double kMinSolidity = 1.0e-4;
53
55const double kMinSpeed = 1.0e-10;
56
58const unsigned kFlagSolidityClamped = 1u;
60const unsigned kFlagReynoldsClamped = 2u;
62const unsigned kFlagSpeedBelowEpsilon = 4u;
64const unsigned kFlagVelocityRatioClamped = kPanelFlagVelocityRatioClamped;
65
71const double kB2 = 1.0;
72
79const double kMaxA3 = 0.25;
80
87const double kMinA3 = -0.125;
88
95const double kMaxAbsB4 = 0.5;
96
97
98using panel_formulas::CylinderDragCoefficient;
99
100
107template<class T>
108T ScreenDragCoefficient(const T& cylinderCd, const T& solidity)
109{
110 const T open = 1.0 - solidity;
111 return cylinderCd * solidity * (2.0 - solidity) / (2.0 * open * open);
112}
113
114
124template<class T>
125T SchubauerLiftCoefficient(const T& cd)
126{
127 using std::sqrt;
128
129 const double quarterPi = 0.78539816339744830962;
130 const T normal = 0.5 * cd;
131 const T tangential = quarterPi * 4.0 * normal / (8.0 + normal);
132 return (normal - tangential) / sqrt(2.0);
133}
134
135
136using panel_formulas::VelocityReductionFactor;
137
138
144template<class T>
145T InductionFactor(const T& solidity)
146{
147 return 0.5 * (1.0 + VelocityReductionFactor(solidity));
148}
149
150
157template<class T>
158T LocalDragCoefficient(const T& panelCd, const T& solidity)
159{
160 const T open = 1.0 - solidity;
161 const T onePlusR = 1.0 + VelocityReductionFactor(solidity);
162 return panelCd * 4.0 * open * open / (solidity * onePlusR * onePlusR);
163}
164
165
171template<class T>
172T ClampAndFlag(const T& value, double lower, double upper, unsigned flag, unsigned& flags)
173{
174 if (!(value >= lower)) { // catches value < lower and a NaN value (MARE-0145), as TwineCrossFlow's own floor does
175 flags |= flag;
176 return T(lower);
177 }
178 if (value > upper) {
179 flags |= flag;
180 return T(upper);
181 }
182 return value;
183}
184
185
187template<class T>
188struct Inflow
189{
194
205};
206
207
216template<class T>
217Inflow<T> ComputeInflow(const T velocity[3], const T normal[3], unsigned& flags)
218{
219 using std::abs;
220 using std::acos;
221 using std::sqrt;
222
223 Inflow<T> inflow;
224 inflow.speed =
225 sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1] + velocity[2] * velocity[2]);
226
227 T guardedSpeed = inflow.speed;
228 if (inflow.speed < kMinSpeed) {
229 flags |= kFlagSpeedBelowEpsilon;
230 guardedSpeed = T(kMinSpeed);
231 }
232
233 T normalComponent = T(0.0);
234 for (int i = 0; i < 3; i++) {
235 inflow.direction[i] = velocity[i] / guardedSpeed;
236 normalComponent = normalComponent + inflow.direction[i] * normal[i];
237 }
238
239 inflow.cosTheta = abs(normalComponent);
240 if (inflow.cosTheta > 1.0) {
241 inflow.cosTheta = T(1.0);
242 }
243 inflow.theta = acos(inflow.cosTheta);
244
245 for (int i = 0; i < 3; i++) {
246 inflow.liftBasis[i] =
247 normalComponent * normal[i] - normalComponent * normalComponent * inflow.direction[i];
248 }
249 return inflow;
250}
251
252
259template<class T>
260T DragAngleFactor(const T& cosTheta, double a3)
261{
262 const T cos3Theta = (4.0 * cosTheta * cosTheta - 3.0) * cosTheta;
263 return (1.0 - a3) * cosTheta + a3 * cos3Theta;
264}
265
266
274template<class T>
275T LiftAngleFactorPerSinCos(const T& cosTheta, double b4)
276{
277 const T cos2Theta = 2.0 * cosTheta * cosTheta - 1.0;
278 return 2.0 * kB2 + 4.0 * b4 * cos2Theta;
279}
280
281
306template<class T>
307PanelLoad<T> EvaluateScreen(double a3, double b4, bool withInduction,
308 const PanelGeometry<T>& panel, const Netting<T>& netting, const Fluid& fluid,
309 const FlowSample<T>& flow)
310{
311 using std::sqrt;
312
313 PanelLoad<T> load {};
314 load.flags = 0u;
315
316 const T solidity =
317 ClampAndFlag(netting.solidity, kMinSolidity, kMaxSolidity, kFlagSolidityClamped, load.flags);
318 const Inflow<T> inflow = ComputeInflow(flow.relativeVelocity, panel.normal, load.flags);
319
320 const T velocityRatio = VelocityReductionFactor(solidity, load.flags);
321 const T induction = withInduction ? 0.5 * (1.0 + velocityRatio) : T(1.0);
322
323 // U_t = f |U| / (1 - Sn): MF2022 Eq. 8 (Eq. 6 when f = 1), KF2012 Eq. 5 at theta = 0.
324 load.throughFlowSpeed = induction * inflow.speed / (1.0 - solidity);
325 load.reynolds = load.throughFlowSpeed * netting.twineThickness / fluid.nu;
326
327 const T reynolds =
328 ClampAndFlag(load.reynolds, kMinReynolds, kMaxReynolds, kFlagReynoldsClamped, load.flags);
329 // f^2 scales c_d and c_l alike (lead rulings R1 and R59): MF2022 Eq. 9 normalises the lift with
330 // the same factor as the drag (p. 041301-7), so c_l = f^2 Schubauer(c_d0), not Schubauer(f^2 c_d0).
331 const T cdWithoutInduction = ScreenDragCoefficient(CylinderDragCoefficient(reynolds), solidity);
332 const T inductionSquared = induction * induction;
333 const T cd = cdWithoutInduction * inductionSquared;
334 const T cl = inductionSquared * SchubauerLiftCoefficient(cdWithoutInduction);
335
336 const T dragCoefficient = cd * DragAngleFactor(inflow.cosTheta, a3);
337 const T liftPerSinCos = cl * LiftAngleFactorPerSinCos(inflow.cosTheta, b4);
338 const T sinTheta = sqrt(1.0 - inflow.cosTheta * inflow.cosTheta);
339 const T liftCoefficient = liftPerSinCos * sinTheta * inflow.cosTheta;
340 const T dynamicForce = 0.5 * fluid.rho * panel.area * inflow.speed * inflow.speed;
341
342 const twine_friction::InPlaneFriction<T> friction = twine_friction::EvaluateTwineFriction(
343 netting, fluid, solidity, flow.relativeVelocity, panel.normal);
344 const T guardedSpeed = inflow.speed < kMinSpeed ? T(kMinSpeed) : inflow.speed;
345 const T frictionDragPerQ = friction.drag / (0.5 * fluid.rho * guardedSpeed * guardedSpeed);
346 const T totalDragPerQ = panel.area * dragCoefficient + frictionDragPerQ;
347
348 for (int i = 0; i < 3; i++) {
349 load.force[i] = dynamicForce * (dragCoefficient * inflow.direction[i] + liftPerSinCos * inflow.liftBasis[i])
350 + friction.force[i];
351 }
352 load.drag = dynamicForce * dragCoefficient + friction.drag;
353 load.lift = dynamicForce * liftCoefficient + friction.lift;
354 load.theta = inflow.theta;
355 load.momentumDeficit = totalDragPerQ; // drag / (1/2 rho |U|^2); the screen part without dividing by |U|
356 load.localCd = LocalDragCoefficient(dragCoefficient + frictionDragPerQ / panel.area, solidity);
357 return load;
358}
359
360} // namespace kf2012
361} // namespace hydrodynamics
The inflow on a panel: its speed, direction and angle to the normal.
Definition KF2012Common.h:189
T theta
rad, in [0, pi/2].
Definition KF2012Common.h:193
T liftBasis[3]
Definition KF2012Common.h:204
T direction[3]
U-hat = U / max(|U|, kMinSpeed).
Definition KF2012Common.h:191
T speed
|U|, m/s.
Definition KF2012Common.h:190
T cosTheta
cos(theta) = |U-hat . n|, in [0, 1].
Definition KF2012Common.h:192