Exemple #1
0
    def compute(self, inputs, outputs):
        z = inputs["z"]
        windLoads = (DirectionVector(
            inputs["windLoads_Px"], inputs["windLoads_Py"],
            inputs["windLoads_Pz"]).inertialToWind(
                inputs["windLoads_beta"]).windToYaw(inputs["yaw"]))
        waveLoads = (DirectionVector(
            inputs["waveLoads_Px"], inputs["waveLoads_Py"],
            inputs["waveLoads_Pz"]).inertialToWind(
                inputs["waveLoads_beta"]).windToYaw(inputs["yaw"]))

        Px = np.interp(z, inputs["windLoads_z"], windLoads.x) + np.interp(
            z, inputs["waveLoads_z"], waveLoads.x)
        Py = np.interp(z, inputs["windLoads_z"], windLoads.y) + np.interp(
            z, inputs["waveLoads_z"], waveLoads.y)
        Pz = np.interp(z, inputs["windLoads_z"], windLoads.z) + np.interp(
            z, inputs["waveLoads_z"], waveLoads.z)
        qdyn = np.interp(
            z, inputs["windLoads_z"], inputs["windLoads_qdyn"]) + np.interp(
                z, inputs["waveLoads_z"], inputs["waveLoads_qdyn"])

        # The following are redundant, at one point we will consolidate them to something that works for both cylinder (not using vartrees) and jacket (still using vartrees)
        outputs["Px"] = Px
        outputs["Py"] = Py
        outputs["Pz"] = Pz
        outputs["qdyn"] = qdyn
Exemple #2
0
    def compute(self, inputs, outputs):
        z = inputs['z']
        hubHt = z[-1]  # top of cylinder
        windLoads = DirectionVector(
            inputs['windLoads_Px'], inputs['windLoads_Py'],
            inputs['windLoads_Pz']).inertialToWind(
                inputs['windLoads_beta']).windToYaw(inputs['yaw'])
        waveLoads = DirectionVector(
            inputs['waveLoads_Px'], inputs['waveLoads_Py'],
            inputs['waveLoads_Pz']).inertialToWind(
                inputs['waveLoads_beta']).windToYaw(inputs['yaw'])

        Px = np.interp(z, inputs['windLoads_z'], windLoads.x) + np.interp(
            z, inputs['waveLoads_z'], waveLoads.x)
        Py = np.interp(z, inputs['windLoads_z'], windLoads.y) + np.interp(
            z, inputs['waveLoads_z'], waveLoads.y)
        Pz = np.interp(z, inputs['windLoads_z'], windLoads.z) + np.interp(
            z, inputs['waveLoads_z'], waveLoads.z)
        qdyn = np.interp(
            z, inputs['windLoads_z'], inputs['windLoads_qdyn']) + np.interp(
                z, inputs['waveLoads_z'], inputs['waveLoads_qdyn'])

        #The following are redundant, at one point we will consolidate them to something that works for both cylinder (not using vartrees) and jacket (still using vartrees)
        outputs['Px'] = Px
        outputs['Py'] = Py
        outputs['Pz'] = Pz
        outputs['qdyn'] = qdyn
Exemple #3
0
    def compute_partials(self, inputs, J, discrete_inputs):

        dF = DirectionVector.fromArray(inputs['F']).hubToYaw(inputs['tilt'])
        dFx, dFy, dFz = dF.dx, dF.dy, dF.dz

        dtopF_dFx = np.array([dFx['dx'], dFy['dx'], dFz['dx']])
        dtopF_dFy = np.array([dFx['dy'], dFy['dy'], dFz['dy']])
        dtopF_dFz = np.array([dFx['dz'], dFy['dz'], dFz['dz']])
        dtopF_dF = hstack([dtopF_dFx, dtopF_dFy, dtopF_dFz])
        dtopF_w_dm = np.array([0.0, 0.0, -gravity])

        #dtopF = hstack([dtopF_dF, np.zeros((3, 6)), dtopF_w_dm, np.zeros((3, 3))])

        dM = DirectionVector.fromArray(inputs['M']).hubToYaw(inputs['tilt'])
        dMx, dMy, dMz = dM.dx, dM.dy, dM.dz
        dMxcross, dMycross, dMzcross = self.save_rhub.cross_deriv(
            self.saveF, 'dr', 'dF')

        dtopM_dMx = np.array([dMx['dx'], dMy['dx'], dMz['dx']])
        dtopM_dMy = np.array([dMx['dy'], dMy['dy'], dMz['dy']])
        dtopM_dMz = np.array([dMx['dz'], dMy['dz'], dMz['dz']])
        dtopM_dM = hstack([dtopM_dMx, dtopM_dMy, dtopM_dMz])
        dM_dF = np.array([dMxcross['dF'], dMycross['dF'], dMzcross['dF']])

        dtopM_dFx = np.dot(dM_dF, dtopF_dFx)
        dtopM_dFy = np.dot(dM_dF, dtopF_dFy)
        dtopM_dFz = np.dot(dM_dF, dtopF_dFz)
        dtopM_dF = hstack([dtopM_dFx, dtopM_dFy, dtopM_dFz])
        dtopM_dr = np.array([dMxcross['dr'], dMycross['dr'], dMzcross['dr']])

        #dMx_w_cross, dMy_w_cross, dMz_w_cross = self.save_rcm.cross_deriv(self.saveF_w, 'dr', 'dF')

        #if discrete_inputs['rna_weightM']:
        #    dtopM_drnacm = np.array([dMx_w_cross['dr'], dMy_w_cross['dr'], dMz_w_cross['dr']])
        #    dtopM_dF_w = np.array([dMx_w_cross['dF'], dMy_w_cross['dF'], dMz_w_cross['dF']])
        #else:
        #    dtopM_drnacm = np.zeros((3, 3))
        #    dtopM_dF_w = np.zeros((3, 3))
        dtopM_drnacm = np.zeros((3, 3))
        dtopM_dF_w = np.zeros((3, 3))
        dtopM_dm = np.dot(dtopM_dF_w, dtopF_w_dm)

        if discrete_inputs['downwind']:
            dtopM_dr[:, 0] *= -1
            dtopM_drnacm[:, 0] *= -1

        #dtopM = hstack([dtopM_dF, dtopM_dM, dtopM_dr, dtopM_dm, dtopM_drnacm])

        J['top_F', 'F'] = dtopF_dF
        J['top_F', 'M'] = np.zeros((3, 3))
        J['top_F', 'hub_cm'] = np.zeros((3, 3))
        J['top_F', 'rna_mass'] = dtopF_w_dm
        J['top_F', 'rna_cm'] = np.zeros((3, 3))

        J['top_M', 'F'] = dtopM_dF
        J['top_M', 'M'] = dtopM_dM
        J['top_M', 'hub_cm'] = dtopM_dr
        J['top_M', 'rna_mass'] = dtopM_dm
        J['top_M', 'rna_cm'] = dtopM_drnacm
Exemple #4
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        F = inputs['F']
        M = inputs['M']
        tilt = float(inputs['tilt'])

        F = DirectionVector.fromArray(F).hubToYaw(tilt)
        M = DirectionVector.fromArray(M).hubToYaw(tilt)

        # change x-direction if downwind
        hub_cm = np.copy(inputs['hub_cm'])
        rna_cm = np.copy(inputs['rna_cm'])
        if discrete_inputs['downwind']:
            hub_cm[0] *= -1
            rna_cm[0] *= -1
        hub_cm = DirectionVector.fromArray(hub_cm)
        rna_cm = DirectionVector.fromArray(rna_cm)
        self.save_rhub = hub_cm
        self.save_rcm = rna_cm

        # aerodynamic moments
        M = M + hub_cm.cross(F)
        self.saveF = F
        '''
        Removing this permanently gbarter 1/2020 because of too much confusion in TowerSE and Frame3DD
        From now on TowerSE will always add to loading of added mass items, including RNA
        
        # add weight loads
        F_w = DirectionVector(0.0, 0.0, -float(inputs['rna_mass'])*gravity)
        M_w = rna_cm.cross(F_w)
        self.saveF_w = F_w

        Fout = F + F_w

        if discrete_inputs['rna_weightM']:
            Mout = M + M_w
        else:
            Mout = M
            #REMOVE WEIGHT EFFECT TO ACCOUNT FOR P-Delta Effect
            print("!!!! No weight effect on rotor moments -TowerSE  !!!!")
        '''
        Fout = F
        Mout = M

        # put back in array
        outputs['top_F'] = np.array([Fout.x, Fout.y, Fout.z])
        outputs['top_M'] = np.array([Mout.x, Mout.y, Mout.z])
