Я хотел бы иметь возможность передавать строковые значения между компонентами. Возможно ли это в последней версии OpenMDAO или это будет возможно в будущих выпусках?
Если я правильно понимаю, то передача строк поддерживалась в более ранних выпусках OpenMDAO (V<=1) с передачей по объекту. В настоящее время я использую обходной путь, при котором строковые входные и выходные данные моих инструментов записываются в отдельные файлы и при необходимости берутся из этих файлов. Тогда это выходит за рамки модели OpenMDAO.
Вот небольшой пример типа модели, которая будет поддерживаться, если строки можно использовать в качестве входных и выходных данных. Это, конечно, просто демонстрационный случай.
from openmdao.core.explicitcomponent import ExplicitComponent
from openmdao.core.group import Group
from openmdao.core.indepvarcomp import IndepVarComp
from openmdao.core.problem import Problem
from openmdao.devtools.problem_viewer.problem_viewer import view_model
class PreProcessor(ExplicitComponent):
def setup(self):
self.add_input('a', val=0.)
self.add_output('para_shape', val='hill')
def compute(self, inputs, outputs):
if inputs['a'] <= 0.:
outputs['para_shape'] = 'hill'
else:
outputs['para_shape'] = 'canyon'
class Parabola(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.)
self.add_input('para_shape', val='hill')
self.add_output('y', val=0.)
def compute(self, inputs, outputs):
if inputs['para_shape'] == 'hill':
outputs['y'] = -inputs['x']**2
elif inputs['para_shape'] == 'canyon':
outputs['y'] = inputs['x']**2
else:
raise IOError('Invalid "para_shape" value "{}" provided.'.format(inputs['para_shape']))
if __name__ == "__main__":
model = Group()
ivc = IndepVarComp()
ivc.add_output('a', 2.)
ivc.add_output('x', 4.)
model.add_subsystem('vars', ivc, promotes=['*'])
model.add_subsystem('preprocessor', PreProcessor(), promotes=['*'])
model.add_subsystem('parabola', Parabola(), promotes=['*'])
prob = Problem(model)
prob.setup()
view_model(prob, outfile='n2_pass_by_object_example.html')
prob.run_model()
Если я запущу это, я получу ValueError
то could not convert string to float: hill
, чего и следовало ожидать. Мне просто интересно, есть ли способ заставить это работать, сохраняя para_shape
как строковый вывод PreProcessor
и строковый ввод для Parabola
.
Кроме того, в моем случае было бы просто удобно передавать строки, я подумал, что это также может быть полезно, когда используются алгоритмы оптимизации, поддерживающие дискретные значения, например, с генетическим алгоритмом. В этих алгоритмах para_shape
может быть проектной переменной с возможными значениями hill
или canyon
. За кулисами такая строковая переменная, вероятно, будет сопоставлена с целочисленным значением, например 0:hill, 1:canyon
.
Таким образом, мой вопрос: будет ли реализована передача по объекту (или аналогичная возможность, которая позволяет мне определять строковый ввод/вывод) для OpenMDAO 2 или уже есть способ сделать это?
Хорошая новость заключается в том, что текущая версия OpenMDAO поддерживает дискретные переменные. Я обновил ваш пример, чтобы использовать текущий синтаксис для объявления дискретных переменных и передачи их функции вычисления. По сути, изменения заключаются в том, что вам нужно объявлять дискретные переменные с помощью add_discrete_input
и add_discrete_output
. Кроме того, вы должны добавить discrete_inputs
и discrete_outputs
в качестве аргументов к вашей функции compute
, чтобы новая версия выглядела так: def compute(self, inputs, outputs, discrete_inputs, discrete_outputs)
. Также обратите внимание, что другие функции, такие как compute_partials
, compute_jacvec_product
и другие, также требуют дополнительных дискретных аргументов, если ваш компонент использует их.
Плохая новость заключается в том, что ваш пример выявил ошибку в view_model
. Похоже, что view_model
в настоящее время не поддерживает должным образом дискретные переменные. Я поместил ошибку в наш трекер ошибок, описывающую проблему, так что, надеюсь, мы скоро ее исправим.
from openmdao.core.explicitcomponent import ExplicitComponent
from openmdao.core.group import Group
from openmdao.core.indepvarcomp import IndepVarComp
from openmdao.core.problem import Problem
from openmdao.devtools.problem_viewer.problem_viewer import view_model
class PreProcessor(ExplicitComponent):
def setup(self):
self.add_input('a', val=0.)
self.add_discrete_output('para_shape', val='hill')
def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
if inputs['a'] <= 0.:
discrete_outputs['para_shape'] = 'hill'
else:
discrete_outputs['para_shape'] = 'canyon'
class Parabola(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.)
self.add_discrete_input('para_shape', val='hill')
self.add_output('y', val=0.)
def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
if discrete_inputs['para_shape'] == 'hill':
outputs['y'] = -inputs['x']**2
elif discrete_inputs['para_shape'] == 'canyon':
outputs['y'] = inputs['x']**2
else:
raise IOError('Invalid "para_shape" value "{}" provided.'.format(inputs['para_shape']))
if __name__ == "__main__":
model = Group()
ivc = IndepVarComp()
ivc.add_output('a', 2.)
ivc.add_output('x', 4.)
model.add_subsystem('vars', ivc, promotes=['*'])
model.add_subsystem('preprocessor', PreProcessor(), promotes=['*'])
model.add_subsystem('parabola', Parabola(), promotes=['*'])
prob = Problem(model)
prob.setup()
view_model(prob, outfile='n2_pass_by_object_example.html')
prob.run_model()
Хорошо, может быть, предложением по улучшению, чтобы направить пользователя к потенциальному решению, было бы изменить сообщение ValueError
на что-то вроде: ValueError: Could not convert string to float: hill. For string values, use discrete_inputs / _outputs in the component methods.
Просто идея! :)
Фантастика, это работает как шарм. Я думаю, что вы не предоставили обновленный код, возможно, случайно скопировали старый?