ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GAMS在碳封存优化中的应用:从数学建模到工程实践

GAMS在碳封存优化中的应用:从数学建模到工程实践 1. 项目概述当优化建模遇上地质封存做能源优化这行的朋友最近应该都注意到了GAMS和TotalEnergies在碳封存领域合作的消息。乍一看这可能只是条普通的企业新闻但往深了想这其实是数学优化软件与能源巨头在减碳路径上的一次关键耦合。GAMS全称General Algebraic Modeling System在运筹学、能源系统规划、经济学建模领域摸爬滚打了几十年而TotalEnergies作为欧洲能源巨头旗下拥有大量油气田开发与CCS碳捕集与封存项目这两家凑到一起核心目标就一件事把CO2往地下注入的整个过程用数学优化模型算到最优。碳封存优化这个事很多外行听起来觉得简单——找个废油田把二氧化碳打进去不就完了但实际工程远不是这样。注入井的井位布置、注入速率、压力窗口、地层孔隙度、渗透率非均质性以及多井同时注入时的干扰问题每一样都是变量。更麻烦的是CO2注入不是一次性完成而是持续几十年的事这期间地层压力会积累、气体会运移、可能还会与地层水反应生成碳酸盐。要在这个动态过程中找到一个兼顾安全性、经济性、封存效率的最优方案靠人工经验和试错是行不通的。GAMS这类建模工具的价值就在于把这些物理约束、工程约束、经济约束全部转成方程组交给求解器去算让决策建立在可量化、可复现的模型结果上。这篇东西适合谁看我觉得至少有四类人一是做CCS项目前期规划的技术人员想了解优化模型怎么参与注入方案设计二是用GAMS做能源系统建模的研究生和工程师想看看这个工具在碳封存场景下的具体打开方式三是做油藏数值模拟的朋友想知道怎么把模拟器输出变成优化器输入四是单纯关注减碳技术路线的读者想搞明白“优化”两个字在碳封存项目里到底优化了些什么。2. 碳封存优化为什么要用GAMS而不是直接写Python先说一个经常被问的问题现在Python这么万能TensorFlow都能跑为什么还要用GAMS这种“老古董”答案其实不复杂主要是三个层面的考虑。第一约束建模的表达效率。碳封存优化本质上是一个大规模非线性约束优化问题涉及注入井数量、注入速率、井底压力、破裂压力、累计注入量、长期稳定性评估等几十上百个约束条件。Python里你要用SciPy或Pyomo写这些约束代码量大不说查错也是个麻烦事。GAMS的设计哲学就是“数学表达式直接写”约束条件和目标函数直接用接近数学教材的语法声明模型结构一眼看去清清楚楚。对于工程审查和团队协作来说这种透明性极其重要——甲方审你的模型看的是你约束条件列得对不对而不是一个个翻你的Python函数。第二求解器对接的便利性。GAMS自带一个求解器接口层CONOPT、IPOPT、BARON、CPLEX这些主流的商业或开源求解器都能直接调用。做碳封存优化的人都知道同一个模型用CONOPT解可能遇到数值困难换IPOPT就收敛了这很常见。GAMS的机制是你只需要写一行option语句求解器随便换不需要改动模型主体。Python里如果用Pyomo也能实现但要处理各个求解器的许可证、API接口差异、参数传递方式工作量明显上了一个量级。第三大规模情景分析的支撑能力。碳封存优化逃不开敏感性和不确定性分析——注入速率上下浮动10%成本曲线怎么变地层渗透率降低20%最优井位和注入方案怎么调整GAMS里做这类情景分析很方便通过参数映射和循环控制可以批量跑几十个甚至上百个case每次修改参数、调用求解器、输出结果都是自动化的。工程师要做的只是把跑完的结果收集起来做KPI对比这个对项目前期的方案比选来说价值非常大。当然我不是说Python没用。实际上我自己的经验是GAMS负责建模型和求解Python负责前后处理和数据可视化两者结合才是最高效的配置。GAMS用GAMS的建模语言写优化问题结果导出成gdx文件或者csv再用Python的pandas读进来画图、做对比分析。这个工作在实操中已经成为标准流程了。3. 碳封存优化模型的核心数学结构要理解GAMS在碳封存优化里具体干些什么得先把它要解决的数学问题看懂。3.1 目标函数什么才算“最优”碳封存项目的优化目标不是唯一的根据项目阶段不同目标函数也不同。最常见的目标是最小化单位封存成本$/t CO2计算公式拆开来看就是[ \min ; C_{total} \sum_{i1}^{N} \left( C_{cap,i} C_{inj,i} \right) / Q_{total} ]其中 ( C_{cap,i} ) 是第i口注入井的资本支出包含钻井、完井、井口设备、管线连接等费用( C_{inj,i} ) 是运营支出主要是注入泵耗电、CO2输送、监测费用等( Q_{total} ) 是封存总量。有些项目更看重封存效率这时目标函数会变成在给定井数条件下最大化累计注入量[ \max ; Q_{total} \sum_{t1}^{T} \sum_{i1}^{N} q_{i,t} \Delta t ]( q_{i,t} ) 是第i口井在第t个时间步的注入速率( \Delta t ) 是时间步长。这两种目标在实际项目中往往要平衡——一味追求低成本可能牺牲注入效率一味追求注入量又会让成本失控。所以GAMS模型里经常做成多目标优化用加权法把两个目标合成一个[ \min ; \omega_1 C_{total} - \omega_2 Q_{total} ]权重的取值就是工程决策的体现了这个在后面讲参数设置时再展开。3.2 约束条件安全与物理的双重红线约束条件是碳封存优化模型的核心也是GAMS建模最花功夫的地方。第一类是压力窗口约束。注入井的井底压力必须高于CO2达到超临界态所需的最小压力一般对应7.38 MPa临界压力同时绝对不能超过地层破裂压力否则地层就裂了CO2可能沿着裂缝快速逃逸。这个约束可以写成[ P_{min} \leq P_{i,t} \leq P_{frac} ]( P_{frac} ) 是破裂压力通常由测井资料和地应力实验获得。注意CO2的临界温度是31.1°C在地下大多数深度都能满足但压力必须够所以注入泵的功率设计很大程度上就是受这个约束牵制的。第二类是地层层位约束。井轨迹设计出来以后完井段的射孔位置必须落在目标储层内不能打到盖层里去。在建模里体现为对注入层位索引的取值范围约束属于整数决策变量。第三类是地面处理能力约束。CO2来源是捕获站来源的压力和流量有一定波动范围注入系统必须兼容这个范围。也就是 ( q_{i,t} ) 的上下限要和上游捕获装置的产气曲线对齐。第四类是封存量约束。累计注入量不能超过地层的理论封存容量这个容量由孔隙体积、CO2密度和不可动气饱和度决定[ \sum_{t1}^{T} \sum_{i1}^{N} q_{i,t} \Delta t \leq M_{total} A h \phi (1 - S_w) \rho_{CO2} ]这里 ( A ) 是储层面积( h ) 是储层厚度( \phi ) 是孔隙度( S_w ) 是含水饱和度( \rho_{CO2} ) 是CO2在地层条件下的密度。这个公式看起来简单实际做的时候孔隙度和含水饱和度在平面上是非均匀的所以要按网格分区输入模型规模一下子就上去了。3.3 为什么是全物理模拟优化模型两者怎么衔接说到这里有个绕不开的问题GAMS本身不解决CO2在地下的流动问题。如果用GAMS做注入速率优化地层压力响应怎么计算这里其实有两条技术路线。一条是把油藏模拟器比如CMG、Eclipse、TOUGH当成全物理的“黑盒响应函数”GAMS在优化迭代过程中反复调用模拟器跑出压力分布后评估约束是否满足、目标函数是否收敛。这种耦合方式实现起来复杂、计算量大但精度高。另一条是常见的做法——先离线用油藏模拟器生成代理模型surrogate model比如跑几十组不同注采方案拟合出井底压力随注入量变化的响应方程然后把代理模型嵌到GAMS的约束里。这样既保证了模型实用性又避开了直接调模拟器搞耦合的工程灾难实际项目里这是最稳妥的路径。TotalEnergies在公开技术交流里也强调过类似思路优化模型要做的是决策空间的快速搜索而不是替代高精度模拟器。GAMS的价值不是自己算出地下流体的命运而是在模拟器提供的响应关系基础上帮你把几十口井、几十个时间步、几万个参数组合的决策空间搜索到接近最优的点。4. 实操在GAMS里搭建一个碳封存注入优化模型光讲原理不干活那是学院派干的事。这一节我把模型搭建的完整流程拆开来每一步都给出可以照搬的代码和参数设置思路。4.1 数据准备阶段先别急着开GAMS数据准备好没有是第一关口。一个典型的碳封存优化案例需要四类数据。第一类是地质参数。储层深度、厚度、孔隙度分布、渗透率分布、含水饱和度、温度压力梯度、地层破裂压力。这些数据来自测井解释和地质建模通常已经整理成Petrel或Eclipse的网格属性文件。实操里要做的不是直接导入而是先按优化模型的网格分区要求做粗化——比如油藏模拟器用的是50x50的精细网格优化模型不需要这么细可以按工程分区聚合成6到9个区每个区用平均孔隙度、平均渗透率代表。第二类是流体物性参数。CO2在储层温压条件下的密度、粘度、溶解度以及溶解CO2后卤水密度变化等。这些可以查公开数据库比如NIST的流体物性查询或者用BWRS状态方程直接估算。注意CO2密度和深度压力、温度直接相关不同项目差别很大。第三类是工程参数。备选井位坐标、注入泵功率上限、井口最大允许压力、单井最大日注入量、建设期与运营期成本参数等。第四类是经济参数。钻井成本按深度折算、完井成本、每年运行维护费率、碳税或碳信用价格、折现率、项目寿命一般按20到30年规划。碳价这个参数对最优方案的影响极大后面做敏感性分析时会专门讲。4.2 GAMS模型代码结构解析下面给一个简化的碳封存井位与注入优化模型框架。实际项目的模型规模比这个大得多但结构上是一致的。$title CCS Injection Optimization Model $ontext Simplified CO2 storage optimization model Well placement and injection rate allocation $offtext Sets i potential injection wells / w1*w6 / t time periods / t1*t10 / p reservoir zones / zone1*zone3 / Parameters depth(i) well depth (m) / w1 1800, w2 1850, w3 2100, w4 2200, w5 1950, w6 2000 / capInt(i) injection capacity per well (kt/year) / w1 500, w2 500, w3 450, w4 450, w5 550, w6 550 / cpCost(i) capital cost per well (MUSD) / w1 12.5, w2 13.0, w3 16.5, w4 17.0, w5 14.5, w6 15.0 / opCost annual operating cost ratio / 0.04 / Pfrac fracture pressure (MPa) / 28.5 / Pmin minimum injection pressure (MPa) / 8.5 / discount discount rate / 0.08 / duration project life (years) / 20 / carbonPrice carbon credit price (USD/t) / 35 / Scalars qmax max total annual injection (kt/year) / 2500 / nmax max number of wells / 4 / Variables x(i) well selection binary q(i,t) injection rate (kt/year); Binary Variable x; Positive Variable q; Equations obj minimize total cost maxWells limit number of wells maxInj(i,t) capacity constraint per well minInj(i,t) minimum injection rate if selected totalInj minimum total storage requirement pressureCons pressure upper bound constraint; obj.. sum(i, cpCost(i)*x(i)) sum((i,t), opCost*cpCost(i)*x(i) carbonPrice*q(i,t)/1000) E z; maxWells.. sum(i, x(i)) L nmax; maxInj(i,t).. q(i,t) L capInt(i)*x(i); minInj(i,t).. q(i,t) G 100*x(i); totalInj.. sum((i,t), q(i,t)) G 20000; pressureCons.. sum(i, q(i,t)) L 2800; Model ccsOpt /all/; option minlp dicopt; Solve ccsOpt using minlp minimizing z;几处关键点值得展开说说**Binary变量x(i)**是井位选择的开关变量。1表示建井0表示不建。为什么要用整数变量因为工程上不存在“建半口井”的概念井要么建要么不建这是一个典型的整数决策问题。加上x(i)后模型从LP/NLP变成了MIP/MINLP求解难度明显提升但对于实际项目来说这个整数约束必须保留——工程师不可能根据0.7口井的优化结果去写可行性报告。minInj(i,t)约束的含义是如果选了这口井它的年注入量至少要有100 kt。为什么不用0作为下限这是为了避免数学上出现“选了井但注量为0”的无意义解。之前我就见过团队跑出来的方案显示某口井被选中但注入量为零这就是规模病态的表现这种约束就是避免这类问题的手段。类似的技巧在整数规划里叫big-M法约束作用是建立连续变量与整数变量的逻辑关联。pressureCons约束恒量了每期的总注入量上限。模型里这个值是拍出来的但实际项目中它的来源就是前面提到的代理模型。具体做法是先用油藏模拟器跑几个不同注入总量下的情景得到对应的井底压力然后拟合一条“总注入量-最大井底压力”的响应曲线把压力安全窗口换算成注入总量的可行区间写进优化模型。这样既能保证优化结果工程上可行又不需要在GAMS里直接解流体力学方程。4.3 求解器选型与参数调优经验这个模型是MINLP类型因为有二进制变量x同时约束里有一些非线性项求解器选择就是决定成败的事了。我习惯的配置是先用DICOPT跑一遍外近似法快速拿到一个可行的次优解了解解空间的量级然后用SBB做分支定界搜索尝试进一步逼近全局最优如果模型规模大或者非线性强会考虑用外部求解器如BARON做全局优化但这个很考验模型规模通常只有中低维问题跑得动。求解器参数方面最常用的调整是option reslim设定求解时间上限。碳封存项目的决策频率不高前期规划阶段一个case跑半小时甚至一晚上都无所谓所以可以放宽到3600秒甚至更高。但如果要做几百组敏感性分析建议单个case控制在300秒以内否则批次任务总时长会失控。option optcr设定相对最优间隙。默认值是0.1表示停止条件是最优解和最优界的差距小于10%。做方案比选阶段可以放宽到0.15甚至0.2跑得快很多到最终方案确认阶段回到0.01甚至0确保拿到的解接近真正的最优。option mip_cplex相关的参数如果用的是CPLEX求解MIP部分建议关闭前置启发式或者至少保持默认。这个听起来反直觉但有实际教训——某些情况下启发式拿到的初始解会误导分支方向导致后期搜索效率变低。另外有个实战小技巧先跑一个去掉整数约束的连续松弛版本。这个版本直接LP/NLP求解速度快得多得到的目标函数值可以作为MIP问题的下界参考。如果后面整数解的目标值比松弛解高出太多比如超过20%就说明整数约束对方案的影响很大可能要考虑增加备选井位来降低整数约束带来的自由度损失。4.4 典型优化结果解读我们以一个简化的案例来说明怎么读优化结果。假设给了6口备选井编号w1到w6经济参数和深度如上表项目目标是20年累计封存2万吨CO2但受碳价约束既不能超标太多也不能不够实际上CCS项目的补贴或碳信用收入通常在目标函数里以负成本形式体现。跑完DICOPT后的典型输出大约是这样的选中的井是w2、w4、w5w1被排除的主要原因是它与w2的井位距离过近同时投产会造成压力干扰而约束maxWells限制了最多只能选4口。各井注入量分配不是平均的w5因为深度适中、渗透率条件好承担了更大的注入份额w4深度最浅但资本成本低年注入量设在中位水平。总成本分解出来资本支出占比约35%运行维护占25%二氧化碳捕集压缩前段分配来的成本占40%。如果碳价从35美元涨到60美元优化模型会倾向于选择更多井、更大注入量因为封存收入增加抵消了额外建设成本。这个结果说明了一件很重要的事优化不是简单地“多注多得”而是在边际成本和边际收益的交点上做取舍。碳价上行时封存变成了肥肉项目会扩张碳价低迷时项目会收缩到刚好满足合约下限的规模。这就是为什么行业里常说碳封存项目方案好不好一半取决于地质条件一半取决于碳价预期。5. 常见问题与排查技巧实录在实际碰这个题目的过程中坑真的不少。这一节把我自己踩过的、以及同行交流中反复出现的几类问题整理成速查形式希望对大家有实际帮助。5.1 模型不收敛怎么办症状求解器报“infeasible不可行”或者迭代次数打满都达不到收敛条件。排查思路首先检查约束是否自相矛盾。最常见的情况是maxWells限得太紧但同时totalInj的封存量目标又定得太高——几个备选井的容量加起来都不够目标值那就必然无解。把totalInj目标逐步降低看模型到哪个值开始有可行解能反推出现有井位方案的实际最大封存量。其次要检查数值尺度。GAMS对数值尺度比较敏感——如果目标是6000但约束数值在0.01量级求解器的容差设置就会造成困扰。碳封存模型里深度是1800米成本是12.5百万美元注入量是500千吨/年这些数值本身在同一量级一般不严重但要小心碳价和成本的乘积扩大到百万级后跟压力值混在一起。我习惯用集合p来统一做成本量纲归一化比如所有金额除以1000统一成“百万美元”所有注入量除以100统一成“十万吨”能有效减少数值病态。5.2 求解时间过长症状模型在MIP分支上卡住intelligence不明显。对策先看问题规模。备选井数量从10口增到30口二进制变量的组合空间是指数增长的30口井意味着2的30次方种组合暴力搜索必死。这时候必须加启发式约束剪枝比如根据空间距离预设“如果选了井A则不选井B”的互斥关系可以大幅缩小分支树。另一个技巧是把时间维度粗化。如果是10年规划可以先按年为单位跑一个粗模型拿到井位选择的整数解再把这个解固定下来把时间维度细化到季度或月做连续变量的精细优化。这种“两阶段求解法”在工程实践里屡试不爽。5.3 优化结果不符合工程直觉症状模型给出的最优解里某个注入参数看起来“不合理”比如让某口浅层井承担了大量注入而工区东侧地质条件明显更好的井却没被选中。排查方向别急着怀疑求解器先查参数输入。最容易出错的几个点渗透率数据在从Petrel导出时有没有做单位换算毫达西换算成平方米地层压力参数用的是初始静压还是考虑了注入后的增压如果用初始值代替生产后的动态压力压力约束全是错的。经济参数里有没有重复计算成本项比如钻井成本被同时算进资本支出和固定运营支出里我遇到过最离谱的一次是地质模型里两口井的坐标单位弄反了一个用米一个用千米导致空间距离计算差了1000倍模型自然选择了“距离很远”但实际上位置重叠的两口井。所以拿到结果第一件事是把选中的井位投到地图上用空间分布做一次人工验证这个习惯能帮你省掉大量排查时间。5.4 敏感性分析结果解读的陷阱做碳价、渗透率、注入能力的单因素敏感性分析时经常看到“关键参数从A变到B方案从方案一跳到方案四中间没有过渡方案”的现象。这不是模型出bug了而是整数决策变量的特性——井位选择是离散的参数微调可能不会改变井位方案但到达临界点后方案会整体跳变。这个现象说明项目决策边界对某个参数非常敏感反而值得重点关注如果碳价波动10%就会导致整个最优方案推翻说明项目抗风险能力差需要留安全余量。6. 写在后面优化模型在碳封存项目中的位置我在实际操作中的一个感受是GAMS在碳封存项目里只是引擎整个工作流的价值取决于前端数据质量和后端工程解读。数据没整明白再牛的求解器也算不出能落地的方案结果出来了没人能读懂约束卡在哪里、边界在哪套参数下容易被突破优化就算白做了。TotalEnergies这类大型能源公司与GAMS合作加速碳封存优化背后传递的信号很明确在成本压力越来越大的背景下碳封存项目不能只靠传统油藏工程经验来选址布井量化优化会成为标配工具。对于正在往这个方向靠的年轻工程师我的建议是别急着学某个具体软件先把目标函数、约束条件、整数变量、非线性这些运筹学的基本功打扎实再去碰GAMS或者Python你会发现工具上手比你想象中快得多。地质上多了解点沉积相、断裂系统、储层非均质性对注入方案的影响跟优化建模结合起来的产出远比单一技能栈值钱。最后分享一个实操小经验给领导汇报优化模型结果时不要一上来就抛公式和代码。先把不优化和经验方案的对比成本曲线摆出来再解释约束条件是怎么保证安全和工程可实施的最后放一张最优井位部署图。这个顺序我试过很多次通常能在十分钟内让非技术决策者听懂优化模型的业务价值。
返回列表