Skip to content

MTHINC Interface Compression#1303

Draft
wilfonba wants to merge 4 commits intoMFlowCode:masterfrom
wilfonba:MTHINC
Draft

MTHINC Interface Compression#1303
wilfonba wants to merge 4 commits intoMFlowCode:masterfrom
wilfonba:MTHINC

Conversation

@wilfonba
Copy link
Contributor

@wilfonba wilfonba commented Mar 12, 2026

Description

This PR adds MTHINC interface coompression to the code base and fixes the THINC bug in #1181. The existing golden files for THINC interface compression were preserved, and new golden files and tests were created for MTHINC.

Type of change

  • New feature

Testing

I ran a 3D advection case with and without MTHINC. The Video below shows the result.

test.mp4

I also ran this 3D case with 1 rank and 8 ranks and the results were identical to machine precision.

I also ran performance tests. The overhead for MTHINC is ~3% while the overhead for THINC is ~1%. The grind times are:

  • int_comp = 0: 0.87496. (No compression, baseline)
  • int_comp = 1: 0.88536 (1%) (THINC compression)
  • int_comp = 2: 0.90575 (3%) (MTHINC compression)

The following table shows the NVTX ranges, with the relevant lines bolded.
Time (%) Total Time (ns) Instances Avg (ns) Med (ns) Min (ns) Max (ns) StdDev (ns) Style Range


 24.9   13,635,671,627          1  13,635,671,627.0  13,635,671,627.0  13,635,671,627  13,635,671,627          0.0  PushPop  :SIMULATION-TIME-MARCH         
 21.9   12,028,368,575         50     240,567,371.5     239,558,938.5     239,102,813     277,030,239  5,362,040.8  PushPop  :TIMESTEP                      
 20.0   10,943,871,787        150      72,959,145.2      72,615,230.0      71,982,358     103,857,165  2,655,760.9  PushPop  :COMPUTE-RHS                   
  9.8    5,380,339,845        450      11,956,310.8      11,430,372.0      11,257,113      42,327,380  1,616,888.0  PushPop  :RHS-RECONSTRUCTION            
  6.4    3,512,704,372        450       7,806,009.7       7,688,008.5       6,772,932      10,757,677    871,999.9  PushPop  :RHS-RIEMANN-SOLVER            
  5.3    2,918,277,977          1   2,918,277,977.0   2,918,277,977.0   2,918,277,977   2,918,277,977          0.0  PushPop  :INIT                          
  3.9    2,125,470,880          1   2,125,470,880.0   2,125,470,880.0   2,125,470,880   2,125,470,880          0.0  PushPop  :INIT-MODULES                  
  2.9    1,604,204,876          1   1,604,204,876.0   1,604,204,876.0   1,604,204,876   1,604,204,876          0.0  PushPop  :SAVE-DATA                     
  2.0    1,119,965,978        450       2,488,813.3       2,492,816.0       2,396,918       2,620,908     65,047.0  PushPop  :RHS-ADVECTION-SRC             
  1.3      716,022,954          1     716,022,954.0     716,022,954.0     716,022,954     716,022,954          0.0  PushPop  :INIT-MPI                      
  **0.4      226,183,678        150       1,507,891.2       1,514,955.0         932,339       1,688,933     75,128.7  PushPop  :RHS-COMPRESSION-NORMALS**       
  0.3      188,718,163        150       1,258,121.1       1,251,360.0       1,247,450       2,093,079     68,748.1  PushPop  :RHS-CONVERT                   
  **0.3      146,755,381        450         326,123.1         316,463.0         259,085       1,364,532     58,618.9  PushPop  :RHS-RECONSTRUCTION-COMPRESSION**
  0.3      139,030,888          1     139,030,888.0     139,030,888.0     139,030,888     139,030,888          0.0  PushPop  :FINALIZE-MODULES              
  0.1       76,748,956          1      76,748,956.0      76,748,956.0      76,748,956      76,748,956          0.0  PushPop  :INIT-GPU-VARS                 
  0.1       52,380,023        150         349,200.2         340,387.5         326,512       1,383,705     85,705.9  PushPop  :RHS-COMMUNICATION             
  0.0          162,801        450             361.8             298.5             148           4,177        358.1  PushPop  :RHS-HYPOELASTICITY            
  0.0           57,545        150             383.6             318.5             173           3,554        351.9  PushPop  :RHS-ELASTIC 

Checklist

  • I added or updated tests for new behavior
  • I updated documentation if user-facing behavior changed

See the developer guide for full coding standards.

GPU changes (expand if you modified src/simulation/)
  • GPU results match CPU results
  • Tested on NVIDIA GPU or AMD GPU

AI code reviews

Reviews are not triggered automatically. To request a review, comment on the PR:

  • @coderabbitai review — incremental review (new changes only)
  • @coderabbitai full review — full review from scratch
  • /review — Qodo review
  • /improve — Qodo code suggestions

@github-actions
Copy link

Claude Code Review

Head SHA: 202d7da
Files changed: 81 (key source files: m_thinc.fpp [new, +499], m_muscl.fpp [-86], m_rhs.fpp [+22], m_weno.fpp [-8], m_global_parameters.fpp, m_mpi_proxy.fpp, m_start_up.fpp, toolchain/mfc/params/definitions.py, toolchain/mfc/case_validator.py, toolchain/mfc/test/cases.py)


