资讯动态

MIKE 21随水深变化的底床糙率文件制作:从原理到脚本实践

发布时间:2026/10/3 10:43:58 来源:尧图企业网站定制
MIKE 21里想给底床糙率加上水深函数属性很多人在这一步卡住到处搜也搜不到能直接照做的教程。我当年买过的MIKE 21快速入门书里对糙率这部分也基本是一带而过只告诉你在面板里输入一个M值完全没提怎么处理随水深变化这种更贴近实际的需求。这其实不是MIKE 21不能做而是需要先理解它的输入逻辑再根据逻辑去生成一份专门的糙率空间分布文件。这篇文章我就从头到尾把这个过程拆开讲从原理到两种制作方法再到最后怎么挂进模型、怎么验证全部串起来。1. 先搞懂MIKE 21底床糙率的读取逻辑1.1 Manning数M和糙率系数n别搞反MIKE 21里涉及底床糙率时最常用的是曼宁公式。很多做水文水动力的人对v (1/n) R^(2/3) S^(1/2)不陌生公式里的n就是曼宁糙率系数n越大代表床面越粗糙、水流阻力越大。但在MIKE 21的参数面板里默认输入值往往不是n而是曼宁数MM和n互为倒数M 1 / n比如野外手册查到的天然河道糙率n0.035在MIKE 21里如果选的是Manning number类型要填的就是M 1 / 0.035 ≈ 29这个换算关系看似简单实际建模时却特别容易翻车。我见过不止一个初学者把n值直接原封不动填进Manning number的输入框里导致模型里的糙率比原意大了将近30倍水位怎么率定都对不上。所以在动手做糙率文件之前先问自己一句模型里选的是Manning number还是Manning n后面所有文件的取值都围绕同一个标准来。1.2 随水深变化为什么不是内置选项既然MIKE 21能处理空间变化糙率、时间变化糙率那为什么不能直接在界面上写一句糙率等于某个关于水深的函数原因在于MIKE 21的核心计算逻辑是按网格单元逐项读参数的。水深在空间上是分布的同一个时刻主槽水深5米、滩地水深0.3米想让糙率跟着水深一起变本质上是让每个网格单元拿到一个符合它的水深条件的糙率值。软件不是不能算而是这个水深与糙率的映射关系需要你自己提前算好再写成空间分布文件喂给它。所以正确思路是先想办法得到模型范围里的水深分布再用一整套规则把水深换算成糙率最后生成一份dfs2或dfsu文件让MIKE 21在每一时刻从文件里读取对应网格的糙率。记住这条链路后面的操作就顺理成章了。2. 制作糙率文件前必须准备好的三个数据2.1 网格和地形文件不管你是用结构网格的MIKE 21还是非结构网格的MIKE 21 FM糙率文件必须与模型网格在空间上一一对应也就是说文件里的每个网格单元位置、坐标系、投影都要和模型完全一致。最好的做法是不要新建一个大概差不多的网格而是直接基于模型的地形网格来创建糙率文件。实际操作中你先确认手头有以下基础文件结构网格网格定义文件.mesh或已经在MIKE Zero里导出的地形dfs2非结构网格网格文件.mesh注意是FM模型的mesh格式水深结果文件或用于推水深的初始水位场检查网格和地形的时候重点看单位是米还是坐标单位很多从CAD或GIS导进来的数据会带着奇怪的坐标系导致后续文件叠加时出现偏移。MIKE 21对这类问题不怎么给明确报错往往只是模拟结果不对排查起来非常痛苦。2.2 水深基准场怎么来要知道随水深变化就得先有一个水深场。这个水深场可以有两种获取方式。方式A跑一个稳态模拟。设置上游入流或者恒定水位边界下游给定水位边界让模型稳定运行足够长时间直到整个计算区域内的水位和流量不再随时间变化。从结果文件里直接提取Water Depth这一项就得到当前工况下的水深分布。这个方法适合有明确上下游边界条件、关心特定流量级下水深工况的项目。方式B如果没有水动力结果也可以用初始水位减去地形高程来近似。比如整个模型范围你给定一个初始水位5米地形高程是3米的地方初始水深就是2米。这种方式简单粗暴适合用来做主槽和滩地糙率分区这种概化程度较高的处理。需要注意地形高程高于水位的地方水深为负要单独处理成0或者一个无效值不能让它参与糙率映射计算。我自己通常更喜欢用稳态模拟的方式因为这样得到的水深场与后续要跑的计算工况更接近特别是研究洪水演进时不同流量下主槽与滩地的过水面积完全不一样用同一个静水水深场去定糙率分区会有偏差。2.3 水深-糙率映射表怎么定有了水深场接下来就是确定多深的水对应多大的糙率。这一步没有任何软件能替你拍板必须结合你自己的项目资料。一个典型的平原河道漫滩系统映射关系可以设置成下面这样水深范围米曼宁糙率 n对应曼宁数 M0 ~ 0.50.040250.5 ~ 1.50.035291.5 ~ 3.00.03033 3.00.02540这个表的逻辑其实很符合水力学直觉浅水区往往在滩地上有杂草、灌木甚至建筑物阻力大深水区一般是主槽河床被水流冲刷得比较光滑阻力小。如果研究区域是山区性河流河床卵石粒径大糙率整体要提高如果是感潮河段底质较细糙率整体可以降低。这里多说一句映射表只是一个初始方案最后还要靠实测水位流量过程率定。但好消息是用文件方式管理糙率后改糙率只需要重新生成一次文件不需要动MIKE 21模型主体结构效率比直接改参数高很多。3. 没有编程基础也能做的MIKE Zero手动生成法3.1 用Grid Series Editor做栅格重分类如果只做一次糙率文件网格数量也不大完全可以在MIKE Zero里手动搞定不用写一行代码。具体步骤是这样的打开MIKE Zero选择Grid Series Editor模块。新建一个dfs2文件这时需要设置网格属性。强烈建议直接读取现有水深结果文件或地形文件的网格属性确保坐标系、网格大小、起始点、旋转角完全复制过来这一步能避免后续文件读不进模型的各种低级错误。在水深文件中确认数据通常水深结果文件里可能还有水位、流速等多个item你自己要知道哪一个item代表Water Depth。用Grid Series Editor里的数学表达式功能做栅格重分类。比如可以应用条件表达式当水深小于0.5米时赋0.04当水深介于0.5到1.5米时赋0.035以此类推。将计算结果导出或另存为一个新的dfs2文件这就是初步的糙率空间分布文件。手动方式的优点在于直观每一步都看得见缺点也很明显一旦做的是非结构网格dfsuGrid Series Editor不是直接支持的。如果你用的是MIKE 21 FM非结构网格建议直接跳到下一部分的脚本方法或者先用DFS2做再通过网格插值转成dfsu。3.2 借助GIS和网格插值工具实现重分类还有一种曲线救国的方式把MIKE 21的水深结果导出成网格点数据XYZ或ASCII格式放到QGIS或ArcGIS里用栅格计算器做重分类然后再把重分类后的栅格导回MIKE Zero支持的dfs2格式。这个流程对熟悉GIS的人很友好因为栅格计算器里写条件表达式比MIKE Zero里的数学表达式更顺手而且可以复用很多现成的地表分类数据。这里有一个关键提示从MIKE导出XYZ再导回dfs2中间会经过一次散点插值插值方法选不好会改变糙率空间分布的细节甚至出现某些单元的空值。我一般建议用最近邻或自然邻域插值不要用克里金或样条因为糙率本身是分区常量式分布平滑插值反而会让不同水深区交界处的糙率出现过渡带那不是你想要的效果。3.3 手动方法的适用边界什么时候用手动方法就够了我的判断标准是模型网格数量在几万以下水深-糙率的分段规则不变只需要生成一版文件供对比计算。这时候用Grid Series Editor或者GIS重分类都行省时省力。但当出现下面任何一种情况手动方式就开始让人抓狂了网格超过几十万个重分类计算时间很长需要多次调整深度-糙率分段阈值每改一次就要重做一遍有多个工况、多个水深基准场需要批量生成糙率文件想对糙率文件做进一步的统计、平滑、分区处理这时候就该上脚本了。4. 批量生成糙率文件Python脚本才是效率解药4.1 为什么推荐脚本DHI这些年开放了不少接口其中mikeio这个Python库已经相当成熟可以直接读写dfs2、dfsu、dfs0这些MIKE格式文件。用它来做水深重分类本质上就是把你在GIS里手动干的活变成可重复执行的代码好处是参数调整只改一行阈值文件批量生成只是循环的事而且代码跑完的结果确定性高不容易出现手动操作时的误点漏点。前提是你的电脑上装好了Python环境以及mikeio库。安装方式和其他Python库没有区别pip install mikeio如果你还没装Anaconda或Miniconda建议顺手装一个后面处理其他水文数据也用得上。4.2 用mikeio读取水深并生成dfs2下面这段代码我实际跑过可以直接参考。假设你已经有一个稳态模拟得到的水深结果文件water_depth.dfs2我想把它转成曼宁系数n的糙率文件。import numpy as np import mikeio # 读取水深结果第一个item假设是Water Depth ds mikeio.read(water_depth.dfs2) depth ds.data[0] # 定义水深 - 曼宁糙率n的映射函数 def n_from_depth(depth): n np.full_like(depth, 0.030) # 默认值 n[depth 0.0] 0.040 # 干单元区域 n[(depth 0.0) (depth 0.5)] 0.040 n[(depth 0.5) (depth 1.5)] 0.035 n[(depth 1.5) (depth 3.0)] 0.030 n[depth 3.0] 0.025 return n n_rough n_from_depth(depth) # 写回新的dfs2文件 out_items [mikeio.ItemInfo(Manning n, mikeio.EUMType.Manning_Resistance_Number, mikeio.EUMUnit.manning_resistance_number)] ds_out mikeio.Dataset([n_rough], timeds.time, geometryds.geometry, itemsout_items) ds_out.to_dfs(roughness_n.dfs2)这里有一个单位问题的提醒如果你在MIKE 21模型面板里选的是Manning number M那你应该把n_from_depth的输出取倒数再写进文件也就是M 1 / n。如果你选的是Manning n就可以直接写n。两种方式都能让模型跑起来但一定要注意和模型设置匹配这是我实际踩过最深的坑之一。4.3 非结构网格dfsu的生成对于MIKE 21 FM模型的非结构网格处理逻辑完全一样只是读写对象从dfs2变成了dfsu。mikeio对dfsu的支持也很成熟读取后数据形状是时间步 × 单元数重分类操作完全兼容。ds mikeio.read(water_depth.dfsu) depth ds.data[0] n_rough n_from_depth(depth) out_items [mikeio.ItemInfo(Manning n, mikeio.EUMType.Manning_Resistance_Number, mikeio.EUMUnit.manning_resistance_number)] ds_out mikeio.Dataset([n_rough], timeds.time, geometryds.geometry, itemsout_items) ds_out.to_dfs(roughness_n.dfsu)需要注意的是dfsu文件里各个单元的排列顺序是固定的重分类时不要做任何会改变单元顺序的操作比如排序、去重。只要你不重排数组参考模板文件读取和写出就会保持元素一致性。5. 把糙率文件挂进MIKE 21模型里的正确姿势5.1 结构网格MIKE 21的加载路径如果你用的是MIKE 21结构网格模块打开HD参数设置界面找到Bottom Roughness或Bed Resistance这一项。这里选择Spatial Variation空间变化然后指定刚生成的dfs2文件。界面会要求你选择对应的item序号如果你生成的文件里只有糙率这一个item一般就是第1个。加载后还要注意时间轴的设置。如果糙率文件里只有一个时间步模型在计算时会把该值视为恒定不变如果文件里含有多个时间步MIKE 21会做时间插值。对于随水深变化的需求通常使用单时间步的恒定空间场就够了因为水深-糙率的转换关系本身就是一套固定的映射不是随时间任意变化的。5.2 非结构网格MIKE 21 FM的加载路径MIKE 21 FM的路径略有不同但也很直观进入Domain设置找到Bed Resistance把类型改为File选择dfsu糙率文件。这里同样需要指定item序号。FM模型对这个文件的网格一致性要求更高因为dfsu的网格和单元顺序必须与模型计算网格完全一致否则加载时直接报错。我建议在生成dfsu糙率文件时直接用模型本身输出的dfsu结果文件作为模板读取这样网格和单元顺序无论如何都不会错。不要绕道dfs2再插值一次多一步就多一个出错的可能性。5.3 坐标、单位和时间轴的三个大坑这部分全是我实践里见过的问题专门列出来。第一个坑是坐标偏移。用Grid Series Editor手建dfs2文件时很多人不复制原网格属性结果文件虽然能打开但导入模型后糙率分布整体偏移了几公里。这种问题在结果上看不太出来因为模型照样能算但你会觉得怎么填了糙率文件水位反而更不对了。排查方法是用MIKE Animator同时打开地形文件和糙率文件检查两者的等值线是否重合。第二个坑是单位。MIKE本身很灵活但灵活也意味着容易混乱。比如在一个使用Manning number的模型里你却喂进去一份Manning n的糙率文件糙率差异会直接导致模型结果失真。我的办法是在文件名里就写清楚是n还是Mroughness_n.dfsu还是roughness_M.dfsu形成习惯。第三个坑是时间轴。如果你生成文件时不小心把时间基准、时间步长设得和模型不一致MIKE 21可能会用插值或取最近值的方式读取糙率的时间变化就不符合预期。稳妥做法是用模型可接受的绝对时间起点文件时间步设置为单步。6. 文件生成后怎么验证有没有生效6.1 可视化检查空间分布糙率文件生成并加载进模型后不要急着直接跑正式模拟先做一次简单的可视化验证。用MIKE Animator打开模型的地形文件和糙率文件把两者并排显示。重点观察糙率分区是否与地形走向一致浅滩区域是不是确实取了较大的糙率主槽是不是取了较小的糙率。如果某处出现零值、负值或者异常大的值多半是水深场中存在干单元或异常缩放导致的。这些位置在干湿交替计算中虽然不一定被激活但一旦计算水位上升、干单元变成湿单元明显的糙率异常值就可能引发数值不稳定轻则结果跳动重则直接发散。6.2 用对照模拟判断糙率文件的合理性最有效的验证方式是跑一组对照同一个模型、同一个边界条件一组用全模型恒定糙率另一组用随水深变化的糙率文件然后对比关键断面或站点模拟出的水位、流速过程线。如果随水深变化的糙率文件是合理的你通常能看到低水位时期浅水区糙率较大模拟水位比常数糙率方案更高一些流速更低高水位时期主槽深水区糙率起主导作用两种方案差距缩小。这种规律性差异说明糙率文件确实在计算中发挥作用了也和你设置的映射关系一致。如果对照结果完全没有差异首先要怀疑糙率文件根本没有加载成功比如item选错了、时间轴不匹配或者模型里仍然使用默认糙率值。这是我认为最需要建立的一个排查顺序先确认文件加载再确认映射逻辑最后确认取值量级。6.3 率定时的调整顺序最后聊一下率定的调参顺序。糙率映射表一般有三到四个参数浅水糙率、过渡水深阈值、深水糙率。每次调整我建议只动一个参数比如只调整浅水糙率从0.040改到0.050其他保持不变。这样你才能从模型响应中判断出水位偏高是因为滩地糙率偏大还是因为深水主槽糙率偏大。一个比较实用的经验是水位偏低优先增大浅水区糙率水位偏高优先减小深水区糙率。因为水位偏高通常意味着河道的泄流能力不够问题往往出在主槽阻力被高估了水位偏低则意味着阻力被低估浅水漫滩区域往往是主要嫌疑。当然这只是一般规律具体项目还要结合植被、底质和实测资料来判断。另外糙率文件做出来不是一劳永逸的。如果模拟里既有枯水季又有丰水季水深分布差异很大建议对不同流量工况各生成一份糙率文件然后在模型里按时间区间切换。MIKE 21支持时间上分段的文件利用这个特性可以让不同时期用不同糙率场比全局一套糙率更合理。我在实际项目中体会最深的一点是糙率文件本质上是你对水下地形阻力的空间概化的一套看法它不是越复杂越好。分三到五个水深区间基本够用分十几个区间除了增加率定难度并不会带来明显的精度提升。先跑通、再对比、再逐参数调整这条路径走下去随水深变化的糙率文件就能真正为你所用而不是变成模型里一个看起来专业但没啥反应的摆设。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