Как инициализировать модели PYFMI параллельно?
Я использую pyfmi для моделирования с помощью EnergyPlus. Я понял, что инициализация отдельных моделей EnergyPlus занимает довольно много времени. Поэтому я надеюсь найти способ инициализировать модели параллельно. Я безуспешно пробовал использовать многопроцессорную библиотеку Python. Если это важно, я использую Ubuntu 16.10 и использую Python 3.6. Вот что я хочу сделать последовательно:
fmus = {}
for id in id_list:
chdir(fmu_path+str(id))
fmus[id] = load_fmu('f_' + str(id)+'.fmu',fmu_path+str(id))
fmus[id].initialize(start_time,final_time)
Результатом является словарь с идентификаторами в качестве ключа и моделями в качестве значения: {id1:FMUModelCS1,id2:FMUModelCS1}
Цель состоит в том, чтобы позже вызвать модели по их ключу и провести имитационное моделирование.
Вот моя попытка многопроцессорности:
def ep_intialization(id,start_time,final_time):
chdir(fmu_path+str(id))
model = load_fmu('f_' + str(id)+'.fmu',fmu_path+str(id))
model.initialize(start_time,final_time)
return {id:model}
data = ((id,start_time,final_time) for id in id_list)
if __name__ == '__main__':
pool = Pool(processes=cpus)
pool.starmap(ep_intialization, data)
pool.close()
pool.join()
Я могу видеть процессы моделей на моем системном мониторе, но затем скрипт вызывает ошибку, потому что модели нельзя выбрать:
MaybeEncodingError: Error sending result: '[{id2: <pyfmi.fmi.FMUModelCS1 object at 0x561eaf851188>}]'. Reason: 'TypeError('self._fmu,self.callBackFunctions,self.callbacks,self.context,self.variable_list cannot be converted to a Python object for pickling',)'
Но я не могу представить, что нет возможности инициализировать модели параллельно. Также приветствуются другие фреймворки / библиотеки, кроме потоковой / многопроцессорной.
Я видел этот ответ, но похоже, что он фокусируется на моделировании после инициализации.
1 ответ
Ответ ниже одного вы ссылаетесь, кажется, объяснить, что проблема с многопроцессорной и FMU Инстанциация.
Я попытался использовать пафос, предложенный в этом ответе, но столкнулся с той же проблемой:
from pyfmi import load_fmu
from multiprocessing import Pool
from os import chdir
from pathos.multiprocessing import Pool
def ep_intialization(id):
chdir('folder' + str(id))
model = load_fmu('BouncingBall.fmu')
model.initialize(0,10)
return {id:model}
id_list = [1,2]
cpus = 2
data = ((id) for id in id_list)
pool = Pool(cpus)
out = pool.map(ep_intialization, data)
Это дает:
MaybeEncodingError: Error sending result: '[{1: <pyfmi.fmi.FMUModelME2 object at 0x564e0c529290>}]'. Reason: 'TypeError('self._context,self._fmu,self.callBackFunctions,self.callbacks cannot be converted to a Python object for pickling',)'
Вот еще одна идея:
Я предполагаю, что создание экземпляра происходит медленно, потому что EnergyPlus связывает множество библиотек с FMU. Если моделируемые компоненты имеют одинаковый интерфейс (вход, выход, параметры), вы, вероятно, можете использовать один FMU с дополнительным параметром, который переключает модели.
Это было бы намного эффективнее: вам нужно было бы только создать экземпляр одного FMU и вызвать его параллельно с разными параметрами и входами.
Пример:
Я никогда не работал с EnergyPlus, но, возможно, следующий пример проиллюстрирует подход:
У вас есть три варианта здания, и вас просто интересует общий тепловой поток по всей площади здания как функция - "погоды" (что бы это ни значило - может быть, множество переменных).
Поместите все три здания в одну модель EnergyPlus и создайте вокруг них условие if или case (псевдокод):
if (id_building == 1) {
[model the building one]
elseif (if_building == 2) {
[model the building two]
[...]
Определите "погоду" или что-то еще в качестве входной переменной для FMU и определите id_building также как параметр. Задайте общий тепловой поток как выходную переменную.
Это позволит вам выбрать здание перед началом моделирования.
Два требования:
- Синтаксис EnergyPlus допускает структуры if или case.
- Все ваши модели работают с одним и тем же интерфейсом (в нашем примере у нас есть погодные переменные, а поток - исходящие переменные).
Для второго требования существует грязный обходной путь: просто определите все переменные, которые нужны всем вашим моделям, и используйте только то, что вам нужно, в соответствующем блоке if.