Использование метамодели в процессе проектирования с использованием вложенного подхода

Мы заинтересованы в использовании суррогатной модели в процессе проектирования самолета, реализованном в OpenMDAO. По сути, мы хотим использовать аэродинамический код (например, VSPaero в нашей цели) для создания базы данных (с использованием DOE), а затем создать суррогат, который будет использоваться в процессе проектирования. Похоже на ваше предложение 2) использовать MOE в openMDAO, и мы также хотим получить доступ к "градиентной" информации суррогата, которая будет использоваться в полной задаче проектирования.
Мы начали с кода, который вы предоставили во вложенном проблемном вопросе, и попытались создать макет с упрощенным компонентом для аэродинамики. Пример кода приведен ниже (используется кригинг), и у нас есть две проблемы для его завершения:

  • нам нужно реализовать функцию "линеаризации" в нашем компоненте, если мы хотим использовать информацию о суррогатном градиенте: я думаю, что мы должны использовать функцию задачи "calc_gradient" для этого. Это правильно?
  • в нашем примере кода обучение будет проводиться каждый раз, когда мы называем компонент, который не очень эффективен: есть ли способ вызвать его только один раз или выполнить суррогатное обучение только после установки () более крупной проблемы (проектирование самолета) в нашем случае)?

Вот код (извините, он немного длинный):

from openmdao.api import IndepVarComp, Group, Problem, ScipyOptimizer, ExecComp, DumpRecorder, Component, NLGaussSeidel,ScipyGMRES, Newton,SqliteRecorder,MetaModel, \
    KrigingSurrogate, FloatKrigingSurrogate
from openmdao.drivers.latinhypercube_driver import LatinHypercubeDriver, OptimizedLatinHypercubeDriver

from openmdao.solvers.solver_base import NonLinearSolver
import numpy as np
import sys

alpha_test = np.array([0.56, 0.24, 0.30, 0.32, 0.20])
eta_test = np.array([-0.30, -0.14, -0.19, -0.18, -0.12])

num_elem = len(alpha_test)    

class SysAeroSurrogate(Component):
    """ Simulates the presence of an aero surrogate mode using linear aerodynamic model """
    """ coming from pymission code """
    """ https://github.com/OpenMDAO-Plugins/pyMission/blob/master/src/pyMission/aerodynamics.py """    

    def __init__(self, num_elem=1):
        super(SysAeroSurrogate, self).__init__()

        self.add_param('alpha', 0.5)
        self.add_param('eta', -0.33)
        self.add_param('AR', 0.0)
        self.add_param('oswald', 0.0)

        self.add_output('CL',  val=0.0)
        self.add_output('CD',  val=0.0) ## Drag Coefficient        

    def solve_nonlinear(self, params, unknowns, resids):
        """ Compute lift and drag coefficient using angle of attack and tail
        rotation angles. Linear aerodynamics is assumed."""

        alpha = params['alpha']
        eta = params['eta']
        aspect_ratio = params['AR']
        oswald = params['oswald']

        lift_c0 = 0.30
        lift_ca = 6.00
        lift_ce = 0.27
        drag_c0 = 0.015      

        unknowns['CL'] = lift_c0 + lift_ca*alpha*1e-1 + lift_ce*eta*1e-1
        unknowns['CD'] = (drag_c0 + (unknowns['CL'])**2 /(np.pi * aspect_ratio * oswald))/1e-1


class SuroMM(Group):
    def __init__(self):
        super(SuroMM, self).__init__()

        #kriging
        AeroMM = self.add("AeroMM", MetaModel())
        AeroMM.add_param('alpha', val=0.)
        AeroMM.add_param('eta', val=0.)                  
        AeroMM.add_output('CL_MM', val=0., surrogate=FloatKrigingSurrogate())
        AeroMM.add_output('CD_MM', val=0., surrogate=FloatKrigingSurrogate())      


