NREL / floris

A controls-oriented engineering wake model.
http://nrel.github.io/floris
BSD 3-Clause "New" or "Revised" License
203 stars 154 forks source link

Consolidate turbine libraries #345

Open rafmudaf opened 2 years ago

rafmudaf commented 2 years ago

For simplicity in the setuptools configuration, I created a new turbine library in floris/turbine_library so there is now two instances with the other one in examples/inputs/turbine_definitions. @bayc Let's think about how to resolve this via setup.py and the package_data keyword.

See #325

bayc commented 2 years ago

Sounds good! For now (to prevent confusion), I removed the examples/inputs/turbine_definitions folder so the users only have one place to look for the v3 release.

ElieKadoche commented 2 years ago

Hello! First, thank you for the amazing work done on the v3. From my understanding, if a user wants to add another turbine type, the new associated YAML file should be placed in the turbine_library folder, located in the FLORIS source code.

Modifying the content of the source code does not seem appropriate. Wouldn't it be better to allow an additional (external) turbine library? For example, there could be an additional_turbine_library variable in the YAML configuration.

https://github.com/NREL/floris/blob/89e071fa3845228e1f808a4689fc32603d431171/floris/simulation/farm.py#L76-L77

bayc commented 2 years ago

Hello! First, thank you for the amazing work done on the v3. From my understanding, if a user wants to add another turbine type, the new associated YAML file should be placed in the turbine_library folder, located in the FLORIS source code.

Modifying the content of the source code does not seem appropriate. Wouldn't it be better to allow an additional (external) turbine library? For example, there could be an additional_turbine_library variable in the YAML configuration.

https://github.com/NREL/floris/blob/89e071fa3845228e1f808a4689fc32603d431171/floris/simulation/farm.py#L76-L77

Thank you for the feedback! This is something we have been discussing internally and agree that there should be a better solution to allow for user-defined turbine types. We will update here with any changes addressing this.

econdon16 commented 2 years ago

Even when creating a new turbine in the turbine_library (the iea_15MW turbine) using the iea_10MW.yaml file as a template, I'm getting the following error: ValueError: User-selected turbine definition "iea_15MW" does not exist in pre-defined turbine library.

Is there a way to bypass this for now until the external library is created?

Bartdoekemeijer commented 2 years ago

Hi @econdon16 . I have had success placing new turbine files in floris/floris/turbine_library and importing them in a similar manner as for the NREL 5MW and IEA 10MW turbine in the input YAML file. Can you share where you placed your files and how you modified your input YAML file?

econdon16 commented 2 years ago

@Bartdoekemeijer I duplicated the iea_10MW.yaml file within the same turbine_library folder and edited it to include the following:

turbine_type: 'iea_15MW' generator_efficiency: 1.0 hub_height: 150.0 pP: 1.88 pT: 1.88 rotor_diameter: 240.0 TSR: 8.0 power_thrust_table: power: ... thrust: ... wind_speed: ...

