Esempio n. 1
0
def main(num_par_doe):
    # First, define a Problem to be able to optimize our function.
    sub = Problem(root=MultiMinGroup())

    # set up our SLSQP optimizer
    sub.driver = subdriver = ScipyOptimizer()
    subdriver.options['optimizer'] = 'SLSQP'
    subdriver.options['disp'] = False  # disable optimizer output

    # In this case, our design variable is indep.x, which happens
    # to be connected to the x parameter on our 'comp' component.
    subdriver.add_desvar("indep.x", lower=-pi, upper=pi)

    # We are minimizing comp.fx, so that's our objective.
    subdriver.add_objective("comp.fx")

    # Now, create our top level problem
    prob = Problem(root=Group())

    prob.root.add("top_indep", IndepVarComp('x', 0.0))

    # add our subproblem.  Note that 'indep.x' is actually an unknown
    # inside of the subproblem, but outside of the subproblem we're treating
    # it as a parameter.
    prob.root.add("subprob",
                  SubProblem(sub, params=['indep.x'], unknowns=['comp.fx']))

    prob.root.connect("top_indep.x", "subprob.indep.x")

    # use a CaseDriver as our top level driver so we can run multiple
    # separate optimizations concurrently.  We'll run 'num_par_doe'
    # concurrent cases.  In this case we need no more than 2 because
    # we're only running 2 total cases.
    prob.driver = CaseDriver(num_par_doe=num_par_doe)

    prob.driver.add_desvar('top_indep.x')
    prob.driver.add_response(['subprob.indep.x', 'subprob.comp.fx'])

    # these are the two cases we're going to run.  The top_indep.x values of
    # -1 and 1 will end up at the local and global minima when we run the
    # concurrent subproblem optimizers.
    prob.driver.cases = [[('top_indep.x', -1.0)], [('top_indep.x', 1.0)]]

    prob.setup(check=False)

    # run the concurrent optimizations
    prob.run()

    # collect responses for all of our input cases
    optvals = [
        dict(resp) for resp, success, msg in prob.driver.get_responses()
    ]

    # find the minimum value of subprob.comp.fx in our responses
    global_opt = sorted(optvals, key=lambda x: x['subprob.comp.fx'])[0]

    return global_opt
Esempio n. 2
0
    def test_byobj_run(self):
        subprob = Problem(root=ExampleByObjGroup())

        prob = Problem(root=Group())
        prob.root.add('subprob', SubProblem(subprob,
                                            params=['G2.C1.x'],
                                            unknowns=['G3.C4.y']))

        prob.setup(check=False)
        prob.run()

        self.assertEqual(prob['subprob.G3.C4.y'], 'fooC2C3C4')
Esempio n. 3
0
    def test_simplest_run_w_promote(self):
        subprob = Problem(root=Group())
        subprob.root.add('indep', IndepVarComp('x', 7.0), promotes=['x'])
        subprob.root.add('mycomp', ExecComp('y=x*2.0'), promotes=['x','y'])

        prob = Problem(root=Group())
        prob.root.add('subprob', SubProblem(subprob, ['x'], ['y']))

        prob.setup(check=False)
        prob.run()
        result = prob.root.unknowns['subprob.y']
        self.assertAlmostEqual(14.0, result, 3)
Esempio n. 4
0
    def test_calc_gradient(self):
        root = Group()
        root.add('indep', IndepVarComp('x', np.array([1., 1., 1., 1.])))
        root.add('comp', RosenSuzuki())

        root.connect('indep.x', 'comp.x')

        subprob = Problem(root)
        subprob.driver.add_desvar('indep.x', lower=-10, upper=99)
        subprob.driver.add_objective('comp.f')
        subprob.driver.add_constraint('comp.g', upper=0.)

        prob = Problem(root=Group())
        prob.root.add('desvars', IndepVarComp('x', np.ones(4)))
        prob.root.add('subprob', SubProblem(subprob,
                                            params=['indep.x'],
                                            unknowns=['comp.f', 'comp.g']))
        prob.root.connect('desvars.x', 'subprob.indep.x')

        prob.setup(check=False)
        prob.run()

        indep_list = ['desvars.x']
        unknown_list = ['subprob.comp.f', 'subprob.comp.g']

        # check that calc_gradient returns proper dict value when mode is 'fwd'
        J = prob.calc_gradient(indep_list, unknown_list, mode='fwd', return_format='dict')
        assert_almost_equal(J['subprob.comp.f']['desvars.x'],
                           expectedJ['subprob.comp.f']['desvars.x'])
        assert_almost_equal(J['subprob.comp.g']['desvars.x'],
                            expectedJ['subprob.comp.g']['desvars.x'])

        # check that calc_gradient returns proper array value when mode is 'fwd'
        J = prob.calc_gradient(indep_list, unknown_list, mode='fwd', return_format='array')
        assert_almost_equal(J, expectedJ_array)

        # check that calc_gradient returns proper dict value when mode is 'rev'
        J = prob.calc_gradient(indep_list, unknown_list, mode='rev', return_format='dict')
        assert_almost_equal(J['subprob.comp.f']['desvars.x'], expectedJ['subprob.comp.f']['desvars.x'])
        assert_almost_equal(J['subprob.comp.g']['desvars.x'], expectedJ['subprob.comp.g']['desvars.x'])

        # check that calc_gradient returns proper array value when mode is 'rev'
        J = prob.calc_gradient(indep_list, unknown_list, mode='rev', return_format='array')
        assert_almost_equal(J, expectedJ_array)

        # check that calc_gradient returns proper dict value when mode is 'fd'
        J = prob.calc_gradient(indep_list, unknown_list, mode='fd', return_format='dict')
        assert_almost_equal(J['subprob.comp.f']['desvars.x'], expectedJ['subprob.comp.f']['desvars.x'], decimal=5)
        assert_almost_equal(J['subprob.comp.g']['desvars.x'], expectedJ['subprob.comp.g']['desvars.x'], decimal=5)

        # check that calc_gradient returns proper array value when mode is 'fd'
        J = prob.calc_gradient(indep_list, unknown_list, mode='fd', return_format='array')
        assert_almost_equal(J, expectedJ_array, decimal=5)
Esempio n. 5
0
    def test_basic_run(self):
        subprob = Problem(root=ExampleGroup())

        prob = Problem(root=Group())
        prob.root.add('subprob', SubProblem(subprob, ['G2.C1.x'], ['G3.C4.y']))

        prob.setup(check=False)
        prob.run()

        self.assertAlmostEqual(prob['subprob.G3.C4.y'], 40.)

        stream = cStringIO()

        # get test coverage for list_connections and make sure it doesn't barf
        prob.root.subprob.list_connections(stream=stream)
Esempio n. 6
0
    def test_general_access(self):
        sprob = Problem(root=Group())
        sroot = sprob.root
        sroot.add('Indep', IndepVarComp('x', 7.0))
        sroot.add('C1', ExecComp(['y1=x1*2.0', 'y2=x2*3.0']))
        sroot.connect('Indep.x', 'C1.x1')

        prob = Problem(root=Group())
        prob.root.add('subprob', SubProblem(sprob,
                                            params=['Indep.x', 'C1.x2'],
                                            unknowns=['C1.y1', 'C1.y2']))

        prob.setup(check=False)

        prob['subprob.Indep.x'] = 99.0 # set a param that maps to an unknown in subproblem
        prob['subprob.C1.x2'] = 5.0  # set a dangling param

        prob.run()

        self.assertEqual(prob['subprob.C1.y1'], 198.0)
        self.assertEqual(prob['subprob.C1.y2'], 15.0)
Esempio n. 7
0
    def test_opt_cylinder_nested(self, which_err=None, check=False):
        prob = Problem(root=Group())
        driver = prob.driver = ScipyOptimizer()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['disp'] = False

        prob.driver.add_desvar("indep.r", lower=0.0, upper=1.e99)
        prob.driver.add_desvar("indep.h", lower=0.0, upper=1.e99)
        prob.driver.add_objective("subprob.cylinder.area")
        prob.driver.add_constraint("subprob.cylinder.volume", equals=1.5)

        # we need IndepVarComp for model params at top level because the top level
        # driver has them as design vars.
        prob.root.add("indep", IndepVarComp([('r', 1.0, {'units':'cm'}),
                                             ('h', 1.0, {'units':'cm'})]))

        subprob = ErrProb(which_err=which_err, root=CylinderGroup())
        prob.root.add('subprob', SubProblem(subprob,
                                params=['indep.r', 'indep.h'],
                                unknowns=['cylinder.area', 'cylinder.volume']))
        prob.root.connect('indep.r', 'subprob.indep.r')
        prob.root.connect('indep.h', 'subprob.indep.h')

        # we have to set check=True to test some error handling, but never
        # want to see the output, so just send it to a cStringIO
        prob.setup(check=check, out_stream=cStringIO())
        prob.run()

        self.assertAlmostEqual(prob['subprob.cylinder.volume'], 1.5,
                               places=4,
                               msg="volume should be 1.5, but got %s" %
                               prob['subprob.cylinder.volume'])

        for name, opt in cylinder_opts:
            self.assertAlmostEqual(prob[name], opt,
                                   places=4,
                                   msg="%s should be %s, but got %s" %
                                   (name, opt, prob[name]))

        prob.cleanup()
Esempio n. 8
0
    def test_opt_cylinder_nested_w_promotes(self):
        prob = Problem(root=Group())
        driver = prob.driver = ScipyOptimizer()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['disp'] = False

        prob.driver.add_desvar("indep.r", lower=0.0, upper=1.e99)
        prob.driver.add_desvar("indep.h", lower=0.0, upper=1.e99)
        prob.driver.add_objective("cylinder.area")
        prob.driver.add_constraint("cylinder.volume", equals=1.5)

        # we need IndepVarComp for model params at top level because the top level
        # driver has them as design vars.
        prob.root.add("indep", IndepVarComp([('r', 1.0, {'units':'cm'}),
                                             ('h', 1.0, {'units':'cm'})]))

        subprob = Problem(root=CylinderGroup())
        prob.root.add('subprob', SubProblem(subprob,
                                params=list(prob.driver._desvars),
                                unknowns=list(driver._cons)+list(driver._objs)),
                                promotes=['indep.r', 'indep.h',
                                          'cylinder.area', 'cylinder.volume'])

        # the names of the indep vars match the promoted names from the subproblem, so
        # they're implicitly connected.

        prob.setup(check=False)
        prob.run()

        for name, opt in cylinder_opts:
            self.assertAlmostEqual(prob[name], opt,
                                   places=4,
                                   msg="%s should be %s, but got %s" %
                                   (name, opt, prob[name]))

        self.assertAlmostEqual(prob['cylinder.volume'], 1.5,
                               places=4,
                               msg="volume should be 1.5, but got %s" %
                               prob['cylinder.volume'])
 
 # TopProblem: define a Problem to set up different optimization cases
 top = Problem(root=Group())
 
 # TopProblem: add independent variables
 top.root.add('indep1', IndepVarComp('range', 50.0))
 top.root.add('indep2', IndepVarComp('rProp', 100.0))
 top.root.add('indep3', IndepVarComp('cruiseSpeed', 50.0))
 top.root.add('indep4', IndepVarComp('batteryMass', 11.70))
 top.root.add('indep5', IndepVarComp('motorMass', 3.00))
 top.root.add('indep6', IndepVarComp('mtom', 6.500))
 # top.root.add('indep7', IndepVarComp('vehicle', 'tiltwing'))  # 1st get this working with just the tiltwing
 
 # TopProblem: add the SubProblem
 top.root.add('subprob', SubProblem(sub, params=['indep1.range', 'indep2.rProp', \
                                                 'indep3.cruiseSpeed', 'indep4.batteryMass', \
                                                 'indep5.motorMass', 'indep6.mtom'],
                                         unknowns=['OperatingCost.C_costPerFlight']))
 
 # TopProblem: connect top's independent variables to sub's params
 top.root.connect('indep1.range', 'subprob.indep1.range')
 top.root.connect('indep2.rProp', 'subprob.indep2.rProp')  # Each of SubProblem's IndepVarComp components has to be connected (maybe promoted works too) to a 
 top.root.connect('indep3.cruiseSpeed', 'subprob.indep3.cruiseSpeed')  # IndepVarComp component in the top level. 
 top.root.connect('indep4.batteryMass', 'subprob.indep4.batteryMass')  # Alternatively it might make more sense to output the design variables states as metrics.
 top.root.connect('indep5.motorMass', 'subprob.indep5.motorMass')
 top.root.connect('indep6.mtom', 'subprob.indep6.mtom')
 
 # TopProblem: set up the parameter study
 # for a parameter study, the following drivers can be used:
 # UniformDriver, FullFactorialDriver, LatinHypercubeDriver, OptimizedLatinHypercubeDriver
 # in this case, we will use FullFactorialDriver
 top.driver = FullFactorialDriver(num_levels=77)
