Esempio n. 1
0
    def load_blade_info(self):
        '''
        Loads wind turbine blade data from an OpenFAST model. 
        Should be used if blade information is needed (i.e.) for flap controller tuning, but a rotor performance file is defined and and cc-blade is not run already. 
        
        Parameters:
        -----------
            self - note: needs to contain fast input file info provided by load_from_fast.
        '''
        from wisdem.aeroelasticse.FAST_reader import InputReader_OpenFAST

        # Load Fast input deck
        # self.TurbineName = FAST_InputFile.strip('.fst')
        # fast = InputReader_OpenFAST(FAST_ver=FAST_ver,dev_branch=dev_branch)
        # self.fast.FAST_InputFile = FAST_InputFile
        # self.fast.FAST_directory = FAST_directory
        # self.fast.execute()

        # Make sure cc_rotor exists for DAC analysis
        try:
            if self.cc_rotor:
                self.af_data = self.fast.fst_vt['AeroDyn15']['af_data']
                self.bld_flapwise_damp = self.fast.fst_vt['ElastoDynBlade']['BldFlDmp1']/100 * 0.7
        except AttributeError:
            # Create CC-Blade Rotor
            r0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlSpn']) 
            chord0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlChord'])
            theta0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlTwist'])
            # -- Adjust for Aerodyn15
            r = r0 + self.Rhub
            chord_intfun = interpolate.interp1d(r0,chord0, bounds_error=None, fill_value='extrapolate', kind='zero')
            chord = chord_intfun(r)
            theta_intfun = interpolate.interp1d(r0,theta0, bounds_error=None, fill_value='extrapolate', kind='zero')
            theta = theta_intfun(r)
            af_idx = np.array(self.fast.fst_vt['AeroDynBlade']['BlAFID']).astype(int) - 1 #Reset to 0 index
            AFNames = self.fast.fst_vt['AeroDyn15']['AFNames']   

            # Use airfoil data from FAST file read, assumes AeroDyn 15, assumes 1 Re num per airfoil
            af_dict = {}
            for i, section in enumerate(self.fast.fst_vt['AeroDyn15']['af_data']):
                Re = [section[0]['Re']]
                Alpha = section[0]['Alpha']
                if section[0]['NumTabs'] > 1:  # sections with flaps
                    ref_tab = int(np.floor(section[0]['NumTabs']/2))
                    Cl = section[ref_tab]['Cl']
                    Cd = section[ref_tab]['Cd']
                    Cm = section[ref_tab]['Cm']
                    af_dict[i] = CCAirfoil(Alpha, Re, Cl, Cd, Cm)
                else:                           # sections without flaps
                    Cl = section[0]['Cl']
                    Cd = section[0]['Cd']
                    Cm = section[0]['Cm']
                    af_dict[i] = CCAirfoil(Alpha, Re, Cl, Cd, Cm)





            # define airfoils for CCBlade
            af = [0]*len(r)
            for i in range(len(r)):
                af[i] = af_dict[af_idx[i]]

            # Now save the CC-Blade rotor
            nSector = 8  # azimuthal discretizations
            self.cc_rotor = CCBlade(r, chord, theta, af, self.Rhub, self.rotor_radius, self.NumBl, rho=self.rho, mu=self.mu,
                            precone=-self.precone, tilt=-self.tilt, yaw=self.yaw, shearExp=self.shearExp, hubHt=self.hubHt, nSector=nSector)

            # Save some blade  data 
            self.af_data = self.fast.fst_vt['AeroDyn15']['af_data']
            self.span = r 
            self.chord = chord
            self.twist = theta
            self.bld_flapwise_damp = self.fast.fst_vt['ElastoDynBlade']['BldFlDmp1']/100 * 0.7
Esempio n. 2
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        # Create Airfoil class instances
        af = [None] * self.n_span
        for i in range(self.n_span):
            if self.n_tab > 1:
                ref_tab = int(np.floor(self.n_tab / 2))
                af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                  inputs['airfoils_Re'],
                                  inputs['airfoils_cl'][i, :, :, ref_tab],
                                  inputs['airfoils_cd'][i, :, :, ref_tab],
                                  inputs['airfoils_cm'][i, :, :, ref_tab])
            else:
                af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                  inputs['airfoils_Re'],
                                  inputs['airfoils_cl'][i, :, :, 0],
                                  inputs['airfoils_cd'][i, :, :, 0],
                                  inputs['airfoils_cm'][i, :, :, 0])

        n_pitch = self.n_pitch
        n_tsr = self.n_tsr
        n_U = self.n_U
        min_TSR = self.min_TSR
        max_TSR = self.max_TSR
        min_pitch = self.min_pitch
        max_pitch = self.max_pitch
        U_vector = inputs['U_vector_in']
        V_in = inputs['v_min']
        V_out = inputs['v_max']

        tsr_vector = inputs['tsr_vector_in']
        pitch_vector = inputs['pitch_vector_in']

        self.ccblade = CCBlade(
            inputs['r'], inputs['chord'], inputs['theta'], af, inputs['Rhub'],
            inputs['Rtip'], discrete_inputs['nBlades'], inputs['rho'],
            inputs['mu'], inputs['precone'], inputs['tilt'], inputs['yaw'],
            inputs['shearExp'], inputs['hub_height'],
            discrete_inputs['nSector'], inputs['precurve'],
            inputs['precurveTip'], inputs['presweep'], inputs['presweepTip'],
            discrete_inputs['tiploss'], discrete_inputs['hubloss'],
            discrete_inputs['wakerotation'], discrete_inputs['usecd'])

        if max(U_vector) == 0.:
            U_vector = np.linspace(V_in[0], V_out[0], n_U)
        if max(tsr_vector) == 0.:
            tsr_vector = np.linspace(min_TSR, max_TSR, n_tsr)
        if max(pitch_vector) == 0.:
            pitch_vector = np.linspace(min_pitch, max_pitch, n_pitch)

        outputs['pitch_vector'] = pitch_vector
        outputs['tsr_vector'] = tsr_vector
        outputs['U_vector'] = U_vector

        R = inputs['Rtip']
        k = 0
        for i in range(n_U):
            for j in range(n_tsr):
                k += 1
                # if k/2. == int(k/2.) :
                print('Cp-Ct-Cq surfaces completed at ' +
                      str(int(k / (n_U * n_tsr) * 100.)) + ' %')
                U = U_vector[i] * np.ones(n_pitch)
                Omega = tsr_vector[j] * U_vector[
                    i] / R * 30. / np.pi * np.ones(n_pitch)
                myout, _ = self.ccblade.evaluate(U,
                                                 Omega,
                                                 pitch_vector,
                                                 coefficients=True)
                outputs['Cp'][j, :, i], outputs['Ct'][j, :, i], outputs['Cq'][
                    j, :, i] = [myout[key] for key in ['CP', 'CT', 'CQ']]
