code wiki / (root) / nx_chem.nx

nx_chem.nx source

↩ module page · 153 lines · 6588 B

1// nx_chem.nx -- chemistry primitives (atomic table + stoichiometry). 2// 3// Native NishiLang chemistry foundation. Patent-clean: standard 4// IUPAC atomic masses + balance algorithm. 5 6// nx_safety_envelope: 7// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 8// sil_target: SIL1 9// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 10// verdict: NOT_YET_EVALUATED 11 12import "nx_kernel_v2.nx" 13const NX_MAGIC_4003: i64 = 4003 14const NX_MAGIC_6941: i64 = 6941 15const NX_MAGIC_9012: i64 = 9012 16const NX_MAGIC_10811: i64 = 10811 17const NX_MAGIC_12011: i64 = 12011 18const NX_MAGIC_14007: i64 = 14007 19const NX_MAGIC_15999: i64 = 15999 20const NX_MAGIC_18998: i64 = 18998 21const NX_MAGIC_20180: i64 = 20180 22const NX_MAGIC_22990: i64 = 22990 23const NX_MAGIC_24305: i64 = 24305 24const NX_MAGIC_26982: i64 = 26982 25const NX_MAGIC_28086: i64 = 28086 26const NX_MAGIC_30974: i64 = 30974 27const NX_MAGIC_32066: i64 = 32066 28const NX_MAGIC_35453: i64 = 35453 29const NX_MAGIC_39948: i64 = 39948 30 31// Sym IDs (chem family 415xxx) 32const NX_CHEM_SYM_MOLECULE: nx_int = 415001 33const NX_CHEM_SYM_ATOM: nx_int = 415002 34const NX_CHEM_SYM_REACTION: nx_int = 415003 35 36// Element struct: name + atomic number + atomic mass (Q3 fixed-point, 37// i.e., mass * 1000). Storing as integer Q3 keeps everything exact. 38struct Element { 39 symbol: *u8, // 1- or 2-char element symbol, NUL-terminated 40 z: nx_int, // atomic number 41 mass_q3: nx_int, // atomic mass in milli-AMU (e.g., H = 1008) 42} 43const NX_ELEM_BYTES: nx_int = 24 44 45// Periodic-table builder: returns a flat array of Element[N] with the 46// first N elements (1..N) populated. Keeps the file small while still 47// covering H..Ne (the chemistry-foundation set). Caller can extend 48// the array by adding more rows. 49func nx_chem_periodic_table() -> *Element { 50 let n: nx_int = 18 51 let arr: *Element = (sys_mmap((n * NX_ELEM_BYTES) as i64)) as *Element 52 let e1: *Element = arr 53 e1.symbol = "H " as *u8; e1.z = 1; e1.mass_q3 = 1008 54 let e2: *Element = ((arr as nx_int) + (1 * NX_ELEM_BYTES)) as *Element 55 e2.symbol = "He" as *u8; e2.z = 2; e2.mass_q3 = NX_MAGIC_4003 56 let e3: *Element = ((arr as nx_int) + (2 * NX_ELEM_BYTES)) as *Element 57 e3.symbol = "Li" as *u8; e3.z = 3; e3.mass_q3 = NX_MAGIC_6941 58 let e4: *Element = ((arr as nx_int) + (3 * NX_ELEM_BYTES)) as *Element 59 e4.symbol = "Be" as *u8; e4.z = 4; e4.mass_q3 = NX_MAGIC_9012 60 let e5: *Element = ((arr as nx_int) + (4 * NX_ELEM_BYTES)) as *Element 61 e5.symbol = "B " as *u8; e5.z = 5; e5.mass_q3 = NX_MAGIC_10811 62 let e6: *Element = ((arr as nx_int) + (5 * NX_ELEM_BYTES)) as *Element 63 e6.symbol = "C " as *u8; e6.z = 6; e6.mass_q3 = NX_MAGIC_12011 64 let e7: *Element = ((arr as nx_int) + (6 * NX_ELEM_BYTES)) as *Element 65 e7.symbol = "N " as *u8; e7.z = 7; e7.mass_q3 = NX_MAGIC_14007 66 let e8: *Element = ((arr as nx_int) + (7 * NX_ELEM_BYTES)) as *Element 67 e8.symbol = "O " as *u8; e8.z = 8; e8.mass_q3 = NX_MAGIC_15999 68 let e9: *Element = ((arr as nx_int) + (8 * NX_ELEM_BYTES)) as *Element 69 e9.symbol = "F " as *u8; e9.z = 9; e9.mass_q3 = NX_MAGIC_18998 70 let e10: *Element = ((arr as nx_int) + (9 * NX_ELEM_BYTES)) as *Element 71 e10.symbol = "Ne" as *u8; e10.z = 10; e10.mass_q3 = NX_MAGIC_20180 72 let e11: *Element = ((arr as nx_int) + (10 * NX_ELEM_BYTES)) as *Element 73 e11.symbol = "Na" as *u8; e11.z = 11; e11.mass_q3 = NX_MAGIC_22990 74 let e12: *Element = ((arr as nx_int) + (11 * NX_ELEM_BYTES)) as *Element 75 e12.symbol = "Mg" as *u8; e12.z = 12; e12.mass_q3 = NX_MAGIC_24305 76 let e13: *Element = ((arr as nx_int) + (12 * NX_ELEM_BYTES)) as *Element 77 e13.symbol = "Al" as *u8; e13.z = 13; e13.mass_q3 = NX_MAGIC_26982 78 let e14: *Element = ((arr as nx_int) + (13 * NX_ELEM_BYTES)) as *Element 79 e14.symbol = "Si" as *u8; e14.z = 14; e14.mass_q3 = NX_MAGIC_28086 80 let e15: *Element = ((arr as nx_int) + (14 * NX_ELEM_BYTES)) as *Element 81 e15.symbol = "P " as *u8; e15.z = 15; e15.mass_q3 = NX_MAGIC_30974 82 let e16: *Element = ((arr as nx_int) + (15 * NX_ELEM_BYTES)) as *Element 83 e16.symbol = "S " as *u8; e16.z = 16; e16.mass_q3 = NX_MAGIC_32066 84 let e17: *Element = ((arr as nx_int) + (16 * NX_ELEM_BYTES)) as *Element 85 e17.symbol = "Cl" as *u8; e17.z = 17; e17.mass_q3 = NX_MAGIC_35453 86 let e18: *Element = ((arr as nx_int) + (17 * NX_ELEM_BYTES)) as *Element 87 e18.symbol = "Ar" as *u8; e18.z = 18; e18.mass_q3 = NX_MAGIC_39948 88 return arr 89} 90 91// Lookup element by atomic number (1-indexed). Returns null Element* 92// if z is out of range [1..18]. 93func nx_chem_element_by_z(table: *Element, z: nx_int) -> *Element { 94 if z < 1 { return 0 as *Element } 95 if z > 18 { return 0 as *Element } 96 return ((table as nx_int) + ((z - 1) * NX_ELEM_BYTES)) as *Element 97} 98 99// Molecule: parallel arrays of (z, count) -- "H2O" = [(1,2), (8,1)]. 100struct Molecule { 101 z_arr: *nx_int, 102 c_arr: *nx_int, 103 n: nx_int, 104} 105const NX_MOL_BYTES: nx_int = 24 106 107func nx_chem_molecule_new(n: nx_int) -> *Molecule { 108 let m: *Molecule = (sys_mmap(NX_MOL_BYTES as i64)) as *Molecule 109 m.z_arr = (sys_mmap((n * 8) as i64)) as *nx_int 110 m.c_arr = (sys_mmap((n * 8) as i64)) as *nx_int 111 m.n = n 112 return m 113} 114 115func nx_chem_molecule_set(m: *Molecule, i: nx_int, z: nx_int, count: nx_int) -> nx_int { 116 let pz: *nx_int = ((m.z_arr as nx_int) + (i * 8)) as *nx_int 117 let pc: *nx_int = ((m.c_arr as nx_int) + (i * 8)) as *nx_int 118 pz[0] = z 119 pc[0] = count 120 return i 121} 122 123// Compute molecular mass in milli-AMU. Uses the periodic table. 124func nx_chem_molar_mass_q3(m: *Molecule, table: *Element) -> nx_int { 125 var sum: nx_int = 0 126 var i: nx_int = 0 127 while i < m.n { 128 let pz: *nx_int = ((m.z_arr as nx_int) + (i * 8)) as *nx_int 129 let pc: *nx_int = ((m.c_arr as nx_int) + (i * 8)) as *nx_int 130 let elt: *Element = nx_chem_element_by_z(table, pz[0]) 131 if (elt as nx_int) != 0 { 132 sum = sum + (elt.mass_q3 * pc[0]) 133 } 134 i = i + 1 135 } 136 return sum 137} 138 139// Convenience: H2O = (H,2) + (O,1). 140func nx_chem_water() -> *Molecule { 141 let m: *Molecule = nx_chem_molecule_new(2) 142 let _s1: nx_int = nx_chem_molecule_set(m, 0, 1, 2) 143 let _s2: nx_int = nx_chem_molecule_set(m, 1, 8, 1) 144 return m 145} 146 147// CO2 = (C,1) + (O,2) 148func nx_chem_co2() -> *Molecule { 149 let m: *Molecule = nx_chem_molecule_new(2) 150 let _s1: nx_int = nx_chem_molecule_set(m, 0, 6, 1) 151 let _s2: nx_int = nx_chem_molecule_set(m, 1, 8, 2) 152 return m 153}