Skip to content

Commit d4e38cf

Browse files
committed
merge upstream
2 parents f5abb8d + 9d866bd commit d4e38cf

38 files changed

Lines changed: 1819 additions & 405 deletions

.github/scripts/check_coverage_map_health.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,23 @@
1313
entries, meta = load_map(COVERAGE_MAP_PATH)
1414
if entries is None:
1515
sys.exit("Coverage map missing or corrupt.")
16-
current_keys = {b.to_case().coverage_key() for b in list_cases()}
16+
# Compute each current test's coverage key. Loading a case executes its case
17+
# file; some (e.g. chemistry examples) import optional deps like cantera that are
18+
# not installed in this lightweight job. Skip any case that fails to load instead
19+
# of crashing — map_health measures the fraction of *loadable* current tests that
20+
# are mapped, so a smaller current_keys cannot produce a false "stale" result.
21+
current_keys = set()
22+
unloadable = []
23+
for b in list_cases():
24+
try:
25+
current_keys.add(b.to_case().coverage_key())
26+
except Exception as exc: # noqa: BLE001 — a case file that won't import must not crash the health check
27+
last_line = (str(exc).strip().splitlines() or ["(no message)"])[-1][:140]
28+
unloadable.append((getattr(b, "trace", repr(b)), last_line))
29+
if unloadable:
30+
print(f"Note: {len(unloadable)} case(s) could not be loaded in this lightweight job (excluded from the check):")
31+
for trace, err in unloadable[:15]:
32+
print(f" - {trace}: {err}")
1733
ok, msg = map_health(
1834
meta=meta,
1935
current_keys=current_keys,

.github/workflows/common/test.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ if [ -n "${job_shard:-}" ]; then
5757
shard_opts="--shard $job_shard"
5858
fi
5959

60-
# Coverage-based test selection in SHADOW mode on PRs: prints what it WOULD select but the
61-
# full suite still runs (no --select-enforce). Changed files come from git detection
62-
# (self-healing deepen) since the SLURM job doesn't receive the paths-filter list.
60+
# Coverage-based test selection ENFORCED on PRs: runs only tests whose recorded coverage
61+
# overlaps the PR's changed files (conservative ladder; non-.fpp and uncovered-.fpp changes
62+
# fall back to run-all). Pushes to master run the full suite as a backstop. Changed files
63+
# come from git detection (self-healing deepen) since the SLURM job doesn't receive the
64+
# paths-filter list.
6365
select_opts=""
6466
if [ "${GITHUB_EVENT_NAME:-}" = "pull_request" ]; then
65-
select_opts="--only-changes"
67+
select_opts="--select-enforce"
6668
fi
6769

6870
./mfc.sh test -v --max-attempts 3 --no-build $select_opts -a -j $n_test_threads $rdma_opts $device_opts $build_opts $shard_opts -- -c $job_cluster

.github/workflows/coverage-refresh.yml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ jobs:
2222
group: phoenix
2323
labels: gt
2424
steps:
25+
# persist-credentials: false stops actions/checkout from configuring the
26+
# default GITHUB_TOKEN as an http.extraheader, which otherwise OVERRIDES the
27+
# token embedded in the push URL below — making the push authenticate as
28+
# github-actions[bot] (which cannot bypass the require-PR rule) instead of
29+
# the CACHE_PUSH_TOKEN identity.
2530
- uses: actions/checkout@v4
26-
with: { clean: false }
31+
with: { clean: false, persist-credentials: false }
2732
- name: Build + collect coverage map (SLURM)
2833
run: bash .github/scripts/submit-slurm-job.sh .github/workflows/common/coverage-refresh.sh cpu none phoenix
2934
- name: Commit refreshed map
@@ -34,10 +39,15 @@ jobs:
3439
git config user.name "mfc-bot"
3540
git config user.email "mfc-bot@users.noreply.github.com"
3641
git add tests/coverage_map.json.gz
37-
git commit -m "test: refresh coverage map [skip ci]"
38-
# Push to protected master via CACHE_PUSH_TOKEN (a PAT/App token with
39-
# contents:write + branch-protection bypass), mirroring deploy-tap.yml's
40-
# x-access-token push. The default GITHUB_TOKEN is rejected by protection.
42+
# --no-verify: this bot commit stages only the binary coverage map; it
43+
# must not run the repo pre-commit hook (./mfc.sh precheck/spelling),
44+
# which is for source changes and aborts the commit on the runner.
45+
git commit --no-verify -m "test: refresh coverage map [skip ci]"
46+
# Push to master with CACHE_PUSH_TOKEN, a classic PAT from an org-owner
47+
# account. GitHub Apps cannot bypass the require-PR ruleset rule for
48+
# direct pushes, but a PAT authenticates as the user (OrganizationAdmin),
49+
# which IS an honored bypass actor. persist-credentials:false above
50+
# ensures this token is actually used for the push.
4151
git push "https://x-access-token:${CACHE_PUSH_TOKEN}@github.com/MFlowCode/MFC.git" HEAD:master
4252
else
4353
echo "Coverage map unchanged."

.github/workflows/test.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,13 @@ jobs:
264264
- name: Test
265265
if: '!matrix.nvhpc'
266266
run: |
267-
# Coverage-based test selection in SHADOW mode on PRs: the selector
268-
# prints what it WOULD run, but the full suite still runs (no
269-
# --select-enforce). Enforcement is a separate, later change.
267+
# Coverage-based test selection ENFORCED on PRs: runs only the tests whose
268+
# recorded coverage overlaps the PR's changed files (conservative ladder in
269+
# coverage.py — non-.fpp changes and .fpp files no test covers fall back to
270+
# run-all). Pushes to master run the full suite (SELECT empty) as a backstop,
271+
# and the NVHPC jobs below still run --test-all as a pre-merge full check.
270272
SELECT=()
271-
[ "${{ github.event_name }}" = "pull_request" ] && SELECT=(--only-changes --changed-files "$CHANGED_FILES")
273+
[ "${{ github.event_name }}" = "pull_request" ] && SELECT=(--select-enforce --changed-files "$CHANGED_FILES")
272274
/bin/bash mfc.sh test -v --max-attempts 3 -j $(nproc) "${SELECT[@]}" $TEST_ALL $TEST_PCT $PRECISION
273275
env:
274276
TEST_ALL: ${{ matrix.mpi == 'mpi' && '--test-all' || '' }}

docs/documentation/case.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ This is enabled by adding ``'elliptic_smoothing': "T",`` and ``'elliptic_smoothi
322322
| Parameter | Type | Description |
323323
| ---: | :----: | :--- |
324324
| `num_ibs` | Integer | Number of immersed boundary patches |
325+
| `num_particle_beds` | Integer | Number of particle bed specifications to generate immersed boundary patches from |
326+
| `ib_neighborhood_radius` | Integer | Parameter that controls the neighborhood size for IB detection. |
325327
| `geometry` | Integer | Geometry configuration of the patch.|
326328
| `x[y,z]_centroid` | Real | Centroid of the applied geometry in the [x,y,z]-direction. |
327329
| `length_x[y,z]` | Real | Length, if applicable, in the [x,y,z]-direction. |
@@ -383,6 +385,8 @@ Additional details on this specification can be found in [The Naca Airfoil Serie
383385

384386
- `ib_coefficient_of_friction` is the coefficient of friction used in IB collisions.
385387

388+
- `ib_neighborhood_radius` controls the size of the neighborhood size. This value defaults to 1, which indicates that any given rank is aware of IB's up to 1 ranks away. This parameter is required to strong-scale a case when IB's eventually grow to be larger than one full processor domain wide.
389+
386390
### 5. Fluid Material's {#sec-fluid-materials}
387391

388392
| Parameter | Type | Description |
@@ -653,7 +657,7 @@ To restart the simulation from $k$-th time step, see @ref running "Restarting Ca
653657
| `alpha_wrt(i)` | Logical | Add the volume fraction of fluid $i$ to the database |
654658
| `gamma_wrt` | Logical | Add the specific heat ratio function to the database |
655659
| `heat_ratio_wrt` | Logical | Add the specific heat ratio to the database |
656-
| `ib_state_wrt` | Logical | Write IB state and loads to a datafile at each time step |
660+
| `ib_state_wrt` | Logical | Parameter to handle writing IB state on saves and outputting the state as a point mesh to SILO files. |
657661
| `pi_inf_wrt` | Logical | Add the liquid stiffness function to the database |
658662
| `pres_inf_wrt` | Logical | Add the liquid stiffness to the formatted database |
659663
| `c_wrt` | Logical | Add the sound speed to the database |
@@ -714,14 +718,14 @@ If `file_per_process` is true, then pre_process, simulation, and post_process mu
714718

715719
- ``[variable's name]_wrt`` activates the output of each specified variable into the database.
716720

717-
- `schlieren_alpha(i)` specifies the intensity of the numerical Schlieren of $i$-th component.
721+
- `schlieren_alpha(i)` specifies the intensity of the numerical Schlieren of $i$-th component. It must be specified for every fluid when `schlieren_wrt` is enabled.
718722

719723
- `fd_order` specifies the order of the finite difference scheme used to compute the vorticity from the velocity field and the numerical schlieren from the density field using an integer of 1, 2, and 4.
720724
`fd_order = 1`, `2`, and `4` correspond to the first, second, and fourth-order finite difference schemes.
721725

722726
- `probe_wrt` activates the output of state variables at coordinates specified by `probe(i)%[x;y,z]`.
723727

724-
- `ib_state_wrt` activates the output of data specified by patch_ib(i)%force(:) (and torque, vel, angular_vel, angles, [x,y,z]_centroid) into a single binary datafile for all IBs at all timesteps. During post_processing, this file is converted into separate time histories for each IB.
728+
- `ib_state_wrt` is used to trigger post-processing of the IB state to be written out as a point mesh in the SILO files. When no IBs are moving, it also triggers force and torque calculation so that those values may be written to the output state files.
725729

726730
- `output_partial_domain` activates the output of part of the domain specified by `[x,y,z]_output%%beg` and `[x,y,z]_output%%end`.
727731
This is useful for large domains where only a portion of the domain is of interest.

docs/module_categories.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"m_compute_cbc",
3939
"m_boundary_common",
4040
"m_ibm",
41+
"m_particle_bed",
4142
"m_igr",
4243
"m_ib_patches",
4344
"m_compute_levelset"
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import json
2+
import math
3+
4+
# 2D shock wave interacting with a bed of 20 free-floating circular particles.
5+
6+
gam_a = 1.4
7+
8+
# Shock parameters (Mach 1.5)
9+
mach_number = 1.5
10+
pre_shock_pressure = 1
11+
pre_shock_density = 1.4
12+
pre_shock_speed = 0.0
13+
post_shock_pressure = 2.4583
14+
post_shock_density = 2.6069
15+
post_shock_speed = 0.6944
16+
17+
domain_size = 4.0
18+
wave_front = -1.5
19+
20+
total_time = 1.5
21+
num_time_steps = 2000
22+
dt = float(total_time / num_time_steps)
23+
num_saves = 100
24+
steps_to_save = int(num_time_steps / num_saves)
25+
26+
# Soft-sphere collision parameters (from 3D_mibm_sphere_head_on_collision)
27+
collision_time = 20.0 * dt
28+
29+
# Particle bed parameters
30+
bed_x = 0.5
31+
bed_y = 0.0
32+
bed_lx = 2.0
33+
bed_ly = 3.5
34+
particle_radius = 0.15
35+
particle_mass = 0.25
36+
particle_min_spacing = 0.05
37+
38+
print(
39+
json.dumps(
40+
{
41+
# Logistics
42+
"run_time_info": "T",
43+
# Computational Domain Parameters
44+
"x_domain%beg": -domain_size * 0.5,
45+
"x_domain%end": domain_size * 0.5,
46+
"y_domain%beg": -domain_size * 0.5,
47+
"y_domain%end": domain_size * 0.5,
48+
"cyl_coord": "F",
49+
"m": 256,
50+
"n": 256,
51+
"p": 0,
52+
"dt": dt,
53+
"t_step_start": 0,
54+
"t_step_stop": num_time_steps,
55+
"t_step_save": steps_to_save,
56+
# Simulation Algorithm Parameters
57+
"num_patches": 2,
58+
"model_eqns": 2,
59+
"alt_soundspeed": "F",
60+
"num_fluids": 1,
61+
"mpp_lim": "F",
62+
"mixture_err": "T",
63+
"time_stepper": 3,
64+
"weno_order": 5,
65+
"weno_eps": 1.0e-16,
66+
"weno_Re_flux": "T",
67+
"weno_avg": "T",
68+
"avg_state": 2,
69+
"mapped_weno": "T",
70+
"null_weights": "F",
71+
"mp_weno": "T",
72+
"riemann_solver": 2,
73+
"wave_speeds": 1,
74+
"bc_x%beg": -17,
75+
"bc_x%end": -8,
76+
"bc_y%beg": -15,
77+
"bc_y%end": -15,
78+
# Immersed boundaries — all circles come from the particle bed
79+
"ib": "T",
80+
"num_ibs": 0,
81+
"viscous": "T",
82+
# Collision model (soft-sphere, from 3D_mibm_sphere_head_on_collision)
83+
"collision_model": 1,
84+
"coefficient_of_restitution": 0.9,
85+
"collision_time": collision_time,
86+
"ib_coefficient_of_friction": 0.1,
87+
# Particle bed: 20 free-floating circles placed randomly in region
88+
"num_particle_beds": 1,
89+
"particle_bed(1)%x_centroid": bed_x,
90+
"particle_bed(1)%y_centroid": bed_y,
91+
"particle_bed(1)%z_centroid": 0.0,
92+
"particle_bed(1)%length_x": bed_lx,
93+
"particle_bed(1)%length_y": bed_ly,
94+
"particle_bed(1)%length_z": 0.0,
95+
"particle_bed(1)%num_particles": 20,
96+
"particle_bed(1)%radius": particle_radius,
97+
"particle_bed(1)%mass": particle_mass,
98+
"particle_bed(1)%min_spacing": particle_min_spacing,
99+
"particle_bed(1)%moving_ibm": 2,
100+
"particle_bed(1)%seed": 42,
101+
# Output
102+
"format": 1,
103+
"precision": 2,
104+
"prim_vars_wrt": "T",
105+
"E_wrt": "T",
106+
"ib_state_wrt": "F",
107+
"parallel_io": "T",
108+
# IC Patch 1: post-shock region (left of wave front)
109+
"patch_icpp(1)%geometry": 3,
110+
"patch_icpp(1)%x_centroid": 0.5 * wave_front - 0.25 * domain_size,
111+
"patch_icpp(1)%y_centroid": 0.0,
112+
"patch_icpp(1)%length_x": 0.5 * domain_size + wave_front,
113+
"patch_icpp(1)%length_y": domain_size,
114+
"patch_icpp(1)%vel(1)": post_shock_speed,
115+
"patch_icpp(1)%vel(2)": 0.0,
116+
"patch_icpp(1)%pres": post_shock_pressure,
117+
"patch_icpp(1)%alpha_rho(1)": post_shock_density,
118+
"patch_icpp(1)%alpha(1)": 1.0,
119+
# IC Patch 2: pre-shock region (right of wave front)
120+
"patch_icpp(2)%geometry": 3,
121+
"patch_icpp(2)%x_centroid": 0.5 * wave_front + 0.25 * domain_size,
122+
"patch_icpp(2)%y_centroid": 0.0,
123+
"patch_icpp(2)%length_x": 0.5 * domain_size - wave_front,
124+
"patch_icpp(2)%length_y": domain_size,
125+
"patch_icpp(2)%vel(1)": pre_shock_speed,
126+
"patch_icpp(2)%vel(2)": 0.0,
127+
"patch_icpp(2)%pres": pre_shock_pressure,
128+
"patch_icpp(2)%alpha_rho(1)": pre_shock_density,
129+
"patch_icpp(2)%alpha(1)": 1.0,
130+
# Fluid properties: air
131+
"fluid_pp(1)%gamma": 1.0 / (gam_a - 1.0),
132+
"fluid_pp(1)%pi_inf": 0,
133+
"fluid_pp(1)%Re(1)": 2500000,
134+
}
135+
)
136+
)

examples/2D_mibm_shock_cylinder/case.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"precision": 2,
8888
"prim_vars_wrt": "T",
8989
"E_wrt": "T",
90-
"ib_state_wrt": "T",
90+
"ib_state_wrt": "F",
9191
"parallel_io": "T",
9292
# Patch: Constant Tube filled with air
9393
# Specify the cylindrical air tube grid geometry

src/common/include/case.fpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
! For pre-process.
66
#:def analytical()
7-
87
#:enddef
98

109
! For moving immersed boundaries in simulation
1110
#:def mib_analytical()
12-
1311
#:enddef

src/common/m_constants.fpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,20 @@ module m_constants
1616
real(wp), parameter :: verysmall = 1.e-12_wp !< Very small number
1717
!> Radius cutoff to avoid division by zero for 3D spherical harmonic patch (geometry 14)
1818
real(wp), parameter :: small_radius = 1.e-32_wp
19-
integer, parameter :: num_stcls_min = 5 !< Minimum # of stencils
20-
integer, parameter :: path_len = 400 !< Maximum path length
21-
integer, parameter :: name_len = 50 !< Maximum name length
22-
integer, parameter :: dflt_int = -100 !< Default integer value
23-
integer, parameter :: fourier_rings = 5 !< Fourier filter ring limit
24-
integer, parameter :: num_fluids_max = 10 !< Maximum number of fluids in the simulation
25-
integer, parameter :: num_probes_max = 10 !< Maximum number of flow probes in the simulation
26-
integer, parameter :: num_patches_max = 10 !< Maximum number of IC patches
27-
integer, parameter :: num_ib_patches_max = 50000 !< Maximum number of immersed boundary patches (patch_ib)
19+
integer, parameter :: num_stcls_min = 5 !< Minimum # of stencils
20+
integer, parameter :: path_len = 400 !< Maximum path length
21+
integer, parameter :: name_len = 50 !< Maximum name length
22+
integer, parameter :: dflt_int = -100 !< Default integer value
23+
integer, parameter :: fourier_rings = 5 !< Fourier filter ring limit
24+
integer, parameter :: num_fluids_max = 10 !< Maximum number of fluids in the simulation
25+
integer, parameter :: num_probes_max = 10 !< Maximum number of flow probes in the simulation
26+
integer, parameter :: num_patches_max = 10 !< Maximum number of IC patches
27+
!> Maximum number of immersed boundary patches (legacy, not used for patch_ib sizing)
28+
integer, parameter :: num_ib_patches_max = 2050000
29+
!> Fixed capacity of patch_ib (namelist patches + local particle bed subset after reduction)
30+
integer, parameter :: num_ib_patches_max_namelist = 54000
31+
integer, parameter :: num_local_ibs_max = 2000 !< Maximum number of immersed boundary patches (patch_ib)
32+
integer, parameter :: num_particle_beds_max = 10 !< Maximum number of particle bed patch specifications
2833
integer, parameter :: num_bc_patches_max = 10 !< Maximum number of boundary condition patches
2934
integer, parameter :: max_2d_fourier_modes = 10 !< Max Fourier mode index for 2D modal patch (geometry 13)
3035
integer, parameter :: max_sph_harm_degree = 5 !< Max degree L for 3D spherical harmonic patch (geometry 14)

0 commit comments

Comments
 (0)