Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More oneROSCO2 updates, primarily housekeeping #76

Merged
merged 15 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 17 additions & 21 deletions Examples/example_12.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,28 @@
from ROSCO_toolbox import turbine as ROSCO_turbine
from ROSCO_toolbox import controller as ROSCO_controller


def run_example():
# Shorthand directories
this_dir = os.path.dirname(os.path.abspath(__file__))
tune_dir = os.path.join(this_dir, '../Tune_Cases')
test_dir = os.path.join(this_dir, '../Test_Cases')

# Setup linear turbine paths
linfile_root = os.path.join(test_dir, 'IEA-15-240-RWT-UMaineSemi', 'linearizations')
load_parallel = True
linturb_options = {'linfile_root': linfile_root,
'load_parallel': load_parallel}

# ROSCO options
parameter_filename = os.path.join(tune_dir, 'IEA15MW.yaml')
parameter_filename = os.path.join(tune_dir, 'IEA15MW_robust.yaml')
inps = load_rosco_yaml(parameter_filename)
path_params = inps['path_params']
turbine_params = inps['turbine_params']
controller_params = inps['controller_params']
linmodel_tuning = inps['linmodel_tuning']
ROSCO_options = {
'path_params': path_params,
'turbine_params': turbine_params,
'controller_params': controller_params
}

