Это не проблема OpenMDAO, но больше тема, о которой я хотел бы услышать ваши мысли с (упрощенным) предложением решения.Проблема в том, чтобы установить начальное значение для переменной, которую нужно объединить с помощью решателя.В моем случае у меня может быть модель, в которой один инструмент (InitialGuess
) может дать начальное предположение для переменной (скажем, для y1
), которая будет сходиться в группу, где y1
является выходом другогоинструмент (D1
).В настоящее время не разрешено иметь два инструмента, которые имеют y1
в качестве выходных данных (и это понятно).Следовательно, невозможно использовать InitialGuess
в качестве предварительного кондиционера и позволить 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
.В этом случае это будет даже означать, что conv_group
будет решено на первой итерации, но в реалистическом случае это просто приведет к меньшему количеству итераций.Псевдокод в примере дает представление о том, как это можно определить в скрипте.
Мне было интересно, есть ли способ сделать это в OpenMDAO?Если нет, то я подумал, что было бы неплохо включить такую возможность.