这不是OpenMDAO的问题,而是一个我想听听您关于(简单)解决方案建议的想法的主题。问题在于为需要与求解器收敛的变量设置初始值。在我的情况下,我可以建立一个模型,其中一个工具(InitialGuess
能够给出一个变量的初始猜测(比如y1
),该变量将集中在{{1 }}是另一个工具(y1
)的输出。目前,不允许有两个工具以D1
作为输出(这是可以理解的)。因此,不可能将y1
作为前置条件,而让InitialGuess
计算更新后的值。但是,在某些模型中,将前置条件作为组件之一可能会有所帮助。在飞机的设计示例中,较低保真度的工具可以提供初始的猜测,以便使求解器可以从使用较高保真度的工具的更好点开始。
我创建了一个小例子来说明我的观点(基于Sellar问题)。代码显示在图片下方。这张图片显示了应该以蓝色创建的“初始猜测连接”:
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
之前更新y1
和y2
的值。在这种情况下,这甚至意味着conv_group
将在第一次迭代中求解,但是在实际情况下,这只会导致更少的迭代。示例中的伪代码提供了有关如何在脚本中定义伪代码的建议。
我想知道OpenMDAO中是否已经有一种方法?如果没有,我认为包含这样的功能可能是一个不错的主意。
答案 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
的一个方便之处在于,假设您只需要访问输入,输出或残差,就可以使用它来执行所需的任何计算。