code wiki / _hdl_build / nx_fluid_gate.nx

nx_fluid_gate.nx source

↩ module page · 113 lines · 5590 B

1// nx_fluid_gate.nx -- ★R6: the height-field FLUID SIMULATION, proven by physics (not "pixels moved"): 2// T1 PROPAGATION: a drop's wavefront radius GROWS over steps (waves travel at finite speed; not static, not instant) 3// T2 ★CONSERVATION: total volume sum(h) is invariant across the sim (mass conservation = the correct-integrator test) 4// T3 REFLECTION + DAMPING: the wave reaches a far boundary (propagation across the domain) AND peak |h| decays 5// over long time (energy dissipates) -- and it stays BOUNDED (no blow-up = numerically stable) 6// T4 determinism + animation strip knowledge/nx_fluid.png (a drop rippling + reflecting across 5 frames) 7// license_tier: ORIGINAL expect_exit: 0 8import "nx_syscalls.nx" 9import "nx_png.nx" 10import "nx_fluid.nx" 11 12func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 } 14func iabs(v: i64) -> i64 { if v<0 {return 0-v} return v } 15 16func main() -> i64 { 17 hw("=== nx_fluid_gate -- R6: height-field wave simulation, physics-verified ===\n" as *u8) 18 var fails: i64 = 0 19 let N: i64 = fl_n() 20 let cx: i64 = N/2; let cy: i64 = N/2 21 fl_init() 22 fl_drop(cx, cy, 12, 60000) 23 24 let vol0: i64 = fl_volume() 25 // step, sampling wavefront radius, volume, peak-amplitude, and a boundary probe 26 var r_early: i64 = 0 27 var r_late: i64 = 0 28 var volmin: i64 = vol0 29 var volmax: i64 = vol0 30 var reached_edge: i64 = 0 31 var amp_early: i64 = 0 32 var amp_late: i64 = 0 33 var amp_max: i64 = fl_maxabs() 34 var s: i64 = 0 35 while s < 420 { 36 fl_step() 37 let vv: i64 = fl_volume() 38 if vv < volmin { volmin = vv } 39 if vv > volmax { volmax = vv } 40 let ma: i64 = fl_maxabs() 41 if ma > amp_max { amp_max = ma } 42 if s == 5 { amp_early = ma } 43 if s == 400 { amp_late = ma } 44 if s == 40 { r_early = fl_front(cx, cy, 400) } 45 if s == 150 { r_late = fl_front(cx, cy, 400) } 46 if reached_edge == 0 { 47 var e: i64 = 1 48 while e < N-1 { 49 if iabs(fl_h(e, 2)) > 300 { reached_edge = 1; e = N } 50 else { if iabs(fl_h(2, e)) > 300 { reached_edge = 1; e = N } else { e = e + 1 } } 51 } 52 } 53 s = s + 1 54 } 55 let voldrift: i64 = iabs(volmax - volmin) 56 let voltol: i64 = iabs(vol0)/100 + 1000 // <1% of the drop volume 57 let amp0: i64 = fl_maxabs() // (unused ref) 58 hw(" propagation: front r@40="); pn(r_early); hw(" r@150="); pn(r_late); hw("\n" as *u8) 59 hw(" conservation: vol0="); pn(vol0); hw(" drift="); pn(voldrift); hw(" (tol "); pn(voltol); hw(")\n" as *u8) 60 hw(" amplitude: early="); pn(amp_early); hw(" late="); pn(amp_late); hw(" max-ever="); pn(amp_max); hw(" reached-edge="); pn(reached_edge); hw("\n" as *u8) 61 62 var t1: i64 = 0 63 if r_late > r_early + 5 { if r_early > 0 { t1 = 1 } } 64 if t1 == 1 { hw("T1 PASS PROPAGATION: the wavefront travels outward at finite speed\n" as *u8) } 65 else { fails=fails+1; hw("T1 FAIL propagation\n" as *u8) } 66 67 var t2: i64 = 0 68 if voldrift < voltol { t2 = 1 } 69 if t2 == 1 { hw("T2 PASS CONSERVATION: total volume is invariant (correct fluid integrator)\n" as *u8) } 70 else { fails=fails+1; hw("T2 FAIL volume drifts\n" as *u8) } 71 72 var t3: i64 = 0 73 // peak amplitude decays (spreading + damping) and never blows up past the initial drop 74 if reached_edge == 1 { if amp_late*2 < amp_early { if amp_max < amp_early*3 { t3 = 1 } } } 75 if t3 == 1 { hw("T3 PASS REFLECTION+DAMPING: wave crosses the domain, peak amplitude decays, stays bounded\n" as *u8) } 76 else { fails=fails+1; hw("T3 FAIL energy behaviour\n" as *u8) } 77 78 // T4 determinism: re-run the same sim, compare the height field 79 let Hs: i64 = fl_h(cx+20, cy) // a probe value from run 1 (post-420 steps) 80 fl_init() 81 fl_drop(cx, cy, 12, 60000) 82 var s2: i64 = 0 83 while s2 < 420 { fl_step(); s2 = s2 + 1 } 84 var det: i64 = 0 85 if fl_h(cx+20, cy) == Hs { det = 1 } 86 var t4: i64 = 0 87 if det == 1 { t4 = 1 } 88 if t4 == 1 { hw("T4 PASS deterministic\n" as *u8) } 89 else { fails=fails+1; hw("T4 FAIL nondeterministic\n" as *u8) } 90 91 // animation strip: fresh drop, render 5 frames as it ripples + reflects 92 fl_init() 93 fl_drop(cx, cy, 12, 60000) 94 let TW: i64 = 300; let TH: i64 = 300 95 let strip: *i64 = sys_mmap(TW*5*TH*8) as *i64 96 let fb: *i64 = sys_mmap(TW*TH*8) as *i64 97 var fr: i64 = 0 98 while fr < 5 { 99 fl_render(fb, TW, TH, 420, 620, 380) 100 var y: i64 = 0 101 while y < TH { var x: i64=0; while x<TW { strip[y*(TW*5)+fr*TW+x] = fb[y*TW+x]; x=x+1 } y=y+1 } 102 var st: i64 = 0 103 while st < 55 { fl_step(); st = st + 1 } 104 fr = fr + 1 105 } 106 write_png(strip, TW*5, TH, "knowledge/nx_fluid.png" as *u8) 107 hw("T5 animation strip -> knowledge/nx_fluid.png (a drop rippling + reflecting, 5 frames)\n" as *u8) 108 109 if fails == 0 { hw("FLUID-GATE GREEN -- R6: a height-field wave simulation (propagating, volume-conserving, reflecting, damped, stable, deterministic) = real fluid sim, sovereign + integer. Residual vs FLIP: particle splashes/breaking waves.\n" as *u8); sys_exit(0); return 0 } 110 hw("FLUID-GATE RED fails="); pn(fails); hw("\n" as *u8) 111 sys_exit(1) 112 return 1 113}