☰
PHAST-SAFETI二次开发教程(07):气象与地形工况——Weather、大气稳定度、地面条件与建筑阻塞区
2026/10/8 2:05:19 网站建设 项目流程

PHAST-SAFETI二次开发教程(07):气象与地形工况——Weather、大气稳定度、地面条件与建筑阻塞区

版本声明块

  • 工具/软件:Phast™ / Safeti™(版本主线 9.x,具体以官方发布说明为准)
  • 语言/环境:Python ≥ 3.11;官方库 PyPWS(包名pypws);桌面侧气象/地图设置以官方 User Manual 为准
  • 本文目标:把「气象 × 地面 × 建筑/阻塞」这组环境输入整理成可枚举、可复现、可审计的工况矩阵

一句话结论:环境输入不是一个数,而是一组维度——官方 PyPWS 把气象与地面抽象为Weather与Substrate两个实体、把大气稳定度抽象为AtmosphericStabilityClass、把地面类型抽象为SurfaceType与PoolSurfaceType;批量场景的气象工况数等于各维度取值数的连乘(例如风速 3 档 × 稳定度 6 档 × 地面 2 类即 36 个气象工况,此处数值仅作组合逻辑示意),因此「工况爆炸」必须在生成阶段就被算清并去重。

本篇铁律适用(三级标注,取自系列登记的 10 条)

  • [硬约束] 铁律 4 单位与坐标系纪律:风速、温度等一律 SI;地图导入前先声明 GIS 坐标系基准。
  • [硬约束] 铁律 2 闭源事实纪律:实体属性名与枚举取值以官方 PyPWS 参考文档为准;未确证字段在代码中显式标注待核对。
  • [强约束] 铁律 6 批处理幂等 + 可续跑:工况矩阵必须可重放,命名唯一。
  • [提示] 铁律 8 物理量不臆造:稳定度分类、粗糙度等取值来自官方技术文档或项目法规依据,不自造。

〇、本篇要解决的认知问题

  1. 一个Weather由哪些维度构成,哪些是自由度、哪些是派生量?
  2. 大气稳定度在数据模型里是什么,AtmosphericStabilityClass与风速是什么关系?
  3. 地面条件为什么要拆成Substrate、SurfaceType、PoolSurfaceType三层?
  4. 建筑(尾流/室内释放)在什么场景下必须打开,对结果影响在哪一环?
  5. 地图上的阻塞区(congested regions)为什么是爆炸建模的输入,而不是扩散的输入?
  6. 把气象做成批量维度时,怎么避免组合爆炸与重复工况?

以下「认知问题回显(FAQ)」与上列问题一一对应、同序作答。


一、机制解析

1.1 环境输入的三个维度

官方 PyPWS 的输入实体清单里,环境输入占两个:Weather与Substrate;枚举清单里与它们相关的至少四个:AtmosphericStabilityClass、SurfaceType、PoolSurfaceType,以及与热辐射类结果相关的RadiationType。官方对泄漏计算的描述也点明「关联数据对象如 leaks、pipe ruptures、weathers 在调用计算时被消费」,说明气象是被消费的独立数据对象,而不是计算对象的一个散装字段。

维度数据载体典型自由度作用环节
风Weather风速、风向量扩散(UDM)、火焰倾角
大气条件Weather+AtmosphericStabilityClass稳定度类别扩散的湍流参数
地面/基底Substrate地表类型、粗糙度类特征扩散的近地面边界
地表介质SurfaceType/PoolSurfaceType陆地、水面等;液池所处表面液池扩展与蒸发
建(构)筑物场景级设置尾流模型、室内释放开关扩散初始条件
阻塞区地图/plot plan 几何阻塞区空间范围爆炸超压建模

1.2 稳定度的位置

