FRI 与 KG-TOWER 二次开发教程(11):批量工况与参数扫描——负荷、物性、塔径与内件方案族
发布时间:2026/10/1 21:47:20来源:尧图网络
FRI 与 KG-TOWER 二次开发教程11批量工况与参数扫描——负荷、物性、塔径与内件方案族版本与事实声明环境Python 3.8仅标准库可无缝换成 pandas 落盘。核算逻辑复用第 05/07 篇的公开闭式近似CsbC_{sb}Csb、K2K_2K2等为声明输入本系列不发明。不涉及 FRI/KG-TOWER 的任何 API两者均无公开 API批量的权威对照仍建议用 KG-TOWER 导出报表或 Aspen Column Analysis 结果第 08/14 篇。文中任何数值为示例性建模不代表任何标准规定不对应任何真实装置数据。KG-TOWER 许可禁止逆向与派生扫描工作流不得以解析软件内部数据为目的铁律 3。一句话结论批量扫描的骨架是工况矩阵 → 逐点核算 → 落表 → 断点续扫其可靠性取决于一个设计决策——用内容寻址的case_id塔段内件工况哈希作唯一键这样重复运行会跳过已算工况示例首轮 204 个工况合格 105 个第二轮续扫新算 0 个幂等成立。〇、本篇要解决的认知问题Q1为什么批量核算的难点不是算得快而是算得可续、可查、可复现Q2全因子设计与拉丁超立方该怎么选四类扫描维度各自的工程含义是什么Q3什么叫变量-目标契约表它为什么能避免扫描扫错方向Q4断点续扫与幂等是怎么实现的为什么必须用内容寻址的键Q5扫描结果怎么判断这 105 个合格工况是有意义的一、机制解析1.1 为什么可续比快重要为什么这对你重要一次扫描动辄几百到几万个工况现实里它一定会被打断改参数、换机器、软件崩溃、下班。如果你的扫描脚本没有断点续扫能力被中断一次就要从头再来——而重头再来在核算是重头再烧一遍算力在软件侧更是重头再点一遍界面。所以批量引擎的第一需求不是性能而是可续性resumability把每个工况的唯一键与结果落盘重启时先读已完成的键集合跳过它们。扫描生命周期 ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ 生成工况键 │──│ 过滤已算 │──│ 逐点核算 │──│ 追加落盘 │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ ▲ │ └────────── 中断后重启从已算键集合继续 ────────┘1.2 工况矩阵全因子 vs 拉丁超立方设计构造优点代价适用全因子full factorial每个维度取若干水平笛卡尔积覆盖完整、可做方差分析、边界清晰组合数爆炸维度 ≤3、水平 ≤5 的确定性扫描拉丁超立方LHS每维等概率分层后随机配对维度高时样本效率高边界点可能取不到、结果需统计解释维度 ≥4 的探索性分析经验法则先全因子打边界再 LHS 填内部。工程上最常见的是3~4 个维度、每维 4~6 水平的全因子本例 4×17×3204当维度上升到 6 以上再换 LHS。1.3 四类扫描维度各自在回答什么问题负荷load回答这套几何的操作窗口有多宽第 07 篇的窗口表物性ρ、μ、σ回答体系变了结论还成立吗尤其表面张力见第 10 篇塔径D回答标称系列里哪一档最优内件方案族板型/孔径/开孔率、填料型号/尺寸回答选型问题第 13 篇把它形式化为代价排序。为什么负荷必须与塔径联合扫单扫负荷只能给一条窗口线单扫塔径只能给一列单点只有两者联合才能得到操作窗口 × 塔径的二维可行域第 13 篇的候选表就来自这里。1.4 变量-目标契约表防止扫错方向扫描前必须写清哪些是自变量、哪些是因变量、每个因变量的判据是什么。否则很容易出现扫了半天结果里没有一个量是你真正关心的。自变量范围步长/水平D0.9~1.2 m4 档load0.40~1.200.05hole_ratio0.04~0.063 档因变量判据阈值来源flood_pct≤ 85%经验法则weep_ratio≥ 1.5经验法则dc_ratio≤ 1.0E9 判据ok三者同时成立组合判据这张表就是扫描引擎的输入契约——第 04 篇的四层数据模型在批量场景下的具体化。1.5 断点续扫与幂等内容寻址的键键的设计第 04 篇已建立case_id sha1( 规范化(D, load, hole_ratio, ...) )[:10]三点要求只含决定结果的输入把与结果无关的字段如运行时间、注释排除否则同一工况会生成不同键浮点规范化先round(v, 6)再哈希避免 0.30000000000000004 与 0.3 生成两个键稳定序列化键在json.dumps(..., sort_keysTrue)下生成。幂等的判据第二次运行新算 0。示例首轮总工况 204 / 新算 204 / 跳过 0 / 合格 105第二轮总工况 204 / 新算 0 / 跳过 204——这正是幂等成立的实测证据。1.6 扫描的可复现性顺序、种子与并行扫描结果的可复现包含三层缺一层就会出现两次跑出的表不一样输入顺序可复现如果扫描维度由set或无序字典驱动迭代顺序在不同进程/不同机器上可能不同导致结果表的行序漂移。做法所有维度用有序序列list/tuple并在落盘时按case_id排序输出。随机可复现若用 LHS 或蒙特卡洛必须固定随机种子np.random.default_rng(seed)并把种子写进元数据否则同一批工况在第二次运行时是另一批工况。并行可复现并行只改变完成顺序不应改变结果内容。因此并行任务必须是纯函数第 19 篇且结果落盘时按case_id排序而不是按完成顺序追加。为什么这对你重要扫描表一旦被用于回归测试或审计“两次不一致就会让整批结论失效。经验法则任何扫描脚本第一件事是跑两次diff 结果表”——两次完全一致才说明可复现性成立。1.7 维度设计的取舍为什么本例是 4×17×3本例选择塔径 4 档 × 负荷 17 档 × 开孔率 3 档 204。三个维度的档位差异是有讲究的负荷档位最密17 档因为操作窗口的上下限需要卡在哪个负荷点才准档位太疏会漏掉边界附近的行为塔径档位中等4 档因为塔径通常是标称系列0.9/1.0/1.1/1.2 m档位由制造约束决定不能任意细分开孔率档位最少3 档因为开孔率是设计自由度工程上通常只在少数几个值间选如 4%/5%/6%扫太密没有工程意义。经验法则档位密度应对齐物理分辨率而非计算能力——在关键判据敏感的方向上加密在离散选型的方向上用标称档位。二、完整代码与逐行剖析代码 2-1多维度扫描 断点账本可直接运行# -*- coding: utf-8 -*- sweep.py —— 批量工况与参数扫描含断点账本 扫描维度塔径 D × 负荷系数 load × 开孔率 hole_ratio 断点续扫以 case_id 为键已算过则跳过幂等 importmath,hashlib,json,os,csvdefdry_dp(u_h,C0,rhoV,rhoL):return51.0*(u_h/C0)**2*(rhoV/rhoL)defweir(Lm,rhoL,lw):return750.0*(Lm/(rhoL*lw))**(2.0/3.0)defdc_loss(Lm,rhoL,Am):return166.0*(Lm/(rhoL*Am))**2defweep_u(rhoV,dh,K2):return(K2-0.90*(25.4-dh))/math.sqrt(rhoV)defevaluate(D,load,V0,L0,rhoV,rhoL,Csb,cfg):Vm,LmV0*load,L0*load Amath.pi/4*D**2A_actA*(1-2*cfg[Ad_ratio])u_sup(Vm/rhoV)/A u_flCsb*math.sqrt((rhoL-rhoV)/rhoV)u_h(Vm/rhoV)/(cfg[hole_ratio]*A_act)h_owweir(Lm,rhoL,cfg[weir_ratio]*D)h_tdry_dp(u_h,cfg[C0],rhoV,rhoL)cfg[hw]h_owcfg[h_r]h_dcb(h_tcfg[hw]h_owdc_loss(Lm,rhoL,cfg[Ad_ratio]*A))*cfg[phi]limit(cfg[tray_sp]*1000cfg[hw])/2ratiou_h/weep_u(rhoV,cfg[dh],cfg[K2])returndict(flood_pct100*u_sup/u_fl,h_th_t,weep_ratioratio,dc_ratioh_dcb/limit,okint(100*u_sup/u_fl85.0andratio1.5andh_dcblimit))defcase_id(rec):内容寻址唯一键只含决定结果的输入稳定序列化returnhashlib.sha1(json.dumps(rec,sort_keysTrue).encode()).hexdigest()[:10]FIELDS[D,load,hole_ratio,flood_pct,h_t,weep_ratio,dc_ratio,ok]defrun(out_csv,V02.0,L04.0,rhoV2.5,rhoL780.0,Csb0.075):cfgdict(Ad_ratio0.10,C00.80,hw50.0,h_r12.5,weir_ratio0.75,tray_sp0.6,phi0.6,dh8.0,K232.0)doneset()ifos.path.exists(out_csv):# 读已完成键断点续扫withopen(out_csv,newline,encodingutf-8)asf:forrowincsv.DictReader(f):done.add(case_id({D:float(row[D]),load:float(row[load]),hole_ratio:float(row[hole_ratio])}))new0;total0;oks0modeaifdoneelsewwithopen(out_csv,mode,newline,encodingutf-8)asf:wcsv.DictWriter(f,fieldnamesFIELDS)ifmodew:w.writeheader()forDin(0.9,1.0,1.1,1.2):forloadin[x/100forxinrange(40,125,5)]:forhrin(0.04,0.05,0.06):key_input{D:D,load:load,hole_ratio:hr}total1ifcase_id(key_input)indone:continuerevaluate(D,load,V0,L0,rhoV,rhoL,Csb,{**cfg,hole_ratio:hr})w.writerow({D:D,load:load,hole_ratio:hr,**{k:(round(v,4)ifisinstance(v,float)elsev)fork,vinr.items()}})new1;oksr[ok]returndict(totaltotal,newnew,skippedtotal-new,ok_newoks)if__name____main__:importtime t0time.time();s1run(_sweep.csv);t1time.time()print(f[首轮] 总工况{s1[total]}新算{s1[new]}跳过{s1[skipped]}f合格{s1[ok_new]}耗时{t1-t0:.2f}s)s2run(_sweep.csv)print(f[续扫] 总工况{s2[total]}新算{s2[new]}跳过{s2[skipped]}f幂等第二轮新算应为 0)实测输出本机 Python 3[首轮] 总工况204 新算204 跳过0 合格105 耗时0.00s [续扫] 总工况204 新算0 跳过204 幂等第二轮新算应为 0逐段剖析case_id()只哈希{D, load, hole_ratio}三个字段——这是只含决定结果的输入的严格落地。如果误把flood_pct等输出也纳入键键会随结果变化续扫必然失效。反直觉点 1mode a if done else w。这个看似琐碎的分支决定了首次写表头、续扫追加。如果无脑用w续扫会把已算结果全清空——这是断点续扫最经典的自毁 bug。round(v, 4)在落盘时做但哈希用的是原始输入D、load、hr均来自固定的离散列表本例输入本身离散所以哈希天然稳定。若输入来自连续随机LHS则必须在哈希前 round第 04 篇的设计。耗时0.00s说明这类纯算式扫描极快204 个工况不到 10 ms 量级。真正的瓶颈从来不是 CPU而是 I/O写大量 CSV与外部软件调用KG-TOWER/PROII。这条观察直接决定了第 19 篇规模化的重点优化调度与缓存而不是优化公式。反直觉点 2合格105/204≈51%。一半工况不合格是正常的——扫描的目的不是全部合格而是找出可行域的边界形状。把合格率低当成脚本 bug 去修是本末倒置。代码 2-2结果聚合与可行域边界提取把 204 行变成结论# -*- coding: utf-8 -*-aggregate.py —— 从扫描长表提取每个 (D, hole_ratio) 下的合格负荷区间 importcsvfromcollectionsimportdefaultdictdefload_table(path_sweep.csv):rowslist(csv.DictReader(open(path,encodingutf-8)))forrinrows:forkin(D,load,hole_ratio,flood_pct,h_t,weep_ratio,dc_ratio):r[k]float(r[k])r[ok]int(r[ok])returnrowsdefintervals(rows):grpdefaultdict(list)forrinrows:grp[(r[D],r[hole_ratio])].append(r)out{}forkey,rsingrp.items():rs.sort(keylambdar:r[load])ok_loads[r[load]forrinrsifr[ok]]ifok_loads:out[key](min(ok_loads),max(ok_loads),len(ok_loads))returnoutif__name____main__:rowsload_table()print(f读取{len(rows)}行按 (D, hole_ratio) 分组)for(D,hr),(lo,hi,n)insorted(intervals(rows).items()):print(f D{D:.1f}m, 开孔率{hr:.2f}: 合格负荷{lo:.2f}~{hi:.2f}{n}个点)实测输出读取 204 行按 (D, hole_ratio) 分组 D0.9 m, 开孔率0.04 : 合格负荷 0.40~0.8510 个点 D0.9 m, 开孔率0.05 : 合格负荷 0.50~0.858 个点 D0.9 m, 开孔率0.06 : 合格负荷 0.60~0.856 个点 D1.0 m, 开孔率0.04 : 合格负荷 0.50~1.1013 个点 D1.0 m, 开孔率0.05 : 合格负荷 0.65~1.1010 个点 D1.0 m, 开孔率0.06 : 合格负荷 0.75~1.108 个点 D1.1 m, 开孔率0.04 : 合格负荷 0.60~1.2013 个点 D1.1 m, 开孔率0.05 : 合格负荷 0.75~1.2010 个点 D1.1 m, 开孔率0.06 : 合格负荷 0.90~1.207 个点 D1.2 m, 开孔率0.04 : 合格负荷 0.75~1.2010 个点 D1.2 m, 开孔率0.05 : 合格负荷 0.90~1.207 个点 D1.2 m, 开孔率0.06 : 合格负荷 1.10~1.203 个点逐段剖析这段代码把 204 行数据变成结论——每个几何组合下的合格负荷区间。三条读表规律值得记住开孔率越大下限越高D1.0 时 0.50→0.65→0.75开孔率大 → 孔气速低 → 更易漏液所以下限被抬起来塔径越大下限也越高开孔率 0.04 时 0.40→0.50→0.60→0.75同理由塔径大 → 气速低 → 更易漏液上限基本由泛点率锁定在不同几何间差异较小多在 1.10~1.20。最宽窗口出现在 D1.0 m 与 D1.1 m 的开孔率 0.04组合区间跨度均约 0.60即 0.50~1.10 与 0.60~1.20——这正是第 13 篇代价排序的输入。注意窗口最宽与压降最低不是同一个方案所以选型必须用多目标代价而不是单一指标。三、常见报错与排查报错 3-1续扫后结果表变空。现象第二次运行后 CSV 只剩少数行。根因文件以w模式打开把首轮结果覆盖了。解法改为有已完成键则a、否则w并在写表头前判断文件是否为空或tell()0。报错 3-2续扫时重复计算类似工况被算两次。现象结果表出现近似重复行。根因键未做浮点规范化0.06与0.060000000000000005生成两个键。解法哈希前round(v, 6)输入若来自 CSV读入即float()并 round。报错 3-3扫描跑了几小时还没完怀疑算力不够。现象耗时长。根因瓶颈通常在外部软件调用每次启动 KG-TOWER/PROII或逐行写文件不是公式。解法把外部调用抽象成批次任务 缓存结果CSV 改为批量 flush 或用 Parquet第 12/19 篇。报错 3-4合格率很低如 20%想调参让它高一点。现象反复调阈值以提高合格率。根因概念错误——扫描的目的是划出可行域边界不是刷通过率。解法检查阈值是否合理若合理如实报告可行域形状哪些维度是瓶颈不要为了让报告好看而放松阈值第 12 篇会把阈值三级标注防止随意改动。报错 3-5换了内件方案族后键冲突不同方案得到同一 case_id。现象切换方案后结果串味。根因键里没有方案标识。解法把internals_id型号关键参数纳入键即第 04 篇的bag_id__internals_id__hash三元组。四、动手练习练习 1跑通 幂等运行代码 2-1 两次。判定首轮输出总工况204 新算204 跳过0 合格105第二轮输出新算0 跳过204容差数值精确相等。练习 2聚合结论运行代码 2-2。判定输出若干行D… 开孔率… : 合格负荷 lo~hi找出合格区间最长的组合并写出其 D 与开孔率。练习 3删除断点后重算删掉_sweep.csv再运行。判定新算恢复为 204证明首轮行为随后再运行一次又变为 0证明幂等可重复建立。练习 4扩维把扫描维度从 3 个扩到 4 个新增tray_sp ∈ {0.45, 0.6, 0.75}预估组合数并实跑。判定组合数 4×17×3×3 612与实测总工况一致容差 0并能说明新增维度为什么会同时改变上限判据“与背压”。五、小结与下一篇预告本篇把扫描引擎搭起来了工况矩阵本例 4×17×3204、四类扫描维度负荷/物性/塔径/内件方案族、变量-目标契约表、内容寻址键 断点续扫幂等实测续扫新算 0。三条要点可续比快重要瓶颈在 I/O 与外部调用不在公式合格率低不是 bug是可行域形状。第 12 篇《结果结构化落盘与设计裕度判定》把扫描长表升级为可审计的裕度体系——长表/宽表取舍、四类裕度泛点率/漏液比/背压/压降、判据阈值的三级标注铁律/最佳实践/经验法则、以及 CSV/Parquet/JSON 的元数据设计。示例将给出最紧项binding与最紧归一裕度的计算。本篇认知问题回显FAQQ1为什么批量核算的难点不是算得快而是可续、可查、可复现A因为一次扫描动辄几百到上万个工况现实里一定会被打断改参数、换机、崩溃、下班。没有断点续扫就要从头重算代价是重烧算力、软件侧还要重刷界面。可续性靠结果唯一键 落盘实现可查性靠结果层记录 method/units/warnings可复现靠固定随机种子与关联式来源记录。Q2全因子与拉丁超立方怎么选四类扫描维度是什么A全因子适维低≤3、水平少≤5的确定性扫描边界清晰、能做方差分析但组合数爆炸拉丁超立方适维高≥4的探索性分析样本效率高但边界点可能取不到。经验法则是先全因子打边界再 LHS 填内部。四类维度为负荷、物性ρ/μ/σ、塔径、内件方案族分别回答窗口多宽、体系变了结论还成立吗、标称档哪档最优、选哪个内件。Q3什么叫变量-目标契约表为什么它能避免扫错方向A它是扫描前写清的清单自变量及其范围/水平如 D 0.9~1.2 m 四档、load 0.40~1.20 步长 0.05、hole_ratio 三档以及因变量及其判据阈值flood_pct ≤85%、weep_ratio ≥1.5、dc_ratio ≤1.0、ok 为三者同时成立。它避免扫了半天却没有一个量是自己关心的也是扫描引擎的输入契约。Q4断点续扫与幂等怎么实现为什么必须用内容寻址的键A用case_id sha1(规范化输入)[:10]作唯一键只哈希决定结果的输入字段、哈希前做浮点 round、用sort_keysTrue稳定序列化运行时先读已完成键集合跳过已算工况落盘时有已完成键则追加、否则新建并写表头。必须内容寻址因为自增序号在改变扫描顺序后会错位而内容寻址保证同输入同键从而跳过与幂等都成立。实测首轮 204/新算 204续扫新算 0。Q5怎么判断105 个合格工况是有意义的A用聚合把长表变成结论按 (D, hole_ratio) 分组取每个组合下连续合格的负荷区间lo~hi与点数比较各区间的长度。合格率约 51% 是正常现象——扫描的目的是划出可行域形状与瓶颈维度而不是刷通过率因此不应为让报告好看而放松阈值阈值须按第 12 篇的三级标注管理。
网站建设高端定制企业官网