Skip to content

Commit

Permalink
Squashed 'ROSCO/' changes from e3b7db779..e710c24e1
Browse files Browse the repository at this point in the history
e710c24e1 Add MoorDyn outlist params to FstOutput
c18ef4ccf Sync FAST_vars_out more
a395365de Remove duplicated F_NotchType check
eece1594d Add nodes to vartree
217d3b5e3 Add nodes to FAST_vars_out
53153121c Increment openfast version in CI
c2690c2d9 Sync FAST_reader/writer with WEIS versions
b8011a0b6 Merge remote-tracking branch 'rudy/develop' into of350
9a9fd5377 Merge remote-tracking branch 'rudy/main' into of350
83ad87b2a Revert CI back to conda
ff42e2814 Remove petsc and mpi
890125b45 Update mamba install in CI
3d9cb5bcb Merge branch 'develop' into bf/ol_yaw_rate
5fd97e254 Increment version number
12f8fdb4b Merge remote-tracking branch 'upstream/main' into develop
2411b55a1 Update FAST_writer.py
ca9d0d6d5 Update FAST_reader.py
7d89b79e6 Update StC-Force-Col3.dat
f75f74cb8 Update StC-Force-Col2.dat
3c6326b8a Update StC-Force-Col1.dat
fa442dc09 Update NREL-2p8-127_InflowFile.dat
40729f711 Update NRELOffshrBsline5MW_InflowWind.dat
d898709c8 Update IEA-15-240-RWT_InflowFile.dat
75054db7e Update NREL-2p8-127_InflowFile.dat
f67f301cf Update NREL-2p8-127_InflowFile.dat
5f9dd590b Update BAR_10_InflowFile.dat
265bb46a5 Update NRELOffshrBsline5MW_InflowWind.dat
bd250e536 Update IEA-15-240-RWT_InflowFile.dat
1039f72f2 Update BAR_10_InflowFile.dat
1ced5b0ae Clean up CI scripts
5910fa659 Remove conda installs from rosco-compile
0586e3955 Use environment.yml file
e8d5cf472 Use mamba in compile, too
7e946136c Remove more potential typos
8a4ef64b4 Remove potential libpython typo
716579685 Install extras when environment first set up
3d28f0bc6 Update CI to use mamba, first attempt
5e2430e7c Check OL outputs in example
656ea40b5 Add back open loop yaw rate control
79426f799 Increment version number
339ad5391 Tidy example output
585e2c8b1 Open loop platform control (WISDEM#236)
de15e52d4 Various bug fixes (WISDEM#233)
5a7046f70 Active Wake Control (WISDEM#230)
1ccc1b36b Platform control and Optional Inputs (WISDEM#227)
a7d33035f Merge remote-tracking branch 'upstream/main' into develop
42525a98a V270 prep (WISDEM#218)
a1cf97bbe Rename examples (WISDEM#215)
3155b63dd Add script for updating DISCON versions (WISDEM#214)
e554c1da0 IPC Saturation Fix [RAAW] (WISDEM#210)
be28641f1 Allow PA_Mode 1 (WISDEM#213)
05d7b3b94 Compatibility with Numpy v1.24 (WISDEM#208)
9d27a333b OpenFAST v3.3.0 (WISDEM#202)
5ad1d4109 Doc fix (WISDEM#200)
827b2814f Update sim.py (WISDEM#196)
602332eac Various Bug Fixes (WISDEM#188)
9384f0307 Added feature to read AeroDyn 14 files also for the case without tower influence. (WISDEM#177)
decd69470 Various Bug Fixes (WISDEM#167)
2efac8480 Adding pitch actuator fault (WISDEM#163)

git-subtree-dir: ROSCO
git-subtree-split: e710c24e16046f2a310993f1de4a7975cdb28ee1
  • Loading branch information
dzalkind committed Jun 15, 2023
1 parent e64e4e9 commit bf98f3b
Show file tree
Hide file tree
Showing 15 changed files with 1,788 additions and 102 deletions.
4 changes: 2 additions & 2 deletions .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
16 changes: 16 additions & 0 deletions Examples/14_open_loop_control.py
Original file line number Diff line number Diff line change
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
8 changes: 8 additions & 0 deletions ROSCO/src/Controllers.f90
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ SUBROUTINE YawRateControl(avrSWAP, CntrPar, LocalVar, objInst, zmqVar, DebugVar,
! Output yaw rate command in rad/s
avrSWAP(48) = YawRateCom * D2R

! If using open loop yaw rate control, overwrite controlled output
! Open loop torque control
IF ((CntrPar%OL_Mode == 1) .AND. (CntrPar%Ind_YawRate > 0)) THEN
IF (LocalVar%Time >= CntrPar%OL_Breakpoints(1)) THEN
avrSWAP(48) = interp1d(CntrPar%OL_Breakpoints,CntrPar%OL_YawRate,LocalVar%Time, ErrVar)
ENDIF
ENDIF

! Save for debug
DebugVar%YawRateCom = YawRateCom
DebugVar%NacHeadingTarget = NacHeadingTarget
Expand Down
6 changes: 0 additions & 6 deletions ROSCO/src/ReadSetParameters.f90
Original file line number Diff line number Diff line change
Expand Up @@ -738,12 +738,6 @@ SUBROUTINE CheckInputs(LocalVar, CntrPar, avrSWAP, ErrVar, size_avcMSG)
ErrVar%ErrMsg = 'F_NotchType must be 0, 1, 2, or 3.'
ENDIF

! F_NotchType
IF ((CntrPar%F_NotchType < 0) .OR. (CntrPar%F_NotchType > 2)) THEN
ErrVar%aviFAIL = -1
ErrVar%ErrMsg = 'F_NotchType must be 0, 1, or 2.'
ENDIF

! IPC_ControlMode
IF ((CntrPar%IPC_ControlMode < 0) .OR. (CntrPar%IPC_ControlMode > 2)) THEN
ErrVar%aviFAIL = -1
Expand Down
94 changes: 91 additions & 3 deletions ROSCO_toolbox/ofTools/fast_io/FAST_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,30 @@ def read_ElastoDyn(self, ed_file):
self.set_outlist(self.fst_vt['outlist']['ElastoDyn'], channel_list)

data = f.readline()

# ElastoDyn optional outlist
try:
f.readline()
self.fst_vt['ElastoDyn']['BldNd_BladesOut'] = int(f.readline().split()[0])
self.fst_vt['ElastoDyn']['BldNd_BlOutNd'] = f.readline().split()[0]

f.readline()
data = f.readline()
while data.split()[0] != 'END':
if data.find('"')>=0:
channels = data.split('"')
opt_channel_list = channels[1].split(',')
else:
row_string = data.split(',')
if len(row_string)==1:
opt_channel_list = row_string[0].split('\n')[0]
else:
opt_channel_list = row_string
self.set_outlist(self.fst_vt['outlist']['ElastoDyn_Nodes'], opt_channel_list)
data = f.readline()
except:
# The optinal outlist does not exist.
None

f.close()

Expand Down Expand Up @@ -601,6 +625,30 @@ def read_BeamDyn(self, bd_file):
channel_list = channels[1].split(',')
self.set_outlist(self.fst_vt['outlist']['BeamDyn'], channel_list)
data = f.readline()

# BeamDyn optional outlist
try:
f.readline()
# self.fst_vt['BeamDyn']['BldNd_BladesOut'] = int(f.readline().split()[0])
self.fst_vt['BeamDyn']['BldNd_BlOutNd'] = f.readline().split()[0]

f.readline()
data = f.readline()
while data.split()[0] != 'END':
if data.find('"')>=0:
channels = data.split('"')
opt_channel_list = channels[1].split(',')
else:
row_string = data.split(',')
if len(row_string)==1:
opt_channel_list = row_string[0].split('\n')[0]
else:
opt_channel_list = row_string
self.set_outlist(self.fst_vt['outlist']['BeamDyn_Nodes'], opt_channel_list)
data = f.readline()
except:
# The optinal outlist does not exist.
None

f.close()

Expand Down Expand Up @@ -661,6 +709,7 @@ def read_InflowWind(self):
self.fst_vt['InflowWind']['WindType'] = int(f.readline().split()[0])
self.fst_vt['InflowWind']['PropagationDir'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['VFlowAng'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['VelInterpCubic'] = bool_read(f.readline().split()[0])
self.fst_vt['InflowWind']['NWindVel'] = int(f.readline().split()[0])
self.fst_vt['InflowWind']['WindVxiList'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['WindVyiList'] = float_read(f.readline().split()[0])
Expand Down Expand Up @@ -717,6 +766,21 @@ def read_InflowWind(self):
self.fst_vt['InflowWind']['Z0'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['XOffset'] = float_read(f.readline().split()[0])

# LIDAR parameters
f.readline()
self.fst_vt['InflowWind']['SensorType'] = int(f.readline().split()[0])
self.fst_vt['InflowWind']['NumPulseGate'] = int(f.readline().split()[0])
self.fst_vt['InflowWind']['PulseSpacing'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['NumBeam'] = int(f.readline().split()[0])
self.fst_vt['InflowWind']['FocalDistanceX'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['FocalDistanceY'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['FocalDistanceZ'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['RotorApexOffsetPos'] = [idx.strip() for idx in f.readline().split('RotorApexOffsetPos')[0].split(',')]
self.fst_vt['InflowWind']['URefLid'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['MeasurementInterval'] = float_read(f.readline().split()[0])
self.fst_vt['InflowWind']['LidRadialVel'] = bool_read(f.readline().split()[0])
self.fst_vt['InflowWind']['ConsiderHubMotion'] = int(f.readline().split()[0])

# Inflow Wind Output Parameters (inflow_out_params)
f.readline()
self.fst_vt['InflowWind']['SumPrint'] = bool_read(f.readline().split()[0])
Expand Down Expand Up @@ -889,6 +953,30 @@ def read_AeroDyn15(self):
self.set_outlist(self.fst_vt['outlist']['AeroDyn'], channel_list)
data = f.readline()

# AeroDyn15 optional outlist
try:
f.readline()
self.fst_vt['AeroDyn15']['BldNd_BladesOut'] = int(f.readline().split()[0])
self.fst_vt['AeroDyn15']['BldNd_BlOutNd'] = f.readline().split()[0]

f.readline()
data = f.readline()
while data.split()[0] != 'END':
if data.find('"')>=0:
channels = data.split('"')
opt_channel_list = channels[1].split(',')
else:
row_string = data.split(',')
if len(row_string)==1:
opt_channel_list = row_string[0].split('\n')[0]
else:
opt_channel_list = row_string
self.set_outlist(self.fst_vt['outlist']['AeroDyn_Nodes'], opt_channel_list)
data = f.readline()
except:
# The optinal outlist does not exist.
None

f.close()

self.read_AeroDyn15Blade()
Expand Down Expand Up @@ -1082,11 +1170,11 @@ def read_AeroDyn15OLAF(self, olaf_filename):
f.readline()
self.fst_vt['AeroDyn15']['OLAF']['VelocityMethod'] = int_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['TreeBranchFactor']= float_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['PartPerSegment'] = int(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['PartPerSegment'] = int_read(f.readline().split()[0])
f.readline()
f.readline()
self.fst_vt['AeroDyn15']['OLAF']['WrVTk'] = int(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['nVTKBlades'] = int(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['WrVTk'] = int_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['nVTKBlades'] = int_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['VTKCoord'] = int_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['VTK_fps'] = float_read(f.readline().split()[0])
self.fst_vt['AeroDyn15']['OLAF']['nGridOut'] = int_read(f.readline().split()[0])
Expand Down
Loading

0 comments on commit bf98f3b

Please sign in to comment.