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)
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()
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()
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'))
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"
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.]))
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()
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)
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)
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))
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
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()
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)
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))
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)
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)
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)
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
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
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()
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) ])
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' ]
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)
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)
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()
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)
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
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()
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)