Как использовать вложенные проблемы в OpenMDAO 1.x?

Я пытаюсь реализовать Collaborative Optimization и другие многоуровневые архитектуры OpenMDAO. Я читаю здесь, что это можно сделать, определив отдельный метод solve_nonlinear в подclassе проблемы.

Проблема заключается в том, что при запуске экземпляра проблемы определенная функция solve_linear не вызывается. Вот код –

from __future__ import print_function, division import numpy as np import time from openmdao.api import Component,Group, IndepVarComp, ExecComp,\ Problem, ScipyOptimizer, NLGaussSeidel, ScipyGMRES class SellarDis1(Component): """Component containing Discipline 1.""" def __init__(self): super(SellarDis1, self).__init__() self.add_param('z', val=np.zeros(2)) self.add_param('x', val=0.0) self.add_param('y2', val=1.0) self.add_output('y1', val=1.0) def solve_nonlinear(self, params, unknowns, resids): y1 = z1**2 + z2 + x1 - 0.2*y2""" z1 = params['z'][0] z2 = params['z'][1] x1 = params['x'] y2 = params['y2'] unknowns['y1'] = z1**2 + z2 + x1 - 0.2*y2 def linearize(self, params, unknowns, resids): J = {} J['y1','y2'] = -0.2 J['y1','z'] = np.array([[2*params['z'][0], 1.0]]) J['y1','x'] = 1.0 return J class SellarDis2(Component): def __init__(self): super(SellarDis2, self).__init__() self.add_param('z', val=np.zeros(2)) self.add_param('y1', val=1.0) self.add_output('y2', val=1.0) def solve_nonlinear(self, params, unknowns, resids): z1 = params['z'][0] z2 = params['z'][1] y1 = params['y1'] y1 = abs(y1) unknowns['y2'] = y1**.5 + z1 + z2 def linearize(self, params, unknowns, resids): J = {} J['y2', 'y1'] = 0.5*params['y1']**-0.5 J['y2', 'z'] = np.array([[1.0, 1.0]]) return J class Sellar(Group): def __init__(self): super(Sellar, self).__init__() self.add('px', IndepVarComp('x', 1.0), promotes=['*']) self.add('pz', IndepVarComp('z', np.array([5.0,2.0])), promotes=['*']) self.add('d1', SellarDis1(), promotes=['*']) self.add('d2', SellarDis2(), promotes=['*']) self.add('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0, y1=0.0, y2=0.0), promotes=['*']) self.add('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['*']) self.add('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['*']) self.nl_solver = NLGaussSeidel() self.nl_solver.options['atol'] = 1.0e-12 self.ln_solver = ScipyGMRES() def solve_nonlinear(self, params=None, unknowns=None, resids=None, metadata=None): print("Group's solve_nonlinear was called!!") # Discipline Optimizer would be called here? super(Sellar, self).solve_nonlinear(params, unknowns, resids) class ModifiedProblem(Problem): def solve_nonlinear(self, params, unknowns, resids): print("Problem's solve_nonlinear was called!!") # or here ? super(ModifiedProblem, self).solve_nonlinear() top = ModifiedProblem() top.root = Sellar() top.driver = ScipyOptimizer() top.driver.options['optimizer'] = 'SLSQP' top.driver.add_desvar('z', lower=np.array([-10.0, 0.0]), upper=np.array([10.0, 10.0])) top.driver.add_desvar('x', lower=0., upper=10.0) top.driver.add_objective('obj') top.driver.add_constraint('con1', upper=0.0) top.driver.add_constraint('con2', upper=0.0) top.setup(check=False) top.run() 

Выходной код выше –

 Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Group's solve_nonlinear was called!! Optimization terminated successfully. (Exit mode 0) Current function value: [ 3.18339395] Iterations: 6 Function evaluations: 6 Gradient evaluations: 6 Optimization Complete ----------------------------------- 

что означает, что решающая нелинейность, определенная в подclassе Проблема, не вызывается в любое время. Итак, следует ли мне назвать оптимизаторов дисциплины в подclassе Группы?

Кроме того, как передать целевые переменные между двумя задачами оптимизации (System & Disciplines), специально возвращая оптимизированные глобальные переменные из отдельных дисциплин обратно в системный оптимизатор.

Спасибо всем.

    Вы правы, что solve_nonlinear по Problem никогда не вызывается, потому что Problem не является компонентом OpenMDAO и не имеет метода solve_nonlinear . То, что вы хотите сделать, чтобы запустить проблему подмоделей внутри другой проблемы, – это инкапсулировать ее в экземпляр Component. Это будет выглядеть примерно так:

     class SubOptimization(Component) def __init__(self): super(SubOptimization, self).__init__() # Inputs to this subprob self.add_param('z', val=np.zeros(2)) self.add_param('x', val=0.0) self.add_param('y2', val=1.0) # Unknowns for this sub prob self.add_output('y1', val=1.0) self.problem = prob = Problem() prob.root = Group() prob.add('px', IndepVarComp('x', 1.0), promotes=['*']) prob.add('d1', SellarDis1(), promotes=['*']) # TODO - add cons/objs for sub prob prob.driver = ScipyOptimizer() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.add_desvar('x', lower=0., upper=10.0) prob.driver.add_objective('obj') prob.driver.add_constraint('con1', upper=0.0) prob.driver.add_constraint('con2', upper=0.0) prob.setup() # Must finite difference across optimizer self.fd_options['force_fd'] = True def solve_nonlinear(self, params, unknowns, resids): prob = self.problem # Pass values into our problem prob['x'] = params['x'] prob['z'] = params['z'] prob['y2'] = params['y2'] # Run problem prob.run() # Pull values from problem unknowns['y1'] = prob['y1'] 

    Вы можете поместить этот компонент в свою основную проблему (вместе с одной для дисциплины 2, хотя 2 действительно не нуждается в суб-оптимизации, поскольку она не имеет локальных вариантов дизайна) и оптимизирует глобальную переменную проектирования вокруг нее.

    Одно предостережение: это не то, что я пробовал (и я не тестировал неполный fragment кода выше), но он должен получить вас на правильном пути. Возможно, вы можете столкнуться с ошибкой, так как это не очень много проверено. Когда я получу какое-то время, я смогу собрать такой тест для тестов OpenMDAO, чтобы мы были в безопасности.

    Давайте будем гением компьютера.