(My input file works with the iea_10MW.yaml file so I don't think the issue is there.)

bayc commented 2 years ago

The code will look for the turbine file based on the file name. As such, do you have the file saved as iea_15MW.yaml?

econdon16 commented 2 years ago

Yes I have named it that exactly @bayc

bayc commented 2 years ago

In farm.py on line 77, you can see how the file path is constructed for loading the turbines (https://github.com/NREL/floris/blob/main/floris/simulation/farm.py#L77):

fname = _floris_dir / "turbine_library" / f"{val}.yaml"

You could try printing fname out before the if statement on line 78 and seeing if the file path exists/is correct. Perhaps the solution we have there doesn't work for all systems.

econdon16 commented 2 years ago

I found my error to be in my environment organization. Though I thought I have floris v3.0.1 in it's own location, the turbine_library was being called from an installation of floris v3.0.1 in an anaconda environment i.e. I have floris/floris/turbine_library in two locations and it was favoring the one in a distant file. Adding my iea_15MW.yaml file to that location solved the issue, but any advice on editing that path?

rafmudaf commented 2 years ago

If you're using conda, I think the Python interpreter will require that you add your new turbine to the floris in the anaconda installation. Like @ElieKadoche mentioned in https://github.com/NREL/floris/issues/345#issuecomment-1055490523, modifying the source code of an installed package is bad practice and we will resolve this in a future release. I'm not sure if I correctly understood so does this answer your question?

rafmudaf commented 2 years ago

@econdon16 alternatively you can supply your turbine definition directly (as in, not in a turbine library directory) using the !include keyword in the input file...

farm:
  layout_x:
  - 0.0
  - 630.0
  - 1260.0
  layout_y:
  - 0.0
  - 0.0
  - 0.0
  turbine_type:
  - !include /your/path/to/raf_20MW.yaml
spixap commented 1 year ago

Does anyone know how to create a yaml file that has a custom turbine type (!include /your/path/to/raf_20MW.yaml) not manually but directly from a python script? When I am trying to write the yaml file (using pyyalm and yalm.dump) the keyword !include is interpreted as a string and does not work. Thank you very much.

rafmudaf commented 1 year ago

Good question - I can't think of how to do this. Can you share a small example of what you've tried?

Are you automatically generating FLORIS input files? If so, you could also include the turbine definition directly under turbine_type rather than including the link to the turbine type yaml file.

spixap commented 1 year ago

Thanks, @rafmudaf for your suggestion. Indeed this is what I also tried and it worked. All you need is to include the individual wind turbine content (i.e. the content that would normally be in the reference: !include /your/path/to/raf_20MW.yaml) per turbine, in the floris input file. Then you can overwrite the characteristics in the custom floris input file easily from the python script. In that way, you can even assign different Cp/Ct curves per wind turbine in the farm :)

Here follows an example with a custom input file: _gch_new_input_32_turbines_Cp_Ctrewritable.yaml

Loop to assign different curves to different turbines and write new input file

with open(r'inputs\gch_new_input_32_turbines_Cp_Ct_rewritable.yaml', 'r') as inputSpecsFile:
      farmSpecs = yaml.full_load(inputSpecsFile)

u_curves_list =  u_curves.tolist()
TSR_2_floris_list = TSR_2_floris.tolist()

for iturbine in range(N_TURBINES):

    Cp_2_floris_list = Cp_2_floris[iturbine,:].tolist()
    Ct_2_floris_list = Ct_2_floris[iturbine,:].tolist()

    farmSpecs['farm']['turbine_type'][iturbine]['power_thrust_table']['power']       = Cp_2_floris_list
    farmSpecs['farm']['turbine_type'][iturbine]['power_thrust_table']['thrust']      = Ct_2_floris_list
    farmSpecs['farm']['turbine_type'][iturbine]['power_thrust_table']['wind_speed']  = u_curves_list
    farmSpecs['farm']['turbine_type'][iturbine]['TSR']                               = TSR_2_floris_list[iturbine]

newFarmSpec = farmSpecs

with open(r'inputs\gch_new_input_32_turbines_Cp_Ct_rewritable.yaml', 'w') as file:
    documents = yaml.dump(newFarmSpec,file)
rafmudaf commented 1 year ago

This should be added to the user documentation

rafmudaf commented 1 year ago

@RHammond2 mostly addressed this issue in #568, but I'm leaving this open since it is not yet in the documentation.

pengyulu1112 commented 1 year ago

The error always show that nrel_5MW_custom.yaml is not defined when I am using external library, how can I solve it?

rafmudaf commented 1 year ago

The error always show that nrel_5MW_custom.yaml is not defined when I am using external library, how can I solve it?

@pengyulu1112 could you share a simple script demonstrating the error? Also, please share the version of floris that you're using.

pengyulu1112 commented 1 year ago

The version is 3.4.

I just modified the hub height of nrel_5MW, and I saved it as nrel_5MW100.yaml, I changed the hug height to 100m. But when I always meet the error shows that nrel_5MW100 does not exist in either the internal or external turbine library. So I wondering how to define an external turbine to my code. Thank you very much. Have a nice day!

This is the wind turbine I changed. Just vary the hub height of nrel_5MW. I renamed it as nrel_5MW100.yaml

turbine_type: 'nrel_5MW100'
generator_efficiency: 1.0
hub_height: 100.0
pP: 1.88
pT: 1.88
rotor_diameter: 126.0
TSR: 8.0
ref_density_cp_ct: 1.225
ref_tilt_cp_ct: 5.0
power_thrust_table:
  # Removed to save space

And this is the wind farm I set.

name: GCH
description: Three turbines using Gauss Curl Hybrid model
floris_version: v3.0.0

logging:
  console:
    enable: true
    level: WARNING
  file:
    enable: false
    level: WARNING

solver:
  type: turbine_grid
  turbine_grid_points: 3

farm:
  layout_x:
  - 0.0
  - 504.0
  - 1008

  layout_y:
  - 0.0
  - 0.0
  - 0.0

  turbine_type:
  - nrel_5MW
  - nrel_5MW
  - nrel_5MW100

flow_field:
  air_density: 1.225
  reference_wind_height: 90.0 # Since multiple defined turbines, must specify explicitly the reference wind height
  turbulence_intensity: 0.06
  wind_directions:
  - 270.0
  wind_shear: 0.12
  wind_speeds:
  - 8.0
  wind_veer: 0.0

wake:
  model_strings:
    combination_model: sosfs
    deflection_model: gauss
    turbulence_model: crespo_hernandez
    velocity_model: gauss

  enable_secondary_steering: false
  enable_yaw_added_recovery: false
  enable_transverse_velocities: false

  wake_deflection_parameters:
    gauss:
      ad: 0.0
      alpha: 0.58
      bd: 0.0
      beta: 0.077
      dm: 1.0
      ka: 0.38
      kb: 0.004
    jimenez:
      ad: 0.0
      bd: 0.0
      kd: 0.05

  wake_velocity_parameters:
    cc:
      a_s: 0.179367259
      b_s: 0.0118889215
      c_s1: 0.0563691592
      c_s2: 0.13290157
      a_f: 3.11
      b_f: -0.68
      c_f: 2.41
      alpha_mod: 1.0
    gauss:
      alpha: 0.58
      beta: 0.077
      ka: 0.38
      kb: 0.004
    jensen:
      we: 0.05

  wake_turbulence_parameters:
    crespo_hernandez:
      initial: 0.1
      constant: 0.5
      ai: 0.8
      downstream: -0.32

And this is the code I use.

import matplotlib.pyplot as plt
import floris.tools.visualization as wakeviz
from floris.tools import FlorisInterface
from floris.turbine_library import TurbineInterface, TurbineLibrary

fi = FlorisInterface("D:/python/floris/floris-main/examples/inputs/try/1x3mul.yaml")

horizontal_plane = fi.calculate_horizontal_plane(x_resolution=200, y_resolution=100, height=90)
y_plane = fi.calculate_y_plane(x_resolution=200, z_resolution=100, crossstream_dist=0.0)

# Create the plots
fig, ax_list = plt.subplots(2, 1, figsize=(9, 4))
ax_list = ax_list.flatten()

fig0 = wakeviz.visualize_cut_plane(horizontal_plane, ax=ax_list[0], title="Horizontal")
fig1 = wakeviz.visualize_cut_plane(y_plane, ax=ax_list[1], title="Streamwise profile")

ax_list[0].set_xlabel('x-coordinate of the wind turbine(m)')
ax_list[0].set_ylabel('wind turbine position(m)')

ax_list[1].set_xlabel('x-coordinate of the wind turbine(m)')
ax_list[1].set_ylabel('Height')

cbar = plt.colorbar(fig1, ax=ax_list)
cbar.set_label('Wind speed (m/s)')

wakeviz.show_plots()

Here is the error.

E:\python\FLoris\venv\Scripts\python.exe E:\python\FLoris\multiple_turbinetypes.py 
Traceback (most recent call last):
  File "E:\python\FLoris\multiple_turbinetypes.py", line 35, in <module>
    fi = FlorisInterface("D:/python/floris/floris-main/examples/inputs/try/1x3mul.yaml")
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\python\FLoris\venv\Lib\site-packages\floris\tools\floris_interface.py", line 57, in __init__
    self.floris = Floris.from_file(self.configuration)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\python\FLoris\venv\Lib\site-packages\floris\simulation\floris.py", line 338, in from_file
    return Floris.from_dict(input_dict)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "E:\python\FLoris\venv\Lib\site-packages\floris\type_dec.py", line 160, in from_dict
    return cls(**kwargs)
           ^^^^^^^^^^^^^
  File "<attrs generated init floris.simulation.floris.Floris>", line 6, in __init__
  File "E:\python\FLoris\venv\Lib\site-packages\floris\type_dec.py", line 160, in from_dict
    return cls(**kwargs)
           ^^^^^^^^^^^^^
  File "<attrs generated init floris.simulation.farm.Farm>", line 26, in __init__
  File "E:\python\FLoris\venv\Lib\site-packages\floris\simulation\farm.py", line 136, in __attrs_post_init__
    raise FileNotFoundError(
FileNotFoundError: The turbine type: nrel_5MW100 does not exist in either the internal or external turbine library.

Process finished with exit code 1
rafmudaf commented 1 year ago

@pengyulu1112 Take a look at the description in https://github.com/NREL/floris/pull/568. An additional field is required in your input file: turbine_library_path.

pengyulu1112 commented 1 year ago

Thank you! I creat a new file which named nrel_5MW100.yaml in E:/ then it works!! Thank you very much!