コード例 #1
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        # initialization point
        # if discrete_inputs['blade_in_overwrite'] != {}:
        #     blade = copy.deepcopy(discrete_inputs['blade_in_overwrite'])
        # else:
        blade = copy.deepcopy(self.refBlade)
        NINPUT = len(blade['ctrl_pts']['r_in'])

        # Set inputs to update blade geometry
        Rhub = inputs['hubFraction'] * inputs['bladeLength']
        Rtip = Rhub + inputs['bladeLength']

        outputs['Rhub'] = Rhub
        outputs['Rtip'] = Rtip

        r_in = blade['ctrl_pts']['r_in']

        outputs['r_in'] = Rhub + (Rtip - Rhub) * np.array(r_in)

        blade['ctrl_pts']['bladeLength'] = inputs['bladeLength']
        blade['ctrl_pts']['r_in'] = r_in
        blade['ctrl_pts']['chord_in'] = inputs['chord_in']
        blade['ctrl_pts']['theta_in'] = inputs['theta_in']
        blade['ctrl_pts']['precurve_in'] = inputs['precurve_in']
        blade['ctrl_pts']['presweep_in'] = inputs['presweep_in']
        blade['ctrl_pts']['sparT_in'] = inputs['sparT_in']
        blade['ctrl_pts']['teT_in'] = inputs['teT_in']
        blade['ctrl_pts']['r_max_chord'] = inputs['r_max_chord']

        #check that airfoil positions are increasing
        correct_af_position = False
        airfoil_position = copy.deepcopy(inputs['airfoil_position']).tolist()
        for i in reversed(range(1, len(airfoil_position))):
            if airfoil_position[i] <= airfoil_position[i - 1]:
                airfoil_position[i - 1] = airfoil_position[i] - 0.001
                correct_af_position = True
        if correct_af_position:
            blade['outer_shape_bem']['airfoil_position'][
                'grid'] = airfoil_position
            warning_corrected_airfoil_position = "Airfoil spanwise positions must be increasing.  Changed from: %s to: %s" % (
                inputs['airfoil_position'].tolist(), airfoil_position)
            warnings.warn(warning_corrected_airfoil_position)
        else:
            blade['outer_shape_bem']['airfoil_position']['grid'] = inputs[
                'airfoil_position'].tolist()

        # Update
        refBlade = ReferenceBlade()
        refBlade.verbose = False
        refBlade.NINPUT = len(outputs['r_in'])
        refBlade.NPTS = len(blade['pf']['s'])
        refBlade.analysis_level = blade['analysis_level']
        if blade['analysis_level'] < 3:
            refBlade.spar_var = blade['precomp']['spar_var']
            refBlade.te_var = blade['precomp']['te_var']

        blade_out = refBlade.update(blade)

        # Get geometric outputs
        outputs['hub_diameter'] = 2.0 * Rhub
        outputs['r'] = Rhub + (Rtip - Rhub) * np.array(blade_out['pf']['s'])
        outputs['diameter'] = 2.0 * outputs['r'][-1]

        outputs['chord'] = blade_out['pf']['chord']
        outputs['max_chord'] = max(blade_out['pf']['chord'])
        outputs['theta'] = blade_out['pf']['theta']
        outputs['precurve'] = blade_out['pf']['precurve']
        outputs['presweep'] = blade_out['pf']['presweep']
        outputs['rthick'] = blade_out['pf']['rthick']
        outputs['le_location'] = blade_out['pf']['p_le']

        # airfoils  = blade_out['airfoils']
        outputs['airfoils_cl'] = blade_out['airfoils_cl']
        outputs['airfoils_cd'] = blade_out['airfoils_cd']
        outputs['airfoils_cm'] = blade_out['airfoils_cm']
        outputs['airfoils_aoa'] = blade_out['airfoils_aoa']
        outputs['airfoils_Re'] = blade_out['airfoils_Re']

        upperCS = blade_out['precomp']['upperCS']
        lowerCS = blade_out['precomp']['lowerCS']
        websCS = blade_out['precomp']['websCS']
        profile = blade_out['precomp']['profile']
        materials = blade_out['precomp']['materials']

        for i in range(len(profile)):
            outputs['airfoils_coord_x'][:, i] = blade_out['profile'][:, 0, i]
            outputs['airfoils_coord_y'][:, i] = blade_out['profile'][:, 1, i]

        # Assumptions:
        # - if the composite layer is divided into multiple regions (i.e. if the spar cap is split into 3 regions due to the web locations),
        #   the middle region is selected with int(n_reg/2), note for an even number of regions, this rounds up
        sector_idx_strain_spar_ss = blade_out['precomp'][
            'sector_idx_strain_spar_ss']
        sector_idx_strain_spar_ps = blade_out['precomp'][
            'sector_idx_strain_spar_ps']
        sector_idx_strain_te_ss = blade_out['precomp'][
            'sector_idx_strain_te_ss']
        sector_idx_strain_te_ps = blade_out['precomp'][
            'sector_idx_strain_te_ps']

        # Get Beam Properties
        beam = PreComp(outputs['r'], outputs['chord'], outputs['theta'],
                       outputs['le_location'], outputs['precurve'],
                       outputs['presweep'], profile, materials, upperCS,
                       lowerCS, websCS, sector_idx_strain_spar_ps,
                       sector_idx_strain_spar_ss, sector_idx_strain_te_ps,
                       sector_idx_strain_te_ss)
        EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, rhoJ, Tw_iner, flap_iner, edge_iner = beam.sectionProperties(
        )

        outputs['eps_crit_spar'] = beam.panelBucklingStrain(
            sector_idx_strain_spar_ss)
        outputs['eps_crit_te'] = beam.panelBucklingStrain(
            sector_idx_strain_te_ss)

        xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations(
            sector_idx_strain_spar_ss, sector_idx_strain_spar_ps)
        xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations(
            sector_idx_strain_te_ss, sector_idx_strain_te_ps)

        outputs['z'] = outputs['r']
        outputs['EIxx'] = EIxx
        outputs['EIyy'] = EIyy
        outputs['GJ'] = GJ
        outputs['EA'] = EA
        outputs['EIxy'] = EIxy
        outputs['x_ec'] = x_ec
        outputs['y_ec'] = y_ec
        outputs['rhoA'] = rhoA
        outputs['rhoJ'] = rhoJ
        outputs['Tw_iner'] = Tw_iner
        outputs['flap_iner'] = flap_iner
        outputs['edge_iner'] = edge_iner

        outputs['xu_strain_spar'] = xu_strain_spar
        outputs['xl_strain_spar'] = xl_strain_spar
        outputs['yu_strain_spar'] = yu_strain_spar
        outputs['yl_strain_spar'] = yl_strain_spar
        outputs['xu_strain_te'] = xu_strain_te
        outputs['xl_strain_te'] = xl_strain_te
        outputs['yu_strain_te'] = yu_strain_te
        outputs['yl_strain_te'] = yl_strain_te

        # Blade cost model
        bcm = blade_cost_model(
            options=self.options
        )  # <------------- options, import blade cost model
        bcm.name = blade_out['config']['name']
        bcm.materials = materials
        bcm.upperCS = upperCS
        bcm.lowerCS = lowerCS
        bcm.websCS = websCS
        bcm.profile = profile
        bcm.chord = outputs['chord']
        bcm.r = (outputs['r'] - outputs['Rhub']) / (
            outputs['Rtip'] - outputs['Rhub']) * float(inputs['bladeLength'])
        bcm.bladeLength = float(inputs['bladeLength'])
        bcm.le_location = outputs['le_location']
        blade_cost, blade_mass = bcm.execute_blade_cost_model()

        outputs['total_blade_cost'] = blade_cost
        outputs['total_blade_mass'] = blade_mass

        #
        discrete_outputs['blade_out'] = blade_out
        outputs['sparT_in_out'] = inputs['sparT_in']
