nx_pillar_physics_test.nx source
↩ module page · 96 lines · 4931 B
1// nx_pillar_physics_test.nx -- verify cantilever moment + load-proportional
2// footprint sizing EXCEEDS industry constant-diameter baseline.
3//
4// Closed-form invariants:
5// (a) Zero/negative load → 0 moment
6// (b) Moment scales linearly with mass (2× mass → 2× moment)
7// (c) Moment scales linearly with arm (2× arm → 2× moment)
8// (d) Zero/negative moment → MIN footprint (industry baseline)
9// (e) Light load PLA → footprint == MIN (matches industry)
10// (f) Heavy load PLA → footprint > MIN (industry would underbuild)
11// (g) MONOTONIC: heavier load → larger footprint
12// (h) MATERIAL-AWARE: same load, stiffer material → smaller footprint
13// (industry uses SAME footprint regardless of material -- their gap)
14// (i) Runaway load clamped to MAX_FOOT (no infinite growth)
15// (j) Convenience nx_pillar_footprint_for_load matches direct math
16//
17// expect_exit: 0
18// license_tier: ORIGINAL
19
20import "nx_syscalls.nx"
21import "nx_material_profile.nx"
22import "nx_pillar_physics.nx"
23
24const Q14: i64 = 16384
25
26func main() -> i64 {
27 let pla: *NxMaterialProfile = nx_material_profile_generic_pla()
28 let abs_: *NxMaterialProfile = nx_material_profile_generic_abs()
29 let peek: *NxMaterialProfile = nx_material_profile_generic_peek()
30
31 // --- (a) Zero/negative load → 0 moment ---
32 if nx_cantilever_moment(0, 10 * Q14) != 0 { return 10 }
33 if nx_cantilever_moment(10 * Q14, 0) != 0 { return 11 }
34 if nx_cantilever_moment(-1, 10 * Q14) != 0 { return 12 }
35 if nx_cantilever_moment(10 * Q14, -1) != 0 { return 13 }
36
37 // --- (b) Linear in mass: 2× mass → 2× moment ---
38 let m1: i64 = nx_cantilever_moment(1 * Q14, 5 * Q14)
39 let m2: i64 = nx_cantilever_moment(2 * Q14, 5 * Q14)
40 if m2 != 2 * m1 { return 20 }
41
42 // --- (c) Linear in arm: 2× arm → 2× moment ---
43 let m3: i64 = nx_cantilever_moment(3 * Q14, 4 * Q14)
44 let m4: i64 = nx_cantilever_moment(3 * Q14, 8 * Q14)
45 if m4 != 2 * m3 { return 30 }
46
47 // --- (d) Zero moment → MIN footprint ---
48 let yield_pla: i64 = pla.tensile_yield_mpa_q14
49 let f_zero: i64 = nx_pillar_min_footprint(0, yield_pla, NX_MAT_PILLAR_SAFETY_Q14)
50 if f_zero != NX_MAT_PILLAR_MIN_FOOT_Q14 { return 40 }
51
52 // --- (e) Light load PLA: footprint should be MIN (clamped) ---
53 let light_moment: i64 = nx_cantilever_moment(1 * Q14, 1 * Q14) // 1 g·mm
54 let f_light: i64 = nx_pillar_min_footprint(light_moment, yield_pla,
55 NX_MAT_PILLAR_SAFETY_Q14)
56 if f_light != NX_MAT_PILLAR_MIN_FOOT_Q14 { return 50 }
57
58 // --- (f) Heavy load PLA: footprint should exceed MIN ---
59 let heavy_moment: i64 = nx_cantilever_moment(10 * Q14, 10 * Q14) // 100 g·mm
60 let f_heavy: i64 = nx_pillar_min_footprint(heavy_moment, yield_pla,
61 NX_MAT_PILLAR_SAFETY_Q14)
62 if f_heavy <= NX_MAT_PILLAR_MIN_FOOT_Q14 { return 60 }
63
64 // --- (g) Monotonic: heavier > lighter (across non-clamped range) ---
65 let m_mid: i64 = nx_cantilever_moment(5 * Q14, 5 * Q14) // 25 g·mm
66 let m_heavy: i64 = nx_cantilever_moment(10 * Q14, 10 * Q14) // 100 g·mm
67 let f_mid: i64 = nx_pillar_min_footprint(m_mid, yield_pla, NX_MAT_PILLAR_SAFETY_Q14)
68 let f_heavy_g: i64 = nx_pillar_min_footprint(m_heavy, yield_pla, NX_MAT_PILLAR_SAFETY_Q14)
69 if f_heavy_g <= f_mid { return 70 }
70
71 // --- (h) Material-aware: stiffer material → smaller footprint
72 // (under same load that's NOT clamped to MIN/MAX for both)
73 let yield_abs: i64 = abs_.tensile_yield_mpa_q14 // 20 MPa (soft)
74 let yield_peek: i64 = peek.tensile_yield_mpa_q14 // 95 MPa (stiff)
75 let same_moment: i64 = heavy_moment // 100 g·mm
76 let f_abs: i64 = nx_pillar_min_footprint(same_moment, yield_abs, NX_MAT_PILLAR_SAFETY_Q14)
77 let f_peek: i64 = nx_pillar_min_footprint(same_moment, yield_peek, NX_MAT_PILLAR_SAFETY_Q14)
78 if f_abs <= f_peek { return 80 }
79 // Industry note: Orca/Bambu/Cura/Prusa would all emit identical pillars
80 // here because they don't read material yield. We size them differently.
81
82 // --- (i) Runaway load: footprint clamped to MAX, doesn't overflow ---
83 let huge_moment: i64 = nx_cantilever_moment(1000 * Q14, 1000 * Q14) // 1e6 g·mm
84 let f_huge: i64 = nx_pillar_min_footprint(huge_moment, yield_pla,
85 NX_MAT_PILLAR_SAFETY_Q14)
86 if f_huge != NX_MAT_PILLAR_MAX_FOOT_Q14 { return 90 }
87
88 // --- (j) Convenience matches direct ---
89 let conv: i64 = nx_pillar_footprint_for_load(10 * Q14, 10 * Q14, pla)
90 let direct_m: i64 = nx_cantilever_moment(10 * Q14, 10 * Q14)
91 let direct_f: i64 = nx_pillar_min_footprint(direct_m, yield_pla,
92 NX_MAT_PILLAR_SAFETY_Q14)
93 if conv != direct_f { return 100 }
94
95 return 0
96}