简体   繁体   English

Python:GEKKO 求解代数微分方程的快速替代方案

[英]Python: Fast alternatives to GEKKO for solving Algebraic differential equations

To simulate power flows in grids, I use GEKKO to solve my algebraic differential equation system.为了模拟电网中的潮流,我使用 GEKKO 来求解我的代数微分方程系统。

For smaller simulations, it works pretty well, but running it several times in a row, for example while training a reinforcement learning agent, takes quite a while.对于较小的模拟,它工作得很好,但是连续运行几次,例如在训练强化学习代理时,需要相当长的时间。

Could anyone suggest a solver with a smaller overhead, which speeds up the simulation?谁能建议一个开销较小的求解器来加快模拟速度?

A small example of how the system looks like is in our GitHub repo linked here:系统外观的一个小例子在我们的 GitHub 回购链接中:

https://github.com/upb-lea/openmodelica-microgrid-gym/blob/feature_50_SinglePhaseModel/experiments/swing_equation/gekko_freq_volt.py https://github.com/upb-lea/openmodelica-microgrid-gym/blob/feature_50_SinglePhaseModel/experiments/swing_equation/gekko_freq_volt.py

There are other alternatives such as assimulo and CasADi.还有其他替代品,例如 assimulo 和 CasADi。 But I have yet to find something that comes close to GEKKO.但我还没有找到接近 GEKKO 的东西。 My suggestion would be, to define the model with parameters instead of variables.我的建议是,用参数而不是变量来定义 model。 This will definitely decrease the time needed to keep reinitializing your model.这肯定会减少重新初始化 model 所需的时间。

In some benchmark tests, Gekko is about 5x faster than pyomo.在一些基准测试中,Gekko 比 pyomo 快大约 5 倍。 We've also worked with groups who are currently using CasADi to speed up optimization with Gekko.我们还与目前正在使用 CasADi 的团队合作,以加快对 Gekko 的优化。 If it is an algebraic modeling language then Gekko is one of the fastest options.如果它是一种代数建模语言,那么 Gekko 是最快的选择之一。 Here are some suggestions with Gekko.以下是对 Gekko 的一些建议。 Switch to IMODE=4 with m.options.TIME_SHIFT=0 to solve from the prior solution as a warm-start.使用m.options.TIME_SHIFT=0切换到 IMODE IMODE=4以从先前的解决方案作为热启动解决。 This can dramatically improve the solution speed.这可以显着提高求解速度。 Another option is to parallelize the function calls for the reinforcement learning agent with multi-threading .另一种选择是并行化 function 调用,以使用multi-threading进行强化学习代理。

import numpy as np
import threading
import time, random
from gekko import GEKKO

class ThreadClass(threading.Thread):
    def __init__(self, id, server, ai, bi):
        s = self
        s.id = id
        s.server = server
        s.m = GEKKO(remote=False)
        s.a = ai
        s.b = bi
        s.objective = float('NaN')

        # initialize variables
        s.m.x1 = s.m.Var(1,lb=1,ub=5)
        s.m.x2 = s.m.Var(5,lb=1,ub=5)
        s.m.x3 = s.m.Var(5,lb=1,ub=5)
        s.m.x4 = s.m.Var(1,lb=1,ub=5)

        # Equations
        s.m.Equation(s.m.x1*s.m.x2*s.m.x3*s.m.x4>=s.a)
        s.m.Equation(s.m.x1**2+s.m.x2**2+s.m.x3**2+s.m.x4**2==s.b)

        # Objective
        s.m.Minimize(s.m.x1*s.m.x4*(s.m.x1+s.m.x2+s.m.x3)+s.m.x3)

        # Set global options
        s.m.options.IMODE = 3 # steady state optimization
        s.m.options.SOLVER = 1 # APOPT solver

        threading.Thread.__init__(s)

    def run(self):

        # Don't overload server by executing all scripts at once
        sleep_time = random.random()
        time.sleep(sleep_time)

        print('Running application ' + str(self.id) + '\n')

        # Solve
        self.m.solve(disp=False)

        # Retrieve objective if successful
        if (self.m.options.APPSTATUS==1):
            self.objective = self.m.options.objfcnval
        else:
            self.objective = float('NaN')
        self.m.cleanup()

# Select server
server = 'https://byu.apmonitor.com'

# Optimize at mesh points
x = np.arange(20.0, 30.0, 2.0)
y = np.arange(30.0, 50.0, 2.0)
a, b = np.meshgrid(x, y)

# Array of threads
threads = []

# Calculate objective at all meshgrid points

# Load applications
id = 0
for i in range(a.shape[0]):
    for j in range(b.shape[1]):
        # Create new thread
        threads.append(ThreadClass(id, server, a[i,j], b[i,j]))
        # Increment ID
        id += 1

# Run applications simultaneously as multiple threads
# Max number of threads to run at once
max_threads = 8
for t in threads:
    while (threading.activeCount()>max_threads):
        # check for additional threads every 0.01 sec
        time.sleep(0.01)
    # start the thread
    t.start()

# Check for completion
mt = 3.0 # max time
it = 0.0 # incrementing time
st = 1.0 # sleep time
while (threading.activeCount()>=1):
    time.sleep(st)
    it = it + st
    print('Active Threads: ' + str(threading.activeCount()))
    # Terminate after max time
    if (it>=mt):
        break

# Wait for all threads to complete
#for t in threads:
#    t.join()
#print('Threads complete')

# Initialize array for objective
obj = np.empty_like(a)

# Retrieve objective results
id = 0
for i in range(a.shape[0]):
    for j in range(b.shape[1]):
        obj[i,j] = threads[id].objective
        id += 1

# plot 3D figure of results
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(a, b, obj, \
                       rstride=1, cstride=1, cmap=cm.coolwarm, \
                       vmin = 12, vmax = 22, linewidth=0, antialiased=False)
ax.set_xlabel('a')
ax.set_ylabel('b')
ax.set_zlabel('obj')
ax.set_title('Multi-Threaded GEKKO')
plt.show()

If there is a DAE integrator such as IDA in Sundials , then this may also be an alternative for simulation.如果在 Sundials 中有一个 DAE 集成器,例如 IDA ,那么这也可能是模拟的替代方案。 Gekko solves higher DAE index problems while most of the integrators such as DASSL, DASPK, and IDA are limited to index-1 DAEs and optionally index-2 Hessenberg form. Gekko 解决了更高的 DAE 索引问题,而大多数集成器(如 DASSL、DASPK 和 IDA)仅限于索引 1 DAE 和可选的索引 2 Hessenberg 形式。 This often creates a significant burden to rearrange the equations into that form, if possible.如果可能的话,这通常会造成将方程重新排列成那种形式的巨大负担。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM