示例#1
0
            dev_branch=True,rot_source='txt',txt_filename=path_params['rotor_performance_filename'])
else:
    turbine.load_from_fast(path_params['FAST_InputFile'], \
        os.path.join(this_dir,path_params['FAST_directory']), \
            dev_branch=True,rot_source=None, txt_filename=path_params['rotor_performance_filename'])

    write_rotor_performance(turbine,
                            txt_filename=os.path.join(
                                this_dir,
                                path_params['rotor_performance_filename']))

# Flap tuning if necessary
if controller_params['Flp_Mode']:
    turbine.load_blade_info()

# Instantiate controller tuning and tune controller
controller = ROSCO_controller.Controller(controller_params)
controller.tune_controller(turbine)

# Write parameter input file
param_file = 'DISCON.IN'
write_DISCON(turbine,
             controller,
             param_file=param_file,
             txt_filename=os.path.join(
                 this_dir, path_params['rotor_performance_filename']))

# Plot rotor performance
turbine.Cp.plot_performance()
plt.show()
示例#2
0
    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
        '''
        Call ROSCO toolbox to define controller
        '''
        rosco_init_options = self.modeling_options['Level3']['ROSCO']
        # Add control tuning parameters to dictionary
        rosco_init_options['omega_pc'] = inputs['PC_omega']
        rosco_init_options['zeta_pc'] = inputs['PC_zeta']
        rosco_init_options['omega_vs'] = inputs['VS_omega']
        rosco_init_options['zeta_vs'] = inputs['VS_zeta']
        if rosco_init_options['Flp_Mode'] > 0:
            rosco_init_options['omega_flp'] = inputs['Flp_omega']
            rosco_init_options['zeta_flp'] = inputs['Flp_zeta']
        else:
            rosco_init_options['omega_flp'] = 0.0
            rosco_init_options['zeta_flp'] = 0.0
        #
        rosco_init_options['max_pitch'] = float(inputs['max_pitch'])
        rosco_init_options['min_pitch'] = float(inputs['min_pitch'])
        rosco_init_options['vs_minspd'] = float(inputs['vs_minspd'])
        rosco_init_options['ss_vsgain'] = float(inputs['ss_vsgain'])
        rosco_init_options['ss_pcgain'] = float(inputs['ss_pcgain'])
        rosco_init_options['ps_percent'] = float(inputs['ps_percent'])
        if rosco_init_options['Flp_Mode'] > 0:
            rosco_init_options['flp_maxpit'] = float(inputs['delta_max_pos'])
        else:
            rosco_init_options['flp_maxpit'] = None
        #
        rosco_init_options['ss_cornerfreq'] = None
        rosco_init_options['sd_maxpit'] = None
        rosco_init_options['sd_cornerfreq'] = None

        # Define necessary turbine parameters
        WISDEM_turbine = type('', (), {})()
        WISDEM_turbine.v_min = float(inputs['v_min'])
        WISDEM_turbine.J = float(inputs['rotor_inertia'])
        WISDEM_turbine.rho = float(inputs['rho'])
        WISDEM_turbine.rotor_radius = float(inputs['R'])
        WISDEM_turbine.Ng = float(inputs['gear_ratio'])
        # Incoming value already has gearbox eff included, so have to separate it out
        WISDEM_turbine.GenEff = float(inputs['generator_efficiency'] /
                                      inputs['gearbox_efficiency']) * 100.
        WISDEM_turbine.GBoxEff = float(inputs['gearbox_efficiency']) * 100.
        WISDEM_turbine.rated_rotor_speed = float(inputs['rated_rotor_speed'])
        WISDEM_turbine.rated_power = float(inputs['rated_power'])
        WISDEM_turbine.rated_torque = float(
            inputs['rated_torque']) / WISDEM_turbine.Ng * float(
                inputs['gearbox_efficiency'])
        WISDEM_turbine.v_rated = float(inputs['v_rated'])
        WISDEM_turbine.v_min = float(inputs['v_min'])
        WISDEM_turbine.v_max = float(inputs['v_max'])
        WISDEM_turbine.max_pitch_rate = float(inputs['max_pitch_rate'])
        WISDEM_turbine.TSR_operational = float(inputs['tsr_operational'])
        WISDEM_turbine.max_torque_rate = float(inputs['max_torque_rate'])
        WISDEM_turbine.TowerHt = float(inputs['TowerHt'])

        # Floating Feedback Filters
        WISDEM_turbine.twr_freq = float(inputs['twr_freq'])
        WISDEM_turbine.ptfm_freq = float(inputs['ptfm_freq'])

        # 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 rosco_init_options['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 = float(
                inputs['flap_freq']) * 2 * np.pi
            WISDEM_turbine.bld_flapwise_damp = self.modeling_options['Level3'][
                'ROSCO']['Bld_FlpDamp']

        # Tune Controller!
        controller = ROSCO_controller.Controller(rosco_init_options)
        controller.tune_controller(WISDEM_turbine)

        # DISCON Parameters
        #   - controller
        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'][
            'IPC_Ki'] = float(inputs['IPC_Ki1p'])
        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'] = float(inputs['v_rated'])
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_FlpCornerFreq'] = [
                float(inputs['flap_freq']) * 2 * np.pi / 3., 0.7
            ]
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_LPFCornerFreq'] = float(inputs['edge_freq']) * 2 * np.pi / 4.
        self.modeling_options['openfast']['fst_vt']['DISCON_in'][
            'F_NotchCornerFreq'] = WISDEM_turbine.twr_freq  # inputs(['twr_freq']) # zero for now, fix when floating introduced to WISDEM
        self.modeling_options['openfast'][
            'fst_vt']['DISCON_in']['F_FlCornerFreq'] = [
                WISDEM_turbine.ptfm_freq, 0.707
            ]  # 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
        if rosco_init_options['Flp_Mode'] >= 1:
            outputs[
                'flptune_coeff1'] = 2 * WISDEM_turbine.bld_flapwise_damp * WISDEM_turbine.bld_flapwise_freq + controller.kappa[
                    -1] * WISDEM_turbine.bld_flapwise_freq**2 * controller.Kp_flap[
                        -1]
            outputs['flptune_coeff2'] = WISDEM_turbine.bld_flapwise_freq**2 * (
                controller.Ki_flap[-1] * controller.kappa[-1] + 1)
        outputs['PC_Kp'] = controller.pc_gain_schedule.Kp[0]
        outputs['PC_Ki'] = controller.pc_gain_schedule.Ki[0]
        outputs['Flp_Kp'] = controller.Kp_flap[-1]
        outputs['Flp_Ki'] = controller.Ki_flap[-1]
    def gen_control_cases(self, input_params, DISCON_params, values, group):
        '''
        Generate control case input dictionary for controller parameters

        Parameters
        ----------
        input_params: list
            List of parameters that exist in the controller tuning yaml file that will be modified
        DISCON_params: list
            List of parameters in DISCON.IN that will be changed by the paremeters in input_params
        values: list
            List with nested lists of floats that correspond to the input_params. 
                - i.e. [[0.1],[0.5]]
        group: int
            Group number for case_inputs

        Returns
        -------
        case_inputs: dict
            Dictionary of case inputs for WISDEM's CaseGen_General
        tuning_inputs: dict
            Dictionary containing yaml input tuning parameters
        '''
        # Load turbine
        turbine = ROSCO_turbine.Turbine(self.turbine_params)
        turbine.load_from_fast(self.path_params['FAST_InputFile'],
                               self.path_params['FAST_directory'],
                               dev_branch=True)
        # if not os.path.exists(self.path_params['rotor_performance_filename']):
        #     R.write_rotor_performance(turbine,txt_filename=path_params['rotor_performance_filename'])

        # Check for flaps
        if 'zeta_flp' in input_params or 'omega_flp' in input_params:
            self.controller_params['Flp_Mode'] = 2
            turbine.load_blade_info()

        # Create tuning value matrix
        tuning_matrix = list(itertools.product(*values))

        # Generate cases
        case_inputs = {}
        tuning_inputs = {key: [] for key in input_params}
        DISCON_vals_list = {key: [] for key in DISCON_params}
        for tuning_params in tuning_matrix:
            for inp_ind, inp_p in enumerate(input_params):
                # Modify controller parameters
                self.controller_params[inp_p] = tuning_params[inp_ind]
                # tuning_inputs[inp_p].append(tuning_params[inp_ind])

            # Initialize and tune controller
            controller = ROSCO_controller.Controller(self.controller_params)
            controller.tune_controller(turbine)

            # Get DISCON input parameters
            data_processing = ROSCO_Utilities.DataProcessing()
            DISCON_inputs = data_processing.DISCON_dict(turbine, controller)

            # Check for invalid controller inputs
            if (any(item in ['VS_KP', 'VS_KI'] for item in DISCON_params)
                    and any(DISCON_inputs[DISCON_p][0] > 0
                            for DISCON_p in DISCON_params)):
                print(
                    'WARNING: Control gains cannot be greater than zero and are for {} = {}'
                    .format([param for param in input_params], tuning_params))
            elif (any(item in ['Flp_Kp', 'Flp_Ki'] for item in DISCON_params)
                  and any(DISCON_inputs[DISCON_p][0] < 0
                          for DISCON_p in DISCON_params)):
                print(
                    'WARNING: Control gains cannot be less than zero and are for {} = {}'
                    .format([param for param in input_params], tuning_params))
            # Save DISCON and tuning inputs
            else:
                for DISCON_p in DISCON_params:
                    DISCON_vals = DISCON_inputs[DISCON_p]
                    DISCON_vals_list[DISCON_p].append(DISCON_vals)
                for inp_ind, inp_p in enumerate(input_params):
                    tuning_inputs[inp_p].append(tuning_params[inp_ind])
        # Write case_inputs
        for DISCON_p in DISCON_params:
            case_inputs[('DISCON_in', DISCON_p)] = {
                'vals': DISCON_vals_list[DISCON_p],
                'group': group
            }

        return case_inputs, tuning_inputs
