OpenMDAO2对组连接和输入/输出变量的限制使我无法编写干净的模块化软件
from openmdao.api import Group, ExplicitComponent, IndepVarComp, Problem
class A(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Az', val=0.0)
def compute(self, inputs, outputs):
outputs['Az'] = inputs['x'] + inputs['y']
class B(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Bz', val=0.0)
def compute(self, inputs, outputs):
outputs['Bz'] = 2*inputs['x'] - inputs['y']
class AB(Group):
def setup(self):
self.add_subsystem('A', A(), promotes=['*'])
self.add_subsystem('B', B(), promotes=['*'])
indeps = IndepVarComp()
indeps.add_output('x', 0.0)
indeps.add_output('y', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
class C(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Cz', val=0.0)
def compute(self, inputs, outputs):
outputs['Cz'] = 3*inputs['x'] - 2*inputs['y']
class D(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Dz', val=0.0)
def compute(self, inputs, outputs):
outputs['Dz'] = 4*inputs['x'] - 2.5*inputs['y']
class CD(Group):
def setup(self):
self.add_subsystem('C', C(), promotes=['*'])
self.add_subsystem('D', D(), promotes=['*'])
indeps = IndepVarComp()
indeps.add_output('x', 0.0)
indeps.add_output('y', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
有时候,我只想与AB组一起工作(运行方案,优化等),有时我只想与CD组一起工作。我可以做到的,
prob = Problem()
prob.model = AB()
prob.setup()
prob['x'] = 10.0
prob['y'] = 20.0
prob.run_model()
print(prob['Az'],prob['Bz'])
但是,有时候我想和ABCD集团一起工作:
class ABCD(Group):
def setup(self):
self.add_subsystem('AB', AB())
self.add_subsystem('CD', CD())
indeps = IndepVarComp()
indeps.add_output('xx', 0.0)
indeps.add_output('yy', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
self.connect('xx', ['AB.x', 'CD.x'])
self.connect('yy', ['AB.y', 'CD.y'])
在那种情况下,没有变量提升,连接或IndepVarComps用法的组合,不会给我带来“具有多个连接的输入”的错误。
在OpenMDAO 1.x中,我可以通过从较低级别的组(AB,CD)中删除IndepVarComps并仅在最高级别的组(see answer)中使用它们来解决此问题。但是,OpenMDAO 2.x引发错误,连接了两个输入而没有输出。例如:
class AB(Group):
def setup(self):
self.add_subsystem('A', A(), promotes=['*'])
self.add_subsystem('B', B(), promotes=['*'])
现在,我坚持维护同一代码的多个副本,一个用于AB的副本,另一个用于ABCD的副本,或者只是用纯python手动连接我的模块并远离OpenMDAO。我想念什么吗?任何帮助或指导都将受到欢迎。
答案 0 :(得分:3)
在您的简单示例中,我可以看到两种解决问题的方法。两者都涉及在组上使用选项。由于我不确定哪种方法会更好,因此在下面的示例中将它们都包括在内。
一种方法是,如果AB / CD拥有自己的indeps,则可以将其设为可选。然后,您可以根据需要切换所需的行为。这行得通,但我个人认为它很混乱。
第二个选项是仅创建一个组,但使用这些选项来控制mode
参数创建的内容。我认为这样比较干净,因为您只有4个组件和一组组件。
from openmdao.api import Group, ExplicitComponent, IndepVarComp
class A(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Az', val=0.0)
def compute(self, inputs, outputs):
outputs['Az'] = inputs['x'] + inputs['y']
class B(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Bz', val=0.0)
def compute(self, inputs, outputs):
outputs['Bz'] = 2*inputs['x'] - inputs['y']
class AB(Group):
def initialize(self):
self.options.declare('owns_indeps', types=bool, default=True)
def setup(self):
if self.options['owns_indeps']:
indeps = IndepVarComp()
indeps.add_output('x', 0.0)
indeps.add_output('y', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
self.add_subsystem('A', A(), promotes=['*'])
self.add_subsystem('B', B(), promotes=['*'])
class C(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Cz', val=0.0)
def compute(self, inputs, outputs):
outputs['Cz'] = 3*inputs['x'] - 2*inputs['y']
class D(ExplicitComponent):
def setup(self):
self.add_input('x', val=0.0)
self.add_input('y', val=0.0)
self.add_output('Dz', val=0.0)
def compute(self, inputs, outputs):
outputs['Dz'] = 4*inputs['x'] - 2.5*inputs['y']
class CD(Group):
def initialize(self):
self.options.declare('owns_indeps', types=bool, default=True)
def setup(self):
if self.options['owns_indeps']:
indeps = IndepVarComp()
indeps.add_output('x', 0.0)
indeps.add_output('y', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
self.add_subsystem('C', C(), promotes=['*'])
self.add_subsystem('D', D(), promotes=['*'])
class ABCD(Group):
def setup(self):
self.add_subsystem('AB', AB(owns_indeps=False))
self.add_subsystem('CD', CD(owns_indeps=False))
indeps = IndepVarComp()
indeps.add_output('xx', 0.0)
indeps.add_output('yy', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
self.connect('xx', ['AB.x', 'CD.x'])
self.connect('yy', ['AB.y', 'CD.y'])
class ABCD_ALT(Group):
"""Alternate approach that would not require more than one group class at all"""
def initialize(self):
self.options.declare('mode', values=['AB', 'CD', 'ABCD'], default='AB')
def setup(self):
mode = self.options['mode']
indeps = IndepVarComp()
indeps.add_output('xx', 0.0)
indeps.add_output('yy', 0.0)
self.add_subsystem('indeps', indeps, promotes=['*'])
if 'AB' in mode:
self.add_subsystem('A', A(), promotes=['*'])
self.add_subsystem('B', B(), promotes=['*'])
if 'CD' in mode:
self.add_subsystem('C', C(), promotes=['*'])
self.add_subsystem('D', D(), promotes=['*'])
self.connect('xx', 'x')
self.connect('yy', 'y')
if __name__ == "__main__":
from openmdao.api import Problem
p = Problem()
# p.model = AB()
# p.model = CD()
p.model = ABCD()
# p.model = ABCD_ALT(mode='AB')
p.setup()