Exemple #5
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        F = inputs['F']
        M = inputs['M']
        tilt = float(inputs['tilt'])
        
        F = DirectionVector.fromArray(F).hubToYaw(tilt)
        M = DirectionVector.fromArray(M).hubToYaw(tilt)

        # change x-direction if downwind
        hub_cm = np.copy(inputs['hub_cm'])
        rna_cm = np.copy(inputs['rna_cm'])
        if discrete_inputs['downwind']:
            hub_cm[0] *= -1
            rna_cm[0] *= -1
        hub_cm = DirectionVector.fromArray(hub_cm)
        rna_cm = DirectionVector.fromArray(rna_cm)
        self.save_rhub = hub_cm
        self.save_rcm = rna_cm

        # aerodynamic moments
        M = M + hub_cm.cross(F)
        self.saveF = F


        # add weight loads
        F_w = DirectionVector(0.0, 0.0, -float(inputs['rna_mass'])*gravity)
        M_w = rna_cm.cross(F_w)
        self.saveF_w = F_w

        Fout = F + F_w

        if discrete_inputs['rna_weightM']:
            Mout = M + M_w
        else:
            Mout = M
            #REMOVE WEIGHT EFFECT TO ACCOUNT FOR P-Delta Effect
            print("!!!! No weight effect on rotor moments -TowerSE  !!!!")

        # put back in array
        outputs['top_F'] = np.array([Fout.x, Fout.y, Fout.z])
        outputs['top_M'] = np.array([Mout.x, Mout.y, Mout.z])