Esempio n. 3
0
    def load_from_ccblade(self):
        '''
        Loads rotor performance information by running cc-blade aerodynamic analysis. Designed to work with Aerodyn15 blade input files. 

        Parameters:
        -----------
            fast: dict
                  Dictionary containing fast model details - defined using from InputReader_OpenFAST (distributed as a part of AeroelasticSE)

        '''
        print('Loading rotor performance data from CC-Blade.')
        
        # Create CC-Blade Rotor
        r0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlSpn']) 
        chord0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlChord'])
        theta0 = np.array(self.fast.fst_vt['AeroDynBlade']['BlTwist'])
        # -- Adjust for Aerodyn15
        r = r0 + self.Rhub
        chord_intfun = interpolate.interp1d(r0,chord0, bounds_error=None, fill_value='extrapolate', kind='zero')
        chord = chord_intfun(r)
        theta_intfun = interpolate.interp1d(r0,theta0, bounds_error=None, fill_value='extrapolate', kind='zero')
        theta = theta_intfun(r)
        af_idx = np.array(self.fast.fst_vt['AeroDynBlade']['BlAFID']).astype(int) - 1 #Reset to 0 index
        AFNames = self.fast.fst_vt['AeroDyn15']['AFNames']   

        # Use airfoil data from FAST file read, assumes AeroDyn 15, assumes 1 Re num per airfoil
        af_dict = {}
        try:
            for i, _ in enumerate(self.fast.fst_vt['AeroDyn15']['af_data']):
                Re    = [self.fast.fst_vt['AeroDyn15']['af_data'][i][0]['Re']]
                Alpha = self.fast.fst_vt['AeroDyn15']['af_data'][i][0]['Alpha']
                Cl    = self.fast.fst_vt['AeroDyn15']['af_data'][i][0]['Cl']
                Cd    = self.fast.fst_vt['AeroDyn15']['af_data'][i][0]['Cd']
                Cm    = self.fast.fst_vt['AeroDyn15']['af_data'][i][0]['Cm']
                af_dict[i] = CCAirfoil(Alpha, Re, Cl, Cd, Cm)
        except: # Read airfoil tables without tab cabalities (will remove once wisdem master branch cleans up)
            for i, _ in enumerate(self.fast.fst_vt['AeroDyn15']['af_data']):
                Re    = [self.fast.fst_vt['AeroDyn15']['af_data'][i]['Re']]
                Alpha = self.fast.fst_vt['AeroDyn15']['af_data'][i]['Alpha']
                Cl    = self.fast.fst_vt['AeroDyn15']['af_data'][i]['Cl']
                Cd    = self.fast.fst_vt['AeroDyn15']['af_data'][i]['Cd']
                Cm    = self.fast.fst_vt['AeroDyn15']['af_data'][i]['Cm']
                af_dict[i] = CCAirfoil(Alpha, Re, Cl, Cd, Cm)

        # define airfoils for CCBlade
        af = [0]*len(r)
        for i in range(len(r)):
            af[i] = af_dict[af_idx[i]]

        # Now save the CC-Blade rotor
        nSector = 8  # azimuthal discretizations
        self.cc_rotor = CCBlade(r, chord, theta, af, self.Rhub, self.rotor_radius, self.NumBl, rho=self.rho, mu=self.mu,
                        precone=-self.precone, tilt=-self.tilt, yaw=self.yaw, shearExp=self.shearExp, hubHt=self.hubHt, nSector=nSector)
        print('CCBlade initiated successfully.')
        
        # Generate the look-up tables, mesh the grid and flatten the arrays for cc_rotor aerodynamic analysis
        TSR_initial = np.arange(3, 15,0.5)
        pitch_initial = np.arange(-1,25,0.5)
        pitch_initial_rad = pitch_initial * deg2rad
        ws_array = np.ones_like(TSR_initial) * self.v_rated # evaluate at rated wind speed
        omega_array = (TSR_initial * ws_array / self.rotor_radius) * RadSec2rpm
        ws_mesh, pitch_mesh = np.meshgrid(ws_array, pitch_initial)
        ws_flat = ws_mesh.flatten()
        pitch_flat = pitch_mesh.flatten()
        omega_mesh, _ = np.meshgrid(omega_array, pitch_initial)
        omega_flat = omega_mesh.flatten()
        # tsr_flat = (omega_flat * rpm2RadSec * self.rotor_radius)  / ws_flat


        # Get values from cc-blade
        print('Running CCBlade aerodynamic analysis, this may take a minute...')
        try:
            _, _, _, _, CP, CT, CQ, _ = self.cc_rotor.evaluate(ws_flat, omega_flat, pitch_flat, coefficients=True)
        except ValueError: # On IEAontology4all
            outputs, derivs = self.cc_rotor.evaluate(ws_flat, omega_flat, pitch_flat, coefficients=True)
            CP = outputs['CP']
            CT = outputs['CT']
            CQ = outputs['CQ']
        print('CCBlade aerodynamic analysis run successfully.')

        # Reshape Cp, Ct and Cq
        Cp = np.transpose(np.reshape(CP, (len(pitch_initial), len(TSR_initial))))
        Ct = np.transpose(np.reshape(CT, (len(pitch_initial), len(TSR_initial))))
        Cq = np.transpose(np.reshape(CQ, (len(pitch_initial), len(TSR_initial))))

        # Store necessary metrics for analysis
        self.pitch_initial_rad = pitch_initial_rad
        self.TSR_initial = TSR_initial
        self.Cp_table = Cp
        self.Ct_table = Ct 
        self.Cq_table = Cq
        
        # Save some blade parameters
        self.span = r
        self.chord = chord
        self.twist = theta