# Path options
example_out_dir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'examples_out' )
example_out_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'examples_out')
output_name = '12_robust_scheduling'
path_options = {'output_dir': example_out_dir,
'output_name': output_name
Expand All @@ -65,31 +61,31 @@ def run_example():
k_float = controller.Kp_float

# Scheduling options
opt_options = { 'driver': 'optimization', #'design_of_experiments',
'windspeed': [12, 13, 14, 15, 18, 24],
'stability_margin': 0.1,
'omega':[0.05, 0.2], # two inputs denotes a range for a design variable
'k_float': [k_float]} # one input denotes a set value
opt_options = {'driver': 'optimization', # 'design_of_experiments',
'windspeed': controller_params['U_pc'],
'stability_margin': linmodel_tuning['stability_margin'],
'omega': [linmodel_tuning['omega_pc']['min'],
linmodel_tuning['omega_pc']['max']], # two inputs denotes a range for a design variable
'k_float': [k_float]} # one input denotes a set value

# Collect options
options = {}
options['linturb_options'] = linturb_options
options['ROSCO_options'] = ROSCO_options
options['path_options'] = path_options
options['opt_options'] = opt_options
options['linturb_options'] = linmodel_tuning
options['ROSCO_options'] = ROSCO_options
options['path_options'] = path_options
options['opt_options'] = opt_options

# Run robust scheduling
sd = rsched_driver(options)
sd.setup()
sd.execute()

# Re-define ROSCO tuning parameters
controller.U_pc = opt_options['windspeed']
controller.omega_pc = sd.omegas
controller.zeta_pc = np.ones(
len(opt_options['windspeed'])) * controller.zeta_pc

# Tune ROSCO with to satisfy robust stability margin
# Tune ROSCO with to satisfy robust stability margin
controller.tune_controller(turbine)

# Plot gain schedule
Expand Down Expand Up @@ -118,10 +114,10 @@ def run_example():
ax[4].set_ylabel('Integral Gain')
ax[4].grid()


if False:
if True:
plt.show()
else:
plt.savefig(os.path.join(example_out_dir, '12_RobustSched.png'))

if __name__ == '__main__':
run_example()
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
# NREL's Reference OpenSource Controller (ROSCO) toolbox for wind turbine applications
NREL's Reference OpenSource Controller (ROSCO) toolbox for wind turbine applications is a toolbox designed to ease controller implementation for the wind turbine researcher. Some primary capabilities include:
NREL's Reference OpenSource Controller (ROSCO) for wind turbine applications is a toolset designed to ease controller use and implementation for the wind turbine researcher. Some primary capabilities include:
* A reference controller with industry-standard functionality
* Generic tuning of NREL's ROSCO controller
* Simple 1-DOF turbine simulations for quick controller capability verifications
* Parsing of OpenFAST input and output files


## Introduction
The NREL Reference OpenSource Controller (ROSCO) provides an open, modular and fully adaptable baseline wind turbine controller to the scientific community. The ROSCO toolbox leverages this architecture and implementation to provide a generic tuning process for the controller. Because of the open character and modular set-up, scientists are able to collaborate and contribute in making continuous improvements to the code for the controller and the toolbox. The ROSCO toolbox is a mostly-python code base with a number of functionalities.
The NREL Reference OpenSource Controller (ROSCO) provides an open, modular and fully adaptable baseline wind turbine controller to the scientific community. The ROSCO toolbox leverages this architecture and implementation to provide a generic tuning process for the controller. Because of the open character and modular set-up, scientists are able to collaborate and contribute in making continuous improvements to the code for the controller and the toolbox. The ROSCO controller is implemented in FORTRAN, while the remainder of the toolset is a mostly-python code base with a number of functionalities.

* [ROSCO](https://github.com/NREL/ROSCO) - the fortran source code for the ROSCO controller.
* [Examples](https://github.com/NREL/ROSCO_toolbox/tree/master/examples) - short working examples of the capabilities of the ROSCO toolbox.
* [Tune_Cases](https://github.com/NREL/ROSCO_toolbox/tree/master/Tune_Cases) - example generic tuning scripts for a number of open-source reference turbines.
* [Test_Cases](https://github.com/NREL/ROSCO_toolbox/tree/master/Test_Cases) - numerous NREL 5MW bases cases to run for controller updates and comparisons. A "test-suite", if you will...
* [Matlab_Toolbox](https://github.com/NREL/ROSCO_toolbox/tree/master/Matlab_Toolbox) - MATLAB scripts to parse and plot simulation output data.
* [ofTools](https://github.com/NREL/ROSCO_toolbox/tree/master/ofTools) - A number of scripts to facilitate usage of OpenFAST and manage OpenFAST input and output files.
* [ROSCO](https://github.com/NREL/ROSCO/tree/main/ROSCO) - the fortran source code for the ROSCO controller.
* [Examples](https://github.com/NREL/ROSCO/tree/main/Examples) - short working examples of the capabilities of the ROSCO toolbox.
* [Tune_Cases](https://github.com/NREL/ROSCO/tree/main/Tune_Cases) - example generic tuning scripts for a number of open-source reference turbines.
* [Test_Cases](https://github.com/NREL/ROSCO/tree/main/Test_Cases) - numerous NREL 5MW bases cases to run for controller updates and comparisons. A "test-suite", if you will...
* [Matlab_Toolbox](https://github.com/NREL/ROSCO/tree/main/Matlab_Toolbox) - MATLAB scripts to parse and plot simulation output data.
* [ofTools](https://github.com/NREL/ROSCO/tree/main/ROSCO_toolbox/ofTools) - A number of scripts to facilitate usage of OpenFAST and manage OpenFAST input and output files.
* [linear](https://github.com/NREL/ROSCO/tree/main/ROSCO_toolbox/linear) - Scripts to aid with the use of linear models for controller tuning and simplified simulation.


## Documentation
All relevant documentation about the ROSCO toolbox and ROSCO controller can be found at through [ROSCO's readthedocs webpage](https://rosco-toolbox.readthedocs.io/en/latest/). Here, users can find the information on [installing the ROSCO toolbox](https://rosco-toolbox.readthedocs.io/en/latest/source/install.html#installing-the-rosco-toolbox) and [compiling ROSCO](https://rosco-toolbox.readthedocs.io/en/latest/source/install.html#compiling-rosco) for control purposes. Additionally, there is information on the standard workflow and uses cases for the ROSCO toolchain, and more.
All relevant documentation about the ROSCO toolbox and ROSCO controller can be found at through [ROSCO's readthedocs webpage](https://rosco.readthedocs.io/en/latest/). Here, users can find the information on [installing the ROSCO tools](https://rosco.readthedocs.io/en/latest/source/install.html) and [compiling ROSCO](https://rosco.readthedocs.io/en/latest/source/install.html#rosco-controller) for control purposes. Additionally, there is information on the standard workflow, uses cases for the ROSCO tool-chain, and more.

## Issues and Discussion
If you find issues with any of the code that resides in this repository, it is encouraged for you to open a [GitHub issue](https://github.com/NREL/ROSCO/issues). If you have general questions or comments regarding the code, please start a [discussion via GitHub](https://github.com/NREL/ROSCO/discussions). We encourage you to use these resources for all ROSCO-related questions and comments, rather than other resources such as the FAST forums. This helps us keep ROSCO-related items centralized, and provides a singular place for the community to look when they have questions that might arise. Please keep in mind that we will do our very best to respond in a timely manner, but may take a few days to get back to you if you catch us during a busy time.

## Contributing
If it wasn't obvious from _open-source_ being in the title of the tool-set, this is an open-source code base that we would love for the community to contribute to. If you find yourself fixing any bugs, writing new routines, or even making small typo changes, please submit a [pull request](https://github.com/NREL/ROSCO/pulls).

## Survey
Please help us better understand the ROSCO user-base and how we can improve rosco through this brief survey:
Expand All @@ -27,18 +35,18 @@ Please help us better understand the ROSCO user-base and how we can improve rosc
If the ROSCO Toolbox played a role in your research, please cite it. This software can be
cited as:

NREL: ROSCO Toolbox. Version 2.3.0, https://github.com/NREL/rosco_toolbox, 2021.
NREL: ROSCO. Version 2.4.0, https://github.com/NREL/ROSCO, 2021.

For LaTeX users:

```
@misc{ROSCO_toolbox_2021,
author = {NREL},
title = {{ROSCO Toolbox. Version 2.3.0}},
title = {{ROSCO. Version 2.4.0}},
year = {2021},
publisher = {GitHub},
journal = {GitHub repository},
url = {https://github.com/NREL/rosco_toolbox}
url = {https://github.com/NREL/ROSCO}
}
```
If the ROSCO generic tuning theory and implementation played a roll in your research, please cite the following paper
Expand All @@ -54,10 +62,6 @@ URL = {https://wes.copernicus.org/preprints/wes-2021-19/},
DOI = {10.5194/wes-2021-19}
}
```
Additionally, if you have extensively used the [ROSCO](https://github.com/NREL/ROSCO) controller or [WISDEM](https://github.com/wisdem/wisdem), please cite them accordingly.


## Additional Contributors and Acknowledgments
Primary contributions to the ROSCO Toolbox have been provided by researchers the National Renewable Energy Laboratory (Nikhar J. Abbas, Daniel Zalkind, Alan Wright, and Paul Fleming) and the University of Colorado Boulder (Lucy Pao). Much of the intellect behind these contributions has been inspired or derived from an extensive amount of work in the literature. The bulk of this has been cited through the primary publications about this work.

There have been a number of contributors to the logic of the ROSCO controller itself. Please see the [ROSCO github page](https://github.com/NREL/ROSCO) for more information on who these contributors have been.
Primary contributions to ROSCO have been provided by researchers the National Renewable Energy Laboratory and the University of Colorado Boulder. Additionally, the ROSCO controller was built upon the foundations of the [Delft Research Controller](https://github.com/TUDelft-DataDrivenControl/DRC_Fortran). Much of the intellect behind these contributions has been inspired or derived from an extensive amount of work in the literature. The bulk of this has been cited through the primary publications about this work.
2 changes: 1 addition & 1 deletion ROSCO/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.6)
project(ROSCO VERSION 2.3.0 LANGUAGES Fortran)
project(ROSCO VERSION 2.4.0 LANGUAGES Fortran)

set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/ftnmods")

Expand Down
2 changes: 1 addition & 1 deletion ROSCO/src/Constants.f90
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
! specific language governing permissions and limitations under the License.

MODULE Constants
Character(*), PARAMETER :: rosco_version = 'v2.3.0' ! ROSCO version
Character(*), PARAMETER :: rosco_version = 'v2.4.0' ! ROSCO version
REAL(8), PARAMETER :: RPS2RPM = 9.5492966 ! Factor to convert radians per second to revolutions per minute.
REAL(8), PARAMETER :: R2D = 57.295780 ! Factor to convert radians to degrees.
REAL(8), PARAMETER :: D2R = 0.0175 ! Factor to convert degrees to radians.
Expand Down
2 changes: 1 addition & 1 deletion ROSCO_toolbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

__author__ = """Nikhar J. Abbas and Daniel S. Zalkind"""
__email__ = 'nikhar.abbas@nrel.gov'
__version__ = '2.3.0'
__version__ = '2.4.0'
35 changes: 22 additions & 13 deletions ROSCO_toolbox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import sys
import datetime
from scipy import interpolate, gradient, integrate
from ROSCO_toolbox.utilities import list_check

# Some useful constants
now = datetime.datetime.now()
Expand Down Expand Up @@ -63,11 +64,12 @@ def __init__(self, controller_params):
self.Flp_Mode = controller_params['Flp_Mode']

# Necessary parameters
self.U_pc = controller_params['U_pc']
self.zeta_pc = controller_params['zeta_pc']
self.omega_pc = controller_params['omega_pc']
self.zeta_vs = controller_params['zeta_vs']
self.omega_vs = controller_params['omega_vs']
self.U_pc = list_check(controller_params['U_pc'], return_bool=False)
self.zeta_pc = list_check(controller_params['zeta_pc'], return_bool=False)
self.omega_pc = list_check(controller_params['omega_pc'], return_bool=False)
self.zeta_vs = controller_params['zeta_vs']
self.omega_vs = controller_params['omega_vs']
self.interp_type = controller_params['interp_type']

# Optional parameters with defaults
self.min_pitch = controller_params['min_pitch']
Expand Down Expand Up @@ -122,6 +124,12 @@ def __init__(self, controller_params):
if self.WS_GS_n <= self.PC_GS_n:
raise Exception('Number of WS breakpoints is not greater than pitch control breakpoints')

# Error checking: pitch controller inputs
if list_check(self.U_pc) and \
(list_check(self.omega_pc) or list_check(self.zeta_pc)) and \
not len(self.U_pc) == len(self.omega_pc) == len(self.zeta_pc):
raise Exception(
'U_pc, omega_pc, and zeta_pc are all list-like and are not of equal length')


def tune_controller(self, turbine):
Expand Down Expand Up @@ -241,17 +249,18 @@ def tune_controller(self, turbine):
B_tau = B_tau * np.ones(len(v))

# Resample omega_ and zeta_pc at above rated wind speeds
if self.U_pc \
and isinstance(self.omega_pc, (list,np.ndarray)) \
and isinstance(self.zeta_pc, (list,np.ndarray)) \
and len(self.U_pc) == len(self.omega_pc) == len(self.zeta_pc):
self.omega_pc_U = multi_sigma(v_above_rated[1:],self.U_pc,self.omega_pc)
self.zeta_pc_U = multi_sigma(v_above_rated[1:],self.U_pc,self.zeta_pc)
elif isinstance(self.omega_pc, float) and isinstance(self.zeta_pc, float):
if not list_check(self.omega_pc) and not list_check(self.zeta_pc):
self.omega_pc_U = self.omega_pc * np.ones(len(v_above_rated[1:]))
self.zeta_pc_U = self.zeta_pc * np.ones(len(v_above_rated[1:]))
else:
raise Exception('ROSCO_toolbox: The lengths of U_pc, omega_pc, and zeta_pc must be equal')
if self.interp_type == 'sigma': # sigma interpolation
self.omega_pc_U = multi_sigma(v_above_rated[1:], self.U_pc, self.omega_pc)
self.zeta_pc_U = multi_sigma(v_above_rated[1:], self.U_pc, self.zeta_pc)
else: # standard scipy interpolation types
interp_omega = interpolate.interp1d(self.U_pc, self.omega_pc, kind=self.interp_type, bounds_error=False, fill_value='extrapolate')
interp_zeta = interpolate.interp1d(self.U_pc, self.zeta_pc, kind=self.interp_type, bounds_error=False, fill_value='extrapolate')
self.omega_pc_U = interp_omega(v_above_rated[1:])
self.zeta_pc_U = interp_zeta(v_above_rated[1:])

# -- Find gain schedule --
self.pc_gain_schedule = ControllerTypes()
Expand Down
53 changes: 46 additions & 7 deletions ROSCO_toolbox/inputs/toolbox_schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ properties:
minimum: 0
maximum: 3
default: 2
description: Generator torque control mode in above rated conditions (0- constant torque, 1- constant power, 2- TSR tracking PI control, 3- TSR tracking and constant power)
description: Generator torque control mode in above rated conditions (0- constant torque, 1- constant power, 2- TSR tracking PI control with constant torque, 3- TSR tracking with constant power)
PC_ControlMode:
type: number
minimum: 0
Expand Down Expand Up @@ -203,6 +203,11 @@ properties:
type: number
minimum: 0
default: [0.2]
interp_type:
type: string
description: Type of interpolation between above rated tuning values (only used for multiple pitch controller tuning values)
default: linear
enum: ['sigma', 'linear', 'quadratic', 'cubic']
zeta_vs:
type: number
minimum: 0
Expand Down Expand Up @@ -305,7 +310,7 @@ properties:
minimum: 0
description: Flap controller desired natural frequency [rad/s]
unit: rad/s

filter_params:
type: object
default: {}
Expand All @@ -323,8 +328,42 @@ properties:
default: 0.01042
description: Natural frequency of first-order high-pass filter for nacelle fore-aft motion [rad/s]

# modeling_options:
# type: object
# default: {}
# properties:

linmodel_tuning:
type: object
default: {}
description: Inputs used for tuning ROSCO using linear (level 2) models
properties:
type:
type: string
description: Type of level 2 based tuning - robust gain scheduling (robust) or simulation based optimization (simulation)
default: 'none'
enum: ['none', 'robust', 'simulation']
linfile_path:
type: string
description: Path to OpenFAST linearization (.lin) files, if they exist
default: none
lintune_outpath:
type: string
description: Path for outputs from linear model based tuning
default: lintune_outfiles
load_parallel:
type: boolean
description: Load linearization files in parallel (True/False)
default: False
stability_margin:
type: [number, array]
description: Desired maximum stability margin
default: 0.1
omega_pc:
type: object
default: {}
description: Pitch controller bandwidth constraints
min:
type: [number, array]
default: 0.0
description: Desired maximum allowable omega for robust tuning. Array must be of length U_pc.
max:
type: [number, array]
default: 0.2
description: Desired maximum allowable omega for robust tuning. Array must be of length U_pc.

Loading