Exemple #6
0
    def test(self):

        x = np.array([1.0, 2.0])
        y = np.array([1.3, 4.3])
        z = np.array([2.3, 2.3])
        a = DirectionVector(x, y, z)

        x = np.array([3.2, 1.5])
        y = np.array([2.1, 3.2])
        z = np.array([5.6, 7.7])
        b = DirectionVector(x, y, z)

        c = a.cross(b)
        dx, dy, dz = a.cross_deriv(b)
        dx, dy, dz = a.cross_deriv_array(b)

        d = -a
        e = a + b
        f = a - b
        f += a
        f -= a
        k = a * b
        p = a / b
        p *= b
        p /= a

        e = a + 1.2
        f = a - 1.2
        f += 2.
        f -= 3.
        k = a * 4.
        p = a / 2.
        p *= 3.
        p /= 2.

        T1 = 5.0
        T2 = 4.0
        T3 = -3.0
        tilt = 20.0

        F = DirectionVector(T1, T2, T3).hubToYaw(tilt)

        Fp1 = DirectionVector(T1 + 1e-6, T2, T3).hubToYaw(tilt)
        Fp2 = DirectionVector(T1, T2 + 1e-6, T3).hubToYaw(tilt)
        Fp3 = DirectionVector(T1, T2, T3 + 1e-6).hubToYaw(tilt)
        Fp4 = DirectionVector(T1, T2, T3).hubToYaw(tilt + 1e-6)

        dFx = F.dx
        dFy = F.dy
        dFz = F.dz

        npt.assert_almost_equal(dFx['dx'], (Fp1.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dy'], (Fp2.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dz'], (Fp3.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dtilt'], (Fp4.x - F.x) / 1e-6)

        npt.assert_almost_equal(dFy['dx'], (Fp1.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dy'], (Fp2.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dz'], (Fp3.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dtilt'], (Fp4.y - F.y) / 1e-6)

        npt.assert_almost_equal(dFz['dx'], (Fp1.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dy'], (Fp2.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dz'], (Fp3.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dtilt'], (Fp4.z - F.z) / 1e-6)

        yaw = 3.0
        F = DirectionVector(T1, T2, T3).hubToYaw(tilt).yawToWind(yaw)

        Fp1 = DirectionVector(T1 + 1e-6, T2, T3).hubToYaw(tilt).yawToWind(yaw)
        Fp2 = DirectionVector(T1, T2 + 1e-6, T3).hubToYaw(tilt).yawToWind(yaw)
        Fp3 = DirectionVector(T1, T2, T3 + 1e-6).hubToYaw(tilt).yawToWind(yaw)
        Fp4 = DirectionVector(T1, T2, T3).hubToYaw(tilt + 1e-6).yawToWind(yaw)
        Fp5 = DirectionVector(T1, T2, T3).hubToYaw(tilt).yawToWind(yaw + 1e-6)

        dFx = F.dx
        dFy = F.dy
        dFz = F.dz

        npt.assert_almost_equal(dFx['dx'], (Fp1.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dy'], (Fp2.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dz'], (Fp3.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dtilt'], (Fp4.x - F.x) / 1e-6)
        npt.assert_almost_equal(dFx['dyaw'], (Fp5.x - F.x) / 1e-6)

        npt.assert_almost_equal(dFy['dx'], (Fp1.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dy'], (Fp2.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dz'], (Fp3.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dtilt'], (Fp4.y - F.y) / 1e-6)
        npt.assert_almost_equal(dFy['dyaw'], (Fp5.y - F.y) / 1e-6)

        npt.assert_almost_equal(dFz['dx'], (Fp1.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dy'], (Fp2.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dz'], (Fp3.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dtilt'], (Fp4.z - F.z) / 1e-6)
        npt.assert_almost_equal(dFz['dyaw'], (Fp5.z - F.z) / 1e-6)

        inertial_F = F.windToInertial(20.)
        new_F = inertial_F.inertialToWind(20.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        wind_F = F.yawToWind(15.)
        new_F = wind_F.windToYaw(15.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        yaw_F = F.hubToYaw(12.)
        new_F = yaw_F.yawToHub(12.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        az_F = F.hubToAzimuth(12.)
        new_F = az_F.azimuthToHub(12.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        blade_F = F.azimuthToBlade(12.)
        new_F = blade_F.bladeToAzimuth(12.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        blade_F = F.airfoilToBlade(12.)
        new_F = blade_F.bladeToAirfoil(12.)
        npt.assert_almost_equal(F.toArray(), new_F.toArray())

        profile_F = F.airfoilToProfile()
        new_F = profile_F.profileToAirfoil()
        npt.assert_almost_equal(F.toArray(), new_F.toArray())
Exemple #7
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
Exemple #8
0
get_cp_cm = CCBlade(r, chord, twist, af, hub_r, Rtip, B, rho, mu, cone, tilt,
                    0., shearExp, hub_height, nSector, presweep, precurve[-1],
                    presweep, presweep[-1], tiploss, hubloss, wakerotation,
                    usecd)
# get_cp_cm.induction        = True
Omega = Uhub * tsr / Rtip * 30.0 / np.pi  # Rotor speed
myout, derivs = get_cp_cm.evaluate([Uhub], [Omega], [pitch], coefficients=True)
P, T, Q, M, CP, CT, CQ, CM = [
    myout[key] for key in ['P', 'T', 'Q', 'M', 'CP', 'CT', 'CQ', 'CM']
]
get_cp_cm.induction_inflow = True
loads, deriv = get_cp_cm.distributedAeroLoads([Uhub], Omega, pitch, 0.)

########## Post Process Output ##########
# Compute forces in the airfoil coordinate system, pag 21 of https://www.nrel.gov/docs/fy13osti/58819.pdf
P_b = DirectionVector(loads['Np'], -loads['Tp'], 0)
P_af = P_b.bladeToAirfoil(twist)
# Compute lift and drag forces
F = P_b.bladeToAirfoil(twist + loads['alpha'] + pitch)
# Print output .dat file with the quantities distributed along span
np.savetxt(
    os.path.join(output_folder, 'distributed_quantities.dat'),
    np.array([
        s, r, loads['alpha'], loads['a'], loads['ap'], loads['Cl'],
        loads['Cd'], F.x, F.y, loads['Np'], -loads['Tp'], P_af.x, P_af.y
    ]).T,
    header=
    'Blade nondimensional span position (-) \t Rotor position (m) \t Angle of attack (deg) \t Axial induction (-) \t Tangential induction (-) \t Lift coefficient (-) \t Drag coefficient (-) \t Lift force (N) \t Drag force (N) \t Force along x BCS - N (N) \t Force along y BCS - T (N) \t Force along x ACS (N) \t Force along y ACS (N)',
    delimiter='\t')
# Print output .dat file with the rotor equivalent quantities
np.savetxt(