如何使用单独的模型组件为收敛变量设置初始猜测?

时间:2019-05-03 13:13:21

标签: openmdao

这不是OpenMDAO的问题,而是一个我想听听您关于(简单)解决方案建议的想法的主题。问题在于为需要与求解器收敛的变量设置初始值。在我的情况下,我可以建立一个模型,其中一个工具(InitialGuess能够给出一个变量的初始猜测(比如y1),该变量将集中在{{1 }}是另一个工具(y1)的输出。目前,不允许有两个工具以D1作为输出(这是可以理解的)。因此,不可能将y1作为前置条件,而让InitialGuess计算更新后的值。但是,在某些模型中,将前置条件作为组件之一可能会有所帮助。在飞机的设计示例中,较低保真度的工具可以提供初始的猜测,以便使求解器可以从使用较高保真度的工具的更好点开始。

我创建了一个小例子来说明我的观点(基于Sellar问题)。代码显示在图片下方。这张图片显示了应该以蓝色创建的“初始猜测连接”:

enter image description here

D1

在上面的示例中,from openmdao.core.explicitcomponent import ExplicitComponent from openmdao.devtools.problem_viewer.problem_viewer import view_model from openmdao.solvers.nonlinear.nonlinear_block_gs import NonlinearBlockGS class InitialGuess(ExplicitComponent): def setup(self): self.add_input('x1', val=0.) self.add_input('z1', val=0.) self.add_input('z2', val=0.) self.add_output('y1', val=0.) self.add_output('y2', val=0.) def compute(self, inputs, outputs): x1 = inputs['x1'] z1 = inputs['z1'] z2 = inputs['z2'] outputs['y1'] = (-0.1 + ((z1 - 0.1) ** 2 + 0.8 * z2 + x1) ** (0.5)) ** 2 outputs['y2'] = z1 + z2 - 0.1 + ((z1 - 0.1) ** 2 + 0.8 * z2 + x1) ** (0.5) class D1(ExplicitComponent): def setup(self): self.add_input('x1', val=0.) self.add_input('z1', val=0.) self.add_input('z2', val=0.) self.add_input('y2', val=0.) self.add_output('y1', val=0.) def compute(self, inputs, outputs): x1 = inputs['x1'] z1 = inputs['z1'] z2 = inputs['z2'] y2 = inputs['y2'] outputs['y1'] = z1 ** 2. + x1 + z2 - .2 * y2 class D2(ExplicitComponent): def setup(self): self.add_input('z1', val=0.) self.add_input('z2', val=0.) self.add_input('y1', val=0.) self.add_output('y2', val=0.) def compute(self, inputs, outputs): z1 = inputs['z1'] z2 = inputs['z2'] y1 = inputs['y1'] outputs['y2'] = abs(y1)**.5 + z1 + z2 if __name__ == "__main__": from openmdao.core.problem import Problem from openmdao.core.group import Group from openmdao.core.indepvarcomp import IndepVarComp model = Group() ivc = IndepVarComp() ivc.add_output('x1', 3.0) ivc.add_output('z1', 2.0) ivc.add_output('z2', 2.0) model.add_subsystem('des_vars', ivc) model.add_subsystem('initial_guess', InitialGuess()) conv_group = Group() conv_group.add_subsystem('d1_comp', D1()) conv_group.add_subsystem('d2_comp', D2()) model.add_subsystem('conv_group', conv_group) model.connect('des_vars.x1', 'initial_guess.x1') model.connect('des_vars.x1', 'conv_group.d1_comp.x1') model.connect('des_vars.z1', 'initial_guess.z1') model.connect('des_vars.z1', 'conv_group.d1_comp.z1') model.connect('des_vars.z1', 'conv_group.d2_comp.z1') model.connect('des_vars.z2', 'initial_guess.z2') model.connect('des_vars.z2', 'conv_group.d1_comp.z2') model.connect('des_vars.z2', 'conv_group.d2_comp.z2') model.connect('conv_group.d1_comp.y1', 'conv_group.d2_comp.y1') model.connect('conv_group.d2_comp.y2', 'conv_group.d1_comp.y2') ### # PSEUDO_CODE # model.connect_as('initial_guess', 'initial_guess.y1', 'conv_group.d2_comp.y1') # model.connect_as('initial_guess', 'initial_guess.y2', 'conv_group.d1_comp.y1') ### conv_group.nonlinear_solver = NonlinearBlockGS() prob = Problem(model) prob.setup() view_model(prob, outfile='n2_initial_guess_example.html', show_browser=False) prob.run_model() print('y1 guess = ' + str(prob['initial_guess.y1'][0])) print('y1 conv = ' + str(prob['conv_group.d1_comp.y1'][0])) print('y2 guess = ' + str(prob['initial_guess.y2'][0])) print('y2 conv = ' + str(prob['conv_group.d2_comp.y2'][0])) initial_guess是完全分开的,但是,如果通过单个conv_group调用,run_model组件将非常有帮助在解决initial_guess之前更新y1y2的值。在这种情况下,这甚至意味着conv_group将在第一次迭代中求解,但是在实际情况下,这只会导致更少的迭代。示例中的伪代码提供了有关如何在脚本中定义伪代码的建议。

我想知道OpenMDAO中是否已经有一种方法?如果没有,我认为包含这样的功能可能是一个不错的主意。

1 个答案:

答案 0 :(得分:1)

OpenMDAO主分支(截至05/01/2019)OpenMDAO支持使用guess_nonlinear方法在以下系统上提供初步猜测:http://openmdao.org/twodocs/versions/latest/features/core_features/grouping_components/guess_method.html

此功能将在V2.7中发布,但同时可以通过从主服务器拉入来访问。

此方法在求解组之前运行,并将隐式输出设置为所需的任何初始值。

guess_nonlinear的一个方便之处在于,假设您只需要访问输入,输出或残差,就可以使用它来执行所需的任何计算。