`IBMStepper`: the IBM loop is not a fixed point iteration — `ibm_tolerance` cannot fire, and `ibm_relaxation`/`ibm_max_iterations` act as a forcing gain
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 50/100
Línea de trabajo
Comienza en xlb/operator/stepper/ibm_stepper.py, en warp_implementation, y sigue compute_velocity_and_correct, interpolate_velocity_and_update_force y correct_population_ibm para confirmar cómo cambian f_1 y lag_forces entre sweeps. Reproduce el residual y el comportamiento de las iteraciones reportados; después determina si el resultado previsto es una corrección iterativa o un forzado explícito documentado; se considera terminado cuando el comportamiento elegido y su semántica de tolerancia, relajación y número máximo de iteraciones estén cubiertos por la validación.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
In xlb/operator/stepper/ibm_stepper.py, the loop in warp_implementation never updates f_1. The only kernel that writes f_1 — correct_population_ibm — is launched once after the loop exits. As a result every sweep recomputes the same u from the same populations, so the loop does not converge in the sense the docstring describes.
This makes the documented behaviour
- Residual-based stopping instead of a fixed iteration count. The loop monitors the maximum incremental change in Lagrangian forces and stops early when it falls below
ibm_tolerance[...]
unreachable in practice.
Mechanism
Inside the loop:
compute_velocity_and_correctreadsf_1to getuand writeseul_velocities, but does not modifyf_1.interpolate_velocity_and_update_forceinterpolateseul_velocitiesback to the markers and doeslag_forces += v_solid - u_interp.
Since f_1 is unchanged, u is identical on every sweep, hence delta_F = v_solid - u_interp is identical on every sweep. Therefore:
lag_forcesafter sweepkis exactlyk * delta_F(a linear ramp)- the residual
|lag_forces - lag_forces_prev|equals|delta_F|— a constant
A constant residual can never cross a threshold it did not already satisfy on the first sweep.
Reproduction
A faithful 1-D transcription of the kernel sequence (Peskin weights, Voronoi areas, same spread/interpolate operators), omega=1.0, 6 sweeps:
residual : 1.00000 1.00000 1.00000 1.00000 1.00000 1.00000
|lag|max : 1.00000 2.00000 3.00000 4.00000 5.00000 6.00000
The residual is bit-for-bit constant; the accumulated force grows linearly.
We also instrumented the real Warp path on GPU and counted iterations: 100% of steps hit the ibm_max_iterations ceiling with the convergence flag still set, across two different resolutions and two different ibm_relaxation values (60 steps each). That matches the analysis.
Consequences
1. ibm_tolerance is effectively dead. The early exit never triggers; the loop always runs ibm_max_iterations times.
2. ibm_relaxation and ibm_max_iterations are a boundary forcing gain, not convergence controls. Working through the algebra, the correction applied after the loop is
eul_forces = omega * ( (n-1) * spread(delta_F)/weights - u )
so the gain on the target term is ibm_relaxation * (ibm_max_iterations - 1). Note the - 1: the final sweep spreads the forces accumulated by the previous sweep.
3. ibm_max_iterations = 1 silently drops the wall velocity entirely. With n = 1 the target gain is zero and only -omega * u is applied. For a static body that still drives u -> 0, which is the correct no-slip target, so it looks fine. For a moving body the prescribed surface velocity v_solid never enters the equations at all. This one is easy to miss because the static case masks it.
4. Stability. Because the scheme is an explicit forcing with gain rather than a contraction, the near-surface amplification factor flips sign and exceeds 1 as the gain rises. In our reference implementation, for a static body: omega=1.0, n=4 gives -2.61, omega=0.5 gives -0.805, omega=0.25 gives +0.098. We see the corresponding ordering in practice — at fine grid resolutions the run diverges at the higher gains and survives longer as the gain is lowered.
(The absolute numbers overstate the real amplification, since the reference implementation omits the collide/stream between corrections. The robust findings are the ordering and the sign flip.)
Suggested fix
Apply each sweep's correction to f_1 inside the loop, so the next sweep reads an updated u. Two details matter:
- spread the per-sweep increment, not the accumulated
lag_forces— the accumulated total is already baked intof_1by the previous sweeps' corrections, so spreading it again double-counts; - drop the
- uterm in the normalization for the same reason.
With that change the residual actually decreases, ibm_tolerance and the early exit become meaningful, and the surface correction is monotonically damping for 0 < ibm_relaxation <= 1 (no sign flip at any of the gains above).
We have implemented this in our fork behind an opt-in flag, keeping the current behaviour as the default so existing results stay reproducible. Happy to open a PR against main if that shape is useful to you — either the flag approach or a straight fix.
Environment
xlbmain(the code path above is unchanged as of today)- Warp backend, D3Q27,
warp-lang1.12.1
Alternative reading
If the current behaviour is intentional — i.e. this is meant to be a single explicit forcing step with a tunable gain rather than a multi-direct forcing iteration — then the fix is documentation rather than code: the ibm_tolerance parameter should be removed or marked non-functional, and the docstring's points (2) and (3) reworded, since ibm_relaxation and ibm_max_iterations are gain knobs. Either way the current docs describe behaviour the code does not have.
- Lenguaje dominante
- Python
- Estrellas
- 508
- Forks
- 85
- Merge medio
- 4 d 18 h
- PR fusionados (30 d)
- 1
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Autodesk/XLB
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
-
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
-
After new update the mesh will disappear in many cases ....Quizá libre de nuevo @hsalehipour la tomó hace 185 días y no hay ningún pull request abierto. Abierto
-
Request for the 2D "Flow over a cylinder" case from the reference paperQuizá libre de nuevo @hsalehipour la tomó hace 330 días y no hay ningún pull request abierto. Abierto
-
Extend neon/warp API interoperabilityQuizá libre de nuevo @massimim la tomó hace 488 días y no hay ningún pull request abierto. Abierto
Todos los issues de Autodesk/XLB
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
letsencrypt/cp-cps#353 ·
-
Marble Madness II is missingAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
PedestrianDynamics/pyFDS-Evac#394 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
DOI-USGS/pywatershed#421 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
python-pillow/Pillow#10087 · 1 comentario ·
Los mantenedores suelen responder en 1 día