钢结构自动提料
把钢结构厂的「摘料明细清单」自动整理成可直接采购的「整理表」,覆盖 明细录入 → 分组整理 → 采购计划生成 全流程。核心是一个已固化的决策引擎脚本 scripts/生成整理表v2.py。
何时使用
- 用户给出一份摘料清单(
.xls或.xlsx),要求「整理」「提料」「生成整理表」「采购决策」。 - 用户要求对钢板(PL)、卷制钢管(PD)、圆管(PIP/CHS)、型材(HN/HW/L/RHS/D)、钢筋(D)做采购分组与定尺。
- 用户要核对某类材料(如 PD1000*20 卷管)的排布与损耗是否合理。
运行环境
- Python 3.x,需
xlrd(读 .xls)、openpyxl(写 .xlsx)、xlwt(.xlsx→.xls 转换)。 - 推荐用项目隔离的 venv(
项目虚拟环境)。
核心用法
python 生成整理表v2.py <输入.xls> [输出.xlsx] [交货状态]
- 输入:摘料清单
.xls(可传参覆盖默认输入)。 - 输入是
.xlsx时:脚本用xlrd只读.xls,需先用 openpyxl+xlwt 把.xlsx无损转成.xls(保留全部 sheet 与单元格值),再喂给脚本。 - 输出:
.xlsx整理表(复制原 sheet + 新增「整理」表),默认<输入名>_整理.xlsx。 - 交货状态:可显式传入(
热轧/控轧/正火等);不传时按总说明 4.1 自动分档(Q235/Q355≤50→控轧 CR,Q355>50/Q420/Q460→TMCP)。
示例:
# .xls 直接处理
python 生成整理表v2.py "input/xxx摘料清单.xls" "out.xlsx"
# .xlsx 先转换再处理(一次性内联脚本)
python -c "import openpyxl,xlwt; ..." # 读 .xlsx 各 sheet,xlwt 写 .xls
python 生成整理表v2.py "_转换.xls" "out.xlsx"
输出结构(32 列)
- 左区 A-Q(17 列):规格 / 板厚 / 板宽 / 材质 / 数量 / 长度(mm) / 面积(m²) / 净重(kg) / 毛重(kg) / 零件号 / 总净重(K=H×E) / 总毛重(L=I×E) / 毛净比(M=(L-K)/K) / 总长(N=F×E, 仅型材) / 备注(主件标记) / 扣减备注 / 采购损耗(Q)。
- 右区 R-AF(15 列):材料名称 / 材质 / 规格(板厚) / 宽度管径(mm) / 定长(mm) / 单位 / 数量 / 总重(t) / 交货状态探伤要求 / 技术要求 / 宽度方向下料方法 / 长度方向下料方法 / 可否取样 / 定宽计算 / 定长计算。
- 最后一行:合计行(不含 PL6*30 垫板)。
已固化的采购决策规则
钢板(PL)
- 薄板 T≤16:不定尺开平板 / 定宽开平板(1500/1800/2000 三档选利用率最高)。
- 厚板:双定尺(优先)/ 定宽 / 不定尺。
- 双定尺板幅:宽 1800(强制下限)~3200(容差 3250),长 ≥6000、≤12000(卷管可到 15000)。
- 定长方向拼板:短件(<6m)拼 m 段凑 [6000, 12000]。
- 损耗率:毛净比≤5%→4%,每超 5%→+2%(按子组毛净比阶梯)。
- 低材质并入高材质采购(< 一张板重 = 板厚×2×12×7.85);合并分段损耗(本体/并入各套各自损耗率,Q 列加权)。
- 两档判定(band_B):特殊材质(Q390+)一律 B 档(此条经调整,原 <30 归 A 档);普通材质板厚≥40 → B 档,其余普通材质 → A 档。C 档(薄板 T≤16 开平板)仅普通材质;特殊材质薄板不进 C 档,直接走 B 档。
定宽决策机制(best_fixed_width)
- 定宽 = 只定板宽、不定板长;采购按
Y=K×(1+损耗率)/1000反推吨位,不落张数/定长。 - 算法:统计子组宽度块 wc,枚举 1~2 种宽度×1~N 块排板组合(总宽=Σ(w×n)+块数×5 ∈ 板幅区间),FFD 降序装箱把全部块塞进「货架」(每货架=一张 W 宽的板),选利用率最高(=已用宽/(货架数×W));利用率相同选板宽更大。
- 板幅优先级:先 [1800,2500] 找可行方案;仅当零件太宽导致优先区间无解才退 [2500,3200](业务约定标黄)。
- C 档薄板「定宽开平板」特例(best_c_fixed_width):板宽仅 1500/1800/2000 三档,选利用率最高,触发=子组净重>10t 且能凑上三档之一。
- 三种采购方式本质区别:双定尺(定宽+定长,整张买,损耗最低 1~3%)/ 定宽(只定宽,套损耗率 4%+)/ 不定尺(全不定,损耗最大)。
定宽「按宽度分组 + 3张板阈值」正向分档(此条经调整,替换旧的吨位阈值+场景C)
- 触发流程(厚板/普通材质非C档分支):①先对每个长件组合做双定尺判定(B 档 len_tol=200 全试;A 档子组净重>15t 才试,min_cluster_net=15000);双定尺成功只写 covered_items,leftover 归未双定尺池。②双定尺失败/未覆盖的件 + 短件,全部进「未双定尺池」。③对未双定尺件按板宽重新分组(int(板宽) 为 key),每个宽度组:净重 > 3张标准板重(3×t×2×12×7.85) → 单独分组走定宽(emit_fixed,宽度凑不出方案则退回不定尺);净重 ≤ 3张板 → 合并为一个不定尺子组(emit_roll)。
- 已取消:旧的「B档普通>20t/特殊无限制、A档>15t 才定宽」吨位阈值定宽,以及「事后场景C:先定宽再 downgrade 归并」的做法。不采用"先写定宽再降级"的别扭表示,改为分子组阶段正向按宽度分档。
卷制钢管(PD,D>1000)→ 卷管双定尺
- 中径展开 C=π×(D−t);轴向分段查合作钢厂卷管能力表(直径取整 100、壁厚取整 5、材质精确匹配)。
- 方向互换:筒节轴向长=板宽、展开周长=板长。
- 轴向精确聚类(容差 0.5mm);qty≤1 或 无可行 nb(×1<1800 且 ×2>3250)的聚类为「孤立段」。
- 孤立段并入:候选=所有「轴向≥孤立段 且 qty>1」的稳定聚类(跨档并入允许,排除孤立段互并);判据=「全局增量最小」 delta=并入后吨位−(孤立段单独吨位+候选吨位)。不能只看并入后候选的局部 key(贪心陷阱)。
- 孤立段自身「并排不可行」时(轴向×1<1800 且 ×2>3250),cluster_tonnage=None,必须强制并入,否则丢件导致负损耗。落点判据仍是「增量最小」 delta=merged_ton−dst_ton(不含 cl_ton 项),绝不能退化成「绝对吨位最小」。
- 串联数 nl 按聚类独立遍历(nl_min~nl_max),平局选张数少;板长上限 12000(常规板幅)。
- 备注列标「卷管」、不可取样。
BOX / BH / BT 截面拆板
- BOX 2腹+2翼 展开超 3250 时降级 1腹+1翼(如 BOX1000:952×2+1000×2=3924→952+1000=1962)。
- BH 4 段
BH500*300*16*30(上下翼同厚)→ 腹板+2 翼板。 - BH 5 段
BH499*150*8*8*16(上下翼不同厚)→ 腹板(H−tf_top−tf_bot)+上翼+下翼。 - BT 埋件截面
BT440*200*20*20= H×B×tw×tf,仅 1 腹板 + 1 翼板:腹板宽=H−tf(只减 1 个翼板厚),翼板=tf×B,各 1 块/件(新增)。 - 拆板件(BH/BOX)长度方向「顺序装箱」替代聚类(pack_length_boards,不同长度段拼满 ≤12000)。
圆管(PIP/CHS,D<1000)与成品卷管(PD<1000)
- 成品管按支数定长采购,6m 一支,不足一支按 1 支(不加损耗)。
- PD<1000 卷制钢管按成品圆管采购(6m 一支,材质标「圆管」),与 PIP 一致;PD≥1000 才展开卷制走卷管双定尺(修正:此前 PD<1000 落到型材分支因 PROFILE_LEN 缺 "PD" 键导致丢采购、负损耗)。
型材(HN/HW/L/RHS/D)
- H 型钢 12m、角钢 6m、矩形管 9m;支数=ceil(总长/定长);不足半支不采购(圆管除外)。
标准件(螺母/套筒/螺栓等)
- NUT_M24(螺母)、TT40(套筒)、螺栓、垫圈等标准件忽略,不输出到整理表(材质为「螺母」「套筒」「螺栓」「垫圈」「螺杆」,或规格前缀 NUT/TT/WASH/BOLT)(新增)。
- 材质匹配用「包含」而非精确(改):海外项目材质带前缀/后缀("螺杆4.6""M20盲孔螺母""预焊螺母"),精确匹配会漏掉。
交货状态(总说明 4.1 自动分档,项目级可配)
- 默认档:Q235 钢材、板厚≤50mm 的 Q355 → 控轧(CR);板厚>50mm 的 Q355、Q420、Q460 → 热机械轧制(TMCP)。
- 热轧变体(第3参传「自动:热轧」):Q235/Q355 ≤50 → 热轧,>50 → TMCP;Q420/Q460 全部 TMCP(经评定)。
- 显式传入具体状态名(如「热轧」)→ 所有采购行统一该状态。
- 注意:各项目总说明的交货状态规则不同,关键规则可能写在总说明的嵌入截图里(xlrd 文字搜索不到)。提取方法:pywin32 + WPS COM(
KET.Application,Excel COM 打不开 WPS 生成的 .xls)打开文件,Shapes.CopyPicture()+ PILImageGrab.grabclipboard()导出图片查看。
不采购(排除项)
- PL6*30 焊接垫板(单独分组,不计合计)。
- 分组净重 < 400kg。
- 型材不满半支。
关键坑(务必遵守)
- 海外项目格式差异:
- 可能无「零件号」列(无拆板件)——locate_detail_sheet已改为按「规格+材质+数量」判定,零件号/备注用idx.get兜底。
- 净重/毛重可能是单件值(需×数量),与国内「总净重」口径不同;小计/合计行在"长度"列标记。
- 可能无总说明 sheet,find_project_name识别不到工程名称 → 交货状态必须显式传参(如「热轧」)。
- 存在净重0的特殊材质(SCW480 超厚板、SUS304 不锈钢)需单独跟业务方确认:忽略 or 按密度补算(不锈钢7.93)。 - openpyxl 清空单元格:必须
.value = None显式赋值,cell(value=None)不生效。 - 卷管双定尺 nl 遍历平局:N 能被 nb×nl 整除时 key 恒定,靠「平局选张数少」+ 板长上限 12000 决定 nl。
- 双定尺板长上限:常规板幅(宽≤2500)→12000,非常规板幅(宽 2500~3200)→15000(企业作业标准)。
- 合并采购逐级合并:Q355B→Q355C→Q420,合并后够一张板即停。
- 拆板件装箱「单元」:BH=1腹2翼;BOX 2+2=2腹2翼(=1 构件);BOX 1+1=1腹1翼(半构件,独立下料无成套问题)。
- 孤立段并入不能用「局部 key 最小」或「绝对吨位最小」:必须用「全局/增量最小」,否则会误并入轴向更近但板宽浪费更大的聚类,或选到轴向远的聚类导致损耗偏高。
- 钢板双定尺多宽度聚类必须全量消费 cover_cluster_widths 的返回(修复):该函数贪心多轮覆盖,rows_ 每轮一种板宽组合,合起来才覆盖聚类内全部块;只取 rows_[0] 会丢其余宽度组合 → 无声丢件(leftover 为空但 covered_items 全计入)→ 负损耗(曾因此 -29.6%)。修复后每个宽度组合独立成采购行(不同板宽分开买板)。
输出采购计划(第三步:整理表 → 采购计划)
三步提料流程:① 摘料清单 → 整理表;② 整理表由人工确认修改;③ 整理表 → 采购计划。
脚本 scripts/输出采购计划.py 按采购计划模板文件精确复刻格式,从整理表的某个采购 sheet(如「整理-西」)生成采购计划。
python 输出采购计划.py <整理表.xlsx> <sheet名> <工程名> <分部名> <输出.xlsx> [编制日期]
# 例:python 输出采购计划.py "整理表.xlsx" "整理" \
# "工程项目名称" "分部工程名称" \
# "采购计划.xlsx"
文件命名规则(已确认):项目名称-分部-采购计划-编制日期。
模板结构(已逐项分析固化)
- 14 列数据:序号/材料名称/材质/规格(板厚)/定宽(mm)/定长(mm)/单位/数量/总重(t)/交货状态/技术要求/宽度方向下料方法/长度方向下料方法/可否取样。
- 表头 4 行:行1-2「材料预算表」标题(楷体_GB2312)+生产加工号/共页/表号/版次;行3 工程名称/分部名称/日期;行4-5 表格头(序号~技术要求纵向合并,下料规格横跨 L:M,行5 拆宽度方向/长度方向/可否取样)。
- 表尾:汇总两行(摘料净重/毛重/采购净重/扣减库存的标签值纵向跨两行,采购损耗/综合损耗各占一行)+ 备注一行(居中)。数据区与汇总区之间不留空行(业务约定要求紧贴)。
- 字体:表头 14pt 宋体、数据 18pt 宋体;边框 thin 全框、居中对齐;列宽(=/256):序号6.1/材料名20.75/材质19/规格25.75/定宽11.5/定长11.5/单位6.4/数量6.4/总重20.75/交货23.25/技术35.75/下料21.9×2/取样37.4。
字段映射(整理表 → 采购计划)
- 材料名称 18、材质 19、规格板厚 20、定宽 U=21、定长 V=22、单位 23、数量 24、总重 25、交货状态 26、技术要求 27、宽度方向下料 28、长度方向下料 29、可否取样 30。
- 合计行:净重=列11(kg)、毛重=列12(kg),均 /1000 转 t。
关键规则(业务约定三点要求固化)
- 技术要求保留原值:「不定尺,开平板」等不简写。
- 表尾用公式:采购净重=
=SUM(总重列);采购损耗=(采购净重-摘料净重)/摘料净重;综合损耗=(采购净重+扣减库存-摘料净重)/摘料净重;两个损耗0.00%百分比格式保留 2 位。 - 精确复刻模板格式(字体/字号/边框/合并/列宽/行高)。
- 排除 AA 列以「并入」开头的行(已并入其他采购行,不重复输出)。
- 表头固定值:生产加工号/、表号 企业表单编号、版次 A。
取样情况备注(GB 50205 5.2.5 组批规定,业务约定固化)
- 表尾「备注」行下新增「取样情况」备注行:按 (材质+板厚档) 检查 N 列(可否取样),组内存在"可取样"行 → 「满足取样要求」;全为"不可取样" → 「不满足取样要求(请要求钢厂提供出厂复验报告/质保书)」。
- 组批上限(仅作规则参考,不拆行):Q235/Q345(Q355 按 Q345 档)板厚<40mm→每批≤150t、≥40mm→每批≤60t;Q390 及以上、GJ 系列(Q**GJ)→每批≤60t。业务约定明确「组批超批次重量不用拆行」,采购计划保持原行数,分批由现场按到货处理。
- 板厚档以 40mm 分界;型材(规格为字符串)默认按 <40mm 档。
关键坑(采购计划专项)
- 必须 WPS 重算 + 重设列宽:openpyxl 生成后,用 WPS COM(
KET.Application)CalculateFullRebuild()落公式缓存值,并在 WPS 内Columns(i).ColumnWidth重设列宽再 Save。原因:WPS 重算保存会把 F/H/M 三列宽重置为 13.0;且 openpyxl 读 WPS 保存的文件对部分列宽解析有误(读回 13.0 是误报,WPS 自己读回正确)。 - 合并单元格先写值再 merge:MergedCell 的 value 只读。
- 备注文字居中(
horizontal=center+wrap_text=True),不要左对齐。
工作流程
- 确认输入:定位摘料清单
.xls,确认项目、交货状态。 - 运行脚本:按上述用法执行,生成
.xlsx整理表。 - 核对结果:检查是否有负损耗(Q 列 <0)、孤立段是否丢件、合计净重是否符合预期。
- 人工复核(可选):生成「整理(审核)」副本供人工比对(已决定不再保留审核 sheet,最终 sheet 只含「整理」)。
- 输出采购计划(可选):已确认整理表后,用
scripts/输出采购计划.py生成采购计划,WPS 重算落公式缓存值。 - 交付:输出 .xlsx 并汇报净重、采购行数、各材料分组要点。
排布/损耗排查方法(当结果存疑某类材料排布时)
- 用「全局增量 delta」视角分析孤立段并入:并入哪个聚类能让整体新增采购最少。
- 负损耗排查顺序:① 是否孤立段并排不可行被丢件 → ② 落点是否误用「绝对吨位最小」→ ③ 源净重 vs 采购口径是否一致(卷管「毛重」=中径展开 π(D−t)×t×7.85,「净重」用偏小密度 ≈7.608,两者口径差约 0.3%)。
- 回归验证:改完逻辑后用历史摘料清单重跑,确认结果不变、无副作用。