风速 / 风向 │ ▼ ┌─────────────────┐ 稳定度类别(AtmosphericStabilityClass) │ Weather │◀──── 由风速与大气条件共同确定,落在环境对象上 └────────┬────────┘ │ ▼ ┌─────────────────┐ 地面条件(Substrate / SurfaceType / PoolSurfaceType) │ 扩散(UDM) │◀──── 近地面边界与地表介质 └────────┬────────┘ │ ┌────────┴────────┐ ▼ ▼ 火灾/毒性结果 阻塞区几何 ──▶ 爆炸超压建模

这张图要读出两条「不连线」的关系:阻塞区不参与扩散的湍流参数),它服务的是爆炸建模;而地面条件参与扩散与液池,不参与爆炸。把输入挂错环节是环境类错误中最常见的一类。

1.3 组合爆炸的算术

气象工况数 = ∏(各维度取值数)。工程上必须先把这张乘积算出来再决定策略:全因子(所有组合都跑)适合筛选与达标论证;一次一因子(固定基准、逐维变动)适合敏感性归因。官方在 Safeti™ 侧使用sensitivity studies(敏感性研究)这一名称,Phast™ 侧 9.0 引入的批量执行能力名为Batch runner——两者不要混用,也不要生造别的功能名。

1.4 环境输入的版本与证据纪律

环境参数是最容易被「顺手抄」的一类输入:上一份报告里的风速、别人模板里的稳定度、界面上残留的默认值,都可能在你不知情的情况下进入工况。三条纪律把这类风险压到最低。

第一条,每个气象取值都要有出处。现场气象年、法规规定的设计工况或官方技术文档三者必有其一,并在工况表里以来源列固定;查不到出处的取值一律以官方文档为准,不得凭经验填写(铁律 8)。

第二条,风速与稳定度必须成对登记。二者在物理上耦合,只记风速的工况表在复现时无法确定湍流强度;因此工况表的主键应包含稳定度,去重也按「风速 + 稳定度」这一对来判断。

第三条,地面条件要区分「扩散边界」与「液池边界」。同一块地即使物理上只有一种形态,在数据模型里也要分别声明扩散侧的地面/基底条件与液池侧的表面类型,否则改了一处以为改了全部,结果只动了半边。

此外,建筑尾流与阻塞区属几何与场景级设置,它们的口径随版本演进较多,落地前应回到官方 User Manual 与发布说明核对,不要沿用旧项目的配置假设。


二、完整操作与脚本逐段剖析

2.1 第一段:构造气象与地面实体

说明:以下实体类名、枚举名与导入路径取自官方 PyPWS 参考文档;属性名以官方 PyPWS 参考文档为准(铁律 2),标注[核对]的行请在落地前按官方字段表确认名称与单位。

# -*- coding: utf-8 -*-# 演示:构造一个气象对象与一个地面(基底)对象frompypws.entitiesimportWeather,Substrate# 官方实体:气象、基底frompypws.enumsimportAtmosphericStabilityClass# 稳定度枚举frompypws.enumsimportSurfaceType,PoolSurfaceType# 地面类型 / 液池表面类型frompypws.utilitiesimportgetAnalyticsApiTarget# 打印当前 API 目标print("Running against: %s"%(getAnalyticsApiTarget()))# 先固定运行目标,便于审计weather=Weather()# 声明气象对象weather.windSpeed=5.0# [核对] 风速,单位 m/s(SI)weather.stabilityClass=AtmosphericStabilityClass.D# [核对] 大气稳定度类别(示例取 D 类)# 说明:稳定度取值集合以官方枚举定义为准;下方逐项打印用于确认枚举可用取值substrate=Substrate()# 声明地面/基底对象substrate.surfaceType=SurfaceType.LAND# [核对] 地表类型(示例取陆地)substrate.poolSurfaceType=PoolSurfaceType.LAND# [核对] 液池所处表面类型substrate.surfaceRoughness=0.03# [核对] 地表粗糙度,单位 m(按官方字段表核对量纲)# 枚举自检:确认当前安装版本提供了预期的枚举成员(防止跨版本名称漂移)members=[mformindir(AtmosphericStabilityClass)ifm.isupper()]# 只取大写成员print("AtmosphericStabilityClass 成员:",members)# 打印后填入你自己的取值白名单print("SurfaceType 成员:",[mformindir(SurfaceType)ifm.isupper()])print("PoolSurfaceType 成员:",[mformindir(PoolSurfaceType)ifm.isupper()])

