PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
wallfunction.c
Go to the documentation of this file.
1/**
2 * @file wallfunction.c
3 * @brief Wall function implementations for near-wall turbulence modeling
4 *
5 * This file contains various wall function models that bridge the gap between
6 * the wall and the first computational grid point. Wall functions allow simulations
7 * to avoid resolving the viscous sublayer, reducing computational cost while
8 * maintaining reasonable accuracy for turbulent wall-bounded flows.
9 *
10 * PHYSICAL BACKGROUND:
11 * The near-wall region in turbulent flows is characterized by three layers:
12 * 1. Viscous sublayer (y+ < 5): Dominated by viscous effects, u+ = y+
13 * 2. Buffer layer (5 < y+ < 30): Transition region
14 * 3. Log-law region (y+ > 30): Inertial layer, u+ = (1/κ) ln(y+) + B
15 * where:
16 * u+ = u / u_τ (normalized velocity)
17 * y+ = y * u_τ / ν (normalized wall distance)
18 * u_τ = sqrt(τ_w / ρ) (friction velocity)
19 * κ ≈ 0.41 (von Karman constant)
20 * B ≈ 5.5 (log-law intercept for smooth walls)
21 *
22 * IMPLEMENTED MODELS:
23 * - No-slip: Linear interpolation for stationary walls
24 * - Free-slip: Normal interpolation, tangential extrapolation
25 * - Werner-Wengle: Algebraic wall function
26 * - Log-law: Standard equilibrium wall function with roughness
27 * - Cabot: Non-equilibrium wall function with pressure gradient effects
28 *
29 * @author Original implementation adapted from legacy code
30 * @date Enhanced with comprehensive documentation
31 */
32
33#include "wallfunction.h"
34#include <math.h>
35#include <stdlib.h>
36#include <stdio.h>
37
38// ============================================================================
39// PHYSICAL CONSTANTS
40// ============================================================================
41
42/** @brief von Karman constant (universal turbulence constant) */
43#define KAPPA 0.41
44
45/** @brief Log-law intercept constant B for smooth walls */
46#define LOGLAW_B 5.5
47
48/** @brief Viscous sublayer thickness y+ threshold */
49#define VISCOUS_SUBLAYER_YPLUS 11.81
50
51/** @brief Smooth-to-rough transition y+ threshold */
52#define ROUGHNESS_TRANSITION_YPLUS 2.25
53
54/** @brief Fully rough regime y+ threshold */
55#define FULLY_ROUGH_YPLUS 90.0
56
57/** @brief Eddy viscosity damping coefficient (van Driest damping) */
58#define DAMPING_COEFFICIENT 19.0
59
60// ============================================================================
61// BASIC BOUNDARY CONDITION FUNCTIONS
62// ============================================================================
63
64/**
65 * @brief Applies no-slip wall boundary condition with linear interpolation
66 *
67 * This function enforces a no-slip boundary condition (zero velocity at the wall)
68 * by linearly interpolating between the wall velocity (typically zero) and the
69 * velocity at a reference point in the flow.
70 *
71 * MATHEMATICAL FORMULATION:
72 * For a point at distance sb from the wall, with a reference velocity Uc
73 * at distance sc from the wall:
74 * U_boundary = U_wall + (U_reference - U_wall) * (sb / sc)
75 *
76 * PHYSICAL INTERPRETATION:
77 * This provides a first-order approximation assuming linear velocity variation
78 * in the near-wall region, which is valid in the viscous sublayer.
79 *
80 * @param[in] user Simulation context (unused but required for interface)
81 * @param[in] distance_reference Wall-normal distance to reference point (sc)
82 * @param[in] distance_boundary Wall-normal distance to boundary point (sb)
83 * @param[in] velocity_wall Velocity at the wall (Ua), typically zero
84 * @param[in] velocity_reference Velocity at reference point (Uc)
85 * @param[out] velocity_boundary Computed velocity at boundary point (Ub)
86 * @param[in] normal_x X-component of wall normal vector
87 * @param[in] normal_y Y-component of wall normal vector
88 * @param[in] normal_z Z-component of wall normal vector
89 *
90 * @note For moving walls, velocity_wall would be non-zero
91 * @note The normal vector should point INTO the fluid domain
92 */
93void noslip(UserCtx *user,
94 double distance_reference, double distance_boundary,
95 Cmpnts velocity_wall, Cmpnts velocity_reference,
96 Cmpnts *velocity_boundary,
97 double normal_x, double normal_y, double normal_z)
98{
99 // Compute velocity difference between reference point and wall
100 double delta_u = velocity_reference.x - velocity_wall.x;
101 double delta_v = velocity_reference.y - velocity_wall.y;
102 double delta_w = velocity_reference.z - velocity_wall.z;
103
104 // Linear interpolation factor
105 double interpolation_factor = distance_boundary / distance_reference;
106
107 // Apply linear interpolation
108 (*velocity_boundary).x = interpolation_factor * delta_u;
109 (*velocity_boundary).y = interpolation_factor * delta_v;
110 (*velocity_boundary).z = interpolation_factor * delta_w;
111
112 // Add wall velocity (shift to absolute frame)
113 (*velocity_boundary).x += velocity_wall.x;
114 (*velocity_boundary).y += velocity_wall.y;
115 (*velocity_boundary).z += velocity_wall.z;
116}
117
118/**
119 * @brief Applies free-slip wall boundary condition
120 *
121 * Free-slip conditions allow tangential flow but enforce zero normal velocity.
122 * This is appropriate for inviscid walls or symmetry planes where there is
123 * no shear stress but flow cannot penetrate the boundary.
124 *
125 * DECOMPOSITION:
126 * Velocity is decomposed into normal and tangential components:
127 * U = U_n * n + U_t
128 * where U_n = U · n (normal component)
129 * U_t = U - U_n * n (tangential component)
130 *
131 * BOUNDARY CONDITIONS:
132 * - Normal component: Interpolated from interior (∂U_n/∂n ≠ 0)
133 * - Tangential component: Extrapolated from interior (∂U_t/∂n = 0)
134 *
135 * @param[in] user Simulation context
136 * @param[in] distance_reference Wall-normal distance to reference point
137 * @param[in] distance_boundary Wall-normal distance to boundary point
138 * @param[in] velocity_wall Velocity at the wall
139 * @param[in] velocity_reference Velocity at reference point
140 * @param[out] velocity_boundary Computed velocity at boundary point
141 * @param[in] normal_x X-component of wall normal vector
142 * @param[in] normal_y Y-component of wall normal vector
143 * @param[in] normal_z Z-component of wall normal vector
144 */
145void freeslip(UserCtx *user,
146 double distance_reference, double distance_boundary,
147 Cmpnts velocity_wall, Cmpnts velocity_reference,
148 Cmpnts *velocity_boundary,
149 double normal_x, double normal_y, double normal_z)
150{
151 // Extract normal components of velocities
152 double wall_normal_velocity = velocity_wall.x * normal_x +
153 velocity_wall.y * normal_y +
154 velocity_wall.z * normal_z;
155
156 double reference_normal_velocity = velocity_reference.x * normal_x +
157 velocity_reference.y * normal_y +
158 velocity_reference.z * normal_z;
159
160 // Interpolate normal velocity component
161 double boundary_normal_velocity = wall_normal_velocity +
162 (reference_normal_velocity - wall_normal_velocity) * (distance_boundary / distance_reference);
163
164 // Extract tangential velocity components (extrapolated from reference point)
165 double tangential_u = velocity_reference.x - reference_normal_velocity * normal_x;
166 double tangential_v = velocity_reference.y - reference_normal_velocity * normal_y;
167 double tangential_w = velocity_reference.z - reference_normal_velocity * normal_z;
168
169 // Reconstruct total velocity: U = U_t + U_n * n
170 (*velocity_boundary).x = tangential_u + boundary_normal_velocity * normal_x;
171 (*velocity_boundary).y = tangential_v + boundary_normal_velocity * normal_y;
172 (*velocity_boundary).z = tangential_w + boundary_normal_velocity * normal_z;
173}
174
175// ============================================================================
176// ROUGHNESS-CORRECTED LOG-LAW FUNCTIONS
177// ============================================================================
178
179/**
180 * @brief Computes roughness-modified log-law coefficient E
181 *
182 * The coefficient E accounts for wall roughness effects on the log-law:
183 * u+ = (1/κ) ln(E * y+)
184 *
185 * ROUGHNESS REGIMES:
186 * 1. Hydraulically smooth (ks+ < 2.25): E = exp(κ*B), no roughness effect
187 * 2. Transitional (2.25 < ks+ < 90): Smooth interpolation between regimes
188 * 3. Fully rough (ks+ > 90): E modified by roughness height
189 * where ks+ = u_τ * ks / ν (roughness Reynolds number)
190 *
191 * @param[in] friction_velocity Friction velocity u_τ
192 * @param[in] roughness_height Equivalent sand grain roughness height ks
193 * @param[in] kinematic_viscosity Kinematic viscosity ν
194 * @return Roughness-modified log-law coefficient E
195 *
196 * @note This follows the Nikuradse sand grain roughness correlation
197 */
198double E_coeff(double friction_velocity, double roughness_height, double kinematic_viscosity)
199{
200 // Compute roughness Reynolds number
201 double roughness_reynolds = friction_velocity * roughness_height / kinematic_viscosity;
202
203 double roughness_correction;
204
205 if (roughness_reynolds <= ROUGHNESS_TRANSITION_YPLUS) {
206 // Hydraulically smooth regime: no correction needed
207 roughness_correction = 0.0;
208 }
209 else if (roughness_reynolds < FULLY_ROUGH_YPLUS) {
210 // Transitional regime: smooth interpolation using sine function
211 // This provides a gradual transition between smooth and rough wall behavior
212 double transition_factor = log(roughness_reynolds) - log(ROUGHNESS_TRANSITION_YPLUS);
213 double max_correction = LOGLAW_B - 8.5 + (1.0 / KAPPA) * log(roughness_reynolds);
214
215 roughness_correction = max_correction *
216 sin(0.4258 * (log(roughness_reynolds) - 0.811));
217 }
218 else {
219 // Fully rough regime: maximum correction
220 roughness_correction = LOGLAW_B - 8.5 + (1.0 / KAPPA) * log(roughness_reynolds);
221 }
222
223 // Return E = exp[κ(B - ΔB)]
224 return exp(KAPPA * (LOGLAW_B - roughness_correction));
225}
226
227/**
228 * @brief Computes velocity from log-law for rough walls
229 *
230 * Calculates the tangential velocity at a given wall distance using
231 * the roughness-modified log-law of the wall.
232 *
233 * APPLICABLE REGIMES:
234 * - Viscous sublayer (y+ < 11.53): u+ = y+
235 * - Log-layer (11.53 < y+ < 300): u+ = (1/κ) ln(E * y+)
236 * - Outer layer (y+ > 300): Returns -1 (invalid, wake region)
237 *
238 * @param[in] kinematic_viscosity Kinematic viscosity ν
239 * @param[in] wall_distance Distance from wall y
240 * @param[in] friction_velocity Friction velocity u_τ
241 * @param[in] roughness_height Equivalent sand grain roughness ks
242 * @return Tangential velocity u_t, or -1 if outside valid range
243 *
244 * @note The upper limit y+ < 300 ensures we stay within the log-layer
245 * @note For y+ > 300, wake effects become important and log-law is invalid
246 */
247double u_hydset_roughness(double kinematic_viscosity, double wall_distance,
248 double friction_velocity, double roughness_height)
249{
250 // Normalized wall distance
251 double yplus = friction_velocity * wall_distance / kinematic_viscosity;
252
253 // Threshold values for regime transitions
254 const double viscous_limit = VISCOUS_SUBLAYER_YPLUS;
255 const double loglayer_limit = 300.0;
256
257 double tangential_velocity;
258
259 if (yplus <= viscous_limit) {
260 // Viscous sublayer: linear velocity profile
261 tangential_velocity = friction_velocity * yplus;
262 }
263 else if (yplus <= loglayer_limit) {
264 // Log-layer: logarithmic velocity profile with roughness correction
265 double E = E_coeff(friction_velocity, roughness_height, kinematic_viscosity);
266 tangential_velocity = (friction_velocity / KAPPA) * log(E * yplus);
267 }
268 else {
269 // Outside valid range (wake region or beyond)
270 tangential_velocity = -1.0;
271 }
272
273 return tangential_velocity;
274}
275
276// ============================================================================
277// NEWTON-RAPHSON SOLVER FOR FRICTION VELOCITY (LOG-LAW)
278// ============================================================================
279
280/**
281 * @brief Residual function for friction velocity equation (log-law with roughness)
282 *
283 * This function computes the residual for Newton-Raphson iteration:
284 * f(u_τ) = u_predicted(u_τ) - u_known
285 * where u_predicted comes from the log-law or linear law depending on y+.
286 *
287 * @param[in] kinematic_viscosity Kinematic viscosity
288 * @param[in] known_velocity Known velocity at distance y
289 * @param[in] wall_distance Distance from wall
290 * @param[in] friction_velocity_guess Current guess for u_τ
291 * @param[in] roughness_height Wall roughness height
292 * @return Residual value (should be zero at solution)
293 */
294double f_hydset(double kinematic_viscosity, double known_velocity,
295 double wall_distance, double friction_velocity_guess,
296 double roughness_height)
297{
298 double yplus = friction_velocity_guess * wall_distance / kinematic_viscosity;
299 double residual;
300
301 if (yplus <= VISCOUS_SUBLAYER_YPLUS) {
302 // Viscous sublayer: u = u_τ * y+
303 residual = friction_velocity_guess * yplus - known_velocity;
304 }
305 else {
306 // Log-layer: u = (u_τ / κ) * ln(E * y+)
307 double E = E_coeff(friction_velocity_guess, roughness_height, kinematic_viscosity);
308 residual = friction_velocity_guess * (1.0 / KAPPA * log(E * yplus)) - known_velocity;
309 }
310
311 return residual;
312}
313
314/**
315 * @brief Numerical derivative of residual function
316 *
317 * Computes df/du_τ using finite differences for Newton-Raphson iteration.
318 *
319 * @param[in] kinematic_viscosity Kinematic viscosity
320 * @param[in] known_velocity Known velocity
321 * @param[in] wall_distance Distance from wall
322 * @param[in] friction_velocity_guess Current guess for u_τ
323 * @param[in] roughness_height Wall roughness
324 * @return Derivative df/du_τ
325 */
326double df_hydset(double kinematic_viscosity, double known_velocity,
327 double wall_distance, double friction_velocity_guess,
328 double roughness_height)
329{
330 const double perturbation = 1.e-7;
331
332 double f_plus = f_hydset(kinematic_viscosity, known_velocity, wall_distance,
333 friction_velocity_guess + perturbation, roughness_height);
334
335 double f_minus = f_hydset(kinematic_viscosity, known_velocity, wall_distance,
336 friction_velocity_guess - perturbation, roughness_height);
337
338 return (f_plus - f_minus) / (2.0 * perturbation);
339}
340
341/**
342 * @brief Solves for friction velocity using Newton-Raphson iteration
343 *
344 * Given a known velocity at a known distance from the wall, this function
345 * iteratively solves for the friction velocity u_τ that satisfies the
346 * roughness-modified log-law or linear law.
347 *
348 * ALGORITHM:
349 * Newton-Raphson: u_τ^(n+1) = u_τ^n - f(u_τ^n) / f'(u_τ^n)
350 * Convergence criterion: |u_τ^(n+1) - u_τ^n| < 1e-7
351 *
352 * @param[in] kinematic_viscosity Kinematic viscosity
353 * @param[in] known_velocity Velocity at reference point
354 * @param[in] wall_distance Distance from wall to reference point
355 * @param[in] initial_guess Initial guess for u_τ
356 * @param[in] roughness_height Wall roughness height
357 * @return Converged friction velocity u_τ
358 *
359 * @note Maximum 30 iterations; warns if convergence not achieved
360 * @note Typical convergence in 3-5 iterations for good initial guess
361 */
362double find_utau_hydset(double kinematic_viscosity, double known_velocity,
363 double wall_distance, double initial_guess,
364 double roughness_height)
365{
366 double friction_velocity = initial_guess;
367 double friction_velocity_old = initial_guess;
368
369 const int max_iterations = 30;
370 const double convergence_tolerance = 1.e-7;
371
372 int iteration;
373 for (iteration = 0; iteration < max_iterations; iteration++) {
374 // Newton-Raphson update
375 double residual = f_hydset(kinematic_viscosity, known_velocity, wall_distance,
376 friction_velocity_old, roughness_height);
377 double derivative = df_hydset(kinematic_viscosity, known_velocity, wall_distance,
378 friction_velocity_old, roughness_height);
379
380 friction_velocity = friction_velocity_old - residual / derivative;
381
382 // Check convergence
383 if (fabs(friction_velocity - friction_velocity_old) < convergence_tolerance) {
384 break;
385 }
386
387 friction_velocity_old = friction_velocity;
388 }
389
390 // Warn if convergence not achieved
391 if (iteration == max_iterations) {
393 "WARNING: u_tau iteration did not converge after %d iterations. "
394 "Final difference: %le\n",
395 iteration, fabs(friction_velocity - friction_velocity_old));
396 }
397
398 return friction_velocity;
399}
400
401// ============================================================================
402// TURBULENT EDDY VISCOSITY MODELS
403// ============================================================================
404
405/**
406 * @brief Computes turbulent eddy viscosity ratio (ν_t / ν)
407 *
408 * Uses the mixing length model with van Driest damping:
409 * ν_t / ν = κ * y+ * [1 - exp(-y+ / A+)]²
410 * where A+ ≈ 19 is the damping coefficient.
411 *
412 * PHYSICAL INTERPRETATION:
413 * - Near wall (y+ → 0): ν_t → 0 (viscous effects dominate)
414 * - Far from wall (y+ >> A+): ν_t ~ κ * y+ (mixing length theory)
415 * - Damping function smoothly transitions between these limits
416 *
417 * @param[in] yplus Normalized wall distance y+ = y * u_τ / ν
418 * @return Eddy viscosity ratio ν_t / ν
419 *
420 * @note This is the standard mixing length model with van Driest damping
421 * @note Valid in the inner layer (y+ < 50-100)
422 */
423double nu_t(double yplus)
424{
425 // van Driest damping function: [1 - exp(-y+ / A+)]²
426 double damping_function = 1.0 - exp(-yplus / DAMPING_COEFFICIENT);
427
428 // Mixing length model: ν_t / ν = κ * y+ * D²
429 return KAPPA * yplus * damping_function * damping_function;
430}
431
432/**
433 * @brief Integrates eddy viscosity profile from wall to distance y
434 *
435 * Computes integrals needed for non-equilibrium wall functions:
436 * If mode=0: ∫[0 to y] dy / (ν + ν_t)
437 * If mode=1: ∫[0 to y] y dy / (ν + ν_t)
438 *
439 * These integrals appear in the solution of the momentum equation
440 * with pressure gradients in the near-wall region.
441 *
442 * NUMERICAL METHOD:
443 * - Trapezoidal rule with 30 integration points
444 * - Higher-order correction at endpoints for accuracy
445 *
446 * @param[in] kinematic_viscosity Kinematic viscosity ν
447 * @param[in] wall_distance Distance from wall y
448 * @param[in] friction_velocity Friction velocity u_τ
449 * @param[in] integration_mode 0 for F integral, 1 for Fy integral
450 * @return Value of the integral
451 *
452 * @note Used in Cabot wall function for pressure gradient effects
453 */
454double integrate_1(double kinematic_viscosity, double wall_distance,
455 double friction_velocity, int integration_mode)
456{
457 const int num_points = 30;
458 double step_size = wall_distance / (num_points - 1);
459 double integral_values[num_points];
460
461 // Compute integrand at each point
462 for (int i = 0; i < num_points; i++) {
463 double current_distance = i * step_size;
464 double yplus = current_distance * friction_velocity / kinematic_viscosity;
465 double eddy_viscosity_ratio = nu_t(yplus);
466
467 if (integration_mode == 0) {
468 // Mode 0: integrand = 1 / [(1 + ν_t/ν) * ν]
469 integral_values[i] = 1.0 / ((1.0 + eddy_viscosity_ratio) * kinematic_viscosity);
470 }
471 else {
472 // Mode 1: integrand = y / [(1 + ν_t/ν) * ν]
473 integral_values[i] = current_distance /
474 ((1.0 + eddy_viscosity_ratio) * kinematic_viscosity);
475 }
476 }
477
478 // Trapezoidal rule integration with corrected endpoints
479 double integral_sum = 0.0;
480
481 // Interior points: weight = (f[i-1] + 2*f[i] + f[i+1]) * dy/4
482 for (int i = 1; i < num_points - 1; i++) {
483 integral_sum += (integral_values[i-1] + 2.0 * integral_values[i] +
484 integral_values[i+1]) * 0.25 * step_size;
485 }
486
487 // Endpoint correction for higher accuracy
488 integral_sum += 0.1667 * step_size *
489 (2.0 * integral_values[0] + integral_values[1] +
490 2.0 * integral_values[num_points-1] + integral_values[num_points-2]);
491
492 return integral_sum;
493}
494
495// ============================================================================
496// CABOT NON-EQUILIBRIUM WALL FUNCTION
497// ============================================================================
498
499/**
500 * @brief Computes wall shear stress with pressure gradient effects
501 *
502 * Solves the integrated momentum equation in the near-wall region:
503 * τ_w = (u - dp/dx * F_y) / F_1
504 * where F_1 and F_y are integrals of the effective viscosity profile.
505 *
506 * This accounts for non-equilibrium effects due to streamwise pressure gradients.
507 *
508 * @param[in] kinematic_viscosity Kinematic viscosity
509 * @param[in] friction_velocity Friction velocity u_τ
510 * @param[in] wall_distance Distance from wall
511 * @param[in] velocity Velocity at wall_distance
512 * @param[in] pressure_gradient_tangent Tangential pressure gradient dp/ds
513 * @return Wall shear stress τ_w
514 *
515 * @note This is more accurate than equilibrium wall functions in separated flows
516 */
517double taw(double kinematic_viscosity, double friction_velocity,
518 double wall_distance, double velocity, double pressure_gradient_tangent)
519{
520 // Compute integrated viscosity profiles
521 double F1 = integrate_1(kinematic_viscosity, wall_distance, friction_velocity, 0);
522 double Fy = integrate_1(kinematic_viscosity, wall_distance, friction_velocity, 1);
523
524 // Apply momentum balance: τ_w * F1 = u - (dp/dx) * Fy
525 return (1.0 / F1) * (velocity - pressure_gradient_tangent * Fy);
526}
527
528/**
529 * @brief Computes velocity using Cabot wall function
530 *
531 * Reconstructs velocity from wall shear stress and pressure gradient:
532 * u = τ_w * F1 + (dp/dx) * Fy
533 *
534 * @param[in] kinematic_viscosity Kinematic viscosity
535 * @param[in] wall_distance Distance from wall
536 * @param[in] friction_velocity Friction velocity
537 * @param[in] pressure_gradient_tangent Tangential pressure gradient
538 * @param[in] wall_shear_stress Wall shear stress
539 * @return Velocity at wall_distance
540 */
541double u_Cabot(double kinematic_viscosity, double wall_distance,
542 double friction_velocity, double pressure_gradient_tangent,
543 double wall_shear_stress)
544{
545 double F1 = integrate_1(kinematic_viscosity, wall_distance, friction_velocity, 0);
546 double Fy = integrate_1(kinematic_viscosity, wall_distance, friction_velocity, 1);
547
548 return wall_shear_stress * F1 + pressure_gradient_tangent * Fy;
549}
550
551/**
552 * @brief Residual function for Cabot wall function
553 *
554 * Computes: f(u_τ) = u_τ - sqrt(|τ_w(u_τ)|)
555 * This enforces consistency between u_τ and τ_w.
556 *
557 * @param[in] kinematic_viscosity Kinematic viscosity
558 * @param[in] velocity Velocity
559 * @param[in] wall_distance Distance from wall
560 * @param[in] friction_velocity_guess Guess for u_τ
561 * @param[in] pressure_gradient_tangent Tangential pressure gradient
562 * @param[in] pressure_gradient_normal Normal pressure gradient (currently unused)
563 * @return Residual value
564 */
565double f_Cabot(double kinematic_viscosity, double velocity, double wall_distance,
566 double friction_velocity_guess, double pressure_gradient_tangent,
567 double pressure_gradient_normal)
568{
569 double wall_shear = taw(kinematic_viscosity, friction_velocity_guess,
570 wall_distance, velocity, pressure_gradient_tangent);
571
572 return friction_velocity_guess - sqrt(fabs(wall_shear));
573}
574
575/**
576 * @brief Numerical derivative for Cabot wall function
577 */
578double df_Cabot(double kinematic_viscosity, double velocity, double wall_distance,
579 double friction_velocity_guess, double pressure_gradient_tangent,
580 double pressure_gradient_normal)
581{
582 const double perturbation = 1.e-7;
583
584 double f_plus = f_Cabot(kinematic_viscosity, velocity, wall_distance,
585 friction_velocity_guess + perturbation,
586 pressure_gradient_tangent, pressure_gradient_normal);
587
588 double f_minus = f_Cabot(kinematic_viscosity, velocity, wall_distance,
589 friction_velocity_guess - perturbation,
590 pressure_gradient_tangent, pressure_gradient_normal);
591
592 return (f_plus - f_minus) / (2.0 * perturbation);
593}
594
595/**
596 * @brief Solves for friction velocity using Cabot wall function
597 *
598 * This non-equilibrium wall function accounts for pressure gradient effects,
599 * making it more accurate in separated or strongly accelerating/decelerating flows.
600 *
601 * @param[in] kinematic_viscosity Kinematic viscosity
602 * @param[in] velocity Velocity at reference point
603 * @param[in] wall_distance Distance from wall
604 * @param[in] initial_guess Initial guess for u_τ
605 * @param[in] pressure_gradient_tangent Tangential pressure gradient
606 * @param[in] pressure_gradient_normal Normal pressure gradient
607 * @param[out] friction_velocity Converged friction velocity
608 * @param[out] wall_shear_velocity Wall shear stress for velocity
609 * @param[out] wall_shear_normal Wall shear stress for normal pressure gradient
610 */
611void find_utau_Cabot(double kinematic_viscosity, double velocity, double wall_distance,
612 double initial_guess, double pressure_gradient_tangent,
613 double pressure_gradient_normal, double *friction_velocity,
614 double *wall_shear_velocity, double *wall_shear_normal)
615{
616 double current_guess = initial_guess;
617 double new_guess;
618
619 const int max_iterations = 30;
620 const double convergence_tolerance = 1.e-10;
621
622 int iteration;
623 for (iteration = 0; iteration < max_iterations; iteration++) {
624 double residual = f_Cabot(kinematic_viscosity, velocity, wall_distance,
625 current_guess, pressure_gradient_tangent,
626 pressure_gradient_normal);
627
628 double derivative = df_Cabot(kinematic_viscosity, velocity, wall_distance,
629 current_guess, pressure_gradient_tangent,
630 pressure_gradient_normal);
631
632 new_guess = fabs(current_guess - residual / derivative);
633
634 if (fabs(current_guess - new_guess) < convergence_tolerance) {
635 break;
636 }
637
638 current_guess = new_guess;
639 }
640
641 if (fabs(current_guess - new_guess) > 1.e-5 && iteration >= 29) {
642 printf("\n!!!!!!!! Cabot Iteration Failed !!!!!!!!\n");
643 }
644
645 *friction_velocity = new_guess;
646 *wall_shear_velocity = taw(kinematic_viscosity, new_guess, wall_distance,
647 velocity, pressure_gradient_tangent);
648 *wall_shear_normal = taw(kinematic_viscosity, new_guess, wall_distance,
649 0.0, pressure_gradient_normal);
650}
651
652// ============================================================================
653// WERNER-WENGLE ALGEBRAIC WALL FUNCTION
654// ============================================================================
655
656/**
657 * @brief Computes velocity using Werner-Wengle wall function
658 *
659 * Algebraic wall function that provides explicit relation:
660 * u+ = y+ for y+ < 11.81 (viscous sublayer)
661 * u+ = A * (y+)^B for y+ ≥ 11.81 (power law)
662 * where A = 8.3, B = 1/7 are empirical constants.
663 *
664 * ADVANTAGES:
665 * - Explicit (no iteration required)
666 * - Computationally cheap
667 * - Reasonable accuracy for equilibrium boundary layers
668 *
669 * LIMITATIONS:
670 * - Less accurate than log-law for high Reynolds numbers
671 * - No pressure gradient effects
672 *
673 * @param[in] kinematic_viscosity Kinematic viscosity
674 * @param[in] wall_distance Distance from wall
675 * @param[in] friction_velocity Friction velocity
676 * @return Tangential velocity
677 */
678double u_Werner(double kinematic_viscosity, double wall_distance,
679 double friction_velocity)
680{
681 double yplus = friction_velocity * wall_distance / kinematic_viscosity;
682
683 // Werner-Wengle constants
684 const double power_law_coefficient = 8.3;
685 const double power_law_exponent = 1.0 / 7.0;
686
687 double velocity;
688
689 if (yplus <= VISCOUS_SUBLAYER_YPLUS) {
690 // Viscous sublayer: u+ = y+
691 velocity = yplus * friction_velocity;
692 }
693 else {
694 // Power-law region: u+ = A * (y+)^B
695 velocity = power_law_coefficient * pow(yplus, power_law_exponent) * friction_velocity;
696 }
697
698 return velocity;
699}
700
701/**
702 * @brief Residual function for Werner-Wengle iteration
703 *
704 * Computes residual: f(u_τ) = u_τ² - g(u, y, ν)
705 * where g is derived from the velocity profile inversion.
706 *
707 * @param[in] kinematic_viscosity Kinematic viscosity
708 * @param[in] velocity Known velocity
709 * @param[in] wall_distance Distance from wall
710 * @param[in] friction_velocity Guess for friction velocity
711 * @return Residual value
712 */
713double f_Werner(double kinematic_viscosity, double velocity,
714 double wall_distance, double friction_velocity)
715{
716 const double power_law_coefficient = 8.3;
717 const double power_law_exponent = 1.0 / 7.0;
718
719 // Transition point between viscous and power-law regions
720 double transition_distance = VISCOUS_SUBLAYER_YPLUS * kinematic_viscosity / friction_velocity;
721
722 // Transition velocity
723 double transition_velocity = kinematic_viscosity / (2.0 * transition_distance) *
724 pow(power_law_coefficient, 2.0 / (1.0 - power_law_exponent));
725
726 double residual;
727
728 if (fabs(velocity) <= transition_velocity) {
729 // Viscous sublayer regime
730 residual = friction_velocity * friction_velocity -
731 velocity / wall_distance * kinematic_viscosity;
732 }
733 else {
734 // Power-law regime (more complex inversion formula)
735 double term1 = 0.5 * (1.0 - power_law_exponent) *
736 pow(power_law_coefficient, (1.0 + power_law_exponent) /
737 (1.0 - power_law_exponent)) *
738 pow(kinematic_viscosity / wall_distance, 1.0 + power_law_exponent);
739
740 double term2 = (1.0 + power_law_exponent) / power_law_coefficient *
741 pow(kinematic_viscosity / wall_distance, power_law_exponent) *
742 fabs(velocity);
743
744 residual = friction_velocity * friction_velocity -
745 velocity / fabs(velocity) * pow(term1 + term2, 2.0 / (1.0 + power_law_exponent));
746 }
747
748 return residual;
749}
750
751/**
752 * @brief Numerical derivative for Werner-Wengle iteration
753 */
754double df_Werner(double kinematic_viscosity, double velocity,
755 double wall_distance, double friction_velocity)
756{
757 const double perturbation = 1.e-7;
758
759 double f_plus = f_Werner(kinematic_viscosity, velocity, wall_distance,
760 friction_velocity + perturbation);
761
762 double f_minus = f_Werner(kinematic_viscosity, velocity, wall_distance,
763 friction_velocity - perturbation);
764
765 return (f_plus - f_minus) / (2.0 * perturbation);
766}
767
768/**
769 * @brief Solves for friction velocity using Werner-Wengle wall function
770 *
771 * @param[in] kinematic_viscosity Kinematic viscosity
772 * @param[in] velocity Velocity at reference point
773 * @param[in] wall_distance Distance from wall
774 * @param[in] initial_guess Initial guess for u_τ
775 * @return Converged friction velocity
776 */
777double find_utau_Werner(double kinematic_viscosity, double velocity,
778 double wall_distance, double initial_guess)
779{
780 double current_guess = initial_guess;
781 double new_guess;
782
783 const int max_iterations = 20;
784 const double convergence_tolerance = 1.e-7;
785
786 int iteration;
787 for (iteration = 0; iteration < max_iterations; iteration++) {
788 double residual = f_Werner(kinematic_viscosity, velocity, wall_distance, current_guess);
789 double derivative = df_Werner(kinematic_viscosity, velocity, wall_distance, current_guess);
790
791 new_guess = current_guess - residual / derivative;
792
793 if (fabs(current_guess - new_guess) < convergence_tolerance) {
794 break;
795 }
796
797 current_guess = new_guess;
798 }
799
800 if (fabs(current_guess - new_guess) > 1.e-5 && iteration >= 19) {
801 printf("\n!!!!!!!! Werner-Wengle Iteration Failed !!!!!!!!\n");
802 }
803
804 return new_guess;
805}
806
807// ============================================================================
808// SIMPLE LOG-LAW WALL FUNCTION (NO ROUGHNESS)
809// ============================================================================
810
811/**
812 * @brief Computes velocity using simple log-law (smooth wall with roughness offset)
813 *
814 * Simple logarithmic profile:
815 * u = (u_τ / κ) * ln((y + y0) / y0)
816 * where y0 is a roughness length scale.
817 *
818 * @param[in] wall_distance Distance from wall
819 * @param[in] friction_velocity Friction velocity
820 * @param[in] roughness_length Roughness length scale y0
821 * @return Velocity
822 *
823 * @note This is a simplified model; use u_hydset_roughness for better accuracy
824 */
825double u_loglaw(double wall_distance, double friction_velocity, double roughness_length)
826{
827 return friction_velocity * (1.0 / KAPPA) * log((roughness_length + wall_distance) / roughness_length);
828}
829
830/**
831 * @brief Solves for friction velocity using simple log-law (explicit formula)
832 *
833 * Explicit inversion: u_τ = κ * u / ln((y + y0) / y0)
834 *
835 * @param[in] velocity Known velocity
836 * @param[in] wall_distance Distance from wall
837 * @param[in] roughness_length Roughness length scale
838 * @return Friction velocity
839 */
840double find_utau_loglaw(double velocity, double wall_distance, double roughness_length)
841{
842 return KAPPA * velocity / log((wall_distance + roughness_length) / roughness_length);
843}
844
845// ============================================================================
846// UTILITY FUNCTIONS
847// ============================================================================
848
849/**
850 * @brief Returns the sign of a number
851 *
852 * @param[in] value Input value
853 * @return +1 if positive, -1 if negative, 0 if zero
854 */
855static double sign(double value)
856{
857 if (value > 0) return 1.0;
858 else if (value < 0) return -1.0;
859 else return 0.0;
860}
861
862// ============================================================================
863// HIGH-LEVEL WALL FUNCTION INTERFACE FUNCTIONS
864// ============================================================================
865
866/**
867 * @brief Applies standard wall function with Werner-Wengle model
868 *
869 * This is a high-level interface that:
870 * 1. Decomposes velocity into normal/tangential components
871 * 2. Applies wall function to tangential velocity
872 * 3. Interpolates normal velocity
873 * 4. Reconstructs total velocity
874 *
875 * @param[in] user Simulation context
876 * @param[in] distance_reference Distance to reference point
877 * @param[in] distance_boundary Distance to boundary point
878 * @param[in] velocity_wall Wall velocity
879 * @param[in] velocity_reference Reference velocity
880 * @param[out] velocity_boundary Output boundary velocity
881 * @param[out] friction_velocity Output friction velocity
882 * @param[in] normal_x X-component of wall normal
883 * @param[in] normal_y Y-component of wall normal
884 * @param[in] normal_z Z-component of wall normal
885 */
886void wall_function(UserCtx *user, double distance_reference, double distance_boundary,
887 Cmpnts velocity_wall, Cmpnts velocity_reference,
888 Cmpnts *velocity_boundary, PetscReal *friction_velocity,
889 double normal_x, double normal_y, double normal_z)
890{
891 SimCtx *simCtx = user->simCtx;
892 double kinematic_viscosity = 1.0 / simCtx->ren;
893
894 // Decompose velocity into components
895 double delta_u = velocity_reference.x - velocity_wall.x;
896 double delta_v = velocity_reference.y - velocity_wall.y;
897 double delta_w = velocity_reference.z - velocity_wall.z;
898
899 double normal_velocity = delta_u * normal_x + delta_v * normal_y + delta_w * normal_z;
900
901 double tangential_u = delta_u - normal_velocity * normal_x;
902 double tangential_v = delta_v - normal_velocity * normal_y;
903 double tangential_w = delta_w - normal_velocity * normal_z;
904
905 double tangential_magnitude = sqrt(tangential_u * tangential_u +
906 tangential_v * tangential_v +
907 tangential_w * tangential_w);
908
909 // Apply Werner-Wengle wall function
910 double utau_guess = 0.05;
911 double tangential_modeled = u_Werner(kinematic_viscosity, distance_boundary, utau_guess);
912
913 // Scale tangential components
914 if (tangential_magnitude > 1.e-10) {
915 tangential_u *= tangential_modeled / tangential_magnitude;
916 tangential_v *= tangential_modeled / tangential_magnitude;
917 tangential_w *= tangential_modeled / tangential_magnitude;
918 }
919 else {
920 tangential_u = tangential_v = tangential_w = 0.0;
921 }
922
923 // Reconstruct velocity: U = U_t + U_n * n
924 (*velocity_boundary).x = tangential_u + (distance_boundary / distance_reference) * normal_velocity * normal_x;
925 (*velocity_boundary).y = tangential_v + (distance_boundary / distance_reference) * normal_velocity * normal_y;
926 (*velocity_boundary).z = tangential_w + (distance_boundary / distance_reference) * normal_velocity * normal_z;
927
928 // Add wall velocity
929 (*velocity_boundary).x += velocity_wall.x;
930 (*velocity_boundary).y += velocity_wall.y;
931 (*velocity_boundary).z += velocity_wall.z;
932}
933
934/**
935 * @brief Applies log-law wall function with roughness correction
936 *
937 * This is the recommended wall function interface for most applications.
938 * It uses the roughness-corrected log-law which is accurate for both
939 * smooth and rough walls.
940 *
941 * @param[in] user Simulation context
942 * @param[in] roughness_height Wall roughness height ks
943 * @param[in] distance_reference Distance to reference point
944 * @param[in] distance_boundary Distance to boundary point
945 * @param[in] velocity_wall Wall velocity (typically zero)
946 * @param[in] velocity_reference Reference velocity
947 * @param[out] velocity_boundary Output boundary velocity
948 * @param[out] friction_velocity Output friction velocity u_τ
949 * @param[in] normal_x X-component of wall normal
950 * @param[in] normal_y Y-component of wall normal
951 * @param[in] normal_z Z-component of wall normal
952 *
953 * @note Sets velocity to reference value if y+ > 300 (outside log-layer)
954 */
955void wall_function_loglaw(UserCtx *user, double roughness_height,
956 double distance_reference, double distance_boundary,
957 Cmpnts velocity_wall, Cmpnts velocity_reference,
958 Cmpnts *velocity_boundary, PetscReal *friction_velocity,
959 double normal_x, double normal_y, double normal_z)
960{
961 SimCtx *simCtx = user->simCtx;
962 double kinematic_viscosity = 1.0 / simCtx->ren;
963
964 // Decompose velocity
965 double delta_u = velocity_reference.x - velocity_wall.x;
966 double delta_v = velocity_reference.y - velocity_wall.y;
967 double delta_w = velocity_reference.z - velocity_wall.z;
968
969 double normal_velocity = delta_u * normal_x + delta_v * normal_y + delta_w * normal_z;
970
971 double tangential_u = delta_u - normal_velocity * normal_x;
972 double tangential_v = delta_v - normal_velocity * normal_y;
973 double tangential_w = delta_w - normal_velocity * normal_z;
974
975 double tangential_magnitude = sqrt(tangential_u * tangential_u +
976 tangential_v * tangential_v +
977 tangential_w * tangential_w);
978
979 // Solve for friction velocity
980 *friction_velocity = find_utau_hydset(kinematic_viscosity, tangential_magnitude,
981 distance_reference, 0.001, roughness_height);
982
983 // Compute wall function velocity
984 double tangential_modeled = u_hydset_roughness(kinematic_viscosity, distance_boundary,
985 *friction_velocity, roughness_height);
986
987 // Check if outside valid range (y+ > 300)
988 if (tangential_modeled < 0.0) {
989 tangential_modeled = tangential_magnitude;
990 }
991
992 // Scale tangential components
993 if (tangential_magnitude > 1.e-10) {
994 tangential_u *= tangential_modeled / tangential_magnitude;
995 tangential_v *= tangential_modeled / tangential_magnitude;
996 tangential_w *= tangential_modeled / tangential_magnitude;
997 }
998 else {
999 tangential_u = tangential_v = tangential_w = 0.0;
1000 }
1001
1002 // Reconstruct total velocity
1003 (*velocity_boundary).x = tangential_u + (distance_boundary / distance_reference) * normal_velocity * normal_x;
1004 (*velocity_boundary).y = tangential_v + (distance_boundary / distance_reference) * normal_velocity * normal_y;
1005 (*velocity_boundary).z = tangential_w + (distance_boundary / distance_reference) * normal_velocity * normal_z;
1006
1007 // Add wall velocity
1008 (*velocity_boundary).x += velocity_wall.x;
1009 (*velocity_boundary).y += velocity_wall.y;
1010 (*velocity_boundary).z += velocity_wall.z;
1011}
1012
1013/**
1014 * @brief Applies Cabot non-equilibrium wall function with pressure gradients
1015 *
1016 * This wall function accounts for pressure gradient effects and is most
1017 * accurate in separated or strongly accelerating/decelerating flows.
1018 *
1019 * @param[in] user Simulation context
1020 * @param[in] roughness_height Wall roughness (currently unused in this version)
1021 * @param[in] distance_reference Distance to reference point
1022 * @param[in] distance_boundary Distance to boundary point
1023 * @param[in] velocity_wall Wall velocity
1024 * @param[in] velocity_reference Reference velocity
1025 * @param[out] velocity_boundary Output boundary velocity
1026 * @param[out] friction_velocity Output friction velocity
1027 * @param[in] normal_x X-component of wall normal
1028 * @param[in] normal_y Y-component of wall normal
1029 * @param[in] normal_z Z-component of wall normal
1030 * @param[in] pressure_gradient_x X-component of pressure gradient
1031 * @param[in] pressure_gradient_y Y-component of pressure gradient
1032 * @param[in] pressure_gradient_z Z-component of pressure gradient
1033 * @param[in] iteration_count Current iteration count
1034 *
1035 * @note Only updates friction velocity every 5 iterations for stability
1036 * @note Normal pressure gradient currently set to zero
1037 */
1038void wall_function_Cabot(UserCtx *user, double roughness_height,
1039 double distance_reference, double distance_boundary,
1040 Cmpnts velocity_wall, Cmpnts velocity_reference,
1041 Cmpnts *velocity_boundary, PetscReal *friction_velocity,
1042 double normal_x, double normal_y, double normal_z,
1043 double pressure_gradient_x, double pressure_gradient_y,
1044 double pressure_gradient_z, int iteration_count)
1045{
1046 SimCtx *simCtx = user->simCtx;
1047 double kinematic_viscosity = 1.0 / simCtx->ren;
1048
1049 // Decompose velocity
1050 double delta_u = velocity_reference.x - velocity_wall.x;
1051 double delta_v = velocity_reference.y - velocity_wall.y;
1052 double delta_w = velocity_reference.z - velocity_wall.z;
1053
1054 double normal_velocity = delta_u * normal_x + delta_v * normal_y + delta_w * normal_z;
1055
1056 double tangential_u = delta_u - normal_velocity * normal_x;
1057 double tangential_v = delta_v - normal_velocity * normal_y;
1058 double tangential_w = delta_w - normal_velocity * normal_z;
1059
1060 double tangential_magnitude = sqrt(tangential_u * tangential_u +
1061 tangential_v * tangential_v +
1062 tangential_w * tangential_w);
1063
1064 // Compute tangential pressure gradient
1065 double pressure_gradient_tangent = 0.0;
1066 if (tangential_magnitude > 1.e-10) {
1067 pressure_gradient_tangent = (pressure_gradient_x * tangential_u +
1068 pressure_gradient_y * tangential_v +
1069 pressure_gradient_z * tangential_w) / tangential_magnitude;
1070 }
1071
1072 // Normal pressure gradient (currently set to zero)
1073 double pressure_gradient_normal = 0.0;
1074
1075 // Solve for friction velocity (only on first iteration or periodically)
1076 if (iteration_count == 0 || iteration_count > 4) {
1077 double utau, wall_shear1, wall_shear2;
1078 find_utau_Cabot(kinematic_viscosity, tangential_magnitude, distance_reference,
1079 0.01, pressure_gradient_tangent, pressure_gradient_normal,
1080 &utau, &wall_shear1, &wall_shear2);
1081 *friction_velocity = utau;
1082 }
1083
1084 // Compute wall function velocity with pressure gradient correction
1085 double tangential_modeled = u_Cabot(kinematic_viscosity, distance_boundary,
1086 *friction_velocity, pressure_gradient_tangent,
1087 taw(kinematic_viscosity, *friction_velocity,
1088 distance_reference, tangential_magnitude,
1089 pressure_gradient_tangent));
1090
1091 // Scale tangential components
1092 if (tangential_magnitude > 1.e-10) {
1093 tangential_u *= tangential_modeled / tangential_magnitude;
1094 tangential_v *= tangential_modeled / tangential_magnitude;
1095 tangential_w *= tangential_modeled / tangential_magnitude;
1096 }
1097 else {
1098 tangential_u = tangential_v = tangential_w = 0.0;
1099 }
1100
1101 // Reconstruct total velocity
1102 (*velocity_boundary).x = tangential_u + (distance_boundary / distance_reference) * normal_velocity * normal_x;
1103 (*velocity_boundary).y = tangential_v + (distance_boundary / distance_reference) * normal_velocity * normal_y;
1104 (*velocity_boundary).z = tangential_w + (distance_boundary / distance_reference) * normal_velocity * normal_z;
1105
1106 // Add wall velocity
1107 (*velocity_boundary).x += velocity_wall.x;
1108 (*velocity_boundary).y += velocity_wall.y;
1109 (*velocity_boundary).z += velocity_wall.z;
1110}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:731
PetscReal ren
Definition variables.h:632
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
A 3D point or vector with PetscScalar components.
Definition variables.h:100
The master context for the entire simulation.
Definition variables.h:585
User-defined context containing data specific to a single computational grid level.
Definition variables.h:728
double df_Cabot(double kinematic_viscosity, double velocity, double wall_distance, double friction_velocity_guess, double pressure_gradient_tangent, double pressure_gradient_normal)
Numerical derivative for Cabot wall function.
double f_Cabot(double kinematic_viscosity, double velocity, double wall_distance, double friction_velocity_guess, double pressure_gradient_tangent, double pressure_gradient_normal)
Residual function for Cabot wall function.
void wall_function_loglaw(UserCtx *user, double roughness_height, double distance_reference, double distance_boundary, Cmpnts velocity_wall, Cmpnts velocity_reference, Cmpnts *velocity_boundary, PetscReal *friction_velocity, double normal_x, double normal_y, double normal_z)
Applies log-law wall function with roughness correction.
double find_utau_loglaw(double velocity, double wall_distance, double roughness_length)
Solves for friction velocity using simple log-law (explicit formula)
double u_Werner(double kinematic_viscosity, double wall_distance, double friction_velocity)
Computes velocity using Werner-Wengle wall function.
double u_hydset_roughness(double kinematic_viscosity, double wall_distance, double friction_velocity, double roughness_height)
Computes velocity from log-law for rough walls.
static double sign(double value)
Returns the sign of a number.
void wall_function(UserCtx *user, double distance_reference, double distance_boundary, Cmpnts velocity_wall, Cmpnts velocity_reference, Cmpnts *velocity_boundary, PetscReal *friction_velocity, double normal_x, double normal_y, double normal_z)
Applies standard wall function with Werner-Wengle model.
#define DAMPING_COEFFICIENT
Eddy viscosity damping coefficient (van Driest damping)
double taw(double kinematic_viscosity, double friction_velocity, double wall_distance, double velocity, double pressure_gradient_tangent)
Computes wall shear stress with pressure gradient effects.
double find_utau_hydset(double kinematic_viscosity, double known_velocity, double wall_distance, double initial_guess, double roughness_height)
Solves for friction velocity using Newton-Raphson iteration.
double u_Cabot(double kinematic_viscosity, double wall_distance, double friction_velocity, double pressure_gradient_tangent, double wall_shear_stress)
Computes velocity using Cabot wall function.
#define ROUGHNESS_TRANSITION_YPLUS
Smooth-to-rough transition y+ threshold.
double df_Werner(double kinematic_viscosity, double velocity, double wall_distance, double friction_velocity)
Numerical derivative for Werner-Wengle iteration.
double f_Werner(double kinematic_viscosity, double velocity, double wall_distance, double friction_velocity)
Residual function for Werner-Wengle iteration.
#define VISCOUS_SUBLAYER_YPLUS
Viscous sublayer thickness y+ threshold.
double u_loglaw(double wall_distance, double friction_velocity, double roughness_length)
Computes velocity using simple log-law (smooth wall with roughness offset)
void wall_function_Cabot(UserCtx *user, double roughness_height, double distance_reference, double distance_boundary, Cmpnts velocity_wall, Cmpnts velocity_reference, Cmpnts *velocity_boundary, PetscReal *friction_velocity, double normal_x, double normal_y, double normal_z, double pressure_gradient_x, double pressure_gradient_y, double pressure_gradient_z, int iteration_count)
Applies Cabot non-equilibrium wall function with pressure gradients.
#define LOGLAW_B
Log-law intercept constant B for smooth walls.
void noslip(UserCtx *user, double distance_reference, double distance_boundary, Cmpnts velocity_wall, Cmpnts velocity_reference, Cmpnts *velocity_boundary, double normal_x, double normal_y, double normal_z)
Applies no-slip wall boundary condition with linear interpolation.
void find_utau_Cabot(double kinematic_viscosity, double velocity, double wall_distance, double initial_guess, double pressure_gradient_tangent, double pressure_gradient_normal, double *friction_velocity, double *wall_shear_velocity, double *wall_shear_normal)
Solves for friction velocity using Cabot wall function.
double integrate_1(double kinematic_viscosity, double wall_distance, double friction_velocity, int integration_mode)
Integrates eddy viscosity profile from wall to distance y.
#define FULLY_ROUGH_YPLUS
Fully rough regime y+ threshold.
double f_hydset(double kinematic_viscosity, double known_velocity, double wall_distance, double friction_velocity_guess, double roughness_height)
Residual function for friction velocity equation (log-law with roughness)
double E_coeff(double friction_velocity, double roughness_height, double kinematic_viscosity)
Computes roughness-modified log-law coefficient E.
#define KAPPA
von Karman constant (universal turbulence constant)
double nu_t(double yplus)
Computes turbulent eddy viscosity ratio (ν_t / ν)
double df_hydset(double kinematic_viscosity, double known_velocity, double wall_distance, double friction_velocity_guess, double roughness_height)
Numerical derivative of residual function.
double find_utau_Werner(double kinematic_viscosity, double velocity, double wall_distance, double initial_guess)
Solves for friction velocity using Werner-Wengle wall function.
void freeslip(UserCtx *user, double distance_reference, double distance_boundary, Cmpnts velocity_wall, Cmpnts velocity_reference, Cmpnts *velocity_boundary, double normal_x, double normal_y, double normal_z)
Applies free-slip wall boundary condition.