В продолжение этого вопрос я добавил фиктивный код, с которым у меня проблемы с доступом к деривативам. Я также добавил переменную comp. Это просто флаг для преобразования проблемы с явным компонентом или группой, содержащей явный компонент.
from openmdao.api import Problem, ScipyOptimizeDriver, ExecComp, IndepVarComp, SqliteRecorder, CaseReader
from openmdao.api import Group
from openmdao.api import ExplicitComponent
comp=True
class Exp(ExplicitComponent):
def setup(self):
self.add_input('des1',val=1)
self.add_input('des2',val=1)
self.add_output('out',val=1)
self.add_output('con',val=1)
self.declare_partials('*', '*',method='fd',step=0.001)
def compute(self, inputs, outputs):
outputs['out']=inputs['des1']**2+inputs['des2']
outputs['con']=inputs['des1']
class AERO(Group):
def setup(self):
self.add_subsystem('Exp',Exp(),promotes=['*'])
infodict = {'desvar':{'des1':{"fdstep": 0.1,"init": 1.0,"max": 1.3,"min": 0.8},
'des2':{"fdstep": 0.1,"init": 2.0,"max": 1.3,"min": 0.8}}}
prob = Problem()
probname = prob.model = Group()
recordername='recorder1.sql'
GLOBAL_DESIGN_VAR = IndepVarComp()
probname.add_subsystem('GLOBAL_DESIGN_VAR', GLOBAL_DESIGN_VAR,promotes=['*'])
if comp:
probname.add_subsystem('Exp', Exp(),promotes=['*'])
else:
probname.add_subsystem('AERO', AERO(),promotes=['*'])
for key,val in infodict['desvar'].items():
GLOBAL_DESIGN_VAR.add_output(key, val['init'])
probname.add_design_var(key,lower=val['min'], upper=val['max'])
probname.add_objective('out')
probname.add_constraint('con',upper=0.1)
prob.driver=ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['disp'] = True
prob.driver.options['tol'] = 1e-9
recorder = SqliteRecorder(recordername)
prob.driver.add_recorder(recorder)
#prob.driver.recording_options['includes'] = []
#prob.driver.recording_options['record_inputs'] = True
# prob.driver.recording_options['record_outputs'] = True
#prob.driver.recording_options['record_objectives'] = True
#prob.driver.recording_options['record_constraints'] = True
#prob.driver.recording_options['record_desvars'] = True
prob.driver.recording_options['record_derivatives'] = True
prob.setup(check=True)
prob.run_driver()
prob.cleanup()
cr = CaseReader(recordername)
# driver_cases = cr.list_cases('driver')
# Get derivatives associated with the last iteration.
case = cr.get_case(-1)
print(case)
# check that derivatives have been recorded.
print(case.jacobian.keys())
Я немного подчистил ваш скрипт, но, если не считать плохого начального состояния des2
(2.0 вышло за заданные вами пределы), оптимизация прошла нормально. С плохой начальной догадкой он попал в maxiter и дал NAN
. В любом случае производные были записаны.
from openmdao.api import Problem, ScipyOptimizeDriver, ExecComp, IndepVarComp, SqliteRecorder, CaseReader
from openmdao.api import Group
from openmdao.api import ExplicitComponent
class Exp(ExplicitComponent):
def setup(self):
self.add_input('des1',val=1)
self.add_input('des2',val=1)
self.add_output('out',val=1)
self.add_output('con',val=1)
self.declare_partials('*', '*',method='fd',step=0.001)
def compute(self, inputs, outputs):
outputs['out']=inputs['des1']**2+inputs['des2']
outputs['con']=inputs['des1']
prob = Problem()
dvs = IndepVarComp()
prob.model.add_subsystem('dvs', dvs, promotes=['*'])
prob.model.add_subsystem('Exp', Exp(),promotes=['*'])
dvs.add_output('des1', 1.0)
prob.model.add_design_var('des1',lower=0.8, upper=1.3)
# dvs.add_output('des2', 2.0) # BAD INITIAL GUESS!!!!!
dvs.add_output('des2', 1.0)
prob.model.add_design_var('des2',lower=0.8, upper=1.3)
prob.model.add_objective('out')
prob.model.add_constraint('con',upper=0.1)
prob.driver=ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['disp'] = True
prob.driver.options['tol'] = 1e-9
RECORDER_NAME = 'recorder1.sql'
recorder = SqliteRecorder(RECORDER_NAME)
prob.driver.add_recorder(recorder)
#prob.driver.recording_options['includes'] = []
#prob.driver.recording_options['record_inputs'] = True
# prob.driver.recording_options['record_outputs'] = True
#prob.driver.recording_options['record_objectives'] = True
#prob.driver.recording_options['record_constraints'] = True
#prob.driver.recording_options['record_desvars'] = True
prob.driver.recording_options['record_derivatives'] = True
prob.setup(check=True)
prob.run_driver()
prob.cleanup()
cr = CaseReader(RECORDER_NAME)
cases = cr.get_cases()
for c in cases:
print(c.outputs['des1'], c.outputs['des2'])
if c.jacobian is not None:
print(c.jacobian)
print()
При запуске это дает:
Optimization terminated successfully. (Exit mode 0)
Current function value: 1.4400000000000002
Iterations: 7
Function evaluations: 3
Gradient evaluations: 3
Optimization Complete
-----------------------------------
[1.] [1.]
[1.] [1.]
[0.8] [0.8]
{('out', 'des1'): array([[2.001]]), ('out', 'des2'): array([[1.]]), ('con', 'des1'): array([[1.]]), ('con', 'des2'): array([[-0.]])}
[0.8] [0.8]
{('out', 'des1'): array([[1.601]]), ('out', 'des2'): array([[1.]]), ('con', 'des1'): array([[1.]]), ('con', 'des2'): array([[-0.]])}
Обратите внимание, что не с каждым случаем связаны производные. Шаги линейного поиска выполняются без пересчета производных, поэтому ничего не записывается. В вашем исходном тестовом сценарии последний случай не имел производных, но некоторые из предыдущих случаев имели (хотя все они будут заполнены NAN
).
код в вопросе был со случайными вычислениями, поэтому я не обратил внимания на то, что начальное значение вышло за пределы. но я думаю, что всегда смотрел на первую или последнюю итерацию, где не было градиента из-за поиска строки, я думаю, спасибо ....