Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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])
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
    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)
Ejemplo n.º 22
0
    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.]])
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    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)
Ejemplo n.º 25
0
    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)
Ejemplo n.º 26
0
    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))
Ejemplo n.º 27
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)
Ejemplo n.º 28
0
    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)
Ejemplo n.º 29
0
    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)
Ejemplo n.º 30
0
    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)
Ejemplo n.º 31
0
 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)
Ejemplo n.º 34
0
    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)
Ejemplo n.º 35
0
    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)
Ejemplo n.º 36
0
    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)
Ejemplo n.º 38
0
    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)
Ejemplo n.º 40
0
 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)
Ejemplo n.º 42
0
    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)
Ejemplo n.º 43
0
    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)
Ejemplo n.º 47
0
    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)
Ejemplo n.º 48
0
    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)
Ejemplo n.º 49
0
    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)
Ejemplo n.º 51
0
    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.)
Ejemplo n.º 52
0
    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
Ejemplo n.º 53
0
    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)
Ejemplo n.º 54
0
    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()
Ejemplo n.º 55
0
    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()
Ejemplo n.º 56
0
    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)
Ejemplo n.º 58
0
    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)
Ejemplo n.º 59
0
    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)
Ejemplo n.º 60
0
    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)