NREL / reV

Renewable Energy Potential (reV) Model
https://nrel.github.io/reV/
BSD 3-Clause "New" or "Revised" License
107 stars 24 forks source link

Hub Height Differences #440

Closed Zoe-Fehlau-ES closed 9 months ago

Zoe-Fehlau-ES commented 10 months ago

I have a code that I use to obtain wind speed and capacity factor for a specific latitude and longitude using the wind_gen_standard_losses_0.json file. I'm wondering how the results would differ if I use a hub height of 120m instead of the default 80m. Would I need to modify other settings in the wind_gen_standard_losses_0.json file if I change the hub height?

def Get_Gen(Site, resource, year, pp, sam_fp, res_file):
    """
    Generates or retrieves generation data for a specific site.

    Args:
    - Site (str): Name of the site.
    - resource (str): Type of energy resource.
    - year (int): The year for which the data is being generated.
    - pp (ProjectPoints): ProjectPoints object containing site data.
    - sam_fp (str): Path to the SAM file.
    - res_file (str): Path to the resource file.

    Returns:
    - Generation data for the specified site and resource.
    """

    if len(lat_lons)==1:
        lat, long = lat_lons[0][0], lat_lons[0][1]
        if os.path.isfile(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl')==False:            
            print(f'\nGetting {resource} Gen and CF Profile: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
            start_time = time.time()
            output_request = (['cf_profile', 'wind_speed']) if resource=='windpower' else (['cf_profile', 'gen_profile'])
            gen = Gen.reV_run(resource, pp, sam_fp, res_file, max_workers=1, out_fpath=None, output_request=output_request)
            print(f'Excution time: {time.time()-start_time} sec')

            with open(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl', 'wb') as file:
                pickle.dump(gen, file)
            return gen

        else:
            print('\nPulling Gen Data')
            with open(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl', 'rb') as file:
                gen = pickle.load(file)
            return gen
    else:
        GEN = []
        for lat, long in lat_lons:
            if os.path.isfile(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl')==False:
                print(f'\nGetting {resource} Gen and CF Profile: {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}')
                start_time = time.time()
                output_request = (['cf_profile', 'wind_speed']) if resource=='windpower' else (['cf_profile', 'gen_profile'])
                gen = Gen.reV_run(resource, pp, sam_fp, res_file, max_workers=1, out_fpath=None, output_request=output_request)
                print(f'Excution time: {time.time()-start_time} sec')

                with open(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl', 'wb') as file:
                    pickle.dump(gen, file)
                GEN.append(gen)

            else:
                print('\nPulling Gen Data')
                with open(f'_outputs/{resource}/{year} - {Site}/Gen {Site}.pkl', 'rb') as file:
                    gen = pickle.load(file)
                GEN.append(gen)
        return pd.concat(GEN)
ppinchuk commented 10 months ago

Hi, you should be able to change the hub height to 120 in your SAM config file (wind_gen_standard_losses_0.json) to get results at 120m. Is there some sort of issue you are running into if you do that?

You don't need to change any other settings, but keep in mind that reV generation is intended to model the energy generation for a particular technology. A typical workflow, therefore, would try to have the turbine configuration closely resemble some known technology. NREL's System Advisor Model (SAM) has a large library of turbine configurations (i.e. hub height, rotor diameter, rated power, and power curve combinations) that you could explore.

That being said, if you are simply doing some sort of sensitivity analysis and are not as interested in modeling realistic technologies, then hub height should be the only thing you need to change.

Does this help answer your question?

Zoe-Fehlau-ES commented 10 months ago

Thank you for explaining that @ppinchuk. So to make our model as realistic as possible, I need to extract data from SAM and create my own SAM config file, to model a 120m hub height, correct? Is it advisable to use PySAM, instead? How come the results of these two methods differ so much?

This is some code a coworker has used to generate Wind Profiles:

def get_wind_gen(lat, lon, windCap, year=2014, hh=120):

    MY_KEY = f'{key}' #key is global variable

    # Declare url string
    # Note: WKT point is lon/lat https://www.here.com/learn/blog/what-is-a-wkt-file-and-how-to-create-one
    url = f'https://developer.nrel.gov/api/wind-toolkit/v2/wind/wtk-download.csv?api_key={MY_KEY}&wkt=POINT({lon}%20{lat})&names={year}&utc=false&leap_day=false&email=apalomino@energystrat.com&reason=example&affiliation=NREL'

    # Get windspeed
    df = pd.read_csv(url, header=1)[['Year','Month','Day','Hour', f'wind speed at {hh}m (m/s)']] #assume hub height of 120m
    #df.index = pd.to_datetime(dict(year=df.Year, month=df.Month, day=df.Day, hour=df.Hour))
    #df = df[f'wind speed at {hh}m (m/s)']

    # Set the time index in the pandas dataframe:
    df = df.set_index(pd.date_range(f'1/1/{year}', freq='60Min', periods=525600/int(60)))
    # Drop unecessary year, month, day, hour columns
    df = df[f'wind speed at {hh}m (m/s)']

    # NREL Wind Toolkit index = wind speed bin
    speedToGen = pd.DataFrame(index=np.arange(0,25.25,0.25), columns=['Generation (MW)'])
    nrelWindTK = pd.read_excel(r'_data\NREL Validation of WIND Toolkit.xlsx')['IEC Class 3'].to_dict()   
    speedToGen['Generation (MW)'] = speedToGen.index.map(nrelWindTK)
    speedToGen = speedToGen.interpolate()['Generation (MW)'].to_dict()

    #windGen = windCap * df.apply(lambda x: nrelWindTK[np.round(x) if x <= 25 else 1])
    windGen = windCap * df.apply(lambda x: speedToGen[round(x*4)/4] if x <= 25 else 1)
    # Rename series 
    windGen = windGen.rename('Wind MW'); 

    return windGen
ppinchuk commented 10 months ago

Extracting turbine technology configurations from the SAM GUI is likely the easiest way to create the SAM file, but it is not the only option. Other analysists do create SAM files from scratch if they have custom turbine configurations, but in all cases it is recommended to pick a "sensible" technology representation.

PySAM is just a python wrapper around the SAM simulation core, so it probably doesn't actually have access to turbine configurations. I'm not 100% sure about this though, so if you do find a way to do it with PySAM, it should be equivalent and you can totally go for it.

Not sure what you mean by "How come the results of these two methods differ so much"? Can you please elaborate on what you are comparing?

I'm also confused about the relevance of the code excerpts your provided. Please let me know what exactly you are having troubles with, and I'd be happy to take a closer look

Zoe-Fehlau-ES commented 10 months ago

I have been comparing the results of my code and my coworker's code who used PySam instead of reV. We used the same year, hub height, and lat/long, but we got very different wind speeds and generation profiles (about an annual generation difference of 298 GWh). I suspect that the difference is due to the unrealistic nature of the Sam Config file. For reference, my coworker is using the get_wind_gen function in the pySAM.py code and I am using my reV code.py.

Python Code Github.zip

I will try extracting turbine technology configurations from the SAM GUI like you suggested to see if that will fix things.

ppinchuk commented 10 months ago

Hey Zoe, Finding the source of the discrepancy would require some careful debugging. Here are my quick thoughts:

1) Definitely make sure both pieces of code are taking the same input data. You said you verified that the input years are the same and that the location is the same, but it's strange that you are seeing different wind speed outputs. Wind speed should be completely independent of generation and should match for both codes. Verify that the wind speeds you are putting in are the same in both cases.

2) The get_wind_gen code you showed doesn't actually even use PySAM. Instead, it looks like wind speeds are mapped directly to generation values using an "IEC Class 3" turbine mapping from NREL Validation of WIND Toolkit.xlsx. This is almost certainly the source of the discrepancy, since reV (and SAM/PySAM) use a wind turbine power curve to compute generation.

One way you can quickly check the effects of the second point above is to input a "power curve" based on the "IEC Class 3" values into your SAM config. In other words, pull that mapping out of the excel file and put in the wind speeds and output power values into the SAM config. Then run reV and see if you get values closer to the other code. It won't be perfect since reV/SAM/PySAM take air pressure and temperature into account, but it will probably get you pretty close.

Hope that helps

ppinchuk commented 10 months ago

Looks like the SAM GUI has a "Composite IEC Class 3" Turbine power curve. Might be easiest to pull the config for this turbine and do a quick check to make sure the power curve matches the data in NREL Validation of WIND Toolkit.xlsx, and then run it through reV.

image

Zoe-Fehlau-ES commented 10 months ago

I really appreciate your help @ppinchuk . I'll make sure to have a chat with my colleague about their code and also take a look at the PySAM examples myself. Additionally, I plan to download and play around with the SAM GUI. Thanks for providing these insights.

Zoe-Fehlau-ES commented 10 months ago

Hey @ppinchuk, I was able to download the SAM GUI and find the Turbine Power Curves for a specific turbine. However, now my question is about the amount of turbine technology configurations that I can extract from the JSON file using the GUI. Specifically, I'm curious if I can extract the wind_farm_losses_percent or if it's only possible to get the power curve and hub height information. Can I obtain the wind farm losses percentage from the Losses tab if I model the wind farm more comprehensively, including the Wind Resource and Wind Farm tabs? Sorry for my lack of knowledge. image

ppinchuk commented 10 months ago

Hey Zoe, You can totally use the "Losses" tab in SAM to set up your turbine losses. In fact, you can use the GUI for all of your turbine specs. First, fill out all the input fields the way you want them in all the tabs (basically get to the point right before you would hit "Simulate"). Then, click on the downward-facing arrow next to the project name at the top ("untitled" by default), go all the way down to "Generate Code...", and then select "PySAM JSON" at the very bottom. This will export several files, one of which will be called "*_windpower.json". You will need to remove the "wind_resource_filename" and "wind_resource_distribution" keys from that config file, but otherwise you can use it directly as the SAM config input to reV (maybe also make sure "wind_resource_model_choice" is set to 0).

Let me know if you run into any issues

ppinchuk commented 10 months ago

P.S. reV generation typically models a single turbine (we use reV bespoke or reV supply-curve-aggregation for modeling wind farms), so if you want your results to most closely match how you have been running reV up to this point, I would recommend selecting the "Use a single turbine" option in the "Wind Farm" tab:

image

That being said, if you really do want to model a turbine layout you can... just be aware that results will look different than what you would have gotten out of reV up until this point

Zoe-Fehlau-ES commented 9 months ago

Sorry for never responding. Thank you so much for your help @ppinchuk