コード例 #2
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        ##############################
        def region_stacking(i, idx, start_nd_arc, end_nd_arc, layer_name,
                            layer_thickness, fiber_orientation, layer_mat,
                            material_dict, materials, region_loc):
            # Recieve start and end of composite sections chordwise, find which composites layers are in each
            # chordwise regions, generate the precomp composite class instance

            # error handling to makes sure there were no numeric errors causing values very close too, but not exactly, 0 or 1
            start_nd_arc = [
                0. if start_nd_arci != 0. and np.isclose(start_nd_arci, 0.)
                else start_nd_arci for start_nd_arci in start_nd_arc
            ]
            end_nd_arc = [
                0. if end_nd_arci != 0. and np.isclose(end_nd_arci, 0.) else
                end_nd_arci for end_nd_arci in end_nd_arc
            ]
            start_nd_arc = [
                1. if start_nd_arci != 1. and np.isclose(start_nd_arci, 1.)
                else start_nd_arci for start_nd_arci in start_nd_arc
            ]
            end_nd_arc = [
                1. if end_nd_arci != 1. and np.isclose(end_nd_arci, 1.) else
                end_nd_arci for end_nd_arci in end_nd_arc
            ]

            # region end points
            dp = sorted(list(set(start_nd_arc + end_nd_arc)))

            #initialize
            n_plies = []
            thk = []
            theta = []
            mat_idx = []

            # loop through division points, find what layers make up the stack between those bounds
            for i_reg, (dp0, dp1) in enumerate(zip(dp[0:-1], dp[1:])):
                n_pliesi = []
                thki = []
                thetai = []
                mati = []
                for i_sec, start_nd_arci, end_nd_arci in zip(
                        idx, start_nd_arc, end_nd_arc):
                    name = layer_name[i_sec]
                    if start_nd_arci <= dp0 and end_nd_arci >= dp1:

                        if name in region_loc.keys():
                            if region_loc[name][i] == None:
                                region_loc[name][i] = [i_reg]
                            else:
                                region_loc[name][i].append(i_reg)

                        n_pliesi.append(1.)
                        thki.append(layer_thickness[i_sec])
                        if fiber_orientation[i_sec] == None:
                            thetai.append(0.)
                        else:
                            thetai.append(fiber_orientation[i_sec])
                        mati.append(material_dict[layer_mat[i_sec]])

                n_plies.append(np.array(n_pliesi))
                thk.append(np.array(thki))
                theta.append(np.array(thetai))
                mat_idx.append(np.array(mati))

            # print('----------------------')
            # print('dp', dp)
            # print('n_plies', n_plies)
            # print('thk', thk)
            # print('theta', theta)
            # print('mat_idx', mat_idx)
            # print('materials', materials)

            sec = CompositeSection(dp, n_plies, thk, theta, mat_idx, materials)
            return sec, region_loc
            ##############################

        def web_stacking(i, web_idx, web_start_nd_arc, web_end_nd_arc,
                         layer_thickness, fiber_orientation, layer_mat,
                         material_dict, materials, flatback, upperCSi):
            dp = []
            n_plies = []
            thk = []
            theta = []
            mat_idx = []

            if len(web_idx) > 0:
                dp = np.mean(
                    (np.abs(web_start_nd_arc), np.abs(web_start_nd_arc)),
                    axis=0).tolist()

                dp_all = [[-1. * start_nd_arci, -1. * end_nd_arci]
                          for start_nd_arci, end_nd_arci in zip(
                              web_start_nd_arc, web_end_nd_arc)]
                web_dp, web_ids = np.unique(dp_all,
                                            axis=0,
                                            return_inverse=True)
                for webi in np.unique(web_ids):
                    # store variable values (thickness, orientation, material) for layers that make up each web, based on the mapping array web_ids
                    n_pliesi = [
                        1. for i_reg, web_idi in zip(web_idx, web_ids)
                        if web_idi == webi
                    ]
                    thki = [
                        layer_thickness[i_reg]
                        for i_reg, web_idi in zip(web_idx, web_ids)
                        if web_idi == webi
                    ]
                    thetai = [
                        fiber_orientation[i_reg]
                        for i_reg, web_idi in zip(web_idx, web_ids)
                        if web_idi == webi
                    ]
                    thetai = [
                        0. if theta_ij == None else theta_ij
                        for theta_ij in thetai
                    ]
                    mati = [
                        material_dict[layer_mat[i_reg]]
                        for i_reg, web_idi in zip(web_idx, web_ids)
                        if web_idi == webi
                    ]

                    n_plies.append(np.array(n_pliesi))
                    thk.append(np.array(thki))
                    theta.append(np.array(thetai))
                    mat_idx.append(np.array(mati))

            if flatback:
                dp.append(1.)
                n_plies.append(upperCSi.n_plies[-1])
                thk.append(upperCSi.t[-1])
                theta.append(upperCSi.theta[-1])
                mat_idx.append(upperCSi.mat_idx[-1])

            dp_out = sorted(list(set(dp)))

            sec = CompositeSection(dp_out, n_plies, thk, theta, mat_idx,
                                   materials)
            return sec
            ##############################

        layer_name = self.options['modeling_options']['blade']['layer_name']
        layer_mat = self.options['modeling_options']['blade']['layer_mat']

        upperCS = [None] * self.n_span
        lowerCS = [None] * self.n_span
        websCS = [None] * self.n_span
        profile = [None] * self.n_span

        # Check that the layer to be optimized actually exist
        te_ss_var_ok = False
        te_ps_var_ok = False
        spar_cap_ss_var_ok = False
        spar_cap_ps_var_ok = False
        for i_layer in range(self.n_layers):
            if layer_name[i_layer] == self.te_ss_var:
                te_ss_var_ok = True
            if layer_name[i_layer] == self.te_ps_var:
                te_ps_var_ok = True
            if layer_name[i_layer] == self.spar_cap_ss_var:
                spar_cap_ss_var_ok = True
            if layer_name[i_layer] == self.spar_cap_ps_var:
                spar_cap_ps_var_ok = True

        if te_ss_var_ok == False:
            print(
                'The layer at the trailing edge suction side is set to be optimized, but does not exist in the input yaml. Please check.'
            )
        if te_ps_var_ok == False:
            print(
                'The layer at the trailing edge pressure side is set to be optimized, but does not exist in the input yaml. Please check.'
            )
        if spar_cap_ss_var_ok == False:
            print(
                'The layer at the spar cap suction side is set to be optimized, but does not exist in the input yaml. Please check.'
            )
        if spar_cap_ps_var_ok == False:
            print(
                'The layer at the spar cap pressure side is set to be optimized, but does not exist in the input yaml. Please check.'
            )
        region_loc_vars = [
            self.te_ss_var, self.te_ps_var, self.spar_cap_ss_var,
            self.spar_cap_ps_var
        ]

        region_loc_ss = {
        }  # track precomp regions for user selected composite layers
        region_loc_ps = {}
        for var in region_loc_vars:
            region_loc_ss[var] = [None] * self.n_span
            region_loc_ps[var] = [None] * self.n_span

        ## Materials
        material_dict = {}
        materials = []
        for i_mat in range(self.n_mat):
            materials.append(
                Orthotropic2DMaterial(inputs['E'][i_mat, 0], inputs['E'][i_mat,
                                                                         1],
                                      inputs['G'][i_mat,
                                                  0], inputs['nu'][i_mat, 0],
                                      inputs['rho'][i_mat],
                                      discrete_inputs['mat_name'][i_mat]))
            material_dict[discrete_inputs['mat_name'][i_mat]] = i_mat

        ## Spanwise
        for i in range(self.n_span):
            # time0 = time.time()

            ## Profiles
            # rotate
            profile_i = inputs['coord_xy_interp'][i, :, :]
            profile_i_rot = np.column_stack(
                rotate(inputs['pitch_axis'][i], 0., profile_i[:, 0],
                       profile_i[:, 1], np.radians(inputs['theta'][i])))

            # import matplotlib.pyplot as plt
            # plt.plot(profile_i[:,0], profile_i[:,1])
            # plt.plot(profile_i_rot[:,0], profile_i_rot[:,1])
            # plt.axis('equal')
            # plt.title(i)
            # plt.show()

            # normalize
            profile_i_rot[:, 0] -= min(profile_i_rot[:, 0])
            profile_i_rot = profile_i_rot / max(profile_i_rot[:, 0])

            profile_i_rot_precomp = copy.copy(profile_i_rot)
            idx_s = 0
            idx_le_precomp = np.argmax(profile_i_rot_precomp[:, 0])
            if idx_le_precomp != 0:

                if profile_i_rot_precomp[0, 0] == profile_i_rot_precomp[-1, 0]:
                    idx_s = 1
                profile_i_rot_precomp = np.row_stack(
                    (profile_i_rot_precomp[idx_le_precomp:],
                     profile_i_rot_precomp[idx_s:idx_le_precomp, :]))
            profile_i_rot_precomp[:, 1] -= profile_i_rot_precomp[
                np.argmin(profile_i_rot_precomp[:, 0]), 1]

            # # renormalize
            profile_i_rot_precomp[:, 0] -= min(profile_i_rot_precomp[:, 0])
            profile_i_rot_precomp = profile_i_rot_precomp / max(
                profile_i_rot_precomp[:, 0])

            if profile_i_rot_precomp[-1, 0] != 1.:
                profile_i_rot_precomp = np.row_stack(
                    (profile_i_rot_precomp, profile_i_rot_precomp[0, :]))

            # 'web' at trailing edge needed for flatback airfoils
            if profile_i_rot_precomp[0, 1] != profile_i_rot_precomp[
                    -1, 1] and profile_i_rot_precomp[
                        0, 0] == profile_i_rot_precomp[-1, 0]:
                flatback = True
            else:
                flatback = False

            profile[i] = Profile.initWithTEtoTEdata(
                profile_i_rot_precomp[:, 0], profile_i_rot_precomp[:, 1])

            # import matplotlib.pyplot as plt
            # plt.plot(profile_i_rot_precomp[:,0], profile_i_rot_precomp[:,1])
            # plt.axis('equal')
            # plt.title(i)
            # plt.show()

            idx_le = np.argmin(profile_i_rot[:, 0])

            profile_i_arc = arc_length(profile_i_rot)
            arc_L = profile_i_arc[-1]
            profile_i_arc /= arc_L

            loc_LE = profile_i_arc[idx_le]
            len_PS = 1. - loc_LE

            ## Composites
            ss_idx = []
            ss_start_nd_arc = []
            ss_end_nd_arc = []
            ps_idx = []
            ps_start_nd_arc = []
            ps_end_nd_arc = []
            web_start_nd_arc = []
            web_end_nd_arc = []
            web_idx = []

            # Determine spanwise composite layer elements that are non-zero at this spanwise location,
            # determine their chord-wise start and end location on the pressure and suctions side

            spline_arc2xnd = PchipInterpolator(profile_i_arc, profile_i_rot[:,
                                                                            0])

            # time1 = time.time()
            for idx_sec in range(self.n_layers):
                if discrete_inputs['definition_layer'][idx_sec] != 10:
                    if inputs['layer_thickness'][idx_sec, i] != 0.:
                        if inputs['layer_start_nd'][
                                idx_sec, i] < loc_LE or inputs['layer_end_nd'][
                                    idx_sec, i] < loc_LE:
                            ss_idx.append(idx_sec)
                            if inputs['layer_start_nd'][idx_sec, i] < loc_LE:
                                # ss_start_nd_arc.append(sec['start_nd_arc']['values'][i])
                                ss_end_nd_arc_temp = float(
                                    spline_arc2xnd(
                                        inputs['layer_start_nd'][idx_sec, i]))
                                if ss_end_nd_arc_temp > 1 or ss_end_nd_arc_temp < 0:
                                    exit(
                                        'Error in the definition of material '
                                        + layer_name[idx_sec] +
                                        '. It cannot fit in the section number '
                                        + str(i) + ' at span location ' +
                                        str(inputs['r'][i] / inputs['r'][-1] *
                                            100.) + ' %.')
                                if ss_end_nd_arc_temp == profile_i_rot[
                                        0, 0] and profile_i_rot[0, 0] != 1.:
                                    ss_end_nd_arc_temp = 1.
                                ss_end_nd_arc.append(ss_end_nd_arc_temp)
                            else:
                                ss_end_nd_arc.append(1.)
                            # ss_end_nd_arc.append(min(sec['end_nd_arc']['values'][i], loc_LE)/loc_LE)
                            if inputs['layer_end_nd'][idx_sec, i] < loc_LE:
                                ss_start_nd_arc.append(
                                    float(
                                        spline_arc2xnd(
                                            inputs['layer_end_nd'][idx_sec,
                                                                   i])))
                            else:
                                ss_start_nd_arc.append(0.)

                        if inputs['layer_start_nd'][
                                idx_sec, i] > loc_LE or inputs['layer_end_nd'][
                                    idx_sec, i] > loc_LE:
                            ps_idx.append(idx_sec)
                            # ps_start_nd_arc.append((max(sec['start_nd_arc']['values'][i], loc_LE)-loc_LE)/len_PS)
                            # ps_end_nd_arc.append((min(sec['end_nd_arc']['values'][i], 1.)-loc_LE)/len_PS)

                            if inputs['layer_start_nd'][
                                    idx_sec,
                                    i] > loc_LE and inputs['layer_end_nd'][
                                        idx_sec, i] < loc_LE:
                                # ps_start_nd_arc.append(float(remap2grid(profile_i_arc, profile_i_rot[:,0], sec['start_nd_arc']['values'][i])))
                                ps_end_nd_arc.append(1.)
                            else:
                                ps_end_nd_arc_temp = float(
                                    spline_arc2xnd(
                                        inputs['layer_end_nd'][idx_sec, i]))
                                if np.isclose(ps_end_nd_arc_temp,
                                              profile_i_rot[-1, 0]
                                              ) and profile_i_rot[-1, 0] != 1.:
                                    ps_end_nd_arc_temp = 1.
                                ps_end_nd_arc.append(ps_end_nd_arc_temp)
                            if inputs['layer_start_nd'][idx_sec, i] < loc_LE:
                                ps_start_nd_arc.append(0.)
                            else:
                                ps_start_nd_arc.append(
                                    float(
                                        spline_arc2xnd(
                                            inputs['layer_start_nd'][idx_sec,
                                                                     i])))
                else:
                    target_idx = inputs['layer_web'][idx_sec] - 1

                    if inputs['layer_thickness'][idx_sec, i] != 0.:
                        web_idx.append(idx_sec)

                        start_nd_arc = float(
                            spline_arc2xnd(
                                inputs['web_start_nd'][int(target_idx), i]))
                        end_nd_arc = float(
                            spline_arc2xnd(
                                inputs['web_end_nd'][int(target_idx), i]))

                        web_start_nd_arc.append(start_nd_arc)
                        web_end_nd_arc.append(end_nd_arc)

            # time1 = time.time() - time1
            # print(time1)

            # generate the Precomp composite stacks for chordwise regions
            if np.min([ss_start_nd_arc, ss_end_nd_arc]) < 0 or np.max(
                [ss_start_nd_arc, ss_end_nd_arc]) > 1:
                print('Error in the layer definition at station number ' +
                      str(i))
                exit()
            upperCS[i], region_loc_ss = region_stacking(
                i, ss_idx, ss_start_nd_arc, ss_end_nd_arc, layer_name,
                inputs['layer_thickness'][:,
                                          i], inputs['fiber_orientation'][:,
                                                                          i],
                layer_mat, material_dict, materials, region_loc_ss)
            lowerCS[i], region_loc_ps = region_stacking(
                i, ps_idx, ps_start_nd_arc, ps_end_nd_arc, layer_name,
                inputs['layer_thickness'][:,
                                          i], inputs['fiber_orientation'][:,
                                                                          i],
                layer_mat, material_dict, materials, region_loc_ps)
            if len(web_idx) > 0 or flatback:
                websCS[i] = web_stacking(i, web_idx, web_start_nd_arc,
                                         web_end_nd_arc,
                                         inputs['layer_thickness'][:, i],
                                         inputs['fiber_orientation'][:, i],
                                         layer_mat, material_dict, materials,
                                         flatback, upperCS[i])
            else:
                websCS[i] = CompositeSection([], [], [], [], [], [])

        sector_idx_strain_spar_cap_ss = [
            None if regs == None else regs[int(len(regs) / 2)]
            for regs in region_loc_ss[self.spar_cap_ss_var]
        ]
        sector_idx_strain_spar_cap_ps = [
            None if regs == None else regs[int(len(regs) / 2)]
            for regs in region_loc_ps[self.spar_cap_ps_var]
        ]
        sector_idx_strain_te_ss = [
            None if regs == None else regs[int(len(regs) / 2)]
            for regs in region_loc_ss[self.te_ss_var]
        ]
        sector_idx_strain_te_ps = [
            None if regs == None else regs[int(len(regs) / 2)]
            for regs in region_loc_ps[self.te_ps_var]
        ]

        # Get Beam Properties
        beam = PreComp(inputs['r'], inputs['chord'], np.zeros_like(
            inputs['r']), inputs['pitch_axis'], inputs['precurve'],
                       inputs['presweep'], profile, materials, upperCS,
                       lowerCS, websCS, sector_idx_strain_spar_cap_ps,
                       sector_idx_strain_spar_cap_ss, sector_idx_strain_te_ps,
                       sector_idx_strain_te_ss)
        EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, area, rhoJ, Tw_iner, flap_iner, edge_iner, x_tc, y_tc, x_sc, y_sc, x_cg, y_cg = beam.sectionProperties(
        )

        # outputs['eps_crit_spar'] = beam.panelBucklingStrain(sector_idx_strain_spar_cap_ss)
        # outputs['eps_crit_te'] = beam.panelBucklingStrain(sector_idx_strain_te_ss)

        xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations(
            sector_idx_strain_spar_cap_ss, sector_idx_strain_spar_cap_ps)
        xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations(
            sector_idx_strain_te_ss, sector_idx_strain_te_ps)

        # Store what materials make up the composites for SC/TE
        for i in range(self.n_span):
            for j in range(self.n_mat):
                if sector_idx_strain_spar_cap_ss[i]:
                    if j in upperCS[i].mat_idx[
                            sector_idx_strain_spar_cap_ss[i]]:
                        outputs['sc_ss_mats'][i, j] = 1.
                if sector_idx_strain_spar_cap_ps[i]:
                    if j in lowerCS[i].mat_idx[
                            sector_idx_strain_spar_cap_ps[i]]:
                        outputs['sc_ps_mats'][i, j] = 1.
                if sector_idx_strain_te_ss[i]:
                    if j in upperCS[i].mat_idx[sector_idx_strain_te_ss[i]]:
                        outputs['te_ss_mats'][i, j] = 1.
                if sector_idx_strain_te_ps[i]:
                    if j in lowerCS[i].mat_idx[sector_idx_strain_te_ps[i]]:
                        outputs['te_ps_mats'][i, j] = 1.

        outputs['z'] = inputs['r']
        outputs['EIxx'] = EIxx
        outputs['EIyy'] = EIyy
        outputs['GJ'] = GJ
        outputs['EA'] = EA
        outputs['EIxy'] = EIxy
        outputs['x_ec'] = x_ec
        outputs['y_ec'] = y_ec
        outputs['rhoA'] = rhoA
        outputs['A'] = area
        outputs['rhoJ'] = rhoJ
        outputs['Tw_iner'] = Tw_iner
        outputs['flap_iner'] = flap_iner
        outputs['edge_iner'] = edge_iner

        outputs["x_tc"] = x_tc
        outputs["y_tc"] = y_tc
        outputs["x_sc"] = x_sc
        outputs["y_sc"] = y_sc
        outputs["x_cg"] = x_cg
        outputs["y_cg"] = y_cg

        outputs['xu_strain_spar'] = xu_strain_spar
        outputs['xl_strain_spar'] = xl_strain_spar
        outputs['yu_strain_spar'] = yu_strain_spar
        outputs['yl_strain_spar'] = yl_strain_spar
        outputs['xu_strain_te'] = xu_strain_te
        outputs['xl_strain_te'] = xl_strain_te
        outputs['yu_strain_te'] = yu_strain_te
        outputs['yl_strain_te'] = yl_strain_te

        # Compute mass and inertia of blade and rotor
        blade_mass = np.trapz(rhoA, inputs['r'])
        blade_moment_of_inertia = np.trapz(rhoA * inputs['r']**2., inputs['r'])
        tilt = inputs['uptilt']
        n_blades = discrete_inputs['n_blades']
        mass_all_blades = n_blades * blade_mass
        Ibeam = n_blades * blade_moment_of_inertia
        Ixx = Ibeam
        Iyy = Ibeam / 2.0  # azimuthal average for 2 blades, exact for 3+
        Izz = Ibeam / 2.0
        Ixy = 0.0
        Ixz = 0.0
        Iyz = 0.0  # azimuthal average for 2 blades, exact for 3+
        # rotate to yaw c.s.
        I = DirectionVector(Ixx, Iyy, Izz).hubToYaw(
            tilt)  # because off-diagonal components are all zero
        I_all_blades = np.r_[I.x, I.y, I.z, Ixy, Ixz, Iyz]

        outputs['blade_mass'] = blade_mass
        outputs['blade_moment_of_inertia'] = blade_moment_of_inertia
        outputs['mass_all_blades'] = mass_all_blades
        outputs['I_all_blades'] = I_all_blades

        # Placeholder - rotor cost
        bcm = blade_cost_model(verbosity=self.verbosity)
        bcm.name = ''
        bcm.materials = {}
        bcm.mat_options = {}

        bcm.mat_options['core_mat_id'] = np.zeros(self.n_mat)
        bcm.mat_options['coating_mat_id'] = -1
        bcm.mat_options['le_reinf_mat_id'] = -1
        bcm.mat_options['te_reinf_mat_id'] = -1

        for i_mat in range(self.n_mat):
            name = discrete_inputs['mat_name'][i_mat]
            # if name != 'resin':
            bcm.materials[name] = {}
            bcm.materials[name]['id'] = i_mat + 1
            bcm.materials[name]['name'] = discrete_inputs['mat_name'][i_mat]
            bcm.materials[name]['density'] = inputs['rho'][i_mat]
            bcm.materials[name]['unit_cost'] = inputs['unit_cost'][i_mat]
            bcm.materials[name]['waste'] = inputs['waste'][i_mat] * 100.
            if discrete_inputs['component_id'][i_mat] > 1:  # It's a composite
                bcm.materials[name]['fiber_density'] = inputs['rho_fiber'][
                    i_mat]
                bcm.materials[name]['area_density_dry'] = inputs[
                    'rho_area_dry'][i_mat]
                bcm.materials[name]['fvf'] = inputs['fvf'][i_mat] * 100.
                bcm.materials[name]['fwf'] = inputs['fwf'][i_mat] * 100.
                bcm.materials[name]['ply_t'] = inputs['ply_t'][i_mat]
                if discrete_inputs['component_id'][
                        i_mat] > 3:  # The material does not need to be cut@station
                    bcm.materials[name]['cut@station'] = 'N'
                else:
                    bcm.materials[name]['cut@station'] = 'Y'
                    bcm.materials[name]['roll_mass'] = inputs['roll_mass'][
                        i_mat]
            else:
                bcm.materials[name]['fvf'] = 100.
                bcm.materials[name]['fwf'] = 100.
                bcm.materials[name]['cut@station'] = 'N'
                if discrete_inputs['component_id'][i_mat] <= 0:
                    bcm.materials[name]['ply_t'] = inputs['ply_t'][i_mat]

            if discrete_inputs['component_id'][i_mat] == 0:
                bcm.mat_options['coating_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the coating
            elif discrete_inputs['component_id'][i_mat] == 1:
                bcm.mat_options['core_mat_id'][
                    bcm.materials[name]['id'] -
                    1] = 1  # Assigning the material to the core
            elif discrete_inputs['component_id'][i_mat] == 2:
                bcm.mat_options['skin_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the shell skin
            elif discrete_inputs['component_id'][i_mat] == 3:
                bcm.mat_options['skinwebs_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the webs skin
            elif discrete_inputs['component_id'][i_mat] == 4:
                bcm.mat_options['sc_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the spar caps
            elif discrete_inputs['component_id'][i_mat] == 5:
                bcm.mat_options['le_reinf_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the le reinf
                bcm.mat_options['te_reinf_mat_id'] = bcm.materials[name][
                    'id']  # Assigning the material to the te reinf

        bcm.upperCS = upperCS
        bcm.lowerCS = lowerCS
        bcm.websCS = websCS
        bcm.profile = profile
        bcm.chord = inputs['chord']
        bcm.r = inputs['r'] - inputs['r'][0]
        bcm.bladeLength = inputs['r'][-1] - inputs['r'][0]
        bcm.le_location = inputs['pitch_axis']
        blade_cost, blade_mass = bcm.execute_blade_cost_model()

        outputs['total_blade_cost'] = blade_cost
        outputs['total_blade_mass'] = blade_mass