nx_estimate_test.nx source
↩ module page · 95 lines · 4200 B
1// nx_estimate_test.nx -- pre-print estimate sanity checks against
2// hand-computed expected ranges.
3//
4// Test inputs: tetrahedron at edge=10mm (Q14 = 10*16384=163840),
5// Qidi X-Max 3 + Generic PLA, 20% infill.
6//
7// Expected math:
8// bbox extent = 10mm × 10mm × 10mm
9// bbox volume = 1000 mm³
10// perim_fraction = 8%; infill_fraction = (100-8)*20/100 = 18.4%
11// solid_pct = 26% -> solid_volume ≈ 260 mm³ (with integer trunc, 260)
12// filament_xsect (1.75mm) = π × 0.875² ≈ 2.405 mm²
13// filament_mm = 260 / 2.405 ≈ 108 mm
14// sustainable_flow = min(machine 35, material 15) = 15 mm³/s
15// extrude_time = 260 / 15 ≈ 17.3 sec; with 25% overhead ≈ 21.7 sec
16// print_minutes ≈ 0 (rounds down from 21 sec)
17//
18// Closed-form invariants:
19// (a) OK verdict for 10mm tetrahedron + 20% infill PLA on Qidi.
20// (b) volume_mm3 in [200, 320]
21// (c) filament_mm in [80, 140]
22// (d) print_minutes in [0, 1]
23// (e) WARN_TINY for 1mm tetrahedron (tiny volume)
24// (f) WARN_LONG for huge mesh (200mm cube ≈ 8M mm³ -> >24h at low
25// flow).
26// (g) WARN_FIL for medium-large mesh consuming > 250m filament.
27// (h) ERR_INPUT for negative density.
28// (i) Verdict names non-NULL.
29//
30// expect_exit: 0
31// license_tier: ORIGINAL
32
33import "nx_syscalls.nx"
34import "nx_mesh.nx"
35import "nx_machine_graph.nx"
36import "nx_material_profile.nx"
37import "nx_estimate.nx"
38
39const Q14: i64 = 16384
40
41func main() -> i64 {
42 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3()
43 let pla: *NxMaterialProfile = nx_material_profile_generic_pla()
44
45 // --- (a)(b)(c)(d) 10mm tetrahedron, 20% infill ---
46 let tet: *NxMesh = nx_mesh_make_tetrahedron(10 * Q14, 0)
47 let r: *NxPrintEstimate = nx_estimate_print(tet, qidi, pla, 20)
48 if r.verdict != NX_EST_OK { return 10 }
49 if r.volume_mm3 < 200 { return 11 }
50 if r.volume_mm3 > 320 { return 12 }
51 if r.filament_mm < 80 { return 13 }
52 if r.filament_mm > 140 { return 14 }
53 if r.print_minutes < 0 { return 15 }
54 if r.print_minutes > 1 { return 16 }
55
56 // --- (e) 3mm tetrahedron -> WARN_TINY (1mm would round volume to 0) ---
57 let tiny: *NxMesh = nx_mesh_make_tetrahedron(3 * Q14, 0)
58 let r_tiny: *NxPrintEstimate = nx_estimate_print(tiny, qidi, pla, 20)
59 if r_tiny.verdict != NX_EST_WARN_TINY { return 20 }
60
61 // --- (f) 200mm tetrahedron, 100% infill -> WARN_LONG ---
62 // bbox volume = 200³ = 8e6 mm³ × 92% solid (perim+full infill)
63 // = ~7.4M mm³ / 15 mm³/s ≈ 137 hours -> WARN_LONG (>1440 min)
64 let big: *NxMesh = nx_mesh_make_tetrahedron(200 * Q14, 0)
65 let r_big: *NxPrintEstimate = nx_estimate_print(big, qidi, pla, 100)
66 if r_big.verdict != NX_EST_WARN_LONG { return 30 }
67
68 // --- (g) 100mm tetrahedron, 100% infill -> WARN_FIL ---
69 // bbox 1e6 mm³ × 92% = 920000 / 2.405 = ~382k mm filament > 250k
70 // BUT also long print -- WARN_LONG fires first per check order.
71 // Use 60mm tetrahedron with 100% infill:
72 // bbox 216000 × 92% = 198720 / 2.405 ≈ 82600mm = 82m filament -- under 250k
73 // Need exactly the in-between case... try 80mm 100%:
74 // bbox 512000 × 92% = 471000 / 2.405 = ~196000 mm = 196m -- still under
75 // Try 95mm 100%:
76 // bbox 857375 × 92% = 788785 / 2.405 = ~328000mm = 328m -- > 250m! YES
77 // But also check time: 788785 / 15 = ~52600 sec * 1.25 = 65750 sec = 1095 min
78 // < 1440 so WARN_FIL fires before WARN_LONG.
79 let med: *NxMesh = nx_mesh_make_tetrahedron(95 * Q14, 0)
80 let r_med: *NxPrintEstimate = nx_estimate_print(med, qidi, pla, 100)
81 if r_med.verdict != NX_EST_WARN_FIL { return 40 }
82
83 // --- (h) ERR_INPUT for negative density ---
84 let r_bad: *NxPrintEstimate = nx_estimate_print(tet, qidi, pla, -10)
85 if r_bad.verdict != NX_EST_ERR_INPUT { return 50 }
86
87 // --- (i) Verdict names ---
88 if (nx_est_verdict_name(NX_EST_OK) as i64) == 0 { return 60 }
89 if (nx_est_verdict_name(NX_EST_WARN_LONG) as i64) == 0 { return 61 }
90 if (nx_est_verdict_name(NX_EST_WARN_FIL) as i64) == 0 { return 62 }
91 if (nx_est_verdict_name(NX_EST_WARN_TINY) as i64) == 0 { return 63 }
92 if (nx_est_verdict_name(NX_EST_ERR_INPUT) as i64) == 0 { return 64 }
93
94 return 0
95}