Как инициализировать модели 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 также как параметр. Задайте общий тепловой поток как выходную переменную.

Это позволит вам выбрать здание перед началом моделирования.

Два требования:

  1. Синтаксис EnergyPlus допускает структуры if или case.
  2. Все ваши модели работают с одним и тем же интерфейсом (в нашем примере у нас есть погодные переменные, а поток - исходящие переменные).

Для второго требования существует грязный обходной путь: просто определите все переменные, которые нужны всем вашим моделям, и используйте только то, что вам нужно, в соответствующем блоке if.

Другие вопросы по тегам