Esempio n. 4
0
    ]))
airfoils = input_yaml['airfoils']
cl = np.zeros((len(s), n_aoa, 1, 1))
cd = np.zeros((len(s), n_aoa, 1, 1))
cm = np.zeros((len(s), n_aoa, 1, 1))
for i in range(len(s)):
    cl[i, :, 0, 0] = np.interp(aoa, airfoils[i]['polars'][0]['c_l']['grid'],
                               airfoils[i]['polars'][0]['c_l']['values'])
    cd[i, :, 0, 0] = np.interp(aoa, airfoils[i]['polars'][0]['c_d']['grid'],
                               airfoils[i]['polars'][0]['c_d']['values'])
    cm[i, :, 0, 0] = np.interp(aoa, airfoils[i]['polars'][0]['c_m']['grid'],
                               airfoils[i]['polars'][0]['c_m']['values'])

af = [None] * len(s)
for i in range(len(s)):
    af[i] = CCAirfoil(np.rad2deg(aoa), [1e+6], cl[i, :, 0, 0], cd[i, :, 0, 0],
                      cm[i, :, 0, 0])

########## Run CCBlade ##########
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.)
Esempio n. 5
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
        '''
        Call ROSCO toolbox to define controller
        '''

        # Add control tuning parameters to dictionary
        self.modeling_options['servose']['omega_pc'] = inputs['PC_omega']
        self.modeling_options['servose']['zeta_pc'] = inputs['PC_zeta']
        self.modeling_options['servose']['omega_vs'] = inputs['VS_omega']
        self.modeling_options['servose']['zeta_vs'] = inputs['VS_zeta']
        if self.modeling_options['servose']['Flp_Mode'] > 0:
            self.modeling_options['servose']['omega_flp'] = inputs['Flp_omega']
            self.modeling_options['servose']['zeta_flp'] = inputs['Flp_zeta']
        else:
            self.modeling_options['servose']['omega_flp'] = 0.0
            self.modeling_options['servose']['zeta_flp'] = 0.0
        #
        self.modeling_options['servose']['max_pitch'] = inputs['max_pitch'][0]
        self.modeling_options['servose']['min_pitch'] = inputs['min_pitch'][0]
        self.modeling_options['servose']['vs_minspd'] = inputs['vs_minspd'][0]
        self.modeling_options['servose']['ss_vsgain'] = inputs['ss_vsgain'][0]
        self.modeling_options['servose']['ss_pcgain'] = inputs['ss_pcgain'][0]
        self.modeling_options['servose']['ps_percent'] = inputs['ps_percent'][
            0]
        if self.modeling_options['servose']['Flp_Mode'] > 0:
            self.modeling_options['servose']['flp_maxpit'] = inputs[
                'delta_max_pos'][0]
        else:
            self.modeling_options['servose']['flp_maxpit'] = None
        #
        self.modeling_options['servose']['ss_cornerfreq'] = None
        self.modeling_options['servose']['sd_maxpit'] = None
        self.modeling_options['servose']['sd_cornerfreq'] = None

        # Define necessary turbine parameters
        WISDEM_turbine = type('', (), {})()
        WISDEM_turbine.v_min = inputs['v_min'][0]
        WISDEM_turbine.J = inputs['rotor_inertia'][0]
        WISDEM_turbine.rho = inputs['rho'][0]
        WISDEM_turbine.rotor_radius = inputs['R'][0]
        WISDEM_turbine.Ng = inputs['gear_ratio'][0]
        WISDEM_turbine.GenEff = inputs['generator_efficiency'][0] * 100.
        WISDEM_turbine.GBoxEff = inputs['gearbox_efficiency'][0] * 100.
        WISDEM_turbine.rated_rotor_speed = inputs['rated_rotor_speed'][0]
        WISDEM_turbine.rated_power = inputs['rated_power'][0]
        WISDEM_turbine.rated_torque = inputs['rated_torque'][
            0] / WISDEM_turbine.Ng * inputs['gearbox_efficiency'][0]
        WISDEM_turbine.v_rated = inputs['v_rated'][0]
        WISDEM_turbine.v_min = inputs['v_min'][0]
        WISDEM_turbine.v_max = inputs['v_max'][0]
        WISDEM_turbine.max_pitch_rate = inputs['max_pitch_rate'][0]
        WISDEM_turbine.TSR_operational = inputs['tsr_operational'][0]
        WISDEM_turbine.max_torque_rate = inputs['max_torque_rate'][0]

        # Load Cp tables
        self.Cp_table = inputs['Cp_table']
        self.Ct_table = inputs['Ct_table']
        self.Cq_table = inputs['Cq_table']
        self.pitch_vector = WISDEM_turbine.pitch_initial_rad = inputs[
            'pitch_vector']
        self.tsr_vector = WISDEM_turbine.TSR_initial = inputs['tsr_vector']
        self.Cp_table = WISDEM_turbine.Cp_table = self.Cp_table.reshape(
            len(self.pitch_vector), len(self.tsr_vector))
        self.Ct_table = WISDEM_turbine.Ct_table = self.Ct_table.reshape(
            len(self.pitch_vector), len(self.tsr_vector))
        self.Cq_table = WISDEM_turbine.Cq_table = self.Cq_table.reshape(
            len(self.pitch_vector), len(self.tsr_vector))

        RotorPerformance = ROSCO_turbine.RotorPerformance
        WISDEM_turbine.Cp = RotorPerformance(self.Cp_table, self.pitch_vector,
                                             self.tsr_vector)
        WISDEM_turbine.Ct = RotorPerformance(self.Ct_table, self.pitch_vector,
                                             self.tsr_vector)
        WISDEM_turbine.Cq = RotorPerformance(self.Cq_table, self.pitch_vector,
                                             self.tsr_vector)

        # Load blade info to pass to flap controller tuning process
        if self.modeling_options['servose']['Flp_Mode'] >= 1:
            # Create airfoils
            af = [None] * self.n_span
            for i in range(self.n_span):
                if self.n_tab > 1:
                    ref_tab = int(np.floor(self.n_tab / 2))
                    af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                      inputs['airfoils_Re'],
                                      inputs['airfoils_cl'][i, :, :, ref_tab],
                                      inputs['airfoils_cd'][i, :, :, ref_tab],
                                      inputs['airfoils_cm'][i, :, :, ref_tab])
                else:
                    af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                      inputs['airfoils_Re'],
                                      inputs['airfoils_cl'][i, :, :, 0],
                                      inputs['airfoils_cd'][i, :, :, 0],
                                      inputs['airfoils_cm'][i, :, :, 0])

            # Initialize CCBlade as cc_rotor object
            WISDEM_turbine.cc_rotor = CCBlade(
                inputs['r'], inputs['chord'], inputs['theta'], af,
                inputs['Rhub'], inputs['Rtip'], discrete_inputs['nBlades'],
                inputs['rho'], inputs['mu'], inputs['precone'], inputs['tilt'],
                inputs['yaw'], inputs['shearExp'], inputs['hub_height'],
                discrete_inputs['nSector'], inputs['precurve'],
                inputs['precurveTip'], inputs['presweep'],
                inputs['presweepTip'], discrete_inputs['tiploss'],
                discrete_inputs['hubloss'], discrete_inputs['wakerotation'],
                discrete_inputs['usecd'])

            # Load aerodynamic performance data for blades
            WISDEM_turbine.af_data = [{} for i in range(self.n_span)]
            for i in range(self.n_span):
                # Check number of flap positions for each airfoil section
                if self.n_tab > 1:
                    if inputs['airfoils_Ctrl'][
                            i, 0, 0] == inputs['airfoils_Ctrl'][i, 0, 1]:
                        n_tabs = 1  # If all Ctrl angles of the flaps are identical then no flaps
                    else:
                        n_tabs = self.n_tab
                else:
                    n_tabs = 1
                # Save data for each flap position
                for j in range(n_tabs):
                    WISDEM_turbine.af_data[i][j] = {}
                    WISDEM_turbine.af_data[i][j]['NumTabs'] = n_tabs
                    WISDEM_turbine.af_data[i][j]['Ctrl'] = inputs[
                        'airfoils_Ctrl'][i, 0, j]
                    WISDEM_turbine.af_data[i][j]['Alpha'] = np.array(
                        inputs['airfoils_aoa']).flatten().tolist()
                    WISDEM_turbine.af_data[i][j]['Cl'] = np.array(
                        inputs['airfoils_cl'][i, :, 0, j]).flatten().tolist()
                    WISDEM_turbine.af_data[i][j]['Cd'] = np.array(
                        inputs['airfoils_cd'][i, :, 0, j]).flatten().tolist()
                    WISDEM_turbine.af_data[i][j]['Cm'] = np.array(
                        inputs['airfoils_cm'][i, :, 0, j]).flatten().tolist()

            # Save some more airfoil info
            WISDEM_turbine.span = inputs['r']
            WISDEM_turbine.chord = inputs['chord']
            WISDEM_turbine.twist = inputs['theta']
            WISDEM_turbine.bld_flapwise_freq = inputs['flap_freq'][
                0] * 2 * np.pi
            WISDEM_turbine.bld_flapwise_damp = self.modeling_options[
                'openfast']['fst_vt']['ElastoDynBlade']['BldFlDmp1'] / 100 * 0.7

        # Tune Controller!
        controller = ROSCO_controller.Controller(
            self.modeling_options['servose'])
        controller.tune_controller(WISDEM_turbine)

        # DISCON Parameters
        #   - controller

        if 'DISCON_in' not in self.modeling_options['openfast']['fst_vt'].keys(
        ):
            self.modeling_options['openfast']['fst_vt']['DISCON_in'] = {}
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'LoggingLevel'] = controller.LoggingLevel
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_LPFType'] = controller.F_LPFType
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_NotchType'] = controller.F_NotchType
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'IPC_ControlMode'] = controller.IPC_ControlMode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_ControlMode'] = controller.VS_ControlMode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_ControlMode'] = controller.PC_ControlMode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Y_ControlMode'] = controller.Y_ControlMode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SS_Mode'] = controller.SS_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_Mode'] = controller.WE_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PS_Mode'] = controller.PS_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SD_Mode'] = controller.SD_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Fl_Mode'] = controller.Fl_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Flp_Mode'] = controller.Flp_Mode
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_LPFDamping'] = controller.F_LPFDamping
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_SSCornerFreq'] = controller.ss_cornerfreq
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_GS_angles'] = controller.pitch_op_pc
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_GS_KP'] = controller.pc_gain_schedule.Kp
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_GS_KI'] = controller.pc_gain_schedule.Ki
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_MaxPit'] = controller.max_pitch
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_MinPit'] = controller.min_pitch
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_MinOMSpd'] = controller.vs_minspd
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_Rgn2K'] = controller.vs_rgn2K
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_RefSpd'] = controller.vs_refspd
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_KP'] = controller.vs_gain_schedule.Kp
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_KI'] = controller.vs_gain_schedule.Ki
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SS_VSGain'] = controller.ss_vsgain
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SS_PCGain'] = controller.ss_pcgain
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_FOPoles_N'] = len(controller.v)
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_FOPoles_v'] = controller.v
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_FOPoles'] = controller.A
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'ps_wind_speeds'] = controller.v
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PS_BldPitchMin'] = controller.ps_min_bld_pitch
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SD_MaxPit'] = controller.sd_maxpit + 0.1
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'SD_CornerFreq'] = controller.sd_cornerfreq
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Fl_Kp'] = controller.Kp_float
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Flp_Kp'] = controller.Kp_flap
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Flp_Ki'] = controller.Ki_flap
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Flp_MaxPit'] = controller.flp_maxpit
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Flp_Angle'] = 0.

        # - turbine
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_BladeRadius'] = WISDEM_turbine.rotor_radius
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'v_rated'] = inputs['v_rated'][0]
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_FlpCornerFreq'] = [
                inputs['flap_freq'][0] * 2 * np.pi / 3., 0.7
            ]
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_LPFCornerFreq'] = inputs['edge_freq'][0] * 2 * np.pi / 4.
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_NotchCornerFreq'] = 0.0  # inputs(['twr_freq']) # zero for now, fix when floating introduced to WISDEM
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_FlCornerFreq'] = [
                0.0, 0.0
            ]  # inputs(['ptfm_freq']) # zero for now, fix when floating introduced to WISDEM
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_MaxRat'] = WISDEM_turbine.max_pitch_rate
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_MinRat'] = -WISDEM_turbine.max_pitch_rate
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_MaxRat'] = WISDEM_turbine.max_torque_rate
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'PC_RefSpd'] = WISDEM_turbine.rated_rotor_speed * WISDEM_turbine.Ng
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_RtPwr'] = WISDEM_turbine.rated_power
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_RtTq'] = WISDEM_turbine.rated_torque
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_MaxTq'] = WISDEM_turbine.rated_torque * 1.1
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'VS_TSRopt'] = WISDEM_turbine.TSR_operational
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_RhoAir'] = WISDEM_turbine.rho
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_GearboxRatio'] = WISDEM_turbine.Ng
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'WE_Jtot'] = WISDEM_turbine.J
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cp_pitch_initial_rad'] = self.pitch_vector
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cp_TSR_initial'] = self.tsr_vector
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cp_table'] = WISDEM_turbine.Cp_table
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Ct_table'] = WISDEM_turbine.Ct_table
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cq_table'] = WISDEM_turbine.Cq_table
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cp'] = WISDEM_turbine.Cp
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Ct'] = WISDEM_turbine.Ct
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'Cq'] = WISDEM_turbine.Cq

        # Outputs
        outputs['Flp_Kp'] = controller.Kp_flap[-1]
        outputs['Flp_Ki'] = controller.Ki_flap[-1]
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
        r = inputs['r']
        chord = inputs['chord']
        theta = inputs['theta']
        Rhub = inputs['Rhub']
        Rtip = inputs['Rtip']
        hub_height = inputs['hub_height']
        precone = inputs['precone']
        tilt = inputs['tilt']
        yaw = inputs['yaw']
        precurve = inputs['precurve']
        precurveTip = inputs['precurveTip']
        # airfoils = discrete_inputs['airfoils']
        B = discrete_inputs['nBlades']
        rho = inputs['rho']
        mu = inputs['mu']
        shearExp = inputs['shearExp']
        nSector = discrete_inputs['nSector']
        tiploss = discrete_inputs['tiploss']
        hubloss = discrete_inputs['hubloss']
        wakerotation = discrete_inputs['wakerotation']
        usecd = discrete_inputs['usecd']
        V_load = inputs['V_load']
        Omega_load = inputs['Omega_load']
        pitch_load = inputs['pitch_load']
        azimuth_load = inputs['azimuth_load']

        if len(precurve) == 0:
            precurve = np.zeros_like(r)

        # airfoil files
        af = [None] * self.n_span
        for i in range(self.n_span):
            af[i] = CCAirfoil(inputs['airfoils_aoa'], inputs['airfoils_Re'],
                              inputs['airfoils_cl'][i, :, :, 0],
                              inputs['airfoils_cd'][i, :, :, 0],
                              inputs['airfoils_cm'][i, :, :, 0])

        ccblade = CCBlade(r,
                          chord,
                          theta,
                          af,
                          Rhub,
                          Rtip,
                          B,
                          rho,
                          mu,
                          precone,
                          tilt,
                          yaw,
                          shearExp,
                          hub_height,
                          nSector,
                          precurve,
                          precurveTip,
                          tiploss=tiploss,
                          hubloss=hubloss,
                          wakerotation=wakerotation,
                          usecd=usecd,
                          derivatives=True)

        # distributed loads
        loads, self.derivs = ccblade.distributedAeroLoads(
            V_load, Omega_load, pitch_load, azimuth_load)
        Np = loads['Np']
        Tp = loads['Tp']

        # concatenate loads at root/tip
        outputs['loads_r'] = r

        # conform to blade-aligned coordinate system
        outputs['loads_Px'] = Np
        outputs['loads_Py'] = -Tp
        outputs['loads_Pz'] = 0 * Np
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        r = inputs['r']
        chord = inputs['chord']
        theta = inputs['theta']
        Rhub = inputs['Rhub']
        Rtip = inputs['Rtip']
        hub_height = inputs['hub_height']
        precone = inputs['precone']
        tilt = inputs['tilt']
        yaw = inputs['yaw']
        precurve = inputs['precurve']
        precurveTip = inputs['precurveTip']
        # airfoils = discrete_inputs['airfoils']
        B = discrete_inputs['nBlades']
        rho = inputs['rho']
        mu = inputs['mu']
        shearExp = inputs['shearExp']
        nSector = discrete_inputs['nSector']
        tiploss = discrete_inputs['tiploss']
        hubloss = discrete_inputs['hubloss']
        wakerotation = discrete_inputs['wakerotation']
        usecd = discrete_inputs['usecd']
        Uhub = inputs['Uhub']
        Omega = inputs['Omega']
        pitch = inputs['pitch']

        af = [None] * self.naero
        for i in range(self.naero):
            af[i] = CCAirfoil(inputs['airfoils_aoa'], inputs['airfoils_Re'],
                              inputs['airfoils_cl'][:, i, :],
                              inputs['airfoils_cd'][:, i, :],
                              inputs['airfoils_cm'][:, i, :])

        ccblade = CCBlade(r,
                          chord,
                          theta,
                          af,
                          Rhub,
                          Rtip,
                          B,
                          rho,
                          mu,
                          precone,
                          tilt,
                          yaw,
                          shearExp,
                          hub_height,
                          nSector,
                          precurve,
                          precurveTip,
                          tiploss=tiploss,
                          hubloss=hubloss,
                          wakerotation=wakerotation,
                          usecd=usecd,
                          derivatives=True)

        # power, thrust, torque
        myoutputs, self.derivs = ccblade.evaluate(Uhub,
                                                  Omega,
                                                  pitch,
                                                  coefficients=False)
        outputs['T'] = myoutputs['T']
        outputs['Q'] = myoutputs['Q']
        outputs['P'] = myoutputs['P']
