Improvements to a semi-implicit integration scheme for viscous fluids in SPH

Why

Low Reynolds number ⇒\Longrightarrow small timestep

Standard WCSPH with explicit integrator:

Δt≤minβ{C1h∥a⃗β∥,C2hcβ,C3ρβh2μβ} \Delta t \le \min_\beta \left\{ C_1\sqrt{\frac{h}{\lVert\vec a_\beta\rVert}}, C_2\frac{h}{c_\beta}, C_3\frac{\rho_\beta h^2}{\mu_\beta} \right\}

hh smoothing length, cc sound speed, a⃗\vec a acceleration, ρ\rho density and μ\mu dynamic viscosity

High viscosity + moderate/high resolution ⇒\Longrightarrow very small Δt\Delta t.

(For sound speed we cheat with c=10umaxc = 10 u_{max},
can’t do that with viscosity in viscous flows!)

Implicit integration to the rescue

Avoid viscous constraint on time-step with semi-implicit integration (Zago et al., 2018 doi:10.1016/j.jcp.2018.07.060):

u⃗β(n+1)=u⃗β(n)+Δt(f⃗β,P(n)+g⃗)+Δt∑α2μ‾αβ(n)ρα(n)ρβ(n)Fαβ(n)mαu⃗αβ(n+1) \vec u_\beta^{(n+1)} = \vec u_\beta^{(n)} + \Delta t \left(\vec f_{\beta,P}^{(n)} + \vec g\right) + \Delta t \sum_\alpha \frac{2\bar\mu_{\alpha\beta}^{(n)}}{\rho_\alpha^{(n)} \rho_\beta^{(n)}} F^{(n)}_{\alpha\beta} m_\alpha \vec u_{\alpha\beta}^{(n+1)}

uu velocity, FF scalar part of ∇W\nabla W, f⃗P\vec f_P pressure forces, ⋅(⋅)\cdot^{(\cdot)} step of evaluation.

Rearrange and get A(n)(Δt)u⃗(n+1)=b⃗(n)(Δt) A^{(n)}(\Delta t) \vec u^{(n+1)} = \vec b^{(n)}(\Delta t)

b⃗\vec b is just inviscid integration

Simple case

Fluid part of matrix A(n)A^{(n)} is always diagonally dominant.
Also symmetric if single-fluid system had uniform initialization.

Boundary? Depends on BC!

Dynamic BC ⇒\Longrightarrow boundary particle velocity is known ⇒\Longrightarrow matrix is SPD ⇒\Longrightarrow solve with Conjugate Gradient.

(But let’s be honest here, there’s better BCs.)

What

Other boundary conditions?

Consider e.g. “dummy” boundary conditions (Adami et al.).

Viscous contribution from boundary 𝒲\mathcal W to fluid ℱ\mathcal F particles uses fictitious velocity

u⃗β,v=2u⃗β,w−∑α∈ℱu⃗αWβα∑α∈ℱWβα \vec u_{\beta,v} = 2 \vec u_{\beta,w} - \frac{ \sum_{\alpha\in\mathcal F} \vec u_\alpha W_{\beta\alpha} }{ \sum_{\alpha\in\mathcal F} W_{\beta\alpha} }

u⃗w\vec u_w prescribed wall velocity

Implicit visc. scheme ⇒\Longrightarrow must compute u⃗v\vec u_v for 𝒲\mathcal W and u⃗\vec u for ℱ\mathcal F together.

Matrix shape

