65#include "PanelFormulas.h"
66#include "PanelLoadTypes.h"
68#include <sfh/constants.h>
69#include <sfh/math/math.h>
73namespace hydrodynamics
85namespace twine_cross_flow_detail
89const double kMinSpeed = 1.0e-10;
91const double kMaxSpeed = 1.0e10;
93const double kMaxDrag = 1.0e100;
95const double kMinSolidity = 1.0e-4;
97const double kMaxSolidity = 0.5;
99const double kMinLiftDirectionNorm = 1.0e-10;
102const double kMinReynolds = 32.0;
104const double kMaxReynolds = 1.0e4;
106const unsigned kFlagSolidityClamped = 1u << 0;
107const unsigned kFlagReynoldsClamped = 1u << 1;
108const unsigned kFlagSpeedBelowEpsilon = 1u << 2;
109const unsigned kFlagVelocityRatioClamped = kPanelFlagVelocityRatioClamped;
112T Dot(
const T a[3],
const T b[3])
114 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
117using panel_formulas::CylinderDragCoefficient;
126T PolynomialReynoldsNumber(
const T& reynoldsNumber,
unsigned& flags)
128 if (reynoldsNumber < kMinReynolds) {
129 flags |= kFlagReynoldsClamped;
130 return T(kMinReynolds);
132 if (reynoldsNumber > kMaxReynolds) {
133 flags |= kFlagReynoldsClamped;
134 return T(kMaxReynolds);
136 return reynoldsNumber;
150void BarFamilyDrag(
const TwineCrossFlow& law,
double dragFactor,
const T barDirection[3],
151 const T effVel[3],
const T& effSpeed,
const T& cylinderCd, T force[3])
153 const T alongBar = Dot(effVel, barDirection);
156 for (
int i = 0; i < 3; i++) {
157 tangentialVel[i] = alongBar * barDirection[i];
158 normalVel[i] = effVel[i] - tangentialVel[i];
160 const T normalSpeed = sfh::math::Max(T(kMinSpeed), sfh::math::Norm(normalVel, 3));
163 T sinAngle = normalSpeed / effSpeed;
168 const T cn = cylinderCd * sinAngle;
170 const T normalDrag = sfh::math::Bound(T(dragFactor * effSpeed * cn), T(-kMaxDrag), T(kMaxDrag));
171 const T tangentialDrag =
172 sfh::math::Bound(T(dragFactor * effSpeed * (law.ct * sfh::pi)), T(-kMaxDrag), T(kMaxDrag));
174 for (
int i = 0; i < 3; i++) {
175 force[i] = normalDrag * normalVel[i] + tangentialDrag * tangentialVel[i];
181PanelLoad<T> ZeroLoad(
unsigned flags)
183 PanelLoad<T> load {};
184 for (
int i = 0; i < 3; i++) {
185 load.force[i] = T(0);
190 load.reynolds = T(0);
191 load.momentumDeficit = T(0);
192 load.throughFlowSpeed = T(0);
224PanelLoad<T> Evaluate(
const TwineCrossFlow& law,
const PanelGeometry<T>& geometry,
225 const Netting<T>& netting,
const Fluid& fluid,
const FlowSample<T>& flow)
227 using namespace twine_cross_flow_detail;
231 const T*
const velocity = flow.relativeVelocity;
232 const T*
const normal = geometry.normal;
235 const T speed = sfh::math::Norm(velocity, 3);
236 if (speed < kMinSpeed) {
237 flags |= kFlagSpeedBelowEpsilon;
240 T solidity = netting.solidity;
241 if (!(solidity > kMinSolidity)) {
242 solidity = T(kMinSolidity);
243 flags |= kFlagSolidityClamped;
244 }
else if (solidity > kMaxSolidity) {
245 solidity = T(kMaxSolidity);
246 flags |= kFlagSolidityClamped;
249 if (!netting.hasBarDirections) {
250 return ZeroLoad<T>(flags);
254 const T speedUp = sqrt(2 - solidity) / (sqrt(2.0) * (1 - solidity));
255 const T normalSpeed = Dot(velocity, normal);
257 for (
int i = 0; i < 3; i++) {
258 effVel[i] = velocity[i] + (speedUp - 1) * normalSpeed * normal[i];
260 const T effSpeed = sfh::math::Bound(sfh::math::Norm(effVel, 3), T(kMinSpeed), T(kMaxSpeed));
263 const T meshFlowSpeed = effSpeed * sqrt(2.0) / sqrt(2 - solidity);
264 const T reynoldsNumber = meshFlowSpeed * netting.twineThickness / fluid.nu;
266 const double twineLength = sfh::math::Max(netting.barLength - netting.knotDiameter, 0.0);
267 const double barDragFactor = 0.5 * fluid.rho * netting.twineThickness * twineLength;
268 const double dragFactorU = barDragFactor * netting.numBarsU;
269 const double dragFactorV = barDragFactor * netting.numBarsV;
273 const T cylinderCd = CylinderDragCoefficient(PolynomialReynoldsNumber(reynoldsNumber, flags));
274 BarFamilyDrag(law, dragFactorU, netting.barU, effVel, effSpeed, cylinderCd, forceU);
275 BarFamilyDrag(law, dragFactorV, netting.barV, effVel, effSpeed, cylinderCd, forceV);
278 const double knotArea = sfh::pi * netting.knotDiameter * netting.knotDiameter / 4;
279 const double knotDragFactor = 0.5 * fluid.rho * netting.numKnots * law.cnKnots * knotArea;
280 const T knotDrag = knotDragFactor * effSpeed * effSpeed;
282 PanelLoad<T> load {};
283 for (
int i = 0; i < 3; i++) {
284 load.force[i] = forceU[i] + forceV[i] + knotDrag * effVel[i] / effSpeed;
288 const T boundedSpeed = sfh::math::Max(speed, T(kMinSpeed));
290 for (
int i = 0; i < 3; i++) {
291 flowDirection[i] = velocity[i] / boundedSpeed;
293 T cosTheta = Dot(flowDirection, normal);
294 T normalDownstream[3];
295 for (
int i = 0; i < 3; i++) {
296 normalDownstream[i] = (cosTheta < 0) ? -normal[i] : normal[i];
299 cosTheta = -cosTheta;
303 for (
int i = 0; i < 3; i++) {
304 liftDirection[i] = normalDownstream[i] - cosTheta * flowDirection[i];
306 const T liftDirectionNorm =
307 sfh::math::Max(sfh::math::Norm(liftDirection, 3), T(kMinLiftDirectionNorm));
309 load.drag = Dot(load.force, flowDirection);
310 load.lift = Dot(load.force, liftDirection) / liftDirectionNorm;
311 load.theta = acos(sfh::math::Min(cosTheta, T(1)));
313 const T dynamicPressure = 0.5 * fluid.rho * boundedSpeed * boundedSpeed;
314 load.reynolds = reynoldsNumber;
315 load.throughFlowSpeed = meshFlowSpeed;
316 load.momentumDeficit = load.drag / dynamicPressure;
319 const T dragCoefficient = load.momentumDeficit / geometry.area;
320 const T reductionFactor = panel_formulas::VelocityReductionFactor(solidity, flags);
321 load.localCd = dragCoefficient * 4 * (1 - solidity) * (1 - solidity) / (solidity * (1 + reductionFactor) * (1 + reductionFactor));
Definition TwineCrossFlow.h:80
double ct
Nominal tangential drag coefficient; multiplied by pi.
Definition TwineCrossFlow.h:81
double cnKnots
Knot drag coefficient on the knot's projected area.
Definition TwineCrossFlow.h:82