nx_gtm_build.nx source
↩ module page · 129 lines · 4569 B
1// nx_gtm_build.nx -- GO-TO-MARKET / BUILD PLAN. Turns the BOM's parts into
2// an ORDERED assembly plan: the steps, durations, and precedence constraints
3// (what must be done before what). Computes the build CRITICAL PATH -- the
4// longest dependency chain, i.e. the minimum build time with unlimited
5// parallel hands -- so the bottleneck is explicit and the parallel saving is
6// quantified. (Named nx_gtm_build to avoid the existing nx_assembly CAD
7// exploded-view engine + nx_build_plan printer scheduler.)
8//
9// INTEGER-EXACT. Durations in minutes. Step ids are in topological orde
10// (every prerequisite has a lower id), so the earliest-finish of each step is
11// a single forward pass: ef(i) = duration(i) + max(ef of its prerequisites).
12// Instantiated for the water AWG bench prototype.
13//
14// THE exceed: the build schedule + its bottleneck are COMPUTED from the
15// precedence DAG, not sketched -- the 4-hour enclosure print is the critical
16// path, so it should be pre-printed or started first.
17//
18// grounded: critical_path_method + assembly_line_precedence + design_for_assembly
19// genealogy_id: assembly_build_plan + nishi_go_to_market
20
21import "nx_syscalls.nx"
22
23// ===== Build steps (topological order) ============================
24
25const GB_PRINT_ENCLOSURE: i64 = 0
26const GB_COLD_STACK: i64 = 1 // peltier + heatsink + cold plate
27const GB_MOUNT_FANS: i64 = 2
28const GB_COLLECTION: i64 = 3 // tray + tubing + pump + tank
29const GB_TREATMENT: i64 = 4 // UV-C + carbon
30const GB_MINERAL: i64 = 5
31const GB_WIRE_CONTROL: i64 = 6 // MCU + sensors + PSU + wiring
32const GB_INTEGRATE: i64 = 7 // mount all subsystems in the enclosure
33const GB_LEAK_TEST: i64 = 8
34const GB_POWER_ON_TEST: i64 = 9
35const GB_N: i64 = 10
36
37func gb_count() -> i64 {
38 return GB_N
39}
40
41// Duration of each step (minutes).
42func gb_duration(id: i64) -> i64 {
43 if id == GB_PRINT_ENCLOSURE { return 240 } // the 3D print (long pole)
44 if id == GB_COLD_STACK { return 30 }
45 if id == GB_MOUNT_FANS { return 15 }
46 if id == GB_COLLECTION { return 40 }
47 if id == GB_TREATMENT { return 25 }
48 if id == GB_MINERAL { return 15 }
49 if id == GB_WIRE_CONTROL { return 45 }
50 if id == GB_INTEGRATE { return 60 }
51 if id == GB_LEAK_TEST { return 20 }
52 if id == GB_POWER_ON_TEST { return 30 }
53 return 0
54}
55
56// The `slot`-th prerequisite of a step (up to 4), or -1 if none.
57func gb_prereq(id: i64, slot: i64) -> i64 {
58 if id == GB_MOUNT_FANS { if slot == 0 { return GB_COLD_STACK } }
59 if id == GB_TREATMENT { if slot == 0 { return GB_COLLECTION } }
60 if id == GB_MINERAL { if slot == 0 { return GB_TREATMENT } }
61 if id == GB_INTEGRATE {
62 if slot == 0 { return GB_PRINT_ENCLOSURE }
63 if slot == 1 { return GB_MOUNT_FANS }
64 if slot == 2 { return GB_MINERAL }
65 if slot == 3 { return GB_WIRE_CONTROL }
66 }
67 if id == GB_LEAK_TEST { if slot == 0 { return GB_INTEGRATE } }
68 if id == GB_POWER_ON_TEST { if slot == 0 { return GB_LEAK_TEST } }
69 return 0 - 1
70}
71
72// Total work if done serially (sum of all step durations).
73func gb_total_time() -> i64 {
74 var t: i64 = 0
75 var i: i64 = 0
76 while i < GB_N {
77 t = t + gb_duration(i)
78 i = i + 1
79 }
80 return t
81}
82
83// Critical-path length = max earliest-finish over the precedence DAG
84// (minimum build time with parallel hands).
85func gb_critical_path() -> i64 {
86 let ef: *i64 = sys_mmap(GB_N * 8) as *i64
87 var i: i64 = 0
88 while i < GB_N {
89 var maxpre: i64 = 0
90 var s: i64 = 0
91 while s < 4 {
92 let pre: i64 = gb_prereq(i, s)
93 if pre >= 0 { if ef[pre] > maxpre { maxpre = ef[pre] } }
94 s = s + 1
95 }
96 ef[i] = gb_duration(i) + maxpre
97 i = i + 1
98 }
99 var m: i64 = 0
100 i = 0
101 while i < GB_N {
102 if ef[i] > m { m = ef[i] }
103 i = i + 1
104 }
105 return m
106}
107
108// Earliest finish of one step (same forward pass, returns ef[target]).
109func gb_earliest_finish(target: i64) -> i64 {
110 let ef: *i64 = sys_mmap(GB_N * 8) as *i64
111 var i: i64 = 0
112 while i < GB_N {
113 var maxpre: i64 = 0
114 var s: i64 = 0
115 while s < 4 {
116 let pre: i64 = gb_prereq(i, s)
117 if pre >= 0 { if ef[pre] > maxpre { maxpre = ef[pre] } }
118 s = s + 1
119 }
120 ef[i] = gb_duration(i) + maxpre
121 i = i + 1
122 }
123 return ef[target]
124}
125
126// Time saved by building in parallel vs serially.
127func gb_parallel_savings() -> i64 {
128 return gb_total_time() - gb_critical_path()
129}