Как установить начальное предположение для переменной сходимости с отдельным компонентом модели? - PullRequest
0 голосов
/ 03 мая 2019

Это не проблема OpenMDAO, но больше тема, о которой я хотел бы услышать ваши мысли с (упрощенным) предложением решения.Проблема в том, чтобы установить начальное значение для переменной, которую нужно объединить с помощью решателя.В моем случае у меня может быть модель, в которой один инструмент (InitialGuess) может дать начальное предположение для переменной (скажем, для y1), которая будет сходиться в группу, где y1 является выходом другогоинструмент (D1).В настоящее время не разрешено иметь два инструмента, которые имеют y1 в качестве выходных данных (и это понятно).Следовательно, невозможно использовать InitialGuess в качестве предварительного кондиционера и позволить D1 вычислить обновленные значения.Однако в некоторых моделях может быть полезно иметь такой предварительный кондиционер в качестве одного из компонентов.В примере конструкции самолета инструмент с более низкой точностью может дать начальные предположения, чтобы решатель мог начать в более удобной точке с помощью инструментов с более высокой точностью.

Я создал небольшой пример, иллюстрирующий мою точку зрения (основанный напроблема Селлара).Код показан под картинкой.На этом рисунке показаны «исходные предположительные соединения», которые должны быть созданы синим цветом:

enter image description here

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?Если нет, то я подумал, что было бы неплохо включить такую ​​возможность.

1 Ответ

1 голос
/ 03 мая 2019

Основная ветвь OpenMDAO (по состоянию на 01.05.2009) OpenMDAO поддерживает предоставление начального предположения с использованием метода guess_nonlinear в системах: http://openmdao.org/twodocs/versions/latest/features/core_features/grouping_components/guess_method.html

Эта функция будет выпущена в V2.7, номожно получить, потянув от мастера в то же время.

Этот метод запускается перед решением группы и устанавливает неявные выходные данные на любое начальное значение, которое вы хотите.

Удобная вещь в guess_nonlinear состоит в том, что вы можете использовать его для выполнения любых вычислений, которые выхотите, предполагая, что вам нужен только доступ к входам, выходам или остаткам.

...