Пример #1
0
def initialize_problem(Analysis_Level):
    
    # Initialize blade design
    refBlade = ReferenceBlade()
    refBlade.verbose  = True
    refBlade.NINPUT       = 200
    Nsection_Tow          = 19
    refBlade.NPTS         = 200
    refBlade.spar_var     = ['Spar_cap_ss', 'Spar_cap_ps'] # SS, then PS
    refBlade.te_var       = 'TE_reinforcement'
    refBlade.validate     = False
    refBlade.fname_schema = fname_schema
    blade = refBlade.initialize(fname_input)
    
    FASTpref                        = {}
    FASTpref['Analysis_Level']      = Analysis_Level
    # Set FAST Inputs
    if Analysis_Level >= 1:
        # File management
        FASTpref['FAST_ver']            = 'OpenFAST'
        FASTpref['dev_branch']          = True
        FASTpref['FAST_exe']            = '~/local/bin/openfast'
        FASTpref['FAST_directory']      = '../OpenFAST'   # Path to fst directory files
        FASTpref['FAST_InputFile']      = 'IEA-15-240-RWT.fst' # FAST input file (ext=.fst)
        FASTpref['Turbsim_exe']         = '~/local/bin/turbsim'
        FASTpref['FAST_namingOut']      = 'IEA-15-240-RWT'
        FASTpref['FAST_runDirectory']   = 'temp/' + FASTpref['FAST_namingOut']
        
        # Run Settings
        FASTpref['cores']               = 1
        FASTpref['debug_level']         = 2 # verbosity: set to 0 for quiet, 1 & 2 for increasing levels of output

        # DLCs
        FASTpref['DLC_gust']            = None      # Max deflection
        # FASTpref['DLC_gust']            = RotorSE_DLC_1_4_Rated       # Max deflection    ### Not in place yet
        FASTpref['DLC_extrm']           = None      # Max strain
        # FASTpref['DLC_extrm']           = RotorSE_DLC_7_1_Steady      # Max strain        ### Not in place yet
        FASTpref['DLC_turbulent']       = None
        # FASTpref['DLC_turbulent']       = RotorSE_DLC_1_1_Turb      # Alternate turbulent case, replacing rated and extreme DLCs for calculating max deflection and strain
        FASTpref['DLC_powercurve']      = None      # AEP
        # FASTpref['DLC_powercurve']      = None      # AEP

        # Initialize, read initial FAST files to avoid doing it iteratively
        fast = InputReader_OpenFAST(FAST_ver=FASTpref['FAST_ver'], dev_branch=FASTpref['dev_branch'])
        fast.FAST_InputFile = FASTpref['FAST_InputFile']
        fast.FAST_directory = FASTpref['FAST_directory']
        fast.execute()
        fst_vt = fast.fst_vt
    else:
        fst_vt = {}

    prob = om.Problem()
    prob.model=MonopileTurbine(RefBlade=blade, Nsection_Tow=Nsection_Tow, VerbosityCosts=False, FASTpref=FASTpref)
    prob.model.nonlinear_solver = om.NonlinearRunOnce()
    prob.model.linear_solver    = om.DirectSolver()

    return prob, blade, fst_vt
Пример #2
0
    )  #TURBINE_CLASS['I']  # (Enum): IEC turbine class

    return rotor


if __name__ == "__main__":

    # Turbine Ontology input
    fname_input = "turbine_inputs/nrel5mw_mod_update.yaml"

    # Initialize blade design
    refBlade = ReferenceBlade()
    refBlade.verbose = True
    refBlade.NINPUT = NINPUT
    refBlade.NPITS = 50
    refBlade.validate = False
    refBlade.fname_schema = "turbine_inputs/IEAontology_schema.yaml"

    refBlade.spar_var = ['Spar_Cap_SS', 'Spar_Cap_PS']
    refBlade.te_var = 'TE_reinforcement'
    blade = refBlade.initialize(fname_input)

    # setup
    rotor = Problem()
    rotor.model = RotorGeometry(RefBlade=blade, topLevelFlag=True)
    rotor.setup()
    rotor = Init_RotorGeometry_wRefBlade(rotor, blade)
    rotor.run_driver()

    print(rotor['total_blade_cost'])
