Flac二次开发弹性应变能分析:FISH脚本、公式与工程应用
发布时间:2026/10/15 5:45:36 锦皓数字建站

做过Flac模拟的都知道默认后处理抓应力和塑性区已经很顺手了可真要关心“能量”的时候软件给出的信息就显得不够。我这次做的Flac二次开发就是为了解决一个实际工程问题怎么把模型里存储的弹性应变能分析出来并且用能量分布来评价开挖扰动的影响。这篇文章会把二次开发的思路、FISH脚本、公式推导、调试踩坑全部写清楚适合已经会Flac基本操作、想进一步写自定义功能的同行参考。弹性应变能这个名字听起来学术其实就是材料在弹性变形阶段攒下来的那部分可恢复能量。边坡、地下洞室、隧道这些岩体工程问题里能量在哪里积累、什么时候释放往往比单纯的应力大小更能说明问题尤其是判断潜在失稳区域和动力灾害倾向性的时候能量指标经常有奇效。别指望Flac吐出来的默认数据能直接给你画一张能量云图它不给你计算好了你需要自己动手写脚本去“算”。1. 项目整体设计与关键思路拆解1.1 软件原生能力缺在哪先说一个让我有切身体会的点Flac本身不是不能做能量计算但它原生给出的能量信息大多是单元整体能量或者总的变形能没法很好地拆成弹性部分和塑性耗散部分。举个例子你用弹塑性本构模型跑到收敛再查看某个zone的应力应变数据这组数据里包含了不可恢复的塑性变形如果你直接拿它代进能量公式算出来的结果是偏大的甚至是错的。这就要靠二次开发来补齐要么在模型里人工定义弹性应变能的计算函数要么直接另跑一个纯弹性模型做对照把弹性能量场单独提取出来。很多刚接触二次开发的朋友上来就会写一段FISH去循环每个zone但真正要落地到工程分析还得考虑分区统计、历史输出、可视化映射这一套流程其实比你想象的要长。1.2 选型用FISH还是用Python现在做Flac二次开发主要有两条路一条是FISH脚本另一条是Flac里带的外部脚本接口比如Python。我个人强烈建议核心的能量计算逻辑一定要用FISH去做。原因是FISH是直接在Flac内核里运行的对zone数据的内存访问是“原生级”的性能优势非常明显。特别是模型有几十万甚至上百万个zone的时候用外部脚本去逐zone读取应力应变再计算那速度会让你怀疑人生。FISH跑一遍全场能量扫描的时间如果用Python可能要等十分钟它一分钟之内基本能出结果这种差距在需要反复调整参数时非常致命。我的经验是混合使用FISH负责写能量计算和历史数据记录外部脚本负责后处理绘图和批量对比。这样两边都发挥各自的长处也不用在脚本语言上死磕性能。1.3 技术路线的设计这次项目的技术路线其实非常清晰分成四步走。第一步建立基准模型完成初始地应力平衡。第二步在模型稳定之后进行一次“能量扫描”得到开挖之前的初始弹性应变能场。第三步进行开挖或加载模拟实时记录每个zone的应力和应变用FISH函数生成能量密度。第四步将能量密度映射到zone的额外变量上用等值线云图展示同时输出全模型的总弹性应变能历史曲线。这里有一个关键设计要说明如果想要严格分离弹性应变能和塑性耗散比较稳妥的办法是跑两次模型。第一次使用纯弹性本构算出来的能量场就是纯粹的弹性应变能第二次使用实际的弹塑性本构算出来的总能量和弹性模型之间的差值就反映了塑性耗散和应力重分布的影响。这个思路看起来笨但在实际项目中操作性强也最容易被审报告的人理解。2. 弹性应变能的核心原理与公式2.1 能量密度从哪来弹性应变能密度通俗讲就是单位体积岩体“像弹簧一样被压缩或者拉伸的时候存下的能量”。这个概念的物理基础是应力对应变做功。在单轴压缩状态下单位体积弹性应变能等于应力-应变曲线下三角形的面积就是1/2乘以应力乘以应变的那个公式。到了多轴应力状态公式扩展成张量形式也就是弹性应变能密度等于1/2倍的应力张量与应变张量的双点积。写成展开式就是W 1/2 * (σxxεxx σyyεyy σzzεzz τxyγxy τyzγyz τzxγzx)。注意这里的切应变用工程切应变如果用张量切应变公式里的系数会不一样这一点非常容易算错。很多教程为了让公式简洁只保留了正应力项把剪切项漏掉了。我一开始也这么干结果发现剪切作用占主导的区域比如边坡坡脚算出来的能量云图明显不对。后来把剪切项补上才算是跟理论解对得上。2.2 弹性能与塑性耗散怎么区分搞清楚了公式紧接着就是弹塑性模型中怎么区分能量成分的问题。在纯弹性状态下总应变就是弹性应变所以直接用应力乘应变没问题。但一旦单元进入屈服应力应变关系就不再是一一对应的线性关系了这时候zone.strain返回的总应变里面已经包含了塑性应变分量。如果你还机械地套用0.5倍应力乘以总应变的公式那算出来的结果是“表观弹性应变能”比真实的可恢复弹性应变能要大。在塑性区比较发育的模型中这个误差会被成倍放大能量云图会在破坏区中心出现一个看上去特别吓人的高能团块但它压根不是实际可释放的能量。应对办法有两个。最简单粗暴的做法是只统计尚未进入屈服的zone用zone.state去判别。更严谨的做法是另跑一次纯弹性模型用弹性模型算出的能量场作为参考和弹塑性模型的能量场做差得到的差值就是塑性耗散和能量重分布的效果。这个方案在岩土工程领域有大量文献支撑也适合写进计算报告。2.3 单位与量纲检查Flac里面默认使用的是国际单位制的变体常见的组合是应力单位帕斯卡、长度单位米。按这个组合算出来弹性应变能密度的单位是焦耳每立方米也就是帕斯卡。如果你自己自定义了单位体系比如应力用兆帕、长度用米算出来的能量密度数值需要做转换否则写报告的时候会差出好几个数量级。这里分享一个习惯在FISH脚本里加一个单位换算变量比如换算系数等于1e6乘上去之后把能量密度转成千焦每立方米这样在和现场实测数据的单位对比时就不用来回倒腾了。看似小细节但曾经有一次我忘了转换单位直接把能量曲线和实测值放一起整整花了半天才排查出来。3. FISH实现与核心代码解析3.1 测试模型与数据组织在写FISH之前先建一个最简单的测试模型来做标定。我用的是一块单向压缩的立方体模型尺寸取了10x10x10米网格就用基本的等尺寸单元划分。模型四边约束顶部施加一个垂直压力所有材料参数都用最简单的弹性模量和泊松比这样能量解析解可以手算出来。测试模型的目的只有一个验证FISH算出来的能量跟手算的一致。这个步骤千万不要省因为后续面对复杂的工程模型时你不会有耐心去对照解析解而一旦脚本里隐藏了系数错误后面全部结果都是错的。在正式工程模型里数据组织也是有讲究的。开工之前就要把关注区域和非关注区域分开编组例如“开挖影响区”、“远场区”这样FISH在做分区统计的时候可以直接按组名过滤zone而不需要跑到脚本里一处一处改索引。3.2 第一个核心FISH函数全场弹性应变能计算下面这段就是我主推的全场扫描代码完全用FISH语言写。fish define elastic_energy_sum local total_e 0.0 loop foreach local zp zone.list local s zone.stress(zp) local e zone.strain(zp) local vol zone.volume(zp) local w 0.5 * ( s(1,1)*e(1,1) s(2,2)*e(2,2) s(3,3)*e(3,3) s(1,2)*e(1,2) s(1,3)*e(1,3) s(2,3)*e(2,3) ) total_e total_e w * vol endloop ee_total total_e end这段代码的逻辑非常直白遍历模型中每一个zone读取它的应力张量和应变张量计算单位体积能量密度再乘以单元体积后累加。这里有几个容易踩的坑。第一个stress和strain的读取一定要用zone.stress和zone.strain这两个函数不要用zone.stress.xx这种单独分量函数那样你需要写六遍甚至九遍调用代码冗长不说还容易记错下标。第二个张量数组的下标从1开始不是0这个跟很多高级语言的习惯不一样写习惯了就好。第三个切应变分量在Flac中的存储约定是工程切应变所以公式里直接用1/2括号展开不需要额外乘2这点已经在测试模型上验证过。计算完总能量之后我习惯把这个结果注册成一个FISH全局变量方便后续用历史命令去追踪。这样的话每跑一个计算时步我就能看到总弹性应变能是怎么变化的。3.3 第二个核心FISH函数能量密度写入zone总能量只能告诉你一个全局趋势但工程上更需要的是能量密度的空间分布。这就需要把每个zone的能量密度写进它自己的额外变量槽然后再用等值线图去渲染。fish define elastic_energy_extra loop foreach local zp zone.list local s zone.stress(zp) local e zone.strain(zp) local w 0.5 * ( s(1,1)*e(1,1) s(2,2)*e(2,2) s(3,3)*e(3,3) s(1,2)*e(1,2) s(1,3)*e(1,3) s(2,3)*e(2,3) ) zone.extra(zp,1) w endloop end学过Flac的朋友应该都熟悉zone.extra这种额外变量它就像给每个单元预留了一张便签纸你可以在上面写任何自己需要的量。写完之后在命令窗口里直接打contour extra 1屏幕上就会出现一张清晰的能量密度云图。这样做还有一个额外好处在后续做剖切、做切片分析的时候可以直接针对extra变量操作完全不改变Flac原有数据结构安全且高效。对我这种经常要出图做汇报的人来说这个方法比把能量数据写到外部文件再导入到绘图软件快太多了。3.4 历史记录与能量释放速率能量曲线单看意义有限我更在意的其实是能量随时间的变化速率也就是能量释放速率。这个概念在岩体动力灾害分析里很重要它等于弹性应变能对时间的导数。在Flac里追踪历史量非常简单。先用FISH定义一个函数返回当前模型的总弹性应变能然后通过history命令去记录这个函数的变化计算完成后就能得到一条总能量随计算时步变化的曲线。fish define hist_total_ee hist_total_ee ee_total end这条历史曲线的斜率就是天然的能量释放速率。发现曲线在某一段出现急剧下降说明模型里积聚的弹性应变能被大量释放这往往对应着开挖卸荷或者局部破坏的发生。我强烈建议大家在做完一个方案的计算之后顺手把能量历史曲线和数据文件都导出来。哪怕你暂时不写报告这个曲线也能帮你快速定位到计算过程中最危险的阶段帮助你判断模拟是否收敛、是否出现了非预期的大范围破坏。4. 实操中的坑与调试技巧4.1 zone.stress和zone.strain返回值的坑先说一个比较隐蔽的坑就是Flac里应力应变的数组存储方式跟材料力学书上不太一样。它返回的数组是按照tensor分量排列的其中1.1是xx分量2.2是yy分量3.3是zz分量1.2是xy切分量1.3是xz切分量2.3是yz切分量。如果你熟悉有限元软件常有的Voigt记号第一次看这个会有点蒙。还有一个更麻烦的问题zone.stress返回的应力是“力学正”约定的拉为正压为负。岩土里面我们习惯压为正不少人会把坐标换回去再算能量。我的建议是不要在FISH里面做符号翻转直接按Flac内置的约定计算因为弹性应变能的公式在符号上是对称的拉压不同组合下最终结果不会错只需要保证最后的报告里对正负号的定义给读者交代清楚。还有一次我在单轴压缩测试模型里发现算出来的能量密度跟理论解差了正好一倍。排查到最后发现问题出在应变数组上面我一开始使用的是zone.strain.volume这个函数它返回体积应变而不是应变张量两者在数值上差了一个维度。后来全部改成zone.strain之后立刻就和理论值对上号了。4.2 塑性区单元能量虚高问题这是整个项目里让我最头大的一个问题。在弹塑性模型的能量云图里塑性区深处的单元出现了非常夸张的能量密度数值比周边区域高出两个数量级。看上去就像是那个区域储存了巨大的能量但现场判断又完全不合理。后来冷静分析了一下问题在于塑性变形的累积让应变数组不断变大但应力并没有相应地继续增长因为单元已经进入屈服平台了。用0.5乘以“大应变”乘以“小应力”得到的是被放大的虚假能量真实的弹性应变能根本没那么大。解决办法我在前面已经提过就是通过zone.state判断是否屈服对屈服单元单独做标记处理。我这里给出一个结合状态判别的改进代码片段。fish define elastic_energy_plastic_filter loop foreach local zp zone.list local s zone.stress(zp) local e zone.strain(zp) local w 0.5 * ( s(1,1)*e(1,1) s(2,2)*e(2,2) s(3,3)*e(3,3) s(1,2)*e(1,2) s(1,3)*e(1,3) s(2,3)*e(2,3) ) local isYield zone.state(zp, 0, 0, 0) if isYield # 0 w 0.0 endif zone.extra(zp,1) w endloop end把屈服单元的能量密度置为0能量云图一下子清爽了。整个模型的高能区域恰好落在未破坏的岩体区域这种分布才是工程上可解释的。实际使用中还可以进一步优化把屈服标准从“是或否”改成按屈服程度分级比如用一个damage参数做连续权重但这要看你的材料模型具体输出什么没有通用方案。4.3 大变形模式下的体积与坐标更新Flac有大变形和小变形两种模式默认是小变形但对一些软岩大变形问题你可能会切到大变形模式。这时候单元的体积和坐标会随着大变形不断更新zone.volume返回的值是变形后的即时体积。如果能量计算脚本还是沿用初始体积就会出现能量总量持续偏大的问题而且越到变形后期误差越大。我的建议是在FISH计算能量的时候始终用zone.volume当前值不要自己在外面缓存一份初始体积数组。这样脚本平稳地适配两种模式不需要额外改参数。此外在大变形模式下应力更新会包含几何刚度的修正项这就意味着你拿到的应力张量已经反映了变形后的状态理论公式的部分系数会有些许变化。对工程分析来说这个影响通常很小不纠结但你要知道这个背景别到时候审报告的时候被问住了。4.4 FISH脚本调试的经验之谈FISH的调试环境相对简陋报错信息有时候就一句话比如illegal variable或者bad conversion。遇到这样的报错第一步就是在函数入口加上打印语句把第一个zone的编号、组名、应力数组都输出一遍确认遍历和数据读取没有二义性。另一个高频问题是函数内部的变量名和全局变量名冲突。FISH里如果你不写local声明变量默认就是全局的。一旦你在循环里使用了一个临时变量却忘了加local后面所有函数调用都能看到这个变量污染会很严重。我在开发时踩过这个坑一个循环跑完另一个函数里的计数器直接被改掉了排查了很久。所以规则很清晰凡是循环临时变量一律在定义时加上local前缀。最后还有一个小习惯新写的FISH函数不要直接丢进大模型去跑先在一个空模型或者小模型上用几个已知结果去验证。哪怕这个验证只花五分钟也能帮你避免在成千上万个zone上浪费一晚上的计算时间。5. 典型应用场景与工程影响分析5.1 用能量云图判断边坡潜在破坏热点弹性应变能分析在边坡工程里的价值我是在一次模拟实践中深有体会的。当时模拟一个多层岩质边坡的开挖过程用常规的剪应力云图看坡脚位置剪应力最高看起来最危险。但把弹性应变能密度云图调出来一对比发现能量积聚最突出的位置并不在坡脚而是在坡体中部偏上一点的位置。这个现象其实可以用能量集中解释那个位置的岩体被周围岩体“卡住”不易释放变形能于是能量越积越高。这恰好对应了现场监测中变形量不大但突然失稳的情形。传统指标和能量指标各有侧重你要是只看应力很可能会漏掉这种“低应力高储能”的危险体。后来我在大量算例里反复验证能量云图对高储能区的识别非常敏感。你在报告里放一张能量密度云图再用文字解释一下哪些地方是能量积累区评审专家一眼就能理解你的分析深度。5.2 地下洞室围岩弹性应变能与冲击地压倾向性判别地下洞室开挖后围岩应力重分布洞室周边岩体会出现一个高弹性应变能的环形区。这个环形区的厚度和能量密度直接关系着冲击地压和岩爆的倾向性。我在这类项目里通常会做开挖前后的弹性应变能对比计算能量增量然后做成曲面图。一个很关键的认识是高能量密度区不一定就是最危险的岩爆区。岩爆通常发生在能量密度高、同时围岩强度储备低或者存在结构面的位置。所以能量分析要跟强度指标结合不能单打独斗。工程上更稳妥的做法是把高能量密度区、高应力区和低强度储备区做野外三维叠加三个条件同时满足的区域标示为高风险区。这种分析方法做出来的成果比只给一个“安全系数不够”要高级得多也为后续支护方案的合理布置提供了明确靶点该加锚索的地方加锚索该让压的地方让压。5.3 能量释放速率作为预警指标单看总弹性应变能曲线等于看一个累积量变位不敏感。真正有预警价值的是能量释放速率也就是曲线的斜率。我在几次仿真中都看到过这样的现象某一段计算时步内总能量曲线突然出现一个明显的下跌台阶同时模型的最大位移并没有立刻加速而是滞后一段时间之后才开始快速增长。这个“能量先释放位移后响应”的顺序很有意思。如果你在仿真里加设一个能量释放速率阈值当速率超过该值时自动输出警告那你就能提前几个计算时步捕捉到破坏的先兆。当然阈值的设定没有万能公式要结合工程背景和计算结果反复标定。我的经验是先跑一个完整的开挖模型记录全部能量释放速率数据然后找出速率剧增的几个点再看这些点对应的空间位置和破坏模式从中确定合理的预警线。这个思路对于一个具体工程是可以迁移复用的。6. 常见问题与排查技巧实录6.1 问题速查表下面是我在这次二次开发过程中整理的问题速查表遇到类似现象可以直接对照排查。现象可能原因排查思路能量计算结果比理论值大一倍误把工程切应变当成张量切应变代入检查公式中剪切项系数确认Flac存储约定能量计算结果比理论值小一半少乘了0.5系数重新核对单轴压缩解析解塑性区出现异常高能量直接把总应变当弹性应变用增加zone.state判别或改用纯弹性模型对照能量数值量级不合理单位制混乱未做换算统一应力单位、长度单位设置换算系数同一函数在不同模型结果漂移局部变量泄漏成全局变量检查循环临时变量是否漏写local云图渲染没有数据extra变量写入失败或命令名错误确认zone.extra赋值语句执行成功检查contour命令引用编号这类表放在你的开发文档里非常有用自己排查的时候快后面交给同事维护也不至于一脸懵。6.2 从数据到代码的完整验证链路我最常用的排查方法是“从数据出发倒着找”。先手算一个简单模型的期望能量值比如一个10x10x10米的立方体受到单轴压力10兆帕弹性模量10000兆帕泊松比0.2那么轴向应变、侧向应变都可以手算出来能量密度的理论值也很容易算。然后把这个简单模型用Flac建出来加载同样条件跑通FISH脚本看输出的能量密度是否落在理论值附近。如果差得远就去检查自己的公式和数组下标如果对上再进入多单元模型逐步增加复杂度。这个方法本质上是在用最基础的力学原理给软件做“标定”比憋在代码里瞎猜高效太多了。6.3 数据导出的工程化落地你在实际做项目的时候能量云图只是中间成果深度分析还需要把每个zone的能量数据导出来和位移、应力、塑性状态放到同一个表格里做交叉分析。Flac的FISH支持文件操作你可以把能量密度、坐标、组名等按列写成文本文件然后在外部统计分析软件里生成联合分布图。我写了下面这段简洁的导出逻辑fish define export_energy local fp file.open(energy_export.csv, w) file.write(fp, x,y,z,group,W) loop foreach local zp zone.list local p zone.pos(zp) file.write(fp, string(p(1)) , string(p(2)) , string(p(3)) , zone.group(zp) , string(zone.extra(zp,1))) endloop file.close(fp) end这个文件是很好的中间数据。做项目汇报的时候我不止一次用它把能量密度数据跟现场实测的微震事件位置叠加起来两者的空间吻合度相当高。这种分析报告的说服力远大于单放几张孤立的云图。弹性应变能分析在Flac二次开发里并不算一个多高深的功能但它很实用尤其是在做开挖卸荷与稳定性评价的项目里。我个人最大的体会是不要迷信能量分析单打独斗它最适合跟塑性区、位移场、现场监测数据交叉印证。最顺手的工作模式就是把能量密度写进zone附加变量用云图看空间分布用历史曲线看演变趋势再导出一份数据表做联合分析。这套链路走通了不管你是做边坡、洞室还是隧道都能直接迁移使用。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。