Skip to content

Commit

Permalink
Merge branch 'develop' into shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
dzalkind committed Dec 11, 2024
2 parents 2290c24 + da03e56 commit ba1d06a
Show file tree
Hide file tree
Showing 11 changed files with 357 additions and 276 deletions.
3 changes: 3 additions & 0 deletions Examples/04_simple_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,6 @@ def main():
if __name__ == "__main__":
main()

if __name__=='__main__':
main()

4 changes: 4 additions & 0 deletions rosco/controller/rosco_registry/rosco_types.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,10 @@ LocalVariables:
iStatus:
<<: *integer
description: Initialization status
AlreadyInitialized:
<<: *integer
description: Has ROSCO already been initialized (0-no, 1-yes)
equals: 0
RestartWSE:
<<: *integer
description: Restart WSE flag, 0 - restart, 1- not, to mirror iStatus
Expand Down
4 changes: 2 additions & 2 deletions rosco/controller/rosco_registry/write_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def write_types(yfile):
for attype in reg[toptype].keys():
f90type = read_type(reg[toptype][attype])
atstr = check_size(reg[toptype], attype)
if reg[toptype][attype]['equals']:
atstr += ' = ' + reg[toptype][attype]['equals']
if reg[toptype][attype]['equals'] is not None:
atstr += ' = ' + str(reg[toptype][attype]['equals'])
file.write(' {:<25s} :: {:<25s} ! {}\n'.format(f90type, atstr, reg[toptype][attype]['description']))
file.write('END TYPE {}\n'.format(toptype))
file.write('\n')
Expand Down
6 changes: 4 additions & 2 deletions rosco/controller/src/DISCON.F90
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ SUBROUTINE DISCON(avrSWAP, aviFAIL, accINFILE, avcOUTNAME, avcMSG) BIND (C, NAME
END IF

! Read avrSWAP array into derived types/variables
CALL ReadAvrSWAP(avrSWAP, LocalVar, CntrPar)
CALL ReadAvrSWAP(avrSWAP, LocalVar, CntrPar, ErrVar)

! Set Control Parameters
CALL SetParameters(avrSWAP, accINFILE, SIZE(avcMSG), CntrPar, LocalVar, objInst, PerfData, RootName, ErrVar)
IF (ErrVar%aviFAIL >= 0) THEN
CALL SetParameters(avrSWAP, accINFILE, SIZE(avcMSG), CntrPar, LocalVar, objInst, PerfData, RootName, ErrVar)
ENDIF

! Call external controller, if desired
IF (CntrPar%Ext_Mode > 0 .AND. ErrVar%aviFAIL >= 0) THEN
Expand Down
359 changes: 181 additions & 178 deletions rosco/controller/src/ROSCO_IO.f90

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions rosco/controller/src/ROSCO_Types.f90
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ MODULE ROSCO_Types

TYPE, PUBLIC :: LocalVariables
INTEGER(IntKi) :: iStatus ! Initialization status
INTEGER(IntKi) :: AlreadyInitialized = 0 ! Has ROSCO already been initialized (0-no, 1-yes)
INTEGER(IntKi) :: RestartWSE ! Restart WSE flag, 0 - restart, 1- not, to mirror iStatus
REAL(DbKi) :: Time ! Time [s]
REAL(DbKi) :: DT ! Time step [s]
Expand Down
16 changes: 13 additions & 3 deletions rosco/controller/src/ReadSetParameters.f90
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ MODULE ReadSetParameters
CONTAINS
! -----------------------------------------------------------------------------------
! Read avrSWAP array passed from ServoDyn
SUBROUTINE ReadAvrSWAP(avrSWAP, LocalVar, CntrPar)
SUBROUTINE ReadAvrSWAP(avrSWAP, LocalVar, CntrPar, ErrVar)
USE ROSCO_Types, ONLY : LocalVariables

REAL(ReKi), INTENT(INOUT) :: avrSWAP(*) ! The swap array, used to pass data to, and receive data from, the DLL controller.
TYPE(LocalVariables), INTENT(INOUT) :: LocalVar
TYPE(ControlParameters), INTENT(IN) :: CntrPar
TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar

! Allocate Variables:
INTEGER(IntKi) :: K ! Index used for looping through blades.
Expand Down Expand Up @@ -80,9 +81,18 @@ SUBROUTINE ReadAvrSWAP(avrSWAP, LocalVar, CntrPar)

ENDIF

! GenTemp = avrSWAP(1026)

! WRITE(1000,*) LocalVar%GenSpeed*RPS2RPM, GenTemp
! Check that we haven't already loaded this dynamic library
IF (LocalVar%iStatus == 0) THEN
IF (LocalVar%AlreadyInitialized == 0) THEN
LocalVar%AlreadyInitialized = 1
ELSE
ErrVar%aviFAIL = -1
ErrVar%ErrMsg = 'ERROR: This ROSCO dynamic library has already been loaded.'
RETURN
ENDIF
ENDIF




Expand Down
34 changes: 34 additions & 0 deletions rosco/test/test_initialization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'''
Unit testing for ROSCO
Tests:
initialization
'''

import os
import unittest


# ROSCO toolbox modules
from rosco import discon_lib_path
from rosco.toolbox import control_interface as ROSCO_ci


class UnitTesting(unittest.TestCase):
def test_initialization(self):

this_dir = os.path.dirname(os.path.abspath(__file__))
param_filename = os.path.join(this_dir,'../../Examples/Test_Cases/IEA-15-240-RWT-UMaineSemi/DISCON-UMaineSemi.IN')


# Load controller library
ci_1 = ROSCO_ci.ControllerInterface(discon_lib_path,param_filename=param_filename,sim_name='sim1')

ci_2 = ROSCO_ci.ControllerInterface(discon_lib_path,param_filename=param_filename,sim_name='sim2')

# Check that the error is as expected
assert("b'ROSCO:ERROR: This ROSCO dynamic library has already been loaded" == str(ci_2.avcMSG.raw).split('.')[0])


if __name__ == "__main__":
unittest.main()
178 changes: 101 additions & 77 deletions rosco/toolbox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def __init__(self, controller_params):
self.Flp_Mode = controller_params['Flp_Mode']
self.PA_Mode = controller_params['PA_Mode']
self.PF_Mode = controller_params['PF_Mode']
self.PRC_Mode = controller_params['PRC_Mode']
self.AWC_Mode = controller_params['AWC_Mode']
self.Ext_Mode = controller_params['Ext_Mode']
self.ZMQ_Mode = controller_params['ZMQ_Mode']
Expand Down Expand Up @@ -145,26 +146,49 @@ def __init__(self, controller_params):
# Open loop parameters: set up and error catching
self.OL_Mode = controller_params['OL_Mode']
self.OL_Filename = controller_params['open_loop']['filename']
self.OL_Ind_Breakpoint = self.OL_Ind_GenTq = self.OL_Ind_YawRate = self.OL_Ind_Azimuth = 0
self.OL_Ind_R_Speed = self.OL_Ind_R_Torque = self.OL_Ind_R_Pitch = 0
self.OL_Ind_BldPitch = [0,0,0]
self.OL_Ind_CableControl = [0]
self.OL_Ind_StructControl = [0]
self.Ind_Breakpoint = self.Ind_GenTq = self.Ind_YawRate = self.Ind_Azimuth = 0
self.Ind_R_Speed = self.Ind_R_Torque = self.Ind_R_Pitch = 0
self.Ind_BldPitch = [0,0,0]
self.Ind_CableControl = [0]
self.Ind_StructControl = [0]
self.OL_BP_Mode = 0

if self.OL_Mode:
ol_params = controller_params['open_loop']

# Apply DISCON inputs if they exist
if 'OL_Filename' in controller_params['DISCON']:
ol_params['filename'] = controller_params['DISCON']['OL_Filename']

available_ol_params = [
'OL_BP_Mode',
'Ind_Breakpoint',
'Ind_BldPitch',
'Ind_GenTq',
'Ind_YawRate',
'Ind_Azimuth',
'Ind_R_Speed',
'Ind_R_Torque',
'Ind_R_Pitch',
'Ind_CableControl',
'Ind_StructControl'
]
for param in available_ol_params:
if param in controller_params['DISCON']:
ol_params[param] = controller_params['DISCON'][param]


self.OL_BP_Mode = ol_params['OL_BP_Mode']
self.OL_Ind_Breakpoint = ol_params['OL_Ind_Breakpoint']
self.OL_Ind_BldPitch = ol_params['OL_Ind_BldPitch']
self.OL_Ind_GenTq = ol_params['OL_Ind_GenTq']
self.OL_Ind_YawRate = ol_params['OL_Ind_YawRate']
self.OL_Ind_Azimuth = ol_params['OL_Ind_Azimuth']
self.OL_Ind_R_Speed = ol_params['OL_Ind_R_Speed']
self.OL_Ind_R_Torque = ol_params['OL_Ind_R_Torque']
self.OL_Ind_R_Pitch = ol_params['OL_Ind_R_Pitch']
self.OL_Ind_CableControl = ol_params['OL_Ind_CableControl']
self.OL_Ind_StructControl = ol_params['OL_Ind_StructControl']
self.Ind_Breakpoint = ol_params['Ind_Breakpoint']
self.Ind_BldPitch = ol_params['Ind_BldPitch']
self.Ind_GenTq = ol_params['Ind_GenTq']
self.Ind_YawRate = ol_params['Ind_YawRate']
self.Ind_Azimuth = ol_params['Ind_Azimuth']
self.Ind_R_Speed = ol_params['Ind_R_Speed']
self.Ind_R_Torque = ol_params['Ind_R_Torque']
self.Ind_R_Pitch = ol_params['Ind_R_Pitch']
self.Ind_CableControl = ol_params['Ind_CableControl']
self.Ind_StructControl = ol_params['Ind_StructControl']

# Check that file exists because we won't write it
if not os.path.exists(controller_params['open_loop']['filename']):
Expand Down Expand Up @@ -873,11 +897,11 @@ def write_input(self,ol_filename):
ol_series = self.ol_series

# Init indices
OL_Ind_Breakpoint = 1
OL_Ind_Azimuth = OL_Ind_GenTq = OL_Ind_YawRate = OL_Ind_R_Speed = OL_Ind_R_Torque = OL_Ind_R_Pitch = 0
OL_Ind_BldPitch = 3*[0]
OL_Ind_CableControl = []
OL_Ind_StructControl = []
Ind_Breakpoint = 1
Ind_Azimuth = Ind_GenTq = Ind_YawRate = Ind_R_Speed = Ind_R_Torque = Ind_R_Pitch = 0
Ind_BldPitch = 3*[0]
Ind_CableControl = []
Ind_StructControl = []

ol_index_counter = 0 # start input index at 2

Expand All @@ -902,34 +926,34 @@ def write_input(self,ol_filename):

# Set open loop index based on name
if channel == 'time':
OL_Ind_Breakpoint = ol_index_counter
Ind_Breakpoint = ol_index_counter
skip_write = True
elif channel == 'wind_speed':
OL_Ind_Breakpoint = ol_index_counter
Ind_Breakpoint = ol_index_counter
skip_write = True
elif channel == 'blade_pitch': # collective blade pitch
OL_Ind_BldPitch = 3 * [ol_index_counter]
Ind_BldPitch = 3 * [ol_index_counter]
elif channel == 'generator_torque':
OL_Ind_GenTq = ol_index_counter
Ind_GenTq = ol_index_counter
elif channel == 'nacelle_yaw_rate':
OL_Ind_YawRate = ol_index_counter
Ind_YawRate = ol_index_counter
elif channel == 'nacelle_yaw':
ol_index_counter -= 1 # don't increment counter
skip_write = True
elif channel == 'blade_pitch1':
OL_Ind_BldPitch[0] = ol_index_counter
Ind_BldPitch[0] = ol_index_counter
elif channel == 'blade_pitch2':
OL_Ind_BldPitch[1] = ol_index_counter
Ind_BldPitch[1] = ol_index_counter
elif channel == 'blade_pitch3':
OL_Ind_BldPitch[2] = ol_index_counter
Ind_BldPitch[2] = ol_index_counter
elif channel == 'azimuth':
OL_Ind_Azimuth = ol_index_counter
Ind_Azimuth = ol_index_counter
elif channel == 'R_speed':
OL_Ind_R_Speed = ol_index_counter
Ind_R_Speed = ol_index_counter
elif channel == 'R_torque':
OL_Ind_R_Torque = ol_index_counter
Ind_R_Torque = ol_index_counter
elif channel == 'R_pitch':
OL_Ind_R_Pitch = ol_index_counter
Ind_R_Pitch = ol_index_counter
elif 'cable_control' in channel or 'struct_control' in channel:
skip_write = True
ol_index_counter -= 1 # don't increment counter
Expand All @@ -952,7 +976,7 @@ def write_input(self,ol_filename):
# Let's assume they are 1-indexed and all there, otherwise a key error will be thrown
for cable_chan in cable_chan_names:
ol_input_matrix = np.c_[ol_input_matrix,ol_series[cable_chan]]
OL_Ind_CableControl.append(ol_index_counter)
Ind_CableControl.append(ol_index_counter)
ol_index_counter += 1

# Struct control
Expand All @@ -964,7 +988,7 @@ def write_input(self,ol_filename):
# Let's assume they are 1-indexed and all there, otherwise a key error will be thrown
for i_chan in range(1,n_struct_chan+1):
ol_input_matrix = np.c_[ol_input_matrix,ol_series[f'struct_control_{i_chan}']]
OL_Ind_StructControl.append(ol_index_counter)
Ind_StructControl.append(ol_index_counter)
ol_index_counter += 1


Expand All @@ -991,55 +1015,55 @@ def write_input(self,ol_filename):
units[0] = 'm/s'


if OL_Ind_GenTq:
headers[OL_Ind_GenTq-1] = 'GenTq'
units[OL_Ind_GenTq-1] = '(Nm)'
if Ind_GenTq:
headers[Ind_GenTq-1] = 'GenTq'
units[Ind_GenTq-1] = '(Nm)'

if OL_Ind_YawRate:
headers[OL_Ind_YawRate-1] = 'YawRate'
units[OL_Ind_YawRate-1] = '(rad/s)'
if Ind_YawRate:
headers[Ind_YawRate-1] = 'YawRate'
units[Ind_YawRate-1] = '(rad/s)'

if OL_Ind_Azimuth:
headers[OL_Ind_Azimuth-1] = 'Azimuth'
units[OL_Ind_Azimuth-1] = '(rad)'
if Ind_Azimuth:
headers[Ind_Azimuth-1] = 'Azimuth'
units[Ind_Azimuth-1] = '(rad)'

if any(OL_Ind_BldPitch):
if all_same(OL_Ind_BldPitch):
headers[OL_Ind_BldPitch[0]-1] = 'BldPitch123'
units[OL_Ind_BldPitch[0]-1] = '(rad)'
if any(Ind_BldPitch):
if all_same(Ind_BldPitch):
headers[Ind_BldPitch[0]-1] = 'BldPitch123'
units[Ind_BldPitch[0]-1] = '(rad)'
else:
headers[OL_Ind_BldPitch[0]-1] = 'BldPitch1'
units[OL_Ind_BldPitch[0]-1] = '(rad)'
headers[OL_Ind_BldPitch[1]-1] = 'BldPitch2'
units[OL_Ind_BldPitch[1]-1] = '(rad)'
headers[OL_Ind_BldPitch[2]-1] = 'BldPitch3'
units[OL_Ind_BldPitch[2]-1] = '(rad)'

if OL_Ind_CableControl:
headers[Ind_BldPitch[0]-1] = 'BldPitch1'
units[Ind_BldPitch[0]-1] = '(rad)'
headers[Ind_BldPitch[1]-1] = 'BldPitch2'
units[Ind_BldPitch[1]-1] = '(rad)'
headers[Ind_BldPitch[2]-1] = 'BldPitch3'
units[Ind_BldPitch[2]-1] = '(rad)'

if Ind_CableControl:
for i_chan in range(1,n_cable_chan+1):
header_line += f'\t\tCable{i_chan}'
unit_line += '\t\t(m)'
else:
OL_Ind_CableControl = [0]
Ind_CableControl = [0]

if OL_Ind_StructControl:
if Ind_StructControl:
for i_chan in range(1,n_struct_chan+1):
header_line += f'\t\tStruct{i_chan}'
unit_line += '\t\t(m)'
else:
OL_Ind_StructControl = [0]
Ind_StructControl = [0]

if OL_Ind_R_Speed:
headers[OL_Ind_R_Speed-1] = 'R_speed'
units[OL_Ind_R_Speed-1] = '(-)'
if Ind_R_Speed:
headers[Ind_R_Speed-1] = 'R_speed'
units[Ind_R_Speed-1] = '(-)'

if OL_Ind_R_Torque:
headers[OL_Ind_R_Torque-1] = 'R_Torque'
units[OL_Ind_R_Torque-1] = '(-)'
if Ind_R_Torque:
headers[Ind_R_Torque-1] = 'R_Torque'
units[Ind_R_Torque-1] = '(-)'

if OL_Ind_R_Pitch:
headers[OL_Ind_R_Pitch-1] = 'R_Pitch'
units[OL_Ind_R_Pitch-1] = '(-)'
if Ind_R_Pitch:
headers[Ind_R_Pitch-1] = 'R_Pitch'
units[Ind_R_Pitch-1] = '(-)'

# Join headers and units
header_line = '!' + '\t\t'.join(headers) + '\n'
Expand All @@ -1056,16 +1080,16 @@ def write_input(self,ol_filename):
# Output open_loop dict for control params
open_loop = {}
open_loop['filename'] = ol_filename
open_loop['OL_Ind_Breakpoint'] = OL_Ind_Breakpoint
open_loop['OL_Ind_BldPitch'] = OL_Ind_BldPitch
open_loop['OL_Ind_GenTq'] = OL_Ind_GenTq
open_loop['OL_Ind_YawRate'] = OL_Ind_YawRate
open_loop['OL_Ind_Azimuth'] = OL_Ind_Azimuth
open_loop['OL_Ind_CableControl'] = OL_Ind_CableControl
open_loop['OL_Ind_StructControl'] = OL_Ind_StructControl
open_loop['OL_Ind_R_Speed'] = OL_Ind_R_Speed
open_loop['OL_Ind_R_Torque'] = OL_Ind_R_Torque
open_loop['OL_Ind_R_Pitch'] = OL_Ind_R_Pitch
open_loop['Ind_Breakpoint'] = Ind_Breakpoint
open_loop['Ind_BldPitch'] = Ind_BldPitch
open_loop['Ind_GenTq'] = Ind_GenTq
open_loop['Ind_YawRate'] = Ind_YawRate
open_loop['Ind_Azimuth'] = Ind_Azimuth
open_loop['Ind_CableControl'] = Ind_CableControl
open_loop['Ind_StructControl'] = Ind_StructControl
open_loop['Ind_R_Speed'] = Ind_R_Speed
open_loop['Ind_R_Torque'] = Ind_R_Torque
open_loop['Ind_R_Pitch'] = Ind_R_Pitch
if self.breakpoint == 'time':
open_loop['OL_BP_Mode'] = 0
elif self.breakpoint == 'wind_speed':
Expand Down
Loading

0 comments on commit ba1d06a

Please sign in to comment.