If you are on Linux and you get a core file you can try to use GDB to see what values are overflowing. But from your bug report I see you are on Windows where unfortunately the debugging support is lagging a bit. Your best bet is to add some “write” statements before the line that fails. The error message is telling you the overflow is at line 112 in usr1.f:
107 IF (Ep_g(local_in)==1) THEN
108 I_temp=Light_in*1
109 Inten(local_in,1)=I_temp
110 Light_in=I_temp
111 ELSE
112 I_temp=Light_in*att_ijk
113 Inten(local_in,1)=I_temp
114 Light_in=I_temp
So before line 112, add
write(*,*) "Light_in=", light_in, "att_ijk=", att_ijk
I also ran this by Claude (Opus 5) which found other problems. I cannot guarantee this is all correct but it looks right to me. (You don’t have to worry about item 3 if you’re not planning on running in DMP mode).
1. Wrong index, uninitialized variable (memory corruption)
IF (K_OF(IJK_2)<=nint(lamp_z)) THEN
att(local_in,1) = 1 ! <-- local_in, not IJK_2
local_in has no value at this point in the routine (it’s first assigned in the triple loop below, and it’s not SAVEd, so it’s indeterminate on every call). You’re writing 1 into att at a garbage index — out-of-bounds write, or silent clobbering of an unrelated cell.
Consequence twofold: att(IJK_2,1) is never set for the lamp region, so the following ReactionRates(IJK_2,1) = att(IJK_2,1) reads stale/uninitialized data.
2. Loop nesting defeats the ray march
Light_in is a running product carried across the entire triple loop, but the nesting is K outer, I, then J inner. For K > lamp_z the value arriving at cell (i,j,k) has been attenuated by every cell visited before it in scan order, not by the column above it. Beyond a few levels it underflows to zero.
The march has to be innermost in K, with the reset per column:
DO I_usr2 = Istart3, Iend3
DO J_usr2 = Jstart3, Jend3
Light_in = I_lamp
DO K_usr2 = Kstart3, Kend3
IF (DEAD_CELL_AT(I_usr2,J_usr2,K_usr2)) CYCLE
local_in = FUNIJK(I_usr2,J_usr2,K_usr2)
IF (K_usr2 > nint(lamp_z)) Light_in = Light_in * att(local_in,1)
Inten(local_in,1) = Light_in
ReactionRates(local_in,2) = Light_in
END DO
END DO
END DO
(The Ep_g==1 branch collapses out — it’s Light_in*1, and att is already 1.0 there.)
3. DMP-unsafe
Kstart3..Kend3 are rank-local. With any decomposition in z, each rank restarts its column at I_lamp and the attenuation accumulated upstream is lost — results depend on NODESK. There’s no communication here to fix that; the march either needs a serialized sweep along the z-pencil (send the exit intensity plane to the next rank up) or the decomposition has to be constrained to NODESK=1. Also, the loop includes ghost layers, so boundary cells get counted twice into the product.
4. att is a per-cell transmittance with no length in it
att = -6.0D-3 + Ep_g*ep_new2 is applied as a bare multiplicative factor per cell. That makes the total attenuation att**(number of cells) — refine DZ and the light profile changes completely. Beer–Lambert wants exp(-mu*DZ(K)) with mu an absorption coefficient in 1/m. As written, it’s not grid-convergent.
Related: nothing bounds att. Ep_g*ep_new2 - 0.006 can be negative (sign-flipping intensity) or, if ep_new2 > 1, greater than 1 (light amplifying downstream). Clamp to [0,1] at minimum.
5. Cell indices compared against physical coordinates
IF (J_OF(IJK_1)<=0.02)
J_OF returns the integer J index. Compared against 0.02, this is true only for J ≤ 0 — i.e. the ghost layer, never a real cell. Whoever wrote it meant a y-coordinate of 2 cm. You want the cell-center y (from YN/DY in geometry), not the index.
nint(lamp_z) is the same ambiguity in the other direction: if lamp_z is a height in meters, rounding it and comparing to K_OF is meaningless; if it’s meant to be a cell index it should be an integer in usr_mod. Worth resolving which it is before anything else here matters.
6. NaN masking
IF (Ep_g(IJK_1) /= Ep_g(IJK_1)) is a NaN test. Substituting a plausible-looking value for a NaN void fraction hides a solver failure rather than reporting it — the run continues producing garbage. Also, under -ffast-math / -ffinite-math-only gfortran is entitled to fold this to .FALSE., so the guard may not even exist in the optimized build. If you want the check, use IEEE_IS_NAN from IEEE_ARITHMETIC and call MFIX_EXIT on it.
7. Smaller items
IF (Ep_g(IJK_2)==1) — float equality. Use Ep_g >= ONE - SMALL_NUMBER.
DOUBLE PRECISION, DIMENSION(DIMENSION_3,1) :: my_epg — automatic array on the stack, sized by the full local grid, reallocated every time step. Make it rank-1, and either SAVEd/allocatable or module-level. The trailing ,1 extent serves no purpose.
ReactionRates(:,2) requires NRR >= 2 in the project file; silently out of bounds otherwise.
- Dead code:
local_in_prev, bjbjbj, I_temp (once the branch collapses), and the USE of ic, rxns, param.
- The two
IJKSTART3..IJKEND3 loops can be fused; my_epg doesn’t need to exist as an array at all if att is computed in one pass.
The two that will actually bite you today are #1 and #2. #3 is what will make the answer change when you switch node counts.
Final comments (from me, not Claude)
- Your indentation is a mess, it’s easier to read and debug code which is properly indented
- I could’t even run this case, I got this error before any overflow:
Error from check_data/check_bc_geometry.f:350
Error 1100: Invalid location specified for BC 14.
X: 0.35000E-02, 0.66500E-01 I: 6, 68
Y: -0.50000E-02, 0.75000E-01 J: 2, -1
Z: 0.0000 , 0.0000 K: 1, 1
This usually occurs when the BC region is outside the fluid region,
or when the BC region is smaller than the grid spacing.
Fatal error reported on one or more processes. The .LOG file
may contain additional information about the failure.
Hope this helps,
– Charles