epanet 2.0python调用接口
EPANETTOOLS的Python项目详细描述
epanet 2.0 python调用接口
Epanet 2.0python调用接口
从0.5.0.1版开始,这个库就有了epanet发射器引擎,支持基于压力的需求分析(http://assela.pathirana.net/EPANET-Emitter)。
因为版本是0.4.0.1,所以库与Python3.0兼容
这是什么?
一个python包,允许用户调用python脚本中的所有epanet programmers toolkit函数。
安装
Windows: | Use a Python ditribution that comes with a c copiler (use WinPython or PythonXY) ^{pr 1}$ |
---|---|
POSIX (e.g. Linux, OS-X): | |
Download source archive (zip file), extract and run (as root) ^{pr 2}$or just type ^{pr 3}$ |
用法:
>>> import os, pprint >>> pp=pprint.PrettyPrinter() # we'll use this later. >>> from epanettools.epanettools import EPANetSimulation, Node, Link, Network, Nodes, \ ... Links, Patterns, Pattern, Controls, Control # import all elements needed >>> from epanettools.examples import simple # this is just to get the path of standard examples >>> file = os.path.join(os.path.dirname(simple.__file__),'Net3.inp') # open an example >>> es=EPANetSimulation(file)
节点信息
>>> len(es.network.nodes) 97 >>> list(es.network.nodes)[:5] # just get indexes of nodes [1, 2, 3, 4, 5] >>> [es.network.nodes[x].id for x in list(es.network.nodes)[:5]] # Get ids of first five nodes. ['10', '15', '20', '35', '40'] >>> n=es.network.nodes >>> n[1].id '10' >>> n[94].id 'Lake' >>> n['10'].index # get the index of the node with id '10' 1
现在链接
>>> m=es.network.links >>> len(m) 119 >>> m[1].id '20' >>> m[3].id '50' >>> m[119].id '335'
有关连接的信息
>>> [m[1].start.id,m[1].end.id] # get the two ends of a link ['3', '20'] >>> [m[118].start.id,m[118].end.id] ['Lake', '10'] >>> sorted([i.id for i in n['169'].links]) # get the links connected to a node. ['183', '185', '187', '211']
链接和节点的类型
>>> pp.pprint(Node.node_types) # these are the type codes for nodes. {'JUNCTION': 0, 'RESERVOIR': 1, 'TANK': 2} >>> n[94].node_type 1 >>> n[1].node_type 0 >>> n['2'].node_type 2 >>> pp.pprint(Link.link_types) # these are the type codes for links {'CVPIPE': 0, 'FCV': 6, 'GPV': 8, 'PBV': 5, 'PIPE': 1, 'PRV': 3, 'PSV': 4, 'PUMP': 2, 'TCV': 7} >>> m['335'].link_type # Pump 2 >>> m['101'].link_type # PIPE 1 >>> m[1].link_type # 1 >>> [y.id for x,y in m.items() if y.link_type==Link.link_types['PUMP']] # get ids of pumps ['10', '335'] >>> [y.id for x,y in n.items() if y.node_type==Node.node_types['TANK']] # get ids of tanks ['1', '2', '3']
网络属性可用(甚至在我们运行模拟之前)
>>> d=Link.value_type['EN_DIAMETER'] >>> print("%.3f" % es.network.links[1].results[d][0]) 99.000 >>> p1=es.network.patterns[1] >>> l=list(p1.values()) >>> print("%2.1f "*len(l) % tuple(l )) # doctest: +NORMALIZE_WHITESPACE 1.3 1.9 1.5 1.4 0.8 0.9 0.9 1.1 1.0 1.1 1.1 1.2 1.2 1.1 1.0 0.8 0.8 0.7 0.6 0.6 0.9 1.0 1.2 1.7
得到一些仿真结果。
>>> es.run() >>> p=Node.value_type['EN_PRESSURE'] >>> print("%.3f" % es.network.nodes['103'].results[p][5] ) 59.301 >>> d=Node.value_type['EN_DEMAND'] >>> h=Node.value_type['EN_HEAD'] >>> print("%.3f" % es.network.nodes['103'].results[d][5]) 101.232 >>> print("%.3f" % es.network.nodes['103'].results[h][5]) 179.858 >>> d=Link.value_type['EN_DIAMETER'] >>> print("%.3f" % es.network.links[1].results[d][0]) 99.000 >>> es.runq() # run water quality simulation >>> q=Node.value_type['EN_QUALITY'] >>> print("%.3f" % es.network.nodes['117'].results[q][4]) 85.317 >>> e=Link.value_type['EN_ENERGY'] >>> print("%.5f" % es.network.links['111'].results[e][23]) 0.00685
一些高级结果查询
>>> print("%.3f" % min(es.network.nodes['103'].results[p])) # minimum recorded pressure of node '103' 44.169 >>> n=es.network.nodes >>> # All nodes recording negative pressure. >>> sorted([y.id for x,y in n.items() if min(y.results[p])<0]) ['10'] >>> # Nodes that deliver a flow of more than 4500 flow units >>> d=Node.value_type['EN_DEMAND'] >>> j=Node.node_types['JUNCTION'] >>> sorted([y.id for x,y in n.items() if ( max(y.results[d])>4500 and y.node_type==j )]) ['203']
更改网络
目前,上面新的(基于对象的)接口只支持对底层网络的读访问。要更改网络的值,建议使用传统接口调用。可以从新接口中访问遗留调用。更改网络的步骤:
- 使用网络文件创建epanetsimulation对象
- 使用ensetxxxx调用更改所需的值(仅更改epanetsimulation的属性将不起作用!)
- 使用ensaveinpfile将更改的数据保存到新文件中。
- 使用新保存的文件创建epanetsimulation对象。
Following is an example:
>>> d=Link.value_type['EN_DIAMETER'] >>> e=Node.value_type['EN_ELEVATION'] >>> es.ENgetlinkvalue(81,d)[1] #low level interface 16.0 >>> es.network.links[81].results[d] # new interface [16.0] >>> es.ENgetnodevalue(55,e)[1] # low level interface 15.5 >>> es.network.nodes[55].results[e] #new interface [15.5] >>> r=es.ENsetlinkvalue(81,d,99) # now let's change values - link >>> r # zero means no error! 0 >>> r=es.ENsetnodevalue(55,e,18.25) # change elevation of node >>> r #zero means no error 0 >>> # Note: the original network is not changed! Only the low level values changed. This is a limitation of current implementation >>> es.network.links[81].results[d], es.ENgetlinkvalue(81,d)[1], es.network.nodes[55].results[e], es.ENgetnodevalue(55,e)[1] ([16.0], 99.0, [15.5], 18.25) >>> # to permanantly change values, the changed network has to be written to a new file >>> import tempfile, os >>> f=os.path.join(tempfile.gettempdir(),"temp.inp") >>> es.ENsaveinpfile(f) # save the changed file 0 >>> e2=EPANetSimulation(f) >>> e2.network.links[81].results[d], e2.ENgetlinkvalue(81,d)[1], e2.network.nodes[55].results[e], e2.ENgetnodevalue(55,e)[1] ([99.0], 99.0, [18.25], 18.25) >>> # now in both high level and low level interfaces, we have the right value.
模式操作
>>> patId = "NewPattern"; >>> ret=es.ENaddpattern(patId) >>> print(ret) 0 >>> patFactors=[0.8, 1.1, 1.4, 1.1, 0.8, 0.7, 0.9, 0.0, 0.8, 0.8, 0.0, 0.0] >>> ret,patIndex=es.ENgetpatternindex(patId) >>> print(patIndex) 6 >>> es.ENsetpattern(patIndex, patFactors) 0 >>> es.ENgetpatternid(6)[1] 'NewPattern' >>> es.ENgetpatternlen(6) [0, 12] >>> [round(es.ENgetpatternvalue(6,i)[1],3) for i in range(1,12+1)] [0.8, 1.1, 1.4, 1.1, 0.8, 0.7, 0.9, 0.0, 0.8, 0.8, 0.0, 0.0] >>> es.ENsetpatternvalue(6,9,3.3) 0 >>> [round(es.ENgetpatternvalue(6,i)[1],3) for i in range(1,12+1)] [0.8, 1.1, 1.4, 1.1, 0.8, 0.7, 0.9, 0.0, 3.3, 0.8, 0.0, 0.0]
PDD类型分析
查看http://assela.pathirana.net/EPANET-Emitter以获取详细信息和执行相同分析的桌面(仅限Windows)应用程序。
>>> # lets create a pressure deficient network to demonstate this. >>> d=Link.value_type['EN_DIAMETER'] >>> l=es.network.links['247'] .index # get the index of '247' node. >>> r=es.ENsetlinkvalue(l,d,2.5) # now let's change values - link diameter to a small value. >>> r # zero means no error! 0 >>> f=os.path.join(tempfile.gettempdir(),"temp.inp") >>> es.ENsaveinpfile(f) # save the changed file 0 >>> #now lets analyse this with 'normal' epanet engine >>> e2=EPANetSimulation(f, pdd=False) #note pdd=False is default, no need to write this >>> e2.run() #simulate >>> p=Node.value_type['EN_PRESSURE'] >>> e2.network.nodes['225'].results[p][10] < -10.0 # we should get a large negative pressure value True >>> d=Node.value_type['EN_DEMAND'] >>> print("%4.2f" %e2.network.nodes['225'].results[d][10]) # the demand does not change/ 25.08 >>> e3=EPANetSimulation(f,pdd=True) # now we enable pdd >>> e3.run() >>> p225=e3.network.nodes['225'].results[p][10] # pressure should not be a rediculous value >>> (p225 > -3 and p225 < 500) True >>> d=Node.value_type['EN_DEMAND'] >>> d225=e3.network.nodes['225'].results[d][10] # the demand should be nearly zero >>> (d225 > -.1 and d225 < .1) True
传统接口
除非为了兼容,否则不要使用以下方法!从版本开始>;0.8模式设置 无法使用此接口。
>>> import os >>> from epanettools import epanet2 as et >>> from epanettools.examples import simple >>> file = os.path.join(os.path.dirname(simple.__file__),'Net3.inp') >>> ret=et.ENopen(file,"Net3.rpt","")
Example 1: | Retrieve simulation properties. |
---|
网络的基本性质
>>> ret,result=et.ENgetcount(et.EN_LINKCOUNT) >>> print(ret) 0 >>> print(result) 119 >>> ret,result=et.ENgetcount(et.EN_NODECOUNT) >>> print(ret) 0 >>> print(result) 97 >>> node='105' >>> ret,index=et.ENgetnodeindex(node) >>> print(ret) 0 >>> print ("Node " + node + " has index : " + str(index)) Node 105 has index : 12
获取节点列表
>>> ret,nnodes=et.ENgetcount(et.EN_NODECOUNT) >>> nodes=[] >>> pres=[] >>> time=[] >>> for index in range(1,nnodes): ... ret,t=et.ENgetnodeid(index) ... nodes.append(t) ... t=[] ... pres.append(t) >>> print (nodes) #doctest: +ELLIPSIS ... #doctest: +NORMALIZE_WHITESPACE ['10', '15', '20', '35', '40', '50', '60', ..., '275', 'River', 'Lake', '1', '2']
获取具有给定索引的链接两边的节点索引
>>> et.ENgetlinknodes(55) # note the first item in the list should be ignored. [0, 5, 46]
水力模拟
>>> et.ENopenH() 0 >>> et.ENinitH(0) 0 >>> while True : ... ret,t=et.ENrunH() ... time.append(t) ... # Retrieve hydraulic results for time t ... for i in range(0,len(nodes)): ... ret,p=et.ENgetnodevalue(i+1, et.EN_PRESSURE ) ... pres[i].append(p) ... ret,tstep=et.ENnextH() ... if (tstep<=0): ... break >>> ret=et.ENcloseH() >>> print([round(x,4) for x in pres[0]]) #doctest: +ELLIPSIS ... #doctest: +NORMALIZE_WHITESPACE [-0.6398, 40.1651, 40.891, 41.0433, ..., 0.569, -0.8864, 0.2997]
节点“10”处的压力
>>> ret,ind=et.ENgetnodeindex("10") >>> print (ind) 1 >>> print([round(x,4) for x in pres[ind+1]]) # remember epanet count starts at 1. ... #doctest: +ELLIPSIS ... #doctest: +NORMALIZE_WHITESPACE [12.5657, 12.9353, 13.4351, 14.0307, ..., 13.1174, 13.3985, 13.5478]
变更日志
1.0.0(2018-09-28)
- 现在可以使用python>;3.4。
- 使用适用于Windows的Visual C/C++编译器
.9.0(2016-11-13)
- 添加了关闭管道的可用需求分数。为了提高效率,这是用c库完成的。
0.8.0(2016-10-06)
- 完全消除了对numpy的依赖。
0.7.2(2016-09-28)
- 错误修复
0.7.1(2016-09-21)
- 小改动
0.7.0(2016-09-21)
- 从6.x版大幅升级
- 增加压力驱动需求
- 完全还原回购结构
- 使用ci进行更好的测试