在问题中定义未用作输入的变量,并且等于先前的 input/output

Define variable in problem which is not used as input, and equals a previous input/output

我想定义一个变量,根据某些选项,该变量将等于以前的输出(好像以前的输出有两个名称)或者将是新组件的输出。

一个简单的解决方案是在未实现定义值的组件时省略值的定义,但出于 readability/traceability 原因我更希望定义它(以简化 if 语句代码,并将其作为时间序列输出提供)。

问题是,当使用connect语句时,如果后续条件没有导致变量被用作另一个组件的输入,它会提供一个错误,提示它尝试连接但变量不存在.

我用一种 link 语句(下面的 LinkVarComp 波纹管)进行了临时修复,它创建了一个输出等于输入的显式组件(以及一些额外的东西,如缩放和移位,这可能是对线性方程有用),但我担心这会增加不必要的 computations/design variables/constraints.

是否有 easier/better 解决方法? (也许通过允许变量有多个名称?)最好的做法是让一个变量的名称与之前的 output/input 相同?

一个简单的例子:

import openmdao.api as om
model = om.Group()
    model.add_subsystem('xcomp',subsys=om.IndepVarComp(name='x',val=np.zeros((3,2))),promotes_outputs=['*'])
model.connect('x','y')
p = om.Problem(model)
p.setup(force_alloc_complex=True)

p.set_val('x', np.array([[1.0 ,3],[10 ,-5],[0,3.1]])) 
p.run_model()

因错误而崩溃

NameError: <model> <class Group>: Attempted to connect from 'x' to 'y', but 'y' doesn't exist.

虽然这在使用以下 LinkVarComp 组件时有效(但我想添加新变量和计算)

import openmdao.api as om 
import numpy as np
from math import prod

class LinkVarComp(om.ExplicitComponent):
    """
    Component containing
    """
    def initialize(self):
        """
        Declare component options.
        """
        self.options.declare('shape', types=(int,tuple),default=1)
        self.options.declare('scale', types=int,default=1)
        self.options.declare('shift', types=float,default=0.)
        self.options.declare('input_default', types=float,default=0.)
        self.options.declare('input_name', types=str,default='x')
        self.options.declare('output_name', types=str,default='y')
        self.options.declare('output_default', types=float,default=0.)
        self.options.declare('input_units', types=(str,None),default=None)
        self.options.declare('output_units', types=(str,None),default=None)

    def setup(self):
        self.add_input(name=self.options['input_name'],val=self.options['input_default'],shape=self.options['shape'],units=self.options['input_units'])
        self.add_output(name=self.options['output_name'],val=self.options['output_default'],shape=self.options['shape'],units=self.options['output_units'])
        if type(self.options['shape']) == int:
            n = self.options['shape']
        else:
            n =prod( self.options['shape'])
        ar = np.arange(n)
        self.declare_partials(of=self.options['output_name'] , wrt=self.options['input_name'], rows=ar, cols=ar,val=self.options['scale'])

    def compute(self, inputs, outputs):
        outputs[self.options['output_name']] = self.options['scale']*inputs[self.options['input_name']] + self.options['shift']

model = om.Group()
model.add_subsystem('xcomp',subsys=om.IndepVarComp(name='x',val=np.zeros((3,2))),promotes_outputs=['*'])
model.add_subsystem('link', LinkVarComp(shape=(3,2)),
                        promotes_inputs=['*'],
                        promotes_outputs=['*'])

p = om.Problem(model)
p.setup(force_alloc_complex=True)

p.set_val('x', np.array([[1.0 ,3],[10 ,-5],[0,3.1]]))
p.run_model()
print(p['y'])

输出预期:

[[ 1.   3. ]
 [10.  -5. ]
 [ 0.   3.1]]

在 OpenMDAO 中,您不能让同一个变量使用两个不同的名称。那是不允许的。

您提出的解决方案实际上是创建一个单独的组件来保存输出的副本。这样可行。您可以使用 ExecComp 以更少的代码获得相同的效果:

import numpy as np
import openmdao.api as om

model = om.Group()
model.add_subsystem('xcomp',subsys=om.IndepVarComp(name='x',val=np.zeros((3,2))),promotes_outputs=['*'])
model.add_subsystem('ycomp', om.ExecComp("y=x", shape=(3,2)), promotes=['*'])


p = om.Problem(model)
p.setup(force_alloc_complex=True)

p.set_val('x', np.array([[1.0 ,3],[10 ,-5],[0,3.1]])) 
p.run_model()

print(p['x'])
print(p['y'])

一般来说,我自己可能不会真正这样做。好像有点浪费相反,我会修改我的 post-processing 脚本来寻找 y,如果它没有找到它然后抓取 x