In OpenMDAO, within an optimisation driver, is there any way to repeat/iterate a part of the model (a group) over a range of inputs?
I'm developing an optimisation framework built on OpenMDAO. So far, I have been running the optimisation for one specific load case, and now I would like to extend it to optimising for an objective that is calculated as an average over a number of load cases.
For each set of design variables, I would like to run the model inside a for loop (as in for load_case in load_cases
), record the result of each iteration, and then average them out to get the value of the objective for the driver. Is something like this possible?
Your suggested solution is fine. You have the right idea. I would just suggest that the two duplicate cost classes are not needed.
import openmdao.api as om
class Cost(om.ExplicitComponent):
''' normally defined in a separate script for convenience '''
def setup(self):
self.add_input('x', val=0)
self.add_input('y', val=0)
self.add_output('cost', val=0, units='USD')
def setup_partials(self):
self.declare_partials('*', '*', method='fd')
def compute(self, inputs, outputs):
cost_steel = inputs['x']
cost_ballast = inputs['y']
cost = cost_steel + cost_ballast
outputs['cost'] = cost
class MDA(om.Group):
class ObjCmp(om.ExplicitComponent):
def setup(self):
self.add_input('cost_1', val=0, units='USD')
self.add_input('cost_2', val=0, units='USD')
self.add_output('obj', val=0.0, units='USD')
def setup_partials(self):
self.declare_partials('*', '*', method='fd')
def compute(self, inputs, outputs):
outputs['obj'] = inputs['cost_1'] + inputs['cost_2']
def setup(self):
group_ls = self.add_subsystem('ls1', om.Group(), promotes_inputs=['x','y'],
promotes_outputs=['cost_1'])
group_ls.add_subsystem('Cost1', Cost(), promotes_inputs=['x','y'],
promotes_outputs=[('cost', 'cost_1')])
group_ls.add_subsystem('Cost2', Cost(), promotes_inputs=['x','y'],
promotes_outputs=[('cost', 'cost_2')])
self.add_subsystem('obj_cmp', self.ObjCmp(), promotes_inputs=['cost_1','cost_2'],
promotes_outputs=['obj'])
# build the model
prob = om.Problem(model=MDA())
model = prob.model
model.add_design_var('x', lower=0.1, upper=1)
model.add_design_var('y', lower=0.1, upper=1)
model.add_objective('obj')
# setup the optimization
prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.setup()
# run the optimization
prob.set_val('x', .5)
prob.set_val('y', .5)
prob.run_driver()
# minimum value
print(prob.get_val('obj'))
# location of the minimum
print(prob.get_val('x'))
print(prob.get_val('y'))