【问题标题】:It there a way to cache OpenMDAO component outputs to avoid duplicate executions?有没有办法缓存 OpenMDAO 组件输出以避免重复执行?
【发布时间】:2021-10-08 11:32:03
【问题描述】:

我正在编写一个由五个子系统组成的模型。第一个子系统使用它不迭代解决任何问题的输入为其他子系统生成数据,因此它的输出在计算期间不会改变。我希望它像初始化一样调用一次计算方法。如何编写一个模型,在 run_model 中调用一次,而在 run_driver 中每次只调用一次?

【问题讨论】:

    标签: optimization solver openmdao


    【解决方案1】:

    如果没有更多细节,这有点难以确定,但你提到“迭代”,所以我猜你在模型的顶层有一个求解器,并且有一个组件未参与该求解器循环,但那是越来越每次求解器迭代时调用。

    解决方案是在模型中创建一个仅包含需要迭代的组件的子组。将只运行一次的组件与该组一起放在模型的顶部。将迭代求解器放在子组上。

    另一种解决方案是向您的组件添加一些缓存,因此它会检查其输入以查看它们是否已更改。如果有,请重新运行。如果他们没有,请保留旧答案。

    这是一个包含这两个功能的示例(注意:此示例中的求解器不会收敛,因为它是一个没有有效物理解决方案的玩具问题。我只是将它们放在一起来说明模型结构和缓存)

    import openmdao.api as om
    # from openmdao.utils.assert_utils import assert_check_totals
    
    
    class StingyComp(om.ExplicitComponent): 
    
        def setup(self): 
    
            self.add_input('x1', val=2.)
            self.add_input('x2', val=3.)
    
            self.add_output('x')
    
            self._input_hash = None
    
    
        def compute(self, inputs, outputs):
    
            x1 = inputs['x1'][0] # pull the scalar out so you can hash it
            x2 = inputs['x2'][0]
    
            print("running StingyComp")
            current_input_hash = hash((x1, x2))
            if self._input_hash != current_input_hash : 
                print('    ran compute')
                outputs['x'] = 2*x1 + x2**2
                self._input_hash = current_input_hash
            else: 
                print('    skipped compute')
    
    
    class NormalComp(om.ExplicitComponent): 
    
        def setup(self): 
    
            self.add_input('x1', val=2.)
            self.add_input('x2', val=3.)
    
            self.add_output('y')
    
        def compute(self, inputs, outputs):
    
            x1 = inputs['x1']
            x2 = inputs['x2']
    
            print("running normal Comp")
            outputs['y'] = x1 + x2
    
    
    p = om.Problem()
    
    
    
    p.model.add_subsystem('run_once1', NormalComp(), promotes=['*'])
    p.model.add_subsystem('run_once2', StingyComp(), promotes=['*'])
    
    sub_group = p.model.add_subsystem('sub_group', om.Group(), promotes=['*']) # transparent group that could hold sub-solver
    sub_group.add_subsystem('C1', om.ExecComp('f1 = f2**2 + 1.5 * x - y**2.5'), promotes=['*'])
    sub_group.add_subsystem('C2', om.ExecComp('f2 = f1**2 + x**1.5 - 2.5*y'), promotes=['*'])
    sub_group.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
    sub_group.linear_solver = om.DirectSolver()
    
    
    p.setup()
    
    
    print('first run')
    p.run_model()
    
    print('second run, same inputs')
    p.run_model()
    
    p['x1'] = 10
    p['x2'] = 27.5
    
    print('third run, new inputs')
    p.run_model()
    

    【讨论】:

    • 我只是使用几何输入进行离散化。除非几何形状发生变化(最初给出),否则在求解过程中无需调用。在父组中,我使用 set_order,最初强制它调用,在 N2 图中看到并使用 LinearRunOnce 作为求解器。我只是在计算方法中做了一个简单的打印提示并调用每次迭代,我想确保它确实如此不会导致计算负载。
    • 如果你能保证系统只需要调用一次计算,你在调用计算时设置一个标志,从那时起不要重新计算输出。输出将保持不变,因为它们不会被计算覆盖。请小心使用这种技术,因为如果输入确实在不知不觉中发生了变化,您将得到不正确的输出或部分输出。
    • 你的问题很模糊。如果您能提供一个示例运行脚本,让我们给出更明确的答案。
    • @JustinGray 谢谢你的例子。我的代码以这种方式工作(收敛)。为了清楚起见,我的问题是“有没有办法在第二次运行时不提示'running StingyComp'”,这种方式也可以显着加速我的优化。
    猜你喜欢
    • 2021-12-15
    • 1970-01-01
    • 2014-11-17
    • 2020-12-02
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    相关资源
    最近更新 更多