nx_supplement_csv.nx source
↩ module page · 86 lines · 3060 B
1// nx_supplement_csv.nx -- C6.1 CLI variant emitting CSV instead of JSON.
2//
3// For lab analysts who work in Excel rather than LIMS.
4//
5// USAGE:
6// nx_supplement_csv <cal-file-or-dash> <peak1> [peak2] ...
7//
8// OUTPUT:
9// One CSV header line, then one row per match across all samples.
10// Pipe directly to file -> open in Excel.
11//
12// EXIT CODE:
13// Total banned detections across all samples.
14
15import "nx_chem.nx"
16import "nx_chem_molecule.nx"
17import "nx_chem_smiles.nx"
18import "nx_chem_periodic.nx"
19import "nx_chem_valence.nx"
20import "nx_chem_mass.nx"
21import "nx_chem_isotope_pattern.nx"
22import "nx_chem_adulterant_db.nx"
23import "nx_chem_peak_list.nx"
24import "nx_chem_report_json.nx"
25import "nx_chem_report_csv.nx"
26
27func process_one_csv(db: *AdulterantDB, peak_path: *u8) -> nx_int {
28 let pl: *PeakList = nx_chem_peak_list_read_file(peak_path)
29 if pl.n == 0 { return 0 }
30 let sample_id: *u8 = sys_mmap(256)
31 let _bn: nx_int = nx_chem_basename(peak_path, sample_id)
32 let buf: *u8 = sys_mmap(32768)
33 let n: nx_int = nx_chem_emit_report_csv_rows_only(buf, pl, db, sample_id, 5)
34 let _w: i64 = sys_write(1, buf, n as i64)
35 // Count banned
36 var n_banned: nx_int = 0
37 var pi: nx_int = 0
38 while pi < pl.n {
39 let p: *PeakObservation = ((pl.peaks as nx_int) + (pi * NX_PEAK_OBS_BYTES)) as *PeakObservation
40 let outs: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult
41 let nm: nx_int = nx_chem_adulterant_db_lookup_with_rt(db, p.mz_q4, p.rt_q3, 5, outs, 4)
42 var mi: nx_int = 0
43 while mi < nm {
44 let rr: *MatchResult = ((outs as nx_int) + (mi * NX_MATCH_RESULT_BYTES)) as *MatchResult
45 let ee: *AdulterantEntry = nx_chem_adulterant_entry_by_id(db, rr.entry_id)
46 if ee.regulatory == NX_REG_BANNED { n_banned = n_banned + 1 }
47 mi = mi + 1
48 }
49 pi = pi + 1
50 }
51 return n_banned
52}
53
54func main(argc: i64, argv: *i64) -> i64 {
55 if argc < 3 {
56 let msg: *u8 = "nx_supplement_csv: usage: <cal-file-or-dash> <peak1> [peak2] ...\n" as *u8
57 var n: i64 = 0
58 while msg[n] != 0 { n = n + 1 }
59 let _w: i64 = sys_write(2, msg, n)
60 return 1
61 }
62 let db: *AdulterantDB = nx_chem_adulterant_db_seed()
63 let cal_path: *u8 = argv[1] as *u8
64 let cal_first: nx_int = cal_path[0] as nx_int
65 if cal_first != 45 {
66 let _n: nx_int = nx_chem_load_rt_calibration(db, cal_path)
67 }
68 if cal_first == 45 {
69 if cal_path[1] as nx_int != 0 {
70 let _n: nx_int = nx_chem_load_rt_calibration(db, cal_path)
71 }
72 }
73 // Emit header once at the start
74 let hbuf: *u8 = sys_mmap(256)
75 let nh: nx_int = nx_chem_emit_csv_header(hbuf, 0)
76 let _wh: i64 = sys_write(1, hbuf, nh as i64)
77 var total_banned: i64 = 0
78 var i: i64 = 2
79 while i < argc {
80 let peak_path: *u8 = argv[i] as *u8
81 let b: nx_int = process_one_csv(db, peak_path)
82 total_banned = total_banned + (b as i64)
83 i = i + 1
84 }
85 return total_banned
86}