Уравнения Векторизации / Параллелизации ГЕККО - PullRequest
2 голосов
/ 12 апреля 2020

Используя библиотеку GEKKO в Phython и следуя примеру, чтобы решить волновое уравнение из их исходной статьи , нужно создать целый ряд уравнений.

m.Equations([u[i].dt() == v[i]for i in range(npx)])
m.Equations([v[i].dt() == c**2*(u[mod(i+1,npx)]-2.0*u[mod(i,npx)]+u[mod(i-1,npx)])/dx**2 for i in arange(0,npx,1)])

(я уже уменьшил это до двух строк через mod, включая граничные условия и позволяя мне работать от 0 до 99, но это в основном все то же самое, что и в примере.)

Это все еще использует for -l oop, т.е. v[i]for i in range(npx)]. Можно ли избежать этого и, таким образом, сделать код более читабельным или ускорить симуляцию путем параллелизации / векторизации, как это можно сделать с numpy массивами?

Конечно, для этой проблемы вычисления занимают <18 с на моем ноутбуке , но большие проблемы могут быть очень медленными. </p>

В документации есть что-то о массивах, но я этого не понимаю и не знаю, ищу ли это вообще.

Я прикрепил MWE, используя приведенный выше код здесь .

1 Ответ

2 голосов
/ 13 апреля 2020

Если вы хотите улучшить скорость, попробуйте последовательное решение с m.options.IMODE=7. Для симуляции это обычно намного быстрее, чем IMODE=4 (одновременное решение).

from gekko import GEKKO
import numpy as np
import time
start = time.time()
pi = np.pi
#Initialise model
m = GEKKO(remote = False)
#Discretisations(time and space)
npt = 200; npx = 100
m.time = np.linspace(0, 1, npt)
xpos = np.linspace(0, 2*pi, npx)
dx = xpos[1]-xpos[0]
#Define Variables
c = m.Const(value = 10)
u = [m.Var(value = np.cos(xpos[i])) for i in range(npx)]
v = [m.Var(value = np.sin(2*xpos[i])) for i in range(npx)]
#Automatic discretisation in time and manual discretisation in space
m.Equations([u[i].dt() == v[i] for i in range(npx)])
m.Equations([v[i].dt() == c**2*(u[np.mod(i+1,npx)]-2.0*u[np.mod(i,npx)]\
                                 +u[np.mod(i-1,npx)])/dx**2 \
                          for i in np.arange(0,npx,1)])

#Set options
m.options.imode = 7
m.options.solver = 1
m.options.nodes = 3
m.solve(disp = False, GUI = False)
print('Solve Time: ' + str(m.options.SOLVETIME))
print('Total Time: ' + str(time.time()-start))

При IMODE=4 требуется больше времени для постановки проблемы, но меньше времени для ее решения.

Solve Time: 2.7666
Total Time: 25.547

При IMODE=7 требуется меньше времени для постановки проблемы, но больше времени для ее решения.

Solve Time: 8.2271
Total Time: 11.819

По мере того, как вы решаете более крупные проблемы, IMODE=7 займет гораздо меньше времени, чем IMODE=4 для симуляции. Для параллельных опций вы можете построить свою модель параллельно, но решение этой модели не имеет много опций для гораздо более быстрого решения, кроме IMODE=7. Вы можете создать параллельное приложение Gekko следующими способами:

  • Использовать параллельные линейные решатели в IPOPT с ma77, ma97 и другими. Как правило, это всего лишь увеличение скорости на 20-60% по сравнению с некоторыми тестами, которые я проводил для крупномасштабных задач. Эти параметры недоступны в версии IPOPT, распространяемой публично, поскольку решатели требуют лицензии. Линейный решатель MUMPS распространяется с Gekko, но не включает параллельную поддержку (хотя это может произойти позже). Проблема заключается в том, что решатель является лишь частью решения, и даже если решатель работает бесконечно быстро, автоматическое дифференцирование c, объективная оценка и оценка уравнений по-прежнему занимают около 50% времени ЦП.

  • Запускать самостоятельно. Это часто называют «массово параллельными», потому что процессы могут быть разделены на отдельные потоки, а затем код снова объединяется, когда все подпроцессы завершены. В этом учебном материале по многопоточности и Как сделать параллельные Python Gekko? показано, как выполнять параллельные вычисления. Ваша проблема не настроена на многопоточность, потому что уравнения решаются вместе.

...