Diagonal: Off-diagonal
Aββ(n)(Δt)={1−Δt∑α∈ℱ∪𝒲Kαβ(n)∀β∈ℱ,1∀β∈𝒲 A_{\beta\beta}^{(n)}(\Delta t) = \begin{cases} 1 - \Delta t \displaystyle\sum_{\alpha\in\mathcal F \cup \mathcal W} K_{\alpha\beta}^{(n)} &\forall\beta\in\mathcal F,\\ 1 & \forall\beta\in\mathcal W \end{cases} Aβα(n)(Δt)={ΔtKαβ(n)β∈ℱ, neib α∈ℱ∪𝒲Wβα∑α′∈ℱWβα′β∈𝒲, neib α∈ℱ0otherwise A_{\beta\alpha}^{(n)}(\Delta t) = \begin{cases} \Delta t K_{\alpha\beta}^{(n)} & \text{$\beta\in\mathcal F$, neib $\alpha \in\mathcal F\cup\mathcal W$}\\ \frac{W_{\beta\alpha}}{\displaystyle\sum_{\alpha'\in\mathcal F} W_{\beta\alpha'}} & \text{$\beta\in\mathcal W$, neib $\alpha\in\mathcal F$}\\ 0 & \text{otherwise} \end{cases}

with Kαβ(n)=−2μ‾αβ(n)ρα(n)ρβ(n)Fαβ(n)mαK_{\alpha\beta}^{(n)} = -\frac{2\bar\mu_{\alpha\beta}^{(n)}}{\rho_\alpha^{(n)} \rho_\beta^{(n)}} F_{\alpha\beta}^{(n)} m_\alpha

Fluid rows still diagonally dominant: |Aββ|=1+∑α≠β|Aβα|\lvert A_{\beta\beta}\rvert = 1 + \sum_{\alpha \ne \beta} \lvert A_{\beta\alpha}\rvert,
boundary rows not (|Aββ|=∑α≠β|Aβα|\lvert A_{\beta\beta}\rvert = \sum_{\alpha \ne \beta} \lvert A_{\beta\alpha}\rvert)!

Matrix is Weakly-Chained Diagonally Dominant (chain: single link from 𝒲\mathcal W to contributing ℱ\mathcal F) ⇒\Longrightarrow non-singular.

Can still solve (?)

Matrix is non-singular, but also not symmetric.
Let’s solve A(n)(Δt)u⃗(n+1)=b⃗(n)(Δt)A^{(n)}(\Delta t) \vec u^{(n+1)} = \vec b^{(n)}(\Delta t) using BiCGSTAB.

In single precision.

With residue tolerance εtol∥b⃗∥\varepsilon_{tol} \lVert \vec b\rVert.

And εtol=εM\varepsilon_{tol} = \varepsilon_M single-precision machine epsilon.

(Narrator voice: they couldn’t)

BiCGSTAB numerical stability

BiCGSTAB not STAB enough?
Can’t work with such strict tolerances in single precision
(algorithm stalls or blows up).

(Everybody knows that: it’s why they use εtol=10−5\varepsilon_{tol} = 10^{-5}.)

But why go the easy way when you can suffer?

Let’s fix BiCGSTAB instead.

How

Standard BiCGSTAB

x⃗0\vec x_0 initial guess, r⃗0=b⃗−Ax⃗0\vec r_0 = \vec b - A\vec x_0 residual, r⃗̂0=r⃗0\hat{\vec r}_0 = \vec r_0, p⃗0=0⃗\vec p_0 = \vec 0, γ0=α0=ω0=1\gamma_0 = \alpha_0 = \omega_0 = 1. Iterate:

γi=r⃗̂0⋅r⃗i−1\gamma_i = \hat{\vec r}_0 \cdot \vec r_{i-1}
βi=γiγi−1αi−1ωi−1\beta_i = \frac{\gamma_i}{\gamma_{i-1}} \frac{\alpha_{i-1}}{\omega_{i-1}}
p⃗i=r⃗i−1+βi(p⃗i−1−ωi−1Ap⃗i−1)\vec p_i = \vec r_{i-1} + \beta_i\left( \vec p_{i-1} - \omega_{i-1} A \vec p_{i-1} \right)
δi=r⃗̂0⋅Ap⃗i\delta_i = \hat{\vec r}_0 \cdot A \vec p_i
αi=γiδi\alpha_i = \frac{\gamma_i}{\delta_i}
r⃗⋆=r⃗i−1−αiAp⃗i\vec r_\star = \vec r_{i-1} - \alpha_i A \vec p_i
x⃗⋆=x⃗i−1+αip⃗i\vec x_\star = \vec x_{i-1} + \alpha_i \vec p_i
ωi=r⃗⋆⋅Ar⃗⋆(Ar⃗⋆)⋅(Ar⃗⋆)\omega_i = \frac{\vec r_\star \cdot A \vec r_\star}{(A \vec r_\star)\cdot(A \vec r_\star)}
r⃗i=r⃗⋆−ωiAr⃗⋆\vec r_i = \vec r_\star - \omega_i A \vec r_\star
x⃗i=x⃗⋆+ωir⃗⋆\vec x_i = \vec x_\star + \omega_i \vec r_\star

(new ⇒)

Improving BiCGSTAB/I

x⃗0\vec x_0 initial guess, r⃗0=b⃗−Ax⃗0\vec r_0 = \vec b - A\vec x_0 residual, r⃗̂0=r⃗0\hat{\vec r}_0 = \vec r_0, p⃗0=0⃗\vec p_0 = \vec 0, γ0=α0=ω0=1\gamma_0 = \alpha_0 = \omega_0 = 1. Iterate:

γi=r⃗̂0⋅r⃗i−1\gamma_i = \hat{\vec r}_0 \cdot \vec r_{i-1}
βi=γiγi−1αi−1ωi−1\beta_i = \frac{\gamma_i}{\gamma_{i-1}} \frac{\alpha_{i-1}}{\omega_{i-1}}
p⃗i=r⃗i−1+βi(p⃗i−1−ωi−1Ap⃗i−1)\vec p_i = \vec r_{i-1} + \beta_i\left( \vec p_{i-1} - \omega_{i-1} A \vec p_{i-1} \right) ⇐\Longleftarrow start from here
δi=r⃗̂0⋅Ap⃗i\delta_i = \hat{\vec r}_0 \cdot A \vec p_i
αi=γiδi\alpha_i = \frac{\gamma_i}{\delta_i}
r⃗⋆=r⃗i−1−αiAp⃗i\vec r_\star = \vec r_{i-1} - \alpha_i A \vec p_i
x⃗⋆=x⃗i−1+αip⃗i\vec x_\star = \vec x_{i-1} + \alpha_i \vec p_i
ωi=r⃗⋆⋅Ar⃗⋆(Ar⃗⋆)⋅(Ar⃗⋆)\omega_i = \frac{\vec r_\star \cdot A \vec r_\star}{(A \vec r_\star)\cdot(A \vec r_\star)}
r⃗i=r⃗⋆−ωiAr⃗⋆\vec r_i = \vec r_\star - \omega_i A \vec r_\star
x⃗i=x⃗⋆+ωir⃗⋆\vec x_i = \vec x_\star + \omega_i \vec r_\star

Improving BiCGSTAB/II

Expand and simplify! Consider: p⃗i=r⃗i−1+βi(p⃗i−1−ωi−1Ap⃗i−1)=r⃗i−1+βip⃗i−1−βiωi−1Ap⃗i−1\vec p_i = \vec r_{i-1} + \beta_i \left( \vec p_{i-1} - \omega_{i-1} A \vec p_{i-1} \right) = \vec r_{i-1} + \beta_i \vec p_{i-1} - \beta_i \omega_{i-1} A \vec p_{i-1} and βi=γiγi−1αi−1ωi−1=γiγi−1γi−1δi−1ωi−1=γiδi−1ωi−1=α′i−1ωi−1 \beta_i = \frac{\gamma_i}{\gamma_{i-1}} \frac{\alpha_{i-1}}{\omega_{i-1}} = \frac{\gamma_i}{\gamma_{i-1}} \frac{\gamma_{i-1}}{\delta_{i-1}\omega_{i-1}} = \frac{\gamma_i}{\delta_{i-1}\omega_{i-1}} = \frac{\alpha'_{i-1}}{\omega_{i-1}} where α′i−1=γiδi−1 \alpha'_{i-1} = \frac{\gamma_i}{\delta_{i-1}} so p⃗i=r⃗i−1+βip⃗i−1−α′i−1Ap⃗i−1\vec p_i = \vec r_{i-1} + \beta_i \vec p_{i-1} - \alpha'_{i-1} A \vec p_{i-1}

Modified BiCGSTAB

x⃗0,r⃗0=b⃗−A⃗x⃗0,r⃗̂0=r⃗0\vec x_0, \vec r_0 = \vec b - \vec A\vec x_0, \hat{\vec r}_0 = \vec r_0 as before, p⃗0\vec p_0 don’t care γ0=r⃗̂0⋅r⃗0,α′0=β0=0\gamma_0 = \hat{\vec r}_0 \cdot \vec r_0, \alpha'_0 = \beta_0 = 0. Iterate:

p⃗i=r⃗i−1+βi−1p⃗i−1−α′i−1Ap⃗i−1\vec p_i = \vec r_{i-1} + \beta_{i-1} \vec p_{i-1} - \alpha'_{i-1} A \vec p_{i-1}
δi=r⃗̂0⋅Ap⃗i\delta_i = \hat{\vec r}_0 \cdot A \vec p_i
αi=γiδi\alpha_i = \frac{\gamma_i}{\delta_i}
r⃗⋆=r⃗i−1−αiAp⃗i\vec r_\star = \vec r_{i-1} - \alpha_i A \vec p_i
x⃗⋆=x⃗i−1+αip⃗i\vec x_\star = \vec x_{i-1} + \alpha_i \vec p_i
ωi=r⃗⋆⋅Ar⃗⋆(Ar⃗⋆)⋅(Ar⃗⋆)\omega_i = \frac{\vec r_\star \cdot A \vec r_\star}{(A \vec r_\star)\cdot(A \vec r_\star)}
r⃗i=r⃗⋆−ωiAr⃗⋆\vec r_i = \vec r_\star - \omega_i A \vec r_\star
x⃗i=x⃗⋆+ωir⃗⋆\vec x_i = \vec x_\star + \omega_i \vec r_\star
γi+1=r⃗̂0⋅r⃗i\gamma_{i+1} = \hat{\vec r}_0 \cdot \vec r_i
α′i=γi+1δi\alpha'_i = \frac{\gamma_{i+1}}{\delta_i}
βi=α′iωi\beta_i = \frac{\alpha'_i}{\omega_i}

(⇐ old)

Results

Non-Newtonian Poiseuille

Poiseuille w/ Bingham rheology (Papanastasiou regularization),
semi-implicit predictor/corrector,
convergence/performance results

Performance

Δp\Delta p Δtc\Delta t_c Δtν\Delta t_\nu Explicit RT Implicit RT Speed-up
1/161/16 3.85⋅10−33.85\cdot10^{-3} 6.55⋅10−56.55\cdot10^{-5} 3.1⋅1023.1\cdot10^2 9.5⋅1019.5\cdot10^1 3.3×3.3\times
1/321/32 1.93⋅10−31.93\cdot10^{-3} 1.64⋅10−51.64\cdot10^{-5} 4.9⋅1034.9\cdot10^3 1.4⋅1031.4\cdot10^3 3.5×3.5\times
1/641/64 9.63⋅10−49.63\cdot10^{-4} 4.09⋅10−64.09\cdot10^{-6} 1.3⋅1051.3\cdot10^5 2.7⋅1042.7\cdot10^4 4.8×4.8\times

Longer per-step runtimes (14/21/32 solver iterations on avg),
semi-implicit still wins b.c. timesteps differ by orders of magnitude.

Multi-GPU scaling

Implementation is multi-GPU-capable (easier with reworked BiCGSTAB).
Good strong scaling (w/ enough particles), weak scaling could be improved
(need computation/data exchange overlap).

Thanks