Skip to content

Commit 5d4d53d

Browse files
committed
fix: stable log_cosh difference and prohibit int_comp with viscous/surface_tension
f_thinc_integral_1d used log_cosh(a+h) - log_cosh(a-h) which suffers catastrophic cancellation in single precision when h (= beta*n_transverse/2) is small (interface nearly axis-aligned). Replace with the identity 2*atanh(tanh(a)*tanh(h)), which is algebraically equivalent and numerically stable at all precisions. Fixes the single-precision CI failure on the 2D and 3D MTHINC WENO tests (5126B21F, 4F3722DB). Also add validator rules prohibiting int_comp > 0 with viscous=T or surface_tension=T: the split reconstruction paths in m_rhs prevent s_thinc_compression from ever running in those cases, so permitting the combination would silently produce unsharpened results.
1 parent 78062e3 commit 5d4d53d

2 files changed

Lines changed: 17 additions & 1 deletion

File tree

src/simulation/m_thinc.fpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ contains
5656

5757
end function f_log_cosh
5858

59+
!> @brief Stable difference: log_cosh(a+h) - log_cosh(a-h) = 2*atanh(tanh(a)*tanh(h)). Avoids catastrophic cancellation when h
60+
!! is small relative to a.
61+
function f_log_cosh_diff(a, h) result(res)
62+
63+
$:GPU_ROUTINE(parallelism='[seq]')
64+
real(wp), intent(in) :: a, h
65+
real(wp) :: res
66+
67+
res = 2._wp*atanh(tanh(a)*tanh(h))
68+
69+
end function f_log_cosh_diff
70+
5971
!> @brief Analytical 1-D integral of the THINC function
6072
function f_thinc_integral_1d(a, b) result(res)
6173

@@ -66,7 +78,7 @@ contains
6678
if (abs(b) < verysmall) then
6779
res = 5e-1_wp*(1._wp + tanh(a))
6880
else
69-
res = 5e-1_wp + (f_log_cosh(a + 5e-1_wp*b) - f_log_cosh(a - 5e-1_wp*b))/(2._wp*b)
81+
res = 5e-1_wp + f_log_cosh_diff(a, 5e-1_wp*b)/(2._wp*b)
7082
end if
7183

7284
end function f_thinc_integral_1d

toolchain/mfc/case_validator.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,10 @@ def check_interface_compression(self):
391391
self.prohibit(int_comp not in [0, 1, 2], "int_comp must be 0 (off), 1 (THINC), or 2 (MTHINC)")
392392
self.prohibit(int_comp == 2 and n == 0, "int_comp = 2 (MTHINC) requires at least 2D (n > 0)")
393393
self.prohibit(int_comp != 0 and num_fluids != 2, "int_comp > 0 requires num_fluids = 2")
394+
viscous = self.get("viscous", "F") == "T"
395+
surface_tension = self.get("surface_tension", "F") == "T"
396+
self.prohibit(int_comp != 0 and viscous, "int_comp > 0 is not supported with viscosity (reconstruction is split; compression would be silently skipped)")
397+
self.prohibit(int_comp != 0 and surface_tension, "int_comp > 0 is not supported with surface tension (reconstruction is split; compression would be silently skipped)")
394398

395399
recon_type = self.get("recon_type", 1)
396400
if recon_type == 1: # WENO

0 commit comments

Comments
 (0)