def test_distributed_driver_debug_print_options(self):

        # check that pyoptsparse is installed. if it is, try to use SLSQP.
        OPT, OPTIMIZER = set_pyoptsparse_opt('SLSQP')

        if OPTIMIZER:
            from openmdao.drivers.pyoptsparse_driver import pyOptSparseDriver

        class Mygroup(Group):

            def setup(self):
                self.add_subsystem('indep_var_comp', IndepVarComp('x'), promotes=['*'])
                self.add_subsystem('Cy', ExecComp('y=2*x'), promotes=['*'])
                self.add_subsystem('Cc', ExecComp('c=x+2'), promotes=['*'])

                self.add_design_var('x')
                self.add_constraint('c', lower=-3.)

        prob = Problem()

        prob.model.add_subsystem('par', ParallelGroup())

        prob.model.par.add_subsystem('G1', Mygroup())
        prob.model.par.add_subsystem('G2', Mygroup())

        prob.model.add_subsystem('Obj', ExecComp('obj=y1+y2'))

        prob.model.connect('par.G1.y', 'Obj.y1')
        prob.model.connect('par.G2.y', 'Obj.y2')

        prob.model.add_objective('Obj.obj')

        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'SLSQP'
        prob.driver.options['print_results'] = False

        prob.driver.options['debug_print'] = ['desvars','ln_cons','nl_cons','objs']

        prob.setup(vector_class=PETScVector)

        stdout = sys.stdout
        strout = StringIO()
        sys.stdout = strout
        sys.stdout = strout
        try:
            prob.run_driver()
        finally:
            sys.stdout = stdout

        output = strout.getvalue().split('\n')
        if MPI.COMM_WORLD.rank == 0:
            # Just make sure we have more than one. Not sure we will always have the same number
            #    of iterations
            self.assertTrue(output.count("Design Vars") > 1,
                            "Should be more than one design vars header printed")
            self.assertTrue(output.count("Nonlinear constraints") > 1,
                            "Should be more than one nonlinear constraint header printed")
            self.assertTrue(output.count("Linear constraints") > 1,
                            "Should be more than one linear constraint header printed")
            self.assertTrue(output.count("Objectives") > 1,
                            "Should be more than one objective header printed")

            self.assertTrue(len([s for s in output if s.startswith('par.G1.indep_var_comp.x')]) > 1,
                            "Should be more than one par.G1.indep_var_comp.x printed")
            self.assertTrue(len([s for s in output if s.startswith('par.G2.indep_var_comp.x')]) > 1,
                            "Should be more than one par.G2.indep_var_comp.x printed")
            self.assertTrue(len([s for s in output if s.startswith('par.G1.Cc.c')]) > 1,
                            "Should be more than one par.G1.Cc.c printed")
            self.assertTrue(len([s for s in output if s.startswith('par.G2.Cc.c')]) > 1,
                            "Should be more than one par.G2.Cc.c printed")
            self.assertTrue(len([s for s in output if s.startswith('None')]) > 1,
                            "Should be more than one None printed")
            self.assertTrue(len([s for s in output if s.startswith('Obj.obj')]) > 1,
                            "Should be more than one Obj.obj printed")
        else:
            self.assertEqual(output, [''])
    def test_fan_in_grouped(self):
        size = 3

        prob = Problem()
        prob.model = root = Group()

        root.add_subsystem('P1',
                           IndepVarComp('x', numpy.ones(size, dtype=float)))
        root.add_subsystem('P2',
                           IndepVarComp('x', numpy.ones(size, dtype=float)))
        sub = root.add_subsystem('sub', ParallelGroup())

        sub.add_subsystem(
            'C1',
            ExecComp(['y=-2.0*x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))
        sub.add_subsystem(
            'C2',
            ExecComp(['y=5.0*x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))
        root.add_subsystem(
            'C3',
            DistribExecComp(['y=3.0*x1+7.0*x2', 'y=1.5*x1+3.5*x2'],
                            arr_size=size,
                            x1=numpy.zeros(size, dtype=float),
                            x2=numpy.zeros(size, dtype=float),
                            y=numpy.zeros(size, dtype=float)))
        root.add_subsystem(
            'C4',
            ExecComp(['y=x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))

        root.connect("sub.C1.y", "C3.x1")
        root.connect("sub.C2.y", "C3.x2")
        root.connect("P1.x", "sub.C1.x")
        root.connect("P2.x", "sub.C2.x")
        root.connect("C3.y", "C4.x")

        root.linear_solver = LinearBlockGS()
        sub.linear_solver = LinearBlockGS()

        prob.model.suppress_solver_output = True
        sub.suppress_solver_output = True
        prob.setup(vector_class=PETScVector, check=False, mode='fwd')
        prob.run_driver()

        diag1 = numpy.diag([-6.0, -6.0, -3.0])
        diag2 = numpy.diag([35.0, 35.0, 17.5])

        J = prob.compute_totals(of=['C4.y'], wrt=['P1.x', 'P2.x'])
        assert_rel_error(self, J['C4.y', 'P1.x'], diag1, 1e-6)
        assert_rel_error(self, J['C4.y', 'P2.x'], diag2, 1e-6)

        prob.setup(vector_class=PETScVector, check=False, mode='rev')

        prob.run_driver()

        J = prob.compute_totals(of=['C4.y'], wrt=['P1.x', 'P2.x'])
        assert_rel_error(self, J['C4.y', 'P1.x'], diag1, 1e-6)
        assert_rel_error(self, J['C4.y', 'P2.x'], diag2, 1e-6)
Beispiel #3
0
    def test_recording_remote_voi(self):
        # Create a parallel model
        model = Group()

        model.add_subsystem('par', ParallelGroup())
        model.par.add_subsystem('G1', Mygroup())
        model.par.add_subsystem('G2', Mygroup())
        model.connect('par.G1.y', 'Obj.y1')
        model.connect('par.G2.y', 'Obj.y2')

        model.add_subsystem('Obj', ExecComp('obj=y1+y2'))
        model.add_objective('Obj.obj')

        # Configure driver to record VOIs on both procs
        driver = ScipyOptimizeDriver(disp=False)

        driver.recording_options['record_desvars'] = True
        driver.recording_options['record_objectives'] = True
        driver.recording_options['record_constraints'] = True
        driver.recording_options['includes'] = ['par.G1.y', 'par.G2.y']

        driver.add_recorder(self.recorder)

        # Create problem and run driver
        prob = Problem(model, driver)
        prob.add_recorder(self.recorder)
        prob.setup(mode='fwd')

        t0, t1 = run_driver(prob)
        prob.record_iteration('final')
        t2 = time()

        prob.cleanup()

        # Since the test will compare the last case recorded, just check the
        # current values in the problem. This next section is about getting those values

        # These involve collective gathers so all ranks need to run this
        expected_outputs = driver.get_design_var_values()
        expected_outputs.update(driver.get_objective_values())
        expected_outputs.update(driver.get_constraint_values())

        # includes for outputs are specified as promoted names but we need absolute names
        prom2abs = model._var_allprocs_prom2abs_list['output']
        abs_includes = [prom2abs[n][0] for n in prob.driver.recording_options['includes']]

        # Absolute path names of includes on this rank
        rrank = model.comm.rank
        rowned = model._owning_rank
        local_includes = [n for n in abs_includes if rrank == rowned[n]]

        # Get values for all vars on this rank
        inputs, outputs, residuals = model.get_nonlinear_vectors()

        # Get values for includes on this rank
        local_vars = {n: outputs[n] for n in local_includes}

        # Gather values for includes on all ranks
        all_vars = model.comm.gather(local_vars, root=0)

        if prob.comm.rank == 0:
            # Only on rank 0 do we have all the values. The all_vars variable is a list of
            # dicts from all ranks 0,1,... In this case, just ranks 0 and 1
            dct = {}
            for d in all_vars:
                dct.update(d)

            expected_includes = {
                'par.G1.Cy.y': dct['par.G1.Cy.y'],
                'par.G2.Cy.y': dct['par.G2.Cy.y'],
            }

            expected_outputs.update(expected_includes)

            coordinate = [0, 'ScipyOptimize_SLSQP', (driver.iter_count-1,)]

            expected_data = ((coordinate, (t0, t1), expected_outputs, None),)
            assertDriverIterDataRecorded(self, expected_data, self.eps)

            expected_data = (('final', (t1, t2), expected_outputs),)
            assertProblemDataRecorded(self, expected_data, self.eps)
    def test_fan_out_grouped(self):
        size = 3
        prob = Problem()
        prob.model = root = Group()
        root.add_subsystem('P', IndepVarComp('x', numpy.ones(size,
                                                             dtype=float)))
        root.add_subsystem(
            'C1',
            DistribExecComp(['y=3.0*x', 'y=2.0*x'],
                            arr_size=size,
                            x=numpy.zeros(size, dtype=float),
                            y=numpy.zeros(size, dtype=float)))
        sub = root.add_subsystem('sub', ParallelGroup())
        sub.add_subsystem(
            'C2', ExecComp('y=1.5*x', x=numpy.zeros(size),
                           y=numpy.zeros(size)))
        sub.add_subsystem(
            'C3',
            ExecComp(['y=5.0*x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))

        root.add_subsystem(
            'C2',
            ExecComp(['y=x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))
        root.add_subsystem(
            'C3',
            ExecComp(['y=x'],
                     x=numpy.zeros(size, dtype=float),
                     y=numpy.zeros(size, dtype=float)))
        root.connect('sub.C2.y', 'C2.x')
        root.connect('sub.C3.y', 'C3.x')

        root.connect("C1.y", "sub.C2.x")
        root.connect("C1.y", "sub.C3.x")
        root.connect("P.x", "C1.x")

        prob.setup(vector_class=PETScVector, check=False, mode='fwd')
        prob.run_model()

        diag1 = [4.5, 4.5, 3.0]
        diag2 = [15.0, 15.0, 10.0]

        assert_rel_error(self, prob['C2.y'], diag1)
        assert_rel_error(self, prob['C3.y'], diag2)

        diag1 = numpy.diag(diag1)
        diag2 = numpy.diag(diag2)

        J = prob.compute_totals(of=['C2.y', "C3.y"], wrt=['P.x'])
        assert_rel_error(self, J['C2.y', 'P.x'], diag1, 1e-6)
        assert_rel_error(self, J['C3.y', 'P.x'], diag2, 1e-6)

        prob.setup(vector_class=PETScVector, check=False, mode='rev')
        prob.run_model()

        J = prob.compute_totals(of=['C2.y', "C3.y"], wrt=['P.x'])
        assert_rel_error(self, J['C2.y', 'P.x'], diag1, 1e-6)
        assert_rel_error(self, J['C3.y', 'P.x'], diag2, 1e-6)
Beispiel #5
0
    def test_recording_remote_voi(self):
        prob = Problem()

        prob.model.add_subsystem('par', ParallelGroup())

        prob.model.par.add_subsystem('G1', Mygroup())
        prob.model.par.add_subsystem('G2', Mygroup())

        prob.model.add_subsystem('Obj', ExecComp('obj=y1+y2'))

        prob.model.connect('par.G1.y', 'Obj.y1')
        prob.model.connect('par.G2.y', 'Obj.y2')

        prob.model.add_objective('Obj.obj')

        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'SLSQP'

        prob.driver.recording_options['record_desvars'] = True
        prob.driver.recording_options['record_responses'] = True
        prob.driver.recording_options['record_objectives'] = True
        prob.driver.recording_options['record_constraints'] = True
        prob.driver.recording_options['includes'] = [
            'par.G1.Cy.y', 'par.G2.Cy.y'
        ]

        prob.driver.add_recorder(self.recorder)

        prob.setup(vector_class=PETScVector)
        t0, t1 = run_driver(prob)
        prob.cleanup()

        # Since the test will compare the last case recorded, just check the
        #   current values in the problem. This next section is about getting those values

        # These involve collective gathers so all ranks need to run this
        expected_desvars = prob.driver.get_design_var_values()
        expected_objectives = prob.driver.get_objective_values()
        expected_constraints = prob.driver.get_constraint_values()

        # Determine the expected values for the sysincludes
        # this gets all of the outputs but just locally
        rrank = prob.comm.rank  # root ( aka model ) rank.
        rowned = prob.model._owning_rank['output']
        # names of sysincl vars on this rank
        local_inclnames = [
            n for n in prob.driver.recording_options['includes']
            if rrank == rowned[n]
        ]
        # Get values for vars on this rank
        inputs, outputs, residuals = prob.model.get_nonlinear_vectors()
        #   Potential local sysvars are in this
        sysvars = outputs._names
        # Just get the values for the sysincl vars on this rank
        local_vars = {c: sysvars[c] for c in local_inclnames}
        # Gather up the values for all the sysincl vars on all ranks
        all_vars = prob.model.comm.gather(local_vars, root=0)

        if prob.comm.rank == 0:
            # Only on rank 0 do we have all the values and only on rank 0
            #   are we doing the testing.
            # The all_vars variable is list of dicts from rank 0,1,... In this case just ranks 0 and 1
            dct = all_vars[-1]
            for d in all_vars[:-1]:
                dct.update(d)

            expected_includes = {
                'par.G1.Cy.y': dct['par.G1.Cy.y'],
                'par.G2.Cy.y': dct['par.G2.Cy.y'],
            }

        if prob.comm.rank == 0:
            coordinate = [0, 'SLSQP', (49, )]
            self.assertDriverIterationDataRecorded(
                ((coordinate,
                  (t0, t1), expected_desvars, None, expected_objectives,
                  expected_constraints, expected_includes), ), self.eps)
Beispiel #6
0
    def setup(self):
        E = self.metadata['E']
        L = self.metadata['L']
        b = self.metadata['b']
        volume = self.metadata['volume']
        max_bending = self.metadata['max_bending']
        num_elements = self.metadata['num_elements']
        num_nodes = num_elements + 1
        num_cp = self.metadata['num_cp']
        num_load_cases = self.metadata['num_load_cases']
        parallel_derivs = self.metadata['parallel_derivs']

        inputs_comp = IndepVarComp()
        inputs_comp.add_output('h_cp', shape=num_cp)
        self.add_subsystem('inputs_comp', inputs_comp)

        comp = BsplinesComp(num_control_points=num_cp, num_points=num_elements, in_name='h_cp',
                            out_name='h')
        self.add_subsystem('interp', comp)

        I_comp = MomentOfInertiaComp(num_elements=num_elements, b=b)
        self.add_subsystem('I_comp', I_comp)

        comp = LocalStiffnessMatrixComp(num_elements=num_elements, E=E, L=L)
        self.add_subsystem('local_stiffness_matrix_comp', comp)

        # Parallel Subsystem for load cases.
        par = self.add_subsystem('parallel', ParallelGroup())

        # Determine how to split cases up over the available procs.
        nprocs = self.comm.size
        divide = divide_cases(num_load_cases, nprocs)

        for j, this_proc in enumerate(divide):
            num_rhs = len(this_proc)

            name = 'sub_%d' % j
            sub = par.add_subsystem(name, Group())

            # Load is a sinusoidal distributed force of varying spatial frequency.
            force_vector = np.zeros((2 * num_nodes, num_rhs))
            for i, k in enumerate(this_proc):

                end = 1.5 * np.pi
                if num_load_cases > 1:
                    end += k * 0.5 * np.pi / (num_load_cases - 1)

                x = np.linspace(0, end, num_nodes)
                f = - np.sin(x)
                force_vector[0:-1:2, i] = f

            comp = GlobalStiffnessMatrixComp(num_elements=num_elements)
            sub.add_subsystem('global_stiffness_matrix_comp', comp)

            comp = MultiStatesComp(num_elements=num_elements, force_vector=force_vector,
                                   num_rhs=num_rhs)
            sub.add_subsystem('states_comp', comp)

            comp = MultiDisplacementsComp(num_elements=num_elements, num_rhs=num_rhs)
            sub.add_subsystem('displacements_comp', comp)

            comp = MultiStressComp(num_elements=num_elements, E=E, num_rhs=num_rhs)
            sub.add_subsystem('stress_comp', comp)

            self.connect(
                'local_stiffness_matrix_comp.K_local',
                'parallel.%s.global_stiffness_matrix_comp.K_local' % name)

            sub.connect(
                'global_stiffness_matrix_comp.K',
                'states_comp.K')

            for k in range(num_rhs):
                sub.connect(
                    'states_comp.d_%d' % k,
                    'displacements_comp.d_%d' % k)
                sub.connect(
                    'displacements_comp.displacements_%d' % k,
                    'stress_comp.displacements_%d' % k)

                comp = KSComponent(width=num_elements)
                comp.options['upper'] = max_bending
                sub.add_subsystem('KS_%d' % k, comp)

                sub.connect(
                    'stress_comp.stress_%d' % k,
                    'KS_%d.g' % k)

                if parallel_derivs:
                    color = 'red_%d' % k
                else:
                    color = None

                sub.add_constraint('KS_%d.KS' % k, upper=0.0,
                                   parallel_deriv_color=color)

        comp = VolumeComp(num_elements=num_elements, b=b, L=L)
        self.add_subsystem('volume_comp', comp)

        self.connect('inputs_comp.h_cp', 'interp.h_cp')
        self.connect('interp.h', 'I_comp.h')
        self.connect('I_comp.I', 'local_stiffness_matrix_comp.I')
        self.connect('interp.h', 'volume_comp.h')

        self.add_design_var('inputs_comp.h_cp', lower=1e-2, upper=10.)
        self.add_objective('volume_comp.volume')
    def test_zero_shape(self):
        raise unittest.SkipTest("zero shapes not fully supported yet")
        class MultComp(ExplicitComponent):
            def __init__(self, mult):
                self.mult = mult
                super(MultComp, self).__init__()

            def setup(self):
                if self.comm.rank == 0:
                    self.add_input('x', shape=1)
                    self.add_output('y', shape=1)
                else:
                    self.add_input('x', shape=0)
                    self.add_output('y', shape=0)

            def compute(self, inputs, outputs):
                outputs['y'] = inputs['x'] * self.mult

            def compute_partials(self, inputs, partials):
                partials['y', 'x'] = np.array([self.mult])

        prob = Problem()

        model = prob.model
        model.add_subsystem('iv', IndepVarComp('x', 1.0))
        model.add_subsystem('c1', MultComp(3.0))

        model.sub = model.add_subsystem('sub', ParallelGroup())
        model.sub.add_subsystem('c2', MultComp(-2.0))
        model.sub.add_subsystem('c3', MultComp(5.0))

        model.add_subsystem('c2', MultComp(1.0))
        model.add_subsystem('c3', MultComp(1.0))

        model.connect('iv.x', 'c1.x')

        model.connect('c1.y', 'sub.c2.x')
        model.connect('c1.y', 'sub.c3.x')

        model.connect('sub.c2.y', 'c2.x')
        model.connect('sub.c3.y', 'c3.x')

        of=['c2.y', "c3.y"]
        wrt=['iv.x']

        prob.setup(check=False, mode='fwd')
        prob.set_solver_print(level=0)
        prob.run_model()

        J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x'])

        assert_rel_error(self, J['c2.y', 'iv.x'][0][0], -6.0, 1e-6)
        assert_rel_error(self, J['c3.y', 'iv.x'][0][0], 15.0, 1e-6)

        assert_rel_error(self, prob['c2.y'], -6.0, 1e-6)
        assert_rel_error(self, prob['c3.y'], 15.0, 1e-6)

        prob.setup(check=False, mode='rev')
        prob.run_model()

        J = prob.compute_totals(of=['c2.y', "c3.y"], wrt=['iv.x'])

        assert_rel_error(self, J['c2.y', 'iv.x'][0][0], -6.0, 1e-6)
        assert_rel_error(self, J['c3.y', 'iv.x'][0][0], 15.0, 1e-6)

        assert_rel_error(self, prob['c2.y'], -6.0, 1e-6)
        assert_rel_error(self, prob['c3.y'], 15.0, 1e-6)
Beispiel #8
0
    def __init__(self,
                 nTurbines,
                 nDirections=1,
                 use_rotor_components=False,
                 datasize=0,
                 differentiable=True,
                 optimizingLayout=False,
                 nSamples=0,
                 method_dict=None):

        super(AEPGroup, self).__init__()

        # providing default unit types for general MUX/DeMUX components
        power_units = 'kW'
        direction_units = 'deg'
        wind_speed_units = 'm/s'
        turbine_units = 'm'

        # print 'SAMPLES: ', nSamples

        # add necessary inputs for group
        self.add('dv0',
                 IndepVarComp('windDirections',
                              np.zeros(nDirections),
                              units=direction_units),
                 promotes=['*'])
        self.add('dv1',
                 IndepVarComp('windSpeeds',
                              np.zeros(nDirections),
                              units=wind_speed_units),
                 promotes=['*'])
        self.add('dv2',
                 IndepVarComp('weights', np.zeros(nDirections)),
                 promotes=['*'])

        self.add('dv3',
                 IndepVarComp('turbineX',
                              np.zeros(nTurbines),
                              units=turbine_units),
                 promotes=['*'])
        self.add('dv4',
                 IndepVarComp('turbineY',
                              np.zeros(nTurbines),
                              units=turbine_units),
                 promotes=['*'])

        # add vars to be seen by MPI and gradient calculations
        self.add('dv5',
                 IndepVarComp('rotorDiameter',
                              np.zeros(nTurbines),
                              units=turbine_units),
                 promotes=['*'])
        self.add('dv6',
                 IndepVarComp('axialInduction', np.zeros(nTurbines)),
                 promotes=['*'])
        self.add('dv7',
                 IndepVarComp('generatorEfficiency', np.zeros(nTurbines)),
                 promotes=['*'])
        self.add('dv8',
                 IndepVarComp('air_density', val=1.1716, units='kg/(m*m*m)'),
                 promotes=['*'])

        # add variable tree IndepVarComps
        add_floris_params_IndepVarComps(
            self, use_rotor_components=use_rotor_components)
        add_gen_params_IdepVarComps(self, datasize=datasize)

        # add components and groups
        self.add('windDirectionsDeMUX',
                 DeMUX(nDirections, units=direction_units))
        self.add('windSpeedsDeMUX', DeMUX(nDirections, units=wind_speed_units))

        pg = self.add('all_directions', ParallelGroup(), promotes=['*'])

        # Can probably simplify the below rotor components logic
        if not use_rotor_components:
            self.add('dv9',
                     IndepVarComp('Ct_in', np.zeros(nTurbines)),
                     promotes=['*'])
            self.add('dv10',
                     IndepVarComp('Cp_in', np.zeros(nTurbines)),
                     promotes=['*'])

        #The if nSamples == 0 is left in for visualization
        if use_rotor_components:
            for direction_id in np.arange(0, nDirections):
                # print 'assigning direction group %i' % direction_id
                pg.add(
                    'direction_group%i' % direction_id,
                    DirectionGroup(nTurbines=nTurbines,
                                   direction_id=direction_id,
                                   use_rotor_components=use_rotor_components,
                                   datasize=datasize,
                                   differentiable=differentiable,
                                   add_IdepVarComps=False,
                                   nSamples=nSamples),
                    promotes=([
                        'gen_params:*', 'floris_params:*', 'air_density',
                        'axialInduction', 'generatorEfficiency', 'turbineX',
                        'turbineY', 'hubHeight',
                        'yaw%i' % direction_id, 'rotorDiameter',
                        'wtVelocity%i' % direction_id,
                        'wtPower%i' % direction_id,
                        'dir_power%i' % direction_id
                    ] if (nSamples == 0) else [
                        'gen_params:*', 'floris_params:*', 'air_density',
                        'axialInduction', 'generatorEfficiency', 'turbineX',
                        'turbineY', 'hubHeight',
                        'yaw%i' % direction_id, 'rotorDiameter', 'wsPositionX',
                        'wsPositionY', 'wsPositionZ',
                        'wtVelocity%i' % direction_id,
                        'wtPower%i' % direction_id,
                        'dir_power%i' % direction_id,
                        'wsArray%i' % direction_id
                    ]))
        else:
            for direction_id in np.arange(0, nDirections):
                # print 'assigning direction group %i' % direction_id
                pg.add(
                    'direction_group%i' % direction_id,
                    DirectionGroup(nTurbines=nTurbines,
                                   direction_id=direction_id,
                                   use_rotor_components=use_rotor_components,
                                   datasize=datasize,
                                   differentiable=differentiable,
                                   add_IdepVarComps=False,
                                   nSamples=nSamples),
                    promotes=([
                        'Ct_in', 'Cp_in', 'gen_params:*', 'floris_params:*',
                        'air_density', 'axialInduction', 'generatorEfficiency',
                        'turbineX', 'turbineY',
                        'yaw%i' % direction_id, 'rotorDiameter', 'hubHeight',
                        'wtVelocity%i' % direction_id,
                        'wtPower%i' % direction_id,
                        'dir_power%i' % direction_id
                    ] if (nSamples == 0) else [
                        'Ct_in', 'Cp_in', 'gen_params:*', 'floris_params:*',
                        'air_density', 'axialInduction', 'generatorEfficiency',
                        'turbineX', 'turbineY',
                        'yaw%i' % direction_id, 'rotorDiameter', 'hubHeight',
                        'wsPositionX', 'wsPositionY', 'wsPositionZ',
                        'wtVelocity%i' % direction_id,
                        'wtPower%i' % direction_id,
                        'dir_power%i' % direction_id,
                        'wsArray%i' % direction_id
                    ]))

        # Specify how the energy statistics are computed
        self.add('powerMUX', MUX(nDirections, units=power_units))
        method = method_dict['method']
        if method == 'dakota':
            self.add('AEPcomp',
                     DakotaStatistics(nDirections, method_dict),
                     promotes=['*'])
        elif method == 'chaospy':
            self.add('AEPcomp',
                     ChaospyStatistics(nDirections, method_dict),
                     promotes=['*'])
        elif method == 'rect':
            self.add('AEPcomp',
                     RectStatistics(nDirections, method_dict),
                     promotes=['*'])
        else:
            print "Specify one of these UQ methods = ['dakota', 'chaospy', 'rect']"
            sys.exit()

        # connect components
        self.connect('windDirections', 'windDirectionsDeMUX.Array')
        self.connect('windSpeeds', 'windSpeedsDeMUX.Array')
        for direction_id in range(0, nDirections):
            self.add('y%i' % direction_id,
                     IndepVarComp('yaw%i' % direction_id,
                                  np.zeros(nTurbines),
                                  units=direction_units),
                     promotes=['*'])
            self.connect('windDirectionsDeMUX.output%i' % direction_id,
                         'direction_group%i.wind_direction' % direction_id)
            self.connect('windSpeedsDeMUX.output%i' % direction_id,
                         'direction_group%i.wind_speed' % direction_id)
            self.connect('dir_power%i' % direction_id,
                         'powerMUX.input%i' % direction_id)
        self.connect('powerMUX.Array', 'power')