这段代码的两个设计意图:一是用枚举自检把官方枚举成员打印出来,避免凭记忆写错稳定度类别;二是把所有[核对]行集中,让代码评审时一眼看到哪些属性名还需要回到官方文档确认。

2.2 第二段:生成气象工况矩阵(笛卡尔积 + 去重)

# -*- coding: utf-8 -*-# 演示:把气象维度展开为可复现的工况矩阵,并写出审计用的 CSVimportcsv# 标准库:写 CSVimportitertools# 标准库:笛卡尔积frompypws.entitiesimportWeather,Substrate# 实体frompypws.enumsimportAtmosphericStabilityClass,SurfaceType# —— 维度定义:每一维的取值都应有出处(法规/项目约定/官方文档)——WIND_SPEEDS=[1.5,5.0,9.0]# 风速档位 m/sSTABILITIES=[AtmosphericStabilityClass.D,# 稳定度档位(示例两档)AtmosphericStabilityClass.F]SURFACES=[SurfaceType.LAND,SurfaceType.WATER]# 地面类型档位(示例两档)defbuild_weather(wind_speed,stability):"""按风速与稳定度构造 Weather 实体。"""weather=Weather()# 新建气象对象weather.windSpeed=float(wind_speed)# [核对] 风速 m/sweather.stabilityClass=stability# [核对] 稳定度枚举returnweather# 返回可直接消费的气象对象defbuild_substrate(surface):"""按地表类型构造 Substrate 实体。"""substrate=Substrate()# 新建基底对象substrate.surfaceType=surface# [核对] 地表类型returnsubstrate# 返回基底对象# —— 展开笛卡尔积,并给出显式的工况标识 ——cases=[]# 工况清单容器forindex,(wind_speed,stability,surface)inenumerate(itertools.product(WIND_SPEEDS,STABILITIES,SURFACES),start=1):case_id="W%03d"%index# 唯一工况号:幂等与续跑的基础(铁律 6)cases.append({"case_id":case_id,# 工况号"weather":build_weather(wind_speed,stability),# 气象对象"substrate":build_substrate(surface),# 基底对象"wind_speed":wind_speed,# 原始维度值,便于审计"stability":stability.name,# 枚举名,便于落盘"surface":surface.name,# 枚举名,便于落盘})# —— 组合数自检:乘积必须等于工况条数,否则说明生成逻辑有漏(铁律 6)——expected=len(WIND_SPEEDS)*len(STABILITIES)*len(SURFACES)# 各维连乘assertlen(cases)==expected,"组合数不符:%d vs %d"%(len(cases),expected)# —— 去重自检:以(风速, 稳定度, 地表)三元组为主键 ——keys=[(c["wind_speed"],c["stability"],c["surface"])forcincases]# 主键列表assertlen(keys)==len(set(keys)),"工况矩阵存在重复主键"# —— 落盘审计 CSV:只写维度值,不写不可序列化的对象 ——withopen("weather_cases.csv","w",newline="",encoding="utf-8")asfh:writer=csv.DictWriter(fh,fieldnames=["case_id","wind_speed","stability","surface"])writer.writeheader()# 表头forcaseincases:# 逐工况写行writer.writerow({k:case[k]forkinwriter.fieldnames})# 只取标量字段print("生成工况数:",len(cases))# 人工确认规模

要点:工况号case_id由生成顺序确定,因此只要维度定义不变,工况号就不变——这是断点续跑与结果对账的前提。

2.3 第三段:把气象工况接到泄漏计算并在批量中轮换

