Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d5b86df
Add Herschel-Bulkley non-Newtonian viscosity model
sbryngelson Mar 26, 2026
67f74c0
fix: add GPU_DECLARE/GPU_UPDATE for fluid_pp (required for non-Newton…
sbryngelson Mar 27, 2026
1be6ef3
fix: skip mu_max clamp when mu_max is unset (default sentinel is nega…
sbryngelson Mar 27, 2026
6d8313a
fix: restore master's hyper_cleaning s_L/s_R (was incorrectly changed…
sbryngelson Mar 27, 2026
13b79f1
fix: restore hyper_cleaning block inside wave_speeds==1 branch (stale…
sbryngelson Mar 27, 2026
cc6373c
Merge branch 'master' into feature/non-newtonian-viscosity
sbryngelson Mar 31, 2026
e32f038
Merge branch 'master' into feature/non-newtonian-viscosity
sbryngelson Apr 1, 2026
d8facd7
Merge branch 'master' into feature/non-newtonian-viscosity
sbryngelson Apr 2, 2026
9e08f60
Merge master into feature/non-newtonian-viscosity
sbryngelson Apr 6, 2026
e8903e3
Merge branch 'master' into feature/non-newtonian-viscosity
sbryngelson Apr 6, 2026
d9e5b04
Merge master into feature/non-newtonian-viscosity: resolve conflicts
sbryngelson May 4, 2026
8b2c874
fix: replace momxb with eqn_idx%mom%beg in m_re_visc.fpp
sbryngelson May 4, 2026
0994f50
format: wrap long lines in m_re_visc.fpp to pass CI cleanliness check
sbryngelson May 4, 2026
eab5b06
format: collapse multi-line ValueError to single line in registry.py
sbryngelson May 4, 2026
231ae8d
ci: retrigger CI after transient network failures in NVHPC jobs
sbryngelson May 4, 2026
d02076c
Fix non-Newtonian viscosity bugs: mu_max sentinel, shear-rate clamp, …
sbryngelson May 5, 2026
3fdebb6
Fix IBM non-Newtonian viscosity: compute local shear rate per cell in…
sbryngelson May 5, 2026
266c79e
Expose s_compute_velocity_gradients_at_cell as public for IBM use
sbryngelson May 5, 2026
989b1e7
Fix nvfortran GPU build: drop pure from subroutines with GPU_LOOP dir…
sbryngelson May 5, 2026
3c636c5
Update golden file for non-Newtonian shear-thinning test (45DA4729)
sbryngelson May 5, 2026
4813f74
Fix zero-shear NaN/Inf in f_compute_hb_viscosity
sbryngelson May 5, 2026
55ded73
Fix three bugs flagged in code review
sbryngelson May 5, 2026
93973d6
fix: invalid Fortran continuation in m_ibm.fpp breaks Cray ftn build
sbryngelson May 6, 2026
b2f262c
fix: add IGR guard, shear-thinning mu_max check, and weno_Re_flux test
sbryngelson May 6, 2026
b2635e3
fix: Cray ftn continuation and AMD flang case-opt array mismatch
sbryngelson May 6, 2026
08761e0
fix: pre-extract fluid_pp HB params before GPU_PARALLEL_LOOP in m_ibm…
sbryngelson May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/documentation/case.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,14 @@ Additional details on this specification can be found in [NACA airfoil](https://
| `qvp` ** | Real | Stiffened-gas parameter $q'$ of fluid. |
| `sigma` | Real | Surface tension coefficient |
| `G` | Real | Shear modulus of solid. |
| `non_newtonian` | Logical | Enable non-Newtonian (Herschel-Bulkley) viscosity. See @ref sec-non-newtonian. |
| `tau0` | Real | Yield stress \f$\tau_0\f$ (Herschel-Bulkley). |
| `K` | Real | Consistency index \f$K\f$ (Herschel-Bulkley). |
| `nn` | Real | Flow behavior index \f$n\f$ (Herschel-Bulkley).|
| `hb_m` | Real | Papanastasiou regularization parameter \f$m\f$. |
| `mu_min` | Real | Minimum viscosity clamp. |
| `mu_max` | Real | Maximum viscosity clamp. |
| `mu_bulk` | Real | Bulk viscosity (non-Newtonian). |

Fluid material's parameters. All parameters except for sigma should be prepended with `fluid_pp(i)` where $i$ is the fluid index.

Expand All @@ -403,6 +411,38 @@ The parameters define material's property of compressible fluids that are used i
When these parameters are undefined, fluids are treated as inviscid.
Details of implementation of viscosity in MFC can be found in \cite Coralic15.

#### Non-Newtonian Viscosity (Herschel-Bulkley) {#sec-non-newtonian}

MFC supports non-Newtonian viscosity via the Herschel-Bulkley model with Papanastasiou regularization.
Enable it per-fluid by setting ``fluid_pp(i)%%non_newtonian = 'T'`` (requires ``viscous = 'T'``).

The effective viscosity is:

\f[ \mu(\dot\gamma) = \frac{\tau_0}{\dot\gamma}\bigl(1 - e^{-m\,\dot\gamma}\bigr) + K\,\dot\gamma^{\,n-1} \f]

where \f$\dot\gamma = \sqrt{2\,D_{ij}\,D_{ij}}\f$ is the shear rate computed from the strain-rate tensor.

| Parameter | Type | Description |
| ---: | :---: | :--- |
| ``non_newtonian`` | Logical | Enable non-Newtonian viscosity for this fluid |
| ``tau0`` | Real | Yield stress \f$\tau_0\f$. Set to 0 for a power-law fluid |
| ``K`` | Real | Consistency index \f$K\f$ (must be > 0) |
| ``nn`` | Real | Flow behavior index \f$n\f$: shear-thinning (\f$n<1\f$), Newtonian (\f$n=1\f$), shear-thickening (\f$n>1\f$) |
| ``hb_m`` | Real | Papanastasiou regularization parameter \f$m\f$. Higher values approximate the true yield stress more closely (typical: 1000--10000) |
| ``mu_min`` | Real | Minimum viscosity clamp (must be >= 0) |
| ``mu_max`` | Real | Maximum viscosity clamp (must be > ``mu_min``) |
| ``mu_bulk``| Real | Bulk viscosity for non-Newtonian fluids (optional, default 0 = inviscid bulk) |

All parameters are prepended with ``fluid_pp(i)%%``.

**Special cases:**
- \f$\tau_0 = 0\f$: reduces to power-law model \f$\mu = K\,\dot\gamma^{\,n-1}\f$.
- \f$n = 1,\, \tau_0 = 0\f$: reduces to Newtonian with \f$\mu = K\f$.
- \f$n = 1,\, \tau_0 > 0\f$: reduces to Bingham plastic.

> **Note:** When ``non_newtonian = 'T'``, the ``Re(1)``/``Re(2)`` parameters are ignored for that fluid.
> The viscosity is computed from the Herschel-Bulkley model instead.

- `fluid_pp(i)%%cv`, `fluid_pp(i)%%qv`, and `fluid_pp(i)%%qvp` define $c_v$, $q$, and $q'$ as parameters of $i$-th fluid that are used in stiffened gas equation of state.

- `fluid_pp(i)%%G` is required for `hypoelasticity`.
Expand Down
2 changes: 2 additions & 0 deletions docs/module_categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"m_acoustic_src",
"m_body_forces",
"m_pressure_relaxation",
"m_hb_function",
"m_re_visc",
"m_collisions"
]
},
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 117 additions & 0 deletions examples/2D_lid_driven_cavity_nn/case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""
2D Lid-Driven Cavity Flow with Herschel-Bulkley Non-Newtonian Fluid

Re = 5000, n = 1.5 (shear-thickening) with mesh stretching near walls.

HB model: mu = (tau0/gdot)*(1 - exp(-m*gdot)) + K * gdot^(n-1)
Re_gen = rho * U^(2-n) * L^n / K = 1 * 1^0.5 * 1^1.5 / 0.0002 = 5000

Mesh stretching: cosh-based clustering near all 4 walls (x_a, x_b, y_a, y_b).
Comment on lines +5 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Docstring describes mesh stretching, but the case config does not enable it.

The header says wall clustering/stretching is used, but no stretch_* toggles or stretching coefficients are set in the emitted JSON.

📝 Proposed fix
- Re = 5000, n = 1.5 (shear-thickening) with mesh stretching near walls.
+ Re = 5000, n = 1.5 (shear-thickening) on a uniform grid.
@@
- Mesh stretching: cosh-based clustering near all 4 walls (x_a, x_b, y_a, y_b).
+ (No mesh stretching parameters are enabled in this case file.)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Re = 5000, n = 1.5 (shear-thickening) with mesh stretching near walls.
HB model: mu = (tau0/gdot)*(1 - exp(-m*gdot)) + K * gdot^(n-1)
Re_gen = rho * U^(2-n) * L^n / K = 1 * 1^0.5 * 1^1.5 / 0.0002 = 5000
Mesh stretching: cosh-based clustering near all 4 walls (x_a, x_b, y_a, y_b).
Re = 5000, n = 1.5 (shear-thickening) on a uniform grid.
HB model: mu = (tau0/gdot)*(1 - exp(-m*gdot)) + K * gdot^(n-1)
Re_gen = rho * U^(2-n) * L^n / K = 1 * 1^0.5 * 1^1.5 / 0.0002 = 5000
(No mesh stretching parameters are enabled in this case file.)

"""

import json

eps = 1e-6

# HB model parameters
tau0 = 0.0 # Yield stress (set to 0 for power-law fluid)
K = 0.0002 # Consistency index (Re=5000: K = 1/5000)
nn = 1.5 # Flow behavior index (shear-thickening)
mu_min = 0.00002 # K * gdot_min^(n-1) = 0.0002 * (0.01)^0.5
mu_max = 0.0632 # K * gdot_max^(n-1) = 0.0002 * (1e5)^0.5
hb_m = 1000.0 # Papanastasiou regularization parameter
mu_bulk = 0.0

lid_velocity = 1.0 # Lid velocity (m/s)

# Configuring case dictionary
print(
json.dumps(
{
# Logistics
"run_time_info": "T",
# Computational Domain Parameters
"x_domain%beg": 0.0,
"x_domain%end": 1.0,
"y_domain%beg": 0.0,
"y_domain%end": 1.0,
"m": 255,
"n": 255,
"p": 0,
"cfl_adap_dt": "T",
"cfl_target": 0.5,
"n_start": 0,
"t_stop": 50.0,
"t_save": 25.0,
# Simulation Algorithm Parameters
"num_patches": 1,
"model_eqns": 2,
"alt_soundspeed": "F",
"num_fluids": 2,
"mpp_lim": "F",
"mixture_err": "T",
"time_stepper": 3,
"weno_order": 5,
"weno_eps": 1e-16,
"mapped_weno": "T",
"weno_Re_flux": "T",
"mp_weno": "T",
"weno_avg": "T",
"riemann_solver": 2,
"wave_speeds": 1,
"avg_state": 2,
"bc_x%beg": -16,
"bc_x%end": -16,
"bc_y%beg": -16,
"bc_y%end": -16,
"bc_y%ve1": lid_velocity,
"viscous": "T",
# Formatted Database Files Structure Parameters
"format": 1,
"precision": 2,
"prim_vars_wrt": "T",
"omega_wrt(3)": "T",
"fd_order": 4,
"parallel_io": "T",
# Patch 1: Base
"patch_icpp(1)%geometry": 3,
"patch_icpp(1)%x_centroid": 0.5,
"patch_icpp(1)%y_centroid": 0.5,
"patch_icpp(1)%length_x": 1.0,
"patch_icpp(1)%length_y": 1.0,
"patch_icpp(1)%vel(1)": 0,
"patch_icpp(1)%vel(2)": 0.0,
"patch_icpp(1)%pres": 1e3,
"patch_icpp(1)%alpha_rho(1)": 0.5,
"patch_icpp(1)%alpha(1)": 0.5,
"patch_icpp(1)%alpha_rho(2)": 0.5,
"patch_icpp(1)%alpha(2)": 0.5,
# Fluids Physical Parameters
# Fluid 1:
"fluid_pp(1)%gamma": 1.0 / (1.4 - 1.0),
"fluid_pp(1)%pi_inf": 0.0,
"fluid_pp(1)%Re(1)": 1.0 / K,
"fluid_pp(1)%non_newtonian": "T",
"fluid_pp(1)%tau0": tau0,
"fluid_pp(1)%K": K,
"fluid_pp(1)%nn": nn,
"fluid_pp(1)%mu_max": mu_max,
"fluid_pp(1)%mu_min": mu_min,
"fluid_pp(1)%mu_bulk": mu_bulk,
"fluid_pp(1)%hb_m": hb_m,
# Fluid 2:
"fluid_pp(2)%gamma": 1.0 / (1.4 - 1.0),
"fluid_pp(2)%pi_inf": 0.0,
"fluid_pp(2)%Re(1)": 1.0 / K,
"fluid_pp(2)%non_newtonian": "T",
"fluid_pp(2)%tau0": tau0,
"fluid_pp(2)%K": K,
"fluid_pp(2)%nn": nn,
"fluid_pp(2)%mu_max": mu_max,
"fluid_pp(2)%mu_min": mu_min,
"fluid_pp(2)%mu_bulk": mu_bulk,
"fluid_pp(2)%hb_m": hb_m,
}
)
)
159 changes: 159 additions & 0 deletions examples/2D_poiseuille_nn/case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""
2D Poiseuille Flow with Herschel-Bulkley Non-Newtonian Fluid

Pressure-driven channel flow between two no-slip walls, driven by a constant
body force in the streamwise (x) direction. Periodic BCs in x, no-slip in y.

HB model: mu = (tau0/gdot)*(1 - exp(-m*gdot)) + K * gdot^(n-1)
- tau0: yield stress
- K: consistency index
- n: flow behavior index (< 1 shear-thinning, > 1 shear-thickening)
- m: Papanastasiou regularization parameter

For Newtonian Poiseuille validation, set tau0=0, nn=1, K=mu.
The analytical solution is: u(y) = (G/(2*mu)) * y * (H - y)
where G = rho * g_x is the effective pressure gradient.
"""

import json
import math

# -- Channel geometry (square domain) --
L = 1.0 # Channel length (streamwise, x)
H = 1.0 # Channel height (wall-normal, y)

# -- Grid resolution --
Nx = 24 # Cells in x (streamwise, minimal — periodic)
Ny = 81 # Cells in y (wall-normal)

# -- Fluid properties --
rho = 1.0 # Density
p0 = 1e5 # Reference pressure (high for low Mach)
gamma = 1.4 # Ratio of specific heats

# Sound speed and CFL
c = math.sqrt(gamma * p0 / rho)
dx = L / (Nx + 1)
cfl = 0.3
dt = cfl * dx / c

# -- Body force (pressure gradient substitute) --
# G = rho * g_x acts as dp/dx driving force
g_x = 0.5

# -- HB non-Newtonian model parameters --
tau0 = 0.0 # Yield stress (set 0 for power-law)
K = 0.1 # Consistency index
nn = 2.0 # Flow behavior index (< 1 = shear-thinning)
hb_m = 1000.0 # Papanastasiou regularization parameter
mu_min = 1e-4 # Minimum viscosity bound
mu_max = 10.0 # Maximum viscosity bound
mu_bulk = 0.0 # Bulk viscosity

# Reference Re based on consistency index (used as baseline)
Re_ref = 1.0 / K # = 100

# -- Time control --
t_end = 10.0 # End time (allow flow to reach steady state)
t_save = 5.0 # Save interval

eps = 1e-6

# Configuring case dictionary
print(
json.dumps(
{
# Logistics
"run_time_info": "T",
# Computational Domain Parameters
"x_domain%beg": 0.0,
"x_domain%end": L,
"y_domain%beg": 0.0,
"y_domain%end": H,
"m": Nx,
"n": Ny,
"p": 0,
"cfl_adap_dt": "T",
"cfl_target": cfl,
"n_start": 0,
"t_stop": t_end,
"t_save": t_save,
# Simulation Algorithm Parameters
"num_patches": 1,
"model_eqns": 2,
"alt_soundspeed": "F",
"num_fluids": 2,
"mpp_lim": "F",
"mixture_err": "T",
"time_stepper": 3,
"weno_order": 5,
"weno_eps": 1e-16,
"mapped_weno": "T",
"weno_Re_flux": "T",
"mp_weno": "T",
"weno_avg": "T",
"riemann_solver": 2,
"wave_speeds": 1,
"avg_state": 2,
# Boundary Conditions
# Periodic in x (streamwise), no-slip walls in y
"bc_x%beg": -1,
"bc_x%end": -1,
"bc_y%beg": -16,
"bc_y%end": -16,
# Viscous
"viscous": "T",
# Body Force (drives the flow like a pressure gradient)
"bf_x": "T",
"g_x": g_x,
"k_x": 0.0,
"w_x": 0.0,
"p_x": 0.0,
# Formatted Database Files Structure Parameters
"format": 1,
"precision": 2,
"prim_vars_wrt": "T",
"omega_wrt(3)": "T",
"fd_order": 4,
"parallel_io": "T",
# Patch 1: Entire channel domain (initially at rest)
"patch_icpp(1)%geometry": 3,
"patch_icpp(1)%x_centroid": L / 2.0,
"patch_icpp(1)%y_centroid": H / 2.0,
"patch_icpp(1)%length_x": L,
"patch_icpp(1)%length_y": H,
"patch_icpp(1)%vel(1)": 0.0,
"patch_icpp(1)%vel(2)": 0.0,
"patch_icpp(1)%pres": p0,
"patch_icpp(1)%alpha_rho(1)": rho * 0.5,
"patch_icpp(1)%alpha(1)": 0.5,
"patch_icpp(1)%alpha_rho(2)": rho * 0.5,
"patch_icpp(1)%alpha(2)": 0.5,
# Fluid 1: HB non-Newtonian fluid
"fluid_pp(1)%gamma": 1.0 / (gamma - 1.0),
"fluid_pp(1)%pi_inf": 0.0,
"fluid_pp(1)%Re(1)": Re_ref,
"fluid_pp(1)%non_newtonian": "T",
"fluid_pp(1)%tau0": tau0,
"fluid_pp(1)%K": K,
"fluid_pp(1)%nn": nn,
"fluid_pp(1)%hb_m": hb_m,
"fluid_pp(1)%mu_min": mu_min,
"fluid_pp(1)%mu_max": mu_max,
"fluid_pp(1)%mu_bulk": mu_bulk,
# Fluid 2: same properties (single-phase effectively)
"fluid_pp(2)%gamma": 1.0 / (gamma - 1.0),
"fluid_pp(2)%pi_inf": 0.0,
"fluid_pp(2)%Re(1)": Re_ref,
"fluid_pp(2)%non_newtonian": "T",
"fluid_pp(2)%tau0": tau0,
"fluid_pp(2)%K": K,
"fluid_pp(2)%nn": nn,
"fluid_pp(2)%hb_m": hb_m,
"fluid_pp(2)%mu_min": mu_min,
"fluid_pp(2)%mu_max": mu_max,
"fluid_pp(2)%mu_bulk": mu_bulk,
}
)
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading