Skip to content

Commit

Permalink
Pull ROSCO mhk
Browse files Browse the repository at this point in the history
  • Loading branch information
dzalkind committed Aug 21, 2023
2 parents b3fb63f + ba3daf6 commit 5dc6c21
Show file tree
Hide file tree
Showing 106 changed files with 24,570 additions and 1,048 deletions.
4 changes: 2 additions & 2 deletions ROSCO/.github/workflows/CI_rosco-pytools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ jobs:
# Install OpenFAST
- name: Install OpenFAST
run: |
conda install openfast==3.4
conda install openfast==3.5
# Run examples
- name: Run examples
Expand Down Expand Up @@ -194,7 +194,7 @@ jobs:
# Install OpenFAST
- name: Install OpenFAST
run: |
conda install openfast==3.4
conda install openfast==3.5
# Run ROSCO Testing
- name: Run ROSCO testing
Expand Down
2 changes: 1 addition & 1 deletion ROSCO/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 ROSCO/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 ROSCO/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 ROSCO/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 ROSCO/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 ROSCO/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 ROSCO/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
18 changes: 17 additions & 1 deletion ROSCO/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 Expand Up @@ -145,6 +145,22 @@
fastout = op.load_fast_out(out_file, tmin=0)
fig, ax = op.plot_fast_out(cases=cases,showplot=False)

# Check that open loop commands are close to control outputs from OpenFAST
fo = fastout[0]
tt = fo['Time']
valid_ind = tt > 2 # first few timesteps can differ, depending on OpenFAST solve config

# Computer errors
nacelle_yaw_diff = fo['NacYaw'][valid_ind] - np.degrees(np.interp(tt[valid_ind],olc.ol_timeseries['time'],olc.ol_timeseries['nacelle_yaw']))
bld_pitch_diff = fo['BldPitch1'][valid_ind] - np.degrees(np.interp(tt[valid_ind],olc.ol_timeseries['time'],olc.ol_timeseries['blade_pitch']))
gen_tq_diff = fo['GenTq'][valid_ind] - np.interp(tt[valid_ind],olc.ol_timeseries['time'],olc.ol_timeseries['generator_torque'])/1e3

# Check diff timeseries
np.testing.assert_allclose(nacelle_yaw_diff, 0, atol = 1e-1) # yaw has dynamics and integration error, tolerance higher
np.testing.assert_allclose(bld_pitch_diff, 0, atol = 1e-3)
np.testing.assert_allclose(gen_tq_diff, 0, atol = 1e-3)


if False:
plt.show()
else:
Expand Down
3 changes: 1 addition & 2 deletions ROSCO/Examples/16_external_dll.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def main():
# Set DLL file and DISCON input dynamically (hard-coded in yaml)
controller_params = {}
controller_params['DISCON'] = {}
controller_params['OL_Mode'] = 2
controller_params['DISCON']['DLL_FileName'] = copy_lib
controller_params['DISCON']['DLL_InFile'] = os.path.join(rosco_dir,'Test_Cases/NREL-5MW/DISCON.IN')
controller_params['DISCON']['DLL_ProcName'] = 'DISCON'
Expand All @@ -65,4 +64,4 @@ def main():


if __name__=="__main__":
main()
main()
1 change: 0 additions & 1 deletion ROSCO/Examples/22_cable_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ def main():
r.controller_params = controller_params
r.save_dir = run_dir
r.rosco_dir = rosco_dir

r.run_FAST()


Expand Down
54 changes: 45 additions & 9 deletions ROSCO/Examples/23_structural_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
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


'''
ROSCO currently supports user-defined hooks for structural control control actuation, if StC_Mode = 1.
The control logic can be determined in Controllers.f90 with the StructrualControl subroutine.
In the DISCON input, users must specify StC_GroupIndex relating to the control ChannelID.
These indices can be found in the ServoDyn summary file (*SrvD.sum)
In the example below (and hard-coded in ROSCO) a step change of -4e5 N on the first structural controller
is applied at 50 sec.
In the example below, we implement a smooth step change mimicing the exchange of ballast from the
upwind column to the down wind columns
The develop branch (as of Mar 3, 2023) of OpenFAST (v3.5.0, upcoming) is required to run this example
OpenFAST v3.5.0 is required to run this example
'''


Expand Down Expand Up @@ -65,6 +67,41 @@ def main():
for StC_file in reader.fst_vt['ServoDyn']['SStCfiles']:
reader.fst_vt['SStC'].append(reader.read_StC(StC_file))

# Set up open loop inputs to ROSCO
t_trans = 60
t_sigma = 80
t_max = 200

applied_force = [-2e6, 1e6, 1e6]

olc = OpenLoopControl(t_max=t_max)
olc.interp_timeseries(
'struct_control_1',
[0,t_trans,t_trans+t_sigma],
[0,0,applied_force[0]] ,
'sigma'
)

olc.interp_timeseries(
'struct_control_2',
[0,t_trans,t_trans+t_sigma],
[0,0,applied_force[1]] ,
'sigma'
)

olc.interp_timeseries(
'struct_control_3',
[0,t_trans,t_trans+t_sigma],
[0,0,applied_force[2]] ,
'sigma'
)


ol_params = olc.write_input(os.path.join(run_dir,'open_loop_ballast.dat'))

controller_params = {}
controller_params['open_loop'] = ol_params
controller_params['StC_Mode'] = 2

# simulation set up
r = run_FAST_ROSCO()
Expand All @@ -73,16 +110,15 @@ def main():
r.wind_case_fcn = cl.power_curve
r.wind_case_opts = {
'U': [9],
'T_max': 100,
'TMax': t_max,
}
r.case_inputs = {}
r.fst_vt = reader.fst_vt
r.save_dir = run_dir
r.rosco_dir = rosco_dir

r.fst_vt = reader.fst_vt
r.save_dir = run_dir
r.rosco_dir = rosco_dir
r.controller_params = controller_params
r.run_FAST()



if __name__=="__main__":
main()
Loading

0 comments on commit 5dc6c21

Please sign in to comment.