前言
本文是通过分析WNTR包自带的stochastic_simulation例子来分析如何在随机管段上面进行添加泄漏点模拟管网漏损,希望对以后的管网模拟算例有所帮助。
一、stochastic_simulation例子代码分析
首先导入各类包:
#coding = utf-8
import numpy as np
import wntr
import matplotlib.pyplot as plt
import pickle
# Create a water network model
inp_file = '../networks/Net3.inp'
wn = wntr.network.WaterNetworkModel(inp_file)
调整参数:
# Modify the water network model
wn.options.time.duration = 48*3600#管网模拟持续48小时,也就是两天
wn.options.time.hydraulic_timestep = 1800#管网的水力计算时间间隔为1800s,30min
wn.options.time.report_timestep = 1800#报告计算结果的时间间隔
wn.options.hydraulic.required_pressure = 15#压力驱动模式下,提供需水量的正常水压
wn.options.hydraulic.minimum_pressure = 0#最低水压 出现负压时停止供水
基于各自的直径,对每一个管段定义一个泄漏概率,所有管段的泄漏概率加起来为1,选择特定特征的管段可以使用wn.query_link_attribute()来获得所有满足特征的管段
# Define failure probability for each pipe, based on pipe diameter. Failure
# probability must sum to 1. Net3 has a few pipes with diameter = 99 inches,
# to exclude these from the set of feasible leak locations, use
# query_link_attribute
#选择直径小于等于0.91444m的所有管段
pipe_diameters = wn.query_link_attribute('diameter', np.less_equal,
0.9144, # 36 inches = 0.9144 m
link_type=wntr.network.Pipe)
#再基于管道直径算每个管段的发生泄露的概率
failure_probability = pipe_diameters/pipe_diameters.sum()
我们看看pipe_diameters里面到底有什么东西
>>>print(pipe_diameters)
>>>print(type(pipe_diameters))
>>>print(failure_probability)
60 0.6096
101 0.4572
103 0.4064
105 0.3048
107 0.3048
...
323 0.3048
325 0.2032
329 0.7620
330 0.7620
333 0.7620
Length: 114, dtype: float64
<class 'pandas.core.series.Series'>
60 0.014440
101 0.010830
103 0.009627
105 0.007220
107 0.007220
...
323 0.007220
325 0.004813
329 0.018051
330 0.018051
333 0.018051
Length: 114, dtype: float64
所以wn.query_link_attribute()获得满足传入参数的所有link,可以获得包括管段,阀门,水泵的各种信息。结果是一个pd.Series。索引是link名称,值是相应的link值。
接下来是模型对象的序列化保存,以便下次以相同的初始条件重新开始模拟:
# Pickle the network model and reload it for each realization
f=open('wn.pickle','wb')
pickle.dump(wn,f)
f.close()
# Run 5 realizations
#创建一个新字典用于保存模拟结果
results = {} # Initialize dictionary to store results
np.random.seed(67823) # Set random seed 设置种子 每次模拟都是相同的
for i in range(5):
# Select the number of leaks, random value between 1 and 5
#选择发生漏损的数量,该变量N没有引用,猜测应该传入下面的pipes_to_fail
N = np.random.randint(1,5+1)
# Select N unique pipes based on failure probability
#按照管网泄露的概率随机选择5根管道,在index(管道id)里面挑五个
pipes_to_fail = np.random.choice(failure_probability.index, 5,
replace=False,
p=failure_probability.values)
# Select time of failure, uniform dist, between 1 and 10 hours
#取泄露开始的时间,按照平均分布uniform distribution,取小数点后两位
time_of_failure = np.round(np.random.uniform(1,10,1)[0], 2)
# Select duration of failure, uniform dist, between 12 and 24 hours
#取持续时间,也是按照平均分布取小数点后两位
duration_of_failure = np.round(np.random.uniform(12,24,1)[0], 2)
# Add leaks to the model
#在管网模型里面添加leaks
for pipe_to_fail in pipes_to_fail:
pipe = wn.get_link(pipe_to_fail)
#设置泄露的参数,泄露点面积leak_area
leak_diameter = pipe.diameter*0.3
leak_area=3.14159*(leak_diameter/2)**2
#把该管段打断 为pipe_to_fail pipe_to_fail_B 和节点
wn = wntr.morph.split_pipe(wn, pipe_to_fail, pipe_to_fail + '_B', pipe_to_fail+'leak_node')
leak_node = wn.get_node(pipe_to_fail+'leak_node')
leak_node.add_leak(wn, area=leak_area,
start_time=time_of_failure*3600,
end_time=(time_of_failure + duration_of_failure)*3600)
# Simulate hydraulics and store results
wn.options.hydraulic.demand_model = 'PDD'
sim = wntr.sim.WNTRSimulator(wn)
print('Pipe Breaks: ' + str(pipes_to_fail) + ', Start Time: ' + \
str(time_of_failure) + ', End Time: ' + \
str(time_of_failure+duration_of_failure))
#把模拟的结果result对象传入到我们一开始建立的results字典里面,键是i,值是result对象
results[i] = sim.run_sim()
# Reload the water network model
#每次模拟结束以后,reloadpickle文件,保留初始条件重新开始模拟
f=open('wn.pickle','rb')
wn = pickle.load(f)
f.close()
输出结果
Pipe Breaks: ['137' '311' '60' '175' '179'], Start Time: 5.6, End Time: 28.159999999999997
Pipe Breaks: ['121' '161' '239' '193' '191'], Start Time: 7.01, End Time: 25.79
Pipe Breaks: ['191' '131' '249' '211' '193'], Start Time: 9.85, End Time: 23.310000000000002
Pipe Breaks: ['281' '179' '309' '240' '277'], Start Time: 5.72, End Time: 21.63
Pipe Breaks: ['287' '238' '245' '131' '319'], Start Time: 8.67, End Time: 23.11
看看results这个字典
>>>print(results)
{0: <wntr.sim.results.SimulationResults object at 0x0000022AF43391F0>, \n
1: <wntr.sim.results.SimulationResults object at 0x0000022AF422BFA0>, \n
2: <wntr.sim.results.SimulationResults object at 0x0000022AF6B6F280>, \n
3: <wntr.sim.results.SimulationResults object at 0x0000022AF4490160>, \n
4: <wntr.sim.results.SimulationResults object at 0x0000022AF46DEA60>}
该例子后面的代码是一个弹性模块的方法,关于出现漏水时的高位水箱的供水曲线,与我们研究的管网漏损关系不大,没有仔细研究,有兴趣的朋友仔细查看例子。
最后我们再检查里面发现变量N根本没有使用,按道理来说应该发生的泄漏次数是在1到5随机的,所以:
for i in range(5):
# Select the number of leaks, random value between 1 and 5
#选择发生漏损的数量,该变量N没有引用,猜测应该传入下面的pipes_to_fail
N = np.random.randint(1,5+1)
# Select N unique pipes based on failure probability
#按照管网泄露的概率随机选择N根管道
pipes_to_fail = np.random.choice(failure_probability.index, N,
replace=False,
p=failure_probability.values)
现在将全部代码附上:
#coding = utf-8
import numpy as np
import wntr
import matplotlib.pyplot as plt
import pickle
import random
# Create a water network model
inp_file = '../networks/Net3.inp'
wn = wntr.network.WaterNetworkModel(inp_file)
# Modify the water network model
wn.options.time.duration = 48*3600
wn.options.time.hydraulic_timestep = 1800
wn.options.time.report_timestep = 1800
wn.options.hydraulic.required_pressure = 15
wn.options.hydraulic.minimum_pressure = 0
# Define failure probability for each pipe, based on pipe diameter. Failure
# probability must sum to 1. Net3 has a few pipes with diameter = 99 inches,
# to exclude these from the set of feasible leak locations, use
# query_link_attribute
pipe_diameters = wn.query_link_attribute('diameter', np.less_equal,
0.9144, # 36 inches = 0.9144 m
link_type=wntr.network.Pipe)
failure_probability = pipe_diameters/pipe_diameters.sum()
# Pickle the network model and reload it for each realization
f=open('wn.pickle','wb')
pickle.dump(wn,f)
f.close()
# Run 5 realizations
results = {} # Initialize dictionary to store results
np.random.seed(67823) # Set random seed
for i in range(5):
# Select the number of leaks, random value between 1 and 5
N = np.random.randint(1, 5 + 1)
# Select N unique pipes based on failure probability
pipes_to_fail = np.random.choice(failure_probability.index, N,
replace=False,
p=failure_probability.values)
# Select time of failure, uniform dist, between 1 and 10 hours
time_of_failure = np.round(np.random.uniform(1, 10, 1)[0], 2)
# Select duration of failure, uniform dist, between 12 and 24 hours
duration_of_failure = np.round(np.random.uniform(12, 24, 1)[0], 2)
# Add leaks to the model
for pipe_to_fail in pipes_to_fail:
pipe = wn.get_link(pipe_to_fail)
leak_diameter = pipe.diameter * 0.3
leak_area = 3.14159 * (leak_diameter / 2) ** 2
wn = wntr.morph.split_pipe(wn, pipe_to_fail, pipe_to_fail + '_B', pipe_to_fail + 'leak_node')
leak_node = wn.get_node(pipe_to_fail + 'leak_node')
leak_node.add_leak(wn, area=leak_area,
start_time=time_of_failure * 3600,
end_time=(time_of_failure + duration_of_failure) * 3600)
# Simulate hydraulics and store results
wn.options.hydraulic.demand_model = 'PDD'
sim = wntr.sim.WNTRSimulator(wn)
print('Pipe Breaks: ' + str(pipes_to_fail) + ', Start Time: ' + \
str(time_of_failure) + ', End Time: ' + \
str(time_of_failure + duration_of_failure))
results[i] = sim.run_sim()
# Reload the water network model
f = open('wn.pickle', 'rb')
wn = pickle.load(f)
f.close()
结果如下
Pipe Breaks: ['137' '311'], Start Time: 1.05, End Time: 16.95
Pipe Breaks: ['202'], Start Time: 8.92, End Time: 30.72
Pipe Breaks: ['233' '175' '247' '231' '60'], Start Time: 8.08, End Time: 28.549999999999997
Pipe Breaks: ['225' '116' '281'], Start Time: 4.31, End Time: 26.759999999999998
Pipe Breaks: ['305' '275' '179' '175' '287'], Start Time: 6.93, End Time: 27.28