def test(self): import numpy as np from openmdao.api import Problem, ScipyOptimizeDriver from openmdao.test_suite.test_examples.beam_optimization.beam_group import BeamGroup E = 1. L = 1. b = 0.1 volume = 0.01 num_elements = 50 prob = Problem(model=BeamGroup(E=E, L=L, b=b, volume=volume, num_elements=num_elements)) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = True prob.setup() prob.run_driver() assert_rel_error(self, prob['inputs_comp.h'], [0.14915754, 0.14764328, 0.14611321, 0.14456715, 0.14300421, 0.14142417, 0.13982611, 0.13820976, 0.13657406, 0.13491866, 0.13324268, 0.13154528, 0.12982575, 0.12808305, 0.12631658, 0.12452477, 0.12270701, 0.12086183, 0.11898809, 0.11708424, 0.11514904, 0.11318072, 0.11117762, 0.10913764, 0.10705891, 0.10493903, 0.10277539, 0.10056526, 0.09830546, 0.09599246, 0.09362243, 0.09119084, 0.08869265, 0.08612198, 0.08347229, 0.08073573, 0.07790323, 0.07496382, 0.07190453, 0.06870925, 0.0653583, 0.06182632, 0.05808044, 0.05407658, 0.04975295, 0.0450185, 0.03972912, 0.03363155, 0.02620192, 0.01610863], 1e-4)
def test_linear_system(self): """Check against the scipy solver.""" model = Group() x = np.array([1, 2, -3]) A = np.array([[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]]) b = A.dot(x) model.add_subsystem('p1', IndepVarComp('A', A)) model.add_subsystem('p2', IndepVarComp('b', b)) lingrp = model.add_subsystem('lingrp', Group(), promotes=['*']) lingrp.add_subsystem('lin', LinearSystemComp(size=3, partial_type="matrix_free")) model.connect('p1.A', 'lin.A') model.connect('p2.b', 'lin.b') prob = Problem(model) prob.setup() lingrp.linear_solver = ScipyKrylov() prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['lin.x'], x, .0001) assert_rel_error(self, prob.model._residuals.get_norm(), 0.0, 1e-10)
def test_converge_diverge(self): prob = Problem() prob.model = ConvergeDiverge() prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6) indep_list = ['iv.x'] unknown_list = ['c7.y1'] J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6) prob.setup(vector_class=PETScVector, check=False, mode='rev') prob.run_model() assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6) J = prob.compute_totals(of=unknown_list, wrt=indep_list) assert_rel_error(self, J['c7.y1', 'iv.x'][0][0], -40.75, 1e-6) assert_rel_error(self, prob['c7.y1'], -102.7, 1e-6)
def test_deprecated_ks_component(self): # run same test as above, only with the deprecated component, # to ensure we get the warning and the correct answer. # self-contained, to be removed when class name goes away. from openmdao.components.ks_comp import KSComponent # deprecated prob = Problem() prob.model = model = Group() model.add_subsystem('px', IndepVarComp(name="x", val=np.ones((2,)))) model.add_subsystem('comp', DoubleArrayComp()) msg = "'KSComponent' has been deprecated. Use 'KSComp' instead." with assert_warning(DeprecationWarning, msg): model.add_subsystem('ks', KSComponent(width=2)) model.connect('px.x', 'comp.x1') model.connect('comp.y2', 'ks.g') model.add_design_var('px.x') model.add_objective('comp.y1') model.add_constraint('ks.KS', upper=0.0) prob.setup(check=False) prob.run_driver() assert_rel_error(self, max(prob['comp.y2']), prob['ks.KS'][0])
def test_indices_rev(self): prob = self.setup_model('rev') J = prob.compute_totals(['c4.y', 'c5.y'], ['p.x'], return_format='flat_dict') assert_rel_error(self, J['c5.y', 'p.x'][0], np.array([20., 25.]), 1e-6) assert_rel_error(self, J['c4.y', 'p.x'][0], np.array([8., 0.]), 1e-6)
def test_results(self): a = self.p['a'] b = self.p['b'] c = self.p['c'] out = self.p['add_subtract_comp.adder_output'] expected = 2*a + b - c assert_rel_error(self, out, expected,1e-16)
def test_fan_in_grouped_feature(self): from openmdao.api import Problem, IndepVarComp, ParallelGroup, ExecComp, PETScVector prob = Problem() model = prob.model model.add_subsystem('p1', IndepVarComp('x', 1.0)) model.add_subsystem('p2', IndepVarComp('x', 1.0)) parallel = model.add_subsystem('parallel', ParallelGroup()) parallel.add_subsystem('c1', ExecComp(['y=-2.0*x'])) parallel.add_subsystem('c2', ExecComp(['y=5.0*x'])) model.add_subsystem('c3', ExecComp(['y=3.0*x1+7.0*x2'])) model.connect("parallel.c1.y", "c3.x1") model.connect("parallel.c2.y", "c3.x2") model.connect("p1.x", "parallel.c1.x") model.connect("p2.x", "parallel.c2.x") prob.setup(vector_class=PETScVector, check=False, mode='fwd') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['c3.y'], 29.0, 1e-6)
def test_feature_simple(self): """Tests feature for adding a Scipy GMRES solver and calculating the derivatives.""" from openmdao.api import Problem, Group, IndepVarComp, ScipyKrylov from openmdao.test_suite.components.expl_comp_simple import TestExplCompSimpleDense # Tests derivatives on a simple comp that defines compute_jacvec. prob = Problem() model = prob.model model.add_subsystem('x_param', IndepVarComp('length', 3.0), promotes=['length']) model.add_subsystem('mycomp', TestExplCompSimpleDense(), promotes=['length', 'width', 'area']) model.linear_solver = ScipyKrylov() prob.set_solver_print(level=0) prob.setup(check=False, mode='fwd') prob['width'] = 2.0 prob.run_model() of = ['area'] wrt = ['length'] J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_rel_error(self, J['area', 'length'][0][0], 2.0, 1e-6)
def test_solve_linear_scipy(self): """Solve implicit system with ScipyKrylov.""" # use ScipyIterativeSolver here to check for deprecation warning and verify that the deprecated # class still gets the right answer without duplicating this test. msg = "ScipyIterativeSolver is deprecated. Use ScipyKrylov instead." with assert_warning(DeprecationWarning, msg): group = TestImplicitGroup(lnSolverClass=lambda : ScipyIterativeSolver(solver=self.linear_solver_name)) p = Problem(group) p.setup(check=False) p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output, group.expected_solution, 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output, group.expected_solution, 1e-15)
def test_rk_with_time_invariant(self): np.random.seed(1) indeps = IndepVarComp() rktest = RKTest(NTIME) indeps.add_output('yi', np.random.random((2, 3))) indeps.add_output('yv', np.random.random((2, NTIME))) indeps.add_output('x0', np.random.random((2,))) prob = Problem() prob.model.add_subsystem('indeps', indeps, promotes=['*']) prob.model.add_subsystem('rktest', rktest, promotes=['*']) prob.setup() prob.run_model() # check partials partials = prob.check_partials(out_stream=None) assert_check_partials(partials, atol=6e-5, rtol=6e-5) # check totals inputs = ['yi', 'yv', 'x0'] outputs = ['x'] J = prob.check_totals(of=outputs, wrt=inputs, out_stream=None) for outp in outputs: for inp in inputs: Jn = J[outp, inp]['J_fd'] Jf = J[outp, inp]['J_fwd'] diff = abs(Jf - Jn) assert_rel_error(self, diff.max(), 0.0, 6e-5)
def test_optimize_derivs(self): from openmdao.api import Problem, IndepVarComp from openmdao.api import ScipyOptimizeDriver from openmdao.components.tests.test_external_code_comp import ParaboloidExternalCodeCompDerivs prob = Problem() model = prob.model # create and connect inputs model.add_subsystem('p1', IndepVarComp('x', 3.0)) model.add_subsystem('p2', IndepVarComp('y', -4.0)) model.add_subsystem('p', ParaboloidExternalCodeCompDerivs()) model.connect('p1.x', 'p.x') model.connect('p2.y', 'p.y') # find optimal solution with SciPy optimize # solution (minimum): x = 6.6667; y = -7.3333 prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.model.add_design_var('p1.x', lower=-50, upper=50) prob.model.add_design_var('p2.y', lower=-50, upper=50) prob.model.add_objective('p.f_xy') prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = True prob.setup() prob.run_driver() assert_rel_error(self, prob['p1.x'], 6.66666667, 1e-6) assert_rel_error(self, prob['p2.y'], -7.3333333, 1e-6)
def test_feature_atol(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, NewtonSolver, LinearBlockGS, ExecComp, DirectSolver from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) model.linear_solver = DirectSolver() nlgbs = model.nonlinear_solver = NewtonSolver() nlgbs.options['atol'] = 1e-4 prob.setup() prob.run_model() assert_rel_error(self, prob['y1'], 25.5882856302, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001)
def test_specify_solver(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, ExecComp, LinearBlockJac, NonlinearBlockGS from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives prob = Problem() model = prob.model = Group() model.add_subsystem('px', IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) model.nonlinear_solver = NonlinearBlockGS() model.linear_solver = LinearBlockJac() prob.setup() prob.run_model() wrt = ['z'] of = ['obj'] J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') assert_rel_error(self, J['obj', 'z'][0][0], 9.61001056, .00001) assert_rel_error(self, J['obj', 'z'][0][1], 1.78448534, .00001)
def test_jacobian(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_deriv = np.array([[1.], [0.], [-1.]]) for x0, y0 in zip(test_x, expected_deriv): jac = self.surrogate.linearize(x0) assert_rel_error(self, jac, [y0], 1e-9)
def test_rev_mode_bug(self): prob = Problem() prob.model = SellarDerivatives(nonlinear_solver=NewtonSolver(), linear_solver=DirectSolver()) prob.setup(check=False, mode='rev') prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001) wrt = ['x', 'z'] of = ['obj', 'con1', 'con2'] Jbase = {} Jbase['con1', 'x'] = [[-0.98061433]] Jbase['con1', 'z'] = np.array([[-9.61002285, -0.78449158]]) Jbase['con2', 'x'] = [[0.09692762]] Jbase['con2', 'z'] = np.array([[1.94989079, 1.0775421]]) Jbase['obj', 'x'] = [[2.98061392]] Jbase['obj', 'z'] = np.array([[9.61001155, 1.78448534]]) J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict') for key, val in iteritems(Jbase): assert_rel_error(self, J[key], val, .00001) # In the bug, the solver mode got switched from fwd to rev when it shouldn't # have been, causing a singular matrix and NaNs in the output. prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001)
def test_bulk_prediction(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_y = np.array([[0.82893803], [1.72485853], [0.82893803]]) mu = self.surrogate.predict(test_x) assert_rel_error(self, mu, expected_y, 1e-8)
def test_jacobian(self): from distutils.version import LooseVersion if LooseVersion(np.__version__) >= LooseVersion("1.14"): raise unittest.SkipTest("This test doesn't work in numpy 1.14.") test_x = np.array([[0.5, 0.5], [0.5, 1.5], [1.5, 1.5], [1.5, 0.5] ]) a = -0.97153433 b = -0.97153433 c = 0.59055939 d = 0.59055939 expected_deriv = np.array([ [[a, b], [c, d], [0., 0.], [a, b]], [[a, -b], [c, -d], [0., 0.], [a, -b]], [[-a, -b], [-c, -d], [0., 0.], [-a, -b]], [[-a, b], [-c, d], [0., 0.], [-a, b]] ]) for x0, y0 in zip(test_x, expected_deriv): mu = self.surrogate.linearize(x0) assert_rel_error(self, mu, y0, 1e-6)
def test_bulk_prediction(self): test_x = np.array([[1., 0.5], [0.5, 1.0], [1.0, 1.5], [1.5, 1.], [0., 1.], [.5, .5] ]) a = ((16. / (5 * np.sqrt(5.)) + 16. / (13. * np.sqrt(13.))) / (16./(5*np.sqrt(5.)) + 16. / (13. * np.sqrt(13.)) + 8.)) b = 8. / (8. + 16. / (5 * np.sqrt(5.)) + 16. / (13. * np.sqrt(13.))) c = (2. + 2./(5.*np.sqrt(5))) / (3. + 2. / (5. * np.sqrt(5))) d = 1. / (3. + 2. / (5. * np.sqrt(5))) expected_y = np.array([[a, b, 0.5, a], [a, b, 0.5, a], [a, b, 0.5, a], [a, b, 0.5, a], [c, d, 0.5, c], [0.54872067, 0.45127933, 0.5, 0.54872067] ]) mu = self.surrogate.predict(test_x, num_neighbors=5, dist_eff=3) assert_rel_error(self, mu, expected_y, 1e-6)
def test_prediction(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_y = np.array([[0.5], [1.], [0.5]]) for x0, y0 in zip(test_x, expected_y): mu = self.surrogate.predict(x0) assert_rel_error(self, mu, [y0], 1e-9)
def test_bulk_prediction(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_y = np.array([[0.52631579], [0.94736842], [0.52631579]]) mu = self.surrogate.predict(test_x, num_neighbors=3) assert_rel_error(self, mu, expected_y, 1e-8)
def test_jacobian(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_deriv = np.array([[1.92797784], [0.06648199], [-1.92797784]]) for x0, y0 in zip(test_x, expected_deriv): jac = self.surrogate.linearize(x0, num_neighbors=3) assert_rel_error(self, jac, [y0], 1e-6)
def test_sparse_jacobian(self): import numpy as np from openmdao.api import Problem, Group, IndepVarComp, ExplicitComponent class SparsePartialComp(ExplicitComponent): def setup(self): self.add_input('x', shape=(4,)) self.add_output('f', shape=(2,)) self.declare_partials(of='f', wrt='x', rows=[0, 1, 1, 1], cols=[0, 1, 2, 3]) def compute_partials(self, inputs, partials): # Corresponds to the [(0,0), (1,1), (1,2), (1,3)] entries. partials['f', 'x'] = [1., 2., 3., 4.] model = Group() comp = IndepVarComp() comp.add_output('x', np.ones(4)) model.add_subsystem('input', comp) model.add_subsystem('example', SparsePartialComp()) model.connect('input.x', 'example.x') problem = Problem(model=model) problem.setup(check=False) problem.run_model() totals = problem.compute_totals(['example.f'], ['input.x']) assert_rel_error(self, totals['example.f', 'input.x'], [[1., 0., 0., 0.], [0., 2., 3., 4.]])
def test_mixed_fd(self): comp = SimpleCompMixedFD() problem = self.problem model = problem.model model.add_subsystem('simple', comp, promotes=['x', 'y1', 'y2', 'y3', 'z', 'f', 'g']) problem.setup(check=True) problem.run_model() totals = problem.compute_totals(['f', 'g'], ['x', 'y1', 'y2', 'y3', 'z']) jacobian = {} jacobian['f', 'x'] = [[1.]] jacobian['f', 'z'] = np.ones((1, 4)) jacobian['f', 'y1'] = np.zeros((1, 2)) jacobian['f', 'y2'] = np.zeros((1, 2)) jacobian['f', 'y3'] = np.zeros((1, 2)) jacobian['g', 'y1'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'y2'] = [[1, 0], [0, 1], [1, 0], [0, 1]] jacobian['g', 'y3'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'x'] = [[1], [0], [0], [1]] jacobian['g', 'z'] = np.zeros((4, 4)) assert_rel_error(self, totals, jacobian, 1e-6)
def test_scaled_derivs(self): prob = Problem() prob.model = model = SellarDerivatives() model.add_design_var('z') model.add_objective('obj') model.add_constraint('con1') prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() base = prob.compute_totals(of=['obj', 'con1'], wrt=['z']) prob = Problem() prob.model = model = SellarDerivatives() model.add_design_var('z', ref=2.0, ref0=0.0) model.add_objective('obj', ref=1.0, ref0=0.0) model.add_constraint('con1', lower=0, ref=2.0, ref0=0.0) prob.set_solver_print(level=0) prob.setup(check=False) prob.run_model() derivs = prob.driver._compute_totals(of=['obj_cmp.obj', 'con_cmp1.con1'], wrt=['pz.z'], return_format='dict') assert_rel_error(self, base[('con1', 'z')][0], derivs['con_cmp1.con1']['pz.z'][0], 1e-5) assert_rel_error(self, base[('obj', 'z')][0]*2.0, derivs['obj_cmp.obj']['pz.z'][0], 1e-5)
def test_const_jacobian(self): model = Group() comp = IndepVarComp() for name, val in (('x', 1.), ('y1', np.ones(2)), ('y2', np.ones(2)), ('y3', np.ones(2)), ('z', np.ones((2, 2)))): comp.add_output(name, val) model.add_subsystem('input_comp', comp, promotes=['x', 'y1', 'y2', 'y3', 'z']) problem = Problem(model=model) problem.set_solver_print(level=0) model.linear_solver = ScipyKrylov() model.jacobian = COOJacobian() model.add_subsystem('simple', SimpleCompConst(), promotes=['x', 'y1', 'y2', 'y3', 'z', 'f', 'g']) problem.setup(check=False) problem.run_model() totals = problem.compute_totals(['f', 'g'], ['x', 'y1', 'y2', 'y3', 'z']) jacobian = {} jacobian['f', 'x'] = [[1.]] jacobian['f', 'z'] = np.ones((1, 4)) jacobian['f', 'y1'] = np.zeros((1, 2)) jacobian['f', 'y2'] = np.zeros((1, 2)) jacobian['f', 'y3'] = np.zeros((1, 2)) jacobian['g', 'y1'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'y2'] = [[1, 0], [0, 1], [1, 0], [0, 1]] jacobian['g', 'y3'] = [[1, 0], [1, 0], [0, 1], [0, 1]] jacobian['g', 'x'] = [[1], [0], [0], [1]] jacobian['g', 'z'] = np.zeros((4, 4)) assert_rel_error(self, totals, jacobian)
def test_beam_stress(self): E = 1. L = 1. b = 0.1 volume = 0.01 max_bending = 100.0 num_cp = 5 num_elements = 25 num_load_cases = 2 prob = Problem(model=MultipointBeamGroup(E=E, L=L, b=b, volume=volume, max_bending = max_bending, num_elements=num_elements, num_cp=num_cp, num_load_cases=num_load_cases)) prob.driver = ScipyOptimizeDriver() prob.driver.options['optimizer'] = 'SLSQP' prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = False prob.setup(mode='rev') prob.run_driver() stress0 = prob['parallel.sub_0.stress_comp.stress_0'] stress1 = prob['parallel.sub_0.stress_comp.stress_1'] # Test that the the maximum constraint prior to aggregation is close to "active". assert_rel_error(self, max(stress0), 100.0, tolerance=5e-2) assert_rel_error(self, max(stress1), 100.0, tolerance=5e-2) # Test that no original constraint is violated. self.assertTrue(np.all(stress0 < 100.0)) self.assertTrue(np.all(stress1 < 100.0))
def test_backtracking(self): top = Problem() top.model.add_subsystem('px', IndepVarComp('x', 1.0)) top.model.add_subsystem('comp', ImplCompTwoStates()) top.model.connect('px.x', 'comp.x') top.model.nonlinear_solver = BroydenSolver() top.model.nonlinear_solver.options['maxiter'] = 25 top.model.nonlinear_solver.options['diverge_limit'] = 0.5 top.model.nonlinear_solver.options['state_vars'] = ['comp.y', 'comp.z'] top.model.linear_solver = DirectSolver() top.setup(check=False) top.model.nonlinear_solver.linesearch = BoundsEnforceLS(bound_enforcement='vector') # Setup again because we assigned a new linesearch top.setup(check=False) top.set_solver_print(level=2) # Test lower bound: should go to the lower bound and stall top['px.x'] = 2.0 top['comp.y'] = 0.0 top['comp.z'] = 1.6 top.run_model() assert_rel_error(self, top['comp.z'], 1.5, 1e-8) # Test upper bound: should go to the upper bound and stall top['px.x'] = 0.5 top['comp.y'] = 0.0 top['comp.z'] = 2.4 top.run_model() assert_rel_error(self, top['comp.z'], 2.5, 1e-8)
def test_reference(self): class TmpComp(ExplicitComponent): def initialize(self): self.A = np.ones((3, 3)) def setup(self): self.add_output('y', shape=(3,)) self.add_output('z', shape=(3,)) self.add_input('x', shape=(3,), units='degF') self.declare_partials(of='*', wrt='*') def compute_partials(self, inputs, partials): partials['y', 'x'] = self.A partials['z', 'x'] = self.A p = Problem() model = p.model = Group() indep = model.add_subsystem('indep', IndepVarComp(), promotes=['*']) indep.add_output('x', val=100., shape=(3,), units='degK') model.add_subsystem('comp', TmpComp(), promotes=['*']) p.setup() p.run_model() totals = p.compute_totals(['y', 'z'], ['x']) expected_totals = { ('y', 'x'): 9/5 * np.ones((3, 3)), ('z', 'x'): 9/5 * np.ones((3, 3)), } assert_rel_error(self, totals, expected_totals, 1e-6)
def test_partials_no_compute(self): prob = Problem() model = prob.model model.add_subsystem('px', IndepVarComp('x', val=np.array([5.0, 4.0]))) ks_comp = model.add_subsystem('ks', KSComp(width=2)) model.connect('px.x', 'ks.g') prob.setup(check=False) prob.run_driver() # compute partials with the current model inputs inputs = { 'g': prob['ks.g'] } partials = {} ks_comp.compute_partials(inputs, partials) assert_rel_error(self, partials[('KS', 'g')], np.array([1., 0.]), 1e-6) # swap inputs and call compute partials again, without calling compute inputs['g'][0][0] = 4 inputs['g'][0][1] = 5 ks_comp.compute_partials(inputs, partials) assert_rel_error(self, partials[('KS', 'g')], np.array([0., 1.]), 1e-6)
def test_prediction(self): test_x = np.array([[0.5], [1.5], [2.5]]) expected_y = np.array([[0.52631579], [0.94736842], [0.52631579]]) for x0, y0 in zip(test_x, expected_y): mu = self.surrogate.predict(x0, num_neighbors=3) assert_rel_error(self, mu, [y0], 1e-8)
def test_units(self): out = self.p.get_val('geom|S_ref', units='m**2') expected = 20 * 0.3048**2 assert_rel_error(self, out, expected,1e-4)
def test_brachistochrone_vector_ode_path_constraints_radau_no_indices( self): p = Problem(model=Group()) p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase(ode_class=BrachistochroneVectorStatesODE, transcription=Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.set_state_options('pos', fix_initial=True, fix_final=True) phase.set_state_options('v', fix_initial=True, fix_final=False) phase.add_control('theta', continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter('g', units='m/s**2', opt=False, val=9.80665) phase.add_path_constraint('pos_dot', shape=(2, ), units='m/s', lower=-4, upper=12) phase.add_timeseries_output('pos_dot', shape=(2, ), units='m/s') # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.design_parameters:g'] = 9.80665 p.run_driver() assert_rel_error(self, np.min(p.get_val('phase0.timeseries.pos_dot')[:, -1]), -4, tolerance=1.0E-2) # Plot results if SHOW_PLOTS: exp_out = phase.simulate(times_per_seg=50) fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0] y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1] x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0] y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1] ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution\nVelocity') t_imp = p.get_val('phase0.timeseries.time') t_exp = exp_out.get_val('phase0.timeseries.time') xdot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_imp = p.get_val('phase0.timeseries.pos_dot')[:, 1] xdot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 0] ydot_exp = exp_out.get_val('phase0.timeseries.pos_dot')[:, 1] ax.plot(t_imp, xdot_imp, 'bo', label='implicit') ax.plot(t_exp, xdot_exp, 'b-', label='explicit') ax.plot(t_imp, ydot_imp, 'ro', label='implicit') ax.plot(t_exp, ydot_exp, 'r-', label='explicit') ax.set_xlabel('t (s)') ax.set_ylabel('v (m/s)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time') y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2') x_exp = exp_out.get_val('phase0.timeseries.time') y_exp = exp_out.get_val( 'phase0.timeseries.control_rates:theta_rate2') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('time (s)') ax.set_ylabel('theta rate2 (rad/s**2)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
def test_sellar(self): # Basic sellar test. prob = om.Problem() model = prob.model model.add_subsystem('px', om.IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', om.IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) nlgbs = model.nonlinear_solver = om.NonlinearBlockGS() prob.setup() prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001) # Make sure we aren't iterating like crazy self.assertEqual(model.nonlinear_solver._iter_count, 7) # Only one extra execution self.assertEqual(model.d1.execution_count, 8) # With run_apply_linear, we execute the components more times. prob = om.Problem() model = prob.model model.add_subsystem('px', om.IndepVarComp('x', 1.0), promotes=['x']) model.add_subsystem('pz', om.IndepVarComp('z', np.array([5.0, 2.0])), promotes=['z']) model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2']) model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2']) model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', z=np.array([0.0, 0.0]), x=0.0), promotes=['obj', 'x', 'z', 'y1', 'y2']) model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1']) model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2']) nlgbs = model.nonlinear_solver = om.NonlinearBlockGS() nlgbs.options['use_apply_nonlinear'] = True prob.setup() prob.set_solver_print(level=0) prob.run_model() assert_rel_error(self, prob['y1'], 25.58830273, .00001) assert_rel_error(self, prob['y2'], 12.05848819, .00001) # Make sure we aren't iterating like crazy self.assertEqual(model.nonlinear_solver._iter_count, 7) # Nearly double the executions. self.assertEqual(model.d1.execution_count, 15)
def test_load_case_radau_to_lgl(self): import openmdao.api as om from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.brachistochrone.brachistochrone_ode import BrachistochroneODE p = om.Problem(model=om.Group()) p.driver = om.pyOptSparseDriver() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.Radau(num_segments=20)) p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(.5, 10)) phase.add_state( 'x', fix_initial=True, fix_final=True, rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units']) phase.add_state( 'y', fix_initial=True, fix_final=True, rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units']) phase.add_state( 'v', fix_initial=True, rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], defect_scaler=1.0E3) phase.add_control( 'theta', units='deg', targets=BrachistochroneODE.parameters['theta']['targets'], rate_continuity=False) phase.add_design_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units='m/s**2', opt=False, val=9.80665) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() # Recording rec = om.SqliteRecorder('brachistochrone_solution.db') p.driver.recording_options['record_desvars'] = True p.driver.recording_options['record_responses'] = True p.driver.recording_options['record_objectives'] = True p.driver.recording_options['record_constraints'] = True p.model.recording_options['record_metadata'] = True p.model.add_recorder(rec) p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 p['phase0.states:x'] = phase.interpolate(ys=[0, 10], nodes='state_input') p['phase0.states:y'] = phase.interpolate(ys=[10, 5], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100.5], nodes='control_input') # Solve for the optimal trajectory p.run_driver() # Load the solution cr = om.CaseReader('brachistochrone_solution.db') system_cases = cr.list_cases('root') case = cr.get_case(system_cases[-1]) # Now change the grid so that the previous case won't have the same number of variables phase.options['transcription'] = dm.GaussLobatto(num_segments=50) # Initialize the system with values from the case. # We unnecessarily call setup again just to make sure we obliterate the previous solution # First reset the connections at the top level model until fixed in OpenMDAO p.setup() # Load the values from the previous solution dm.load_case(p, case) # Run the model to ensure we find the same output values as those that we recorded p.run_driver() outputs = dict([ (o[0], o[1]) for o in case.list_outputs(units=True, shape=True, out_stream=None) ]) time_val = outputs['phase0.timeseries.time']['value'] theta_val = outputs['phase0.timeseries.controls:theta']['value'] assert_rel_error(self, p['phase0.timeseries.controls:theta'], phase.interpolate(xs=time_val, ys=theta_val, nodes='all'), tolerance=1.0E-3)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.integration.aerostruct_groups import Aerostruct, AerostructPoint from openmdao.api import IndepVarComp, Problem, Group, SqliteRecorder from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 2, 'wing_type' : 'CRM', 'symmetry' : True, 'num_twist_cp' : 5} mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aerostruct', '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]), 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], 'geom_manipulator' : 'FFD', 'mx' : 2, 'my' : 3, # 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., # Constraints 'exact_failure_constraint' : False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = 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('M', 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('CT', val=9.80665 * 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('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) aerostruct_group = Aerostruct(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect(name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect(name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') # Import the Scipy Optimizer and set the driver of the problem to use # it, which defaults to an SLSQP optimization method from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() recorder = SqliteRecorder("aerostruct_ffd.db") prob.driver.add_recorder(recorder) prob.driver.recording_options['record_derivatives'] = True # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.shape', lower=-3, upper=2) prob.model.add_design_var('wing.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.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # iprofile.setup() # iprofile.start() # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob, outfile='aerostruct_ffd', show_browser=False) # prob.run_model() prob.run_driver() # prob.check_partials(compact_print=True) # print("\nWing CL:", prob['aero_point_0.wing_perf.CL']) # print("Wing CD:", prob['aero_point_0.wing_perf.CD']) # from helper import plot_3d_points # # mesh = prob['aero_point_0.wing.def_mesh'] # plot_3d_points(mesh) # # filename = mesh_dict['wing_type'] + '_' + str(mesh_dict['num_x']) + '_' + str(mesh_dict['num_y']) # filename += '_' + str(surf_dict['mx']) + '_' + str(surf_dict['my']) + '.mesh' # np.save(filename, mesh) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 104675.0989232741, 1e-4)
def test(self): # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 7, 'num_x' : 2, 'wing_type' : 'rect', 'symmetry' : True} mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name' : 'wing', # name of the surface 'type' : 'aero', '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', 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], # 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' : 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 } # Create a dictionary to store options about the surface mesh_dict = {'num_y' : 5, 'num_x' : 3, 'wing_type' : 'rect', 'symmetry' : True, 'offset' : np.array([50, 0., 0.])} mesh = generate_mesh(mesh_dict) surf_dict2 = { # Wing definition 'name' : 'tail', # name of the surface 'type' : 'aero', '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' 'mesh' : mesh, 'num_x' : mesh.shape[0], 'num_y' : mesh.shape[1], # 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.0, # CD of the surface at alpha=0 'fem_origin' : 0.35, # Airfoil properties for viscous drag calculation 'k_lam' : 0.05, # percentage of chord with laminar # flow, used for viscous drag 't_over_c' : 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 } surfaces = [surf_dict, surf_dict2] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5.) indep_var_comp.add_output('M', 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') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: 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') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.035076501750605345, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.4523608754613204, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -10.59426779178033, 1e-6)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': False, 'num_twist_cp': 2, 'span_cos_spacing': 1. } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aerostruct', 'symmetry': False, # 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.ones(2) * 0.06836728, 'twist_cp': twist_cp, 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # 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.12]), # 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': 1., # Constraints 'exact_failure_constraint': False, # if false, use KS function } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = 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('M', 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('CT', val=9.80665 * 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('a', val=295.4, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = Aerostruct(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('CT', point_name + '.CT') prob.model.connect('R', point_name + '.R') prob.model.connect('W0', point_name + '.W0') prob.model.connect('a', point_name + '.a') prob.model.connect('empty_cg', point_name + '.empty_cg') prob.model.connect('load_factor', point_name + '.load_factor') for surface in surfaces: prob.model.connect('load_factor', name + '.load_factor') com_name = point_name + '.' + name + '_perf' prob.model.connect(name + '.K', point_name + '.coupled.' + name + '.K') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_weights', point_name + '.coupled.' + name + '.element_weights') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_weight', point_name + '.' + 'total_perf.' + name + '_structural_weight') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-15., upper=15.) prob.model.add_design_var('wing.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.) # Add design variables, constraisnt, and objective on the problem prob.model.add_design_var('alpha', lower=-10., upper=10.) prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.) prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5) # Set up the problem prob.setup() # from openmdao.api import view_model # view_model(prob) prob.run_driver() assert_rel_error(self, prob['AS_point_0.wing_perf.CL'][0], 0.469152412337, 1e-6) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 95396.2868311, 1e-6) assert_rel_error(self, prob['AS_point_0.wing_perf.failure'][0], 0., 1e-6) assert_rel_error(self, prob['AS_point_0.CM'][1], -0.13357819566, 1e-4)
def test_solve_linear_ksp_precon_left(self): """Solve implicit system with PETScKrylov using a preconditioner.""" group = TestImplicitGroup(lnSolverClass=om.PETScKrylov) precon = group.linear_solver.precon = om.DirectSolver( assemble_jac=False) group.linear_solver.options['precon_side'] = 'left' group.linear_solver.options['ksp_type'] = 'richardson' p = om.Problem(group) p.setup() p.set_solver_print(level=0) # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.run_linearize() group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output, group.expected_solution, 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.run_linearize() group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output, group.expected_solution, 3e-15) # test the direct solver and make sure KSP correctly recurses for _linearize precon = group.linear_solver.precon = om.DirectSolver( assemble_jac=False) group.linear_solver.options['precon_side'] = 'left' group.linear_solver.options['ksp_type'] = 'richardson' p.setup() # Conclude setup but don't run model. p.final_setup() d_inputs, d_outputs, d_residuals = group.get_linear_vectors() # forward d_residuals.set_const(1.0) d_outputs.set_const(0.0) group.linear_solver._linearize() group.run_solve_linear(['linear'], 'fwd') output = d_outputs._data assert_rel_error(self, output, group.expected_solution, 1e-15) # reverse d_outputs.set_const(1.0) d_residuals.set_const(0.0) group.linear_solver._linearize() group.run_solve_linear(['linear'], 'rev') output = d_residuals._data assert_rel_error(self, output, group.expected_solution, 3e-15)
def test_multiple_masses(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 31, 'wing_type': 'rect', 'span': 10, 'symmetry': True } mesh = 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 'fem_model_type': 'tube', 'mesh': mesh, # 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.5, # normalized chordwise location of the spar 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .1, '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, 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = om.Problem() ny = surface['mesh'].shape[1] surface['n_point_masses'] = 2 indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('loads', val=np.zeros((ny, 6)), units='N') indep_var_comp.add_output('load_factor', val=1.) point_masses = np.array([[10., 20.]]) point_mass_locations = np.array([[1., -1., 0.], [1., -2., 0.]]) indep_var_comp.add_output('point_masses', val=point_masses, units='kg') indep_var_comp.add_output('point_mass_locations', val=point_mass_locations, units='m') struct_group = SpatialBeamAlone(surface=surface) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surface['name'], struct_group, promotes=['*']) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['vonmises'][-1, 0], 1557126.5793494075, 1e-4)
def test_results(self): a = self.p['a'] b = self.p['b'] out = self.p['geom|S_ref'] expected = 20 assert_rel_error(self, out, expected,1e-16)
def test_continuity_comp_newtonsolver(self): num_seg = 4 state_options = { 'y': { 'shape': (1, ), 'units': 'm', 'targets': ['y'], 'fix_initial': True, 'fix_final': False, 'propagation': 'forward', 'defect_scaler': None, 'defect_ref': 1.0, 'lower': None, 'upper': None, 'connected_initial': False } } p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]), units='s') ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') p.model.add_subsystem('cnty_iter_group', RungeKuttaStateContinuityIterGroup( num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, k_solver_class=None), promotes_outputs=['states:*']) p.model.connect('h', 'cnty_iter_group.h') p.model.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) # Set the initial value (and all other values) of y p['states:y'][...] = 0.50 p.run_model() # p.model.run_apply_nonlinear() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) expected_resids = np.zeros((num_seg + 1, 1)) op_dict = dict([op for op in outputs]) assert_rel_error( self, op_dict['cnty_iter_group.continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) J_fwd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fd'] assert_rel_error(self, J_fwd, J_fd) J_fwd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fd'] J_fd[0, 0] = -1.0 assert_rel_error(self, J_fwd, J_fd)
def test_turbine_grant_ingram(self): # Copied from CCBlade.jl/test/runtests.jl # --- verification using example from "Wind Turbine Blade Analysis using the Blade Element Momentum Method" # --- by Grant Ingram: https://community.dur.ac.uk/g.l.ingram/download/wind_turbine_design.pdf # Note: There were various problems with the pdf data. Fortunately the excel # spreadsheet was provided: http://community.dur.ac.uk/g.l.ingram/download.php # - They didn't actually use the NACA0012 data. According to the spreadsheet they just used cl = 0.084*alpha with alpha in degrees. # - There is an error in the spreadsheet where CL at the root is always 0.7. This is because the classical approach doesn't converge properly at that station. # - the values for gamma and chord were rounded in the pdf. The spreadsheet has more precise values. # - the tip is not actually converged (see significant error for Delta A). I converged it further using their method. num_nodes = 1 # --- rotor definition --- turbine = True hub_radius = 0.01 prop_radius = 5.0 prop_radius_eff = 500.0 B = 3 # number of blades precone = 0. r = np.array([0.2, 1, 2, 3, 4, 5])[np.newaxis, :] gamma = np.array([ 61.0, 74.31002131, 84.89805553, 89.07195504, 91.25038415, 92.58003871 ]) theta = ((90.0 - gamma) * np.pi / 180)[np.newaxis, :] chord = np.array([ 0.7, 0.706025153, 0.436187551, 0.304517933, 0.232257636, 0.187279622 ])[np.newaxis, :] num_radial = r.size jlmain.eval(""" function affunc(alpha, Re, M) cl = 0.084*alpha*180/pi cd = 0.0 return cl, cd end """) affunc = jlmain.affunc # --- inflow definitions --- Vinf = np.array([7.0]).reshape((num_nodes, 1)) tsr = 8 omega = tsr * Vinf / prop_radius rho = 1.0 Vx = np.tile(Vinf * np.cos(precone), (1, num_radial)) Vy = omega * r * np.cos(precone) prob = om.Problem() comp = make_component( CCBladeResidualComp(num_nodes=num_nodes, num_radial=num_radial, B=B, af=affunc, turbine=turbine)) comp.linear_solver = om.DirectSolver(assemble_jac=True) prob.model.add_subsystem('ccblade', comp) prob.setup() prob['ccblade.phi'] = 1. # initial guess prob['ccblade.r'] = r prob['ccblade.chord'] = chord prob['ccblade.theta'] = theta prob['ccblade.Vx'] = Vx prob['ccblade.Vy'] = Vy prob['ccblade.rho'] = rho prob['ccblade.mu'] = 1. prob['ccblade.asound'] = 1. prob['ccblade.Rhub'] = hub_radius prob['ccblade.Rtip'] = prop_radius_eff prob['ccblade.precone'] = precone prob['ccblade.pitch'] = 0.0 prob.run_model() # First entry in phi is uncomparable because the classical method fails at the root so they fixed cl expected_beta = np.array([66.1354, 77.0298, 81.2283, 83.3961, 84.7113]) beta = 90.0 - np.degrees(prob['ccblade.phi'][0, 1:]) assert_rel_error(self, beta, expected_beta, 1e-5) expected_a = np.array([0.2443, 0.2497, 0.2533, 0.2556, 0.25725]) assert_rel_error(self, prob['ccblade.a'][0, 1:], expected_a, 1e-3) expected_ap = np.array([0.0676, 0.0180, 0.0081, 0.0046, 0.0030]) assert_rel_error(self, prob['ccblade.ap'][0, 1:], expected_ap, 5e-3)
def test(self): import numpy as np from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, \ ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, \ DirectSolver, LinearBlockGS, PetscKSP, SqliteRecorder 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': False, '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': False, # 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 = Problem() # Create an independent variable component that will supply the flow # conditions to the problem. indep_var_comp = 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 from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 # 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.run_model() # prob.check_partials() # exit() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03339013029042684, 1e-5) 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.7886135541410009, 1e-4)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': False, 'span': 10., 'chord': 1, 'span_cos_spacing': 1. } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': False, # 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': np.zeros(5), 'mesh': mesh, 'num_x': mesh.shape[0], 'num_y': mesh.shape[1], # 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.0, # 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': 0.12, # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': True, # if true, compute viscous drag 'sweep': 0., 'dihedral': 0., } surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=5.) indep_var_comp.add_output('M', 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') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: 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') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-5 # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.sweep', lower=10., upper=30.) prob.model.add_design_var('wing.dihedral', lower=-10., upper=20.) 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 the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-5) assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.019234984422361764, 1e-3)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 2, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # 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 } surfaces = [surf_dict] # 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, 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('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.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces, compressible=True) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') 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') for surface in surfaces: com_name = point_name + '.' + name + '_perf' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') # Connect performance calculation variables prob.model.connect(name + '.radius', com_name + '.radius') prob.model.connect(name + '.thickness', com_name + '.thickness') prob.model.connect(name + '.nodes', com_name + '.nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') prob.model.connect(name + '.t_over_c', com_name + '.t_over_c') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 224407.92673401345, 1e-4) assert_rel_error(self, prob['AS_point_0.CM'][1], -0.8308573193422, 1e-5)
def test_continuity_comp_no_iteration(self): num_seg = 4 state_options = { 'y': { 'shape': (1, ), 'units': 'm', 'targets': ['y'], 'fix_initial': True, 'fix_final': False, 'propagation': 'forward', 'defect_scaler': None, 'defect_ref': None, 'lower': None, 'upper': None, 'connected_initial': False } } p = om.Problem(model=om.Group()) ivc = p.model.add_subsystem('ivc', om.IndepVarComp(), promotes_outputs=['*']) ivc.add_output('time', val=np.array([ 0.00, 0.25, 0.25, 0.50, 0.50, 0.75, 0.75, 1.00, 1.00, 1.25, 1.25, 1.50, 1.50, 1.75, 1.75, 2.00 ]), units='s') ivc.add_output('h', val=np.array([0.5, 0.5, 0.5, 0.5]), units='s') p.model.add_subsystem('cnty_iter_group', RungeKuttaStateContinuityIterGroup( num_segments=num_seg, method='RK4', state_options=state_options, time_units='s', ode_class=TestODE, ode_init_kwargs={}, k_solver_class=om.NonlinearRunOnce), promotes_outputs=['states:*']) p.model.connect('h', 'cnty_iter_group.h') p.model.connect('time', 'cnty_iter_group.ode.t') src_idxs = np.arange(16, dtype=int).reshape((num_seg, 4, 1)) p.model.connect('cnty_iter_group.ode.ydot', 'cnty_iter_group.k_comp.f:y', src_indices=src_idxs, flat_src_indices=True) p.model.nonlinear_solver = om.NonlinearRunOnce() p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['states:y'] = np.array([[0.50000000], [1.425130208333333], [2.639602661132812], [4.006818970044454], [5.301605229265987]]) p['cnty_iter_group.k_comp.k:y'] = np.array([[[0.75000000 ], [0.90625000], [0.94531250], [1.09765625]], [[1.087565104166667], [1.203206380208333], [1.232116699218750], [1.328623453776042]], [[1.319801330566406], [1.368501663208008], [1.380676746368408], [1.385139703750610]], [[1.378409485022227], [1.316761856277783], [1.301349949091673], [1.154084459568063]]]) p.run_model() p.model.run_apply_nonlinear() # Test that the residuals of the states are the expected values outputs = p.model.list_outputs(print_arrays=True, residuals=True, out_stream=None) expected_resids = np.zeros((num_seg + 1, 1)) op_dict = dict([op for op in outputs]) assert_rel_error( self, op_dict['cnty_iter_group.continuity_comp.states:y']['resids'], expected_resids) # Test the partials cpd = p.check_partials(method='cs', out_stream=None) J_fwd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp'][ 'states:y', 'state_integrals:y']['J_fd'] assert_rel_error(self, J_fwd, J_fd) J_fwd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fwd'] J_fd = cpd['cnty_iter_group.continuity_comp']['states:y', 'states:y']['J_fd'] J_fd[0, 0] = -1.0 assert_rel_error(self, J_fwd, J_fd)
def test(self): import numpy as np from openaerostruct.geometry.utils import generate_mesh from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.aerodynamics.aero_groups import AeroPoint import openmdao.api as om # Instantiate the problem and the model group prob = om.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') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'rect', 'symmetry': True, 'span': 10., 'chord': 1, 'span_cos_spacing': 1. } mesh = 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' 'twist_cp': np.zeros(2), '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.0, # 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.12]), # thickness over chord ratio (NACA0015) 'c_max_t': .303, # chordwise location of maximum (NACA0015) # thickness 'with_viscous': False, # if true, compute viscous drag, 'with_wave': False, # if true, compute wave drag 'sweep': 0., 'dihedral': 0., 'taper': 1., } # end of surface dictionary geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=[surface]) point_name = 'aero_point_0' prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') name = 'wing' # 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') prob.driver = om.ScipyOptimizeDriver() # # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('wing.twist_cp', lower=-10., upper=15.) prob.model.add_design_var('wing.sweep', lower=-10., upper=30.) prob.model.add_design_var('wing.dihedral', 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 the problem prob.setup() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0],\ 0.0049392534859265614, 1e-6)
def test_initial_val_and_final_val_stick(self): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneODE, transcription=dm.GaussLobatto(num_segments=8, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=False, fix_duration=False, initial_val=0.01, duration_val=1.9) phase.add_state( 'x', rate_source=BrachistochroneODE.states['x']['rate_source'], units=BrachistochroneODE.states['x']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'y', rate_source=BrachistochroneODE.states['y']['rate_source'], units=BrachistochroneODE.states['y']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_state( 'v', rate_source=BrachistochroneODE.states['v']['rate_source'], targets=BrachistochroneODE.states['v']['targets'], units=BrachistochroneODE.states['v']['units'], fix_initial=True, fix_final=False, solve_segments=False) phase.add_control( 'theta', targets=BrachistochroneODE.parameters['theta']['targets'], continuity=True, rate_continuity=True, units='deg', lower=0.01, upper=179.9) phase.add_design_parameter( 'g', targets=BrachistochroneODE.parameters['g']['targets'], units='m/s**2', val=9.80665, opt=False) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) phase.add_boundary_constraint('time', loc='initial', equals=0) p.model.linear_solver = om.DirectSolver() p.setup(check=True) assert_rel_error(self, p['phase0.t_initial'], 0.01) assert_rel_error(self, p['phase0.t_duration'], 1.9)
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) # There is a bug in scipy version < 1.0 that causes this value to be wrong. if LooseVersion(scipy.__version__) >= LooseVersion("1.0"): assert_rel_error(self, prob['Area'], 1.0, 1e-4) else: msg = "Outdated version of Scipy detected; this problem does not solve properly." raise unittest.SkipTest(msg)
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 2, 'wing_type': 'rect', 'symmetry': False } mesh = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', 'symmetry': False, # 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' 'twist_cp': np.array([0.]), '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 } surfaces = [surf_dict] # Create the problem and the model group prob = om.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('beta', val=-5, units='deg') indep_var_comp.add_output('omega', val=np.array([0.0, 0.0, -30.0]), units='deg/s') 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') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: geom_group = Geometry(surface=surface) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces, rotational=True) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('omega', point_name + '.omega') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: 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') # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03487336411850356, 1e-6) assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.4615561217697067, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][0], 0.007313681048738922, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][1], -0.11507021674483686, 1e-6) assert_rel_error(self, prob['aero_point_0.CM'][2], 0.0, 1e-6)
def test_guess_nonlinear_feature(self): from openmdao.api import Problem, Group, ImplicitComponent, IndepVarComp, NewtonSolver, ScipyKrylov class ImpWithInitial(ImplicitComponent): def setup(self): self.add_input('a', val=1.) self.add_input('b', val=1.) self.add_input('c', val=1.) self.add_output('x', val=0.) self.declare_partials(of='*', wrt='*') def apply_nonlinear(self, inputs, outputs, residuals): a = inputs['a'] b = inputs['b'] c = inputs['c'] x = outputs['x'] residuals['x'] = a * x**2 + b * x + c def solve_nonlinear(self, inputs, outputs): a = inputs['a'] b = inputs['b'] c = inputs['c'] outputs['x'] = (-b + (b**2 - 4 * a * c)**0.5) / 2 / a def linearize(self, inputs, outputs, partials): a = inputs['a'] b = inputs['b'] c = inputs['c'] x = outputs['x'] partials['x', 'a'] = x**2 partials['x', 'b'] = x partials['x', 'c'] = 1.0 partials['x', 'x'] = 2 * a * x + b self.inv_jac = 1.0 / (2 * a * x + b) def solve_nonlinear(self, inputs, outputs): """ Do nothing. """ pass def guess_nonlinear(self, inputs, outputs, resids): # Solution at 1 and 3. Default value takes us to -1 solution. Here # we set it to a value that will tke us to the 3 solution. outputs['x'] = 5.0 prob = Problem() model = prob.model = Group() model.add_subsystem('pa', IndepVarComp('a', 1.0)) model.add_subsystem('pb', IndepVarComp('b', 1.0)) model.add_subsystem('pc', IndepVarComp('c', 1.0)) model.add_subsystem('comp2', ImpWithInitial()) model.connect('pa.a', 'comp2.a') model.connect('pb.b', 'comp2.b') model.connect('pc.c', 'comp2.c') model.nonlinear_solver = NewtonSolver() model.nonlinear_solver.options['solve_subsystems'] = True model.nonlinear_solver.options['max_sub_solves'] = 1 model.linear_solver = ScipyKrylov() prob.setup(check=False) prob['pa.a'] = 1. prob['pb.b'] = -4. prob['pc.c'] = 3. prob.run_model() assert_rel_error(self, prob['comp2.x'], 3.)
def test_brachistochrone_vector_boundary_constraints_radau_partial_indices( self): p = om.Problem(model=om.Group()) p.driver = om.ScipyOptimizeDriver() p.driver.declare_coloring() phase = dm.Phase(ode_class=BrachistochroneVectorStatesODE, transcription=dm.Radau(num_segments=20, order=3)) p.model.add_subsystem('phase0', phase) phase.set_time_options(fix_initial=True, duration_bounds=(.5, 10)) phase.add_state( 'pos', shape=(2, ), rate_source=BrachistochroneVectorStatesODE.states['pos'] ['rate_source'], units=BrachistochroneVectorStatesODE.states['pos']['units'], fix_initial=True, fix_final=[True, False]) phase.add_state( 'v', rate_source=BrachistochroneVectorStatesODE.states['v'] ['rate_source'], targets=BrachistochroneVectorStatesODE.states['v']['targets'], units=BrachistochroneVectorStatesODE.states['v']['units'], fix_initial=True, fix_final=False) phase.add_control( 'theta', units='deg', targets=BrachistochroneVectorStatesODE.parameters['theta'] ['targets'], rate_continuity=False, lower=0.01, upper=179.9) phase.add_design_parameter( 'g', targets=BrachistochroneVectorStatesODE.parameters['g']['targets'], units='m/s**2', opt=False, val=9.80665) phase.add_boundary_constraint('pos', loc='final', equals=5, indices=[1]) # Minimize time at the end of the phase phase.add_objective('time', loc='final', scaler=10) p.model.linear_solver = om.DirectSolver() p.setup(check=True, force_alloc_complex=True) p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 2.0 pos0 = [0, 10] posf = [10, 5] p['phase0.states:pos'] = phase.interpolate(ys=[pos0, posf], nodes='state_input') p['phase0.states:v'] = phase.interpolate(ys=[0, 9.9], nodes='state_input') p['phase0.controls:theta'] = phase.interpolate(ys=[5, 100], nodes='control_input') p['phase0.design_parameters:g'] = 9.80665 p.run_driver() assert_rel_error(self, p.get_val('phase0.time')[-1], 1.8016, tolerance=1.0E-3) # Plot results if SHOW_PLOTS: p.run_driver() exp_out = phase.simulate(times_per_seg=20) fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.states:pos')[:, 0] y_imp = p.get_val('phase0.timeseries.states:pos')[:, 1] x_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 0] y_exp = exp_out.get_val('phase0.timeseries.states:pos')[:, 1] ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('x (m)') ax.set_ylabel('y (m)') ax.grid(True) ax.legend(loc='upper right') fig, ax = plt.subplots() fig.suptitle('Brachistochrone Solution') x_imp = p.get_val('phase0.timeseries.time') y_imp = p.get_val('phase0.timeseries.control_rates:theta_rate2') x_exp = exp_out.get_val('phase0.timeseries.time') y_exp = exp_out.get_val( 'phase0.timeseries.control_rates:theta_rate2') ax.plot(x_imp, y_imp, 'ro', label='implicit') ax.plot(x_exp, y_exp, 'b-', label='explicit') ax.set_xlabel('time (s)') ax.set_ylabel('theta rate2 (rad/s**2)') ax.grid(True) ax.legend(loc='lower right') plt.show() return p
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 5, 'num_x': 3, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 6, 'chord_cos_spacing': 0, 'span_cos_spacing': 0, } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # 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': 'wingbox', 'spar_thickness_cp': np.array([0.004, 0.005, 0.005, 0.008, 0.008, 0.01]), # [m] 'skin_thickness_cp': np.array([0.005, 0.01, 0.015, 0.020, 0.025, 0.026]), 'twist_cp': np.array([4., 5., 8., 8., 8., 9.]), 'mesh': mesh, 'data_x_upper': upper_x, 'data_x_lower': lower_x, 'data_y_upper': upper_y, 'data_y_lower': lower_y, 'strength_factor_for_upper_skin': 1., # 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.0078, # 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.08, 0.08, 0.08, 0.10, 0.10, 0.08]), 'original_wingbox_airfoil_t_over_c': 0.12, 'c_max_t': .38, # chordwise location of maximum thickness 'with_viscous': True, 'with_wave': False, # if true, compute wave drag # Structural values are based on aluminum 7075 'E': 73.1e9, # [Pa] Young's modulus 'G': ( 73.1e9 / 2 / 1.33 ), # [Pa] shear modulus (calculated using E and the Poisson's ratio here) 'yield': (420.e6 / 1.5), # [Pa] allowable yield stress 'mrho': 2.78e3, # [kg/m^3] material density 'strength_factor_for_upper_skin': 1.0, # the yield stress is multiplied by this factor for the upper skin # 'fem_origin' : 0.35, # normalized chordwise location of the spar 'wing_weight_ratio': 1.25, 'struct_weight_relief': True, # 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 'Wf_reserve': 15000., # [kg] reserve fuel mass } surfaces = [surf_dict] # Create the problem and assign the model group prob = Problem() # Add problem information as an independent variables component indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=.85 * 295.07, units='m/s') indep_var_comp.add_output('alpha', val=0., units='deg') indep_var_comp.add_output('Mach_number', val=0.85) indep_var_comp.add_output('re', val=0.348 * 295.07 * .85 * 1. / (1.43 * 1e-5), units='1/m') indep_var_comp.add_output('rho', val=0.348, units='kg/m**3') indep_var_comp.add_output('CT', val=0.53 / 3600, units='1/s') indep_var_comp.add_output('R', val=14.307e6, units='m') indep_var_comp.add_output('W0', val=148000 + surf_dict['Wf_reserve'], units='kg') indep_var_comp.add_output('speed_of_sound', val=295.07, units='m/s') indep_var_comp.add_output('load_factor', val=1.) indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: # Get the surface name and create a group to contain components # only for this surface name = surface['name'] aerostruct_group = AerostructGeometry(surface=surface) # Add tmp_group to the problem with the name of the surface. prob.model.add_subsystem(name, aerostruct_group) # Loop through and add a certain number of aero points for i in range(1): point_name = 'AS_point_{}'.format(i) # Connect the parameters within the model for each aero point # Create the aero point group and add it to the model AS_point = AerostructPoint(surfaces=surfaces) prob.model.add_subsystem(point_name, AS_point) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('Mach_number', point_name + '.Mach_number') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') 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') for surface in surfaces: com_name = point_name + '.' + name + '_perf.' prob.model.connect( name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed') prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes') # Connect aerodyamic mesh to coupled group mesh prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh') prob.model.connect( name + '.element_mass', point_name + '.coupled.' + name + '.element_mass') prob.model.connect( 'load_factor', point_name + '.coupled.' + name + '.load_factor') # Connect performance calculation variables prob.model.connect(name + '.nodes', com_name + 'nodes') prob.model.connect( name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location') prob.model.connect( name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass') # Connect wingbox properties to von Mises stress calcs prob.model.connect(name + '.Qz', com_name + 'Qz') prob.model.connect(name + '.J', com_name + 'J') prob.model.connect(name + '.A_enc', com_name + 'A_enc') prob.model.connect(name + '.htop', com_name + 'htop') prob.model.connect(name + '.hbottom', com_name + 'hbottom') prob.model.connect(name + '.hfront', com_name + 'hfront') prob.model.connect(name + '.hrear', com_name + 'hrear') prob.model.connect(name + '.spar_thickness', com_name + 'spar_thickness') prob.model.connect(name + '.t_over_c', com_name + 't_over_c') from openmdao.api import ScipyOptimizeDriver prob.driver = ScipyOptimizeDriver() prob.driver.options['tol'] = 1e-9 prob.driver.options['disp'] = True # Set up the problem prob.setup() AS_point.nonlinear_solver.options['iprint'] = 2 # # from openmdao.api import view_model # view_model(prob) prob.run_model() # prob.model.list_outputs(values=True, # implicit=False, # units=True, # shape=True, # bounds=True, # residuals=True, # scaling=True, # hierarchical=False, # print_arrays=True) # print(prob['AS_point_0.fuelburn'][0]) # print(prob['wing.structural_mass'][0]/1.25) assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 112469.567077, 1e-5) assert_rel_error(self, prob['wing.structural_mass'][0] / 1.25, 24009.5230566, 1e-5)
def test_steady_aircraft_for_docs(self): import matplotlib.pyplot as plt from openmdao.api import Problem, Group, pyOptSparseDriver, IndepVarComp from openmdao.utils.assert_utils import assert_rel_error import dymos as dm from dymos.examples.aircraft_steady_flight.aircraft_ode import AircraftODE from dymos.examples.plotting import plot_results from dymos.utils.lgl import lgl p = Problem(model=Group()) p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = 'SLSQP' p.driver.options['dynamic_simul_derivs'] = True num_seg = 15 seg_ends, _ = lgl(num_seg + 1) traj = p.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase( 'phase0', dm.Phase(ode_class=AircraftODE, transcription=dm.Radau(num_segments=num_seg, segment_ends=seg_ends, order=3, compressed=False))) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(300, 10000), duration_ref=5600) phase.set_state_options('range', units='NM', fix_initial=True, fix_final=False, ref=1e-3, defect_ref=1e-3, lower=0, upper=2000) phase.set_state_options('mass_fuel', units='lbm', fix_initial=True, fix_final=True, upper=1.5E5, lower=0.0, ref=1e2, defect_ref=1e2) phase.set_state_options('alt', units='kft', fix_initial=True, fix_final=True, lower=0.0, upper=60, ref=1e-3, defect_ref=1e-3) phase.add_control('climb_rate', units='ft/min', opt=True, lower=-3000, upper=3000, rate_continuity=True, rate2_continuity=False) phase.add_control('mach', units=None, opt=False) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=2.0, shape=(1, )) p.model.connect('assumptions.S', 'traj.phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'traj.phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'traj.phase0.input_parameters:mass_payload') phase.add_objective('range', loc='final', ref=-1.0e-4) p.setup() p['traj.phase0.t_initial'] = 0.0 p['traj.phase0.t_duration'] = 3600.0 p['traj.phase0.states:range'][:] = phase.interpolate( ys=(0, 724.0), nodes='state_input') p['traj.phase0.states:mass_fuel'][:] = phase.interpolate( ys=(30000, 1e-3), nodes='state_input') p['traj.phase0.states:alt'][:] = 10.0 p['traj.phase0.controls:mach'][:] = 0.8 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 p.run_driver() assert_rel_error(self, p.get_val('traj.phase0.timeseries.states:range', units='NM')[-1], 726.85, tolerance=1.0E-2) exp_out = traj.simulate() plot_results([('traj.phase0.timeseries.states:range', 'traj.phase0.timeseries.states:alt', 'range (NM)', 'altitude (kft)'), ('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:mass_fuel', 'time (s)', 'fuel mass (lbm)')], title='Commercial Aircraft Optimization', p_sol=p, p_sim=exp_out) plt.show()
def test_set_checks_shape(self): indep = IndepVarComp() indep.add_output('a') indep.add_output('x', shape=(5, 1)) g1 = Group() g1.add_subsystem('Indep', indep, promotes=['a', 'x']) g2 = g1.add_subsystem('G2', Group(), promotes=['*']) g2.add_subsystem('C1', ExecComp('b=2*a'), promotes=['a', 'b']) g2.add_subsystem('C2', ExecComp('y=2*x', x=np.zeros((5, 1)), y=np.zeros((5, 1))), promotes=['x', 'y']) model = Group() model.add_subsystem('G1', g1, promotes=['b', 'y']) model.add_subsystem('Sink', ExecComp(('c=2*b', 'z=2*y'), y=np.zeros((5, 1)), z=np.zeros((5, 1))), promotes=['b', 'y']) p = Problem(model=model) p.setup() p.set_solver_print(level=0) p.run_model() msg = "Incompatible shape for '.*': Expected (.*) but got (.*)" num_val = -10 arr_val = -10 * np.ones((5, 1)) bad_val = -10 * np.ones((10)) inputs, outputs, residuals = g2.get_nonlinear_vectors() # # set input # # assign array to scalar with assertRaisesRegex(self, ValueError, msg): inputs['C1.a'] = arr_val # assign scalar to array inputs['C2.x'] = num_val assert_rel_error(self, inputs['C2.x'], arr_val, 1e-10) # assign array to array inputs['C2.x'] = arr_val assert_rel_error(self, inputs['C2.x'], arr_val, 1e-10) # assign bad array shape to array with assertRaisesRegex(self, ValueError, msg): inputs['C2.x'] = bad_val # assign list to array inputs['C2.x'] = arr_val.tolist() assert_rel_error(self, inputs['C2.x'], arr_val, 1e-10) # assign bad list shape to array with assertRaisesRegex(self, ValueError, msg): inputs['C2.x'] = bad_val.tolist() # # set output # # assign array to scalar with assertRaisesRegex(self, ValueError, msg): outputs['C1.b'] = arr_val # assign scalar to array outputs['C2.y'] = num_val assert_rel_error(self, outputs['C2.y'], arr_val, 1e-10) # assign array to array outputs['C2.y'] = arr_val assert_rel_error(self, outputs['C2.y'], arr_val, 1e-10) # assign bad array shape to array with assertRaisesRegex(self, ValueError, msg): outputs['C2.y'] = bad_val # assign list to array outputs['C2.y'] = arr_val.tolist() assert_rel_error(self, outputs['C2.y'], arr_val, 1e-10) # assign bad list shape to array with assertRaisesRegex(self, ValueError, msg): outputs['C2.y'] = bad_val.tolist() # # set residual # # assign array to scalar with assertRaisesRegex(self, ValueError, msg): residuals['C1.b'] = arr_val # assign scalar to array residuals['C2.y'] = num_val assert_rel_error(self, residuals['C2.y'], arr_val, 1e-10) # assign array to array residuals['C2.y'] = arr_val assert_rel_error(self, residuals['C2.y'], arr_val, 1e-10) # assign bad array shape to array with assertRaisesRegex(self, ValueError, msg): residuals['C2.y'] = bad_val # assign list to array residuals['C2.y'] = arr_val.tolist() assert_rel_error(self, residuals['C2.y'], arr_val, 1e-10) # assign bad list shape to array with assertRaisesRegex(self, ValueError, msg): residuals['C2.y'] = bad_val.tolist()
def test_compute_and_derivs(self): prob = self.prob prob.run_model() assert_rel_error(self, prob['comp2.x'], 3.) assert_rel_error(self, prob['comp2.x'], 3.) total_derivs = prob.compute_totals( wrt=['comp1.a', 'comp1.b', 'comp1.c'], of=['comp2.x', 'comp3.x']) assert_rel_error(self, total_derivs['comp2.x', 'comp1.a'], [[-4.5]]) assert_rel_error(self, total_derivs['comp2.x', 'comp1.b'], [[-1.5]]) assert_rel_error(self, total_derivs['comp2.x', 'comp1.c'], [[-0.5]]) assert_rel_error(self, total_derivs['comp3.x', 'comp1.a'], [[-4.5]]) assert_rel_error(self, total_derivs['comp3.x', 'comp1.b'], [[-1.5]]) assert_rel_error(self, total_derivs['comp3.x', 'comp1.c'], [[-0.5]])
def test(self): # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5 } mesh, twist_cp = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'symmetry': True, # if true, model one half of wing # reflected across the plane y = 0 'fem_model_type': 'tube', 'mesh': mesh, 'radius_cp': np.ones((5)) * 0.5, # 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 't_over_c_cp': np.array([0.15]), # maximum airfoil thickness 'thickness_cp': np.ones((3)) * .1, '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, 'exact_failure_constraint': False, } # Create the problem and assign the model group prob = Problem() ny = surf_dict['mesh'].shape[1] indep_var_comp = IndepVarComp() indep_var_comp.add_output('loads', val=np.ones((ny, 6)) * 2e5, units='N') indep_var_comp.add_output('load_factor', val=1.) struct_group = SpatialBeamAlone(surface=surf_dict) # Add indep_vars to the structural group struct_group.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) prob.model.add_subsystem(surf_dict['name'], struct_group) # Set up the problem prob.setup() prob.run_model() assert_rel_error(self, prob['wing.structural_mass'][0], 117819.798089, 1e-4)
def test_continuity_comp(self, transcription='gauss-lobatto', compressed='compressed'): num_seg = 3 gd = GridData(num_segments=num_seg, transcription_order=[5, 3, 3], segment_ends=[0.0, 3.0, 10.0, 20], transcription=transcription, compressed=compressed == 'compressed') self.p = Problem(model=Group()) ivp = self.p.model.add_subsystem('ivc', subsys=IndepVarComp(), promotes_outputs=['*']) ndn = gd.subset_num_nodes['state_disc'] nn = gd.subset_num_nodes['all'] ivp.add_output('x', val=np.arange(nn), units='m') ivp.add_output('y', val=np.arange(nn), units='m/s') ivp.add_output('u', val=np.zeros((nn, 3)), units='deg') ivp.add_output('v', val=np.arange(nn), units='N') ivp.add_output('u_rate', val=np.zeros((nn, 3)), units='deg/s') ivp.add_output('v_rate', val=np.arange(nn), units='N/s') ivp.add_output('u_rate2', val=np.zeros((nn, 3)), units='deg/s**2') ivp.add_output('v_rate2', val=np.arange(nn), units='N/s**2') ivp.add_output('t_duration', val=121.0, units='s') self.p.model.add_design_var('x', lower=0, upper=100) state_options = { 'x': StateOptionsDictionary(), 'y': StateOptionsDictionary() } control_options = { 'u': ControlOptionsDictionary(), 'v': ControlOptionsDictionary() } state_options['x']['units'] = 'm' state_options['y']['units'] = 'm/s' control_options['u']['units'] = 'deg' control_options['u']['shape'] = (3, ) control_options['u']['continuity'] = True control_options['v']['units'] = 'N' if transcription == 'gauss-lobatto': cnty_comp = GaussLobattoContinuityComp( grid_data=gd, time_units='s', state_options=state_options, control_options=control_options) elif transcription == 'radau-ps': cnty_comp = RadauPSContinuityComp(grid_data=gd, time_units='s', state_options=state_options, control_options=control_options) else: raise ValueError('unrecognized transcription') self.p.model.add_subsystem('cnty_comp', subsys=cnty_comp) # The sub-indices of state_disc indices that are segment ends segment_end_idxs = gd.subset_node_indices['segment_ends'] self.p.model.connect('x', 'cnty_comp.states:x', src_indices=segment_end_idxs) self.p.model.connect('y', 'cnty_comp.states:y', src_indices=segment_end_idxs) self.p.model.connect('t_duration', 'cnty_comp.t_duration') size_u = nn * np.prod(control_options['u']['shape']) src_idxs_u = np.arange(size_u).reshape((nn, ) + control_options['u']['shape']) src_idxs_u = src_idxs_u[gd.subset_node_indices['segment_ends'], ...] size_v = nn * np.prod(control_options['v']['shape']) src_idxs_v = np.arange(size_v).reshape((nn, ) + control_options['v']['shape']) src_idxs_v = src_idxs_v[gd.subset_node_indices['segment_ends'], ...] self.p.model.connect('u', 'cnty_comp.controls:u', src_indices=src_idxs_u, flat_src_indices=True) self.p.model.connect('u_rate', 'cnty_comp.control_rates:u_rate', src_indices=src_idxs_u, flat_src_indices=True) self.p.model.connect('u_rate2', 'cnty_comp.control_rates:u_rate2', src_indices=src_idxs_u, flat_src_indices=True) self.p.model.connect('v', 'cnty_comp.controls:v', src_indices=src_idxs_v, flat_src_indices=True) self.p.model.connect('v_rate', 'cnty_comp.control_rates:v_rate', src_indices=src_idxs_v, flat_src_indices=True) self.p.model.connect('v_rate2', 'cnty_comp.control_rates:v_rate2', src_indices=src_idxs_v, flat_src_indices=True) self.p.setup(check=True, force_alloc_complex=True) self.p['x'] = np.random.rand(*self.p['x'].shape) self.p['y'] = np.random.rand(*self.p['y'].shape) self.p['u'] = np.random.rand(*self.p['u'].shape) self.p['v'] = np.random.rand(*self.p['v'].shape) self.p['u_rate'] = np.random.rand(*self.p['u'].shape) self.p['v_rate'] = np.random.rand(*self.p['v'].shape) self.p['u_rate2'] = np.random.rand(*self.p['u'].shape) self.p['v_rate2'] = np.random.rand(*self.p['v'].shape) self.p.run_model() for state in ('x', 'y'): expected_val = self.p[state][segment_end_idxs, ...][2::2, ...] - \ self.p[state][segment_end_idxs, ...][1:-1:2, ...] assert_rel_error( self, self.p['cnty_comp.defect_states:{0}'.format(state)], expected_val.reshape((num_seg - 1, ) + state_options[state]['shape'])) for ctrl in ('u', 'v'): expected_val = self.p[ctrl][segment_end_idxs, ...][2::2, ...] - \ self.p[ctrl][segment_end_idxs, ...][1:-1:2, ...] assert_rel_error( self, self.p['cnty_comp.defect_controls:{0}'.format(ctrl)], expected_val.reshape((num_seg - 1, ) + control_options[ctrl]['shape'])) np.set_printoptions(linewidth=1024) cpd = self.p.check_partials(method='cs', out_stream=None) assert_check_partials(cpd)
def test(self): from openaerostruct.geometry.utils import generate_mesh, write_FFD_file from openaerostruct.geometry.geometry_group import Geometry from openaerostruct.transfer.displacement_transfer import DisplacementTransfer from openaerostruct.aerodynamics.aero_groups import AeroPoint from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver # TODO, SqliteRecorder, CaseReader, profile from openmdao.devtools import iprofile from openmdao.api import view_model from six import iteritems from pygeo import DVGeometry # Create a dictionary to store options about the surface mesh_dict = { 'num_y': 7, 'num_x': 3, 'wing_type': 'CRM', 'symmetry': True, 'num_twist_cp': 5, 'span_cos_spacing': 0. } mesh, _ = generate_mesh(mesh_dict) surf_dict = { # Wing definition 'name': 'wing', # name of the surface 'type': 'aero', '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', 'DVGeo': True, 'mesh': mesh, 'mx': 2, 'my': 3, # 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 } surf_dict['num_x'], surf_dict['num_y'] = surf_dict['mesh'].shape[:2] surfaces = [surf_dict] # Create the problem and the model group prob = Problem() indep_var_comp = IndepVarComp() indep_var_comp.add_output('v', val=248.136, units='m/s') indep_var_comp.add_output('alpha', val=6.64, units='deg') indep_var_comp.add_output('M', 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') prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*']) # Loop over each surface in the surfaces list for surface in surfaces: filename = write_FFD_file(surface, surface['mx'], surface['my']) DVGeo = DVGeometry(filename) geom_group = Geometry(surface=surface, DVGeo=DVGeo) # Add tmp_group to the problem as the name of the surface. # Note that is a group and performance group for each # individual surface. prob.model.add_subsystem(surface['name'], geom_group) # Loop through and add a certain number of aero points for i in range(1): # Create the aero point group and add it to the model aero_group = AeroPoint(surfaces=surfaces) point_name = 'aero_point_{}'.format(i) prob.model.add_subsystem(point_name, aero_group) # Connect flow properties to the analysis point prob.model.connect('v', point_name + '.v') prob.model.connect('alpha', point_name + '.alpha') prob.model.connect('M', point_name + '.M') prob.model.connect('re', point_name + '.re') prob.model.connect('rho', point_name + '.rho') prob.model.connect('cg', point_name + '.cg') # Connect the parameters within the model for each aero point for surface in surfaces: 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') from openmdao.api import pyOptSparseDriver prob.driver = pyOptSparseDriver() prob.driver.options['optimizer'] = "SNOPT" prob.driver.opt_settings = { 'Major optimality tolerance': 1.0e-6, 'Major feasibility tolerance': 1.0e-6 } # Setup problem and add design variables, constraint, and objective prob.model.add_design_var('alpha', lower=-15, upper=15) prob.model.add_design_var('wing.shape', lower=-3, upper=2) # prob.model.add_constraint('wing.shape', equals=0., indices=range(surf_dict['my'] * 2), linear=True) 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 the problem prob.setup() # view_model(prob, outfile='aero.html', show_browser=False) # prob.run_model() prob.run_driver() assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03398038, 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], -0.18379626783513864, 1e-5)
def test_cruise_results(self): p = Problem(model=Group()) if optimizer == 'SNOPT': p.driver = pyOptSparseDriver() p.driver.options['optimizer'] = optimizer p.driver.options['dynamic_simul_derivs'] = True p.driver.opt_settings['Major iterations limit'] = 100 p.driver.opt_settings['Major step limit'] = 0.05 p.driver.opt_settings['Major feasibility tolerance'] = 1.0E-6 p.driver.opt_settings['Major optimality tolerance'] = 1.0E-6 p.driver.opt_settings["Linesearch tolerance"] = 0.10 p.driver.opt_settings['iSumm'] = 6 p.driver.opt_settings['Verify level'] = 3 else: p.driver = ScipyOptimizeDriver() p.driver.options['dynamic_simul_derivs'] = True phase = Phase('gauss-lobatto', ode_class=AircraftODE, num_segments=1, transcription_order=13) # Pass Reference Area from an external source assumptions = p.model.add_subsystem('assumptions', IndepVarComp()) assumptions.add_output('S', val=427.8, units='m**2') assumptions.add_output('mass_empty', val=1.0, units='kg') assumptions.add_output('mass_payload', val=1.0, units='kg') p.model.add_subsystem('phase0', phase) phase.set_time_options(initial_bounds=(0, 0), duration_bounds=(3600, 3600), duration_ref=3600) phase.set_state_options('range', units='km', fix_initial=True, fix_final=False, scaler=0.01, defect_scaler=0.01) phase.set_state_options('mass_fuel', fix_final=True, upper=20000.0, lower=0.0, scaler=1.0E-4, defect_scaler=1.0E-2) phase.add_control('alt', units='km', opt=False, rate_param='climb_rate') phase.add_control('mach', units=None, opt=False) phase.add_input_parameter('S', units='m**2') phase.add_input_parameter('mass_empty', units='kg') phase.add_input_parameter('mass_payload', units='kg') phase.add_path_constraint('propulsion.tau', lower=0.01, upper=1.0) p.model.connect('assumptions.S', 'phase0.input_parameters:S') p.model.connect('assumptions.mass_empty', 'phase0.input_parameters:mass_empty') p.model.connect('assumptions.mass_payload', 'phase0.input_parameters:mass_payload') phase.add_objective('time', loc='final', ref=3600) p.model.linear_solver = DirectSolver(assemble_jac=True) p.model.options['assembled_jac_type'] = 'csc' p.setup() p['phase0.t_initial'] = 0.0 p['phase0.t_duration'] = 1.515132 * 3600.0 p['phase0.states:range'] = phase.interpolate(ys=(0, 1296.4), nodes='state_input') p['phase0.states:mass_fuel'] = phase.interpolate(ys=(12236.594555, 0), nodes='state_input') p['phase0.controls:mach'] = 0.8 p['phase0.controls:alt'] = 5.0 p['assumptions.S'] = 427.8 p['assumptions.mass_empty'] = 0.15E6 p['assumptions.mass_payload'] = 84.02869 * 400 p.run_driver() tas = phase.get_values('tas_comp.TAS', units='m/s') time = phase.get_values('time', units='s') range = phase.get_values('range', units='m') assert_rel_error(self, range, tas * time, tolerance=1.0E-9)