def test_betz_derivatives(self): import openmdao.api as om from openmdao.test_suite.test_examples.test_betz_limit import ActuatorDisc prob = om.Problem() prob.model.add_subsystem('a_disk', ActuatorDisc()) prob.setup() prob.check_partials(compact_print=True)
def problem_init(): prob = Problem() indeps = prob.model.add_subsystem("indeps", IndepVarComp(), promotes=["*"]) indeps.add_output("a", 0.5) indeps.add_output("Area", 10.0, units="m**2") indeps.add_output("rho", 1.225, units="kg/m**3") indeps.add_output("Vu", 10.0, units="m/s") prob.model.add_subsystem("a_disk", ActuatorDisc(), promotes=["*"]) # setup the optimization prob.driver = ScipyOptimizeDriver() prob.driver.options["optimizer"] = "SLSQP" prob.model.add_design_var("a", lower=0.0, upper=1.0) prob.model.add_design_var("Area", lower=0.0, upper=1.0) # negative one so we maximize the objective prob.model.add_objective("Cp", scaler=-1) prob.setup() prob.final_setup() return prob
def test_model_viewer_has_correct_data_from_optimization_problem(self): """ Verify that the correct model structure data exists when stored as compared to the expected structure, using the ActuatorDisc model. """ # build the model prob = Problem() indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*']) indeps.add_output('a', .5) indeps.add_output('Area', 10.0, units='m**2') indeps.add_output('rho', 1.225, units='kg/m**3') indeps.add_output('Vu', 10.0, units='m/s') prob.model.add_subsystem('a_disk', ActuatorDisc(), promotes_inputs=['a', 'Area', 'rho', 'Vu']) # setup the optimization prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.model.add_design_var('a', lower=0., upper=1.) prob.model.add_design_var('Area', lower=0., upper=1.) # negative one so we maximize the objective prob.model.add_objective('a_disk.Cp', scaler=-1) prob.setup() prob.final_setup() model_viewer_data = _get_viewer_data(prob) expected_tree_betz = json.loads(""" {"name": "root", "type": "root", "class": "Group", "component_type": null, "subsystem_type": "group", "is_parallel": false, "linear_solver": "LN: RUNONCE", "nonlinear_solver": "NL: RUNONCE", "children": [ {"name": "indeps", "type": "subsystem", "class": "IndepVarComp", "subsystem_type": "component", "is_parallel": false, "component_type": "indep", "linear_solver": "", "nonlinear_solver": "", "children": [ {"name": "a", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "Area", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "rho", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "Vu", "type": "unknown", "implicit": false, "dtype": "ndarray"}]}, {"name": "a_disk", "type": "subsystem", "class": "ActuatorDisc", "subsystem_type": "component", "is_parallel": false, "component_type": "explicit", "linear_solver": "", "nonlinear_solver": "", "children": [{"name": "a", "type": "param", "dtype": "ndarray"}, {"name": "Area", "type": "param", "dtype": "ndarray"}, {"name": "rho", "type": "param", "dtype": "ndarray"}, {"name": "Vu", "type": "param", "dtype": "ndarray"}, {"name": "Vr", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "Vd", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "Ct", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "thrust", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "Cp", "type": "unknown", "implicit": false, "dtype": "ndarray"}, {"name": "power", "type": "unknown", "implicit": false, "dtype": "ndarray"}]}]} """) expected_pathnames_betz = json.loads('[]') expected_conns_betz = json.loads(""" [{"src": "indeps.a", "tgt": "a_disk.a"}, {"src": "indeps.Area", "tgt": "a_disk.Area"}, {"src": "indeps.rho", "tgt": "a_disk.rho"}, {"src": "indeps.Vu", "tgt": "a_disk.Vu"}] """) expected_abs2prom_betz = json.loads(""" {"input": {"a_disk.a": "a", "a_disk.Area": "Area", "a_disk.rho": "rho", "a_disk.Vu": "Vu"}, "output": {"indeps.a": "a", "indeps.Area": "Area", "indeps.rho": "rho", "indeps.Vu": "Vu", "a_disk.Vr": "a_disk.Vr", "a_disk.Vd": "a_disk.Vd", "a_disk.Ct": "a_disk.Ct", "a_disk.thrust": "a_disk.thrust", "a_disk.Cp": "a_disk.Cp", "a_disk.power": "a_disk.power"}} """) expected_declare_partials_betz = json.loads(""" ["indeps.a > indeps.a", "indeps.Area > indeps.Area", "indeps.rho > indeps.rho", "indeps.Vu > indeps.Vu", "a_disk.Vr > a_disk.a", "a_disk.Vr > a_disk.Vu", "a_disk.Vd > a_disk.a", "a_disk.Ct > a_disk.a", "a_disk.thrust > a_disk.a", "a_disk.thrust > a_disk.Area", "a_disk.thrust > a_disk.rho", "a_disk.thrust > a_disk.Vu", "a_disk.Cp > a_disk.a", "a_disk.power > a_disk.a", "a_disk.power > a_disk.Area", "a_disk.power > a_disk.rho", "a_disk.power > a_disk.Vu", "a_disk.Vr > a_disk.Vr", "a_disk.Vd > a_disk.Vd", "a_disk.Ct > a_disk.Ct", "a_disk.thrust > a_disk.thrust", "a_disk.Cp > a_disk.Cp", "a_disk.power > a_disk.power"] """) expected_driver_name = 'ScipyOptimizeDriver' expected_design_vars_names = ['indeps.a', 'indeps.Area'] expected_responses_names = [ 'a_disk.Cp', ] # check expected model tree self.check_model_viewer_data( model_viewer_data, expected_tree_betz, expected_pathnames_betz, expected_conns_betz, expected_abs2prom_betz, expected_declare_partials_betz, expected_driver_name, expected_design_vars_names, expected_responses_names, )
def test_betz(self): from openmdao.api import Problem, ScipyOptimizeDriver, IndepVarComp, ExplicitComponent class ActuatorDisc(ExplicitComponent): """Simple wind turbine model based on actuator disc theory""" def setup(self): # Inputs self.add_input('a', 0.5, desc="Induced Velocity Factor") self.add_input('Area', 10.0, units="m**2", desc="Rotor disc area") self.add_input('rho', 1.225, units="kg/m**3", desc="air density") self.add_input('Vu', 10.0, units="m/s", desc="Freestream air velocity, upstream of rotor") # Outputs self.add_output('Vr', 0.0, units="m/s", desc="Air velocity at rotor exit plane") self.add_output('Vd', 0.0, units="m/s", desc="Slipstream air velocity, downstream of rotor") self.add_output('Ct', 0.0, desc="Thrust Coefficient") self.add_output('thrust', 0.0, units="N", desc="Thrust produced by the rotor") self.add_output('Cp', 0.0, desc="Power Coefficient") self.add_output('power', 0.0, units="W", desc="Power produced by the rotor") self.declare_partials('Vr', ['a', 'Vu']) self.declare_partials('Vd', 'a') self.declare_partials('Ct', 'a') self.declare_partials('thrust', ['a', 'Area', 'rho', 'Vu']) self.declare_partials('Cp', 'a') self.declare_partials('power', ['a', 'Area', 'rho', 'Vu']) def compute(self, inputs, outputs): """ Considering the entire rotor as a single disc that extracts velocity uniformly from the incoming flow and converts it to power.""" a = inputs['a'] Vu = inputs['Vu'] qA = .5 * inputs['rho'] * inputs['Area'] * Vu ** 2 outputs['Vd'] = Vd = Vu * (1 - 2 * a) outputs['Vr'] = .5 * (Vu + Vd) outputs['Ct'] = Ct = 4 * a * (1 - a) outputs['thrust'] = Ct * qA outputs['Cp'] = Cp = Ct * (1 - a) outputs['power'] = Cp * qA * Vu def compute_partials(self, inputs, J): """ Jacobian of partial derivatives.""" a = inputs['a'] Vu = inputs['Vu'] Area = inputs['Area'] rho = inputs['rho'] # pre-compute commonly needed quantities a_times_area = a * Area one_minus_a = 1.0 - a a_area_rho_vu = a_times_area * rho * Vu J['Vr', 'a'] = -Vu J['Vr', 'Vu'] = one_minus_a J['Vd', 'a'] = -2.0 * Vu J['Ct', 'a'] = 4.0 - 8.0 * a J['thrust', 'a'] = .5 * rho * Vu**2 * Area * J['Ct', 'a'] J['thrust', 'Area'] = 2.0 * Vu**2 * a * rho * one_minus_a J['thrust', 'rho'] = 2.0 * a_times_area * Vu ** 2 * (one_minus_a) J['thrust', 'Vu'] = 4.0 * a_area_rho_vu * (one_minus_a) J['Cp', 'a'] = 4.0 * a * (2.0 * a - 2.0) + 4.0 * (one_minus_a)**2 J['power', 'a'] = 2.0 * Area * Vu**3 * a * rho * ( 2.0 * a - 2.0) + 2.0 * Area * Vu**3 * rho * one_minus_a ** 2 J['power', 'Area'] = 2.0 * Vu**3 * a * rho * one_minus_a ** 2 J['power', 'rho'] = 2.0 * a_times_area * Vu ** 3 * (one_minus_a)**2 J['power', 'Vu'] = 6.0 * Area * Vu**2 * a * rho * one_minus_a**2 # build the model prob = Problem() indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*']) indeps.add_output('a', .5) indeps.add_output('Area', 10.0, units='m**2') indeps.add_output('rho', 1.225, units='kg/m**3') indeps.add_output('Vu', 10.0, units='m/s') prob.model.add_subsystem('a_disk', ActuatorDisc(), promotes_inputs=['a', 'Area', 'rho', 'Vu']) # setup the optimization prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.model.add_design_var('a', lower=0., upper=1.) prob.model.add_design_var('Area', lower=0., upper=1.) # negative one so we maximize the objective prob.model.add_objective('a_disk.Cp', scaler=-1) prob.setup() prob.run_driver() # minimum value assert_rel_error(self, prob['a_disk.Cp'], 16./27., 1e-4) assert_rel_error(self, prob['a'], 0.33333, 1e-4)
def test_model_viewer_has_correct_data_from_optimization_problem(self): """ Verify that the correct model structure data exists when stored as compared to the expected structure, using the ActuatorDisc model. """ # build the model prob = om.Problem() indeps = prob.model.add_subsystem('indeps', om.IndepVarComp(), promotes=['*']) indeps.add_output('a', .5) indeps.add_output('Area', 10.0, units='m**2') indeps.add_output('rho', 1.225, units='kg/m**3') indeps.add_output('Vu', 10.0, units='m/s') prob.model.add_subsystem('a_disk', ActuatorDisc(), promotes_inputs=['a', 'Area', 'rho', 'Vu']) # setup the optimization prob.driver = om.ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.model.add_design_var('a', lower=0., upper=1.) prob.model.add_design_var('Area', lower=0., upper=1.) # negative one so we maximize the objective prob.model.add_objective('a_disk.Cp', scaler=-1) prob.setup() prob.final_setup() model_viewer_data = _get_viewer_data(prob) # To generate the reference JSON file, use this code # from openmdao.utils.testing_utils import _ModelViewerDataTreeEncoder # with open('betz_tree_new.json', 'w') as outfile: # json.dump(model_viewer_data['tree'], outfile,cls=_ModelViewerDataTreeEncoder, indent=4) with open(os.path.join(self.parent_dir, 'betz_tree.json')) as json_file: expected_tree_betz = json.load(json_file) expected_pathnames_betz = json.loads('[]') expected_conns_betz = json.loads(""" [{"src": "indeps.a", "tgt": "a_disk.a"}, {"src": "indeps.Area", "tgt": "a_disk.Area"}, {"src": "indeps.rho", "tgt": "a_disk.rho"}, {"src": "indeps.Vu", "tgt": "a_disk.Vu"}] """) expected_abs2prom_betz = json.loads(""" {"input": {"a_disk.a": "a", "a_disk.Area": "Area", "a_disk.rho": "rho", "a_disk.Vu": "Vu"}, "output": {"indeps.a": "a", "indeps.Area": "Area", "indeps.rho": "rho", "indeps.Vu": "Vu", "a_disk.Vr": "a_disk.Vr", "a_disk.Vd": "a_disk.Vd", "a_disk.Ct": "a_disk.Ct", "a_disk.thrust": "a_disk.thrust", "a_disk.Cp": "a_disk.Cp", "a_disk.power": "a_disk.power"}} """) expected_declare_partials_betz = json.loads(""" ["a_disk.Vr > a_disk.a", "a_disk.Vr > a_disk.Vu", "a_disk.Vd > a_disk.a", "a_disk.Ct > a_disk.a", "a_disk.thrust > a_disk.a", "a_disk.thrust > a_disk.Area", "a_disk.thrust > a_disk.rho", "a_disk.thrust > a_disk.Vu", "a_disk.Cp > a_disk.a", "a_disk.power > a_disk.a", "a_disk.power > a_disk.Area", "a_disk.power > a_disk.rho", "a_disk.power > a_disk.Vu"] """) expected_driver_name = 'ScipyOptimizeDriver' expected_design_vars_names = ['indeps.a', 'indeps.Area'] expected_responses_names = [ 'a_disk.Cp', ] # check expected model tree self.check_model_viewer_data( model_viewer_data, expected_tree_betz, expected_pathnames_betz, expected_conns_betz, expected_abs2prom_betz, expected_declare_partials_betz, expected_driver_name, expected_design_vars_names, expected_responses_names, )