code wiki / _hdl_build / nx_atm_trans_gate.nx

nx_atm_trans_gate.nx source

↩ module page · 120 lines · 5657 B

1// nx_atm_trans_gate.nx -- GATE for the nx_atmosphere transmittance rung (2026-08-26). 2// Accept rule, PRE-DECLARED (before the lib compiled): the i64 march must reproduce the 3// 20,000-sample double-precision reference (computed from the same [bytes] medium table, 4// knowledge/library/sky_volumetrics_impl_spec_2026-08-26.md) within +-64 q16 at four KAT 5// angles; expneg must match exp() KATs; ozone tent endpoints exact; transmittance monotone 6// in mu; and a single-species control must DIVERGE from the KATs, proving they discriminate 7// the full medium. license_tier: ORIGINAL No hw writes (Rule 26). 8import "nx_syscalls.nx" 9import "nx_atmosphere.nx" 10import "nx_gate_verdict.nx" 11 12const XT_TOL: i64 = 64 13// double-reference KATs, r = Rb, computed 2026-08-26 (20k-sample midpoint, same constants) 14const XT_Z_R: i64 = 61627 15const XT_Z_G: i64 = 56860 16const XT_Z_B: i64 = 49959 17const XT_M5_R: i64 = 57985 18const XT_M5_G: i64 = 49405 19const XT_M5_B: i64 = 38160 20const XT_S_R: i64 = 26627 21const XT_S_G: i64 = 8647 22const XT_S_B: i64 = 1059 23const XT_H_R: i64 = 6975 24const XT_H_G: i64 = 628 25const XT_H_B: i64 = 3 26 27func xt_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 28 29func xt_kat(mu_q16: i64, kr: i64, kg: i64, kb: i64, buf: *i64) -> i64 { 30 atm_trans_q16(ATM_RB_Q16, mu_q16, buf) 31 gv_puts(" mu_q16=" as *u8); gv_num(mu_q16) 32 gv_puts(" got=" as *u8); gv_num(buf[0]); gv_puts("/" as *u8); gv_num(buf[1]); gv_puts("/" as *u8); gv_num(buf[2]) 33 gv_puts(" ref=" as *u8); gv_num(kr); gv_puts("/" as *u8); gv_num(kg); gv_puts("/" as *u8); gv_num(kb); gv_puts("\n" as *u8) 34 if xt_abs(buf[0] - kr) > XT_TOL { return 0 } 35 if xt_abs(buf[1] - kg) > XT_TOL { return 0 } 36 if xt_abs(buf[2] - kb) > XT_TOL { return 0 } 37 return 1 38} 39 40func main() -> i64 { 41 let ctr: *i64 = gv_ctr() 42 let buf: *i64 = sys_mmap(64 * 8) as *i64 43 44 // T1 expneg KATs vs exp(): e^-1=24109, e^-2=8869, e^-8=22 (q16), e^-0=Q 45 var t1: i64 = 1 46 if atm_expneg_q16(0) != 65536 { t1 = 0 } 47 if xt_abs(atm_expneg_q16(65536) - 24109) > 40 { t1 = 0 } 48 if xt_abs(atm_expneg_q16(131072) - 8869) > 24 { t1 = 0 } 49 if xt_abs(atm_expneg_q16(524288) - 22) > 4 { t1 = 0 } 50 gv_check("T1 EXPNEG KATs: e^-1, e^-2, e^-8 match exp() within the named Taylor bound" as *u8, t1, ctr) 51 52 // T2 ozone tent endpoints: 0 at 10 km and 40 km, Q at 25 km 53 var t2: i64 = 1 54 if atm_dens_q16(2, 655360) > 66 { t2 = 0 } 55 if atm_dens_q16(2, 2621440) > 66 { t2 = 0 } 56 if xt_abs(atm_dens_q16(2, 1638400) - 65536) > 66 { t2 = 0 } 57 gv_check("T2 OZONE TENT: zero at 10/40 km, unity at the 25 km peak -- the fixture reaches the condition" as *u8, t2, ctr) 58 59 // T3..T6 transmittance KATs at four angles 60 gv_check("T3 KAT zenith mu=1: i64 march matches the 20k-sample double reference within 64 q16" as *u8, xt_kat(65536, XT_Z_R, XT_Z_G, XT_Z_B, buf), ctr) 61 gv_check("T4 KAT mu=0.5" as *u8, xt_kat(32768, XT_M5_R, XT_M5_G, XT_M5_B, buf), ctr) 62 gv_check("T5 KAT sunset mu=0.05: the 25:1 R:B ratio the page reddening derives from" as *u8, xt_kat(3277, XT_S_R, XT_S_G, XT_S_B, buf), ctr) 63 gv_check("T6 KAT horizon mu=0" as *u8, xt_kat(0, XT_H_R, XT_H_G, XT_H_B, buf), ctr) 64 65 // T7 monotone in mu: T rises with mu for each channel over a sweep 66 var t7: i64 = 1 67 var prevR: i64 = 0 - 1 68 var prevG: i64 = 0 - 1 69 var prevB: i64 = 0 - 1 70 var m9: i64 = 0 71 while m9 <= 65536 { 72 atm_trans_q16(ATM_RB_Q16, m9, buf) 73 if buf[0] < prevR { t7 = 0 } 74 if buf[1] < prevG { t7 = 0 } 75 if buf[2] < prevB { t7 = 0 } 76 prevR = buf[0]; prevG = buf[1]; prevB = buf[2] 77 m9 = m9 + 4096 78 } 79 gv_check("T7 MONOTONE: transmittance is non-decreasing in mu on every channel" as *u8, t7, ctr) 80 81 // T8 determinism 82 var t8: i64 = 1 83 atm_trans_q16(ATM_RB_Q16, 3277, buf) 84 let a0: i64 = buf[0] 85 atm_trans_q16(ATM_RB_Q16, 3277, buf) 86 if buf[0] != a0 { t8 = 0 } 87 gv_check("T8 DETERMINISM: same inputs, same bytes" as *u8, t8, ctr) 88 89 // T9 neg-control: a rayleigh-only tau at zenith green must DIVERGE from the full-medium KAT 90 // by far more than the tolerance -- the KATs discriminate the 3-species medium, not just shape. 91 var i9: i64 = 0 92 var tauG9: i64 = 0 93 let dt9: i64 = 5242880 / 500 94 while i9 < 500 { 95 let h9: i64 = i9 * dt9 + dt9 / 2 96 tauG9 = tauG9 + ((ATM_SRAY_G_Q24 * atm_dens_q16(0, h9)) / 65536 * dt9) / 65536 97 i9 = i9 + 1 98 } 99 let gOnly: i64 = atm_expneg_q16(tauG9 / 256) 100 gv_puts(" rayleigh-only zenith G=" as *u8); gv_num(gOnly) 101 gv_puts(" full-medium ref=" as *u8); gv_num(XT_Z_G); gv_puts("\n" as *u8) 102 var t9: i64 = 0 103 if xt_abs(gOnly - XT_Z_G) > 1000 { t9 = 1 } 104 gv_check("T9 neg-control-single-species-diverges: dropping mie+ozone moves zenith G by >1000 q16, so a wrong medium cannot pass the KATs" as *u8, t9, ctr) 105 106 // T10 sun LUT bake: row 0 near horizon KAT, last row near zenith KAT, rows monotone in R 107 let lut: *i64 = sys_mmap(ATM_SUNLUT_N * 24) as *i64 108 atm_bake_sun_lut(lut) 109 var t10: i64 = 1 110 if xt_abs(lut[0] - XT_H_R) > 128 { t10 = 0 } 111 if xt_abs(lut[(ATM_SUNLUT_N - 1) * 3] - XT_Z_R) > 128 { t10 = 0 } 112 var r10: i64 = 1 113 while r10 < ATM_SUNLUT_N { 114 if lut[r10 * 3] < lut[(r10 - 1) * 3] { t10 = 0 } 115 r10 = r10 + 1 116 } 117 gv_check("T10 SUN LUT: 64 rows bracket the horizon and zenith KATs (offset-radius tolerance 128) and rise monotonically" as *u8, t10, ctr) 118 119 return gv_verdict("ATMTRANS" as *u8, ctr, "the transmittance rung: i64 3-species Beer-Lambert march reproducing the double reference at pre-declared KATs, with a diverging single-species control" as *u8) 120}