Skip to content

fix: correct MTHINC normals on non-uniform grids#1401

Open
sbryngelson wants to merge 41 commits intoMFlowCode:masterfrom
sbryngelson:MTHINC
Open

fix: correct MTHINC normals on non-uniform grids#1401
sbryngelson wants to merge 41 commits intoMFlowCode:masterfrom
sbryngelson:MTHINC

Conversation

@sbryngelson
Copy link
Copy Markdown
Member

@sbryngelson sbryngelson commented May 5, 2026

Summary

Builds on #1303 (MTHINC implementation). Fixes two bugs found during review:

Fix 1: MTHINC normals on non-uniform grids (#1395)

The reference-space normal in s_compute_mthinc_normals used a uniform-grid assumption (* 0.5) that gives the wrong direction when cell widths vary. The correct weighting is:

n_ξ ∝ (∂α/∂x) · Δx_j  =  [α(j+1) - α(j-1)] · (x_cb(j) - x_cb(j-1)) / (x_cc(j+1) - x_cc(j-1))

On uniform grids this ratio equals 0.5 exactly, so all existing tests pass unchanged.

Fix 2: int_comp with viscous / surface-tension flows (#1396)

int_comp > 0 requires full (non-split) reconstruction, but the viscous and surface-tension RHS paths were calling split reconstruction, silently disabling interface compression. Fixed by routing those paths through the full reconstruction branch and adding a runtime @:PROHIBIT guard.

New regression test (7A1719C6)

A new golden-file test exercises Fix 1 on a non-uniform grid:

  • 2D domain with cosh-based x-stretching, creating non-uniform cell widths
  • Circular fluid-2 bubble creates a curved interface with diagonal normals (both nr_x ≠ 0 and nr_y ≠ 0) — only diagonal cells are sensitive to the Δx_j weighting correction; axis-aligned interfaces always normalize to ±1 regardless of scaling
  • Uniform vel(1)=0.5 advects the bubble so MTHINC reconstruction produces non-trivial fluxes; 129+ distinct values at t=50 confirm genuine interface evolution

Test plan

  • All 4 existing uniform-grid MTHINC tests pass unchanged (5126B21F, 4E4FECA9, 4F3722DB, 4C4F339C)
  • New non-uniform grid MTHINC test passes (7A1719C6)
  • ./mfc.sh precheck -j 8 passes
  • ./mfc.sh build -t simulation -j 8 compiles cleanly

sbryngelson and others added 30 commits March 26, 2026 18:50
- case.md: add muscl_eps row/description alongside int_comp (MTHINC version)
- m_global_parameters.fpp: keep int_comp as integer (0/1/2), add muscl_eps; keep GPU_DECLARE; both GPU_UPDATEs
- m_mpi_proxy.fpp: broadcast both int_comp and collision_model as integers
- case_validator.py: keep recon_type validation from master; drop stale int_comp=boolean check (superseded by check_interface_compression)
…rface_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.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

Claude Code Review

Head SHA: cbabce3

Files changed:

  • 16
  • src/simulation/m_thinc.fpp (new)
  • src/simulation/m_global_parameters.fpp
  • src/simulation/m_mpi_proxy.fpp
  • src/simulation/m_muscl.fpp
  • src/simulation/m_rhs.fpp
  • src/simulation/m_start_up.fpp
  • src/simulation/m_weno.fpp
  • src/common/m_constants.fpp
  • toolchain/mfc/case_validator.py
  • toolchain/mfc/params/definitions.py

Findings

1. model_eqns == 3 + int_comp > 0 not prohibited — THINC leaves per-fluid internal energies inconsistent

Files: toolchain/mfc/case_validator.py (check_interface_compression) and src/simulation/m_thinc.fpp (s_thinc_compression)

check_interface_compression validates int_comp but does not prohibit int_comp > 0 when model_eqns == 3 (the 6-equation model). For model_eqns == 3, the equation vector includes per-fluid internal energies at eqn_idx%int_en%beg : eqn_idx%int_en%end, which do not exist in model_eqns == 2.

s_thinc_compression only overwrites four index slots:

vL_rs_vf_${XYZ}$(j,k,l, eqn_idx%cont%beg) = rho_b*aTHINC     ! fluid 1 density
vL_rs_vf_${XYZ}$(j,k,l, eqn_idx%cont%end) = rho_e*(1-aTHINC)  ! fluid 2 density
vL_rs_vf_${XYZ}$(j,k,l, eqn_idx%adv%beg)  = aTHINC             ! alpha 1
vL_rs_vf_${XYZ}$(j,k,l, eqn_idx%adv%end)  = 1-aTHINC           ! alpha 2

It never touches eqn_idx%int_en%*. After THINC, the per-fluid internal energy face values remain at their WENO/MUSCL reconstructed values, which are no longer consistent with the sharpened densities and volume fractions. The Riemann solver then receives face states where alpha and density come from THINC but internal energies come from WENO/MUSCL, breaking the thermodynamic closure for model_eqns == 3.

Prior to this PR, WENO + int_comp was prohibited by the old recon_type != 2 check in check_muscl, so the gap was limited to MUSCL + model_eqns == 3. This PR removes that restriction and newly allows WENO + int_comp, making the inconsistent combination reachable for any recon_type.

Fix: Either add self.prohibit(int_comp != 0 and model_eqns == 3, "int_comp requires model_eqns = 2") in check_interface_compression, or extend s_thinc_compression to also overwrite the int_en face values proportionally.


2. WENO call now passes is1_weno instead of is1_weno_d — changed iteration bounds for WENO+int_comp

File: src/simulation/m_weno.fpp

The old WENO call passed is1_weno_d, is2_weno_d, is3_weno_d to s_interface_compression. The old subroutine (in m_muscl.fpp) silently ignored those arguments and used module-level is1_muscl%beg/end etc. in its loop body — WENO's int_comp path was executing with MUSCL's iteration bounds.

The new call correctly passes is1_weno, is2_weno, is3_weno and s_thinc_compression uses the passed is1_d, is2_d, is3_d. While this is the correct fix, it changes the stencil bounds used by WENO+int_comp compared to the old (buggy) behavior. Any WENO+int_comp golden files that existed under the old bounds will differ. The test reorganisation in cases.py adds fresh WENO+int_comp tests, so golden files are newly generated rather than compared against old ones — this should be fine, but the change in bounds should be verified to be physically appropriate for the WENO stencil width.

@sbryngelson sbryngelson marked this pull request as ready for review May 6, 2026 14:06
@qodo-code-review
Copy link
Copy Markdown
Contributor

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

A new THINC interface compression module (m_thinc.fpp) is introduced to implement volume-fraction sharpening using THINC (int_comp=1) and MTHINC (int_comp=2) algorithms. The int_comp parameter is converted from a logical type to an integer with three states: 0 (off), 1 (THINC), 2 (MTHINC). Integration occurs across multiple modules—m_muscl.fpp and m_weno.fpp now delegate compression to the new module, while m_global_parameters.fpp, m_rhs.fpp, and m_start_up.fpp are updated for lifecycle and configuration support. Documentation, example cases, and toolchain validation reflect the new integer parameter format.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing MTHINC normals on non-uniform grids, which aligns with the primary objective stated in the PR description.
Description check ✅ Passed The description includes a summary of changes, references to fixed issues (#1395, #1396), detailed technical explanations of both fixes, a description of the new regression test, and a comprehensive test plan with verification status.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
toolchain/mfc/lint_docs.py (1)

440-440: ⚡ Quick win

Avoid making check_interface_compression a permanent docs-coverage blind spot.

If this skip is temporary, please add a clear TODO/issue reference next to it so the PHYSICS_DOCS entry gets restored and coverage doesn’t silently regress.

As per coding guidelines, "Only comment on code that is within this PR’s diff (changed lines / files)."

toolchain/mfc/test/cases.py (2)

305-312: ⚡ Quick win

muscl_order=1 coverage disappeared from the generated matrix.

The muscl_order == 1 iteration now only pushes/pops the stack and never appends a case, so this helper stops exercising first-order MUSCL entirely. Please add a baseline define_case_d(...) before the muscl_order == 2 specialization, or drop 1 from the loop if that mode is intentionally unsupported.


419-420: ⚡ Quick win

The new int_comp coverage still misses the viscous/surface-tension path.

alter_int_comp(dimInfo) is only invoked before entering the two-fluid Viscous branch, so the generated suite never hits the full-reconstruction path this PR adds for viscous/surface-tension RHS handling. Adding at least one two-fluid viscous case with int_comp > 0 would keep #1396 covered.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1833b390-712d-4929-a69c-fc3c67b6ea8a

📥 Commits

Reviewing files that changed from the base of the PR and between d513442 and cbabce3.

📒 Files selected for processing (106)
  • docs/documentation/case.md
  • docs/module_categories.json
  • examples/1D_sodshocktube_muscl/case.py
  • examples/2D_advection_muscl/case.py
  • examples/2D_riemann_test_muscl/case.py
  • examples/2D_shockdroplet_muscl/case.py
  • examples/3D_rayleigh_taylor_muscl/case.py
  • examples/3D_shockdroplet_muscl/case.py
  • src/common/m_constants.fpp
  • src/simulation/m_global_parameters.fpp
  • src/simulation/m_mpi_proxy.fpp
  • src/simulation/m_muscl.fpp
  • src/simulation/m_rhs.fpp
  • src/simulation/m_start_up.fpp
  • src/simulation/m_thinc.fpp
  • src/simulation/m_weno.fpp
  • tests/0A362971/golden-metadata.txt
  • tests/0A362971/golden.txt
  • tests/238A7B1F/golden-metadata.txt
  • tests/238A7B1F/golden.txt
  • tests/35635326/golden-metadata.txt
  • tests/35635326/golden.txt
  • tests/3ECA875A/golden-metadata.txt
  • tests/3ECA875A/golden.txt
  • tests/4111B2ED/golden-metadata.txt
  • tests/4111B2ED/golden.txt
  • tests/4440D46B/golden.txt
  • tests/4C4F339C/golden-metadata.txt
  • tests/4C4F339C/golden.txt
  • tests/4E4FECA9/golden-metadata.txt
  • tests/4E4FECA9/golden.txt
  • tests/4F3722DB/golden-metadata.txt
  • tests/4F3722DB/golden.txt
  • tests/503EEFF7/golden-metadata.txt
  • tests/503EEFF7/golden.txt
  • tests/50EC2239/golden-metadata.txt
  • tests/50EC2239/golden.txt
  • tests/5126B21F/golden-metadata.txt
  • tests/5126B21F/golden.txt
  • tests/516A2067/golden-metadata.txt
  • tests/516A2067/golden.txt
  • tests/550E8BF5/golden-metadata.txt
  • tests/550E8BF5/golden.txt
  • tests/6077374F/golden.txt
  • tests/67C777D8/golden-metadata.txt
  • tests/67C777D8/golden.txt
  • tests/7A1719C6/golden-metadata.txt
  • tests/7A1719C6/golden.txt
  • tests/82DA2499/golden-metadata.txt
  • tests/82DA2499/golden.txt
  • tests/845DC70C/golden-metadata.txt
  • tests/845DC70C/golden.txt
  • tests/86E9A6D4/golden-metadata.txt
  • tests/86E9A6D4/golden.txt
  • tests/885D5D8C/golden-metadata.txt
  • tests/885D5D8C/golden.txt
  • tests/8876692F/golden-metadata.txt
  • tests/8876692F/golden.txt
  • tests/8C42A56C/golden-metadata.txt
  • tests/8C42A56C/golden.txt
  • tests/9EE432D4/golden-metadata.txt
  • tests/9EE432D4/golden.txt
  • tests/A089CE54/golden-metadata.txt
  • tests/A089CE54/golden.txt
  • tests/A930AE61/golden-metadata.txt
  • tests/A930AE61/golden.txt
  • tests/AD6ED274/golden-metadata.txt
  • tests/AD6ED274/golden.txt
  • tests/BAF51303/golden-metadata.txt
  • tests/BAF51303/golden.txt
  • tests/BDC2A773/golden-metadata.txt
  • tests/BDC2A773/golden.txt
  • tests/C02D71EE/golden-metadata.txt
  • tests/C02D71EE/golden.txt
  • tests/C4047138/golden-metadata.txt
  • tests/C605ECCC/golden-metadata.txt
  • tests/C7A6B609/golden.txt
  • tests/CE35B602/golden-metadata.txt
  • tests/CE35B602/golden.txt
  • tests/CF73B3B6/golden-metadata.txt
  • tests/CF73B3B6/golden.txt
  • tests/D49DCFC0/golden-metadata.txt
  • tests/D49DCFC0/golden.txt
  • tests/DC97B66D/golden-metadata.txt
  • tests/DC97B66D/golden.txt
  • tests/E11FD23A/golden-metadata.txt
  • tests/E11FD23A/golden.txt
  • tests/E3047A62/golden.txt
  • tests/E8979E4A/golden.txt
  • tests/EAD7CADE/golden-metadata.txt
  • tests/EBBC93BD/golden-metadata.txt
  • tests/EBBC93BD/golden.txt
  • tests/F1CF01C4/golden-metadata.txt
  • tests/F1CF01C4/golden.txt
  • tests/F44A293A/golden-metadata.txt
  • tests/F44A293A/golden.txt
  • tests/FA695993/golden-metadata.txt
  • tests/FA695993/golden.txt
  • tests/FE9379D8/golden-metadata.txt
  • tests/FE9379D8/golden.txt
  • toolchain/mfc/case_validator.py
  • toolchain/mfc/lint_docs.py
  • toolchain/mfc/params/definitions.py
  • toolchain/mfc/params/descriptions.py
  • toolchain/mfc/params/registry.py
  • toolchain/mfc/test/cases.py
💤 Files with no reviewable changes (25)
  • tests/86E9A6D4/golden-metadata.txt
  • tests/8876692F/golden-metadata.txt
  • tests/50EC2239/golden-metadata.txt
  • tests/D49DCFC0/golden-metadata.txt
  • tests/86E9A6D4/golden.txt
  • tests/BDC2A773/golden.txt
  • tests/238A7B1F/golden-metadata.txt
  • tests/FA695993/golden-metadata.txt
  • tests/67C777D8/golden-metadata.txt
  • tests/F44A293A/golden-metadata.txt
  • tests/550E8BF5/golden-metadata.txt
  • tests/82DA2499/golden-metadata.txt
  • tests/E3047A62/golden.txt
  • tests/C4047138/golden-metadata.txt
  • tests/C605ECCC/golden-metadata.txt
  • tests/0A362971/golden-metadata.txt
  • examples/2D_riemann_test_muscl/case.py
  • tests/BDC2A773/golden-metadata.txt
  • examples/1D_sodshocktube_muscl/case.py
  • tests/C02D71EE/golden-metadata.txt
  • tests/AD6ED274/golden-metadata.txt
  • tests/BAF51303/golden-metadata.txt
  • tests/EAD7CADE/golden-metadata.txt
  • tests/9EE432D4/golden-metadata.txt
  • tests/0A362971/golden.txt

Comment on lines +213 to +221
if (int_comp > 0 .and. v_size >= eqn_idx%adv%end) then
call nvtxStartRange("WENO-INTCOMP")
#:for MUSCL_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')]
if (muscl_dir == ${MUSCL_DIR}$) then
call s_thinc_compression(v_rs_ws_${XYZ}$_muscl, vL_rs_vf_x, vL_rs_vf_y, vL_rs_vf_z, vR_rs_vf_x, vR_rs_vf_y, &
& vR_rs_vf_z, muscl_dir, is1_muscl, is2_muscl, is3_muscl)
end if
#:endfor
call nvtxEndRange()
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 | 🟠 Major | ⚡ Quick win

int_comp can consume an uninitialized MUSCL workspace in first-order mode.

When muscl_order == 1, s_initialize_muscl() is skipped above, so v_rs_ws_*_muscl has not been populated before this block passes it to s_thinc_compression(). That makes int_comp > 0 + first-order MUSCL undefined unless the combination is prohibited elsewhere. Either initialize the directional workspace for compressed runs too, or explicitly reject muscl_order == 1 when int_comp > 0.

Possible fix
-        if (muscl_order /= 1 .or. dummy) then
+        if (muscl_order /= 1 .or. dummy .or. int_comp > 0) then
             call s_initialize_muscl(v_vf, muscl_dir)
         end if

Comment on lines +41 to +50
!> @brief Stable difference: log_cosh(a+h) - log_cosh(a-h) = 2*atanh(tanh(a)*tanh(h)). Avoids catastrophic cancellation when h
!! is small relative to a.
function f_log_cosh_diff(a, h) result(res)

$:GPU_ROUTINE(parallelism='[seq]')
real(wp), intent(in) :: a, h
real(wp) :: res

res = 2._wp*atanh(tanh(a)*tanh(h))

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 | 🟠 Major | ⚡ Quick win

Clamp the atanh argument before calling it.

For large a or h, tanh(a) and tanh(h) can round to ±1, so the product can hit ±1 exactly and atanh returns infinities even though the original log_cosh(a+h) - log_cosh(a-h) is still finite. That will leak Inf/NaN into the THINC integrals on sharp interfaces.

Suggested fix
     function f_log_cosh_diff(a, h) result(res)
 
         $:GPU_ROUTINE(parallelism='[seq]')
         real(wp), intent(in) :: a, h
-        real(wp)             :: res
+        real(wp)             :: res, t
 
-        res = 2._wp*atanh(tanh(a)*tanh(h))
+        t = tanh(a)*tanh(h)
+        t = max(-1._wp + epsilon(1._wp), min(1._wp - epsilon(1._wp), t))
+        res = 2._wp*atanh(t)
 
     end function f_log_cosh_diff

Comment thread src/simulation/m_weno.fpp
Comment on lines +1386 to +1394
if (int_comp > 0 .and. v_size >= eqn_idx%adv%end) then
call nvtxStartRange("WENO-INTCOMP")
#:for WENO_DIR, XYZ in [(1, 'x'), (2, 'y'), (3, 'z')]
if (weno_dir == ${WENO_DIR}$) then
call s_thinc_compression(v_rs_ws_${XYZ}$, vL_rs_vf_x, vL_rs_vf_y, vL_rs_vf_z, vR_rs_vf_x, vR_rs_vf_y, &
& vR_rs_vf_z, weno_dir, is1_weno, is2_weno, is3_weno)
end if
#:endfor
call nvtxEndRange()
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 | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e

echo "Calls and imports in src/simulation/m_weno.fpp:"
rg -n 'use m_nvtx|nvtxStartRange|nvtxEndRange' src/simulation/m_weno.fpp

echo
echo "NVTX procedure definitions in the codebase:"
fd -i 'm_nvtx.fpp' src | xargs -r rg -n 'subroutine[[:space:]]+nvtx(StartRange|EndRange)'

Repository: MFlowCode/MFC

Length of output: 240


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Looking for m_nvtx file ==="
fd -i 'm_nvtx' src/

echo
echo "=== Checking m_rhs.fpp for NVTX usage (as mentioned in review) ==="
rg -n 'use m_nvtx|nvtxStartRange|nvtxEndRange' src/simulation/m_rhs.fpp 2>/dev/null | head -20

echo
echo "=== Checking all files that call nvtxStartRange/nvtxEndRange ==="
rg -l 'nvtxStartRange|nvtxEndRange' src/

echo
echo "=== Check imports in files using NVTX ==="
for file in $(rg -l 'nvtxStartRange|nvtxEndRange' src/); do
    echo "--- File: $file ---"
    rg -n 'use m_|nvtxStartRange|nvtxEndRange' "$file" | head -30
done

Repository: MFlowCode/MFC

Length of output: 7302


Import m_nvtx before using the new range markers.

The NVTX instrumentation calls at lines 1387 and 1394 require the m_nvtx module, which is not imported in m_weno.fpp. This will cause a compile error. All other files that use nvtxStartRange and nvtxEndRange (e.g., m_rhs.fpp, m_time_steppers.fpp) explicitly include use m_nvtx.

Suggested fix
     use m_variables_conversion
     ! $:USE_GPU_MODULE()
 
     use m_mpi_proxy
+    use m_nvtx
     use m_thinc, only: s_thinc_compression

Comment thread tests/A089CE54/golden-metadata.txt
Comment thread tests/DC97B66D/golden-metadata.txt
@sbryngelson
Copy link
Copy Markdown
Member Author

Automated Code Review

Summary: 1 critical issue, 2 important issues.

Critical Issue

1. Missing use m_nvtx in m_muscl.fpp — compile error on all 4 CI compilers (confidence: 97%)

src/simulation/m_muscl.fpp calls nvtxStartRange("WENO-INTCOMP") and nvtxEndRange() without use m_nvtx in its module-level use list. None of the modules it does use (m_derived_types, m_global_parameters, m_variables_conversion, m_mpi_proxy, m_helper, m_thinc) re-export m_nvtx. Every other NVTX caller in the simulation source explicitly adds use m_nvtx. This will produce an "undefined symbol" compile error.

Fix: Add use m_nvtx to the module-level use block in src/simulation/m_muscl.fpp.

Minor: the NVTX label "WENO-INTCOMP" should be "MUSCL-INTCOMP" — this is the MUSCL module, not WENO.


Important Issues

2. f_log_cosh_diff can produce +Inf for large ic_beta (confidence: 82%)

src/simulation/m_thinc.fpp:

res = 2._wp*atanh(tanh(a)*tanh(h))

tanh(x) = 1.0_wp exactly for |x| >= ~19.1 in IEEE 754 double. When beta * |n1| >= 38.2 (e.g., ic_beta = 40), atanh(±1.0) returns ±Inf, leaking into the Newton solver and solution fields. The default ic_beta = 1.6 is safe, but no upper-bound validation exists in case_validator.py or m_checker.fpp.

Fix (option A): Clamp the atanh argument:

t = tanh(a)*tanh(h)
res = 2._wp*atanh(sign(min(abs(t), 1._wp - epsilon(1._wp)), t))

Fix (option B): Add @:PROHIBIT(ic_beta > 30._wp, ...) in m_checker.fpp and case_validator.py.

3. No Fortran-side @:PROHIBIT for muscl_order==1 + int_comp>0 (confidence: 80%)

case_validator.py correctly blocks this combination, but m_checker.fpp has no matching runtime guard. A user who writes a .inp namelist directly (bypassing Python validation) hits undefined behavior: v_rs_ws_*_muscl contains stale/uninitialized data when muscl_order==1 skips s_initialize_muscl, but s_thinc_compression still runs.

Fix: Add to m_checker.fpp:

@:PROHIBIT(recon_type == MUSCL_TYPE .and. muscl_order == 1 .and. int_comp /= 0, &
           & "int_comp must be 0 when muscl_order = 1")

Suggestions

  • No upper-bound validation for ic_epsic_eps >= 0.5 would disable compression entirely for all physical volume fractions; a simple prohibit(ic_eps >= 0.5, ...) guard would prevent silent misconfiguration
  • Newton solver in f_mthinc_solve_d iterates up to 30 steps with no convergence diagnostic — a @:LOG on the residual after the loop would aid debugging near-degenerate cases

Strengths

  • Non-uniform grid normal formula nr_x = (α(j+1) - α(j-1)) * Δx_j / (x_cc(j+1) - x_cc(j-1)) correctly reduces to 0.5*(α(j+1) - α(j-1)) on uniform grids — all existing tests pass unchanged ✓
  • @:ALLOCATE/@:DEALLOCATE pairing for mthinc_nhat and mthinc_d correct, both gated on int_comp == 2
  • case_validator.py correctly enforces all interdependencies: int_comp > 0 => num_fluids == 2, int_comp == 2 => n > 0, int_comp > 0 => muscl/weno_order > 1
  • GPU_DECLARE(copyin=...) for gq3_pts/gq3_wts is the correct pattern for constant quadrature weights
  • Normal snapping with mthinc_align_tol avoids near-degenerate multi-dimensional quadrature

…ker for muscl_order==1+int_comp

- m_muscl.fpp: add missing 'use m_nvtx' (compile error without it)
- m_thinc.fpp: clamp tanh(a)*tanh(h) to (-1+eps, 1-eps) before atanh to
  prevent Inf/NaN on sharp interfaces (large ic_beta values)
- m_checker.fpp: add runtime PROHIBIT for muscl_order==1 with int_comp>0
  (uninitialized reconstruction workspace)
@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 83.80952% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.88%. Comparing base (36fc04c) to head (3ebb1e3).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/simulation/m_thinc.fpp 85.14% 8 Missing and 18 partials ⚠️
src/simulation/m_muscl.fpp 66.66% 0 Missing and 2 partials ⚠️
src/simulation/m_weno.fpp 80.00% 0 Missing and 2 partials ⚠️
src/simulation/m_checker.fpp 0.00% 1 Missing ⚠️
src/simulation/m_global_parameters.fpp 50.00% 0 Missing and 1 partial ⚠️
src/simulation/m_rhs.fpp 92.85% 0 Missing and 1 partial ⚠️
src/simulation/m_start_up.fpp 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1401      +/-   ##
==========================================
+ Coverage   64.75%   64.88%   +0.12%     
==========================================
  Files          71       72       +1     
  Lines       18721    18883     +162     
  Branches     1551     1571      +20     
==========================================
+ Hits        12123    12252     +129     
- Misses       5640     5655      +15     
- Partials      958      976      +18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants