Ejemplo n.º 1
0
    def test_allow_different_variables(self):
        p1 = om.Problem()
        ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=0.0)
        ivc.add_output('b', val=1.0)
        ivc.add_output('c', val=2.0)
        ivc.add_output('x', val=3.0)
        p1.add_recorder(om.SqliteRecorder('p1.db'))
        p1.setup()

        p2 = om.Problem()
        ivc = p2.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('x', val=3.0)
        ivc.add_output('y', val=4.0)
        ivc.add_output('z', val=5.0)
        p2.add_recorder(om.SqliteRecorder('p2.db'))
        p2.setup()

        p1.run_model()
        p2.run_model()

        p1.record('final')
        p1.cleanup()

        p2.record('final')
        p2.cleanup()

        c1 = om.CaseReader('p1.db').get_case('final')
        c2 = om.CaseReader('p2.db').get_case('final')

        assert_cases_equal(c1, c2, require_same_vars=False)
Ejemplo n.º 2
0
    def test_regression_bug_fix_issue_2062_sql_meta_file_running_parallel(self):

        from openmdao.test_suite.components.paraboloid import Paraboloid

        prob = om.Problem()

        prob.model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
        prob.model.add_design_var('x', lower=0.0, upper=1.0)
        prob.model.add_design_var('y', lower=0.0, upper=1.0)
        prob.model.add_objective('f_xy')

        prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
        prob.driver.options['run_parallel'] = True
        prob.driver.options['procs_per_model'] = 1

        prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))

        prob.setup()
        prob.run_driver()
        prob.cleanup()

        # Run this again. Because of the bug fix for issue 2062, this code should NOT
        #   throw an exception
        prob = om.Problem()

        prob.model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
        prob.model.add_design_var('x', lower=0.0, upper=1.0)
        prob.model.add_design_var('y', lower=0.0, upper=1.0)
        prob.model.add_objective('f_xy')

        prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
        prob.driver.options['run_parallel'] = True
        prob.driver.options['procs_per_model'] = 1

        prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))

        prob.setup()

        if prob.comm.rank == 0:
            expected_warnings = [
                                 (UserWarning,
                                  'The existing case recorder metadata file, cases.sql_meta, '
                                  'is being overwritten.'),
                                 (UserWarning,
                                  'The existing case recorder file, cases.sql_0, is being '
                                  'overwritten.'),
                                 ]
        else:
            expected_warnings = [
                                (UserWarning,
                                  'The existing case recorder file, cases.sql_1, is being '
                                  'overwritten.'),
                                 ]
        with assert_warnings(expected_warnings):
            prob.run_driver()

        prob.cleanup()
Ejemplo n.º 3
0
    def test_sql_meta_file_exists(self):
        # Check that an existing sql_meta file will be deleted/overwritten
        # if it already exists before a run. (see Issue #2062)
        prob = om.Problem()

        prob.model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
        prob.model.add_design_var('x', lower=0.0, upper=1.0)
        prob.model.add_design_var('y', lower=0.0, upper=1.0)
        prob.model.add_objective('f_xy')

        prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
        prob.driver.options['run_parallel'] = True
        prob.driver.options['procs_per_model'] = 1

        prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))

        prob.setup()
        prob.run_driver()
        prob.cleanup()

        # Run this again. It should NOT throw an exception.
        prob = om.Problem()

        prob.model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
        prob.model.add_design_var('x', lower=0.0, upper=1.0)
        prob.model.add_design_var('y', lower=0.0, upper=1.0)
        prob.model.add_objective('f_xy')

        prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
        prob.driver.options['run_parallel'] = True
        prob.driver.options['procs_per_model'] = 1

        prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))

        prob.setup()

        if prob.comm.rank == 0:
            expected_warnings = [
                (UserWarning,
                'The existing case recorder metadata file, cases.sql_meta, '
                'is being overwritten.'),
                (UserWarning,
                'The existing case recorder file, cases.sql_0, is being '
                'overwritten.'),
            ]
        else:
            expected_warnings = [
                (UserWarning,
                    'The existing case recorder file, cases.sql_1, is being '
                    'overwritten.'),
            ]
        with assert_warnings(expected_warnings):
            prob.run_driver()

        prob.cleanup()
Ejemplo n.º 4
0
def driver_setup(prob):
    """Change settings of the driver

    Here the type of the driver has to be selected, wether it will be an
    optimisation driver or a DoE driver. In both cases there are multiple
    options to choose from to tune the driver.
    Two recorders are then attached to the driver for results and N2 plotting.

    Args:
        prob (om.Problem object) : Instance of the Problem class that is used
        to define the current routine.

    """

    if Rt.type == 'Optim':
        # TBD : Genetic algorithm
        # if len(Rt.objective) > 1 and False:
        #     log.info("""More than 1 objective function, the driver will
        #              automatically be set to NSGA2""")
        #     prob.driver = om.pyOptSparseDriver() # multifunc driver : NSGA2
        #     prob.driver.options['optimizer'] = 'NSGA2'
        #     prob.driver.opt_settings['PopSize'] = 7
        #     prob.driver.opt_settings['maxGen'] = Rt.max_iter
        # else:
        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = Rt.driver
        prob.driver.options['maxiter'] = Rt.max_iter
        prob.driver.options['tol'] = Rt.tol
        prob.driver.options['disp'] = True
    elif Rt.type == 'DoE':
        if Rt.doedriver == 'Uniform':
            driver_type = om.UniformGenerator(num_samples=Rt.samplesnb)
        elif Rt.doedriver == 'LatinHypercube':
            driver_type = om.LatinHypercubeGenerator(samples=Rt.samplesnb)
        elif Rt.doedriver == 'FullFactorial':
            driver_type = om.FullFactorialGenerator(levels=Rt.samplesnb)
        elif Rt.doedriver == 'CSVGenerated':
            file = opf.gen_doe_csv(Rt.user_config)
            driver_type = om.CSVGenerator(file)
        prob.driver = om.DOEDriver(driver_type)
        prob.driver.options['run_parallel'] = True
        prob.driver.options['procs_per_model'] = 1
    else:
        log.error('Type of optimisation not recognize!!!')

    ## Attaching a recorder and a diagramm visualizer ##
    prob.driver.recording_options['record_inputs'] = True
    prob.driver.add_recorder(
        om.SqliteRecorder(optim_dir_path + '/circuit.sqlite'))
    prob.driver.add_recorder(
        om.SqliteRecorder(optim_dir_path + '/Driver_recorder.sql'))
Ejemplo n.º 5
0
    def setUp(self):

        self.filename = "cases.sql"
        self.recorder = om.SqliteRecorder(self.filename)

        self.driver_case = "rank0:DOEDriver_PlackettBurman|3"
        self.problem_case = "rank0:DOEDriver_PlackettBurman|3|root._solve_nonlinear|3"
Ejemplo n.º 6
0
    def test_root_index_case(self):
        prob = om.Problem()
        model = prob.model

        model.add_subsystem('p1', om.IndepVarComp('x', 0.0), promotes=['x'])
        model.add_subsystem('p2', om.IndepVarComp('y', 0.0), promotes=['y'])
        model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])

        model.add_design_var('x', lower=0.0, upper=1.0)
        model.add_design_var('y', lower=0.0, upper=1.0)
        model.add_objective('f_xy')

        recorder = om.SqliteRecorder("cases.sql")
        prob.driver = om.DOEDriver(om.PlackettBurmanGenerator())
        prob.model.add_recorder(recorder)

        prob.setup()
        prob.run_driver()
        prob.cleanup()

        data_dict = _get_viewer_data("cases.sql", case_id=3)

        vals = data_dict['tree']['children'][2]['children']
        x_val = vals[0]['value']
        y_val = vals[1]['value']
        f_xy_val = vals[2]['value']

        self.assertEqual(x_val, np.array([1.]))
        self.assertEqual(y_val, np.array([1.]))
        self.assertEqual(f_xy_val, np.array([27.]))
Ejemplo n.º 7
0
    def test_discrete_input_dataframe(self):
        class OMDataFrame:
            def __dict__(self):
                pass

        class ModCompEx2(ModCompEx):
            def setup(self):
                super().setup()
                self.add_discrete_input('test', OMDataFrame())

        prob = om.Problem()
        model = prob.model

        indep = model.add_subsystem('indep', om.IndepVarComp(), promotes=['*'])
        indep.add_discrete_output('x', 11)
        model.add_subsystem('comp', ModCompEx2(3), promotes=['*'])

        rec = om.SqliteRecorder('test.db')
        prob.driver.add_recorder(rec)
        prob.add_recorder(rec)

        prob.setup()
        msg = (
            "DeprecationWarning: The truth value of an empty array is ambiguous. Returning"
            "False, but in future this will result in an error. Use `array.size > 0` to check "
            "that an array is not empty.")

        with assert_no_warning(DeprecationWarning, msg):
            prob.run_model()
Ejemplo n.º 8
0
def run_problem(problem, refine_method='hp', refine_iteration_limit=0, run_driver=True,
                simulate=False, restart=None):
    """
    A Dymos-specific interface to execute an OpenMDAO problem containing Dymos Trajectories or
    Phases.  This function can iteratively call run_driver to perform grid refinement, and automatically
    call simulate following a run to check the validity of a result.

    Parameters
    ----------
    problem : om.Problem
        The OpenMDAO problem object to be run.
    refine : bool
        If True, perform grid refinement on the Phases found in the Problem.
    refine_method : String
        The choice of refinement algorithm to use for grid refinement
    refine_iteration_limit : int
        The number of passes through the grid refinement algorithm to be made.
    run_driver : bool
        If True, run the driver (optimize the problem), otherwise just run the model one time.
    no_iterate : bool
        If True, run the driver but do not iterate.
    simulate : bool
        If True, perform a simulation of Trajectories found in the Problem after the driver
        has been run and grid refinement is complete.
    """
    if 'dymos_solution.db' not in [rec._filepath for rec in iter(problem._rec_mgr)]:
        problem.add_recorder(om.SqliteRecorder('dymos_solution.db'))

    problem.final_setup()  # make sure command line option hook has a chance to run

    if restart is not None:
        case = om.CaseReader(restart).get_case('final')
        load_case(problem, case)
Ejemplo n.º 9
0
    def setUp(self):
        self.orig_dir = os.getcwd()
        self.temp_dir = mkdtemp()
        os.chdir(self.temp_dir)

        self.filename = os.path.join(self.temp_dir, "sqlite_test")
        self.recorder = om.SqliteRecorder(self.filename)
Ejemplo n.º 10
0
    def test_pyxdsm_case_reading(self):
        """
        Writes a recorder file, and the XDSM writer makes the diagram based on the SQL file
        and not the Problem instance.
        """
        import openmdao.api as om

        filename = 'xdsm_from_sql'
        case_recording_filename = filename + '.sql'

        p = om.Problem()
        p.model = model = SellarNoDerivatives()
        model.add_design_var('z', lower=np.array([-10.0, 0.0]),
                             upper=np.array([10.0, 10.0]), indices=np.arange(2, dtype=int))
        model.add_design_var('x', lower=0.0, upper=10.0)
        model.add_objective('obj')
        model.add_constraint('con1', equals=np.zeros(1))
        model.add_constraint('con2', upper=0.0)

        recorder = om.SqliteRecorder(case_recording_filename)
        p.driver.add_recorder(recorder)

        p.setup()
        p.final_setup()

        # Write output
        write_xdsm(case_recording_filename, filename=filename, out_format='tex', show_browser=False, quiet=QUIET)

        # Check if file was created
        self.assertTrue(os.path.isfile(case_recording_filename))
        self.assertTrue(os.path.isfile(filename + '.tex'))

        # Check that there are no errors when running from the command line with a recording.
        check_call('openmdao xdsm --no_browser {}'.format(case_recording_filename))
Ejemplo n.º 11
0
def test_unconstrained_dtlz1(recording_path):
    recorder = om.SqliteRecorder(recording_path)

    pymop_problem = pymop.DTLZ1(n_var=3, n_obj=3)

    prob = om.Problem()
    prob.model = PymopGroup(problem=pymop_problem)
    prob.model.add_recorder(recorder)
    prob.driver = Nsga3Driver(generation_count=500, random_seed=0)

    try:
        prob.setup()
        prob.run_driver()
    finally:
        prob.cleanup()

    cases = case_dataset(om.CaseReader(recording_path))
    pareto_cases = pareto_subset(cases)

    distance_function = "euclidean"
    ref_dirs = uniform_reference_points(pymop_problem.n_obj, p=4)
    ideal_pareto_front = pymop_problem.pareto_front(ref_dirs)
    min_pareto_point_distance = sp.spatial.distance.pdist(
        ideal_pareto_front, distance_function
    ).min()

    distances = sp.spatial.distance.cdist(
        pareto_cases["problem.obj"].values, ideal_pareto_front, distance_function
    )
    distances_to_ideal = np.min(distances, axis=0)

    assert distances_to_ideal.max() <= min_pareto_point_distance * 0.75
Ejemplo n.º 12
0
    def test_balance_comp_options_exclude_no_error(self):

        prob = om.Problem()

        bal = om.BalanceComp()
        bal.add_balance('x', val=1.0)

        prob.model.add_subsystem(name='balance', subsys=bal)

        recorder = om.SqliteRecorder('cases.sql')

        prob.model.add_recorder(recorder)

        prob.model.recording_options['record_inputs'] = True
        prob.model.recording_options['record_outputs'] = True
        prob.model.recording_options['record_residuals'] = True
        bal.recording_options['record_metadata'] = False

        prob.setup()

        msg = (
            "Trying to record option 'guess_func' which cannot be pickled on system BalanceComp "
            "(balance). Set 'recordable' to False. Skipping recording options for this system."
        )

        with assert_no_warning(UserWarning, msg):
            prob.run_model()

        prob = om.Problem()

        bal = om.BalanceComp()
        bal.add_balance('x', val=1.0)

        prob.model.add_subsystem(name='balance', subsys=bal)

        recorder = om.SqliteRecorder('cases.sql')

        prob.model.add_recorder(recorder)

        bal.recording_options['record_metadata'] = True
        bal.recording_options['options_excludes'] = ['guess_func']

        prob.setup()

        with assert_no_warning(UserWarning, msg):
            prob.run_model()
Ejemplo n.º 13
0
    def test_list_outputs(self):
        """
        Confirm that includes/excludes has the same result between System.list_inputs() and
        Case.list_inputs(), and between System.list_outputs() and Case.list_outputs().
        """

        prob = ParaboloidProblem()
        rec = om.SqliteRecorder('test_list_outputs.db')
        prob.model.add_recorder(rec)

        prob.setup()
        prob.run_model()

        read_p = om.CaseReader('test_list_outputs.db').get_case(-1)

        prob_out = io.StringIO()
        rec_out = io.StringIO()

        # Test list_inputs() with includes
        prob.model.list_inputs(val=False, includes="comp*", out_stream=prob_out)
        read_p.list_inputs(val=False, includes="comp*", out_stream=rec_out)

        prob_out_str = prob_out.getvalue()
        rec_out_str = rec_out.getvalue()
        self.assertEqual(prob_out_str, rec_out_str)

        prob_out.flush()
        rec_out.flush()        

        # Test list_outputs() with includes
        prob.model.list_outputs(val=False, includes="p*", out_stream=prob_out)
        read_p.list_outputs(val=False, includes="p*", out_stream=rec_out)

        prob_out_str = prob_out.getvalue()
        rec_out_str = rec_out.getvalue()
        self.assertEqual(prob_out_str, rec_out_str)

        prob_out.flush()
        rec_out.flush()

        # Test list_inputs() with excludes
        prob.model.list_inputs(val=False, excludes="comp*", out_stream=prob_out)
        read_p.list_inputs(val=False, excludes="comp*", out_stream=rec_out)

        prob_out_str = prob_out.getvalue()
        rec_out_str = rec_out.getvalue()
        self.assertEqual(prob_out_str, rec_out_str)

        prob_out.flush()
        rec_out.flush()

        # Test list_outputs() with excludes
        prob.model.list_outputs(val=False, excludes="p*", out_stream=prob_out)
        read_p.list_outputs(val=False, excludes="p*", out_stream=rec_out)

        prob_out_str = prob_out.getvalue()
        rec_out_str = rec_out.getvalue()
        self.assertEqual(prob_out_str, rec_out_str)
Ejemplo n.º 14
0
    def test_proc_per_model(self):
        # Test that we can run a GA on a distributed component without lockups.
        prob = om.Problem()
        model = prob.model

        model.add_subsystem('p', om.IndepVarComp('x', 3.0), promotes=['x'])

        model.add_subsystem('d1', D1(), promotes=['*'])
        model.add_subsystem('d2', D2(), promotes=['*'])

        model.add_subsystem('obj_comp', Summer(), promotes_outputs=['*'])
        model.promotes('obj_comp', inputs=['*'], src_indices=om.slicer[:])
        model.nonlinear_solver = om.NewtonSolver(solve_subsystems=True)
        model.linear_solver = om.LinearBlockGS()

        model.add_design_var('x', lower=-0.5, upper=0.5)
        model.add_objective('obj')

        driver = prob.driver = om.DifferentialEvolutionDriver()
        driver.options['pop_size'] = 4
        driver.options['max_gen'] = 3
        driver.options['run_parallel'] = True
        driver.options['procs_per_model'] = 2

        # also check that parallel recording works
        driver.add_recorder(om.SqliteRecorder("cases.sql"))

        prob.setup()
        prob.set_solver_print(level=0)

        failed, output = run_driver(prob)

        self.assertFalse(failed)

        # we will have run 2 models in parallel on our 4 procs
        num_models = prob.comm.size // driver.options['procs_per_model']
        self.assertEqual(num_models, 2)

        # a separate case file should have been written by rank 0 of each parallel model
        # (the top two global ranks)
        rank = prob.comm.rank
        filename = "cases.sql_%d" % rank

        if rank < num_models:
            expect_msg = "Cases from rank %d are being written to %s." % (
                rank, filename)
            self.assertTrue(expect_msg in output)

            cr = om.CaseReader(filename)
            cases = cr.list_cases('driver')

            # check that cases were recorded on this proc
            num_cases = len(cases)
            self.assertTrue(num_cases > 0)
        else:
            self.assertFalse("Cases from rank %d are being written" %
                             rank in output)
            self.assertFalse(os.path.exists(filename))
Ejemplo n.º 15
0
    def test_different_variables(self):

        p1 = om.Problem()
        ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=0.0)
        ivc.add_output('b', val=1.0)
        ivc.add_output('c', val=2.0)
        ivc.add_output('x', val=3.0)
        p1.add_recorder(om.SqliteRecorder('p1.db'))
        p1.setup()

        p2 = om.Problem()
        ivc = p2.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('x', val=3.0)
        ivc.add_output('y', val=4.0)
        ivc.add_output('z', val=5.0)
        p2.add_recorder(om.SqliteRecorder('p2.db'))
        p2.setup()

        p1.run_model()
        p2.run_model()

        p1.record('final')
        p1.cleanup()

        p2.record('final')
        p2.cleanup()

        c1 = om.CaseReader('p1.db').get_case('final')
        c2 = om.CaseReader('p2.db').get_case('final')

        with self.assertRaises(AssertionError) as e:
            assert_cases_equal(c1, c2)

        expected = "\nrequire_same_vars=True but cases contain different variables.\nVariables in " \
                   "case1 but not in case2: ['a', 'b', 'c']\nVariables in case2 but not in " \
                   "case1: ['y', 'z']"

        self.assertEqual(str(e.exception), expected)
Ejemplo n.º 16
0
    def test_different_shapes(self):

        p1 = om.Problem()
        ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=np.array([0, 1, 2]))
        ivc.add_output('b', val=np.array([[0, 1, 2], [3, 4, 5]]))
        ivc.add_output('c', val=np.eye(3, dtype=float))
        p1.add_recorder(om.SqliteRecorder('p1.db'))
        p1.setup()

        p2 = om.Problem()
        ivc = p2.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=3.0)
        ivc.add_output('b', val=np.array([0, 1, 2]))
        ivc.add_output('c', val=np.ones(3, dtype=float))
        p2.add_recorder(om.SqliteRecorder('p2.db'))
        p2.setup()

        p1.run_model()
        p2.run_model()

        p1.record('final')
        p1.cleanup()

        p2.record('final')
        p2.cleanup()

        c1 = om.CaseReader('p1.db').get_case('final')
        c2 = om.CaseReader('p2.db').get_case('final')

        with self.assertRaises(AssertionError) as e:
            assert_cases_equal(c1, c2)

        expected = "\nThe following variables have different shapes/sizes:\na has shape (3,) in " \
                   "case1 but shape (1,) in case2\nb has shape (2, 3) in case1 but shape (3,) in " \
                   "case2\nc has shape (3, 3) in case1 but shape (3,) in case2"

        self.assertEqual(str(e.exception), expected)
Ejemplo n.º 17
0
    def test_different_values(self):

        p1 = om.Problem()
        ivc = p1.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=np.array([0, 1, 2]))
        ivc.add_output('b', val=np.array([[0, 1, 2], [3, 4, 5]]))
        ivc.add_output('c', val=np.eye(3, dtype=float))
        p1.add_recorder(om.SqliteRecorder('p1.db'))
        p1.setup()

        p2 = om.Problem()
        ivc = p2.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*'])
        ivc.add_output('a', val=3 * np.array([0, 1, 2]))
        ivc.add_output('b', val=2 * np.array([[0, 1, 2], [3, 4, 5]]))
        ivc.add_output('c', val=5 * np.eye(3, dtype=float))
        p2.add_recorder(om.SqliteRecorder('p2.db'))
        p2.setup()

        p1.run_model()
        p2.run_model()

        p1.record('final')
        p1.cleanup()

        p2.record('final')
        p2.cleanup()

        c1 = om.CaseReader('p1.db').get_case('final')
        c2 = om.CaseReader('p2.db').get_case('final')

        expected = "\nThe following variables contain different values:\nvar: " \
                   "error\na: [0. 2. 4.]\nb: [[0. 1. 2.]\n [3. 4. 5.]]\n" \
                   "c: [[4. 0. 0.]\n [0. 4. 0.]\n [0. 0. 4.]]"

        with self.assertRaises(AssertionError) as e:
            assert_cases_equal(c1, c2)

        self.assertEqual(str(e.exception), expected)
Ejemplo n.º 18
0
    def set_recorders(self, wt_opt):
        folder_output = self.opt["general"]["folder_output"]

        # Set recorder on the OpenMDAO driver level using the `optimization_log`
        # filename supplied in the optimization yaml
        if self.opt["recorder"]["flag"]:
            recorder = om.SqliteRecorder(os.path.join(folder_output, self.opt["recorder"]["file_name"]))
            wt_opt.driver.add_recorder(recorder)
            wt_opt.add_recorder(recorder)

            wt_opt.driver.recording_options["excludes"] = ["*_df"]
            wt_opt.driver.recording_options["record_constraints"] = True
            wt_opt.driver.recording_options["record_desvars"] = True
            wt_opt.driver.recording_options["record_objectives"] = True

        return wt_opt
Ejemplo n.º 19
0
def modify_problem(problem,
                   restart=None,
                   reset_grid=False,
                   solution_record_file='dymos_solution.db'):
    """
    Modifies the problem object by loading in a guess from a specified restart file.
    Parameters
    ----------
    problem : om.Problem
        The problem instance being modified.
    restart : String or None
        The name of a database to use for restarting the problem.
    reset_grid: Boolean
        Flag to trigger a grid reset. Not implemented yet.
    solution_record_file: str
        The path to the file to be used for recording the solution recording.
    """
    # record variables to database when running driver under hook
    # pre-hook is important, because recording initialization is skipped if final_setup has run once
    try:
        os.remove(solution_record_file)
    except FileNotFoundError:
        pass  # OK if old database is not present to be deleted

    print('adding recorder at:', solution_record_file)
    problem.add_recorder(om.SqliteRecorder(solution_record_file))

    # if opts.get('reset_grid'):  # TODO: implement this option
    #     pass

    if restart is not None:  # restore variables from database file specified by 'restart'
        print('Restarting run_problem using the %s database.' % restart)
        cr = om.CaseReader(restart)

        # find the proper case
        try:
            case = cr.get_case('final')
        except RuntimeError:
            cases = cr.list_cases()
            if len(cases) < 1:
                print(
                    'WARNING: the requested %s database file does not have any cases to load.'
                    % restart)
                return
            case = cr.get_case(
                cases[-1])  # use last case, ideally it should be the only one
Ejemplo n.º 20
0
        def run_sequential():
            # problem will run in the single proc comm for this rank
            prob = om.Problem(comm=my_comm)

            prob.model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
            prob.model.add_design_var('x', lower=0.0, upper=1.0)
            prob.model.add_design_var('y', lower=0.0, upper=1.0)
            prob.model.add_objective('f_xy')

            prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
            prob.driver.options['run_parallel'] = False
            prob.driver.options['procs_per_model'] = 1
            prob.driver.add_recorder(om.SqliteRecorder("cases.sql"))

            prob.setup()
            prob.run_driver()
            prob.cleanup()
Ejemplo n.º 21
0
    def test_recording(self):
        # coloring involves an underlying call to run_model (and final_setup),
        # this verifies that it is handled properly by the recording setup logic
        recorder = om.SqliteRecorder('cases.sql')

        p = run_opt(pyOptSparseDriver,
                    'auto',
                    assemble_type='csc',
                    optimizer='SNOPT',
                    dynamic_total_coloring=True,
                    print_results=False,
                    recorder=recorder)

        cr = om.CaseReader('cases.sql')

        self.assertEqual(cr.list_cases(), [
            'rank0:pyOptSparse_SNOPT|%d' % i
            for i in range(p.driver.iter_count)
        ])
Ejemplo n.º 22
0
    def setUp(self):
        # override notebook flag for system, variable table and sqlite_reader
        from openmdao.core import system
        from openmdao.utils import variable_table
        from openmdao.recorders import sqlite_reader
        system.notebook = variable_table.notebook = sqlite_reader.notebook = True

        # capture HTML output from variable_table
        self.html_stream = StringIO()
        variable_table.HTML = lambda x: self.html_stream.write(x)
        sqlite_reader.HTML = lambda x: self.html_stream.write(x)

        # create & run problem, generate cases
        model = om.Group()
        model.add_subsystem('comp', Paraboloid(), promotes=['x', 'y', 'f_xy'])
        model.add_design_var('x', lower=0.0, upper=1.0)
        model.add_design_var('y', lower=0.0, upper=1.0)
        model.add_objective('f_xy')

        prob = om.Problem(model)
        prob.driver = om.DOEDriver(om.FullFactorialGenerator(levels=3))
        prob.driver.add_recorder(
            om.SqliteRecorder('cases.sql', record_viewer_data=False))

        prob.setup()
        prob.run_driver()
        prob.cleanup()

        # expected results
        self.expected_sources = ['driver']

        self.expected_cases = [
            'rank0:DOEDriver_FullFactorial|0',
            'rank0:DOEDriver_FullFactorial|1',
            'rank0:DOEDriver_FullFactorial|2',
            'rank0:DOEDriver_FullFactorial|3',
            'rank0:DOEDriver_FullFactorial|4',
            'rank0:DOEDriver_FullFactorial|5',
            'rank0:DOEDriver_FullFactorial|6',
            'rank0:DOEDriver_FullFactorial|7',
            'rank0:DOEDriver_FullFactorial|8'
        ]
Ejemplo n.º 23
0
def N3_SPD_model():

    prob = om.Problem()

    prob.model = MPN3()

    # setup the optimization
    prob.driver = om.pyOptSparseDriver()
    prob.driver.options['optimizer'] = 'SNOPT'
    prob.driver.options['debug_print'] = ['desvars', 'nl_cons', 'objs']
    prob.driver.opt_settings = {'Major step limit': 0.05}

    prob.model.add_design_var('fan:PRdes', lower=1.20, upper=1.4)
    prob.model.add_design_var('lpc:PRdes', lower=2.0, upper=4.0)
    prob.model.add_design_var('TOC.balance.rhs:hpc_PR',
                              lower=40.0,
                              upper=70.0,
                              ref0=40.0,
                              ref=70.0)
    prob.model.add_design_var('RTO_T4',
                              lower=3000.0,
                              upper=3600.0,
                              ref0=3000.0,
                              ref=3600.0)
    prob.model.add_design_var('T4_ratio.TR',
                              lower=0.5,
                              upper=0.95,
                              ref0=0.5,
                              ref=0.95)

    prob.model.add_objective('TOC.perf.TSFC')

    # to add the constraint to the model
    prob.model.add_constraint('TOC.fan_dia.FanDia', upper=100.0, ref=100.0)

    recorder = om.SqliteRecorder('N3_opt.sql')
    prob.model.add_recorder(recorder)
    prob.model.recording_options['record_inputs'] = True
    prob.model.recording_options['record_outputs'] = True

    return (prob)
Ejemplo n.º 24
0
def test_problem_with_case_recorder(cleanup):
    """Tests what happens when using a case recorder"""
    # Adding a case recorder may cause a crash in case of deepcopy.

    problem = FASTOADProblem()
    sellar = Sellar()
    sellar.nonlinear_solver = om.NonlinearBlockGS(
    )  # Solver that is compatible with deepcopy
    sellar.add_recorder(
        om.SqliteRecorder(pth.join(RESULTS_FOLDER_PATH, "cases.sql")))

    problem.model.add_subsystem("sellar", sellar, promotes=["*"])

    problem.input_file_path = pth.join(DATA_FOLDER_PATH, "ref_inputs.xml")

    problem.setup()
    problem.read_inputs()
    problem.run_model()

    assert_allclose(problem.get_val(name="x"), 1.0)
    assert_allclose(problem.get_val(name="z", units="m**2"), [4.0, 3.0])
    assert_allclose(problem["f"], 21.7572, atol=1.0e-4)
Ejemplo n.º 25
0
    def setUp(self):
        # build the model
        prob = om.Problem()
        prob.model.add_subsystem('parab',
                                 Paraboloid(),
                                 promotes_inputs=['x', 'y'])

        # define the component whose output will be constrained
        prob.model.add_subsystem('const',
                                 om.ExecComp('g = x + y'),
                                 promotes_inputs=['x', 'y'])

        # Design variables 'x' and 'y' span components, so we need to provide a common initial
        # value for them.
        prob.model.set_input_defaults('x', 3.0)
        prob.model.set_input_defaults('y', -4.0)

        # setup the optimization
        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.add_recorder(om.SqliteRecorder('parab_record.sql'))

        prob.driver.recording_options['includes'] = ['*']
        prob.driver.recording_options['record_desvars'] = True
        prob.driver.recording_options['record_objectives'] = True
        prob.driver.recording_options['record_constraints'] = True
        prob.driver.recording_options['record_residuals'] = True

        prob.model.add_design_var('x', lower=-50, upper=50)
        prob.model.add_design_var('y', lower=-50, upper=50)
        prob.model.add_objective('parab.f_xy')

        # to add the constraint to the model
        prob.model.add_constraint('const.g', lower=0, upper=10.)

        prob.setup()

        prob.run_driver()
Ejemplo n.º 26
0
    def test_balance_comp_record_options(self):

        prob = om.Problem()

        bal = om.BalanceComp()
        bal.add_balance('x', val=1.0)

        prob.model.add_subsystem(name='balance', subsys=bal)

        recorder = om.SqliteRecorder('cases.sql')

        prob.model.add_recorder(recorder)

        prob.model.recording_options['record_inputs'] = True
        prob.model.recording_options['record_outputs'] = True
        prob.model.recording_options['record_residuals'] = True

        prob.setup()

        # there should be no warnings wrt unpicklable 'guess_func' option,
        # since 'recordable' has been set to False
        with assert_no_warning(UserWarning):
            prob.run_model()
    def test(self):
        import numpy as np

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint
        from openaerostruct.utils.constants import grav_constant

        import openmdao.api as om

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 11,
            'num_x': 2,
            'wing_type': 'CRM',
            'symmetry': True,
            'num_twist_cp': 5
        }

        mesh, twist_cp = generate_mesh(mesh_dict)

        surface = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'symmetry': True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'S_ref_type': 'wetted',  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            'fem_model_type': 'tube',
            'thickness_cp': np.array([.1, .2, .3]),
            'twist_cp': twist_cp,
            'mesh': mesh,

            # Aerodynamic performance of the lifting surface at
            # an angle of attack of 0 (alpha=0).
            # These CL0 and CD0 values are added to the CL and CD
            # obtained from aerodynamic analysis of the surface to get
            # the total CL and CD.
            # These CL0 and CD0 values do not vary wrt alpha.
            'CL0': 0.0,  # CL of the surface at alpha=0
            'CD0': 0.015,  # CD of the surface at alpha=0

            # Airfoil properties for viscous drag calculation
            'k_lam': 0.05,  # percentage of chord with laminar
            # flow, used for viscous drag
            't_over_c_cp':
            np.array([0.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,
            'with_wave': False,  # if true, compute wave drag

            # Structural values are based on aluminum 7075
            'E': 70.e9,  # [Pa] Young's modulus of the spar
            'G': 30.e9,  # [Pa] shear modulus of the spar
            'yield':
            500.e6 / 2.5,  # [Pa] yield stress divided by 2.5 for limiting case
            'mrho': 3.e3,  # [kg/m^3] material density
            'fem_origin': 0.35,  # normalized chordwise location of the spar
            'wing_weight_ratio': 2.,
            'struct_weight_relief':
            False,  # True to add the weight of the structure to the loads on the structure
            'distributed_fuel_weight': False,
            # Constraints
            'exact_failure_constraint': False,  # if false, use KS function
        }

        # Create the problem and assign the model group
        prob = om.Problem()

        # Add problem information as an independent variables component
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=[248.136, 0.5 * 340.], units='m/s')
        indep_var_comp.add_output('alpha', val=[5., 10.], units='deg')
        indep_var_comp.add_output('Mach_number', val=[0.84, 0.5])
        indep_var_comp.add_output('re', val=[1.e6, 0.5e6], units='1/m')
        indep_var_comp.add_output('rho', val=[0.38, .764], units='kg/m**3')
        indep_var_comp.add_output('CT',
                                  val=grav_constant * 17.e-6,
                                  units='1/s')
        indep_var_comp.add_output('R', val=11.165e6, units='m')
        indep_var_comp.add_output('W0', val=0.4 * 3e5, units='kg')
        indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s')
        indep_var_comp.add_output('load_factor', val=[1., 2.5])
        indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')

        prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*'])

        # Add morphing variables as an independent variables component
        morphing_vars = om.IndepVarComp()
        morphing_vars.add_output('t_over_c_cp', val=np.array([0.15]))
        morphing_vars.add_output('thickness_cp',
                                 val=np.array([0.01, 0.01, 0.01]),
                                 units='m')
        morphing_vars.add_output('twist_cp_0',
                                 val=np.array([2., 3., 4., 4., 4.]),
                                 units='deg')
        morphing_vars.add_output('twist_cp_1',
                                 val=np.array([4., 4., 4., 5., 6.]),
                                 units='deg')

        prob.model.add_subsystem('morphing_vars',
                                 morphing_vars,
                                 promotes=['*'])

        # Connect geometric design variables to each point
        prob.model.connect('t_over_c_cp',
                           'AS_point_0.wing.geometry.t_over_c_cp')
        prob.model.connect('t_over_c_cp',
                           'AS_point_1.wing.geometry.t_over_c_cp')

        prob.model.connect('thickness_cp',
                           'AS_point_0.wing.tube_group.thickness_cp')
        prob.model.connect('thickness_cp',
                           'AS_point_1.wing.tube_group.thickness_cp')

        prob.model.connect('twist_cp_0', 'AS_point_0.wing.geometry.twist_cp')
        prob.model.connect('twist_cp_1', 'AS_point_1.wing.geometry.twist_cp')

        for point in range(2):

            name = 'wing'

            point_name = 'AS_point_{}'.format(point)

            # Create the aero point group and add it to the model
            AS_point = AerostructPoint(surfaces=[surface])

            prob.model.add_subsystem(point_name, AS_point)

            aerostruct_group = AerostructGeometry(surface=surface,
                                                  connect_geom_DVs=False)
            AS_point.add_subsystem(name, aerostruct_group)

            # Connect flow properties to the analysis point
            prob.model.connect('alpha',
                               point_name + '.alpha',
                               src_indices=[point])
            prob.model.connect('v', point_name + '.v', src_indices=[point])
            prob.model.connect('Mach_number',
                               point_name + '.Mach_number',
                               src_indices=[point])
            prob.model.connect('re', point_name + '.re', src_indices=[point])
            prob.model.connect('rho', point_name + '.rho', src_indices=[point])
            prob.model.connect('CT', point_name + '.CT')
            prob.model.connect('R', point_name + '.R')
            prob.model.connect('W0', point_name + '.W0')
            prob.model.connect('speed_of_sound',
                               point_name + '.speed_of_sound')
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor',
                               point_name + '.load_factor',
                               src_indices=[point])

            com_name = point_name + '.' + name + '_perf'
            AS_point.connect(name + '.local_stiff_transformed',
                             'coupled.' + name + '.local_stiff_transformed')
            AS_point.connect(name + '.nodes', 'coupled.' + name + '.nodes')

            # Connect aerodyamic mesh to coupled group mesh
            AS_point.connect(name + '.mesh', 'coupled.' + name + '.mesh')

            # Connect performance calculation variables
            AS_point.connect(name + '.radius', name + '_perf' + '.radius')
            AS_point.connect(name + '.thickness',
                             name + '_perf' + '.thickness')
            AS_point.connect(name + '.nodes', name + '_perf' + '.nodes')
            AS_point.connect(name + '.cg_location',
                             'total_perf.' + name + '_cg_location')
            AS_point.connect(name + '.structural_mass',
                             'total_perf.' + name + '_structural_mass')
            AS_point.connect(name + '.geometry.t_over_c',
                             name + '_perf' + '.t_over_c')
            AS_point.connect(name + '.geometry.t_over_c', name + '.t_over_c')

        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9
        prob.driver.options['maxiter'] = 2

        recorder = om.SqliteRecorder("morphing_aerostruct.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True
        prob.driver.recording_options['includes'] = ['*']

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('twist_cp_0', lower=-10., upper=15.)
        prob.model.add_design_var('twist_cp_1', lower=-10., upper=15.)
        prob.model.add_design_var('thickness_cp',
                                  lower=0.01,
                                  upper=0.5,
                                  scaler=1e2)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects',
                                  upper=0.)
        prob.model.add_constraint('AS_point_1.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_1.wing_perf.thickness_intersects',
                                  upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_design_var('alpha', lower=-15., upper=15.)
        prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
        prob.model.add_constraint('AS_point_1.L_equals_W', equals=0.)
        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        # Set up the problem
        prob.setup(check=True)

        # om.view_model(prob)

        prob.run_model()

        # Check the partials at the initial point in the design space,
        # only care about relative error
        data = prob.check_partials(compact_print=True,
                                   out_stream=None,
                                   method='cs',
                                   step=1e-40)

        assert_check_partials(data, atol=1e20, rtol=1e-6)

        # Run the optimizer for 2 iterations
        prob.run_driver()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True,
                                   out_stream=None,
                                   method='cs',
                                   step=1e-40)
        assert_check_partials(data, atol=1e20, rtol=1e-6)
Ejemplo n.º 28
0
def run_opt(layout_number, wec_method_number, wake_model, opt_alg_number,
            max_wec, nsteps):
    OPENMDAO_REQUIRE_MPI = False
    run_number = layout_number
    model = wake_model
    # set model
    MODELS = ['FLORIS', 'BPA', 'JENSEN', 'LARSEN']
    print(MODELS[model])

    # select optimization approach/method
    opt_algs = ['snopt', 'ga', 'ps']
    opt_algorithm = opt_algs[opt_alg_number]

    # select wec method
    wec_methods = ['none', 'diam', 'angle', 'hybrid']
    wec_method = wec_methods[wec_method_number]

    # pop_size = 760

    # save and show options
    show_start = False
    show_end = False
    save_start = False
    save_end = False

    save_locations = True
    save_aep = True
    save_time = True
    rec_func_calls = True

    input_directory = "../../../input_files/"

    # set options for BPA
    print_ti = False
    sort_turbs = True

    # turbine_type = 'NREL5MW'            #can be 'V80' or 'NREL5MW'
    turbine_type = 'V80'  # can be 'V80' or 'NREL5MW'

    wake_model_version = 2016

    WECH = 0
    if wec_method == 'diam':
        output_directory = "../output_files/%s_wec_diam_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        # expansion_factors = np.array([3, 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0, 1.0])
        expansion_factors = np.linspace(1.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 1.0)
        conv_tols = np.array([1E-2, 1E-2, 1E-2, 1E-2, 1E-2, 1E-2, 1E-3])
    elif wec_method == 'angle':
        output_directory = "../output_files/%s_wec_angle_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        # expansion_factors = np.array([50, 40, 30, 20, 10, 0.0, 0.0])
        expansion_factors = np.linspace(0.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 0.0)
    elif wec_method == 'hybrid':
        expansion_factors = np.linspace(1.0, max_wec, nsteps)
        expansion_factors = np.append(np.flip(expansion_factors), 1.0)
        output_directory = "../output_files/%s_wec_hybrid_max_wec_%i_nsteps_%.3f/" % (
            opt_algorithm, max_wec, nsteps)
        relax = True
        WECH = 1
    elif wec_method == 'none':
        relax = False
        if opt_algorithm == "ps":
            expansion_factors = np.array([1.0])
            conv_tols = np.array([1E-3])
        else:
            expansion_factors = np.array([1.0, 1.0])
            conv_tols = np.array([1E-2, 1E-3])
        output_directory = "../output_files/%s/" % opt_algorithm
    else:
        raise ValueError('wec_method must be diam, angle, hybrid, or none')

    # create output directory if it does not exist yet
    import distutils.dir_util
    distutils.dir_util.mkpath(output_directory)

    differentiable = True

    # for expansion_factor in np.array([5., 4., 3., 2.75, 2.5, 2.25, 2.0, 1.75, 1.5, 1.25, 1.0]):
    # for expansion_factor in np.array([20., 15., 10., 5., 4., 3., 2.5, 1.25, 1.0]):
    # expansion_factors = np.array([20., 10., 5., 2.5, 1.25, 1.0])

    wake_combination_method = 1  # can be [0:Linear freestreem superposition,
    #  1:Linear upstream velocity superposition,
    #  2:Sum of squares freestream superposition,
    #  3:Sum of squares upstream velocity superposition]

    ti_calculation_method = 4  # can be [0:No added TI calculations,
    # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas,
    # 2:TI by Niayifar and Porte Agel 2016,
    # 3:TI by Niayifar and Porte Agel 2016 with added soft max function,
    # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio,
    # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function]

    if wec_method_number > 0:
        ti_opt_method = 0  # can be [0:No added TI calculations,
        # 1:TI by Niayifar and Porte Agel altered by Annoni and Thomas,
        # 2:TI by Niayifar and Porte Agel 2016,
        # 3:TI by Niayifar and Porte Agel 2016 with added soft max function,
        # 4:TI by Niayifar and Porte Agel 2016 using area overlap ratio,
        # 5:TI by Niayifar and Porte Agel 2016 using area overlap ratio and SM function]

    else:
        ti_opt_method = 0
    final_ti_opt_method = 5

    if opt_algorithm == 'ps':
        ti_opt_method = ti_calculation_method

    sm_smoothing = 700.

    if ti_calculation_method == 0:
        calc_k_star_calc = False
    else:
        calc_k_star_calc = True

    if ti_opt_method == 0:
        calc_k_star_opt = False
    else:
        calc_k_star_opt = True

    nRotorPoints = 1

    wind_rose_file = 'directional'  # can be one of: 'amalia', 'nantucket', 'directional'

    TI = 0.108
    k_calc = 0.3837 * TI + 0.003678
    # k_calc = 0.022
    # k_opt = 0.04

    shear_exp = 0.31

    # air_density = 1.1716  # kg/m^3
    air_density = 1.225  # kg/m^3 (from Jen)

    if turbine_type == 'V80':

        # define turbine size
        rotor_diameter = 80.  # (m)
        hub_height = 70.0

        z_ref = 80.0  # m
        z_0 = 0.0

        # load performance characteristics
        cut_in_speed = 4.  # m/s
        cut_out_speed = 25.  # m/s
        rated_wind_speed = 16.  # m/s
        rated_power = 2000.  # kW
        generator_efficiency = 0.944

        ct_curve_data = np.loadtxt(input_directory +
                                   'mfg_ct_vestas_v80_niayifar2016.txt',
                                   delimiter=",")
        ct_curve_wind_speed = ct_curve_data[:, 0]
        ct_curve_ct = ct_curve_data[:, 1]

        # air_density = 1.1716  # kg/m^3
        Ar = 0.25 * np.pi * rotor_diameter**2
        # cp_curve_wind_speed = ct_curve[:, 0]
        power_data = np.loadtxt(input_directory +
                                'niayifar_vestas_v80_power_curve_observed.txt',
                                delimiter=',')
        # cp_curve_cp = niayifar_power_model(cp_curve_wind_speed)/(0.5*air_density*cp_curve_wind_speed**3*Ar)
        cp_curve_cp = power_data[:, 1] * (1E6) / (0.5 * air_density *
                                                  power_data[:, 0]**3 * Ar)
        cp_curve_wind_speed = power_data[:, 0]
        cp_curve_spline = UnivariateSpline(cp_curve_wind_speed,
                                           cp_curve_cp,
                                           ext='const')
        cp_curve_spline.set_smoothing_factor(.0001)

    elif turbine_type == 'NREL5MW':

        # define turbine size
        rotor_diameter = 126.4  # (m)
        hub_height = 90.0

        z_ref = 80.0  # m
        z_0 = 0.0

        # load performance characteristics
        cut_in_speed = 3.  # m/s
        cut_out_speed = 25.  # m/s
        rated_wind_speed = 11.4  # m/s
        rated_power = 5000.  # kW
        generator_efficiency = 0.944

        filename = input_directory + "NREL5MWCPCT_dict.p"
        # filename = "../input_files/NREL5MWCPCT_smooth_dict.p"
        import pickle

        data = pickle.load(open(filename, "rb"), encoding='latin1')
        ct_curve = np.zeros([data['wind_speed'].size, 2])
        ct_curve_wind_speed = data['wind_speed']
        ct_curve_ct = data['CT']

        # cp_curve_cp = data['CP']
        # cp_curve_wind_speed = data['wind_speed']

        loc0 = np.where(data['wind_speed'] < 11.55)
        loc1 = np.where(data['wind_speed'] > 11.7)

        cp_curve_cp = np.hstack([data['CP'][loc0], data['CP'][loc1]])
        cp_curve_wind_speed = np.hstack(
            [data['wind_speed'][loc0], data['wind_speed'][loc1]])
        cp_curve_spline = UnivariateSpline(cp_curve_wind_speed,
                                           cp_curve_cp,
                                           ext='const')
        cp_curve_spline.set_smoothing_factor(.000001)
    else:
        raise ValueError("Turbine type is undefined.")

    # load starting locations
    layout_directory = input_directory

    # layout_data = np.loadtxt(layout_directory + "layouts/round_38turbs/nTurbs38_spacing5_layout_%i.txt" % layout_number)
    layout_data = np.loadtxt(
        layout_directory +
        "layouts/grid_16turbs/nTurbs16_spacing5_layout_%i.txt" % layout_number)
    # layout_data = np.loadtxt(layout_directory+"layouts/nTurbs9_spacing5_layout_%i.txt" % layout_number)

    turbineX = layout_data[:, 0] * rotor_diameter
    turbineY = layout_data[:, 1] * rotor_diameter

    turbineX_init = np.copy(turbineX)
    turbineY_init = np.copy(turbineY)

    nTurbines = turbineX.size

    boundary_x = np.array(
        [0.0, 5. * rotor_diameter * (np.sqrt(nTurbines) - 1) + rotor_diameter])
    boundary_y = np.array(
        [0.0, 5. * rotor_diameter * (np.sqrt(nTurbines) - 1) + rotor_diameter])

    if show_start:
        plot_square_farm(turbineX_init,
                         turbineY_init,
                         rotor_diameter,
                         boundary_x,
                         boundary_y,
                         boundary_x[1] - boundary_x[0],
                         show_start=show_start)

    # plot_round_farm(turbineX, turbineY, rotor_diameter, [boundary_center_x, boundary_center_y], boundary_radius,
    #                 show_start=show_start)
    # quit()
    # initialize input variable arrays
    nTurbs = nTurbines
    rotorDiameter = np.zeros(nTurbs)
    hubHeight = np.zeros(nTurbs)
    axialInduction = np.zeros(nTurbs)
    Ct = np.zeros(nTurbs)
    Cp = np.zeros(nTurbs)
    generatorEfficiency = np.zeros(nTurbs)
    yaw = np.zeros(nTurbs)
    minSpacing = 2.  # number of rotor diameters

    # define initial values
    for turbI in range(0, nTurbs):
        rotorDiameter[turbI] = rotor_diameter  # m
        hubHeight[turbI] = hub_height  # m
        axialInduction[turbI] = 1.0 / 3.0
        Ct[turbI] = 4.0 * axialInduction[turbI] * (1.0 - axialInduction[turbI])
        # print(Ct)
        Cp[turbI] = 4.0 * 1.0 / 3.0 * np.power((1 - 1.0 / 3.0), 2)
        generatorEfficiency[turbI] = generator_efficiency
        yaw[turbI] = 0.  # deg.

    # Define flow properties
    if wind_rose_file == 'nantucket':
        # windRose = np.loadtxt(input_directory + 'nantucket_windrose_ave_speeds.txt')
        windRose = np.loadtxt(input_directory +
                              'nantucket_wind_rose_for_LES.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == 'amalia':
        windRose = np.loadtxt(
            input_directory +
            'windrose_amalia_directionally_averaged_speeds.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == 'directional':
        windRose = np.loadtxt(input_directory + 'directional_windrose.txt')
        windDirections = windRose[:, 0]
        windSpeeds = windRose[:, 1]
        windFrequencies = windRose[:, 2]
        size = np.size(windDirections)
    elif wind_rose_file == '1d':
        windDirections = np.array([270.])
        windSpeeds = np.array([8.0])
        windFrequencies = np.array([1.0])
        size = np.size(windDirections)
    else:
        size = 20
        windDirections = np.linspace(0, 270, size)
        windFrequencies = np.ones(size) / size

    wake_model_options = {
        'nSamples': 0,
        'nRotorPoints': nRotorPoints,
        'use_ct_curve': True,
        'ct_curve_ct': ct_curve_ct,
        'ct_curve_wind_speed': ct_curve_wind_speed,
        'interp_type': 1,
        'use_rotor_components': False,
        'differentiable': differentiable,
        'verbose': False
    }

    nVertices = 0
    if MODELS[model] == 'BPA':
        # initialize problem
        prob = om.Problem(
            model=OptAEP(nTurbines=nTurbs,
                         nDirections=windDirections.size,
                         nVertices=nVertices,
                         minSpacing=minSpacing,
                         differentiable=differentiable,
                         use_rotor_components=False,
                         wake_model=gauss_wrapper,
                         params_IdepVar_func=add_gauss_params_IndepVarComps,
                         params_IdepVar_args={'nRotorPoints': nRotorPoints},
                         wake_model_options=wake_model_options,
                         cp_points=cp_curve_cp.size,
                         cp_curve_spline=cp_curve_spline,
                         record_function_calls=True,
                         runparallel=False))
    elif MODELS[model] == 'FLORIS':
        # initialize problem
        prob = om.Problem(
            model=OptAEP(nTurbines=nTurbs,
                         nDirections=windDirections.size,
                         nVertices=nVertices,
                         minSpacing=minSpacing,
                         differentiable=differentiable,
                         use_rotor_components=False,
                         wake_model=floris_wrapper,
                         params_IdepVar_func=add_floris_params_IndepVarComps,
                         params_IdepVar_args={},
                         record_function_calls=True))
    # elif MODELS[model] == 'JENSEN':
    #     initialize problem
    # prob = om.Problem(model=OptAEP(nTurbines=nTurbs, nDirections=windDirections.size, nVertices=nVertices,
    #                                       minSpacing=minSpacing, differentiable=False, use_rotor_components=False,
    #                                       wake_model=jensen_wrapper,
    #                                       params_IdepVar_func=add_jensen_params_IndepVarComps,
    #                                       params_IdepVar_args={},
    #                                               record_function_calls=True))
    else:
        ValueError(
            'The %s model is not currently available. Please select BPA or FLORIS'
            % (MODELS[model]))
    # prob.model.deriv_options['type'] = 'fd'
    # prob.model.deriv_options['form'] = 'central'
    # prob.model.deriv_options['step_size'] = 1.0e-8
    # prob.model.linear_solver = om.LinearBlockGS()
    # prob.model.linear_solver.options['iprint'] = 0
    # prob.model.linear_solver.options['maxiter'] = 5
    #
    # prob.model.nonlinear_solver = om.NonlinearBlockGS()
    # prob.model.nonlinear_solver.options['iprint'] = 0

    # prob.model.linear_solver = om.DirectSolver()

    prob.driver = om.pyOptSparseDriver()

    if opt_algorithm == 'snopt':
        # set up optimizer
        prob.driver.options['optimizer'] = 'SNOPT'
        # prob.driver.options['gradient method'] = 'snopt_fd'

        # set optimizer options
        prob.driver.opt_settings['Verify level'] = -1
        # set optimizer options
        prob.driver.opt_settings['Major optimality tolerance'] = np.float(1e-3)

        prob.driver.opt_settings[
            'Print file'] = output_directory + 'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)
        prob.driver.opt_settings[
            'Summary file'] = output_directory + 'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-2)  # ,
        # active_tol=(2. * rotor_diameter) ** 2)
        # prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-2)  # ,
        # active_tol=2. * rotor_diameter)

        prob.driver.options['dynamic_derivs_sparsity'] = True

    elif opt_algorithm == 'ga':

        prob.driver.options['optimizer'] = 'NSGA2'

        prob.driver.opt_settings['PrintOut'] = 1

        prob.driver.opt_settings['maxGen'] = 50000

        prob.driver.opt_settings['PopSize'] = 10 * nTurbines * 2

        # prob.driver.opt_settings['pMut_real'] = 0.001

        prob.driver.opt_settings['xinit'] = 1

        prob.driver.opt_settings['rtol'] = 1E-4

        prob.driver.opt_settings['atol'] = 1E-4

        prob.driver.opt_settings['min_tol_gens'] = 200

        prob.driver.opt_settings['file_number'] = run_number

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-2)
        # prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-2)

    elif opt_algorithm == 'ps':

        prob.driver.options['optimizer'] = 'ALPSO'

        prob.driver.opt_settings['fileout'] = 1

        prob.driver.opt_settings[
            'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                nTurbs, wind_rose_file, size, MODELS[model], run_number)

        prob.driver.opt_settings['maxOuterIter'] = 10000
        # prob.driver.opt_settings['stopIters'] = 10
        # prob.driver.opt_settings['minInnerIter'] = 100

        prob.driver.opt_settings['SwarmSize'] = 25

        prob.driver.opt_settings[
            'xinit'] = 1  # Initial Position Flag (0 - no position, 1 - position given)

        prob.driver.opt_settings[
            'Scaling'] = 1  # Design Variables Scaling Flag (0 - no scaling, 1 - scaling between [-1, 1])

        # prob.driver.opt_settings['rtol'] = 1E-3  # Relative Tolerance for Lagrange Multipliers
        #
        # prob.driver.opt_settings['atol'] = 1E-2  # Absolute Tolerance for Lagrange Function
        #
        prob.driver.opt_settings[
            'dtol'] = 0.01  # Relative Tolerance in Distance of All Particles to Terminate (GCPSO)
        #
        # prob.driver.opt_settings['itol'] = 1E-3  # Absolute Tolerance for Inequality constraints
        #
        # prob.driver.opt_settings['dynInnerIter'] = 1  # Dynamic Number of Inner Iterations Flag

        prob.model.add_constraint('sc',
                                  lower=np.zeros(
                                      int(((nTurbs - 1.) * nTurbs / 2.))),
                                  scaler=1E-2)
        # prob.model.add_constraint('boundaryDistances', lower=(np.zeros(1 * turbineX.size)), scaler=1E-2)

        # prob.driver.add_objective('obj', scaler=1E0)
    prob.model.add_objective('obj', scaler=1E-4)

    # select design variables
    prob.model.add_design_var(
        'turbineX',
        scaler=1E0,
        lower=np.ones(nTurbines) * (boundary_x[0] + rotor_diameter / 2.),
        upper=np.ones(nTurbines) * (boundary_x[1] - rotor_diameter / 2.))
    prob.model.add_design_var(
        'turbineY',
        scaler=1E0,
        lower=np.ones(nTurbines) * (boundary_y[0] + rotor_diameter / 2.),
        upper=np.ones(nTurbines) * (boundary_y[1] - rotor_diameter / 2.))

    # prob.driver.recording_options['include'] = ['obj']

    # prob.model.ln_solver.options['single_voi_relevance_reduction'] = True
    # prob.model.ln_solver.options['mode'] = 'rev'

    # if run_number == 0:
    #     # set up recorder
    #     recorder = SqliteRecorder(output_directory+'recorder_database_run%i' % run_number)
    #     recorder.options['record_params'] = True
    #     recorder.options['record_metadata'] = False
    #     recorder.options['record_unknowns'] = True
    #     recorder.options['record_derivs'] = False
    #     recorder.options['includes'] = ['turbineX', 'turbineY', 'AEP']
    #     prob.driver.add_recorder(recorder)

    driver_recorder = om.SqliteRecorder(output_directory +
                                        'recorded_data_driver_%s.sql' %
                                        (run_number))
    # model_recorder = om.SqliteRecorder(output_directory + 'recorded_data_model_%s.sql' %(run_number))
    prob.driver.add_recorder(driver_recorder)
    # prob.model.add_recorder(model_recorder)
    prob.driver.recording_options['record_constraints'] = False
    prob.driver.recording_options['record_derivatives'] = False
    prob.driver.recording_options['record_desvars'] = True
    prob.driver.recording_options['record_inputs'] = False
    prob.driver.recording_options['record_model_metadata'] = True
    prob.driver.recording_options['record_objectives'] = True
    prob.driver.recording_options['includes'] = ['AEP']
    prob.driver.recording_options['record_responses'] = False
    #
    # prob_recorder = om.SqliteRecorder(output_directory + 'recorded_data_prob_%s.sql' %(run_number))
    # prob.add_recorder(prob_recorder)
    # prob.recording_options['includes'] = []
    # prob.recording_options['record_objectives'] = True

    # prob.model.recording_options['record_constraints'] = False
    # prob.model.recording_options['record_derivatives'] = False
    # prob.model.recording_options['record_desvars'] = False
    # prob.model.recording_options['record_inputs'] = False
    # prob.model.recording_options['record_model_metadata'] = False
    # prob.model.recording_options['record_objectives'] = True
    # prob.model.recording_options['includes'] = ['AEP']
    # prob.model.recording_options['record_responses'] = False
    # prob.set_solver_print(0)
    # prob.record_iteration('all')
    # set up profiling
    # from plantenergy.GeneralWindFarmComponents import WindFarmAEP
    # methods = [
    #     ('*', (WindFarmAEP,))
    # ]
    #
    # iprofile.setup(methods=methods)

    print("almost time for setup")
    tic = time.time()
    print("entering setup at time = ", tic)
    prob.setup(check=True)
    toc = time.time()
    print("setup complete at time = ", toc)

    # print the results
    print(('Problem setup took %.03f sec.' % (toc - tic)))

    # assign initial values to design variables
    prob['turbineX'] = np.copy(turbineX)
    prob['turbineY'] = np.copy(turbineY)
    for direction_id in range(0, windDirections.size):
        prob['yaw%i' % direction_id] = yaw

    # assign values to constant inputs (not design variables)
    prob['rotorDiameter'] = rotorDiameter
    prob['hubHeight'] = hubHeight
    prob['axialInduction'] = axialInduction
    prob['generatorEfficiency'] = generatorEfficiency
    prob['windSpeeds'] = windSpeeds
    prob['air_density'] = air_density
    prob['windDirections'] = windDirections
    prob['windFrequencies'] = windFrequencies
    prob['Ct_in'] = Ct
    prob['Cp_in'] = Cp
    prob['cp_curve_cp'] = cp_curve_cp
    prob['cp_curve_wind_speed'] = cp_curve_wind_speed
    cutInSpeeds = np.ones(nTurbines) * cut_in_speed
    prob['cut_in_speed'] = cutInSpeeds
    ratedPowers = np.ones(nTurbines) * rated_power
    prob['rated_power'] = ratedPowers

    # assign values to turbine states
    prob['cut_in_speed'] = np.ones(nTurbines) * cut_in_speed
    prob['cut_out_speed'] = np.ones(nTurbines) * cut_out_speed
    prob['rated_power'] = np.ones(nTurbines) * rated_power
    prob['rated_wind_speed'] = np.ones(nTurbines) * rated_wind_speed
    prob['use_power_curve_definition'] = True

    # assign boundary values
    # prob['boundary_center'] = np.array([boundary_center_x, boundary_center_y])
    # prob['boundary_radius'] = boundary_radius

    if MODELS[model] == 'BPA':
        prob['model_params:wake_combination_method'] = np.copy(
            wake_combination_method)
        prob['model_params:ti_calculation_method'] = np.copy(
            ti_calculation_method)
        prob['model_params:wake_model_version'] = np.copy(wake_model_version)
        prob['model_params:wec_factor'] = 1.0
        prob['model_params:wec_spreading_angle'] = 0.0
        prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)
        prob['model_params:sort'] = np.copy(sort_turbs)
        prob['model_params:z_ref'] = np.copy(z_ref)
        prob['model_params:z_0'] = np.copy(z_0)
        prob['model_params:ky'] = np.copy(k_calc)
        prob['model_params:kz'] = np.copy(k_calc)
        prob['model_params:print_ti'] = np.copy(print_ti)
        prob['model_params:shear_exp'] = np.copy(shear_exp)
        prob['model_params:I'] = np.copy(TI)
        prob['model_params:sm_smoothing'] = np.copy(sm_smoothing)
        prob['model_params:WECH'] = WECH
        if nRotorPoints > 1:
            prob['model_params:RotorPointsY'], prob[
                'model_params:RotorPointsZ'] = sunflower_points(nRotorPoints)

    modelruns = 0
    prob.run_model(case_prefix='ModelRun%i' % modelruns)
    AEP_init_calc = np.copy(prob['AEP'])
    print(AEP_init_calc * 1E-6)

    if MODELS[model] == 'BPA':
        prob['model_params:ti_calculation_method'] = np.copy(ti_opt_method)
        prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)

    modelruns += 1
    prob.run_model(case_prefix='ModelRun%i' % modelruns)
    AEP_init_opt = np.copy(prob['AEP'])
    AEP_run_opt = np.copy(AEP_init_opt)
    print(AEP_init_opt * 1E-6)

    config.obj_func_calls_array[:] = 0.0
    config.sens_func_calls_array[:] = 0.0

    expansion_factor_last = 0.0
    driverruns = 0
    tict = time.time()
    if relax:
        for expansion_factor, i in zip(
                expansion_factors,
                np.arange(0, expansion_factors.size)):  # best so far
            # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array))
            # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array))
            # AEP_init_run_opt = prob['AEP']

            if expansion_factor_last == expansion_factor:
                ti_opt_method = np.copy(final_ti_opt_method)
                calc_k_star_opt = True

            print("starting run with exp. fac = ", expansion_factor)

            if opt_algorithm == 'snopt':

                # adjust convergence tolerance
                prob.driver.opt_settings['Major optimality tolerance'] = float(
                    conv_tols[i])
                prob.driver.opt_settings['Print file'] = output_directory + \
                                                         'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % (
                                                             nTurbs, wind_rose_file, size, MODELS[model], run_number,
                                                             expansion_factor, ti_opt_method)

                prob.driver.opt_settings['Summary file'] = output_directory + \
                                                           'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f_TItype%i.out' % (
                                                               nTurbs, wind_rose_file, size, MODELS[model], run_number,
                                                               expansion_factor, ti_opt_method)
            elif opt_algorithm == 'ps':
                prob.driver.opt_settings[
                    'filename'] = output_directory + 'ALPSO_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i.out' % (
                        nTurbs, wind_rose_file, size, MODELS[model],
                        run_number)

            turbineX = np.copy(prob['turbineX'])
            turbineY = np.copy(prob['turbineY'])
            prob['turbineX'] = np.copy(turbineX)
            prob['turbineY'] = np.copy(turbineY)

            if MODELS[model] == 'BPA':
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_opt_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)
                if wec_method == 'diam':
                    prob['model_params:wec_factor'] = np.copy(expansion_factor)
                elif wec_method == "hybrid":
                    prob['model_params:wec_factor'] = np.copy(expansion_factor)
                elif wec_method == 'angle':
                    prob['model_params:wec_spreading_angle'] = np.copy(
                        expansion_factor)

            # run the problem
            print('start %s run' % (MODELS[model]))
            tic = time.time()
            # iprofile.start()
            config.obj_func_calls_array[prob.comm.rank] = 0.0
            config.sens_func_calls_array[prob.comm.rank] = 0.0
            prob.run_driver(case_prefix='DriverRun%i' % driverruns)
            driverruns += 1
            # quit()
            toc = time.time()
            obj_calls = np.copy(config.obj_func_calls_array[0])
            sens_calls = np.copy(config.sens_func_calls_array[0])
            # iprofile.stop()
            toc = time.time()
            # print(np.sum(config.obj_func_calls_array))
            # print(np.sum(config.sens_func_calls_array))
            print('end %s run' % (MODELS[model]))

            run_time = toc - tic
            # print(run_time, expansion_factor)

            AEP_run_opt = np.copy(prob['AEP'])
            # print("AEP improvement = ", AEP_run_opt / AEP_init_opt)

            if MODELS[model] == 'BPA':
                prob['model_params:wec_factor'] = 1.0
                prob['model_params:wec_spreading_angle'] = 0.0
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_calculation_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)

            modelruns += 1
            prob.run_model(case_prefix='ModelRun%i' % modelruns)
            AEP_run_calc = np.copy(prob['AEP'])
            # print("compare: ", aep_run, prob['AEP'])
            print("AEP calc improvement = ", AEP_run_calc / AEP_init_calc)

            if prob.model.comm.rank == 0:
                # if save_aep:
                #     np.savetxt(output_directory + '%s_multistart_aep_results_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_EF%.3f.txt' % (
                #         opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor),
                #                np.c_[AEP_init, prob['AEP']],
                #                header="Initial AEP, Final AEP")
                if save_locations:
                    np.savetxt(
                        output_directory +
                        '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f_TItype%i.txt'
                        % (opt_algorithm, nTurbs, wind_rose_file, size,
                           MODELS[model], run_number, expansion_factor,
                           ti_opt_method),
                        np.c_[turbineX_init, turbineY_init, prob['turbineX'],
                              prob['turbineY']],
                        header=
                        "initial turbineX, initial turbineY, final turbineX, final turbineY"
                    )
                # if save_time:
                #     np.savetxt(output_directory + '%s_multistart_time_%iturbs_%sWindRose_%idirs_%s_run%i_EF%.3f.txt' % (
                #         opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, expansion_factor),
                #                np.c_[run_time],
                #                header="run time")
                if save_time and save_aep and rec_func_calls:
                    output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i.txt' \
                                  % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number)
                    f = open(output_file, "a")

                    if i == 0:
                        header = "run number, exp fac, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \
                                 "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls"
                    else:
                        header = ''

                    np.savetxt(f,
                               np.c_[run_number, expansion_factor,
                                     ti_calculation_method, ti_opt_method,
                                     AEP_init_calc, AEP_init_opt, AEP_run_calc,
                                     AEP_run_opt, run_time, obj_calls,
                                     sens_calls],
                               header=header)
                    f.close()
            expansion_factor_last = expansion_factor
            #
            # cr = om.CaseReader(output_directory + 'recorded_data.sql')
            #
            # driver_cases = cr.list_cases('driver')
            # nits = len(driver_cases)
            # objectives = np.zeros(nits)
            # calls = np.zeros(nits)
            # for i in np.arange(0, nits):
            #     case = cr.get_case(driver_cases[i])
            #     print(case)
            #     objectives[i] = np.copy(case['obj'])
            #     calls[i] = i
            # plt.plot(objectives)
            # plt.scatter(calls, objectives)
            # plt.show()

    else:
        for expansion_factor, i in zip(
                expansion_factors,
                np.arange(0, expansion_factors.size)):  # best so far
            # print("func calls: ", config.obj_func_calls_array, np.sum(config.obj_func_calls_array))
            # print("grad func calls: ", config.sens_func_calls_array, np.sum(config.sens_func_calls_array))
            # AEP_init_run_opt = prob['AEP']

            if expansion_factor_last == expansion_factor:
                ti_opt_method = np.copy(final_ti_opt_method)
                calc_k_star_opt = True

            if opt_algorithm == 'snopt':
                prob.driver.opt_settings['Major optimality tolerance'] = float(
                    conv_tols[i])
                prob.driver.opt_settings['Print file'] = output_directory + \
                                                         'SNOPT_print_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % (
                                                             nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)

                prob.driver.opt_settings['Summary file'] = output_directory + \
                                                           'SNOPT_summary_multistart_%iturbs_%sWindRose_%idirs_%sModel_RunID%i_TItype%i.out' % (
                                                               nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)

            print("starting run with exp. fac = ", expansion_factor)
            # run the problem
            print('start %s run' % (MODELS[model]))
            # cProfile.run('prob.run_driver()')
            if MODELS[model] == 'BPA':
                # prob['model_params:wec_factor'] = 1.
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_opt_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_opt)
            tic = time.time()
            # cProfile.run('prob.run_driver()')
            config.obj_func_calls_array[prob.comm.rank] = 0.0
            config.sens_func_calls_array[prob.comm.rank] = 0.0
            prob.run_driver(case_prefix='DriverRun%i' % driverruns)
            driverruns += 1
            # quit()
            toc = time.time()
            obj_calls = np.copy(config.obj_func_calls_array[0])
            sens_calls = np.copy(config.sens_func_calls_array[0])

            run_time = toc - tic

            AEP_run_opt = np.copy(prob['AEP'])
            # print("AEP improvement = ", AEP_run_calc / AEP_init_calc)

            if MODELS[model] == 'BPA':
                prob['model_params:wec_factor'] = 1.0
                prob['model_params:wec_spreading_angle'] = 0.0
                prob['model_params:ti_calculation_method'] = np.copy(
                    ti_calculation_method)
                prob['model_params:calc_k_star'] = np.copy(calc_k_star_calc)

            modelruns += 1
            prob.run_model(case_prefix='ModelRun%i' % modelruns)
            AEP_run_calc = np.copy(prob['AEP'])

            if prob.model.comm.rank == 0:

                if save_locations:
                    np.savetxt(
                        output_directory +
                        '%s_multistart_locations_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt'
                        % (opt_algorithm, nTurbs, wind_rose_file, size,
                           MODELS[model], run_number, ti_opt_method),
                        np.c_[turbineX_init, turbineY_init, prob['turbineX'],
                              prob['turbineY']],
                        header=
                        "initial turbineX, initial turbineY, final turbineX, final turbineY"
                    )

                if save_time and save_aep and rec_func_calls:
                    output_file = output_directory + '%s_multistart_rundata_%iturbs_%sWindRose_%idirs_%s_run%i_TItype%i.txt' \
                                  % (opt_algorithm, nTurbs, wind_rose_file, size, MODELS[model], run_number, ti_opt_method)
                    f = open(output_file, "a")

                    header = "run number, ti calc, ti opt, aep init calc (kW), aep init opt (kW), " \
                             "aep run calc (kW), aep run opt (kW), run time (s), obj func calls, sens func calls"

                    np.savetxt(f,
                               np.c_[run_number, ti_calculation_method,
                                     ti_opt_method, AEP_init_calc,
                                     AEP_init_opt, AEP_run_calc, AEP_run_opt,
                                     run_time, obj_calls, sens_calls],
                               header=header)
                    f.close()
            expansion_factor_last = expansion_factor

    turbineX_end = np.copy(prob['turbineX'])
    turbineY_end = np.copy(prob['turbineY'])

    toct = time.time()
    total_time = toct - tict

    if prob.model.comm.rank == 0:

        # print the results
        print(('Opt. calculation took %.03f sec.' % (toct - tict)))

        for direction_id in range(0, windDirections.size):
            print('yaw%i (deg) = ' % direction_id,
                  prob['yaw%i' % direction_id])

        print('turbine X positions in wind frame (m): %s' % prob['turbineX'])
        print('turbine Y positions in wind frame (m): %s' % prob['turbineY'])
        print('wind farm power in each direction (kW): %s' % prob['dirPowers'])
        print('Initial AEP (kWh): %s' % AEP_init_opt)
        print('Final AEP (kWh): %s' % AEP_run_calc)
        print('AEP improvement: %s' % (AEP_run_calc / AEP_init_calc))

    if show_end:
        plot_square_farm(turbineX_end,
                         turbineY_end,
                         rotor_diameter,
                         boundary_x,
                         boundary_y,
                         boundary_x[1] - boundary_x[0],
                         show_start=show_start)

    prob.cleanup()

    if MODELS[model] == 'BPA':
        prob['model_params:wec_factor'] = 1.0
        prob['model_params:wec_spreading_angle'] = 0.0
        prob['model_params:ti_calculation_method'] = 4
        prob['model_params:calc_k_star'] = True

    cr = om.CaseReader(output_directory +
                       'recorded_data_driver_%s.sql' % run_number)

    driver_cases = cr.list_cases('driver')
    nits = len(driver_cases)
    objectives = np.zeros(nits)
    AEPopt = np.zeros(nits)
    AEPcalc = np.zeros(nits)
    calls = np.zeros(nits)
    for i in np.arange(0, nits):
        case = cr.get_case(driver_cases[i])
        # print(case)
        AEPopt[i] = case['AEP']
        objectives[i] = case.get_objectives()['obj']

        prob['turbineX'] = np.copy(case['turbineX'])
        prob['turbineY'] = np.copy(case['turbineY'])
        if opt_algorithm == "snopt":
            prob.run_model(case_prefix='ProcessingRun')
            AEPcalc[i] = np.copy(prob['AEP'])
        else:
            AEPcalc[i] = case['AEP']

        calls[i] = i
Ejemplo n.º 29
0
    def test_finite_burn_orbit_raise(self):

        p = om.Problem(model=om.Group())

        p.driver = om.pyOptSparseDriver()
        p.driver.options['optimizer'] = 'SLSQP'
        p.driver.declare_coloring()

        traj = dm.Trajectory()

        traj.add_design_parameter('c',
                                  opt=False,
                                  val=1.5,
                                  units='DU/TU',
                                  targets={
                                      'burn1': ['c'],
                                      'coast': ['c'],
                                      'burn2': ['c']
                                  })

        # First Phase (burn)

        burn1 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5,
                                                       order=3,
                                                       compressed=False))

        burn1 = traj.add_phase('burn1', burn1)

        burn1.set_time_options(fix_initial=True,
                               duration_bounds=(.5, 10),
                               units='TU')
        burn1.add_state('r',
                        fix_initial=True,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        burn1.add_state('theta',
                        fix_initial=True,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='theta_dot',
                        targets=['theta'],
                        units='rad')
        burn1.add_state('vr',
                        fix_initial=True,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        burn1.add_state('vt',
                        fix_initial=True,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        burn1.add_state('accel',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        burn1.add_state('deltav',
                        fix_initial=True,
                        fix_final=False,
                        rate_source='deltav_dot',
                        units='DU/TU')
        burn1.add_control('u1',
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          scaler=0.01,
                          rate_continuity_scaler=0.001,
                          rate2_continuity_scaler=0.001,
                          lower=-30,
                          upper=30,
                          targets=['u1'])
        # Second Phase (Coast)
        coast = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5,
                                                       order=3,
                                                       compressed=False))

        coast.set_time_options(initial_bounds=(0.5, 20),
                               duration_bounds=(.5, 50),
                               duration_ref=50,
                               units='TU')
        coast.add_state('r',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        coast.add_state('theta',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='theta_dot',
                        targets=['theta'],
                        units='rad')
        coast.add_state('vr',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        coast.add_state('vt',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        coast.add_state('accel',
                        fix_initial=True,
                        fix_final=True,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        coast.add_state('deltav',
                        fix_initial=False,
                        fix_final=False,
                        rate_source='deltav_dot',
                        units='DU/TU')

        coast.add_design_parameter('u1',
                                   opt=False,
                                   val=0.0,
                                   units='deg',
                                   targets=['u1'])

        # Third Phase (burn)
        burn2 = dm.Phase(ode_class=FiniteBurnODE,
                         transcription=dm.GaussLobatto(num_segments=5,
                                                       order=3,
                                                       compressed=False))

        traj.add_phase('coast', coast)
        traj.add_phase('burn2', burn2)

        burn2.set_time_options(initial_bounds=(0.5, 50),
                               duration_bounds=(.5, 10),
                               initial_ref=10,
                               units='TU')
        burn2.add_state('r',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=100.0,
                        rate_source='r_dot',
                        targets=['r'],
                        units='DU')
        burn2.add_state('theta',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=100.0,
                        rate_source='theta_dot',
                        targets=['theta'],
                        units='rad')
        burn2.add_state('vr',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=1000.0,
                        rate_source='vr_dot',
                        targets=['vr'],
                        units='DU/TU')
        burn2.add_state('vt',
                        fix_initial=False,
                        fix_final=True,
                        defect_scaler=1000.0,
                        rate_source='vt_dot',
                        targets=['vt'],
                        units='DU/TU')
        burn2.add_state('accel',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=1.0,
                        rate_source='at_dot',
                        targets=['accel'],
                        units='DU/TU**2')
        burn2.add_state('deltav',
                        fix_initial=False,
                        fix_final=False,
                        defect_scaler=1.0,
                        rate_source='deltav_dot',
                        units='DU/TU')

        burn2.add_objective('deltav', loc='final', scaler=100.0)

        burn2.add_control('u1',
                          rate_continuity=True,
                          rate2_continuity=True,
                          units='deg',
                          scaler=0.01,
                          lower=-90,
                          upper=90,
                          targets=['u1'])

        burn1.add_timeseries_output('pos_x', units='DU')
        coast.add_timeseries_output('pos_x', units='DU')
        burn2.add_timeseries_output('pos_x', units='DU')

        burn1.add_timeseries_output('pos_y', units='DU')
        coast.add_timeseries_output('pos_y', units='DU')
        burn2.add_timeseries_output('pos_y', units='DU')

        # Link Phases
        traj.link_phases(phases=['burn1', 'coast', 'burn2'],
                         vars=['time', 'r', 'theta', 'vr', 'vt', 'deltav'])

        traj.link_phases(phases=['burn1', 'burn2'], vars=['accel'])

        p.model.add_subsystem('traj', subsys=traj)

        # Finish Problem Setup

        # Needed to move the direct solver down into the phases for use with MPI.
        #  - After moving down, used fewer iterations (about 30 less)

        p.driver.add_recorder(
            om.SqliteRecorder('two_burn_orbit_raise_example.db'))

        p.setup(check=True, mode='fwd')

        # Set Initial Guesses
        p.set_val('traj.design_parameters:c', value=1.5, units='DU/TU')

        burn1 = p.model.traj.phases.burn1
        burn2 = p.model.traj.phases.burn2
        coast = p.model.traj.phases.coast

        p.set_val('traj.burn1.t_initial', value=0.0)
        p.set_val('traj.burn1.t_duration', value=2.25)
        p.set_val('traj.burn1.states:r',
                  value=burn1.interpolate(ys=[1, 1.5], nodes='state_input'))
        p.set_val('traj.burn1.states:theta',
                  value=burn1.interpolate(ys=[0, 1.7], nodes='state_input'))
        p.set_val('traj.burn1.states:vr',
                  value=burn1.interpolate(ys=[0, 0], nodes='state_input'))
        p.set_val('traj.burn1.states:vt',
                  value=burn1.interpolate(ys=[1, 1], nodes='state_input'))
        p.set_val('traj.burn1.states:accel',
                  value=burn1.interpolate(ys=[0.1, 0], nodes='state_input'))
        p.set_val('traj.burn1.states:deltav',
                  value=burn1.interpolate(ys=[0, 0.1], nodes='state_input'))
        p.set_val('traj.burn1.controls:u1',
                  value=burn1.interpolate(ys=[-3.5, 13.0],
                                          nodes='control_input'))

        p.set_val('traj.coast.t_initial', value=2.25)
        p.set_val('traj.coast.t_duration', value=3.0)

        p.set_val('traj.coast.states:r',
                  value=coast.interpolate(ys=[1.3, 1.5], nodes='state_input'))
        p.set_val('traj.coast.states:theta',
                  value=coast.interpolate(ys=[2.1767, 1.7],
                                          nodes='state_input'))

        p.set_val('traj.coast.states:vr',
                  value=coast.interpolate(ys=[0.3285, 0], nodes='state_input'))
        p.set_val('traj.coast.states:vt',
                  value=coast.interpolate(ys=[0.97, 1], nodes='state_input'))
        p.set_val('traj.coast.states:accel',
                  value=coast.interpolate(ys=[0, 0], nodes='state_input'))

        p.set_val('traj.burn2.t_initial', value=5.25)
        p.set_val('traj.burn2.t_duration', value=1.75)

        p.set_val('traj.burn2.states:r',
                  value=burn2.interpolate(ys=[1, 3.], nodes='state_input'))
        p.set_val('traj.burn2.states:theta',
                  value=burn2.interpolate(ys=[0, 4.0], nodes='state_input'))
        p.set_val('traj.burn2.states:vr',
                  value=burn2.interpolate(ys=[0, 0], nodes='state_input'))
        p.set_val('traj.burn2.states:vt',
                  value=burn2.interpolate(ys=[1, np.sqrt(1 / 3.)],
                                          nodes='state_input'))
        p.set_val('traj.burn2.states:deltav',
                  value=burn2.interpolate(ys=[0.1, 0.2], nodes='state_input'))
        p.set_val('traj.burn2.states:accel',
                  value=burn2.interpolate(ys=[0.1, 0], nodes='state_input'))

        p.set_val('traj.burn2.controls:u1',
                  value=burn2.interpolate(ys=[0, 0], nodes='control_input'))

        dm.run_problem(p)

        assert_rel_error(self,
                         p.get_val('traj.burn2.states:deltav')[-1],
                         0.3995,
                         tolerance=2.0E-3)

        #
        # Plot results
        #
        traj = p.model.traj
        exp_out = traj.simulate()

        fig = plt.figure(figsize=(8, 4))
        fig.suptitle('Two Burn Orbit Raise Solution')
        ax_u1 = plt.subplot2grid((2, 2), (0, 0))
        ax_deltav = plt.subplot2grid((2, 2), (1, 0))
        ax_xy = plt.subplot2grid((2, 2), (0, 1), rowspan=2)

        span = np.linspace(0, 2 * np.pi, 100)
        ax_xy.plot(np.cos(span), np.sin(span), 'k--', lw=1)
        ax_xy.plot(3 * np.cos(span), 3 * np.sin(span), 'k--', lw=1)
        ax_xy.set_xlim(-4.5, 4.5)
        ax_xy.set_ylim(-4.5, 4.5)

        ax_xy.set_xlabel('x ($R_e$)')
        ax_xy.set_ylabel('y ($R_e$)')

        ax_u1.set_xlabel('time ($TU$)')
        ax_u1.set_ylabel('$u_1$ ($deg$)')
        ax_u1.grid(True)

        ax_deltav.set_xlabel('time ($TU$)')
        ax_deltav.set_ylabel('${\Delta}v$ ($DU/TU$)')
        ax_deltav.grid(True)

        t_sol = dict((phs, p.get_val('traj.{0}.timeseries.time'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        x_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        y_sol = dict((phs, p.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
                     for phs in ['burn1', 'coast', 'burn2'])
        dv_sol = dict(
            (phs, p.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        u1_sol = dict((phs,
                       p.get_val('traj.{0}.timeseries.controls:u1'.format(phs),
                                 units='deg')) for phs in ['burn1', 'burn2'])

        t_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.time'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        x_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.pos_x'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        y_exp = dict(
            (phs, exp_out.get_val('traj.{0}.timeseries.pos_y'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        dv_exp = dict(
            (phs,
             exp_out.get_val('traj.{0}.timeseries.states:deltav'.format(phs)))
            for phs in ['burn1', 'coast', 'burn2'])
        u1_exp = dict(
            (phs,
             exp_out.get_val('traj.{0}.timeseries.controls:u1'.format(phs),
                             units='deg')) for phs in ['burn1', 'burn2'])

        for phs in ['burn1', 'coast', 'burn2']:
            try:
                ax_u1.plot(t_exp[phs],
                           u1_exp[phs],
                           '-',
                           marker=None,
                           color='C0')
                ax_u1.plot(t_sol[phs],
                           u1_sol[phs],
                           'o',
                           mfc='C1',
                           mec='C1',
                           ms=3)
            except KeyError:
                pass

            ax_deltav.plot(t_exp[phs],
                           dv_exp[phs],
                           '-',
                           marker=None,
                           color='C0')
            ax_deltav.plot(t_sol[phs],
                           dv_sol[phs],
                           'o',
                           mfc='C1',
                           mec='C1',
                           ms=3)

            ax_xy.plot(x_exp[phs],
                       y_exp[phs],
                       '-',
                       marker=None,
                       color='C0',
                       label='explicit')
            ax_xy.plot(x_sol[phs],
                       y_sol[phs],
                       'o',
                       mfc='C1',
                       mec='C1',
                       ms=3,
                       label='implicit')

        plt.show()
Ejemplo n.º 30
0
    def test(self):
        import numpy as np

        import openmdao.api as om

        from openaerostruct.geometry.utils import generate_mesh
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.aerodynamics.aero_groups import AeroPoint

        # Create a dictionary to store options about the mesh
        mesh_dict = {
            'num_y': 7,
            'num_x': 2,
            'wing_type': 'CRM',
            'symmetry': True,
            'num_twist_cp': 5
        }

        # Generate the aerodynamic mesh based on the previous dictionary
        mesh, twist_cp = generate_mesh(mesh_dict)

        # Create a dictionary with info and options about the aerodynamic
        # lifting surface
        surface = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'symmetry': True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'S_ref_type': 'wetted',  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            'fem_model_type': 'tube',
            'twist_cp': twist_cp,
            'mesh': mesh,

            # Aerodynamic performance of the lifting surface at
            # an angle of attack of 0 (alpha=0).
            # These CL0 and CD0 values are added to the CL and CD
            # obtained from aerodynamic analysis of the surface to get
            # the total CL and CD.
            # These CL0 and CD0 values do not vary wrt alpha.
            'CL0': 0.0,  # CL of the surface at alpha=0
            'CD0': 0.015,  # CD of the surface at alpha=0

            # Airfoil properties for viscous drag calculation
            'k_lam': 0.05,  # percentage of chord with laminar
            # flow, used for viscous drag
            't_over_c_cp':
            np.array([0.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': .303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,  # if true, compute viscous drag
            'with_wave': False,  # if true, compute wave drag
        }

        # Create the OpenMDAO problem
        prob = om.Problem()

        # Create an independent variable component that will supply the flow
        # conditions to the problem.
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('cg', val=np.zeros((3)), units='m')

        # Add this IndepVarComp to the problem model
        prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*'])

        # Create and add a group that handles the geometry for the
        # aerodynamic lifting surface
        geom_group = Geometry(surface=surface)
        prob.model.add_subsystem(surface['name'], geom_group)

        # Create the aero point group, which contains the actual aerodynamic
        # analyses
        aero_group = AeroPoint(surfaces=[surface])
        point_name = 'aero_point_0'
        prob.model.add_subsystem(
            point_name,
            aero_group,
            promotes_inputs=['v', 'alpha', 'Mach_number', 're', 'rho', 'cg'])

        name = surface['name']

        # Connect the mesh from the geometry component to the analysis point
        prob.model.connect(name + '.mesh',
                           point_name + '.' + name + '.def_mesh')

        # Perform the connections with the modified names within the
        # 'aero_states' group.
        prob.model.connect(name + '.mesh',
                           point_name + '.aero_states.' + name + '_def_mesh')

        prob.model.connect(name + '.t_over_c',
                           point_name + '.' + name + '_perf.' + 't_over_c')

        # Import the Scipy Optimizer and set the driver of the problem to use
        # it, which defaults to an SLSQP optimization method
        prob.driver = om.ScipyOptimizeDriver()
        prob.driver.options['tol'] = 1e-9

        recorder = om.SqliteRecorder("aero.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True
        prob.driver.recording_options['includes'] = ['*']

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.)
        prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5)
        prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4)

        # Set up and run the optimization problem
        prob.setup()
        # prob.check_partials(compact_print=True)
        # exit()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],
                         0.033389699871650073, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -1.7885550372372376,
                         1e-6)