code wiki / (root) / nx_chem_isotope_pattern_test.nx

nx_chem_isotope_pattern_test.nx source

↩ module page · 239 lines · 9869 B

1// nx_chem_isotope_pattern_test.nx -- C2.8b KAT. 2// 3// All M+1/M+2 reference values from textbook + IUPAC 2021 abundances. 4// First-order linear approximation -- KATs use single-halogen molecules 5// where first-order is accurate to within rounding. 6// 7// expect_exit: 0 8// license_tier: ORIGINAL 9 10import "nx_chem.nx" 11import "nx_chem_molecule.nx" 12import "nx_chem_smiles.nx" 13import "nx_chem_valence.nx" 14import "nx_chem_isotope_pattern.nx" 15 16func parse_with_h(src: *u8, n: nx_int) -> *MolGraph { 17 let m: *MolGraph = nx_chem_parse_smiles(src, n) 18 let _f: nx_int = nx_chem_compute_implicit_h(m) 19 return m 20} 21 22// ================================================================= 23// A -- water "O" 24// Atoms: 1 O + 2 H (implicit) 25// M+1 = 2*2 (H) + 1*4 (O) = 4 + 4 = 8 (0.08% of M) 26// M+2 = 1*21 (O) = 21 (0.21% of M) 27// ================================================================= 28func a_water() -> nx_int { 29 let s: *u8 = sys_mmap(8); s[0] = 0x4F 30 let m: *MolGraph = parse_with_h(s, 1) 31 let m1: nx_int = nx_chem_isotope_m1_q4(m) 32 let m2: nx_int = nx_chem_isotope_m2_q4(m) 33 if m1 != 8 { return 11 } 34 if m2 != 21 { return 12 } 35 return 0 36} 37 38// ================================================================= 39// B -- methane "C" 40// 1 C + 4 H. M+1 = 108 + 4*2 = 116 (1.16% of M). M+2 = 0. 41// ================================================================= 42func b_methane() -> nx_int { 43 let s: *u8 = sys_mmap(8); s[0] = 0x43 44 let m: *MolGraph = parse_with_h(s, 1) 45 let m1: nx_int = nx_chem_isotope_m1_q4(m) 46 let m2: nx_int = nx_chem_isotope_m2_q4(m) 47 if m1 != 116 { return 21 } 48 if m2 != 0 { return 22 } 49 return 0 50} 51 52// ================================================================= 53// C -- ethanol "CCO" 54// 2 C + 6 H + 1 O. M+1 = 2*108 + 6*2 + 1*4 = 216+12+4 = 232 (2.32%) 55// M+2 = 1*21 = 21 56// ================================================================= 57func c_ethanol() -> nx_int { 58 let s: *u8 = sys_mmap(8); s[0] = 0x43; s[1] = 0x43; s[2] = 0x4F 59 let m: *MolGraph = parse_with_h(s, 3) 60 let m1: nx_int = nx_chem_isotope_m1_q4(m) 61 let m2: nx_int = nx_chem_isotope_m2_q4(m) 62 if m1 != 232 { return 31 } 63 if m2 != 21 { return 32 } 64 return 0 65} 66 67// ================================================================= 68// D -- benzene "c1ccccc1" 69// 6 C + 6 H. M+1 = 6*108 + 6*2 = 648+12 = 660 (6.60%). M+2 = 0. 70// (Each aromatic c gets 1 H from compute_implicit_h) 71// ================================================================= 72func d_benzene() -> nx_int { 73 let s: *u8 = sys_mmap(16) 74 s[0] = 0x63; s[1] = 0x31 75 s[2] = 0x63; s[3] = 0x63 76 s[4] = 0x63; s[5] = 0x63 77 s[6] = 0x63; s[7] = 0x31 78 let m: *MolGraph = parse_with_h(s, 8) 79 let m1: nx_int = nx_chem_isotope_m1_q4(m) 80 let m2: nx_int = nx_chem_isotope_m2_q4(m) 81 if m1 != 660 { return 41 } 82 if m2 != 0 { return 42 } 83 return 0 84} 85 86// ================================================================= 87// E -- chloromethane "CCl" -> "C[Cl]" tricky, use bracket 88// Atoms: 1 C + 3 H + 1 Cl. 89// Wait -- C with one Cl substituent: valence_bits gets 1 from C-Cl 90// bond; CH3Cl => h_count=3. 91// M+1 = 1*108 + 3*2 + 0 = 114 (1.14% of M) 92// M+2 = 1*3196 (Cl) = 3196 (31.96% of M) -- the classic 3:1 Cl signature! 93// ================================================================= 94func e_chloromethane() -> nx_int { 95 let s: *u8 = sys_mmap(16) 96 s[0] = 0x43; s[1] = 0x43; s[2] = 0x6C // "CCl" 97 let m: *MolGraph = parse_with_h(s, 3) 98 let m1: nx_int = nx_chem_isotope_m1_q4(m) 99 let m2: nx_int = nx_chem_isotope_m2_q4(m) 100 if m1 != 114 { return 51 } 101 if m2 != 3196 { return 52 } 102 return 0 103} 104 105// ================================================================= 106// F -- bromomethane "CBr" 107// 1 C + 3 H + 1 Br. M+1 = 1*108 + 3*2 = 114. M+2 = 9728 (97.28%) -- the classic 1:1 Br signature! 108// ================================================================= 109func f_bromomethane() -> nx_int { 110 let s: *u8 = sys_mmap(16) 111 s[0] = 0x43; s[1] = 0x42; s[2] = 0x72 // "CBr" 112 let m: *MolGraph = parse_with_h(s, 3) 113 let m1: nx_int = nx_chem_isotope_m1_q4(m) 114 let m2: nx_int = nx_chem_isotope_m2_q4(m) 115 if m1 != 114 { return 61 } 116 if m2 != 9728 { return 62 } 117 return 0 118} 119 120// ================================================================= 121// G -- methylamine "CN" 122// 1 C + 5 H + 1 N. M+1 = 108 + 5*2 + 37 = 155 (1.55%). M+2 = 0. 123// ================================================================= 124func g_methylamine() -> nx_int { 125 let s: *u8 = sys_mmap(8); s[0] = 0x43; s[1] = 0x4E 126 let m: *MolGraph = parse_with_h(s, 2) 127 let m1: nx_int = nx_chem_isotope_m1_q4(m) 128 let m2: nx_int = nx_chem_isotope_m2_q4(m) 129 if m1 != 155 { return 71 } 130 if m2 != 0 { return 72 } 131 return 0 132} 133 134// ================================================================= 135// H -- methanethiol "CS" 136// 1 C + 4 H + 1 S. M+1 = 108 + 4*2 + 79 = 195. M+2 = 1*447 = 447 (4.47%) 137// ================================================================= 138func h_methanethiol() -> nx_int { 139 let s: *u8 = sys_mmap(8); s[0] = 0x43; s[1] = 0x53 140 let m: *MolGraph = parse_with_h(s, 2) 141 let m1: nx_int = nx_chem_isotope_m1_q4(m) 142 let m2: nx_int = nx_chem_isotope_m2_q4(m) 143 if m1 != 195 { return 81 } 144 if m2 != 447 { return 82 } 145 return 0 146} 147 148// ================================================================= 149// I -- halogen signature: water -> 0 (no Cl, no Br) 150// ================================================================= 151func i_water_signature() -> nx_int { 152 let s: *u8 = sys_mmap(8); s[0] = 0x4F 153 let m: *MolGraph = parse_with_h(s, 1) 154 if nx_chem_halogen_signature(m) != 0 { return 91 } 155 return 0 156} 157 158// ================================================================= 159// J -- chloromethane -> 1 (single Cl, 3:1 signature) 160// ================================================================= 161func j_cl_signature() -> nx_int { 162 let s: *u8 = sys_mmap(8); s[0] = 0x43; s[1] = 0x43; s[2] = 0x6C 163 let m: *MolGraph = parse_with_h(s, 3) 164 if nx_chem_halogen_signature(m) != 1 { return 101 } 165 return 0 166} 167 168// ================================================================= 169// K -- bromomethane -> 2 (single Br, 1:1 signature) 170// ================================================================= 171func k_br_signature() -> nx_int { 172 let s: *u8 = sys_mmap(8); s[0] = 0x43; s[1] = 0x42; s[2] = 0x72 173 let m: *MolGraph = parse_with_h(s, 3) 174 if nx_chem_halogen_signature(m) != 2 { return 111 } 175 return 0 176} 177 178func main() -> nx_exit { 179 println("=== nx_chem_isotope_pattern -- C2.8b KAT: M+1 / M+2 pattern + halogen signatures ===" as *u8) 180 181 let ra: nx_int = a_water() 182 if ra != 0 { println("A water FAIL" as *u8); return ra } 183 println("A water PASS M+1=8/10000 (0.08%) M+2=21/10000 (0.21%)" as *u8) 184 185 let rb: nx_int = b_methane() 186 if rb != 0 { println("B methane FAIL" as *u8); return rb } 187 println("B methane PASS M+1=116/10000 (1.16% -- one C-13 + 4 H-2 contrib)" as *u8) 188 189 let rc: nx_int = c_ethanol() 190 if rc != 0 { println("C ethanol FAIL" as *u8); return rc } 191 println("C ethanol PASS M+1=232 (2.32%) M+2=21" as *u8) 192 193 let rd: nx_int = d_benzene() 194 if rd != 0 { println("D benzene FAIL" as *u8); return rd } 195 println("D benzene PASS M+1=660 (6.60% -- 6 C-13)" as *u8) 196 197 let re: nx_int = e_chloromethane() 198 if re != 0 { println("E chloromethane FAIL" as *u8); return re } 199 println("E chloromethane PASS M+1=114 M+2=3196 (31.96% -- classic Cl 3:1)" as *u8) 200 201 let rf: nx_int = f_bromomethane() 202 if rf != 0 { println("F bromomethane FAIL" as *u8); return rf } 203 println("F bromomethane PASS M+1=114 M+2=9728 (97.28% -- classic Br 1:1)" as *u8) 204 205 let rg: nx_int = g_methylamine() 206 if rg != 0 { println("G methylamine FAIL" as *u8); return rg } 207 println("G methylamine PASS M+1=155 (incl 15-N contribution)" as *u8) 208 209 let rh: nx_int = h_methanethiol() 210 if rh != 0 { println("H methanethiol FAIL" as *u8); return rh } 211 println("H methanethiol PASS M+1=195 M+2=447 (4.47% -- 34-S signature)" as *u8) 212 213 let ri: nx_int = i_water_signature() 214 if ri != 0 { println("I water signature FAIL" as *u8); return ri } 215 println("I water signature PASS 0 = no halogen" as *u8) 216 217 let rj: nx_int = j_cl_signature() 218 if rj != 0 { println("J Cl signature FAIL" as *u8); return rj } 219 println("J Cl signature PASS 1 = single Cl, 3:1 M:M+2 signature" as *u8) 220 221 let rk: nx_int = k_br_signature() 222 if rk != 0 { println("K Br signature FAIL" as *u8); return rk } 223 println("K Br signature PASS 2 = single Br, 1:1 M:M+2 signature" as *u8) 224 225 println("" as *u8) 226 println("=== C2.8b substrate milestone PASS ===" as *u8) 227 println(" isotope_m1_q4 : Q4 fraction-of-M for M+1 peak (first-order linear sum)" as *u8) 228 println(" isotope_m2_q4 : Q4 fraction-of-M for M+2 peak (first-order linear sum)" as *u8) 229 println(" halogen_signature : 0=none, 1=single Cl (3:1), 2=single Br (1:1), 3=multi/mixed" as *u8) 230 println(" Direct supplement-arc adulterant-class identifier from MS spectrum" as *u8) 231 println(" (sibutramine sig=1, 4-bromosalbutamol sig=2, etc.)" as *u8) 232 println(" honest gaps : multi-halogen binomial expansion (C2.8b.1)," as *u8) 233 println(" M+3 / M+4 peaks (C2.8b.2)," as *u8) 234 println(" convolution-style envelope a la BRAIN (C2.8c)" as *u8) 235 println(" composes : C1 AtomicData (z field per atom; iso_abund_ppm reserved for" as *u8) 236 println(" future binomial / convolution implementations)" as *u8) 237 println(" C2.0 MolGraph + C2.3a implicit-H (counts h_count for H total)" as *u8) 238 return 0 239}