Esempio n. 10
0
    #sub.driver.opt_settings['rhobeg'] = 1.0        # COBYLA-specific setting. Initial step size. Default: 1.0
    #sub.driver.opt_settings['catol'] = 0.1         # COBYLA-specific setting. Absolute tolerance for constraint violations. Default: 0.1

    # Add design variables, objective, and constraints to the optimization driver
    sub.driver.add_desvar('p1.x_init', lower=-50, upper=50)
    sub.driver.add_objective('Paraboloid.f_xy')

    # Instantiate a Problem 'top'
    # Instantiate a Group and add it to top
    top = Problem()
    top.root = Group()

    # Add sub to top as a SubProblem called 'Sub'
    # Include sub's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields of SubProblem
    top.root.add(
        'Sub', SubProblem(sub, params=['p1.x_init'], unknowns=[])
    )  # This is where you designate what to expose to the outside world)

    # Initialize x and y as IndepVarComps and add them to top's root group
    top.root.add('p1', IndepVarComp('x_init', 0.0))

    # Connections
    top.root.connect('p1.x_init', 'Sub.p1.x_init')

    # Add driver
    top.driver = FullFactorialDriver(num_levels=11)

    # Add design variables and objectives to the parameter study driver
    top.driver.add_desvar('p1.x_init', lower=-50, upper=50)

    # Data collection
Esempio n. 11
0
    # Instantiate a mid-level Problem 'OptimizationProfiler'
    # Instantiate a Group and add it to OptimizationProfiler
    OptimizationProfiler = Problem()
    OptimizationProfiler.root = Group()

    # Initialize x and y as IndepVarComps and add them to OptimizationProfiler's root group
    OptimizationProfiler.root.add('p1', IndepVarComp('x_0', 0.0))
    OptimizationProfiler.root.add('p2', IndepVarComp('y_0', 0.0))
    OptimizationProfiler.root.add('p3', IndepVarComp('n', 0.0))

    # Add optimizationProblem to OptimizationProfiler as a SubProblem called 'OptimizationProblem'
    # Include optimizationProblem's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields of SubProblem
    OptimizationProfiler.root.add(
        'OptimizationProblem',
        SubProblem(optimizationProblem,
                   params=['p1.x', 'p2.y'],
                   unknowns=['output1.x_f', 'output2.y_f', 'Paraboloid.f_xy'])
    )  # This is where you designate what to expose to the outside world

    # Add the 'SaveTime' and 'MeasureTime' Components to OptimizationProfiler's root Group.
    OptimizationProfiler.root.add('SaveTime', SaveTime())
    OptimizationProfiler.root.add('MeasureTime', MeasureTime())

    # Connections
    OptimizationProfiler.root.connect('p1.x_0', 'SaveTime.pass_in')
    OptimizationProfiler.root.connect('p2.y_0', 'OptimizationProblem.p2.y')
    OptimizationProfiler.root.connect('SaveTime.pass_out',
                                      'OptimizationProblem.p1.x')
    OptimizationProfiler.root.connect('OptimizationProblem.Paraboloid.f_xy',
                                      'MeasureTime.finished')
    # Add design variables, objective, and constraints to the optimization driver
    sub.driver.add_desvar('p1.x', lower=-50, upper=50)
    sub.driver.add_desvar('p2.y_i', lower=-50, upper=50)
    sub.driver.add_objective('Paraboloid.f_xy')

    # Instantiate a Problem 'top'
    # Instantiate a Group and add it to top
    top = Problem()
    top.root = Group()

    # Add sub to top as a SubProblem called 'Sub'
    # Include sub's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields of SubProblem
    top.root.add(
        'Sub',
        SubProblem(
            sub,
            params=['p2.y_i', 'p3.z'],
            unknowns=['Paraboloid.f_xy', 'p1.x', 'output1.y_f', 'output2.z'])
    )  # This is where you designate what to expose to the outside world)

    # Add PythonWrapper Component 'Sum'
    top.root.add('Sum', Sum())

    # Initialize x and z as IndepVarComps and add them to top's root group
    top.root.add('p1', IndepVarComp('y_init', 0.0))
    top.root.add('p2', IndepVarComp('z', 0.0))

    # Connections
    top.root.connect('p1.y_init', 'Sub.p2.y_i')
    top.root.connect('p2.z', 'Sub.p3.z')
    top.root.connect('Sub.output1.y_f', 'Sum.y')
    top.root.connect('Sub.output2.z', 'Sum.z')
Esempio n. 13
0
    # the constraint is violated, it does not eliminate the violation
    # ^ Jonathan comments that you often have to add constraints for the design variable ranges since the design variable bounds
    # are either not passed along to SciPy or are not enforced.

    # Instantiate a top-level Problem 'top'
    # Instantiate a Group and add it to sub
    top = Problem()
    top.root = Group()

    # Initialize y as IndepVarComp and add it to top's root group
    top.root.add('p2', IndepVarComp('y', -14.0))

    # Add Problem 'sub' to 'top' as a SubProblem
    top.root.add(
        'subprob', SubProblem(sub, params=['p2.y'], unknowns=[
            'P.f_xy'
        ]))  # This is where you designate what to expose to the outside world

    # Connect top's IndepVarComps to SubProblem's params
    top.root.connect('p2.y', 'subprob.p2.y')

    # Add driver
    top.driver = FullFactorialDriver(num_levels=20)

    # Add design variables, objective, and constraints
    top.driver.add_desvar('p2.y', lower=-50, upper=50)

    # Data collection
    recorder = SqliteRecorder('record_results')
    recorder.options['record_params'] = True
    recorder.options['record_metadata'] = True
