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

Floating Feedback Gain Scheduling #241

Merged
merged 68 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
656ea40
Add back open loop yaw rate control
dzalkind May 8, 2023
5e2430e
Check OL outputs in example
dzalkind May 8, 2023
3d28f0b
Update CI to use mamba, first attempt
dzalkind May 9, 2023
7165796
Install extras when environment first set up
dzalkind May 9, 2023
8a4ef64
Remove potential libpython typo
dzalkind May 9, 2023
7e94613
Remove more potential typos
dzalkind May 9, 2023
e8d5cf4
Use mamba in compile, too
dzalkind May 9, 2023
0586e39
Use environment.yml file
dzalkind May 9, 2023
5910fa6
Remove conda installs from rosco-compile
dzalkind May 9, 2023
1ced5b0
Clean up CI scripts
dzalkind May 10, 2023
4718065
added yaml file in folder tune_cases
May 15, 2023
beef0f0
additional yaml files added to tune_cases
May 15, 2023
08d2488
additional yaml
May 15, 2023
60c00af
additional yaml
May 15, 2023
facaa3a
further additions
May 15, 2023
f78aac7
various changes to add KPfloat gain scheduling
May 15, 2023
8caa849
updating ROSCO toolbox files and ROSCO source code for KPfloat gain s…
May 17, 2023
1039f72
Update BAR_10_InflowFile.dat
Yuksel-Rudy May 25, 2023
bd250e5
Update IEA-15-240-RWT_InflowFile.dat
Yuksel-Rudy May 25, 2023
265bb46
Update NRELOffshrBsline5MW_InflowWind.dat
Yuksel-Rudy May 25, 2023
5f9dd59
Update BAR_10_InflowFile.dat
Yuksel-Rudy May 25, 2023
f67f301
Update NREL-2p8-127_InflowFile.dat
Yuksel-Rudy May 25, 2023
f64cfc9
Merge remote-tracking branch 'upstream/develop' into dev
dzalkind May 25, 2023
fff26a6
Remove CCT9 at rated model
dzalkind May 25, 2023
1ddd797
Remove CCT above rated model
dzalkind May 25, 2023
0f925d4
Remove extra tuning yamls
dzalkind May 25, 2023
75054db
Update NREL-2p8-127_InflowFile.dat
Yuksel-Rudy May 30, 2023
d898709
Update IEA-15-240-RWT_InflowFile.dat
Yuksel-Rudy May 30, 2023
40729f7
Update NRELOffshrBsline5MW_InflowWind.dat
Yuksel-Rudy May 30, 2023
fa442dc
Update NREL-2p8-127_InflowFile.dat
Yuksel-Rudy May 30, 2023
3c6326b
Update StC-Force-Col1.dat
Yuksel-Rudy May 30, 2023
f75f74c
Update StC-Force-Col2.dat
Yuksel-Rudy May 30, 2023
7d89b79
Update StC-Force-Col3.dat
Yuksel-Rudy May 30, 2023
ca9d0d6
Update FAST_reader.py
Yuksel-Rudy May 30, 2023
2411b55
Update FAST_writer.py
Yuksel-Rudy May 30, 2023
3d9cb5b
Merge branch 'develop' into bf/ol_yaw_rate
dzalkind Jun 8, 2023
890125b
Update mamba install in CI
dzalkind Jun 8, 2023
ff42e28
Remove petsc and mpi
dzalkind Jun 8, 2023
83ad87b
Revert CI back to conda
dzalkind Jun 9, 2023
9a9fd53
Merge remote-tracking branch 'rudy/main' into of350
dzalkind Jun 9, 2023
b8011a0
Merge remote-tracking branch 'rudy/develop' into of350
dzalkind Jun 9, 2023
3a288fa
Give Fl_Kp own gain scheduling, separate from pitch control
dzalkind Jun 9, 2023
c5523e6
Merge remote-tracking branch 'upstream/develop' into dev
dzalkind Jun 9, 2023
7a05e65
Remove duplicate AWC entries in registry
dzalkind Jun 9, 2023
c2690c2
Sync FAST_reader/writer with WEIS versions
dzalkind Jun 9, 2023
6877595
Set default Kp_float and U_Fl for non-floating cases
dzalkind Jun 9, 2023
5315312
Increment openfast version in CI
dzalkind Jun 9, 2023
217d3b5
Add nodes to FAST_vars_out
dzalkind Jun 9, 2023
eece159
Add nodes to vartree
dzalkind Jun 9, 2023
a395365
Remove duplicated F_NotchType check
dzalkind Jun 13, 2023
c18ef4c
Sync FAST_vars_out more
dzalkind Jun 13, 2023
98a2f1a
Update DISCONs with new Fl_* inputs
dzalkind Jun 13, 2023
a0848ff
Make Fl_n an int when writing DISCON
dzalkind Jun 13, 2023
1c4a55a
Merge branch 'of350' into dev
dzalkind Jun 13, 2023
e710c24
Add MoorDyn outlist params to FstOutput
dzalkind Jun 13, 2023
4983dac
Merge branch 'of350' into dev
dzalkind Jun 13, 2023
108440f
Merge remote-tracking branch 'upstream/develop' into dev
dzalkind Jul 11, 2023
6edef38
Add floating feedback example
dzalkind Jul 12, 2023
f31ba12
Fix schema for Kp_float
dzalkind Jul 12, 2023
dce51db
Update run_FAST to work in weis environment
dzalkind Jul 12, 2023
afde0dd
Pull some FAST_reader improvements in Beam/SubDyn
dzalkind Jul 12, 2023
c563cf6
Simplify example 05, most moved to 24_floating_feedback
dzalkind Jul 12, 2023
89ba586
Make rotor_performance_filename relative to tuning yaml
dzalkind Jul 19, 2023
983f13d
Update paths with new Cp location
dzalkind Jul 19, 2023
8bbe13f
Add api change and update toolbox input for docs
dzalkind Jul 19, 2023
48e5926
Update installation docs with wisdem note
dzalkind Jul 19, 2023
8c9b5e2
Update documentation regarding pyFAST in 11_robust_tuning.py
dzalkind Jul 19, 2023
c21b4f4
Update DISCON schema with new inputs
dzalkind Jul 19, 2023
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
2 changes: 1 addition & 1 deletion Examples/01_turbine_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
turbine.load_from_fast(
path_params['FAST_InputFile'],
os.path.join(tune_dir,path_params['FAST_directory']),
rot_source='txt',txt_filename=os.path.join(tune_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
rot_source='txt',txt_filename=os.path.join(tune_dir,path_params['rotor_performance_filename'])
)

# Print some basic turbine info
Expand Down
2 changes: 1 addition & 1 deletion Examples/03_tune_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
controller = ROSCO_controller.Controller(controller_params)

# Load turbine data from OpenFAST and rotor performance text file
cp_filename = os.path.join(tune_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
cp_filename = os.path.join(tune_dir,path_params['rotor_performance_filename'])
turbine.load_from_fast(
path_params['FAST_InputFile'],
os.path.join(tune_dir,path_params['FAST_directory']),
Expand Down
2 changes: 1 addition & 1 deletion Examples/04_simple_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
# controller = ROSCO_controller.Controller(controller_params)

# Load turbine data from OpenFAST and rotor performance text file
cp_filename = os.path.join(tune_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
cp_filename = os.path.join(tune_dir,path_params['rotor_performance_filename'])
turbine.load_from_fast(
path_params['FAST_InputFile'],
os.path.join(tune_dir,path_params['FAST_directory']),
Expand Down
34 changes: 1 addition & 33 deletions Examples/05_openfast_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,48 +41,16 @@
path_params['FAST_InputFile'],
os.path.join(this_dir,path_params['FAST_directory']),
rot_source='txt',
txt_filename=os.path.join(this_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
txt_filename=os.path.join(this_dir,path_params['rotor_performance_filename'])
)

# Tune controller
controller.tune_controller(turbine)

# Now double Kp_float and check that it's passed through
Kp_float = -18
controller_params['Kp_float'] = Kp_float
controller_params['tune_Fl'] = False
controller = ROSCO_controller.Controller(controller_params)
controller.tune_controller(turbine)
np.testing.assert_almost_equal(Kp_float,controller.Kp_float)

# Write parameter input file
param_file = os.path.join(this_dir,'DISCON.IN') # This must be named DISCON.IN to be seen by the compiled controller binary.
write_DISCON(turbine,controller,param_file=param_file, txt_filename=path_params['rotor_performance_filename'])

# Plot gain schedule
fig, ax = plt.subplots(2,2,constrained_layout=True,sharex=True)
ax = ax.flatten()
ax[0].plot(controller.v[len(controller.v_below_rated)+1:], controller.omega_pc_U)
ax[0].set_ylabel('omega_pc')

ax[1].plot(controller.v[len(controller.v_below_rated)+1:], controller.zeta_pc_U)
ax[1].set_ylabel('zeta_pc')

ax[2].plot(controller.v[len(controller.v_below_rated)+1:], controller.pc_gain_schedule.Kp)
ax[2].set_xlabel('Wind Speed')
ax[2].set_ylabel('Proportional Gain')

ax[3].plot(controller.v[len(controller.v_below_rated)+1:], controller.pc_gain_schedule.Ki)
ax[3].set_xlabel('Wind Speed')
ax[3].set_ylabel('Integral Gain')

plt.suptitle('Pitch Controller Gains')

if False:
plt.show()
else:
plt.savefig(os.path.join(example_out_dir,'05_GainSched.png'))

# Run OpenFAST
# --- May need to change fastcall if you use a non-standard command to call openfast
fastcall = 'openfast'
Expand Down
2 changes: 1 addition & 1 deletion Examples/06_peak_shaving.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
turbine.load_from_fast(
path_params['FAST_InputFile'],
os.path.join(tune_dir,path_params['FAST_directory']),
rot_source='txt',txt_filename=os.path.join(tune_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
rot_source='txt',txt_filename=os.path.join(tune_dir,path_params['rotor_performance_filename'])
)
# Tune controller
controller.tune_controller(turbine)
Expand Down
2 changes: 1 addition & 1 deletion Examples/10_linear_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
path_params['FAST_InputFile'],
os.path.join(this_dir,path_params['FAST_directory']),
rot_source='txt',
txt_filename=os.path.join(tune_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
txt_filename=os.path.join(tune_dir,path_params['rotor_performance_filename'])
)

# Tune controller
Expand Down
8 changes: 5 additions & 3 deletions Examples/11_robust_tuning.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Controller tuning to satisfy a robustness criteria
-------------------------------------
NOTE: This example necessitates the mbc3 through either pyFAST or WEIS
pyFAST is the easiest to install by cloning https://github.com/OpenFAST/python-toolbox and
running `python setup.py develop` from your conda environment

In this example:
- setup ROSCO's robust tuning methods for the IEA15MW on the UMaine Semi-sub
Expand Down Expand Up @@ -53,12 +55,12 @@ def run_example():
controller = ROSCO_controller.Controller(controller_params)
turbine.load_from_fast(
path_params['FAST_InputFile'],
os.path.join(this_dir, path_params['FAST_directory']),
rot_source='txt', txt_filename=os.path.join(this_dir,path_params['FAST_directory'],path_params['rotor_performance_filename'])
os.path.join(tune_dir, path_params['FAST_directory']),
rot_source='txt', txt_filename=os.path.join(tune_dir,path_params['rotor_performance_filename'])
)

# Fix path params for robust setup
path_params['FAST_directory'] = os.path.join(this_dir, path_params['FAST_directory'])
path_params['FAST_directory'] = os.path.join(tune_dir, path_params['FAST_directory'])

controller.tune_controller(turbine)
k_float = controller.Kp_float
Expand Down
2 changes: 1 addition & 1 deletion Examples/14_open_loop_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
turbine.load_from_fast(path_params['FAST_InputFile'], \
os.path.join(this_dir,path_params['FAST_directory']), \
rot_source='txt',\
txt_filename=os.path.join(this_dir,path_params['FAST_directory'],path_params['rotor_performance_filename']))
txt_filename=os.path.join(this_dir,path_params['rotor_performance_filename']))

# Tune controller
controller.tune_controller(turbine)
Expand Down
165 changes: 165 additions & 0 deletions Examples/24_floating_feedback.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
'''
----------- 23_structural_control ------------------------
Run openfast with ROSCO and all the floating feedback methods
-----------------------------------------------

Floating feedback methods available in ROSCO/ROSCO_Toolbox

1. Automated tuning, constant for all wind speeds
2. Automated tuning, varies with wind speed
3. Direct tuning, constant for all wind speeds
4. Direct tuning, varies with wind speeds

'''

import os, platform
from ROSCO_toolbox.ofTools.case_gen.run_FAST import run_FAST_ROSCO
from ROSCO_toolbox.ofTools.case_gen import CaseLibrary as cl
import numpy as np
from ROSCO_toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST
from ROSCO_toolbox.inputs.validation import load_rosco_yaml
from ROSCO_toolbox.controller import OpenLoopControl
from ROSCO_toolbox.tune import yaml_to_objs
from ROSCO_toolbox.utilities import write_DISCON, read_DISCON
from ROSCO_toolbox import controller as ROSCO_controller
from ROSCO_toolbox.ofTools.fast_io import output_processing
import matplotlib.pyplot as plt



#directories
this_dir = os.path.dirname(os.path.abspath(__file__))
rosco_dir = os.path.dirname(this_dir)
example_out_dir = os.path.join(this_dir,'examples_out')
os.makedirs(example_out_dir,exist_ok=True)

if platform.system() == 'Windows':
lib_name = os.path.realpath(os.path.join(this_dir, '../ROSCO/build/libdiscon.dll'))
elif platform.system() == 'Darwin':
lib_name = os.path.realpath(os.path.join(this_dir, '../ROSCO/build/libdiscon.dylib'))
else:
lib_name = os.path.realpath(os.path.join(this_dir, '../ROSCO/build/libdiscon.so'))


def main():

# Input yaml and output directory
parameter_filename = os.path.join(rosco_dir,'Tune_Cases/IEA15MW.yaml')
run_dir = os.path.join(example_out_dir,'24_floating_feedback')
os.makedirs(run_dir,exist_ok=True)

controller, turbine, path_params = yaml_to_objs(parameter_filename)

# First, let's write the DISCONs for each method
param_files = []

# Method 1: Automated tuning, constant for all wind speeds
controller_params_1 = controller.controller_params # numbers correspond to methods above
param_file = os.path.join(run_dir,'DISCON_Fl_1.IN')
param_files.append(param_file)
write_DISCON(turbine,controller,
param_file=param_file,
txt_filename=path_params['rotor_performance_filename'])


# Method 2: Automated tuning, all wind speeds
controller_params_2 = controller_params_1.copy()
controller_params_2['U_Fl'] = 'all'
controller_params_2['tune_Fl'] = True
controller = ROSCO_controller.Controller(controller_params_2)
controller.tune_controller(turbine)
param_file = os.path.join(run_dir,'DISCON_Fl_2.IN')
param_files.append(param_file)
write_DISCON(turbine,controller,
param_file=param_file,
txt_filename=path_params['rotor_performance_filename'])

# Method 3: Direct tuning, constant for all wind speeds
controller_params_3 = controller_params_1.copy()
Kp_float = -18
controller_params_3['Kp_float'] = Kp_float
controller_params_3['tune_Fl'] = False
controller = ROSCO_controller.Controller(controller_params_3)
controller.tune_controller(turbine)
np.testing.assert_almost_equal(Kp_float,controller.Kp_float) # Check that it's passed through correctly
param_file = os.path.join(run_dir,'DISCON_Fl_3.IN')
param_files.append(param_file)
write_DISCON(turbine,controller,
param_file=param_file,
txt_filename=path_params['rotor_performance_filename'])

# Method 4: Direct tuning, varies with wind speeds
controller_params_4 = controller_params_1.copy()
controller_params_4['U_Fl'] = [12,16,25]
controller_params_4['Kp_float'] = [-12,-6,-3]
controller_params_4['tune_Fl'] = False
controller = ROSCO_controller.Controller(controller_params_4)
controller.tune_controller(turbine)
param_file = os.path.join(run_dir,'DISCON_Fl_4.IN')
param_files.append(param_file)
write_DISCON(turbine,controller,
param_file=os.path.join(run_dir,'DISCON_Fl_4.IN'),
txt_filename=path_params['rotor_performance_filename'])

# Read all DISCONs and make into case_inputs
case_inputs = {}
discon_lists = {}
for discon in param_files:
discon_vt = read_DISCON(discon)
for discon_input in discon_vt:
if discon_input not in discon_lists: # initialize
discon_lists[discon_input] = []
discon_lists[discon_input].append(discon_vt[discon_input])

for discon_input, input in discon_lists.items():
case_inputs[('DISCON_in',discon_input)] = {'vals': input, 'group': 2}


# simulation set up
r = run_FAST_ROSCO()
r.tuning_yaml = parameter_filename
r.wind_case_fcn = cl.simp_step # single step wind input
r.wind_case_opts = {
'U_start': [13],
'U_end': [16],
'TMax': 100,
'TStep': 50,
}
r.case_inputs = case_inputs
r.save_dir = run_dir
r.rosco_dir = rosco_dir
r.n_cores = 4
r.run_FAST()

op = output_processing.output_processing()
op_dbg = output_processing.output_processing()
op_dbg2 = output_processing.output_processing()

out_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.outb') for i_case in range(4)]
dbg_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg') for i_case in range(4)]
dbg2_files = [os.path.join(run_dir,f'IEA15MW/simp_step/base/IEA15MW_{i_case}.RO.dbg2') for i_case in range(4)]

fst_out = op.load_fast_out(out_files, tmin=0)
debug_vars = op_dbg.load_fast_out(dbg_files, tmin=0)
local_vars = op_dbg2.load_fast_out(dbg2_files, tmin=0)

comb_out = [None] * len(fst_out)
for i, (r_out, f_out) in enumerate(zip(debug_vars,fst_out)):
r_out.update(f_out)
comb_out[i] = r_out
for i, (r_out2, f_out) in enumerate(zip(local_vars,comb_out)):
r_out2.update(f_out)
comb_out[i] = r_out2

cases = {}
cases['Fl Sigs.'] = ['Wind1VelX','Kp_Float', 'Fl_PitCom', 'BldPitch1','PtfmPitch']#,'PtfmPitch','PtfmYaw','NacYaw']
fig, ax = op.plot_fast_out(comb_out,cases, showplot=True)

if False:
plt.show()
else:
plt.savefig(os.path.join(run_dir,'24_floating_feedback.png'))


if __name__=="__main__":
main()
29 changes: 21 additions & 8 deletions Examples/ROSCO_walkthrough.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Examples/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'21_optional_inputs',
'22_cable_control',
'23_structural_control',
'24_floating_feedback',
'update_rosco_discons',
]

Expand Down
35 changes: 11 additions & 24 deletions ROSCO/rosco_registry/rosco_types.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,17 @@ ControlParameters:
Fl_Mode:
<<: *integer
description: Floating specific feedback mode {0 - no nacelle velocity feedback, 1 - nacelle velocity feedback}
Fl_n:
<<: *integer
description: Number of Fl_Kp for gain scheduling
Fl_Kp:
<<: *real
description: Nacelle velocity proportional feedback gain [s]
allocatable: True
Fl_U:
<<: *real
description: Wind speeds for scheduling Fl_Kp [m/s]
allocatable: True

# Trailing edge flaps
Flp_Mode:
Expand Down Expand Up @@ -494,30 +502,6 @@ ControlParameters:
allocatable: True
description: AWC clocking angle [deg]

# Active wake control
AWC_Mode:
<<: *integer
description: Active wake control mode [0 - unused, 1 - SNL method, 2 - NREL method]
AWC_NumModes:
<<: *integer
description: AWC- Number of modes to include [-]
AWC_n:
<<: *integer
allocatable: True
description: AWC azimuthal mode [-]
AWC_freq:
<<: *real
allocatable: True
description: AWC frequency [Hz]
AWC_amp:
<<: *real
allocatable: True
description: AWC amplitude [deg]
AWC_clockangle:
<<: *real
allocatable: True
description: AWC clocking angle [deg]

# Pitch actuator error
PF_Mode:
<<: *integer
Expand Down Expand Up @@ -1017,6 +1001,9 @@ LocalVariables:
TestType:
<<: *real
description: Test variable, no use
Kp_Float:
<<: *real
description: Local, instantaneous Kp_Float, scheduled on wind speed, if desired
VS_MaxTq:
<<: *real
description: Maximum allowable generator torque [Nm].
Expand Down
Loading