在 OpenMDAO 中创建 'partial objective'

Creation of a 'partial objective' in OpenMDAO

我正在创建一个程序来优化一组耦合的子组件以最小化它们的总质量。目前每个组件都是一个组,它的质量有一个提升的输出,然后另一个组组存在于顶层,它将每个质量作为输入,计算总和,然后这个总和被用作 objective对于优化器。

本程序设计为由用户操作,其中子组件的类型和数量在运行时设置。这对我的静态声明的质量求和组来说是有问题的,它需要根据运行时添加的组件来更改它的输入。

因此,我想知道是否有一种方法可以声明一个 'partial objective',其中每个部分都将被加在一起,以供 ScipyOptimize 驱动程序处理的最终 objective? 'partial objectives',设计变量和约束可以简单地添加到每个子系统中,并将子系统添加到模型中,它们将准备好去适应更大的优化。

另一种方式可能是一组中的某种夏季行为,其中要求和的输入是通过 glob 模式专门创建的。类似于

self.add_subsystem('sum', Summer(inputs='mass:*'))

有什么方法可以在 OpenMDAO 3.1.1 中实现这两种类型的功能吗?

我们正在计划进行更改,以便在 setup/configure 时进行更多的模型自省。在实施这些更改之前,实现此目的的典型方法与您实施的方法类似。如果不进行自省,您需要为 Summer 提供它应该期望的输入名称(不是基于通配符的)。

您可以为计算质量的系统赋予一些属性,例如 'mass_output_name'。

然后,您可以遍历所有此类系统:

mass_output_systems = [sys_a, sys_b, sys_c]
mass_names = [sys.mass_output_name for sys in mass_output_systems]

然后将这些提供给您的求和子系统:

self.add_subsystem('sum', Summer(inputs=mass_names))

在 OpenMDAO V3.1 中,有一个 configure 方法可以让您完成您想要的 --- 有一些注意事项。第一个警告是,在 V3.1 中,您可以检查组 configure 中的 I/O 个组件,但您可以 而不是 检查 I/O儿童团体。这是我们正在努力解决的问题,但从 V3.1 开始,此限制就存在了。

None 少,这里有一些代码可以完成我认为你正在寻找的东西。它不是超级干净,但它确实实现了您想要的那种反应式设置。

import openmdao.api as om


class Summer(om.ExplicitComponent): 
    
    def setup(self): 
        # note: will add inputs via the configure method of parent group
        self.add_output('total_mass')

        self.declare_partials('total_mass', wrt='*', val=1)

    def compute(self, inputs, outputs): 

        outputs['total_mass'] = 0
        for inp_name in inputs: 
            outputs['total_mass'] += inputs[inp_name] 


class TotalMass(om.Group): 

    def setup(self): 
        # Only add the summing comp, others will be added by users
        self.add_subsystem('sum', Summer())


    def configure(self): 

        sum_comp = self.sum

        # NOTE: need to access some private attributes of the group here, 
        #   so this is a little fragile, but works as of OM V3.1
        for subsys in self._subsystems_myproc: 
            s_name = subsys.name

            if s_name == 'sum': 
                continue

            i_name = f'{s_name}_mass'
            sum_comp.add_input(i_name)
            self.connect(f'{s_name}.mass', f'sum.{i_name}')


if __name__ == "__main__": 

    p = om.Problem()

    tm = p.model.add_subsystem('tm', TotalMass())

    tm.add_subsystem('part_1', om.ExecComp('mass=3+x'))
    tm.add_subsystem('part_2', om.ExecComp('mass=5+x'))

    p.setup()

    p.run_model()

    p.model.list_outputs()