Esempio n. 14
0
    def test_opt_over_doe_uq(self):
        np.random.seed(42)

        prob = Problem(impl=impl, root=Group())
        prob.root.deriv_options['type'] = 'fd'

        subprob = Problem(impl=impl, root=SellarDerivatives())
        subprob.root.deriv_options['type'] = 'fd'

        if MPI:
            npardoe = self.N_PROCS
        else:
            npardoe = 1

        subprob.driver = UQTestDriver(nsamples=100, num_par_doe=npardoe)
        subprob.driver.add_desvar('z', std_dev=1e-2)
        subprob.driver.add_desvar('x', std_dev=1e-2)
        subprob.driver.add_response('obj')
        subprob.driver.add_response('con1')
        subprob.driver.add_response('con2')

        #subprob.driver.recorders.append(SqliteRecorder("subsellar.db"))

        prob.root.add("indeps",
                      IndepVarComp([('x', 1.0), ('z', np.array([5.0, 2.0]))]),
                      promotes=['x', 'z'])
        prob.root.add(
            "sub",
            SubProblem(subprob,
                       params=['z', 'x'],
                       unknowns=['obj', 'con1', 'con2']))

        prob.root.connect('x', 'sub.x')
        prob.root.connect('z', 'sub.z')

        # top level driver setup
        prob.driver = ScipyOptimizer()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['tol'] = 1.0e-8
        prob.driver.options['maxiter'] = 50
        prob.driver.options['disp'] = False

        prob.driver.add_desvar('z',
                               lower=np.array([-10.0, 0.0]),
                               upper=np.array([10.0, 10.0]))
        prob.driver.add_desvar('x', lower=0.0, upper=10.0)

        prob.driver.add_objective('sub.obj')
        prob.driver.add_constraint('sub.con1', upper=0.0)
        prob.driver.add_constraint('sub.con2', upper=0.0)

        #prob.driver.recorders.append(SqliteRecorder("sellar.db"))

        prob.setup(check=False)

        prob.run()

        tol = 1.e-3
        assert_rel_error(self, prob['sub.obj'], 3.1833940, tol)
        assert_rel_error(self, prob['z'][0], 1.977639, tol)
        assert_rel_error(self, prob['z'][1], 0.0, tol)
        assert_rel_error(self, prob['x'], 0.0, tol)
Esempio n. 15
0
    # Instantiate a top-level Problem 'OptimizationProfiler'
    # Instantiate a Group and add it to OptimizationProfiler
    OptimizationProfiler = Problem()
    OptimizationProfiler.root = Group()

    # Initialize x and y as IndepVarComps and add them to OptimizationProfiler's root group
    OptimizationProfiler.root.add('p1', IndepVarComp('x_0', 0.0))
    OptimizationProfiler.root.add('p2', IndepVarComp('y_0', 0.0))

    # Add optimizationProblem to OptimizationProfiler as a SubProblem called 'OptimizationProblem'
    # Include optimizationProblem's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields SubProblem
    OptimizationProfiler.root.add(
        'OptimizationProblem',
        SubProblem(optimizationProblem,
                   params=['p1.x', 'p2.y'],
                   unknowns=['output1.x_f', 'output2.y_f', 'Paraboloid.f_xy'])
    )  # This is where you designate what to expose to the outside world

    # Add the 'SaveTime' and 'MeasureTime' Components to OptimizationProfiler's root Group.
    OptimizationProfiler.root.add('SaveTime', SaveTime())
    OptimizationProfiler.root.add('MeasureTime', MeasureTime())

    # Connections
    OptimizationProfiler.root.connect('p1.x_0', 'SaveTime.pass_in')
    OptimizationProfiler.root.connect('p2.y_0', 'OptimizationProblem.p2.y')
    OptimizationProfiler.root.connect('SaveTime.pass_out',
                                      'OptimizationProblem.p1.x')
    OptimizationProfiler.root.connect('OptimizationProblem.Paraboloid.f_xy',
                                      'MeasureTime.finished')
    # Instantiate a top-level Problem 'ParaboloidOptimization'
    # Instantiate a Group and add it to ParaboloidOptimization
    ParaboloidOptimization = Problem()
    ParaboloidOptimization.root = Group()

    # Initialize x and y as IndepVarComps and add them to ParaboloidOptimization's root group
    ParaboloidOptimization.root.add('p1', IndepVarComp('x', 0.0))
    ParaboloidOptimization.root.add('p2', IndepVarComp('y', 0.0))

    # Add paraboloidProblem to ParaboloidOptimization as a SubProblem called 'ParaboloidProblem'
    # Include paraboloidProblem's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields SubProblem
    ParaboloidOptimization.root.add(
        'ParaboloidProblem',
        SubProblem(paraboloidProblem,
                   params=['p1.x', 'p2.y'],
                   unknowns=['Paraboloid.f_xy'])
    )  # This is where you designate what to expose to the outside world

    # Connect ParaboloidOptimization's IndepVarComps to ParaboloidProblem's params
    ParaboloidOptimization.root.connect('p1.x', 'ParaboloidProblem.p1.x')
    ParaboloidOptimization.root.connect('p2.y', 'ParaboloidProblem.p2.y')

    # Add driver
    ParaboloidOptimization.driver = ScipyOptimizer()

    # Modify the optimization driver's settings
    ParaboloidOptimization.driver.options[
        'optimizer'] = 'COBYLA'  # Type of Optimizer. 'COBYLA' does not require derivatives
    ParaboloidOptimization.driver.options[
        'tol'] = 1.0e-4  # Tolerance for termination. Not sure exactly what it represents. Default: 1.0e-6