Esempio n. 8
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        # Create Airfoil class instances
        af = [None] * self.n_span
        for i in range(self.n_span):
            if self.n_tab > 1:
                ref_tab = int(np.floor(self.n_tab / 2))
                af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                  inputs['airfoils_Re'],
                                  inputs['airfoils_cl'][i, :, :, ref_tab],
                                  inputs['airfoils_cd'][i, :, :, ref_tab],
                                  inputs['airfoils_cm'][i, :, :, ref_tab])
            else:
                af[i] = CCAirfoil(inputs['airfoils_aoa'],
                                  inputs['airfoils_Re'],
                                  inputs['airfoils_cl'][i, :, :, 0],
                                  inputs['airfoils_cd'][i, :, :, 0],
                                  inputs['airfoils_cm'][i, :, :, 0])

        self.ccblade = CCBlade(
            inputs['r'], inputs['chord'], inputs['theta'], af, inputs['Rhub'],
            inputs['Rtip'], discrete_inputs['nBlades'], inputs['rho'],
            inputs['mu'], inputs['precone'], inputs['tilt'], inputs['yaw'],
            inputs['shearExp'], inputs['hub_height'],
            discrete_inputs['nSector'], inputs['precurve'],
            inputs['precurveTip'], inputs['presweep'], inputs['presweepTip'],
            discrete_inputs['tiploss'], discrete_inputs['hubloss'],
            discrete_inputs['wakerotation'], discrete_inputs['usecd'])

        # JPJ: what is this grid for? Seems to be a special distribution of velocities
        # for the hub
        grid0 = np.cumsum(
            np.abs(
                np.diff(
                    np.cos(np.linspace(-np.pi / 4., np.pi / 2.,
                                       self.n_pc + 1)))))
        grid1 = (grid0 - grid0[0]) / (grid0[-1] - grid0[0])
        Uhub = grid1 * (inputs['v_max'] - inputs['v_min']) + inputs['v_min']

        P_aero = np.zeros(Uhub.shape)
        Cp_aero = np.zeros(Uhub.shape)
        Ct_aero = np.zeros(Uhub.shape)
        Cq_aero = np.zeros(Uhub.shape)
        Cm_aero = np.zeros(Uhub.shape)
        P = np.zeros(Uhub.shape)
        Cp = np.zeros(Uhub.shape)
        T = np.zeros(Uhub.shape)
        Q = np.zeros(Uhub.shape)
        M = np.zeros(Uhub.shape)
        pitch = np.zeros(Uhub.shape) + inputs['control_pitch']

        # Unpack variables
        P_rated = inputs['rated_power']
        R_tip = inputs['Rtip']
        tsr = inputs['tsr_operational']
        driveType = discrete_inputs['drivetrainType']
        driveEta = inputs['gearbox_efficiency'] * inputs['generator_efficiency']

        # Set rotor speed based on TSR
        Omega_tsr = Uhub * tsr / R_tip

        # Determine maximum rotor speed (rad/s)- either by TS or by control input
        Omega_max = min([
            inputs['control_maxTS'] / R_tip, inputs['omega_max'] * np.pi / 30.
        ])

        # Apply maximum and minimum rotor speed limits
        Omega = np.maximum(np.minimum(Omega_tsr, Omega_max),
                           inputs['omega_min'] * np.pi / 30.)
        Omega_rpm = Omega * 30. / np.pi

        # Set baseline power production
        myout, derivs = self.ccblade.evaluate(Uhub,
                                              Omega_rpm,
                                              pitch,
                                              coefficients=True)
        P_aero, T, Q, M, Cp_aero, Ct_aero, Cq_aero, Cm_aero = [
            myout[key] for key in ['P', 'T', 'Q', 'M', 'CP', 'CT', 'CQ', 'CM']
        ]
        P, eff = compute_P_and_eff(P_aero, P_rated, driveType, driveEta)
        Cp = Cp_aero * eff

        # Find Region 3 index
        region_bool = np.nonzero(P >= P_rated)[0]
        if len(region_bool) == 0:
            i_3 = self.n_pc
            region3 = False
        else:
            i_3 = region_bool[0] + 1
            region3 = True

        # Guess at Region 2.5, but we will do a more rigorous search below
        if Omega_max < Omega_tsr[-1]:
            U_2p5 = np.interp(Omega[-1], Omega_tsr, Uhub)
            outputs['V_R25'] = U_2p5
        else:
            U_2p5 = Uhub[-1]
        i_2p5 = np.nonzero(U_2p5 <= Uhub)[0][0]

        # Find rated index and guess at rated speed
        if P_aero[-1] > P_rated:
            U_rated = np.interp(P_rated, P_aero * eff, Uhub)
        else:
            U_rated = Uhub[-1]
        i_rated = np.nonzero(U_rated <= Uhub)[0][0]

        # Function to be used inside of power maximization until Region 3
        def maximizePower(pitch, Uhub, Omega_rpm):
            myout, _ = self.ccblade.evaluate([Uhub], [Omega_rpm], [pitch],
                                             coefficients=False)
            return -myout['P']

        # Maximize power until Region 3
        region2p5 = False
        for i in range(i_3):
            # No need to optimize if already doing well
            if Omega[i] == Omega_tsr[i]: continue

            # Find pitch value that gives highest power rating
            pitch0 = pitch[i] if i == 0 else pitch[i - 1]
            bnds = [pitch0 - 10., pitch0 + 10.]
            pitch[i] = minimize_scalar(
                lambda x: maximizePower(x, Uhub[i], Omega_rpm[i]),
                bounds=bnds,
                method='bounded',
                options={
                    'disp': False,
                    'xatol': 1e-2,
                    'maxiter': 40
                })['x']

            # Find associated power
            myout, _ = self.ccblade.evaluate([Uhub[i]], [Omega_rpm[i]],
                                             [pitch[i]],
                                             coefficients=True)
            P_aero[i], T[i], Q[i], M[i], Cp_aero[i], Ct_aero[i], Cq_aero[
                i], Cm_aero[i] = [
                    myout[key]
                    for key in ['P', 'T', 'Q', 'M', 'CP', 'CT', 'CQ', 'CM']
                ]
            P[i], eff = compute_P_and_eff(P_aero[i], P_rated, driveType,
                                          driveEta)
            Cp[i] = Cp_aero[i] * eff

            # Note if we find Region 2.5
            if ((not region2p5) and (Omega[i] == Omega_max)
                    and (P[i] < P_rated)):
                region2p5 = True
                i_2p5 = i

            # Stop if we find Region 3 early
            if P[i] > P_rated:
                i_3 = i + 1
                i_rated = i
                break

        # Solve for rated velocity
        # JPJ: why rename i_rated to i here? It removes clarity in the following 50 lines that we're looking at the rated properties
        i = i_rated
        if i < self.n_pc - 1:

            def const_Urated(x):
                pitch = x[0]
                Uhub_i = x[1]
                Omega_i = min([Uhub_i * tsr / R_tip, Omega_max])
                myout, _ = self.ccblade.evaluate([Uhub_i],
                                                 [Omega_i * 30. / np.pi],
                                                 [pitch],
                                                 coefficients=False)
                P_aero_i = myout['P']
                P_i, eff = compute_P_and_eff(P_aero_i.flatten(), P_rated,
                                             driveType, driveEta)
                return (P_i - P_rated)

            if region2p5:
                # Have to search over both pitch and speed
                x0 = [0.0, Uhub[i]]
                bnds = [
                    np.sort([pitch[i - 1], pitch[i + 1]]),
                    [Uhub[i - 1], Uhub[i + 1]]
                ]
                const = {}
                const['type'] = 'eq'
                const['fun'] = const_Urated
                params_rated = minimize(lambda x: x[1],
                                        x0,
                                        method='slsqp',
                                        bounds=bnds,
                                        constraints=const,
                                        tol=1e-3)

                if params_rated.success and not np.isnan(params_rated.x[1]):
                    U_rated = params_rated.x[1]
                    pitch[i] = params_rated.x[0]
                else:
                    U_rated = U_rated  # Use guessed value earlier
                    pitch[i] = 0.0
            else:
                # Just search over speed
                pitch[i] = 0.0
                try:
                    U_rated = brentq(lambda x: const_Urated([0.0, x]),
                                     Uhub[i - 1],
                                     Uhub[i + 1],
                                     xtol=1e-4,
                                     rtol=1e-5,
                                     maxiter=40,
                                     disp=False)
                except ValueError:
                    U_rated = minimize_scalar(
                        lambda x: np.abs(const_Urated([0.0, x])),
                        bounds=[Uhub[i - 1], Uhub[i + 1]],
                        method='bounded',
                        options={
                            'disp': False,
                            'xatol': 1e-3,
                            'maxiter': 40
                        })['x']

            Omega_rated = min([U_rated * tsr / R_tip, Omega_max])
            Omega[i:] = np.minimum(
                Omega[i:],
                Omega_rated)  # Stay at this speed if hit rated too early
            Omega_rpm = Omega * 30. / np.pi
            myout, _ = self.ccblade.evaluate([U_rated], [Omega_rpm[i]],
                                             [pitch[i]],
                                             coefficients=True)
            P_aero[i], T[i], Q[i], M[i], Cp_aero[i], Ct_aero[i], Cq_aero[
                i], Cm_aero[i] = [
                    myout[key]
                    for key in ['P', 'T', 'Q', 'M', 'CP', 'CT', 'CQ', 'CM']
                ]
            P[i], eff = compute_P_and_eff(P_aero[i], P_rated, driveType,
                                          driveEta)
            Cp[i] = Cp_aero[i] * eff
            P[i] = P_rated

        # Store rated speed in array
        Uhub[i_rated] = U_rated

        # Store outputs
        outputs['rated_V'] = np.float64(U_rated)
        outputs['rated_Omega'] = Omega_rpm[i]
        outputs['rated_pitch'] = pitch[i]
        outputs['rated_T'] = T[i]
        outputs['rated_Q'] = Q[i]

        # JPJ: this part can be converted into a BalanceComp with a solver.
        # This will be less expensive and allow us to get derivatives through the process.
        if region3:
            # Function to be used to stay at rated power in Region 3
            def rated_power_dist(pitch, Uhub, Omega_rpm):
                myout, _ = self.ccblade.evaluate([Uhub], [Omega_rpm], [pitch],
                                                 coefficients=False)
                P_aero = myout['P']
                P, eff = compute_P_and_eff(P_aero, P_rated, driveType,
                                           driveEta)
                return (P - P_rated)

            # Solve for Region 3 pitch
            options = {'disp': False}
            if self.regulation_reg_III:
                for i in range(i_3, self.n_pc):
                    pitch0 = pitch[i - 1]
                    try:
                        pitch[i] = brentq(lambda x: rated_power_dist(
                            x, Uhub[i], Omega_rpm[i]),
                                          pitch0,
                                          pitch0 + 10.,
                                          xtol=1e-4,
                                          rtol=1e-5,
                                          maxiter=40,
                                          disp=False)
                    except ValueError:
                        pitch[i] = minimize_scalar(
                            lambda x: np.abs(
                                rated_power_dist(x, Uhub[i], Omega_rpm[i])),
                            bounds=[pitch0 - 5., pitch0 + 15.],
                            method='bounded',
                            options={
                                'disp': False,
                                'xatol': 1e-3,
                                'maxiter': 40
                            })['x']

                    myout, _ = self.ccblade.evaluate([Uhub[i]], [Omega_rpm[i]],
                                                     [pitch[i]],
                                                     coefficients=True)
                    P_aero[i], T[i], Q[i], M[i], Cp_aero[i], Ct_aero[
                        i], Cq_aero[i], Cm_aero[i] = [
                            myout[key] for key in
                            ['P', 'T', 'Q', 'M', 'CP', 'CT', 'CQ', 'CM']
                        ]
                    P[i], eff = compute_P_and_eff(P_aero[i], P_rated,
                                                  driveType, driveEta)
                    Cp[i] = Cp_aero[i] * eff
                    #P[i]       = P_rated

            else:
                P[i_3:] = P_rated
                T[i_3:] = 0
                Q[i_3:] = P[i_3:] / Omega[i_3:]
                M[i_3:] = 0
                pitch[i_3:] = 0
                Cp[i_3:] = P[i_3:] / (0.5 * inputs['rho'] * np.pi * R_tip**2 *
                                      Uhub[i_3:]**3)
                Ct_aero[i_3:] = 0
                Cq_aero[i_3:] = 0
                Cm_aero[i_3:] = 0

        outputs['T'] = T
        outputs['Q'] = Q
        outputs['Omega'] = Omega_rpm

        outputs['P'] = P
        outputs['Cp'] = Cp
        outputs['Cp_aero'] = Cp_aero
        outputs['Ct_aero'] = Ct_aero
        outputs['Cq_aero'] = Cq_aero
        outputs['Cm_aero'] = Cm_aero
        outputs['V'] = Uhub
        outputs['M'] = M
        outputs['pitch'] = pitch

        self.ccblade.induction_inflow = True
        tsr_vec = Omega_rpm / 30. * np.pi * R_tip / Uhub
        id_regII = np.argmin(abs(tsr_vec - inputs['tsr_operational']))
        loads, derivs = self.ccblade.distributedAeroLoads(
            Uhub[id_regII], Omega_rpm[id_regII], pitch[id_regII], 0.0)

        # outputs
        outputs['ax_induct_regII'] = loads['a']
        outputs['tang_induct_regII'] = loads['ap']
        outputs['aoa_regII'] = loads['alpha']
        outputs['cl_regII'] = loads['Cl']
        outputs['cd_regII'] = loads['Cd']
        outputs['Cp_regII'] = Cp_aero[id_regII]