# -*- coding: utf-8 -*-# 演示:把气象/地面工况轮换注入泄漏计算,收集排放记录首条速率frompypws.calculationsimportVesselLeakCalculation# 官方容器泄漏计算frompypws.enumsimportResultCode# 结果码defrun_case(case,vessel,leak,calculation_factory=VesselLeakCalculation):"""对单个气象工况执行一次泄漏计算,返回 (case_id, 结果码, 首条记录)。 设计要点: 1) 工厂函数注入,便于单元测试时替换为假对象; 2) 每次新建计算对象,避免跨工况状态污染(幂等要求)。 """calculation=calculation_factory()# 新建计算实例calculation.vessel=vessel# 复用容器对象(含上游相态)calculation.leak=leak# 复用泄漏对象calculation.weather=case["weather"]# 注入本工况气象calculation.substrate=case["substrate"]# 注入本工况地面条件result_code=calculation.run()# 执行计算first_record=None# 首条排放记录占位ifresult_code==ResultCode.SUCCESS:# 仅在成功时取数records=calculation.dischargeRecords# 排放记录列表first_record=records[0]ifrecordselseNone# 取首条(稳态恒有 2 条)else:calculation.print_messages()# 失败时打印诊断消息returncase["case_id"],result_code,first_record# 返回结构化结果results=[]# 结果容器forcaseincases:# 遍历上一段的工况矩阵case_id,code,record=run_case(case,vessel,leak)# 执行单工况results.append({# 记录结构化结果"case_id":case_id,"result_code":code.name,# 结果码名称,便于分组统计"first_record":str(record),# 字段以官方参考章为准})failed=[rforrinresultsifr["result_code"]!="SUCCESS"]# 失败隔离print("总工况:%d,失败:%d"%(len(results),len(failed)))# 批量健康度一眼可见foriteminfailed:# 打印失败清单print("失败工况:",item["case_id"],item["result_code"])# 便于针对性重跑

工程要点:失败工况不抛出中断整个批,而是收集到failed清单;配合 2.2 段的稳定case_id,即可实现「只重跑失败工况」的断点续跑。

2.4 建筑与阻塞区的处理位置

建筑尾流模型与室内释放属于场景级环境设置;地图上的阻塞区属于几何输入,用于爆炸建模。二者在桌面侧配置(以官方 User Manual 为准),在 API 侧则以场景输入传递。落脚本时的纪律是:几何入几何文件/配置,不要塞进气象对象,否则后续维护无法追溯哪一层改了。


三、常见报错与排查

现象 1:枚举成员名写错,脚本在构造处即抛AttributeError。
根因:跨版本枚举命名漂移,或凭记忆写了字母类别而官方枚举另有命名体例。
解法:如 2.1 段那样用dir()打印实际成员并建立本地白名单;把白名单与版本号一起入库。

现象 2:改风速后结果几乎不动。
根因:稳定度与风速在物理上耦合,只改风速而稳定度保持在极端类别,湍流参数被稳定度主导。
解法:把风速与稳定度成对设计为矩阵(2.2 段),而不是单维扫风速。

现象 3:液池蒸发/池火结果与现场经验差异大。
根因:Substrate与实际地表不符(例如硬化地面按草地粗糙度、水面场景按陆地)。
解法:先确认地表类型,再确认液池所处表面类型,最后核对粗糙度量纲。

现象 4:爆炸结果每次都一样,改气象无反应。
根因:把气象当成爆炸的输入。阻塞区是爆炸建模的几何输入,气象主要作用于扩散与火焰形态。
解法:修爆炸场景时改几何阻塞区与点火相关设置,不要靠调气象。

现象 5:工况数远超预期,批跑时间失控。
根因:维度连乘未预估(3×6×2 一类组合在叠加孔径与物料维度后迅速上千)。
解法:在生成阶段打印乘积并断言上限;对筛选阶段改用一次一因子,最终论证阶段再上全因子。