class SurrogateAero(Component):

    def __init__(self):
        super(SurrogateAero, self).__init__()

        ## Inputs to this subprob

        self.add_param('alpha', val=0.5*np.ones(num_elem)) ## Angle of attack
        self.add_param('eta', val=0.5*np.ones(num_elem)) ## Tail rotation angle    
        self.add_param('AR', 0.0)
        self.add_param('oswald', 0.0)           

        ## Unknowns for this sub prob
        self.add_output('CD',  val=np.zeros(num_elem))
        self.add_output('CL',  val=np.zeros(num_elem))  

        #####
        self.problem = prob = Problem()
        prob.root = Group()

        prob.root.add('d1', SuroMM(), promotes=['*'])
        prob.setup()

        #### training of metamodel        
        prob['AeroMM.train:alpha'] = DOEX1
        prob['AeroMM.train:eta'] = DOEX2               
        prob['AeroMM.train:CL_MM'] = DOEY1
        prob['AeroMM.train:CD_MM'] =DOEY2

    def solve_nonlinear(self, params, unknowns, resids):

        CL_temp=np.zeros(num_elem)
        CD_temp=np.zeros(num_elem)        

        prob = self.problem

        # Pass values into our problem
        for i in range(len(params['alpha'])):
            prob['AeroMM.alpha'] = params['alpha'][i]
            prob['AeroMM.eta'] = params['eta'][i]

            # Run problem
            prob.run()

            CL_temp[i] = prob['AeroMM.CL_MM']
            CD_temp[i] = prob['AeroMM.CD_MM']        

        # Pull values from problem
        unknowns['CL'] =  CL_temp
        unknowns['CD'] =  CD_temp


if __name__ == "__main__":

###### creation of database with DOE #####
    top = Problem()
    root = top.root = Group()

    root.add('comp', SysAeroSurrogate(), promotes=['*'])
    root.add('p1', IndepVarComp('alpha', val=0.50), promotes=['*'])
    root.add('p2', IndepVarComp('eta',val=0.50), promotes=['*'])
    root.add('p3', IndepVarComp('AR', 10.), promotes=['*'])
    root.add('p4', IndepVarComp('oswald',  0.92), promotes=['*'])     

    top.driver = OptimizedLatinHypercubeDriver(num_samples=16, seed=0, population=20, generations=4, norm_method=2)
    top.driver.add_desvar('alpha', lower=-5.0*(np.pi/180.0)*1e-1, upper=15.0*(np.pi/180.0)*1e-1)
    top.driver.add_desvar('eta', lower=-5.0*(np.pi/180.0)*1e-1, upper=15.0*(np.pi/180.0)*1e-1)

    top.driver.add_objective('CD')

    recorder = SqliteRecorder('Aero')
    recorder.options['record_params'] = True
    recorder.options['record_unknowns'] = True
    recorder.options['record_resids'] = False
    recorder.options['record_metadata'] = False
    top.driver.add_recorder(recorder)

    top.setup()
    top.run()

    import sqlitedict
    db = sqlitedict.SqliteDict( 'Aero', 'openmdao' )
    print( list( db.keys() ) )
    DOEX1 = []
    DOEX2 = []
    DOEY1 = []
    DOEY2 = []
    for i in list(db.keys()):
            data = db[i]
            p = data['Parameters']
            DOEX1.append(p['comp.alpha'])
            DOEX2.append(p['comp.eta'])

            p = data['Unknowns']
            DOEY1.append(p['CL'])
            DOEY2.append(p['CD'])

    ################  use of surrogate model ######

    prob2 = Problem(root=Group())
    prob2.root.add('SurrAero', SurrogateAero(), promotes=['*'])

    prob2.root.add('v1', IndepVarComp('alpha', val=alpha_test), promotes=['*'])
    prob2.root.add('v2', IndepVarComp('eta',val=eta_test), promotes=['*'])

    prob2.setup()

    prob2.run()

    print'CL predicted:', prob2['CL']
    print'CD predicted:', prob2['CD']

1 ответ

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

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

Другие вопросы по тегам