Esempio n. 9
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
        self.r = inputs['r']
        self.chord = inputs['chord']
        self.theta = inputs['theta']
        self.Rhub = inputs['Rhub']
        self.Rtip = inputs['Rtip']
        self.hub_height = inputs['hub_height']
        self.precone = inputs['precone']
        self.tilt = inputs['tilt']
        self.yaw = inputs['yaw']
        self.precurve = inputs['precurve']
        self.precurveTip = inputs['precurveTip']
        # self.airfoils = discrete_inputs['airfoils']
        self.B = discrete_inputs['nBlades']
        self.rho = inputs['rho']
        self.mu = inputs['mu']
        self.shearExp = inputs['shearExp']
        self.nSector = discrete_inputs['nSector']
        self.tiploss = discrete_inputs['tiploss']
        self.hubloss = discrete_inputs['hubloss']
        self.wakerotation = discrete_inputs['wakerotation']
        self.usecd = discrete_inputs['usecd']
        self.V_load = inputs['V_load']
        self.Omega_load = inputs['Omega_load']
        self.pitch_load = inputs['pitch_load']
        self.azimuth_load = inputs['azimuth_load']

        if len(self.precurve) == 0:
            self.precurve = np.zeros_like(self.r)

        # airfoil files
        # n = len(self.airfoils)
        af = [None] * self.naero
        for i in range(self.naero):
            af[i] = CCAirfoil(inputs['airfoils_aoa'], inputs['airfoils_Re'],
                              inputs['airfoils_cl'][:, i, :],
                              inputs['airfoils_cd'][:, i, :],
                              inputs['airfoils_cm'][:, i, :])
        # af = self.airfoils

        self.ccblade = CCBlade(self.r,
                               self.chord,
                               self.theta,
                               af,
                               self.Rhub,
                               self.Rtip,
                               self.B,
                               self.rho,
                               self.mu,
                               self.precone,
                               self.tilt,
                               self.yaw,
                               self.shearExp,
                               self.hub_height,
                               self.nSector,
                               self.precurve,
                               self.precurveTip,
                               tiploss=self.tiploss,
                               hubloss=self.hubloss,
                               wakerotation=self.wakerotation,
                               usecd=self.usecd,
                               derivatives=True)

        # distributed loads
        Np, Tp, self.dNp, self.dTp \
            = self.ccblade.distributedAeroLoads(self.V_load, self.Omega_load, self.pitch_load, self.azimuth_load)

        # concatenate loads at root/tip
        outputs['loads_r'] = self.r

        # conform to blade-aligned coordinate system
        outputs['loads_Px'] = Np
        outputs['loads_Py'] = -Tp
        outputs['loads_Pz'] = 0 * Np

        # return other outputs needed
        outputs['loads_V'] = self.V_load
        outputs['loads_Omega'] = self.Omega_load
        outputs['loads_pitch'] = self.pitch_load
        outputs['loads_azimuth'] = self.azimuth_load
        '''
Esempio n. 10
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):

        self.r = inputs['r']
        self.chord = inputs['chord']
        self.theta = inputs['theta']
        self.Rhub = inputs['Rhub']
        self.Rtip = inputs['Rtip']
        self.hub_height = inputs['hub_height']
        self.precone = inputs['precone']
        self.tilt = inputs['tilt']
        self.yaw = inputs['yaw']
        self.precurve = inputs['precurve']
        self.precurveTip = inputs['precurveTip']
        # self.airfoils = discrete_inputs['airfoils']
        self.B = discrete_inputs['nBlades']
        self.rho = inputs['rho']
        self.mu = inputs['mu']
        self.shearExp = inputs['shearExp']
        self.nSector = discrete_inputs['nSector']
        self.tiploss = discrete_inputs['tiploss']
        self.hubloss = discrete_inputs['hubloss']
        self.wakerotation = discrete_inputs['wakerotation']
        self.usecd = discrete_inputs['usecd']
        self.Uhub = inputs['Uhub']
        self.Omega = inputs['Omega']
        self.pitch = inputs['pitch']

        af = [None] * self.naero
        for i in range(self.naero):
            af[i] = CCAirfoil(inputs['airfoils_aoa'], inputs['airfoils_Re'],
                              inputs['airfoils_cl'][:, i, :],
                              inputs['airfoils_cd'][:, i, :],
                              inputs['airfoils_cm'][:, i, :])

        self.ccblade = CCBlade(self.r,
                               self.chord,
                               self.theta,
                               af,
                               self.Rhub,
                               self.Rtip,
                               self.B,
                               self.rho,
                               self.mu,
                               self.precone,
                               self.tilt,
                               self.yaw,
                               self.shearExp,
                               self.hub_height,
                               self.nSector,
                               self.precurve,
                               self.precurveTip,
                               tiploss=self.tiploss,
                               hubloss=self.hubloss,
                               wakerotation=self.wakerotation,
                               usecd=self.usecd,
                               derivatives=True)

        # power, thrust, torque
        self.P, self.T, self.Q, self.M, self.dP, self.dT, self.dQ \
            = self.ccblade.evaluate(self.Uhub, self.Omega, self.pitch, coefficients=False)
        outputs['T'] = self.T
        outputs['Q'] = self.Q
        outputs['P'] = self.P
        '''