Esempio n. 17
0
    # Add design variables, objective, and constraints to the optimization driver
    sub.driver.add_desvar('p1.x_init', lower=-50, upper=50)
    sub.driver.add_objective('Paraboloid.f_xy')

    # Instantiate a Problem 'top'
    # Instantiate a Group and add it to top
    top = Problem()
    top.root = Group()

    # Add sub to top as a SubProblem called 'Sub'
    # Include sub's Problem Inputs and Problem Outputs in 'params' and 'unknowns' fields of SubProblem
    top.root.add(
        'Sub',
        SubProblem(sub, params=['p1.x_init'], unknowns=[
            'Paraboloid.f_xy'
        ]))  # This is where you designate what to expose to the outside world)

    # Initialize x and y as IndepVarComps and add them to top's root group
    top.root.add('p1', IndepVarComp('x_init', 0.0))

    # Connections
    top.root.connect('p1.x_init', 'Sub.p1.x_init')

    # Add driver
    top.driver = FullFactorialDriver(num_levels=11)

    # Add design variables and objectives to the parameter study driver
    top.driver.add_desvar('p1.x_init', lower=-50, upper=50)
    top.driver.add_objective('Sub.Paraboloid.f_xy')
Esempio n. 18
0
    top.root.add('indep1', IndepVarComp('range', 50.0))
    top.root.add('indep2', IndepVarComp('rProp', 30.0))
    top.root.add('indep3', IndepVarComp('cruiseSpeed', 50.0))
    top.root.add('indep4', IndepVarComp('batteryMass', 11.70))
    top.root.add('indep5', IndepVarComp('motorMass', 3.00))
    top.root.add('indep6', IndepVarComp('mtom', 6.500))
    # top.root.add('indep7', IndepVarComp('vehicle', 'tiltwing'))  # 1st get this working with just the tiltwing

    # TopProblem: add the SubProblem
    top.root.add('subprob', SubProblem(sub, params=['indep1.range', 'indep2.rProp', \
                                                    'indep3.cruiseSpeed', 'indep4.batteryMass', \
                                                    'indep5.motorMass', 'indep6.mtom'],
                                            unknowns=['OperatingCost.C_costPerFlight', \
                                                    'ConfigWeight.mass_rotor', \
                                                    'ConfigWeight.mass_tailRotor', \
                                                    'ConfigWeight.mass_wire', \
                                                    'ConfigWeight.mass_fuselage', \
                                                    'ConfigWeight.mass_m', \
                                                    'HoverPower.hoverPower_PMax', \
                                                    'HoverPower.hoverPower_PMaxBattery', \
                                                    'CruisePower.PCruise', \
                                                    'CruisePower.PBattery']))

    # TopProblem: connect top's independent variables to sub's params
    top.root.connect('indep1.range', 'subprob.indep1.range')
    top.root.connect(
        'indep2.rProp', 'subprob.indep2.rProp'
    )  # Each of SubProblem's IndepVarComp components has to be connected (maybe promoted works too) to a
    top.root.connect('indep3.cruiseSpeed', 'subprob.indep3.cruiseSpeed'
                     )  # IndepVarComp component in the top level.
    top.root.connect(
Esempio n. 19
0
def with_problem(mdao_config,
                 original_dir,
                 override_driver=None,
                 additional_recorders=(),
                 is_subproblem=False,
                 append_csv=False,
                 profile=False):
    testbenchexecutor.progress_service.update_progress("Configuring PET...",
                                                       -1, -1)
    # TODO: can we support more than one driver
    if len(mdao_config['drivers']) == 0:
        driver = None
    else:
        driver = next(iter(mdao_config['drivers'].values()))

    top = Problem(impl=impl)
    root = top.root = Group()
    recorder = None
    driver_params = {'original_dir': original_dir}
    if driver is not None:
        eval(
            compile(driver['details'].get('Code', ''), '<driver Code>',
                    'exec'), globals(), driver_params)

    subProblemInputMeta = {}
    subProblemOutputMeta = {}

    if driver is not None:
        if driver['type'] == 'optimizer':
            if driver.get('details',
                          {}).get('OptimizationFunction') == 'Custom':
                class_path = driver['details']['OptimizationClass'].split('.')
                mod = __import__('.'.join(class_path[:-1]),
                                 fromlist=[class_path[-1]])
                top.driver = getattr(mod, class_path[-1])()
            else:
                top.driver = ScipyOptimizer()
                top.driver.options['optimizer'] = str(
                    driver.get('details', {}).get('OptimizationFunction',
                                                  'SLSQP'))

            for key, value in six.iteritems(driver_params):
                try:
                    top.driver.options[key] = value
                except KeyError:
                    pass  # Ignore options that aren't valid for driver
        elif driver['type'] == 'parameterStudy':
            drivers = {
                "Uniform": UniformDriver,
                "Full Factorial": FullFactorialDriver,
                "Latin Hypercube": LatinHypercubeDriver,
                "Opt Latin Hypercube": OptimizedLatinHypercubeDriver,
                "CSV File": CsvDriver,
            }
            driver_type = drivers.get(driver['details']['DOEType'])
            if driver_type is None:
                raise Exception('DOEType "{}" is unsupported'.format(
                    driver['details']['DOEType']))
            if override_driver is None:
                top.driver = driver_type(**driver_params)
            else:
                top.driver = override_driver
            seed = getattr(top.driver, 'seed', None)
            if seed is not None:
                print('Using random seed {}'.format(seed))
        elif driver['type'] == 'PCCDriver':
            import PCC.pcc_driver
            driver_params.update(driver['details'])
            driver_params[
                "_run_mdao_subproblem_output_meta"] = subProblemOutputMeta
            top.driver = PCC.pcc_driver.PCCdriver(**driver_params)
        else:
            raise ValueError('Unsupported driver type %s' % driver['type'])

        driver_vars = []
        for var_name, var in six.iteritems(driver['designVariables']):
            if var.get('type', 'double') == 'double':
                default = 0.0
                range_min = var.get('RangeMin')
                range_max = var.get('RangeMax')
                if range_min is not None and range_max is not None:
                    default = range_min + (range_max - range_min) / 2
                driver_vars.append((var_name, default, {}))
            elif var['type'] == 'enum':
                driver_vars.append((var_name, var['items'][0], {
                    "pass_by_obj": True
                }))
            elif var['type'] == 'int':
                driver_vars.append((var_name, 0, {}))
            else:
                raise ValueError(
                    'Unimplemented designVariable type "{}"'.format(
                        var['type']))
            units = var.get('units')
            if units:
                driver_vars[-1][2]['units'] = str(var['units'])

        root.add(get_desvar_path('').split('.')[0], IndepVarComp(driver_vars))
        for var_name, var in six.iteritems(driver['designVariables']):
            if var.get('type', 'double') == 'double':
                top.driver.add_desvar(get_desvar_path(var_name),
                                      lower=var.get('RangeMin'),
                                      upper=var.get('RangeMax'))
            elif var['type'] == 'enum':
                driver_vars.append((var_name, var['items'][0], {
                    "pass_by_obj": True
                }))
                formatted_name = get_desvar_path(var_name)
                top.driver.add_desvar(formatted_name)
                top.driver._desvars[formatted_name]['type'] = var['type']
                top.driver._desvars[formatted_name]['items'] = var['items']
            elif var['type'] == 'int':
                driver_vars.append((var_name, 0.0))
                formatted_name = get_desvar_path(var_name)
                top.driver.add_desvar(formatted_name,
                                      lower=var.get('RangeMin'),
                                      upper=var.get('RangeMax'))
                top.driver._desvars[formatted_name]['type'] = var['type']
            else:
                raise ValueError(
                    'Unimplemented designVariable type "{}"'.format(
                        var['type']))

    for subProblemName, subProblemConfig in six.iteritems(
            mdao_config.get('subProblems', {})):
        subProblemDir = os.path.join(original_dir, subProblemName)

        with with_problem(subProblemConfig, subProblemDir,
                          is_subproblem=True) as (subProblem, inputMeta,
                                                  outputMeta):
            root.add(subProblemName, subProblem)
            subProblemInputMeta[subProblemName] = inputMeta
            subProblemOutputMeta[subProblemName] = outputMeta

    if is_subproblem:
        subProblemInputs = []
        inputMeta = {}
        for name, problemInput in six.iteritems(mdao_config['problemInputs']):
            if problemInput.get("innerSource"):
                if problemInput["innerSource"][0] in mdao_config['drivers']:
                    path = get_desvar_path(problemInput["innerSource"][1])
                else:
                    path = '{}.{}'.format(problemInput["innerSource"][0],
                                          problemInput["innerSource"][1])

                subProblemInputs.append(path)
                inputMeta[name] = path
            else:
                # TODO: How important is it to figure out the correct type here?
                #   We might be able to infer the type from a component that connects to
                #   this ProblemInput, but might have to refer to something outside the
                #   subproblem
                (initial_value,
                 pass_by_obj) = get_problem_input_value(problemInput)

                root.add(
                    name,
                    IndepVarComp(name, initial_value, pass_by_obj=pass_by_obj))
                path = "{0}.{0}".format(name)
                subProblemInputs.append(path)
                inputMeta[name] = path

        # TODO: Handle direct connection between ProblemInput and ProblemOutput (single-element Source)
        # TODO: Pass-through ExecComps to allow direct ProblemInput->ProblemOutput connections to behave
        subProblemOutputs = []
        outputMeta = {}
        for name, source in six.iteritems(mdao_config['problemOutputs']):
            if len(source) == 1:
                if source[0] in mdao_config[
                        'problemInputs'] and 'innerSource' in mdao_config[
                            'problemInputs'][source[0]]:
                    # Assume inner source is a design variable
                    desvar = driver['designVariables']
                    passByObj = False
                    if desvar.get('type', 'double') == 'double':
                        initialVal = 0.0
                    elif desvar['type'] == 'enum':
                        initialVal = ''
                        # TODO or maybe initialVal = 0.0
                    elif desvar['type'] == 'int':
                        initialVal = 0
                    else:
                        raise ValueError(
                            'Unimplemented designVariable type "{}"'.format(
                                desvar['type']))
                else:
                    if source[0] in mdao_config['problemInputs']:
                        (initialVal, passByObj) = get_problem_input_value(
                            mdao_config['problemInputs'][source[0]])
                    else:
                        raise ValueError(
                            'Missing ProblemOutput source: {}'.format(
                                source[0]))
                comp_name = "pass_through_{}".format(name)
                comp = PassThroughComponent()
                comp.add_var(name, initialVal)
                root.add(comp_name, comp)
                inputPath = "{}.{}".format(comp_name, name)
                path = "{}.{}_out".format(comp_name, name)
                root.connect(inputMeta[source[0]], inputPath)
            else:
                if source[0] in mdao_config['drivers']:
                    # TODO: If it's legal for this desvar to also point to a ProblemInput,
                    # we need to create a PassThroughComponent just like above
                    this_driver = mdao_config['drivers'][source[0]]

                    if source[1] in this_driver.get('designVariables', {}):
                        path = get_desvar_path(source[1])
                    else:  # Source is an objective, ivar, or constraint; need to get the actual source
                        if source[1] in this_driver.get('objectives', {}):
                            driver_output_type = 'objectives'
                        elif source[1] in this_driver.get('constraints', {}):
                            driver_output_type = 'constraints'
                        elif source[1] in this_driver.get(
                                'intermediateVariables', {}):
                            driver_output_type = 'intermediateVariables'
                        else:
                            raise ValueError(
                                'Driver output "{}"" not found'.format(
                                    source[1]))
                        real_source = this_driver[driver_output_type][
                            source[1]]['source']
                        if real_source[0] in mdao_config['subProblems']:
                            unknown_name = subProblemOutputMeta[
                                real_source[0]][real_source[1]]
                            path = '{}.{}'.format(real_source[0], unknown_name)
                        else:
                            path = '{}.{}'.format(real_source[0],
                                                  real_source[1])
                elif source[0] in mdao_config['subProblems']:
                    unknown_name = subProblemOutputMeta[source[0]][source[1]]
                    path = '{}.{}'.format(source[0], unknown_name)
                else:
                    path = '{}.{}'.format(source[0], source[1])

            subProblemOutputs.append(path)
            outputMeta[name] = path

    def get_sorted_components():
        """Apply Tarjan's algorithm to the Components."""
        visited = {}
        tbs_sorted = []

        def get_ordinal(name):
            ordinal = visited.get(name, -1)
            if ordinal is None:
                raise ValueError('Loop involving component "{}"'.format(name))
            if ordinal != -1:
                return ordinal
            component = mdao_config['components'][name]
            visited[name] = None
            ordinal = 0
            for source in (
                    param.get('source')
                    for param in component.get('parameters', {}).values()):
                if not source:
                    continue
                if source[0] in mdao_config['drivers']:
                    continue
                if source[0] in mdao_config.get('problemInputs', {}):
                    continue
                if source[0] in mdao_config.get('subProblems', {}):
                    continue
                ordinal = max(ordinal, get_ordinal(source[0]) + 1)
            visited[name] = ordinal
            tbs_sorted.append(name)
            return ordinal

        for component_name in mdao_config['components']:
            get_ordinal(component_name)
        return tbs_sorted

    tbs_sorted = get_sorted_components()

    # TestBenchComponents look at params they're connected to, so create them last
    def is_testbenchcomponent(component_name):
        return mdao_config['components'][component_name].get(
            'type', 'TestBenchComponent') == 'TestBenchComponent'

    tbs_sorted = sorted(tbs_sorted, key=is_testbenchcomponent)
    for component_name in tbs_sorted:
        component = mdao_config['components'][component_name]
        mdao_component = instantiate_component(component, component_name,
                                               mdao_config, root,
                                               subProblemOutputMeta)
        root.add(component_name, mdao_component)

    for component_name, component in six.iteritems(mdao_config['components']):
        for parameter_name, parameter in six.iteritems(
                component.get('parameters', {})):
            if parameter.get('source'):
                source = parameter['source']
                if len(source) == 1 and is_subproblem:
                    # Points to a top-level ProblemInput; look up what design variable it points to and reference that IVC
                    problemInputName = source[0]
                    if problemInputName in inputMeta:
                        root.connect(
                            inputMeta[problemInputName], '{}.{}'.format(
                                component_name,
                                _get_param_name(parameter_name,
                                                component.get('type'))))
                    else:
                        # TODO: Warn or fail if name isn't found?
                        print("WARNING: Missing problem input reference")
                else:
                    if source[0] in mdao_config['drivers']:
                        # print('driver{}.{}'.format(source[1], source[1]))
                        root.connect(
                            get_desvar_path(source[1]), '{}.{}'.format(
                                component_name,
                                _get_param_name(parameter_name,
                                                component.get('type'))))
                    elif source[0] in mdao_config.get('subProblems', {}):
                        # Map subproblem output name to actual unknown name
                        unknown_name = subProblemOutputMeta[source[0]][
                            source[1]]
                        root.connect(
                            '{}.{}'.format(source[0], unknown_name),
                            '{}.{}'.format(
                                component_name,
                                _get_param_name(parameter_name,
                                                component.get('type'))))
                    else:
                        root.connect(
                            '{}.{}'.format(source[0], source[1]),
                            '{}.{}'.format(
                                component_name,
                                _get_param_name(parameter_name,
                                                component.get('type'))))
            else:
                pass  # TODO warn or fail?

    for subProblemName, subProblem in six.iteritems(
            mdao_config.get('subProblems', {})):
        for problemInputName, problemInput in six.iteritems(
                subProblem.get('problemInputs', {})):
            if problemInput.get('outerSource'):
                source = problemInput['outerSource']
                subProblemInputPath = subProblemInputMeta[subProblemName][
                    problemInputName]

                if len(source) == 1 and is_subproblem:
                    problemInputName = source[0]
                    if problemInputName in inputMeta:
                        root.connect(
                            inputMeta[problemInputName],
                            '{}.{}'.format(subProblemName,
                                           subProblemInputPath))
                    else:
                        # TODO: Warn or fail if name isn't found?
                        print("WARNING: Missing problem input reference")
                else:
                    if source[0] in mdao_config['drivers']:
                        # print('driver{}.{}'.format(source[1], source[1]))
                        root.connect(
                            get_desvar_path(source[1]),
                            '{}.{}'.format(subProblemName,
                                           subProblemInputPath))
                    elif source[0] in mdao_config['subProblems']:
                        # Map subproblem output name to actual unknown name
                        unknown_name = subProblemOutputMeta[source[0]][
                            source[1]]
                        root.connect(
                            '{}.{}'.format(source[0], unknown_name),
                            '{}.{}'.format(subProblemName,
                                           subProblemInputPath))
                    else:
                        root.connect(
                            '{}.{}'.format(source[0], source[1]),
                            '{}.{}'.format(subProblemName,
                                           subProblemInputPath))
            else:
                print("Failed to connect")
                pass  # TODO warn or fail?

    # TODO: Make sure objectives/constraints coming from subproblems and
    # from ProblemInputs/ProblemOutputs are handled correctly
    if driver is not None and driver['type'] == 'optimizer':
        for objective in six.itervalues(driver['objectives']):
            if objective["source"][0] in mdao_config.get('subProblems', {}):
                unknown_name = subProblemOutputMeta[objective["source"][0]][
                    objective["source"][1]]
                top.driver.add_objective("{}.{}".format(
                    objective["source"][0], unknown_name))
            else:
                top.driver.add_objective(str('.'.join(objective['source'])))

        for constraint in six.itervalues(driver['constraints']):
            if constraint['source'][0] in mdao_config['drivers']:
                # References the driver; need to get the path to the design var
                constraintPath = get_desvar_path(constraint['source'][1])
            elif constraint['source'][0] in mdao_config.get('subProblems', {}):
                unknown_name = subProblemOutputMeta[objective.source[0]][
                    objective.source[1]]
                constraintPath = "{}.{}".format(objective.source[0],
                                                unknown_name)
            else:
                constraintPath = str('.'.join(constraint['source']))

            if 'RangeMin' in constraint and 'RangeMax' in constraint:
                top.driver.add_constraint(constraintPath,
                                          lower=constraint['RangeMin'],
                                          upper=constraint['RangeMax'])
            elif 'RangeMin' in constraint and 'RangeMax' not in constraint:
                top.driver.add_constraint(constraintPath,
                                          lower=constraint['RangeMin'])
            elif 'RangeMin' not in constraint and 'RangeMax' in constraint:
                top.driver.add_constraint(constraintPath,
                                          upper=constraint['RangeMax'])
            else:
                pass  # TODO: No min or max provided with constraint; warn or fail here?

    def add_recorders():
        recorders = []
        design_var_map = {
            get_desvar_path(designVariable): designVariable
            for designVariable in driver['designVariables']
        }
        objective_map = {
            '{}.{}'.format(objective['source'][0], objective['source'][1]):
            objective_name
            for objective_name, objective in six.iteritems(
                driver['objectives'])
        }
        intermediate_var_map = {
            '{}.{}'.format(intermediate_var['source'][0],
                           intermediate_var['source'][1]):
            intermediate_var_name
            for intermediate_var_name, intermediate_var in six.iteritems(
                driver.get('intermediateVariables', {}))
        }
        constants_map = {}
        for name, constant in (
                c for c in six.iteritems(mdao_config['components'])
                if c[1].get('type', 'TestBenchComponent') == 'IndepVarComp'):
            constants_map.update({
                '{}.{}'.format(name, unknown): unknown
                for unknown in constant['unknowns']
            })

        constraints_map = {
            '{}.{}'.format(constraint['source'][0], constraint['source'][1]):
            constraint_name
            for constraint_name, constraint in six.iteritems(
                driver.get('constraints', {}))
            if constraint['source'][0] not in mdao_config['drivers']
        }  # All constraints that don't point back to design variables

        unknowns_map = defaultdict(list)

        def add_to_unknowns(map):
            for key, val in six.iteritems(map):
                unknowns_map[key].append(val)

        add_to_unknowns(design_var_map)
        add_to_unknowns(objective_map)
        add_to_unknowns(intermediate_var_map)
        add_to_unknowns(constants_map)
        add_to_unknowns(constraints_map)

        new_unknowns_map = defaultdict(list)
        # Locate/fix any unknowns that point to subproblem outputs
        for unknown_path, unknown_names in six.iteritems(unknowns_map):
            for unknown_name in unknown_names:
                split_path = unknown_path.split('.')
                if split_path[0] in subProblemOutputMeta:
                    split_path[1] = subProblemOutputMeta[split_path[0]][
                        split_path[1]]
                    new_path = '.'.join(split_path)
                    new_unknowns_map[new_path].append(unknown_name)
                else:
                    new_unknowns_map[unknown_path].append(unknown_name)

        unknowns_map = new_unknowns_map

        for recorder in mdao_config.get('recorders', [{
                'type': 'DriverCsvRecorder',
                'filename': 'output.csv'
        }]):
            if recorder['type'] == 'DriverCsvRecorder':
                mode = 'w'
                exists = os.path.isfile(recorder['filename'])
                if RestartRecorder.is_restartable(original_dir) or append_csv:
                    mode = 'a'
                if six.PY2:
                    mode += 'b'
                    open_kwargs = {}
                else:
                    open_kwargs = {'newline': ''}
                recorder = MappingCsvRecorder({},
                                              unknowns_map,
                                              io.open(recorder['filename'],
                                                      mode, **open_kwargs),
                                              include_id=recorder.get(
                                                  'include_id', False))
                if (append_csv and exists) or mode == 'ab':
                    recorder._wrote_header = True
            elif recorder['type'] == 'AllCsvRecorder':
                mode = 'w'
                if six.PY2:
                    mode += 'b'
                    open_kwargs = {}
                else:
                    open_kwargs = {'newline': ''}
                recorder = CsvRecorder(
                    out=io.open(recorder['filename'], mode, **open_kwargs))
            elif recorder['type'] == 'CouchDBRecorder':
                recorder = CouchDBRecorder(
                    recorder.get('url', 'http://localhost:5984/'),
                    recorder['run_id'])
                recorder.options['record_params'] = True
                recorder.options['record_unknowns'] = True
                recorder.options['record_resids'] = False
                recorder.options['includes'] = list(unknowns_map.keys())
            else:
                mod_name = '.'.join(recorder['type'].split('.')[:-1])
                class_name = recorder['type'].split('.')[-1]
                recorder = getattr(importlib.import_module(mod_name),
                                   class_name)()

            top.driver.add_recorder(recorder)
        return recorders

    if is_subproblem:
        recorders = []

        # print("SubProblemInputs:", subProblemInputs)
        # print("SubProblemOutputs:", subProblemOutputs)

        # print("InputMeta:", inputMeta)
        # print("OutputMeta:", outputMeta)

        top.setup()

        subProblem = SubProblem(top,
                                params=subProblemInputs,
                                unknowns=subProblemOutputs)

        yield (subProblem, inputMeta, outputMeta)
    else:
        if driver:
            recorders = add_recorders()
        else:
            recorders = []
        for recorder in additional_recorders:
            recorders.append(recorder)
            top.driver.add_recorder(recorder)

        if profile:
            openmdao_profile.setup(top)
            openmdao_profile.start()

        try:
            top.setup()
            # from openmdao.devtools.debug import dump_meta
            # dump_meta(top.root)

            # for subproblemName in six.iterkeys(mdao_config['subProblems']):
            #     subProblem = top.root.find_subsystem(subproblemName)
            #     subProblem._problem.root.dump(verbose=True)

            # top.root.dump(verbose=True)
            yield top
        finally:
            for recorder in recorders:
                recorder.close()