Пример #3
0
def run_problem(optFlag=False, prob_ref=None):

    # Initialize blade design
    refBlade = ReferenceBlade()
    if rank == 0:
        refBlade.verbose = True
    else:
        refBlade.verbose = False
    refBlade.NINPUT = 8
    Nsection_Tow = 19
    refBlade.NPTS = 30
    refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps']  # SS, then PS
    refBlade.te_var = 'TE_reinforcement'
    refBlade.le_var = 'le_reinf'
    refBlade.validate = False
    refBlade.fname_schema = fname_schema
    blade = refBlade.initialize(fname_input)

    Analysis_Level = 0
    FASTpref = {}
    FASTpref['Analysis_Level'] = Analysis_Level
    fst_vt = {}

    # Initialize and execute OpenMDAO problem with input data
    if MPI:
        num_par_fd = MPI.COMM_WORLD.Get_size()
        prob = om.Problem(model=om.Group(num_par_fd=num_par_fd))
        prob.model.approx_totals(method='fd')
        prob.model.add_subsystem('comp',
                                 Optimize_MonopileTurbine(
                                     RefBlade=blade,
                                     Nsection_Tow=Nsection_Tow,
                                     folder_output=folder_output),
                                 promotes=['*'])
    else:
        prob = om.Problem()
        prob.model = Optimize_MonopileTurbine(RefBlade=blade,
                                              Nsection_Tow=Nsection_Tow,
                                              folder_output=folder_output)

    prob.model.nonlinear_solver = om.NonlinearRunOnce()
    prob.model.linear_solver = om.DirectSolver()

    if optFlag and not prob_ref is None:
        if MPI:
            num_par_fd = MPI.COMM_WORLD.Get_size()
            prob = om.Problem(model=om.Group(num_par_fd=num_par_fd))
            prob.model.approx_totals(method='fd')
            prob.model.add_subsystem('comp',
                                     Optimize_MonopileTurbine(
                                         RefBlade=blade,
                                         Nsection_Tow=Nsection_Tow,
                                         folder_output=folder_output),
                                     promotes=['*'])
        else:
            prob = om.Problem()
            prob.model = Optimize_MonopileTurbine(RefBlade=blade,
                                                  Nsection_Tow=Nsection_Tow,
                                                  folder_output=folder_output)

        # --- Driver ---
        prob.driver = om.pyOptSparseDriver()
        prob.driver.options['optimizer'] = 'CONMIN'
        prob.driver.opt_settings['ITMAX'] = 15
        prob.driver.opt_settings['IPRINT'] = 4
        # ----------------------

        # --- Objective ---
        # prob.model.add_objective('lcoe')
        prob.model.add_objective('AEP', scaler=-1.)
        #prob.model.add_objective('mass_one_blade')
        # ----------------------

        # --- Design Variables ---
        indices_no_root = range(2, refBlade.NINPUT)
        indices_no_root_no_tip = range(2, refBlade.NINPUT - 1)
        indices_no_max_chord = range(3, refBlade.NINPUT)
        prob.model.add_design_var('sparT_in',
                                  indices=indices_no_root_no_tip,
                                  lower=0.001,
                                  upper=0.200)
        prob.model.add_design_var('chord_in',
                                  indices=indices_no_max_chord,
                                  lower=0.5,
                                  upper=7.0)
        prob.model.add_design_var('theta_in',
                                  indices=indices_no_root,
                                  lower=-7.5,
                                  upper=20.0)
        prob.model.add_design_var('teT_in',
                                  lower=prob_ref['teT_in'] * 0.5,
                                  upper=0.1)
        #prob.model.add_design_var('leT_in', lower=prob_ref['leT_in']*0.5, upper=0.1)
        # ----------------------

        # --- Constraints ---
        prob.model.add_subsystem('freq_check',
                                 blade_freq_check(),
                                 promotes=['freq_check_out'])
        prob.model.connect('freq_curvefem',
                           'freq_check.freq_curvefem')  #, src_indices=[0])

        # Rotor
        prob.model.add_constraint('tip_deflection_ratio', upper=1.0)
        # prob.model.add_constraint('no_stall_constraint',      upper=1.0)
        prob.model.add_constraint('freq_check_out', lower=1.1)
        #prob.model.add_constraint('rated_Q',     lower=21.4e6, upper=21.6e6)
        # prob.model.add_constraint('mass_one_blade',           upper=prob_ref['mass_one_blade']*1.02)
        prob.model.add_constraint('AEP', lower=0.99 * prob_ref['AEP'])
        # ----------------------

        # --- Recorder ---
        filename_opt_log = folder_output + 'log_opt_' + blade['config']['name']

        prob.driver.add_recorder(om.SqliteRecorder(filename_opt_log))
        prob.driver.recording_options['includes'] = [
            'AEP', 'total_blade_cost', 'lcoe', 'tip_deflection_ratio',
            'mass_one_blade', 'theta_in'
        ]
        prob.driver.recording_options['record_objectives'] = True
        prob.driver.recording_options['record_constraints'] = True
        prob.driver.recording_options['record_desvars'] = True
        # ----------------------

    # Initialize variable inputs
    prob = initialize_variables(prob, blade, Analysis_Level, fst_vt)

    # Run initial condition no matter what
    print('Running at Initial Position:')
    prob.run_model()

    print('########################################')
    print('')
    print('Control variables')
    print('Rotor diam:    {:8.3f} m'.format(prob['diameter'][0]))
    print('TSR:           {:8.3f} -'.format(prob['control_tsr'][0]))
    print('Rated vel:     {:8.3f} m/s'.format(prob['rated_V'][0]))
    print('Rated rpm:     {:8.3f} rpm'.format(prob['rated_Omega'][0]))
    print('Rated pitch:   {:8.3f} deg'.format(prob['rated_pitch'][0]))
    print('Rated thrust:  {:8.3f} N'.format(prob['rated_T'][0]))
    print('Rated torque:  {:8.3f} N-m'.format(prob['rated_Q'][0]))
    print('')
    print('Constraints')
    print('Max TD:       {:8.3f} m'.format(prob['tip_deflection'][0]))
    print('TD ratio:     {:8.3f} -'.format(prob['tip_deflection_ratio'][0]))
    print('Blade root M: {:8.3f} N-m'.format(prob['root_bending_moment'][0]))
    print('')
    print('Objectives')
    print('AEP:         {:8.3f} GWh'.format(prob['AEP'][0]))
    print('LCoE:        {:8.4f} $/MWh'.format(prob['lcoe'][0]))
    print('')
    print('Blades')
    print('Blade mass:  {:8.3f} kg'.format(prob['mass_one_blade'][0]))
    print('Blade cost:  {:8.3f} $'.format(prob['total_blade_cost'][0]))
    print('Blade freq:  {:8.3f} Hz'.format(prob['freq_curvefem'][0]))
    print('3 blade M_of_I:  ', prob['I_all_blades'], ' kg-m^2')
    print('Hub M:  ', prob['Mxyz_total'], ' kg-m^2')
    print('')
    print('RNA Summary')
    print('RNA mass:    {:8.3f} kg'.format(prob['tow.pre.mass'][0]))
    print('RNA C_of_G (TT):  ', prob['rna_cg'], ' m')
    print('RNA M_of_I:  ', prob['tow.pre.mI'], ' kg-m^2')
    print('')
    print('Tower')
    print('Tower top F: ', prob['tow.pre.rna_F'], ' N')
    print('Tower top M: ', prob['tow.pre.rna_M'], ' N-m')
    print('Tower freqs: ', prob['tow.post.structural_frequencies'], ' Hz')
    print('Tower vel:   {:8.3f} kg'.format(prob['tow.wind.Uref'][0]))
    print('Tower mass:  {:8.3f} kg'.format(prob['tower_mass'][0]))
    print('Tower cost:  {:8.3f} $'.format(prob['tower_cost'][0]))
    print('########################################')

    # Angle of attack and stall angle
    faoa, axaoa = plt.subplots(1, 1, figsize=(5.3, 4))
    axaoa.plot(prob['r'],
               prob['nostallconstraint.aoa_along_span'],
               label='Initial aoa')
    axaoa.plot(prob['r'],
               prob['nostallconstraint.stall_angle_along_span'],
               '.',
               label='Initial stall')
    axaoa.legend(fontsize=12)
    plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold')
    plt.ylabel('Angle [deg]', fontsize=14, fontweight='bold')
    plt.xticks(fontsize=12)
    plt.yticks(fontsize=12)
    plt.grid(color=[0.8, 0.8, 0.8], linestyle='--')
    plt.subplots_adjust(bottom=0.15, left=0.15)
    fig_name = 'aoa.png'
    faoa.savefig(folder_output + fig_name)

    # Complete data dump
    #prob.model.list_inputs(units=True)
    #prob.model.list_outputs(units=True)

    if optFlag:
        if rank == 0:
            print('Running Optimization:')
            print('N design var: ',
                  2 * len(indices_no_root_no_tip) + len(indices_no_root) + 1)
        if not MPI:
            prob.model.approx_totals()
        prob.run_driver()

        if rank == 0:
            # --- Save output .yaml ---
            refBlade.write_ontology(fname_output, prob['blade_out'],
                                    refBlade.wt_ref)

            # --- Outputs plotting ---
            print('AEP:         \t\t\t %f\t%f GWh \t Difference: %f %%' %
                  (prob_ref['AEP'] * 1e-6, prob['AEP'] * 1e-6,
                   (prob['AEP'] - prob_ref['AEP']) / prob_ref['AEP'] * 100.))
            print(
                'LCoE:        \t\t\t %f\t%f USD/MWh \t Difference: %f %%' %
                (prob_ref['lcoe'] * 1.e003, prob['lcoe'] * 1.e003,
                 (prob['lcoe'] - prob_ref['lcoe']) / prob_ref['lcoe'] * 100.))
            print('Blade cost:  \t\t\t %f\t%f USD \t Difference: %f %%' %
                  (prob_ref['total_blade_cost'], prob['total_blade_cost'],
                   (prob['total_blade_cost'] - prob_ref['total_blade_cost']) /
                   prob_ref['total_blade_cost'] * 100.))
            print('Blade mass:  \t\t\t %f\t%f kg  \t Difference: %f %%' %
                  (prob_ref['total_blade_mass'], prob['total_blade_mass'],
                   (prob['total_blade_mass'] - prob_ref['total_blade_mass']) /
                   prob_ref['total_blade_mass'] * 100.))
            print('Tower cost:  \t\t\t %f\t%f USD \t Difference: %f %%' %
                  (prob_ref['tower_cost'], prob['tower_cost'],
                   (prob['tower_cost'] - prob_ref['tower_cost']) /
                   prob_ref['tower_cost'] * 100.))
            print('Tower mass:  \t\t\t %f\t%f kg  \t Difference: %f %%' %
                  (prob_ref['tower_mass'], prob['tower_mass'],
                   (prob['tower_mass'] - prob_ref['tower_mass']) /
                   prob_ref['tower_mass'] * 100.))
            # ----------------------

            # Theta
            ft, axt = plt.subplots(1, 1, figsize=(5.3, 4))
            axt.plot(prob_ref['r'], prob_ref['theta'], label='Initial')
            axt.plot(prob_ref['r_in'], prob_ref['theta_in'], '.')
            axt.plot(prob['r'], prob['theta'], label='Optimized')
            axt.plot(prob['r_in'], prob['theta_in'], '.')
            axt.legend(fontsize=12)
            plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold')
            plt.ylabel('Twist [deg]', fontsize=14, fontweight='bold')
            plt.xticks(fontsize=12)
            plt.yticks(fontsize=12)
            plt.grid(color=[0.8, 0.8, 0.8], linestyle='--')
            plt.subplots_adjust(bottom=0.15, left=0.15)
            fig_name = 'theta.png'
            ft.savefig(folder_output + fig_name)

            # Angle of attack and stall angle
            faoa, axaoa = plt.subplots(1, 1, figsize=(5.3, 4))
            axaoa.plot(prob_ref['r'],
                       prob_ref['nostallconstraint.aoa_along_span'],
                       label='Initial aoa')
            axaoa.plot(prob_ref['r'],
                       prob_ref['nostallconstraint.stall_angle_along_span'],
                       '.',
                       label='Initial stall')
            axaoa.plot(prob['r'],
                       prob['nostallconstraint.aoa_along_span'],
                       label='Optimized aoa')
            axaoa.plot(prob['r'],
                       prob['nostallconstraint.stall_angle_along_span'],
                       '.',
                       label='Optimized stall')
            axaoa.legend(fontsize=12)
            plt.xlabel('Blade Span [m]', fontsize=14, fontweight='bold')
            plt.ylabel('Angle [deg]', fontsize=14, fontweight='bold')
            plt.xticks(fontsize=12)
            plt.yticks(fontsize=12)
            plt.grid(color=[0.8, 0.8, 0.8], linestyle='--')
            plt.subplots_adjust(bottom=0.15, left=0.15)
            fig_name = 'aoa.png'
            ft.savefig(folder_output + fig_name)

            plt.show()

    return prob, blade