示例#4
0
def run_PC_sweep(omega, zeta=1.0):
    # Process inputs, single (omega, zeta) or multiple?

    # Turbine inputs
    iec = CaseGen_IEC()
    iec.Turbine_Class = 'I'  # Wind class I, II, III, IV
    iec.Turbulence_Class = 'B'  # Turbulence class 'A', 'B', or 'C'
    iec.D = 240.  # Rotor diameter to size the wind grid
    iec.z_hub = 150.  # Hub height to size the wind grid
    cut_in = 3.  # Cut in wind speed
    cut_out = 25.  # Cut out wind speed
    n_ws = 3  # Number of wind speed bins
    TMax = 800.  # Length of wind grids and OpenFAST simulations, suggested 720 s
    Vrated = 10.59  # Rated wind speed
    Ttrans = max([
        0., TMax - 60.
    ])  # Start of the transient for DLC with a transient, e.g. DLC 1.4
    TStart = max([0., TMax - 600.
                  ])  # Start of the recording of the channels of OpenFAST
    iec.cores = 1
    iec.overwrite = False

    # Initial conditions to start the OpenFAST runs
    u_ref = np.arange(3., 26.)  # Wind speed
    pitch_ref = [
        0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5058525323662666,
        5.253759185225932, 7.50413344606208, 9.310153958810268,
        10.8972969450052, 12.412247669440042, 13.883219268525659,
        15.252012626933068, 16.53735488246438, 17.76456777500061,
        18.953261878035104, 20.11055307762722, 21.238680277668898,
        22.30705111326602, 23.455462501156205
    ]  # Pitch values in deg
    omega_ref = [
        2.019140272160114, 2.8047214918577925, 3.594541645994511,
        4.359025795823625, 5.1123509774611025, 5.855691196288371,
        6.589281196735111, 7.312788026081227, 7.514186181824161,
        7.54665511646938, 7.573823812448151, 7.600476033113538,
        7.630243938880304, 7.638301051122195, 7.622050377183605,
        7.612285710588359, 7.60743945212863, 7.605865650155881,
        7.605792924227456, 7.6062185247519825, 7.607153933765292,
        7.613179734210654, 7.606737845170748
    ]  # Rotor speeds in rpm
    iec.init_cond = {}
    iec.init_cond[("ElastoDyn", "RotSpeed")] = {'U': u_ref}
    iec.init_cond[("ElastoDyn", "RotSpeed")]['val'] = omega_ref
    iec.init_cond[("ElastoDyn", "BlPitch1")] = {'U': u_ref}
    iec.init_cond[("ElastoDyn", "BlPitch1")]['val'] = pitch_ref
    iec.init_cond[("ElastoDyn", "BlPitch2")] = iec.init_cond[("ElastoDyn",
                                                              "BlPitch1")]
    iec.init_cond[("ElastoDyn", "BlPitch3")] = iec.init_cond[("ElastoDyn",
                                                              "BlPitch1")]
    iec.init_cond[("HydroDyn", "WaveHs")] = {
        'U': [3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 40, 50]
    }
    iec.init_cond[("HydroDyn", "WaveHs")]['val'] = [
        1.101917033, 1.101917033, 1.179052649, 1.315715154, 1.536867124,
        1.835816514, 2.187994638, 2.598127096, 3.061304068, 3.617035443,
        4.027470219, 4.51580671, 4.51580671, 6.98, 10.7
    ]
    iec.init_cond[("HydroDyn", "WaveTp")] = {
        'U': [3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 40, 50]
    }
    iec.init_cond[("HydroDyn", "WaveTp")]['val'] = [
        8.515382435, 8.515382435, 8.310063688, 8.006300889, 7.6514231,
        7.440581338, 7.460834063, 7.643300307, 8.046899942, 8.521314105,
        8.987021024, 9.451641026, 9.451641026, 11.7, 14.2
    ]
    iec.init_cond[("HydroDyn", "PtfmSurge")] = {'U': [3., 15., 25.]}
    iec.init_cond[("HydroDyn", "PtfmSurge")]['val'] = [4., 15., 10.]
    iec.init_cond[("HydroDyn", "PtfmPitch")] = {'U': [3., 15., 25.]}
    iec.init_cond[("HydroDyn", "PtfmPitch")]['val'] = [-1., 3., 1.3]
    iec.init_cond[("HydroDyn", "PtfmHeave")] = {'U': [3., 25.]}
    iec.init_cond[("HydroDyn", "PtfmHeave")]['val'] = [0.5, 0.5]

    # DLC inputs
    if False:
        wind_speeds = np.linspace(int(cut_in), int(cut_out), int(n_ws))
        iec.dlc_inputs = {}
        iec.dlc_inputs['DLC'] = [1.1, 1.3, 1.4, 1.5, 5.1, 6.1, 6.3]
        iec.dlc_inputs['U'] = [
            wind_speeds, wind_speeds, [Vrated - 2., Vrated, Vrated + 2.],
            wind_speeds, [Vrated - 2., Vrated, Vrated + 2., cut_out], [], []
        ]
        iec.dlc_inputs['Seeds'] = [[1], [1], [], [], [1], [1], [1]]
        # iec.dlc_inputs['Seeds'] = [range(1,7), range(1,7),[],[], range(1,7), range(1,7), range(1,7)]
        iec.dlc_inputs['Yaw'] = [[], [], [], [], [], [], []]
    else:
        wind_speeds = [18]
        iec.dlc_inputs = {}
        iec.dlc_inputs['DLC'] = [1.1]
        iec.dlc_inputs['U'] = [wind_speeds]
        iec.dlc_inputs['Seeds'] = [[1]]
        # iec.dlc_inputs['Seeds'] = [range(1,7), range(1,7),[],[], range(1,7), range(1,7), range(1,7)]
        iec.dlc_inputs['Yaw'] = [[]]

    iec.PC_MaxRat = 2.
    iec.TStart = Ttrans
    iec.TMax = TMax  # wind file length
    iec.transient_dir_change = 'both'  # '+','-','both': sign for transient events in EDC, EWS
    iec.transient_shear_orientation = 'both'  # 'v','h','both': vertical or horizontal shear for EWS
    iec.wind_dir = 'outputs/wind'
    # Management of parallelization
    # not using for now, copy from run_DLC.py if needed later
    iec.parallel_windfile_gen = True
    iec.cores = 4

    iec.run_dir = 'outputs/iea15mw/PC_sweep_play'

    # Run case generator / wind file writing
    case_inputs = {}
    case_inputs[("Fst", "TMax")] = {'vals': [TMax], 'group': 0}
    case_inputs[("Fst", "TStart")] = {'vals': [TStart], 'group': 0}
    # case_inputs[("Fst","DT_Out")]            = {'vals':[0.01], 'group':0}  #0.005
    case_inputs[("Fst", "OutFileFmt")] = {'vals': [2], 'group': 0}
    case_inputs[("Fst", "CompHydro")] = {'vals': [1], 'group': 0}
    case_inputs[("Fst", "CompSub")] = {'vals': [0], 'group': 0}
    case_inputs[("InflowWind", "WindType")] = {'vals': [1], 'group': 0}
    case_inputs[("ElastoDyn", "TwFADOF1")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "TwFADOF2")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "TwSSDOF1")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "TwSSDOF2")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "FlapDOF1")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "FlapDOF2")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "EdgeDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "DrTrDOF")] = {'vals': ["False"], 'group': 0}
    case_inputs[("ElastoDyn", "GenDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "YawDOF")] = {'vals': ["False"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmSgDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmSwDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmHvDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmRDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmPDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ElastoDyn", "PtfmYDOF")] = {'vals': ["True"], 'group': 0}
    case_inputs[("ServoDyn", "PCMode")] = {'vals': [5], 'group': 0}
    case_inputs[("ServoDyn", "VSContrl")] = {'vals': [5], 'group': 0}
    run_dir1 = os.path.dirname(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) + os.sep
    if platform.system() == 'Windows':
        path2dll = os.path.join(run_dir1, 'local/lib/libdiscon.dll')
    elif platform.system() == 'Darwin':
        path2dll = os.path.join(run_dir1, 'local/lib/libdiscon.dylib')
    else:
        path2dll = os.path.join(run_dir1, 'local/lib/libdiscon.so')

    case_inputs[("ServoDyn", "DLL_FileName")] = {
        'vals': [path2dll],
        'group': 0
    }
    case_inputs[("AeroDyn15", "TwrAero")] = {'vals': ["True"], 'group': 0}
    case_inputs[("AeroDyn15", "TwrPotent")] = {'vals': [1], 'group': 0}
    case_inputs[("AeroDyn15", "TwrShadow")] = {'vals': [1], 'group': 0}
    case_inputs[("HydroDyn", "WaveMod")] = {'vals': [2], 'group': 0}
    case_inputs[("HydroDyn", "WvDiffQTF")] = {'vals': ["False"], 'group': 0}
    channels = {}
    for var in [
            "TipDxc1", "TipDyc1", "TipDzc1", "TipDxb1", "TipDyb1", "TipDxc2",
            "TipDyc2", "TipDzc2", "TipDxb2", "TipDyb2", "TipDxc3", "TipDyc3",
            "TipDzc3", "TipDxb3", "TipDyb3", "RootMxc1", "RootMyc1",
            "RootMzc1", "RootMxb1", "RootMyb1", "RootMxc2", "RootMyc2",
            "RootMzc2", "RootMxb2", "RootMyb2", "RootMxc3", "RootMyc3",
            "RootMzc3", "RootMxb3", "RootMyb3", "TwrBsMxt", "TwrBsMyt",
            "TwrBsMzt", "GenPwr", "GenTq", "RotThrust", "RtAeroCp", "RtAeroCt",
            "RotSpeed", "BldPitch1", "TTDspSS", "TTDspFA", "NacYaw",
            "Wind1VelX", "Wind1VelY", "Wind1VelZ", "LSSTipMxa", "LSSTipMya",
            "LSSTipMza", "LSSTipMxs", "LSSTipMys", "LSSTipMzs", "LSShftFys",
            "LSShftFzs", "TipRDxr", "TipRDyr", "TipRDzr"
    ]:
        channels[var] = True

    # mass sweep
    # case_inputs[("ElastoDyn","PtfmMass")] = {'vals': (1.7838E+07*np.array([.7,.8,.9,1,1.1,1.2,1.3])).tolist(), 'group':3}
    # case_inputs[("ElastoDyn","PtfmRIner")] = {'vals':(1.2507E+10*np.array([.7,.8,.9,1,1.1,1.2,1.3])).tolist(), 'group':3}
    # case_inputs[("ElastoDyn","PtfmPIner")] = {'vals':(1.2507E+10*np.array([.7,.8,.9,1,1.1,1.2,1.3])).tolist(), 'group':3}
    # case_inputs[("ElastoDyn","PtfmYIner")] = {'vals':(2.3667E+10*np.array([.7,.8,.9,1,1.1,1.2,1.3])).tolist(), 'group':3}

    # controller params

    # load default params
    print('here')
    rt_dir = os.path.join(
        os.path.dirname(
            os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
        'ROSCO_toolbox')
    rt_dir = '/Users/dzalkind/Tools/ROSCO_toolbox'
    weis_dir = os.path.join(rt_dir, 'Tune_Cases')
    control_param_yaml = os.path.join(rt_dir, 'Tune_Cases', 'IEA15MW.yaml')
    inps = yaml.safe_load(open(control_param_yaml))
    path_params = inps['path_params']
    turbine_params = inps['turbine_params']
    controller_params = inps['controller_params']

    # make default controller, turbine objects for ROSCO_toolbox
    turbine = ROSCO_turbine.Turbine(turbine_params)
    turbine.load_from_fast(path_params['FAST_InputFile'],
                           os.path.join(rt_dir, path_params['FAST_directory']),
                           dev_branch=True)

    controller = ROSCO_controller.Controller(controller_params)

    # tune default controller
    controller.tune_controller(turbine)

    # check if inputs are lists
    if not isinstance(omega, list):
        omega = [omega]
    if not isinstance(zeta, list):
        zeta = [zeta]

    # Loop through and make PI gains
    pc_kp = []
    pc_ki = []
    omega_zeta = []  # flattened (omega,zeta) pairs
    for o in omega:
        for z in zeta:
            controller.omega_pc = o
            controller.zeta_pc = z
            controller.tune_controller(turbine)
            pc_kp.append(controller.pc_gain_schedule.Kp.tolist())
            pc_ki.append(controller.pc_gain_schedule.Ki.tolist())
            omega_zeta.append((o, z))

    # add control gains to case_list
    case_inputs[('DISCON_in', 'PC_GS_KP')] = {'vals': pc_kp, 'group': 3}
    case_inputs[('DISCON_in', 'PC_GS_KI')] = {'vals': pc_ki, 'group': 3}

    iec.case_name_base = 'pc_play'

    # generate cases
    case_list, case_name_list, dlc_list = iec.execute(case_inputs=case_inputs)

    #for var in var_out+[var_x]:

    # Run FAST cases
    fastBatch = runFAST_pywrapper_batch(FAST_ver='OpenFAST', dev_branch=True)

    # Monopile
    # fastBatch.FAST_InputFile    = 'IEA-15-240-RWT-Monopile.fst'   # FAST input file (ext=.fst)
    # run_dir2                    = os.path.dirname( os.path.dirname( os.path.realpath(__file__) ) ) + os.sep
    # fastBatch.FAST_directory    = os.path.join(run_dir2, 'OpenFAST_models/IEA-15-240-RWT/IEA-15-240-RWT-Monopile')   # Path to fst directory files
    fastBatch.channels = channels
    # fastBatch.FAST_runDirectory = iec.run_dir
    fastBatch.case_list = case_list
    fastBatch.case_name_list = case_name_list
    fastBatch.debug_level = 2

    # if MPI:
    #     fastBatch.run_mpi(comm_map_down)
    # else:
    #     fastBatch.run_serial()

    # U-Maine semi-sub
    fastBatch.FAST_InputFile = 'IEA-15-240-RWT-UMaineSemi.fst'  # FAST input file (ext=.fst)
    run_dir2 = os.path.dirname(os.path.realpath(__file__)) + os.sep
    fastBatch.FAST_directory = os.path.join(
        run_dir2, 'OpenFAST_models', 'IEA-15-240-RWT',
        'IEA-15-240-RWT-UMaineSemi')  # Path to fst directory files
    fastBatch.FAST_runDirectory = iec.run_dir
    if True:
        fastBatch.run_multi(cores=4)
    else:
        fastBatch.run_serial()
            os.path.dirname(os.path.realpath(__file__)),
            'OpenFAST_executables', 'openfast_x64.exe')
elif platform.system() == 'Darwin':
    openfast_call = 'openfast'

# Load yaml file
parameter_filename = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                  'BAR_00', 'ServoData', 'BAR_00.yaml')
inps = yaml.safe_load(open(parameter_filename))
path_params = inps['path_params']
turbine_params = inps['turbine_params']
controller_params = inps['controller_params']

# Instantiate turbine, controller, and file processing classes
turb = turbine.Turbine(turbine_params)
cont = controller.Controller(controller_params)
file_processing = utilities.FileProcessing()
fast_io = utilities.FAST_IO()

# Load turbine data from OpenFAST and rotor performance text file
turb.load_from_fast(path_params['FAST_InputFile'],
                    path_params['FAST_directory'],
                    dev_branch=True)

# Tune controller
cont.tune_controller(turb)

# Write parameter input file
param_filename = 'OpenFAST_BAR_00_DISCON.IN'
param_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          'BAR_00', param_filename)