python - 使用 Dask 并行运行 PyBaMM 电池模拟
问题描述
我正在使用PyBaMM包对电池进行建模,并且我想使用 Dask 并行运行多个模拟。下面的示例是我尝试使用dask.delayed
. Dask 方法比非 Dask 方法慢。在这个例子中是否有更好的方法来使用 Dask?我应该设置一个 DaskClient()
来并行运行模拟吗?我在我的本地机器上运行这个例子,但我最终想在集群上运行一个类似的例子。
下面给出了在 8 核 MacBook Pro 上运行示例所经过的时间。注释掉相应的部分main()
以在有或没有 Dask 的情况下运行。
例子 | 经过时间 |
---|---|
没有黄昏 | 8.02 秒 |
达斯克 | 8.74 秒 |
import matplotlib.pyplot as plt
import pybamm
import time
import dask
def generate_plots(discharge, t, capacity, current, voltage):
def styleplot(ax):
ax.legend(loc='best')
ax.grid(color='0.9')
ax.set_frame_on(False)
ax.tick_params(color='0.9')
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(t[i], current[i], label=f'{discharge[i]} A')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Current [A]')
styleplot(ax)
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(t[i], voltage[i], label=f'{discharge[i]} A')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Terminal voltage [V]')
styleplot(ax)
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(capacity[i], voltage[i], label=f'{discharge[i]} A')
ax.set_xlabel('Discharge capacity [Ah]')
ax.set_ylabel('Terminal voltage [V]')
styleplot(ax)
plt.show()
def run_simulation(dis, t_eval):
model = pybamm.lithium_ion.SPMe()
param = model.default_parameter_values
param['Current function [A]'] = '[input]'
sim = pybamm.Simulation(model, parameter_values=param)
sim.solve(t_eval, inputs={'Current function [A]': dis})
return sim.solution
def main():
tic = time.perf_counter()
discharge = [4, 3.5, 3, 2.5, 2, 1.8, 1.5, 1] # discharge currents [A]
t_eval = [0, 4000] # evaluation time [s]
# No Dask
# ------------------------------------------------------------------------
label = 'no Dask'
sols = []
for dis in discharge:
sol = run_simulation(dis, t_eval)
sols.append(sol)
# Dask
# ------------------------------------------------------------------------
# label = 'Dask'
# lazy_sols = []
# for dis in discharge:
# sol = dask.delayed(run_simulation)(dis, t_eval)
# lazy_sols.append(sol)
# sols = dask.compute(*lazy_sols)
# ------------------------------------------------------------------------
t = []
capacity = []
current = []
voltage = []
for sol in sols:
t.append(sol['Time [s]'].entries)
capacity.append(sol['Discharge capacity [A.h]'].entries)
current.append(sol['Current [A]'].entries)
voltage.append(sol["Terminal voltage [V]"].entries)
toc = time.perf_counter()
print(f'Elapsed time ({label}) = {toc - tic:.2f} s')
generate_plots(discharge, t, capacity, current, voltage)
if __name__ == '__main__':
main()
解决方案
根据@rrpelgrim 的建议,我实现了一个Client()
对象,该对象似乎通过使用分布式调度程序改进了我的示例代码的并行执行。修改后的示例如下所示。您可以通过注释掉main()
. 表中给出了使用 8 核 CPU 的经过时间。
例子 | 经过时间 |
---|---|
没有黄昏 | 8.57 秒 |
达斯克 | 3.83 秒 |
import matplotlib.pyplot as plt
import pybamm
import time
from dask.distributed import Client
def create_plots(discharge, t, capacity, current, voltage):
def styleplot(ax, xlabel, ylabel):
ax.legend(loc='best')
ax.grid(color='0.9')
ax.set_frame_on(False)
ax.tick_params(color='0.9')
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(t[i], current[i], label=f'{discharge[i]} A')
styleplot(ax, xlabel='Time [s]', ylabel='Current [A]')
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(t[i], voltage[i], label=f'{discharge[i]} A')
styleplot(ax, xlabel='Time [s]', ylabel='Terminal voltage [V]')
_, ax = plt.subplots(tight_layout=True)
for i in range(len(discharge)):
ax.plot(capacity[i], voltage[i], label=f'{discharge[i]} A')
styleplot(ax, xlabel='Discharge capacity [Ah]', ylabel='Terminal voltage [V]')
plt.show()
def run_simulation(dis, t_eval):
model = pybamm.lithium_ion.SPMe()
param = model.default_parameter_values
param['Current function [A]'] = '[input]'
sim = pybamm.Simulation(model, parameter_values=param)
sim.solve(t_eval, inputs={'Current function [A]': dis})
return sim.solution
def main(client):
tic = time.perf_counter()
discharge = [4, 3.5, 3, 2.5, 2, 1.8, 1.5, 1] # discharge currents [A]
t_eval = [0, 4000] # evaluation time [s]
# No Dask
# ------------------------------------------------------------------------
# label = 'no Dask'
# sols = []
# for dis in discharge:
# sol = run_simulation(dis, t_eval)
# sols.append(sol)
# Dask
# ------------------------------------------------------------------------
label = 'Dask'
lazy_sols = client.map(run_simulation, discharge, t_eval=t_eval)
sols = client.gather(lazy_sols)
# ------------------------------------------------------------------------
t = []
capacity = []
current = []
voltage = []
for sol in sols:
t.append(sol['Time [s]'].entries)
capacity.append(sol['Discharge capacity [A.h]'].entries)
current.append(sol['Current [A]'].entries)
voltage.append(sol["Terminal voltage [V]"].entries)
toc = time.perf_counter()
print(f'Elapsed time ({label}) = {toc - tic:.2f} s')
create_plots(discharge, t, capacity, current, voltage)
if __name__ == '__main__':
client = Client()
print(client)
main(client)
推荐阅读
- ruby-on-rails - <%= f.submit %> 不会将参数发送到控制器。(Ruby On Rails)
- mongodb - 如何在mongo中查询日期范围,其中字段本身是日期
- bash - SSH 到服务器,运行 if 和 for 循环,并在循环内写入本地文件
- reactjs - 使用 .map 渲染组件会重置组件内的 setTimeout
- extjs - 如何使用 ExtJS 面板渲染器配置添加点击事件?
- java - C#相当于Java的Instant类和RsaSHA256Signer类
- scikit-learn - AttributeError:“OrdinalEncoder”对象没有属性“category_mapping”
- c - C中的多线程套接字
- python - 为 NLP 预处理单词时如何保留特定单词?(str.replace & regex)
- spring - Spring Boot 字段未更新