现象 6:同一气象在不同机器上结果不同。
根因:环境工况只存在于界面里,没有随研究一起归档;换机器后稳定度或粗糙度落回了默认值。
解法:把环境工况表(含来源列与去重主键)与研究文件一起纳入版本管理,任何一次结果都标注所用的工况表版本。


四、动手练习

  1. 在 2.2 段的维度定义里加入第三个稳定度档位,验证组合数与weather_cases.csv行数同步增长,且已有case_id不发生错位。
  2. 为run_case()写一个假计算对象(返回固定ResultCode),验证失败隔离逻辑在没有真实服务时也能被执行。
  3. 挑一个你项目的现场气象,按官方 User Manual 的口径把风速与稳定度落到枚举值,并说明你选该稳定度的依据出处(铁律 8)。

五、小结与下一篇预告

本篇把环境输入整理为「气象 / 地面 / 建筑与阻塞区」三层,明确了Weather、Substrate与三个地面相关枚举的位置,给出了气象工况矩阵的生成、去重、审计与失败隔离写法,并守住了一条容易做错的边界:阻塞区服务爆炸建模,不服务扩散。下一篇08 第一个批处理将进入桌面侧的官方批量路径:Excel import快速建研究与Batch runner队列执行,把本篇的工况矩阵落成可跑的研究集合。


本篇认知问题回显(FAQ)

Q1:一个Weather由哪些维度构成,哪些是自由度、哪些是派生量?
答:自由度是风速、风向与大气条件(以稳定度类别表达)等可独立设定的量,它们在脚本侧落在Weather实体上;地面/基底相关量则落在独立的Substrate实体上。派生量是由这些自由度经过扩散模型计算得到的湍流参数与浓度场——它们不写在环境对象上,而是作为结果出现。完整的属性清单与期望单位以官方 PyPWS 参考文档为准,且一律 SI 单位。

Q2:AtmosphericStabilityClass与风速是什么关系?
答:它是把大气条件离散化为若干类别的枚举。稳定度与风速在物理上耦合(同一风速下不同稳定度对应不同湍流强度),因此工程上应把二者作为成对维度设计成矩阵,而不是只扫风速。具体类别集合以官方枚举定义与官方技术文档为准。

Q3:地面条件为什么要拆成Substrate、SurfaceType、PoolSurfaceType三层?
答:因为三者回答不同问题。Substrate是地面/基底对象,承载地表类型与粗糙度等近地面边界特征,作用于扩散;SurfaceType表达地表介质(如陆地、水面);PoolSurfaceType表达液池所处的表面类型,作用于液池扩展与蒸发。拆层是为了让「扩散的近地面边界」与「液池的热/质量交换边界」可分别设定与审计。

Q4:建筑(尾流/室内释放)在什么场景下必须打开,影响哪一环?
答:当泄漏发生在有显著建(构)筑物遮挡或处于室内的场景时,尾流模型与室内释放设置会改变扩散的初始与近场条件,必须在场景级环境设置中打开,否则近场浓度会被系统性低估。这些设置属桌面侧场景配置,入口与参数以官方 User Manual 为准。

Q5:阻塞区为什么是爆炸建模的输入,而不是扩散的输入?
答:阻塞区(congested regions)描述的是设备/结构密集造成的空间约束,其物理作用是影响火焰加速与超压生成,因此服务爆炸建模;扩散侧的边界由地面条件与气象承担。二者不该互相替代,这也是批处理中最常见的挂错环节错误。

Q6:把气象做成批量维度时,怎么避免组合爆炸与重复工况?
答:三步。第一,生成前先算乘积并设上限断言;第二,用去重主键(风速、稳定度、地表等标量组合)校验唯一性;第三,用稳定且与生成顺序绑定的工况号(如W001)作为幂等键,使得维度定义不变时工况号不变,从而支持断点续跑与结果对账。策略上,筛选阶段用一次一因子,论证阶段再用全因子。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询