Summary

  • Adds a new m_thinc.fpp module implementing both THINC (1D hyperbolic tangent, existing) and MTHINC (multi-dimensional, new), consolidating what was previously split between m_muscl.fpp and m_weno.fpp
  • Promotes int_comp from logical to integer (0=off, 1=THINC, 2=MTHINC) — a breaking type change for existing users
  • Fixes a pre-existing THINC bug (Fix MUSCL THINC right-state using already-overwritten left-state values #1181) where the right-reconstruction density ratios used already-overwritten left-reconstruction values; new code pre-saves rho_b/rho_e before any write
  • Moves compression call from s_weno/s_muscl to the shared s_reconstruct_cell_boundary_values in m_rhs.fpp, enabling THINC/MTHINC with any reconstruction type
  • MTHINC normals are pre-computed once per timestep in s_compute_mthinc_normals before the dimensional splitting loop — correct design

Findings

[HIGH] Missing Fortran-side runtime validation for int_comp
m_checker.fpp / m_checker_common.fpp have no @:PROHIBIT guard for invalid int_comp values or for int_comp=2 with 1D (n=0). Per project convention (CLAUDE.md, parameter-system.md), Fortran-side checks belong in m_checker*.fpp. A user passing int_comp=3 would fail only at Python validation, not at simulation startup. Suggested:

@:PROHIBIT(int_comp < 0 .or. int_comp > 2, "int_comp must be 0, 1, or 2")

[HIGH] int_comp=2 silently degrades to 1D THINC for 1D cases
m_rhs.fpp line 286 and m_thinc.fpp ~line 741 both gate MTHINC on n > 0, so a user who sets int_comp=2 on a 1D case gets quiet THINC behaviour with no warning. This should either be prohibited or documented. Currently neither the validator nor the checker warns.

[MEDIUM] Backward compatibility break: int_comp type change (logical → integer)
toolchain/mfc/params/definitions.py moves int_comp from the LOG group to INT. Existing case files with 'int_comp': True or 'int_comp': False will fail schema validation (fastjsonschema rejects bool for integer fields). A migration note or compatibility shim would help existing users.

[MEDIUM] Removed constraint on int_comp requiring MUSCL
case_validator.py deletes the check that int_comp and recon_type != 2. THINC with WENO is now actively tested and apparently intentional. However, no constraint guards against int_comp > 0 with recon_type=3 (first-order/piecewise-constant). Applying THINC sharpening on top of a piecewise-constant reconstruction seems physically questionable — worth a comment or prohibition.

[MEDIUM] f_mthinc_solve_d Newton iteration unbounded in d
m_thinc.fpp lines 532-541: d is unconstrained during iteration. For degenerate normals or extreme alpha_cell values, d can drift to large magnitudes, causing tanh(beta*(n*xi + d)) -> +/-1 and dV -> 0. The guard if (abs(dV) < 1e-14_wp) exit catches this, but the stored d is unvalidated. Consider clamping d to [-d_max, d_max] for some d_max (e.g., 10/beta).

[LOW] Hardcoded 1e-14_wp convergence thresholds in f_mthinc_solve_d (lines 536, 538) should use a named constant or verysmall consistent with MFC convention.

[LOW] Redundant precision cast m_thinc.fpp line 670: real(ac, wp)ac is already real(wp).

[LOW] MTHINC not actually exercised in some new tests
cases.py line 188: for int_comp in [0, 1, 2] with muscl_order=1. If the base case for alter_muscl is 1D, then int_comp=2 silently runs as 1D THINC (per HIGH finding above), meaning the MTHINC code path is not exercised in those tests.

@wilfonba wilfonba marked this pull request as ready for review March 12, 2026 15:52
@wilfonba wilfonba requested a review from sbryngelson as a code owner March 12, 2026 15:52
Copilot AI review requested due to automatic review settings March 12, 2026 15:52
@qodo-code-review
Copy link
Contributor

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Add MTHINC interface compression and refactor THINC functionality

✨ Enhancement 🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Implements MTHINC (multi-dimensional THINC) interface compression for volume fraction sharpening
  alongside existing THINC support
• Introduces new m_thinc module with helper functions for stable logarithmic-cosine computation,
  1D THINC integrals, and multi-dimensional volume integrals using Gaussian quadrature
• Converts int_comp parameter from logical to integer type with three states: 0=off, 1=THINC,
  2=MTHINC
• Integrates THINC/MTHINC compression into RHS computation with Newton iteration for interface
  position parameter solving
• Refactors interface compression functionality out of MUSCL module into dedicated m_thinc module
• Updates MPI communication to handle new integer parameter type
• Adds comprehensive test cases for MTHINC in 2D/3D configurations with WENO reconstruction
• Updates all example cases and parameter definitions to use new integer enum values
• Includes performance validation showing ~3% overhead for MTHINC vs ~1% for THINC
• Updates documentation and validation logic for the new parameter type and options
Diagram
flowchart LR
  A["int_comp: logical<br/>to integer"] --> B["m_thinc module<br/>THINC + MTHINC"]
  B --> C["RHS computation<br/>with compression"]
  B --> D["Startup initialization<br/>and finalization"]
  C --> E["Test cases<br/>2D/3D MTHINC"]
  A --> F["MPI broadcast<br/>parameter update"]
  A --> G["Parameter validation<br/>0/1/2 values"]
Loading

Grey Divider

File Changes

1. src/simulation/m_thinc.fpp ✨ Enhancement +499/-0

New THINC and MTHINC interface compression module

• New module implementing THINC (1D) and MTHINC (multi-dimensional) interface compression for volume
 fraction sharpening
• Contains helper functions for stable logarithmic-cosine computation, 1D THINC integrals, and
 multi-dimensional volume integrals with Gaussian quadrature
• Implements Newton iteration to solve for interface position parameter d that preserves
 cell-averaged volume fractions
• Provides subroutines to initialize/finalize MTHINC data structures, compute unit normals and
 interface positions, and apply compression to reconstructed variables

src/simulation/m_thinc.fpp


2. src/simulation/m_muscl.fpp Refactoring +1/-86

Remove interface compression from MUSCL module

• Removed s_interface_compression from public interface exports
• Interface compression functionality moved to dedicated m_thinc module

src/simulation/m_muscl.fpp


3. src/simulation/m_rhs.fpp ✨ Enhancement +22/-1

Integrate THINC/MTHINC compression into RHS computation

• Added import of m_thinc module
• Added call to s_compute_mthinc_normals before dimensional splitting loop when int_comp == 2
• Integrated s_thinc_compression call after variable reconstruction with NVTX profiling markers
• Renamed NVTX range from "RHS-WENO" to "RHS-RECONSTRUCTION" for clarity

src/simulation/m_rhs.fpp


View more (78)
4. src/simulation/m_mpi_proxy.fpp 🐞 Bug fix +2/-2

Update MPI broadcast for int_comp parameter type change

• Added int_comp to integer broadcast list for MPI communication
• Removed int_comp from logical broadcast list (changed from boolean to integer type)

src/simulation/m_mpi_proxy.fpp


5. src/simulation/m_global_parameters.fpp ✨ Enhancement +3/-3

Change interface compression parameter to integer enum

• Changed int_comp from logical to integer type with values: 0=off, 1=THINC, 2=MTHINC
• Updated default value from .false. to 0
• Updated documentation comments for ic_beta to reference both THINC and MTHINC

src/simulation/m_global_parameters.fpp


6. src/simulation/m_start_up.fpp ✨ Enhancement +3/-0

Initialize and finalize THINC module in startup

• Added import of m_thinc module
• Added initialization call s_initialize_thinc_module() when int_comp > 0
• Added finalization call s_finalize_thinc_module() when int_comp > 0

src/simulation/m_start_up.fpp


7. toolchain/mfc/test/cases.py 🧪 Tests +8/-2

Add MTHINC test cases and update parameter values

• Added MTHINC testing for WENO cases with weno_order = 5 in 2D/3D configurations
• Updated MUSCL test cases to use integer values [0, 1, 2] for int_comp instead of boolean strings

toolchain/mfc/test/cases.py


8. examples/1D_sodshocktube_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/1D_sodshocktube_muscl/case.py


9. examples/2D_riemann_test_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/2D_riemann_test_muscl/case.py


10. examples/2D_advection_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/2D_advection_muscl/case.py


11. examples/2D_shockdroplet_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/2D_shockdroplet_muscl/case.py


12. examples/3D_shockdroplet_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/3D_shockdroplet_muscl/case.py


13. examples/3D_rayleigh_taylor_muscl/case.py ⚙️ Configuration changes +1/-1

Update example case parameter to integer

• Updated int_comp parameter from string "T" to integer 1 (THINC)

examples/3D_rayleigh_taylor_muscl/case.py


14. toolchain/mfc/params/definitions.py ⚙️ Configuration changes +2/-1

Update parameter type definition for int_comp

• Moved int_comp from logical parameter list to integer parameter list
• Changed parameter type from LOG to INT

toolchain/mfc/params/definitions.py


15. toolchain/mfc/case_validator.py 🐞 Bug fix +3/-3

Update validation for integer int_comp parameter

• Updated validation logic to check int_comp as integer with valid values [0, 1, 2]
• Changed constraint message to clarify MTHINC option and removed requirement for MUSCL-only usage

toolchain/mfc/case_validator.py


16. toolchain/mfc/params/descriptions.py 📝 Documentation +1/-1

Update parameter description for int_comp

• Updated parameter description to reflect integer type with options: 0=off, 1=THINC, 2=MTHINC

toolchain/mfc/params/descriptions.py


17. tests/6102D509/golden-metadata.txt Miscellaneous +38/-67

Update golden test metadata

• Updated test metadata with new Git commit hash and branch name
• Updated CMake and compiler versions in configuration records

tests/6102D509/golden-metadata.txt


18. tests/6775D763/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/6775D763/golden-metadata.txt


19. tests/A438B8CE/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/A438B8CE/golden-metadata.txt


20. tests/AEE7A791/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/AEE7A791/golden-metadata.txt


21. tests/CE35B602/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/CE35B602/golden-metadata.txt


22. tests/F5FABAE9/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/F5FABAE9/golden-metadata.txt


23. tests/A930AE61/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/A930AE61/golden-metadata.txt


24. tests/C420EDF3/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MTHINC test case

tests/C420EDF3/golden-metadata.txt


25. tests/885D5D8C/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MUSCL interface compression test case

tests/885D5D8C/golden-metadata.txt


26. tests/8C42A56C/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MUSCL interface compression test case

tests/8C42A56C/golden-metadata.txt


27. tests/FE9379D8/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MUSCL interface compression test case

tests/FE9379D8/golden-metadata.txt


28. tests/E11FD23A/golden-metadata.txt 🧪 Tests +154/-0

Add new golden test metadata

• New golden test metadata file for MUSCL interface compression test case

tests/E11FD23A/golden-metadata.txt


29. docs/documentation/case.md 📝 Documentation +2/-2

Update documentation for int_comp parameter

• Updated int_comp parameter documentation from logical to integer type
• Added clarification that values [1] THINC and [2] MTHINC are supported
• Updated description to indicate interface compression works with variable reconstruction

docs/documentation/case.md


30. docs/module_categories.json 📝 Documentation +2/-1

Add THINC module to documentation categories

• Added m_thinc module to the reconstruction module category

docs/module_categories.json


31. tests/A438B8CE/golden.txt 🧪 Tests +16/-0

New MTHINC golden test data file

• Added new golden file with 16 lines of test data for MTHINC interface compression
• Contains conservative and primitive variable outputs (cons and prim) across 4 variables
• Includes initial state (timestep 000000) and evolved state (timestep 000050) for validation
• Data represents a 3D advection test case with multiple spatial regions and varying values

tests/A438B8CE/golden.txt


32. tests/F5FABAE9/golden.txt 🧪 Tests +16/-0

New MTHINC golden file test data

• Added new golden file with 16 lines of test data for MTHINC interface compression
• Contains initial and evolved state data for 5 conserved/primitive variables across 320 grid points
• Includes two timesteps (000000 and 000050) showing solution evolution
• Data demonstrates compression results with values ranging from near-zero to 2.5

tests/F5FABAE9/golden.txt


33. src/simulation/m_weno.fpp Additional files +0/-8

...

src/simulation/m_weno.fpp


34. tests/09195EF4/golden-metadata.txt Additional files +0/-0

...

tests/09195EF4/golden-metadata.txt


35. tests/09195EF4/golden.txt Additional files +0/-0

...

tests/09195EF4/golden.txt


36. tests/0A362971/golden-metadata.txt Additional files +0/-160

...

tests/0A362971/golden-metadata.txt


37. tests/0A362971/golden.txt Additional files +0/-10

...

tests/0A362971/golden.txt


38. tests/11D609F6/golden-metadata.txt Additional files +0/-0

...

tests/11D609F6/golden-metadata.txt


39. tests/11D609F6/golden.txt Additional files +0/-0

...

tests/11D609F6/golden.txt


40. tests/1B300F28/golden-metadata.txt Additional files +0/-189

...

tests/1B300F28/golden-metadata.txt


41. tests/1F0C4A44/golden-metadata.txt Additional files +0/-0

...

tests/1F0C4A44/golden-metadata.txt


42. tests/1F0C4A44/golden.txt Additional files +0/-0

...

tests/1F0C4A44/golden.txt


43. tests/2C9844EF/golden-metadata.txt Additional files +0/-156

...

tests/2C9844EF/golden-metadata.txt


44. tests/2C9844EF/golden.txt Additional files +0/-24

...

tests/2C9844EF/golden.txt


45. tests/2D11A034/golden-metadata.txt Additional files +0/-0

...

tests/2D11A034/golden-metadata.txt


46. tests/2D11A034/golden.txt Additional files +0/-0

...

tests/2D11A034/golden.txt


47. tests/2E4AC44C/golden-metadata.txt Additional files +0/-0

...

tests/2E4AC44C/golden-metadata.txt


48. tests/2E4AC44C/golden.txt Additional files +0/-0

...

tests/2E4AC44C/golden.txt


49. tests/3ECA875A/golden-metadata.txt Additional files +0/-0

...

tests/3ECA875A/golden-metadata.txt


50. tests/3ECA875A/golden.txt Additional files +0/-0

...

tests/3ECA875A/golden.txt


51. tests/409B55DF/golden-metadata.txt Additional files +0/-0

...

tests/409B55DF/golden-metadata.txt


52. tests/409B55DF/golden.txt Additional files +0/-0

...

tests/409B55DF/golden.txt


53. tests/503EEFF7/golden-metadata.txt Additional files +0/-0

...

tests/503EEFF7/golden-metadata.txt


54. tests/503EEFF7/golden.txt Additional files +0/-0

...

tests/503EEFF7/golden.txt


55. tests/50EC2239/golden-metadata.txt Additional files +0/-176

...

tests/50EC2239/golden-metadata.txt


56. tests/50EC2239/golden.txt Additional files +0/-18

...

tests/50EC2239/golden.txt


57. tests/6102D509/golden.txt Additional files +10/-0

...

tests/6102D509/golden.txt


58. tests/6775D763/golden.txt Additional files +12/-0

...

tests/6775D763/golden.txt


59. tests/67C777D8/golden.txt Additional files +0/-506

...

tests/67C777D8/golden.txt


60. tests/7156050E/golden-metadata.txt Additional files +0/-0

...

tests/7156050E/golden-metadata.txt


61. tests/7156050E/golden.txt Additional files +0/-0

...

tests/7156050E/golden.txt


62. tests/845DC70C/golden-metadata.txt Additional files +0/-0

...

tests/845DC70C/golden-metadata.txt


63. tests/845DC70C/golden.txt Additional files +0/-0

...

tests/845DC70C/golden.txt


64. tests/885D5D8C/golden.txt Additional files +10/-20

...

tests/885D5D8C/golden.txt


65. tests/8876692F/golden-metadata.txt Additional files +0/-160

...

tests/8876692F/golden-metadata.txt


66. tests/8876692F/golden.txt Additional files +0/-14

...

tests/8876692F/golden.txt


67. tests/8C42A56C/golden.txt Additional files +12/-0

...

tests/8C42A56C/golden.txt


68. tests/A930AE61/golden.txt Additional files +12/-0

...

tests/A930AE61/golden.txt


69. tests/AEE7A791/golden.txt Additional files +0/-0

...

tests/AEE7A791/golden.txt


70. tests/B3C724B5/golden-metadata.txt Additional files +0/-0

...

tests/B3C724B5/golden-metadata.txt


71. tests/B3C724B5/golden.txt Additional files +0/-0

...

tests/B3C724B5/golden.txt


72. tests/B903D17E/golden-metadata.txt Additional files +0/-0

...

tests/B903D17E/golden-metadata.txt


73. tests/B903D17E/golden.txt Additional files +12/-0

...

tests/B903D17E/golden.txt


74. tests/C02D71EE/golden-metadata.txt Additional files +0/-176

...

tests/C02D71EE/golden-metadata.txt


75. tests/C02D71EE/golden.txt Additional files +0/-18

...

tests/C02D71EE/golden.txt


76. tests/C420EDF3/golden.txt Additional files +12/-0

...

tests/C420EDF3/golden.txt


77. tests/CE35B602/golden.txt Additional files +10/-0

...

tests/CE35B602/golden.txt


78. tests/E11FD23A/golden.txt Additional files +10/-0

...

tests/E11FD23A/golden.txt


79. tests/FA4D8FEF/golden-metadata.txt Additional files +0/-189

...

tests/FA4D8FEF/golden-metadata.txt


80. tests/FA4D8FEF/golden.txt Additional files +0/-32

...

tests/FA4D8FEF/golden.txt


81. tests/FE9379D8/golden.txt Additional files +12/-0

...

tests/FE9379D8/golden.txt


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. int_comp absent on device 🐞 Bug ⛯ Reliability
Description
In m_thinc:s_thinc_compression, the OpenACC-parallel kernel branches on int_comp (THINC vs MTHINC)
under default(present), but int_comp is not declared/created for the device in m_global_parameters,
risking an OpenACC runtime 'not present' failure in GPU builds. This risk is introduced because
int_comp is now referenced inside device code instead of only host-side conditionals.
Code

src/simulation/m_thinc.fpp[R380-383]

+                            if (aC >= ic_eps .and. aC <= 1._wp - ic_eps) then
+
+                                if (int_comp == 2 .and. n > 0) then
+                                    ! MTHINC: multi-dimensional face averages
Evidence
The project’s OpenACC loop macro defaults to default(present), meaning variables used inside the
GPU region must already be present on the device. The new THINC kernel references int_comp inside
the GPU loop, but the global parameter module’s GPU_DECLARE lists do not include int_comp, so
there is no clear path that makes it device-present.

src/common/include/acc_macros.fpp[132-158]
src/simulation/m_thinc.fpp[356-384]
src/simulation/m_global_parameters.fpp[205-216]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`int_comp` is referenced inside OpenACC GPU kernels under `default(present)`, but it is not explicitly declared/created on the device. This can produce OpenACC runtime failures (variable not present) in GPU builds.

### Issue Context
- `ACC_PARALLEL_LOOP` defaults to `default(present)`.
- `m_thinc:s_thinc_compression` branches on `int_comp` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` contains the central `GPU_DECLARE` lists for globals, but does not include `int_comp`.

### Fix Focus Areas
- src/simulation/m_thinc.fpp[356-384]
- src/simulation/m_global_parameters.fpp[205-216]
- src/common/include/acc_macros.fpp[132-158]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. vR densities use vL 🐞 Bug ✓ Correctness
Description
In m_thinc:s_thinc_compression (THINC path), rho_b and rho_e are computed only from vL_rs_vf_*
ratios and then applied to overwrite both vL_rs_vf_* and vR_rs_vf_* densities, discarding the
pre-compression vR reconstructed density/alpha ratios. Since WENO/MUSCL compute vL and vR using
different polynomials, this can make the right-face state inconsistent and distort fluxes.
Code

src/simulation/m_thinc.fpp[R453-473]

+                                        ! Save original density ratios before THINC overwrites them
+                                        rho_b = vL_rs_vf_${XYZ}$ (j, k, l, contxb)/vL_rs_vf_${XYZ}$ (j, k, l, advxb)
+                                        rho_e = vL_rs_vf_${XYZ}$ (j, k, l, contxe)/(1._wp - vL_rs_vf_${XYZ}$ (j, k, l, advxb))
+
+                                        ! Left reconstruction
+                                        aTHINC = qmin + 5e-1_wp*qmax*(1._wp + sgn*A)
+                                        if (aTHINC < ic_eps) aTHINC = ic_eps
+                                        if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
+                                        vL_rs_vf_${XYZ}$ (j, k, l, contxb) = rho_b*aTHINC
+                                        vL_rs_vf_${XYZ}$ (j, k, l, contxe) = rho_e*(1._wp - aTHINC)
+                                        vL_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
+                                        vL_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC
+
+                                        ! Right reconstruction
+                                        aTHINC = qmin + 5e-1_wp*qmax*(1._wp + sgn*(tanh(beta_eff) + A)/(1._wp + A*tanh(beta_eff)))
+                                        if (aTHINC < ic_eps) aTHINC = ic_eps
+                                        if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
+                                        vR_rs_vf_${XYZ}$ (j, k, l, contxb) = rho_b*aTHINC
+                                        vR_rs_vf_${XYZ}$ (j, k, l, contxe) = rho_e*(1._wp - aTHINC)
+                                        vR_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
+                                        vR_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC
Evidence
The THINC branch explicitly derives density ratios solely from vL and then uses those same ratios to
set vR values. Separately, WENO reconstruction computes vL and vR using different coefficient sets
(cbL vs cbR), so vR generally differs from vL before compression; overwriting vR with vL-derived
ratios ignores that reconstruction.

src/simulation/m_thinc.fpp[453-473]
src/simulation/m_weno.fpp[729-766]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In the THINC (1D) compression path, right-face densities (`vR_rs_vf_*`) are overwritten using density ratios computed from the left-face reconstruction (`vL_rs_vf_*`). This discards the right-face reconstructed density/alpha ratios and can make the right state inconsistent.

### Issue Context
WENO/MUSCL reconstruct `vL` and `vR` with different coefficient sets, so they are not generally identical before compression. THINC should preserve each face’s density ratio (or use a consistent cell-averaged ratio) when updating densities alongside alpha.

### Fix Focus Areas
- src/simulation/m_thinc.fpp[453-473]
- src/simulation/m_weno.fpp[729-766]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Missing precheck/build/test evidence 📘 Rule violation ⛯ Reliability
Description
The PR description does not document running ./mfc.sh precheck, ./mfc.sh build, or relevant
automated tests after adding a new Fortran module and changing parameter typing. Without this, CI
readiness and correctness of the change cannot be confirmed from the PR.
Code

src/simulation/m_thinc.fpp[R7-14]

+!> @brief THINC and MTHINC interface compression for volume fraction sharpening.
+!! THINC (int_comp=1): 1D directional interface compression applied after
+!! MUSCL/WENO reconstruction. Uses hyperbolic tangent profile per dimension.
+!! MTHINC (int_comp=2): Multi-dimensional THINC that reconstructs a tanh
+!! profile oriented along the interface normal (computed from the gradient
+!! of alpha), then integrates that profile over each cell face using
+!! Gaussian quadrature. A Newton iteration enforces the conservation
+!! constraint (cell-averaged alpha is preserved).
Evidence
Compliance ID 1 requires precheck, build, and relevant tests to be run and pass. The PR description
lists manual case runs/perf results but does not mention running the required commands, while the
diff shows substantial new Fortran functionality and a parameter type change that should be covered
by those checks.

CLAUDE.md
src/simulation/m_thinc.fpp[7-14]
toolchain/mfc/params/definitions.py[983-986]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR does not provide evidence that required CI-equivalent checks were run (`./mfc.sh precheck`, `./mfc.sh build`, and relevant tests).

## Issue Context
This PR adds a new Fortran module for THINC/MTHINC and changes the `int_comp` parameter type/handling; these changes should be validated by precheck/build and appropriate tests.

## Fix Focus Areas
- src/simulation/m_thinc.fpp[7-14]
- toolchain/mfc/params/definitions.py[983-986]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@github-actions
Copy link

Claude Code Review

Head SHA: 202d7daedced880868e31df3614e3d4b0b742f80
Files changed: 81 (source: 15 key files + 66 golden-file renames/updates)

Key source files:

  • src/simulation/m_thinc.fpp (new, 499 lines)
  • src/simulation/m_rhs.fpp (+22/-1)
  • src/simulation/m_muscl.fpp (+1/-86)
  • src/simulation/m_weno.fpp (0/-8)
  • src/simulation/m_global_parameters.fpp (+3/-3)
  • src/simulation/m_mpi_proxy.fpp (+2/-2)
  • src/simulation/m_start_up.fpp (+3/0)
  • toolchain/mfc/case_validator.py, params/definitions.py, test/cases.py

Summary

  • Adds MTHINC (int_comp=2): multi-dimensional THINC using precomputed interface normals and Gaussian quadrature for face averages; Newton iteration enforces the conservation constraint per cell.
  • Fixes a bug in the original THINC right-reconstruction density (Fix MUSCL THINC right-state using already-overwritten left-state values #1181): the old code used the already-overwritten left-face advxb value when computing the right-face density ratio.
  • Refactors THINC out of m_muscl/m_weno into a dedicated m_thinc module called from m_rhs after reconstruction — enabling compression for both WENO and MUSCL.
  • Changes int_comp from logical to integer (0=off, 1=THINC, 2=MTHINC) throughout; correctly moves MPI broadcast from the logical list to the integer list in m_mpi_proxy.fpp.
  • Good numerics: numerically stable f_log_cosh for large arguments, analytical 1-D THINC integral, correct use of GPU Fypp macros throughout.

Findings

[Medium] Missing Fortran runtime check for int_comp range — src/simulation/m_checker.fpp

m_checker.fpp was not updated. Per project convention (CLAUDE.md, parameter-system.md), a Fortran-side @:PROHIBIT guard should be added alongside the Python-side check in case_validator.py:

@:PROHIBIT(int_comp < 0 .or. int_comp > 2, "int_comp must be 0 (off), 1 (THINC), or 2 (MTHINC)")

The Python validator catches this at case-setup time, but the Fortran check is the convention for parameters with constrained integer values.


[Medium] MTHINC silently degrades to 1-D THINC for 1-D cases — src/simulation/m_rhs.fpp:749, m_thinc.fpp

When int_comp=2 and n=0 (1-D):

  • m_rhs.fpp:749: if (int_comp == 2 .and. n > 0) is false → normals are never computed (mthinc_nhat stays zero).
  • Inside s_thinc_compression, if (int_comp == 2 .and. n > 0) is also false → the else branch (1-D THINC) executes silently.

Mathematically this is fine (MTHINC reduces to THINC in 1-D), but the user gets THINC behaviour when requesting MTHINC with no diagnostic. The old Python constraint that required recon_type = 2 was removed but no MTHINC+1D note was added. At minimum, a comment or case_validator.py note would help.


[Low] MTHINC skips monotonicity check — src/simulation/m_thinc.fpp (THINC vs MTHINC branch)

The 1-D THINC path guards with moncon > moncon_cutoff (checks (aCR - aC)*(aC - aCL) > cutoff), preventing compression in non-monotone regions. The MTHINC path only checks nh1² + nh2² + nh3² > 0.5 (valid normal exists). Non-monotone interface cells that still have a computable normal will get MTHINC applied — the ic_eps outer guard prevents pure-fluid cells, but the directional-monotonicity protection is absent. This is likely intentional (MTHINC's normal is a multi-dimensional signal), but should be confirmed or documented.


[Low] Two-fluid assumption is undocumented — src/simulation/m_thinc.fpp

Both THINC and MTHINC update only contxb, contxe, advxb, advxe — the indices for exactly two fluids. Cases with 3+ fluids (multiple adv_idx entries) receive silently incorrect density/volume-fraction reconstructions. The original m_muscl.fpp code had the same limitation, but a @:PROHIBIT(int_comp > 0 .and. num_fluids > 2, ...) or at least a comment in s_thinc_compression would prevent silent misuse.


[Positive] Correct THINC bug fix

The old right-reconstruction in m_muscl.fpp computed the density ratio as:

vR...(contxb) = vL...(contxb) / vL...(advxb) * aTHINC   ! Bug: advxb already overwritten

The new code in m_thinc.fpp correctly saves rho_b = vL.../vL...(advxb) and rho_e = vL.../((1-vL...(advxb))) before modifying the left face, then uses them for both left and right reconstructions. This is the right fix.


[Positive] Architecture improvement

Centralising interface compression into m_thinc called from m_rhs (post-reconstruction) rather than inside m_muscl/m_weno is cleaner and correctly extends THINC coverage to WENO reconstruction — verified by the new WENO + int_comp test cases added to cases.py.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a dedicated THINC/MTHINC interface-compression module and migrates the int_comp setting from a logical flag to an integer selector, while updating tests/docs/tooling accordingly.

Changes:

  • Added src/simulation/m_thinc.fpp implementing THINC (int_comp=1) and MTHINC (int_comp=2) and wired it into the reconstruction flow in m_rhs.
  • Replaced the old MUSCL/WENO-local interface-compression hooks by centralizing compression in RHS reconstruction; removed the MUSCL s_interface_compression implementation.
  • Updated toolchain parameter typing/validation and adjusted examples/docs/tests to use integer int_comp.

Reviewed changes

Copilot reviewed 42 out of 81 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/simulation/m_thinc.fpp New THINC/MTHINC implementation (including MTHINC normal computation and Newton solve).
src/simulation/m_rhs.fpp Calls MTHINC normal computation pre-split; runs compression post-reconstruction with NVTX ranges.
src/simulation/m_muscl.fpp Removes s_interface_compression and MUSCL-side compression call.
src/simulation/m_weno.fpp Removes MUSCL import and WENO-side compression call.
src/simulation/m_start_up.fpp Initializes/finalizes the new THINC module when int_comp > 0.
src/simulation/m_global_parameters.fpp Changes int_comp from logical to integer with updated defaults/comments.
src/simulation/m_mpi_proxy.fpp Broadcasts int_comp as an integer instead of logical.
toolchain/mfc/params/definitions.py Registers int_comp as INT instead of LOG.
toolchain/mfc/case_validator.py Validates int_comp is in {0,1,2}.
toolchain/mfc/test/cases.py Expands generated test matrix to include int_comp values {0,1,2}.
toolchain/mfc/params/descriptions.py Updates parameter description to document 0/1/2 meanings.
docs/documentation/case.md Updates docs to describe integer int_comp and mentions MTHINC.
docs/module_categories.json Adds m_thinc to documentation module grouping.
examples/*/case.py Updates examples from "T" to 1 for THINC.
tests/*/golden-metadata.txt Updates/adds golden metadata for the new/updated test set.

Comment on lines +430 to +433
int_comp = self.get('int_comp', 0)

self.prohibit(int_comp and recon_type != 2,
"int_comp (THINC interface compression) requires recon_type = 2 (MUSCL)")
self.prohibit(int_comp not in [0, 1, 2],
"int_comp must be 0 (off), 1 (THINC), or 2 (MTHINC)")
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

int_comp=2 (MTHINC) is described as multi-dimensional, but the Fortran implementation only runs the MTHINC path when n > 0 (i.e., 2D/3D). In 1D (n=0) it silently falls back to the 1D THINC branch, which makes int_comp=2 behave differently than documented and is easy to misconfigure. Consider adding a validation rule that prohibits int_comp == 2 unless the case is at least 2D (e.g., n > 0).

Copilot uses AI. Check for mistakes.
Comment on lines 189 to 195
if muscl_order == 1:
for int_comp in ["T", "F"]:
for int_comp in [0, 1, 2]:
cases.append(define_case_d(stack, f"int_comp={int_comp}", {'int_comp': int_comp}))
elif muscl_order == 2:
for int_comp in ["T", "F"]:
for int_comp in [0, 1, 2]:
stack.push(f"int_comp={int_comp}", {'int_comp': int_comp})
cases.append(define_case_d(stack, f"muscl_lim=1", {'muscl_lim': 1}))
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This test generator now produces MUSCL cases with int_comp=2 for 1D configurations as well. If int_comp=2 is meant to be strictly MTHINC (multi-dimensional), these 1D cases will either be invalid (after adding validation) or will exercise the THINC fallback while being labeled as MTHINC. Consider filtering int_comp=2 to only 2D/3D dimension sets (e.g., only when "y" in dimInfo[0]) to keep the test matrix consistent with the feature definition.

Copilot uses AI. Check for mistakes.
| `muscl_order` | Integer | MUSCL order [1,2] |
| `muscl_lim` | Integer | MUSCL Slope Limiter: [1] minmod; [2] monotonized central; [3] Van Albada; [4] Van Leer; [5] SUPERBEE |
| `int_comp` | Logical | THINC Interface Compression |
| `int_comp` | Integer | Interface Compression [1] THINC [2] MTHINC |
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The parameter table entry for int_comp was updated to an integer but no longer documents the 0=off value (it currently only lists [1] THINC [2] MTHINC). This can confuse users and contradicts other docs/tooling that treat 0 as the default/off value. Please update the table text to include 0 explicitly.

Suggested change
| `int_comp` | Integer | Interface Compression [1] THINC [2] MTHINC |
| `int_comp` | Integer | Interface Compression: [0] off; [1] THINC; [2] MTHINC |

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +179
real(wp) :: d, V, residual, dV
integer :: iter

d = 0._wp
do iter = 1, 30
V = f_mthinc_volume_integral(n1, n2, n3, d, beta, ndim)
residual = V - alpha_cell
if (abs(residual) < 1e-14_wp) exit
dV = f_mthinc_volume_integral_dd(n1, n2, n3, d, beta, ndim)
if (abs(dV) < 1e-14_wp) exit
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

f_mthinc_solve_d uses hard-coded Newton tolerances (1e-14_wp) for both the residual and derivative checks. Since wp can be single precision in this codebase, 1e-14_wp is below machine epsilon and will never be satisfied, potentially causing unnecessary iterations and inconsistent convergence behavior across precision modes. Consider scaling tolerances using epsilon(1._wp) (and/or a looser absolute tolerance) so the stopping criteria behave sensibly in single/mixed precision builds.

Suggested change
real(wp) :: d, V, residual, dV
integer :: iter
d = 0._wp
do iter = 1, 30
V = f_mthinc_volume_integral(n1, n2, n3, d, beta, ndim)
residual = V - alpha_cell
if (abs(residual) < 1e-14_wp) exit
dV = f_mthinc_volume_integral_dd(n1, n2, n3, d, beta, ndim)
if (abs(dV) < 1e-14_wp) exit
real(wp) :: d, V, residual, dV, tol_res, tol_dV
integer :: iter
tol_res = 100._wp*epsilon(1._wp)
tol_dV = 100._wp*epsilon(1._wp)
d = 0._wp
do iter = 1, 30
V = f_mthinc_volume_integral(n1, n2, n3, d, beta, ndim)
residual = V - alpha_cell
if (abs(residual) < tol_res) exit
dV = f_mthinc_volume_integral_dd(n1, n2, n3, d, beta, ndim)
if (abs(dV) < tol_dV) exit

Copilot uses AI. Check for mistakes.
Comment on lines +453 to +455
! Save original density ratios before THINC overwrites them
rho_b = vL_rs_vf_${XYZ}$ (j, k, l, contxb)/vL_rs_vf_${XYZ}$ (j, k, l, advxb)
rho_e = vL_rs_vf_${XYZ}$ (j, k, l, contxe)/(1._wp - vL_rs_vf_${XYZ}$ (j, k, l, advxb))
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

In the THINC branch, rho_b and rho_e are computed by dividing by the reconstructed left-face volume fraction (vL_rs_vf_*(...,advxb) and 1 - vL_rs_vf_*(...,advxb)). Even though the cell-center aC is bounded by ic_eps, the reconstructed face value can still approach 0 or 1 (e.g., due to reconstruction overshoot/limiting), which can lead to large ratios or division-by-zero. Consider computing these density ratios from cell-averaged values (v_vf(contxb)/aC and v_vf(contxe)/(1-aC)) or applying a small clamp to the denominator before dividing.

Suggested change
! Save original density ratios before THINC overwrites them
rho_b = vL_rs_vf_${XYZ}$ (j, k, l, contxb)/vL_rs_vf_${XYZ}$ (j, k, l, advxb)
rho_e = vL_rs_vf_${XYZ}$ (j, k, l, contxe)/(1._wp - vL_rs_vf_${XYZ}$ (j, k, l, advxb))
! Save original density ratios using cell-averaged volume fractions
rho_b = v_vf_${XYZ}$ (j, k, l, contxb)/max(aC, ic_eps)
rho_e = v_vf_${XYZ}$ (j, k, l, contxe)/max(1._wp - aC, ic_eps)

Copilot uses AI. Check for mistakes.
Comment on lines +380 to +383
if (aC >= ic_eps .and. aC <= 1._wp - ic_eps) then

if (int_comp == 2 .and. n > 0) then
! MTHINC: multi-dimensional face averages
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

1. Int_comp absent on device 🐞 Bug ⛯ Reliability

In m_thinc:s_thinc_compression, the OpenACC-parallel kernel branches on int_comp (THINC vs MTHINC)
under default(present), but int_comp is not declared/created for the device in m_global_parameters,
risking an OpenACC runtime 'not present' failure in GPU builds. This risk is introduced because
int_comp is now referenced inside device code instead of only host-side conditionals.
Agent Prompt
### Issue description
`int_comp` is referenced inside OpenACC GPU kernels under `default(present)`, but it is not explicitly declared/created on the device. This can produce OpenACC runtime failures (variable not present) in GPU builds.

### Issue Context
- `ACC_PARALLEL_LOOP` defaults to `default(present)`.
- `m_thinc:s_thinc_compression` branches on `int_comp` inside `$:GPU_PARALLEL_LOOP`.
- `m_global_parameters` contains the central `GPU_DECLARE` lists for globals, but does not include `int_comp`.

### Fix Focus Areas
- src/simulation/m_thinc.fpp[356-384]
- src/simulation/m_global_parameters.fpp[205-216]
- src/common/include/acc_macros.fpp[132-158]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +453 to +473
! Save original density ratios before THINC overwrites them
rho_b = vL_rs_vf_${XYZ}$ (j, k, l, contxb)/vL_rs_vf_${XYZ}$ (j, k, l, advxb)
rho_e = vL_rs_vf_${XYZ}$ (j, k, l, contxe)/(1._wp - vL_rs_vf_${XYZ}$ (j, k, l, advxb))

! Left reconstruction
aTHINC = qmin + 5e-1_wp*qmax*(1._wp + sgn*A)
if (aTHINC < ic_eps) aTHINC = ic_eps
if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
vL_rs_vf_${XYZ}$ (j, k, l, contxb) = rho_b*aTHINC
vL_rs_vf_${XYZ}$ (j, k, l, contxe) = rho_e*(1._wp - aTHINC)
vL_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
vL_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC

! Right reconstruction
aTHINC = qmin + 5e-1_wp*qmax*(1._wp + sgn*(tanh(beta_eff) + A)/(1._wp + A*tanh(beta_eff)))
if (aTHINC < ic_eps) aTHINC = ic_eps
if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
vR_rs_vf_${XYZ}$ (j, k, l, contxb) = rho_b*aTHINC
vR_rs_vf_${XYZ}$ (j, k, l, contxe) = rho_e*(1._wp - aTHINC)
vR_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
vR_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

2. Vr densities use vl 🐞 Bug ✓ Correctness

In m_thinc:s_thinc_compression (THINC path), rho_b and rho_e are computed only from vL_rs_vf_*
ratios and then applied to overwrite both vL_rs_vf_* and vR_rs_vf_* densities, discarding the
pre-compression vR reconstructed density/alpha ratios. Since WENO/MUSCL compute vL and vR using
different polynomials, this can make the right-face state inconsistent and distort fluxes.
Agent Prompt
### Issue description
In the THINC (1D) compression path, right-face densities (`vR_rs_vf_*`) are overwritten using density ratios computed from the left-face reconstruction (`vL_rs_vf_*`). This discards the right-face reconstructed density/alpha ratios and can make the right state inconsistent.

### Issue Context
WENO/MUSCL reconstruct `vL` and `vR` with different coefficient sets, so they are not generally identical before compression. THINC should preserve each face’s density ratio (or use a consistent cell-averaged ratio) when updating densities alongside alpha.

### Fix Focus Areas
- src/simulation/m_thinc.fpp[453-473]
- src/simulation/m_weno.fpp[729-766]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@wilfonba wilfonba marked this pull request as draft March 12, 2026 16:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

This pull request refactors interface compression from a boolean flag into an integer enumeration with three states: 0 (off), 1 (THINC), and 2 (MTHINC). The implementation moves compression logic from the MUSCL module into a dedicated new THINC module. Interface compression is now integrated into RHS calculations and invoked during variable reconstruction. Documentation, parameter definitions, validation logic, and example configurations are updated to reflect the new integer-based parameter type and semantic values. Test cases are expanded to exercise the new enumeration states.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'MTHINC Interface Compression' directly and clearly describes the main feature addition in the PR.
Description check ✅ Passed The PR description covers the main change (MTHINC implementation), references a related issue (#1181), includes comprehensive testing details with performance metrics and GPU validation, and the author has checked off both required checklist items (tests added/updated and documentation updated).

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

📝 Coding Plan for PR comments
  • Generate coding plan

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
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: 9


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 411ddfaf-e410-411e-a688-203d6a1caf71

📥 Commits

Reviewing files that changed from the base of the PR and between 506c6f5 and 202d7da.

📒 Files selected for processing (81)
  • 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/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/09195EF4/golden-metadata.txt
  • tests/09195EF4/golden.txt
  • tests/0A362971/golden-metadata.txt
  • tests/0A362971/golden.txt
  • tests/11D609F6/golden-metadata.txt
  • tests/11D609F6/golden.txt
  • tests/1B300F28/golden-metadata.txt
  • tests/1F0C4A44/golden-metadata.txt
  • tests/1F0C4A44/golden.txt
  • tests/2C9844EF/golden-metadata.txt
  • tests/2C9844EF/golden.txt
  • tests/2D11A034/golden-metadata.txt
  • tests/2D11A034/golden.txt
  • tests/2E4AC44C/golden-metadata.txt
  • tests/2E4AC44C/golden.txt
  • tests/3ECA875A/golden-metadata.txt
  • tests/3ECA875A/golden.txt
  • tests/409B55DF/golden-metadata.txt
  • tests/409B55DF/golden.txt
  • tests/503EEFF7/golden-metadata.txt
  • tests/503EEFF7/golden.txt
  • tests/50EC2239/golden-metadata.txt
  • tests/50EC2239/golden.txt
  • tests/6102D509/golden-metadata.txt
  • tests/6102D509/golden.txt
  • tests/6775D763/golden-metadata.txt
  • tests/6775D763/golden.txt
  • tests/67C777D8/golden.txt
  • tests/7156050E/golden-metadata.txt
  • tests/7156050E/golden.txt
  • tests/845DC70C/golden-metadata.txt
  • tests/845DC70C/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/A438B8CE/golden-metadata.txt
  • tests/A438B8CE/golden.txt
  • tests/A930AE61/golden-metadata.txt
  • tests/A930AE61/golden.txt
  • tests/AEE7A791/golden-metadata.txt
  • tests/AEE7A791/golden.txt
  • tests/B3C724B5/golden-metadata.txt
  • tests/B3C724B5/golden.txt
  • tests/B903D17E/golden-metadata.txt
  • tests/B903D17E/golden.txt
  • tests/C02D71EE/golden-metadata.txt
  • tests/C02D71EE/golden.txt
  • tests/C420EDF3/golden-metadata.txt
  • tests/C420EDF3/golden.txt
  • tests/CE35B602/golden-metadata.txt
  • tests/CE35B602/golden.txt
  • tests/E11FD23A/golden-metadata.txt
  • tests/E11FD23A/golden.txt
  • tests/F5FABAE9/golden-metadata.txt
  • tests/F5FABAE9/golden.txt
  • tests/FA4D8FEF/golden-metadata.txt
  • tests/FA4D8FEF/golden.txt
  • tests/FE9379D8/golden-metadata.txt
  • tests/FE9379D8/golden.txt
  • toolchain/mfc/case_validator.py
  • toolchain/mfc/params/definitions.py
  • toolchain/mfc/params/descriptions.py
  • toolchain/mfc/test/cases.py
💤 Files with no reviewable changes (10)
  • tests/FA4D8FEF/golden.txt
  • tests/FA4D8FEF/golden-metadata.txt
  • tests/2C9844EF/golden-metadata.txt
  • src/simulation/m_weno.fpp
  • tests/0A362971/golden.txt
  • tests/1B300F28/golden-metadata.txt
  • tests/8876692F/golden-metadata.txt
  • tests/C02D71EE/golden-metadata.txt
  • tests/50EC2239/golden-metadata.txt
  • tests/0A362971/golden-metadata.txt

| `muscl_order` | Integer | MUSCL order [1,2] |
| `muscl_lim` | Integer | MUSCL Slope Limiter: [1] minmod; [2] monotonized central; [3] Van Albada; [4] Van Leer; [5] SUPERBEE |
| `int_comp` | Logical | THINC Interface Compression |
| `int_comp` | Integer | Interface Compression [1] THINC [2] MTHINC |
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document all three valid states for int_comp parameter.

The table entry only lists values [1] and [2], but according to the PR objectives, int_comp is a three-state enumeration: 0 (off/disabled), 1 (THINC), and 2 (MTHINC). Users need to know that setting int_comp=0 disables interface compression.

📝 Suggested documentation fix
-| `int_comp`                 | Integer | Interface Compression [1] THINC [2] MTHINC |
+| `int_comp`                 | Integer | Interface Compression: [0] Off; [1] THINC; [2] MTHINC |
📝 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
| `int_comp` | Integer | Interface Compression [1] THINC [2] MTHINC |
| `int_comp` | Integer | Interface Compression: [0] Off; [1] THINC; [2] MTHINC |

`muscl_lim = 1`, `2`, `3`, `4`, and `5` correspond to minmod, monotonized central, Van Albada, Van Leer, and SUPERBEE, respectively.

- `int_comp` activates interface compression using THINC used in MUSCL Reconstruction, with control parameters (`ic_eps`, and `ic_beta`).
- `int_comp` activates interface compression using [1] THINC or [2] MTHINC used in variable reconstruction, with control parameters (`ic_eps`, and `ic_beta`).
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify all three states and the behavior when int_comp=0.

The description states "int_comp activates interface compression using [1] THINC or [2] MTHINC," but doesn't document the disabled state (0) or explain what happens when int_comp=0. Since this parameter changed from a boolean to a three-state integer enumeration, all valid values should be clearly documented to help users understand how to disable the feature.

📝 Suggested documentation improvement
-- `int_comp` activates interface compression using [1] THINC or [2] MTHINC used in variable reconstruction, with control parameters (`ic_eps`, and `ic_beta`).
+- `int_comp` controls interface compression in variable reconstruction with control parameters (`ic_eps`, and `ic_beta`). `int_comp = 0` disables interface compression; `int_comp = 1` enables THINC compression; `int_comp = 2` enables MTHINC compression.

Based on learnings, modifications to public parameters affect downstream users. This parameter changed from boolean to integer semantics, so complete documentation of all states is essential for users migrating from the previous boolean interface.

Comment on lines +177 to +179
integer :: int_comp !< Interface compression: 0=off, 1=THINC, 2=MTHINC
real(wp) :: ic_eps !< THINC Epsilon to compress on surface cells
real(wp) :: ic_beta !< THINC Sharpness Parameter
real(wp) :: ic_beta !< THINC/MTHINC Sharpness Parameter
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check the GPU_DECLARE and GPU_UPDATE lists in m_global_parameters.fpp
cat -n src/simulation/m_global_parameters.fpp | grep -A 5 -B 5 "GPU_DECLARE\|GPU_UPDATE" | head -100

Repository: MFlowCode/MFC

Length of output: 4902


🏁 Script executed:

# Check what's at lines 177-179 and 627-629 in m_global_parameters.fpp
sed -n '175,181p' src/simulation/m_global_parameters.fpp
sed -n '625,631p' src/simulation/m_global_parameters.fpp

Repository: MFlowCode/MFC

Length of output: 753


🏁 Script executed:

# Search for uses of int_comp, ic_eps, ic_beta in m_thinc.fpp
rg "int_comp|ic_eps|ic_beta" src/simulation/m_thinc.fpp -n --context 3

Repository: MFlowCode/MFC

Length of output: 6402


🏁 Script executed:

# Check if s_compute_mthinc_normals and s_apply_thinc_compression contain GPU kernels
# Look for GPU_DATA, GPU_KERNEL, or !$acc pragmas in m_thinc.fpp around the relevant subroutines
rg "s_compute_mthinc_normals|s_apply_thinc_compression" src/simulation/m_thinc.fpp -A 50 | head -150

Repository: MFlowCode/MFC

Length of output: 6505


🏁 Script executed:

# Check if the code that uses int_comp, ic_eps, ic_beta is within GPU regions
# Look for GPU_DATA or !$acc markers near the usage lines
sed -n '220,500p' src/simulation/m_thinc.fpp | grep -E "GPU_DATA|GPU_KERNEL|!.acc|int_comp|ic_eps|ic_beta"

Repository: MFlowCode/MFC

Length of output: 1546


🏁 Script executed:

# Get fuller context: check if there are GPU regions at all in m_thinc.fpp
rg "GPU_DATA|GPU_KERNEL|!.acc" src/simulation/m_thinc.fpp -n

Repository: MFlowCode/MFC

Length of output: 39


🏁 Script executed:

# Check if int_comp, ic_eps, ic_beta appear in any GPU_DECLARE or GPU_UPDATE statements elsewhere in m_global_parameters.fpp
rg "int_comp|ic_eps|ic_beta" src/simulation/m_global_parameters.fpp

Repository: MFlowCode/MFC

Length of output: 364


🏁 Script executed:

# Verify the complete context: check where int_comp, ic_eps, ic_beta are declared and look for nearby GPU_DECLARE
sed -n '170,190p' src/simulation/m_global_parameters.fpp

Repository: MFlowCode/MFC

Length of output: 1380


🏁 Script executed:

# Check if these variables need GPU_DECLARE by looking at the learning guidance and similar scalar globals
# Look for patterns: declaration followed by GPU_DECLARE for nearby scalars
sed -n '213,225p' src/simulation/m_global_parameters.fpp

Repository: MFlowCode/MFC

Length of output: 792


Add int_comp, ic_eps, and ic_beta to GPU_DECLARE.

These three variables are read inside GPU kernels in s_compute_mthinc_normals() and s_thinc_compression() (in m_thinc.fpp) but are not declared with GPU_DECLARE in this module. Without it, the GPU code may use stale or default values instead of case-input values. Add them to a GPU_DECLARE(create='[...]') statement (e.g., line 216 or nearby).

Comment on lines +749 to +753
if (int_comp == 2 .and. n > 0) then
call nvtxStartRange("RHS-COMPRESSION-NORMALS")
call s_compute_mthinc_normals(q_prim_qp%vf)
call nvtxEndRange
end if
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use the same THINC enablement guard here as in startup.

src/simulation/m_start_up.fpp:1114-1122 only initializes THINC when .not. igr .or. dummy, but this block runs for any int_comp == 2. In a pure IGR run, q_prim_qp%vf is not prepared for THINC and the MTHINC workspace was never allocated.

Minimal fix
-        if (int_comp == 2 .and. n > 0) then
+        if (int_comp == 2 .and. n > 0 .and. (.not. igr .or. dummy)) then
             call nvtxStartRange("RHS-COMPRESSION-NORMALS")
             call s_compute_mthinc_normals(q_prim_qp%vf)
             call nvtxEndRange
         end if
📝 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
if (int_comp == 2 .and. n > 0) then
call nvtxStartRange("RHS-COMPRESSION-NORMALS")
call s_compute_mthinc_normals(q_prim_qp%vf)
call nvtxEndRange
end if
if (int_comp == 2 .and. n > 0 .and. (.not. igr .or. dummy)) then
call nvtxStartRange("RHS-COMPRESSION-NORMALS")
call s_compute_mthinc_normals(q_prim_qp%vf)
call nvtxEndRange
end if

elseif (recon_type == MUSCL_TYPE) then
call s_initialize_muscl_module()
end if
if (int_comp > 0) call s_initialize_thinc_module()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Mirror THINC finalization with the initialization predicate.

Initialization happens inside .not. igr .or. dummy, but finalization only runs in the igr == .false. branch. In igr=.true., dummy=.true. runs, the new THINC/MTHINC state can be allocated and never released.

As per coding guidelines, Always pair @:ALLOCATE calls with matching @:DEALLOCATE calls in the corresponding finalization subroutine.

Also applies to: 1304-1304

Comment on lines +19 to +32
module m_thinc

use m_derived_types
use m_global_parameters
use m_helper

#ifdef MFC_OpenACC
use openacc
#endif

private; public :: s_initialize_thinc_module, &
s_thinc_compression, &
s_compute_mthinc_normals, &
s_finalize_thinc_module
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add implicit none at module scope.

This new module omits implicit none, so a typo in a local or result name will silently compile as an implicitly typed variable.

Suggested change
 module m_thinc
+
+    implicit none
+
     private; public :: s_initialize_thinc_module, &
  s_thinc_compression, &
  s_compute_mthinc_normals, &
  s_finalize_thinc_module

As per coding guidelines, "All Fortran modules must include implicit none at the module level."

Comment on lines +100 to +117
if (ndim == 1) then
res = f_thinc_integral_1d(beta*d, beta*n1)
elseif (ndim == 2) then
res = 0._wp
do q1 = 1, 3
a = beta*(n2*gq3_pts(q1) + d)
res = res + gq3_wts(q1)*f_thinc_integral_1d(a, beta*n1)
end do
else
res = 0._wp
do q1 = 1, 3
do q2 = 1, 3
a = beta*(n2*gq3_pts(q1) + n3*gq3_pts(q2) + d)
res = res + gq3_wts(q1)*gq3_wts(q2) &
*f_thinc_integral_1d(a, beta*n1)
end do
end do
end if
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

int_comp = 2 silently falls back in x-z 2D runs.

num_dims can still be 2 when n == 0 and p > 0, but the MTHINC path is gated on n > 0, and the 2-D helper formulas only use n1/n2. An x-z case therefore never actually executes MTHINC even though the enum says it should. Either reject that configuration explicitly or map the active second dimension in the 2-D formulas.

Also applies to: 197-224, 382-382

Comment on lines +404 to +427
rho1 = v_vf(contxb)%sf(ix, iy, iz)/aC
rho2 = v_vf(contxe)%sf(ix, iy, iz)/(1._wp - aC)

! Left face (face_pos = -0.5)
aTHINC = f_mthinc_face_average( &
nh1, nh2, nh3, d_local, ic_beta, &
${REC_DIR}$, -5e-1_wp, num_dims)
if (aTHINC < ic_eps) aTHINC = ic_eps
if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
vL_rs_vf_${XYZ}$ (j, k, l, contxb) = rho1*aTHINC
vL_rs_vf_${XYZ}$ (j, k, l, contxe) = rho2*(1._wp - aTHINC)
vL_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
vL_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC

! Right face (face_pos = +0.5)
aTHINC = f_mthinc_face_average( &
nh1, nh2, nh3, d_local, ic_beta, &
${REC_DIR}$, 5e-1_wp, num_dims)
if (aTHINC < ic_eps) aTHINC = ic_eps
if (aTHINC > 1._wp - ic_eps) aTHINC = 1._wp - ic_eps
vR_rs_vf_${XYZ}$ (j, k, l, contxb) = rho1*aTHINC
vR_rs_vf_${XYZ}$ (j, k, l, contxe) = rho2*(1._wp - aTHINC)
vR_rs_vf_${XYZ}$ (j, k, l, advxb) = aTHINC
vR_rs_vf_${XYZ}$ (j, k, l, advxe) = 1._wp - aTHINC
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard interface compression to exactly two fluids.

Both branches reconstruct only contxb/contxe and advxb/advxe. With num_fluids == 1, those indices alias; with num_fluids > 2, the last phase is forced to 1 - alpha_1 and intermediate phases are ignored. The validator snippet included with this PR only constrains int_comp to {0,1,2}, so unsupported cases can still reach this path. Please reject int_comp > 0 unless num_fluids == 2, or generalize the reconstruction.

Also applies to: 454-473

Comment on lines +430 to +433
int_comp = self.get('int_comp', 0)

self.prohibit(int_comp and recon_type != 2,
"int_comp (THINC interface compression) requires recon_type = 2 (MUSCL)")
self.prohibit(int_comp not in [0, 1, 2],
"int_comp must be 0 (off), 1 (THINC), or 2 (MTHINC)")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Reject int_comp > 0 unless recon_type == 2.

This range check is necessary, but it now lets int_comp=1/2 pass for non-MUSCL reconstructions because check_muscl() returns immediately afterward. Cross-file, src/simulation/m_rhs.fpp:745-755 still calls s_compute_mthinc_normals when int_comp == 2, while src/simulation/m_rhs.fpp:1896-1950 only runs the THINC compression path inside the MUSCL branch. That means an incompatible setup can get through validation and reach an invalid runtime path.

Suggested fix
         recon_type = self.get('recon_type', 1)
         int_comp = self.get('int_comp', 0)

         self.prohibit(int_comp not in [0, 1, 2],
                      "int_comp must be 0 (off), 1 (THINC), or 2 (MTHINC)")
+        self.prohibit(int_comp > 0 and recon_type != 2,
+                     "int_comp requires recon_type = 2 (MUSCL)")

         # MUSCL_TYPE = 2
         if recon_type != 2:
             return

Based on learnings When adding a parameter with cross-parameter constraints, add corresponding validation logic in toolchain/mfc/case_validator.py.

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 15.87302% with 159 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.73%. Comparing base (d4336a1) to head (202d7da).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
src/simulation/m_thinc.fpp 10.73% 154 Missing and 4 partials ⚠️
src/simulation/m_rhs.fpp 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1303      +/-   ##
==========================================
- Coverage   44.95%   44.73%   -0.23%     
==========================================
  Files          70       71       +1     
  Lines       20503    20651     +148     
  Branches     1946     1960      +14     
==========================================
+ Hits         9217     9238      +21     
- Misses      10164    10291     +127     
  Partials     1122     1122              

☔ 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

Development

Successfully merging this pull request may close these issues.

2 participants