Пример #4
0
    def testAssembly(self):
        # Global inputs and outputs
        fname_schema = mydir + os.sep + 'IEAontology_schema.yaml'
        fname_input = mydir + os.sep + 'IEA-15-240-RWT.yaml'

        # Initialize blade design
        refBlade = ReferenceBlade()
        refBlade.verbose = True
        refBlade.NINPUT = 8
        Nsection_Tow = 19
        refBlade.NPTS = 30
        refBlade.spar_var = ['Spar_cap_ss', 'Spar_cap_ps']  # SS, then PS
        refBlade.te_var = 'TE_reinforcement'
        refBlade.validate = False
        refBlade.fname_schema = fname_schema
        blade = refBlade.initialize(fname_input)
        Analysis_Level = 0

        FASTpref = {}
        FASTpref['Analysis_Level'] = Analysis_Level
        fst_vt = {}

        prob = om.Problem()
        prob.model = MonopileTurbine(RefBlade=blade,
                                     Nsection_Tow=Nsection_Tow,
                                     VerbosityCosts=False,
                                     FASTpref=FASTpref)
        prob.model.nonlinear_solver = om.NonlinearRunOnce()
        prob.model.linear_solver = om.DirectSolver()
        prob.setup()

        prob = Init_RotorSE_wRefBlade(prob,
                                      blade,
                                      Analysis_Level=Analysis_Level,
                                      fst_vt=fst_vt)

        # Environmental parameters for the tower
        prob['significant_wave_height'] = 4.52
        prob['significant_wave_period'] = 9.45
        prob['water_depth'] = 30.
        prob['wind_reference_height'] = prob['hub_height'] = 150.
        prob['shearExp'] = 0.11
        prob['rho'] = 1.225
        prob['mu'] = 1.7934e-5
        prob['water_density'] = 1025.0
        prob['water_viscosity'] = 1.3351e-3
        prob['wind_beta'] = prob['wave_beta'] = 0.0

        # Steel properties for the tower
        prob['material_density'] = 7850.0
        prob['E'] = 210e9
        prob['G'] = 79.3e9
        prob['yield_stress'] = 345e6
        prob['soil_G'] = 140e6
        prob['soil_nu'] = 0.4

        # Design constraints
        prob['max_taper_ratio'] = 0.4
        prob['min_diameter_thickness_ratio'] = 120.0

        # Safety factors
        prob['gamma_fatigue'] = 1.755  # (Float): safety factor for fatigue
        prob['gamma_f'] = 1.35  # (Float): safety factor for loads/stresses
        prob['gamma_m'] = 1.3  # (Float): safety factor for materials
        prob[
            'gamma_freq'] = 1.1  # (Float): safety factor for resonant frequencies
        prob['gamma_n'] = 1.0
        prob['gamma_b'] = 1.1

        # Tower
        prob['tower_buckling_length'] = 30.0
        prob['tower_outfitting_factor'] = 1.07
        prob['foundation_height'] = -30.
        prob['suctionpile_depth'] = 45.
        prob['tower_section_height'] = np.array([
            5., 5., 5., 5., 5., 5., 5., 5., 5., 13., 13., 13., 13., 13., 13.,
            13., 13., 13., 12.58244309
        ])
        prob['tower_outer_diameter'] = np.array([
            10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 10., 9.92647687,
            9.44319282, 8.83283769, 8.15148167, 7.38976138, 6.90908962,
            6.74803581, 6.57231775, 6.5
        ])
        prob['tower_wall_thickness'] = np.array([
            0.05534138, 0.05344902, 0.05150928, 0.04952705, 0.04751736,
            0.04551709, 0.0435267, 0.04224176, 0.04105759, 0.0394965,
            0.03645589, 0.03377851, 0.03219233, 0.03070819, 0.02910109,
            0.02721289, 0.02400931, 0.0208264, 0.02399756
        ])
        prob['tower_buckling_length'] = 15.0
        prob['transition_piece_mass'] = 100e3
        prob['transition_piece_height'] = 15.0

        prob['DC'] = 80.0
        prob['shear'] = True
        prob['geom'] = True
        prob['tower_force_discretization'] = 5.0
        prob['nM'] = 2
        prob['Mmethod'] = 1
        prob['lump'] = 0
        prob['tol'] = 1e-9
        prob['shift'] = 0.0

        # Offshore BOS
        prob['wtiv'] = 'example_wtiv'
        prob['feeder'] = 'future_feeder'
        prob['num_feeders'] = 1
        prob['oss_install_vessel'] = 'example_heavy_lift_vessel'
        prob['site_distance'] = 40.0
        prob['site_distance_to_landfall'] = 40.0
        prob['site_distance_to_interconnection'] = 40.0
        prob['plant_turbine_spacing'] = 7
        prob['plant_row_spacing'] = 7
        prob['plant_substation_distance'] = 1
        prob['tower_deck_space'] = 0.
        prob['nacelle_deck_space'] = 0.
        prob['blade_deck_space'] = 0.
        prob['port_cost_per_month'] = 2e6
        prob['monopile_deck_space'] = 0.
        prob['transition_piece_deck_space'] = 0.
        prob['commissioning_pct'] = 0.01
        prob['decommissioning_pct'] = 0.15
        prob['project_lifetime'] = prob['lifetime'] = 20.0
        prob['number_of_turbines'] = 40
        prob['annual_opex'] = 43.56  # $/kW/yr
        #prob['bos_costs']                      = 1234.5 # $/kW

        prob['tower_add_gravity'] = True

        # For turbine costs
        prob['offshore'] = True
        prob['crane'] = False
        prob['bearing_number'] = 2
        prob['crane_cost'] = 0.0
        prob['labor_cost_rate'] = 3.0
        prob['material_cost_rate'] = 2.0
        prob['painting_cost_rate'] = 28.8

        # Drivetrain
        prob['tilt'] = 6.0
        prob['overhang'] = 11.075
        prob['hub_cm'] = np.array([-10.685, 0.0, 5.471])
        prob['nac_cm'] = np.array([-5.718, 0.0, 4.048])
        prob['hub_I'] = np.array(
            [1382171.187, 2169261.099, 2160636.794, 0.0, 0.0, 0.0])
        prob['nac_I'] = np.array(
            [13442265.552, 21116729.439, 18382414.385, 0.0, 0.0, 0.0])
        prob['hub_mass'] = 190e3
        prob['nac_mass'] = 797.275e3 - 190e3
        prob['hss_mass'] = 0.0
        prob['lss_mass'] = 19.504e3
        prob['cover_mass'] = 0.0
        prob['pitch_system_mass'] = 50e3
        prob['platforms_mass'] = 0.0
        prob['spinner_mass'] = 0.0
        prob['transformer_mass'] = 0.0
        prob['vs_electronics_mass'] = 0.0
        prob['yaw_mass'] = 100e3
        prob['gearbox_mass'] = 0.0
        prob['generator_mass'] = 226.7e3 + 145.25e3
        prob['bedplate_mass'] = 39.434e3
        prob['main_bearing_mass'] = 4.699e3

        prob.run_model()
        # Make sure we get here
        self.assertTrue(True)