diff --git a/.github/workflows/CI_rosco-toolbox.yml b/.github/workflows/CI_rosco-toolbox.yml index bf024e04c..d4a8780a8 100644 --- a/.github/workflows/CI_rosco-toolbox.yml +++ b/.github/workflows/CI_rosco-toolbox.yml @@ -96,11 +96,62 @@ jobs: # Install OpenFAST - name: Install OpenFAST run: | - conda install openfast==2.5.0 + conda install openfast==3.0.0 # Run examples - name: Run examples run: | cd Examples python run_examples.py + + run_testing: + name: Run Testing + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: ["ubuntu-latest"] #, "macOS-latest"] + python-version: ["3.8"] + defaults: + run: + shell: bash -l {0} + + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Setup environment + uses: conda-incubator/setup-miniconda@v2 + with: + miniconda-version: "latest" + channels: conda-forge, general + auto-update-conda: true + python-version: 3.8 + environment-file: environment.yml + + + # Install dependencies of ROSCO toolbox + - name: Add dependencies ubuntu specific + if: false == contains( matrix.os, 'windows') + run: | + conda install -y compilers + conda install -y wisdem + + + # Install ROSCO toolbox + - name: Install ROSCO toolbox + run: | + python setup.py develop --compile-rosco + # Install OpenFAST + - name: Install OpenFAST + run: | + conda install openfast==3.0.0 + + # Run Testing + - name: Run testing + run: | + cd ROSCO_testing + python ROSCO_testing.py \ No newline at end of file diff --git a/.github/workflows/publish_to_pypi.yml b/.github/workflows/publish_to_pypi.yml new file mode 100644 index 000000000..096085a14 --- /dev/null +++ b/.github/workflows/publish_to_pypi.yml @@ -0,0 +1,27 @@ +name: Upload to PyPi + +on: + release: + types: [released] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + if: startsWith(github.ref, 'refs/tags') + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index d9da4963b..0a63e2c3c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "ROSCO"] path = ROSCO url = https://github.com/NREL/ROSCO - branch = main \ No newline at end of file + branch = main diff --git a/README.md b/README.md index d300aa345..1783ed47f 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,22 @@ The NREL Reference OpenSource Controller (ROSCO) provides an open, modular and f ## 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. +## Survey +Please help us better understand the ROSCO user-base and how we can improve rosco through this brief survey: +[ROSCO toolchain survey](https://forms.office.com/Pages/ResponsePage.aspx?id=fp3yoM0oVE-EQniFrufAgGWnC45k8q5Kl90RBkHijqBUN0JTNzBJT1QwMjIzNDhCWDlDTUZPWDdMWC4u) + ## Referencing If the ROSCO Toolbox played a role in your research, please cite it. This software can be cited as: - NREL: ROSCO Toolbox. Version 2.2.0, https://github.com/NREL/rosco_toolbox, 2021. + NREL: ROSCO Toolbox. Version 2.3.0, https://github.com/NREL/rosco_toolbox, 2021. For LaTeX users: ``` @misc{ROSCO_toolbox_2021, author = {NREL}, - title = {{ROSCO Toolbox. Version 2.2.0}}, + title = {{ROSCO Toolbox. Version 2.3.0}}, year = {2021}, publisher = {GitHub}, journal = {GitHub repository}, diff --git a/ROSCO b/ROSCO index e53ff37a5..7e100154b 160000 --- a/ROSCO +++ b/ROSCO @@ -1 +1 @@ -Subproject commit e53ff37a50ced633873a324386f279404953fe52 +Subproject commit 7e100154bb8fad0fa10e7bca826d7ee1b68192b1 diff --git a/ROSCO_testing/ROSCO_testing.py b/ROSCO_testing/ROSCO_testing.py index 4aa7675e0..2380ac961 100644 --- a/ROSCO_testing/ROSCO_testing.py +++ b/ROSCO_testing/ROSCO_testing.py @@ -13,7 +13,7 @@ ''' import numpy as np -import os +import os, platform import glob import multiprocessing as mp @@ -37,7 +37,7 @@ def __init__(self, **kwargs): # Setup simulation parameters self.runDir = os.path.join(os.path.dirname( os.path.realpath(__file__) ), 'testing' ) # directory to run simulations in - self.windDir = None + self.wind_dir = None self.namebase = 'ROtest' # root name for output simulations self.FAST_exe = 'openfast_single' # name of openfast executable (may need full path) self.Turbsim_exe = 'turbsim_single' # name of turbsim executable @@ -54,6 +54,7 @@ def __init__(self, **kwargs): self.mpi_run = False self.mpi_comm_map_down = [] self.outfile_fmt = 2 # 1 = .txt, 2 = binary, 3 = both + self.comp_dir = None # Setup turbine parameters # - Default to NREL 5MW @@ -104,9 +105,9 @@ def ROSCO_Test_lite(self, more_case_inputs={}, U=[]): # Check for time and wind inputs if ('Fst','TMax') in more_case_inputs.keys(): - TMax = np.max(more_case_inputs[('Fst','TMax')]['vals']) + self.TMax = np.max(more_case_inputs[('Fst','TMax')]['vals']) else: - TMax = 330 + self.TMax = 330 if len(U) > 0: WindSpeeds = U @@ -135,7 +136,7 @@ def ROSCO_Test_lite(self, more_case_inputs={}, U=[]): iec.Turbulence_Class = self.Turbulence_Class iec.D = fastRead.fst_vt['ElastoDyn']['TipRad']*2. iec.z_hub = fastRead.fst_vt['InflowWind']['RefHt'] - iec.TMax = TMax + iec.TMax = self.TMax iec.dlc_inputs = {} iec.dlc_inputs['DLC'] = [1.1] # ,6.1,6.3] @@ -145,8 +146,8 @@ def ROSCO_Test_lite(self, more_case_inputs={}, U=[]): iec.transient_dir_change = '-' # '+','-','both': sign for transient events in EDC, EWS iec.transient_shear_orientation = 'v' # 'v','h','both': vertical or horizontal shear for EWS - if self.windDir: - iec.wind_dir = self.windDir + if self.wind_dir: + iec.wind_dir = self.wind_dir else: iec.wind_dir = os.path.join(self.runDir, 'wind') @@ -168,7 +169,7 @@ def ROSCO_Test_lite(self, more_case_inputs={}, U=[]): iec.comm_map_down = mpi_comm_map_down case_inputs = {} - case_inputs[("Fst", "TMax")] = {'vals': [TMax], 'group': 0} + case_inputs[("Fst", "TMax")] = {'vals': [self.TMax], 'group': 0} case_inputs[("Fst", "OutFileFmt")] = {'vals': [self.outfile_fmt], 'group': 0} case_inputs[('ServoDyn', 'GenTiStr')] = {'vals': ['True'], 'group': 0} @@ -258,9 +259,9 @@ def ROSCO_Test_heavy(self, more_case_inputs={}, U=[]): # Check for time and wind inputs if ('Fst','TMax') in more_case_inputs.keys(): - TMax = np.max(more_case_inputs[('Fst','TMax')]['vals']) + self.TMax = np.max(more_case_inputs[('Fst','TMax')]['vals']) else: - TMax = 630 + self.TMax = 630 if len(U) > 0: WindSpeeds = U @@ -299,7 +300,7 @@ def ROSCO_Test_heavy(self, more_case_inputs={}, U=[]): iec.Turbulence_Class = self.Turbulence_Class iec.D = fastRead.fst_vt['ElastoDyn']['TipRad']*2. iec.z_hub = fastRead.fst_vt['InflowWind']['RefHt'] - iec.TMax = TMax + iec.TMax = self.TMax iec.dlc_inputs = {} iec.dlc_inputs['DLC'] = [1.3, 1.4] @@ -311,8 +312,8 @@ def ROSCO_Test_heavy(self, more_case_inputs={}, U=[]): iec.uniqueSeeds = True iec.uniqueWaveSeeds = True - if self.windDir: - iec.wind_dir = self.windDir + if self.wind_dir: + iec.wind_dir = self.wind_dir else: iec.wind_dir = os.path.join(self.runDir, 'wind') iec.case_name_base = self.namebase @@ -333,7 +334,7 @@ def ROSCO_Test_heavy(self, more_case_inputs={}, U=[]): iec.comm_map_down = mpi_comm_map_down case_inputs = {} - case_inputs[("Fst", "TMax")] = {'vals': [TMax], 'group': 0} + case_inputs[("Fst", "TMax")] = {'vals': [self.TMax], 'group': 0} case_inputs[("Fst", "OutFileFmt")] = {'vals': [self.outfile_fmt], 'group': 0} case_inputs[('ServoDyn', 'GenTiStr')] = {'vals': ['False'], 'group': 0} @@ -421,13 +422,13 @@ def ROSCO_Controller_Comp(self, controller_paths, testtype='light', more_case_in ''' # Save initial run directory run_dir_init = self.runDir - wind_dir_init = self.windDir + wind_dir_init = self.wind_dir for ci, path in enumerate(controller_paths): # specify rosco path self.rosco_path = path # temporarily change run directories self.runDir = os.path.join(run_dir_init,'controller_{}'.format(ci)) # specific directory for each controller - self.windDir = os.path.join(run_dir_init, 'wind') # wind in base runDir + self.wind_dir = os.path.join(run_dir_init, 'wind') # wind in base runDir if testtype.lower() == 'light': self.ROSCO_Test_lite(more_case_inputs=more_case_inputs, U=U) @@ -438,7 +439,7 @@ def ROSCO_Controller_Comp(self, controller_paths, testtype='light', more_case_in # reset self self.runDir = run_dir_init - self.windDir = wind_dir_init + self.wind_dir = wind_dir_init def ROSCO_DISCON_Comp(self, DISCON_filenames, testtype='light', more_case_inputs={}, U=[]): ''' @@ -454,15 +455,15 @@ def ROSCO_DISCON_Comp(self, DISCON_filenames, testtype='light', more_case_inputs # Save initial run directory run_dir_init = self.runDir - wind_dir_init = self.windDir + wind_dir_init = self.wind_dir for ci, discon in enumerate(DISCON_filenames): # temporarily change run directories self.runDir = os.path.join(run_dir_init, 'controller_{}'.format(ci)) - self.windDir = os.path.join(run_dir_init, 'wind') # wind in base runDir + self.wind_dir = os.path.join(run_dir_init, 'wind') # wind in base runDir # Point to different DISCON.IN files using more_case_inputs more_case_inputs[('ServoDyn', 'DLL_InFile')] = {'vals': [discon], 'group': 0} - self.windDir = os.path.join(run_dir_init, 'wind') # wind in base runDir + self.wind_dir = os.path.join(run_dir_init, 'wind') # wind in base runDir if testtype.lower() == 'light': self.ROSCO_Test_lite(more_case_inputs=more_case_inputs, U=U) @@ -473,20 +474,42 @@ def ROSCO_DISCON_Comp(self, DISCON_filenames, testtype='light', more_case_inputs # reset self self.runDir = run_dir_init - self.windDir = wind_dir_init + self.wind_dir = wind_dir_init def print_results(self,outfiles): + figs_fname = 'test_outputs.pdf' + + # remove initial transients if more than two minutes if simulation time + if self.TMax > 120: + tmin = 60 + else: + tmin = 0 + + # Comparison plot + if self.comp_dir: + tmin = 100 # if comparing, I'd like to start the comparison at 100 seconds + op_comp = output_processing.output_processing() + outfiles_comp = [os.path.join(self.comp_dir,os.path.split(of)[1]) for of in outfiles] + try: + FAST_Comp = op_comp.load_fast_out(outfiles_comp, tmin=tmin) + figs_fname = 'comp_outputs.pdf' + except: + print('Could not load openfast outputs for comparison, only plotting current test') + tmin = 0 + figs_fname = 'test_outputs.pdf' + + op = output_processing.output_processing() - FAST_Output = op.load_fast_out(outfiles, tmin=0) + FAST_Output = op.load_fast_out(outfiles, tmin=tmin) - figs_fname = 'test_outputs.pdf' + with PdfPages(os.path.join(self.runDir,figs_fname)) as pdf: - for fast_out in FAST_Output: + for i_out, fast_out in enumerate(FAST_Output): if self.FAST_InputFile == 'NREL-5MW.fst': plots2make = {'Baseline': ['Wind1VelX', 'GenPwr', 'RotSpeed', 'BldPitch1', 'GenTq']} else: - plots2make = {'Baseline': ['Wind1VelX', 'GenPwr', 'RotSpeed', 'BldPitch1', 'GenTq','PtfmPitch']} + plots2make = {'Baseline': ['Wind1VelX', 'GenPwr', 'RotSpeed', 'BldPitch1', 'GenTq','PtfmPitch','TwrBsMyt']} numplots = len(plots2make) maxchannels = np.max([len(plots2make[key]) for key in plots2make.keys()]) @@ -498,6 +521,9 @@ def print_results(self,outfiles): subplt = fig.add_subplot(gs0[cid]) try: subplt.plot(fast_out['Time'], fast_out[channel]) + if self.comp_dir: + subplt.plot(FAST_Comp[i_out]['Time'], FAST_Comp[i_out][channel]) + unit_idx = fast_out['meta']['channels'].index(channel) subplt.set_ylabel('{:^} \n ({:^})'.format( channel, @@ -522,35 +548,36 @@ def print_results(self,outfiles): ## =================== INITIALIZATION =================== # Setup simulation parameters - rt.runDir = '/Users/nabbas/Documents/Projects/ROSCO_dev/WSE_updates/WSE_Testing' # directory for FAST simulations rt.namebase = 'IEA-15MW' # Base name for FAST files - rt.FAST_exe = '/Users/nabbas/Documents/WindEnergyToolbox/WEIS/local/bin/openfast' # OpenFAST executable path - rt.Turbsim_exe = '/Users/nabbas/openfast/install/bin/turbsim_single' # Turbsim executable path - rt.FAST_ver = 'OpenFAST' # FAST version - rt.rosco_path = ['/Users/nabbas/Documents/WindEnergyToolbox/ROSCO/build-master/libdiscon.dylib', - '/Users/nabbas/Documents/WindEnergyToolbox/ROSCO/build-wse/libdiscon.dylib', - ] # path to compiled ROSCO controller - rt.dev_branch = True # dev branch of Openfast? - rt.debug_level = 2 # debug level. 0 - no outputs, 1 - minimal outputs, 2 - all outputs - rt.overwrite = True # overwite fast sims? - rt.cores = 4 # number of cores if multiprocessings - rt.mpi_run = False # run using mpi - rt.mpi_comm_map_down = [] # core mapping for MPI - rt.outfile_fmt = 2 # 1 = .txt, 2 = binary, 3 = both + rt.FAST_exe = 'openfast' # OpenFAST executable path + rt.Turbsim_exe = 'turbsim' # Turbsim executable path + rt.FAST_ver = 'OpenFAST' # FAST version + # path to compiled ROSCO controller + if platform.system() == 'Windows': + rt.rosco_path = os.path.join(os.getcwd(), '../ROSCO/build/libdiscon.dll') + elif platform.system() == 'Darwin': + rt.rosco_path = os.path.join(os.getcwd(), '../ROSCO/build/libdiscon.dylib') + else: + rt.rosco_path = os.path.join(os.getcwd(), '../ROSCO/build/libdiscon.so') + rt.dev_branch = True # dev branch of Openfast? + rt.debug_level = 2 # debug level. 0 - no outputs, 1 - minimal outputs, 2 - all outputs + rt.overwrite = True # overwite fast sims? + rt.cores = 4 # number of cores if multiprocessings + rt.mpi_run = False # run using mpi + rt.mpi_comm_map_down = [] # core mapping for MPI + rt.outfile_fmt = 2 # 1 = .txt, 2 = binary, 3 = both rt.dev_branch= 'True' - # Post Processing Parameters - reCrunch = True # re-run pCrunch? # Setup turbine rt.Turbine_Class = 'I' rt.Turbulence_Class = 'B' - rt.FAST_directory = '/Users/nabbas/Documents/WindEnergyToolbox/WEIS/examples/OpenFAST_models/IEA-15-240-RWT/IEA-15-240-RWT-Monopile' - rt.FAST_InputFile = 'IEA-15-240-RWT-Monopile.fst' + rt.FAST_directory = os.path.join(os.getcwd(), '../Test_Cases/IEA-15-240-RWT-UMaineSemi') + rt.FAST_InputFile = 'IEA-15-240-RWT-UMaineSemi.fst' # Additional inputs # ---- DT for this test! ---- case_inputs={} - case_inputs[('Fst', 'TMax')] = {'vals': [330], 'group': 0} + case_inputs[('Fst', 'TMax')] = {'vals': [60], 'group': 0} case_inputs[('Fst', 'DT')] = {'vals': [0.01], 'group': 0} case_inputs[('Fst', 'CompElast')] = {'vals': [1], 'group': 0} @@ -563,5 +590,5 @@ def print_results(self,outfiles): U = [5, 9, 12, 15] # Run test - rt.ROSCO_Controller_Comp(rt.rosco_path, testtype='light', more_case_inputs=case_inputs, U=U) + rt.ROSCO_Test_lite(more_case_inputs=case_inputs, U=U) diff --git a/ROSCO_testing/run_Testing.py b/ROSCO_testing/run_Testing.py index 9434c933c..ef201d424 100644 --- a/ROSCO_testing/run_Testing.py +++ b/ROSCO_testing/run_Testing.py @@ -7,6 +7,8 @@ import ROSCO_testing import importlib +os.system("taskset -p 0xffffffffffff %d" % os.getpid()) + def run_testing(turbine2test, testtype, rosco_binaries=[], discon_files=[], **kwargs): ''' @@ -83,22 +85,26 @@ def run_testing(turbine2test, testtype, rosco_binaries=[], discon_files=[], **kw # Setup ROSCO testing parameters rt_kwargs = {} - rt_kwargs['runDir'] = os.path.join(this_dir,'results/IEA-15MW') # directory for FAST simulations - rt_kwargs['namebase'] = 'lite_test' # Base name for FAST files - rt_kwargs['FAST_exe'] = 'openfast' # OpenFAST executable path + rt_kwargs['runDir'] = os.path.join('/scratch/dzalkind/ROSCO_testing','version2.3.0') # directory for FAST simulations + rt_kwargs['namebase'] = 'heavy_test' # Base name for FAST files + rt_kwargs['FAST_exe'] = '/home/dzalkind/Tools/openfast-main/install/bin/openfast' # OpenFAST executable path + rt_kwargs['wind_dir'] = os.path.join('/scratch/dzalkind/ROSCO_testing','wind','IEA-15_heavy') # OpenFAST executable path rt_kwargs['Turbsim_exe']= 'turbsim' # Turbsim executable path rt_kwargs['FAST_ver'] = 'OpenFAST' # FAST version rt_kwargs['dev_branch'] = True # dev branch of Openfast? rt_kwargs['debug_level']= 2 # debug level. 0 - no outputs, 1 - minimal outputs, 2 - all outputs rt_kwargs['overwrite'] = False # overwite fast sims? - rt_kwargs['cores'] = 4 # number of cores if multiprocessing + rt_kwargs['cores'] = 36 # number of cores if multiprocessing rt_kwargs['mpi_run'] = False # run using mpi rt_kwargs['mpi_comm_map_down'] = [] # core mapping for MPI rt_kwargs['outfile_fmt'] = 2 # 1 = .txt, 2 = binary, 3 = both + # rt_kwargs['comp_dir'] = '/projects/ssc/dzalkind/ROSCO/ROSCO_testing/version2.2.0' # 1 = .txt, 2 = binary, 3 = both + rt_kwargs['comp_dir'] = '/scratch/dzalkind/ROSCO_testing/pr_46' # 1 = .txt, 2 = binary, 3 = both + # ---- Define test type ---- turbine2test = 'IEA-15MW' # IEA-15MW or NREL-5MW - testtype = 'lite' # lite, heavy, binary-comp, discon-comp + testtype = 'heavy' # lite, heavy, binary-comp, discon-comp # Only fill one of these if comparing controllers rosco_binaries = [glob.glob(os.path.join(this_dir,'../ROSCO/build/libdiscon.*'))[0]] # Differently named libdiscons to compare diff --git a/ROSCO_testing/submit.sh b/ROSCO_testing/submit.sh index 182cf9a0e..c32de7bde 100644 --- a/ROSCO_testing/submit.sh +++ b/ROSCO_testing/submit.sh @@ -14,13 +14,15 @@ nOF=60 # Number of openfast runs per finite-difference evaluation nC=$((nDV + nDV * nOF)) # Number of cores needed. Make sure to request an appropriate number of nodes = N / 36 ## nC=72 -source activate /home/dzalkind/.conda-envs/weis-env4 -which python +# module load conda +# conda activate rt-env +source activate /home/dzalkind/.conda-envs/rosco-env +# which python # module purge # module load conda # module load comp-intel intel-mpi mkl -python run_Testing.py +mpirun -n 36 python run_Testing.py # python weis_driver.py diff --git a/ROSCO_toolbox/__init__.py b/ROSCO_toolbox/__init__.py index 63c851566..5f3415c42 100644 --- a/ROSCO_toolbox/__init__.py +++ b/ROSCO_toolbox/__init__.py @@ -3,4 +3,4 @@ __author__ = """Nikhar J. Abbas and Daniel S. Zalkind""" __email__ = 'nikhar.abbas@nrel.gov' -__version__ = '2.2.0' \ No newline at end of file +__version__ = '2.3.0' \ No newline at end of file diff --git a/ROSCO_toolbox/ofTools/fast_io/FAST_reader.py b/ROSCO_toolbox/ofTools/fast_io/FAST_reader.py index 310a8ca26..9297464e1 100644 --- a/ROSCO_toolbox/ofTools/fast_io/FAST_reader.py +++ b/ROSCO_toolbox/ofTools/fast_io/FAST_reader.py @@ -1018,7 +1018,7 @@ def read_AeroDyn15(self): self.fst_vt['AeroDyn15']['WakeMod'] = int(f.readline().split()[0]) self.fst_vt['AeroDyn15']['AFAeroMod'] = int(f.readline().split()[0]) self.fst_vt['AeroDyn15']['TwrPotent'] = int(f.readline().split()[0]) - self.fst_vt['AeroDyn15']['TwrShadow'] = bool_read(f.readline().split()[0]) + self.fst_vt['AeroDyn15']['TwrShadow'] = int(f.readline().split()[0]) self.fst_vt['AeroDyn15']['TwrAero'] = bool_read(f.readline().split()[0]) self.fst_vt['AeroDyn15']['FrozenWake'] = bool_read(f.readline().split()[0]) if self.FAST_ver.lower() != 'fast8': @@ -1092,11 +1092,13 @@ def read_AeroDyn15(self): self.fst_vt['AeroDyn15']['TwrElev'] = [None]*self.fst_vt['AeroDyn15']['NumTwrNds'] self.fst_vt['AeroDyn15']['TwrDiam'] = [None]*self.fst_vt['AeroDyn15']['NumTwrNds'] self.fst_vt['AeroDyn15']['TwrCd'] = [None]*self.fst_vt['AeroDyn15']['NumTwrNds'] + self.fst_vt['AeroDyn15']['TwrTI'] = [None]*self.fst_vt['AeroDyn15']['NumTwrNds'] for i in range(self.fst_vt['AeroDyn15']['NumTwrNds']): data = [float(val) for val in f.readline().split()] self.fst_vt['AeroDyn15']['TwrElev'][i] = data[0] self.fst_vt['AeroDyn15']['TwrDiam'][i] = data[1] self.fst_vt['AeroDyn15']['TwrCd'][i] = data[2] + self.fst_vt['AeroDyn15']['TwrTI'][i] = data[3] # Outputs f.readline() @@ -1402,12 +1404,16 @@ def read_ServoDyn(self): self.fst_vt['ServoDyn']['YawManRat'] = float_read(f.readline().split()[0]) self.fst_vt['ServoDyn']['NacYawF'] = float_read(f.readline().split()[0]) - # Tuned Mass Damper (tuned_mass_damper) + # Structural Control f.readline() - self.fst_vt['ServoDyn']['CompNTMD'] = bool_read(f.readline().split()[0]) - self.fst_vt['ServoDyn']['NTMDfile'] = f.readline().split()[0][1:-1] - self.fst_vt['ServoDyn']['CompTTMD'] = bool_read(f.readline().split()[0]) - self.fst_vt['ServoDyn']['TTMDfile'] = f.readline().split()[0][1:-1] + self.fst_vt['ServoDyn']['NumBStC'] = int(f.readline().split()[0]) + self.fst_vt['ServoDyn']['BStCfiles'] = f.readline().split()[0][1:-1] + self.fst_vt['ServoDyn']['NumNStC'] = int(f.readline().split()[0]) + self.fst_vt['ServoDyn']['NStCfiles'] = f.readline().split()[0][1:-1] + self.fst_vt['ServoDyn']['NumTStC'] = int(f.readline().split()[0]) + self.fst_vt['ServoDyn']['TStCfiles'] = f.readline().split()[0][1:-1] + self.fst_vt['ServoDyn']['NumSStC'] = int(f.readline().split()[0]) + self.fst_vt['ServoDyn']['SStCfiles'] = f.readline().split()[0][1:-1] # Bladed Interface and Torque-Speed Look-Up Table (bladed_interface) f.readline() @@ -1572,15 +1578,21 @@ def read_HydroDyn(self): # FLOATING PLATFORM f.readline() self.fst_vt['HydroDyn']['PotMod'] = int_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['ExctnMod'] = int_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['RdtnMod'] = int_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['RdtnTMax'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['RdtnDT'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['NBody'] = int_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['NBodyMod'] = int_read(f.readline().split()[0]) self.fst_vt['HydroDyn']['PotFile'] = os.path.normpath(os.path.join(os.path.split(hd_file)[0], f.readline().split()[0][1:-1])) self.fst_vt['HydroDyn']['WAMITULEN'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['PtfmRefxt'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['PtfmRefyt'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['PtfmRefzt'] = float_read(f.readline().split()[0]) + self.fst_vt['HydroDyn']['PtfmRefztRot'] = float_read(f.readline().split()[0]) self.fst_vt['HydroDyn']['PtfmVol0'] = float_read(f.readline().split()[0]) self.fst_vt['HydroDyn']['PtfmCOBxt'] = float_read(f.readline().split()[0]) self.fst_vt['HydroDyn']['PtfmCOByt'] = float_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['ExctnMod'] = int_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['RdtnMod'] = int_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['RdtnTMax'] = float_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['RdtnDT'] = float_read(f.readline().split()[0]) # 2ND-ORDER FLOATING PLATFORM FORCES f.readline() @@ -1589,18 +1601,9 @@ def read_HydroDyn(self): self.fst_vt['HydroDyn']['DiffQTF'] = int_read(f.readline().split()[0]) # ? self.fst_vt['HydroDyn']['SumQTF'] = int_read(f.readline().split()[0]) # ? - # FLOATING PLATFORM FORCE FLAGS - f.readline() - self.fst_vt['HydroDyn']['PtfmSgF'] = bool_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['PtfmSwF'] = bool_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['PtfmHvF'] = bool_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['PtfmRF'] = bool_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['PtfmPF'] = bool_read(f.readline().split()[0]) - self.fst_vt['HydroDyn']['PtfmYF'] = bool_read(f.readline().split()[0]) - # PLATFORM ADDITIONAL STIFFNESS AND DAMPING f.readline() - self.fst_vt['HydroDyn']['AddF0'] = [float(idx) for idx in f.readline().strip().split()[:6]] + self.fst_vt['HydroDyn']['AddF0'] = np.array([[float(idx) for idx in f.readline().strip().split()[0]] for i in range(6)]) self.fst_vt['HydroDyn']['AddCLin'] = np.array([[float(idx) for idx in f.readline().strip().split()[:6]] for i in range(6)]) self.fst_vt['HydroDyn']['AddBLin'] = np.array([[float(idx) for idx in f.readline().strip().split()[:6]] for i in range(6)]) self.fst_vt['HydroDyn']['AddBQuad'] = np.array([[float(idx) for idx in f.readline().strip().split()[:6]] for i in range(6)]) @@ -1666,10 +1669,12 @@ def read_HydroDyn(self): self.fst_vt['HydroDyn']['SimplCaMG'] = float(ln[3]) self.fst_vt['HydroDyn']['SimplCp'] = float(ln[4]) self.fst_vt['HydroDyn']['SimplCpMG'] = float(ln[5]) - self.fst_vt['HydroDyn']['SimplAxCa'] = float(ln[6]) - self.fst_vt['HydroDyn']['SimplAxCaMG'] = float(ln[7]) - self.fst_vt['HydroDyn']['SimplAxCp'] = float(ln[8]) - self.fst_vt['HydroDyn']['SimplAxCpMG'] = float(ln[9]) + self.fst_vt['HydroDyn']['SimplAxCd'] = float(ln[6]) + self.fst_vt['HydroDyn']['SimplAxCdMG'] = float(ln[7]) + self.fst_vt['HydroDyn']['SimplAxCa'] = float(ln[8]) + self.fst_vt['HydroDyn']['SimplAxCaMG'] = float(ln[9]) + self.fst_vt['HydroDyn']['SimplAxCp'] = float(ln[10]) + self.fst_vt['HydroDyn']['SimplAxCpMG'] = float(ln[11]) #DEPTH-BASED HYDRODYNAMIC COEFFICIENTS f.readline() diff --git a/ROSCO_toolbox/ofTools/fast_io/FAST_writer.py b/ROSCO_toolbox/ofTools/fast_io/FAST_writer.py index bbbe6b0f5..9aee635fe 100644 --- a/ROSCO_toolbox/ofTools/fast_io/FAST_writer.py +++ b/ROSCO_toolbox/ofTools/fast_io/FAST_writer.py @@ -885,7 +885,7 @@ def write_AeroDyn15(self): f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['WakeMod'], 'WakeMod', '- Type of wake/induction model (switch) {0=none, 1=BEMT}\n')) f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['AFAeroMod'], 'AFAeroMod', '- Type of blade airfoil aerodynamics model (switch) {1=steady model, 2=Beddoes-Leishman unsteady model} [must be 1 when linearizing]\n')) f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['TwrPotent'], 'TwrPotent', '- Type tower influence on wind based on potential flow around the tower (switch) {0=none, 1=baseline potential flow, 2=potential flow with Bak correction}\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['TwrShadow'], 'TwrShadow', '- Calculate tower influence on wind based on downstream tower shadow? (flag)\n')) + f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['TwrShadow'], 'TwrShadow', '- Calculate tower influence on wind based on downstream tower shadow? (flag)\n')) f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['TwrAero'], 'TwrAero', '- Calculate tower aerodynamic loads? (flag)\n')) f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['FrozenWake'], 'FrozenWake', '- Assume frozen wake during linearization? (flag) [used only when WakeMod=1 and when linearizing]\n')) if self.FAST_ver.lower() != 'fast8': @@ -940,10 +940,10 @@ def write_AeroDyn15(self): f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['AeroDyn15']['ADBlFile3']+'"', 'ADBlFile(3)', '- Name of file containing distributed aerodynamic properties for Blade #3 (-) [unused if NumBl < 3]\n')) f.write('====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True]\n') f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['NumTwrNds'], 'NumTwrNds', '- Number of tower nodes used in the analysis (-) [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True]\n')) - f.write('TwrElev TwrDiam TwrCd\n') - f.write('(m) (m) (-)\n') - for TwrElev, TwrDiam, TwrCd in zip(self.fst_vt['AeroDyn15']['TwrElev'], self.fst_vt['AeroDyn15']['TwrDiam'], self.fst_vt['AeroDyn15']['TwrCd']): - f.write('{: 2.15e} {: 2.15e} {: 2.15e} \n'.format(TwrElev, TwrDiam, TwrCd)) + f.write('TwrElev TwrDiam TwrCd TwrTI (used only with TwrShadow=2)\n') + f.write('(m) (m) (-) (-)\n') + for TwrElev, TwrDiam, TwrCd, TwrTI in zip(self.fst_vt['AeroDyn15']['TwrElev'], self.fst_vt['AeroDyn15']['TwrDiam'], self.fst_vt['AeroDyn15']['TwrCd'], self.fst_vt['AeroDyn15']['TwrTI']): + f.write('{: 2.15e} {: 2.15e} {: 2.15e} {: 2.15e}\n'.format(TwrElev, TwrDiam, TwrCd, TwrTI)) f.write('====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True]\n') f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['SumPrint'], 'SumPrint', '- Generate a summary file listing input options and interpolated properties to ".AD.sum"? (flag)\n')) f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['AeroDyn15']['NBlOuts'], 'NBlOuts', '- Number of blade node outputs [0 - 9] (-)\n')) @@ -1266,11 +1266,15 @@ def write_ServoDyn(self): f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['TYawManS'], 'TYawManS', '- Time to start override yaw maneuver and end standard yaw control (s)\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['YawManRat'], 'YawManRat', '- Yaw maneuver rate (in absolute value) (deg/s)\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['NacYawF'], 'NacYawF', '- Final yaw angle for override yaw maneuvers (degrees)\n')) - f.write('---------------------- TUNED MASS DAMPER ---------------------------------------\n') - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['CompNTMD'], 'CompNTMD', '- Compute nacelle tuned mass damper {true/false} (flag)\n')) - f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['NTMDfile']+'"', 'NTMDfile', '- Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false]\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['CompTTMD'], 'CompTTMD', '- Compute tower tuned mass damper {true/false} (flag)\n')) - f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['TTMDfile']+'"', 'TTMDfile', '- Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false]\n')) + f.write('---------------------- STRUCTURAL CONTROL ---------------------------------------\n') + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['NumBStC'], 'NumBStC', '- Number of blade structural controllers (integer)\n')) + f.write('{!s:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['BStCfiles']+'"', 'BStCfiles', '- Name of the file for blade tuned mass damper (quoted string) [unused when CompNTMD is false]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['NumNStC'], 'NumNStC', '- Number of nacelle structural controllers (integer)\n')) + f.write('{!s:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['NStCfiles']+'"', 'NStCfiles', '- Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['NumTStC'], 'NumTStC', '- Number of tower structural controllers (integer)\n')) + f.write('{!s:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['TStCfiles']+'"', 'TStCfiles', '- Name of the file for tower tuned mass damper (quoted string) [unused when CompNTMD is false]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['ServoDyn']['NumSStC'], 'NumSStC', '- Number of sbustructure structural controllers (integer)\n')) + f.write('{!s:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['SStCfiles']+'"', 'SStCfiles', '- Name of the file for sbustructure tuned mass damper (quoted string) [unused when CompNTMD is false]\n')) f.write('---------------------- BLADED INTERFACE ---------------------------------------- [used only with Bladed Interface]\n') f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['DLL_FileName']+'"', 'DLL_FileName', '- Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface]\n')) f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['ServoDyn']['DLL_InFile']+'"', 'DLL_InFile', '- Name of input file sent to the DLL (-) [used only with Bladed Interface]\n')) @@ -1470,29 +1474,34 @@ def write_HydroDyn(self): f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['CurrDIDir'], 'CurrDIDir', '- Depth-independent current heading direction (degrees) [used only when CurrMod=1]\n')) f.write('---------------------- FLOATING PLATFORM --------------------------------------- [unused with WaveMod=6]\n') f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PotMod'], 'PotMod', '- Potential-flow model {0: none=no potential flow, 1: frequency-to-time-domain transforms based on WAMIT output, 2: fluid-impulse theory (FIT)} (switch)\n')) + f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['HydroDyn']['ExctnMod'], 'ExctnMod', '- Wave Excitation model {0: None, 1: DFT, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ssexctn INPUT FILE]\n')) + f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnMod'], 'RdtnMod', '- Radiation memory-effect model {0: no memory-effect calculation, 1: convolution, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ss INPUT FILE]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnTMax'], 'RdtnTMax', '- Analysis time for wave radiation kernel calculations (sec) [only used when PotMod=1; determines RdtnDOmega=Pi/RdtnTMax in the cosine transform; MAKE SURE THIS IS LONG ENOUGH FOR THE RADIATION IMPULSE RESPONSE FUNCTIONS TO DECAY TO NEAR-ZERO FOR THE GIVEN PLATFORM!]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnDT'], 'RdtnDT', '- Time step for wave radiation kernel calculations (sec) [only used when PotMod=1; DT<=RdtnDT<=0.1 recommended; determines RdtnOmegaMax=Pi/RdtnDT in the cosine transform]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['NBody'], 'NBody', '- Number of WAMIT bodies to be used (-) [>=1; only used when PotMod=1. If NBodyMod=1, the WAMIT data contains a vector of size 6*NBody x 1 and matrices of size 6*NBody x 6*NBody; if NBodyMod>1, there are NBody sets of WAMIT data each with a vector of size 6 x 1 and matrices of size 6 x 6]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['NBodyMod'], 'NBodyMod', '- Body coupling model {1: include coupling terms between each body and NBody in HydroDyn equals NBODY in WAMIT, 2: neglect coupling terms between each body and NBODY=1 with XBODY=0 in WAMIT, 3: Neglect coupling terms between each body and NBODY=1 with XBODY=/0 in WAMIT} (switch) [only used when PotMod=1]\n')) f.write('{:<22} {:<11} {:}'.format('"'+self.fst_vt['HydroDyn']['PotFile']+'"', 'PotFile', '- Root name of potential-flow model data; WAMIT output files containing the linear, nondimensionalized, hydrostatic restoring matrix (.hst), frequency-dependent hydrodynamic added mass matrix and damping matrix (.1), and frequency- and direction-dependent wave excitation force vector per unit wave amplitude (.3) (quoted string) [MAKE SURE THE FREQUENCIES INHERENT IN THESE WAMIT FILES SPAN THE PHYSICALLY-SIGNIFICANT RANGE OF FREQUENCIES FOR THE GIVEN PLATFORM; THEY MUST CONTAIN THE ZERO- AND INFINITE-FREQUENCY LIMITS!]\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['WAMITULEN'], 'WAMITULEN', '- Characteristic body length scale used to redimensionalize WAMIT output (meters) [only used when PotMod=1]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmRefxt'], 'PtfmRefxt', '- The xt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmRefyt'], 'PtfmRefyt', '- The yt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmRefzt'], 'PtfmRefzt', '- The zt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1. If NBodyMod=2,PtfmRefzt=0.0]\n')) + f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmRefztRot'], 'PtfmRefztRot', '- The rotation about zt of the body reference frame(s) from xt/yt (degrees) [1 to NBody] [only used when PotMod=1]\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmVol0'], 'PtfmVol0', '- Displaced volume of water when the platform is in its undisplaced position (m^3) [only used when PotMod=1; USE THE SAME VALUE COMPUTED BY WAMIT AS OUTPUT IN THE .OUT FILE!]\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmCOBxt'], 'PtfmCOBxt', '- The xt offset of the center of buoyancy (COB) from the platform reference point (meters) [only used when PotMod=1]\n')) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmCOByt'], 'PtfmCOByt', '- The yt offset of the center of buoyancy (COB) from the platform reference point (meters) [only used when PotMod=1]\n')) - f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['HydroDyn']['ExctnMod'], 'ExctnMod', '- Wave Excitation model {0: None, 1: DFT, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ssexctn INPUT FILE]\n')) - f.write('{:<22d} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnMod'], 'RdtnMod', '- Radiation memory-effect model {0: no memory-effect calculation, 1: convolution, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ss INPUT FILE]\n')) - f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnTMax'], 'RdtnTMax', '- Analysis time for wave radiation kernel calculations (sec) [only used when PotMod=1; determines RdtnDOmega=Pi/RdtnTMax in the cosine transform; MAKE SURE THIS IS LONG ENOUGH FOR THE RADIATION IMPULSE RESPONSE FUNCTIONS TO DECAY TO NEAR-ZERO FOR THE GIVEN PLATFORM!]\n')) - f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['RdtnDT'], 'RdtnDT', '- Time step for wave radiation kernel calculations (sec) [only used when PotMod=1; DT<=RdtnDT<=0.1 recommended; determines RdtnOmegaMax=Pi/RdtnDT in the cosine transform]\n')) f.write('---------------------- 2ND-ORDER FLOATING PLATFORM FORCES ---------------------- [unused with WaveMod=0 or 6, or PotMod=0 or 2]\n') f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['MnDrift'], 'MnDrift', "- Mean-drift 2nd-order forces computed {0: None; [7, 8, 9, 10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero]\n")) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['NewmanApp'], 'NewmanApp', "- Mean- and slow-drift 2nd-order forces computed with Newman's approximation {0: None; [7, 8, 9, 10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero. Used only when WaveDirMod=0]\n")) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['DiffQTF'], 'DiffQTF', "- Full difference-frequency 2nd-order forces computed with full QTF {0: None; [10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero]\n")) f.write('{:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['SumQTF'], 'SumQTF', "- Full summation -frequency 2nd-order forces computed with full QTF {0: None; [10, 11, or 12]: WAMIT file to use}\n")) - f.write('---------------------- FLOATING PLATFORM FORCE FLAGS -------------------------- [unused with WaveMod=6]\n') - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmSgF'], 'PtfmSgF', '- Platform horizontal surge translation force (flag) or DEFAULT\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmSwF'], 'PtfmSwF', '- Platform horizontal sway translation force (flag) or DEFAULT\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmHvF'], 'PtfmHvF', '- Platform vertical heave translation force (flag) or DEFAULT\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmRF'], 'PtfmRF', '- Platform roll tilt rotation force (flag) or DEFAULT\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmPF'], 'PtfmPF', '- Platform pitch tilt rotation force (flag) or DEFAULT\n')) - f.write('{!s:<22} {:<11} {:}'.format(self.fst_vt['HydroDyn']['PtfmYF'], 'PtfmYF', '- Platform yaw rotation force (flag) or DEFAULT\n')) f.write('---------------------- PLATFORM ADDITIONAL STIFFNESS AND DAMPING --------------\n') - f.write(" ".join(['{:14}'.format(i) for i in self.fst_vt['HydroDyn']['AddF0']])+" AddF0 - Additional preload (N, N-m)\n") + for j in range(6): + ln = '{:14} '.format(self.fst_vt['HydroDyn']['AddF0'][j][0]) + if j == 0: + ln = ln + 'AddF0 - Additional preload (N, N-m) [If NBodyMod=1, one size 6*NBody x 1 vector; if NBodyMod>1, NBody size 6 x 1 vectors]\n' + else: + ln = ln + '\n' + f.write(ln) for j in range(6): try: ln = " ".join(['{:14}'.format(i) for i in self.fst_vt['HydroDyn']['AddCLin'][j,:]]) @@ -1567,6 +1576,8 @@ def write_HydroDyn(self): ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplCaMG'])) ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplCp'])) ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplCpMG'])) + ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplAxCd'])) + ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplAxCdMG'])) ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplAxCa'])) ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplAxCaMG'])) ln.append('{:^11}'.format(self.fst_vt['HydroDyn']['SimplAxCp'])) diff --git a/ROSCO_toolbox/ofTools/util/spectral.py b/ROSCO_toolbox/ofTools/util/spectral.py index e5af299dc..307d4f7c6 100644 --- a/ROSCO_toolbox/ofTools/util/spectral.py +++ b/ROSCO_toolbox/ofTools/util/spectral.py @@ -573,7 +573,7 @@ def fnextpow2(x): if nperseg is None: if noverlap is None: overlap_frac=0.5 - elif noverlap is 0: + elif noverlap == 0: overlap_frac=0 else: raise NotImplementedError('TODO noverlap set but not nperseg') diff --git a/ROSCO_toolbox/turbine.py b/ROSCO_toolbox/turbine.py index 34721c469..739553a91 100644 --- a/ROSCO_toolbox/turbine.py +++ b/ROSCO_toolbox/turbine.py @@ -20,6 +20,16 @@ from ROSCO_toolbox.utilities import load_from_txt +# Load OpenFAST readers +try: + import weis.aeroelasticse + use_weis = True + print('Using weis.aeroelasticse in ROSCO_toolbox...') +except: + use_weis = False + print('ofTools in ROSCO_toolbox...') + + # Some useful constants now = datetime.datetime.now() pi = np.pi @@ -159,7 +169,10 @@ def load_from_fast(self, FAST_InputFile,FAST_directory, FAST_ver='OpenFAST',dev_ txt_filename: str, optional filename for *.txt, only used if rot_source='txt' """ - from ROSCO_toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST + if use_weis: + from weis.aeroelasticse.FAST_reader import InputReader_OpenFAST + else: + from ROSCO_toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST print('Loading FAST model: %s ' % FAST_InputFile) self.TurbineName = FAST_InputFile.strip('.fst') @@ -316,8 +329,12 @@ def generate_rotperf_fast(self, openfast_path, FAST_runDirectory=None, run_BeamD 'serial' - run in serial, 'multi' - run using python multiprocessing tools, 'mpi' - run using mpi tools ''' - from ROSCO_toolbox.ofTools.case_gen import runFAST_pywrapper, CaseGen_General - from ROSCO_toolbox.ofTools.util import FileTools + if use_weis: + from weis.aeroelasticse import runFAST_pywrapper, CaseGen_General + from weis.aeroelasticse.Util import FileTools + else: + from ROSCO_toolbox.ofTools.case_gen import runFAST_pywrapper, CaseGen_General + from ROSCO_toolbox.ofTools.util import FileTools # Load pCrunch tools from pCrunch import pdTools, Processing @@ -499,7 +516,10 @@ def load_blade_info(self): ----------- self - note: needs to contain fast input file info provided by load_from_fast. ''' - from ROSCO_toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST + if use_weis: + from weis.aeroelasticse.FAST_reader import InputReader_OpenFAST + else: + from ROSCO_toolbox.ofTools.fast_io.FAST_reader import InputReader_OpenFAST from wisdem.ccblade.ccblade import CCAirfoil, CCBlade # Create CC-Blade Rotor @@ -587,7 +607,14 @@ def __init__(self,performance_table, pitch_initial_rad, TSR_initial): # --- Find TSR --- # Make finer mesh for Tip speed ratios at "optimal" blade pitch angle, do a simple lookup. # -- nja: this seems to work a little better than interpolating - performance_beta_max = np.ndarray.flatten(performance_table[:,self.max_ind[1]]) # performance metric at maximizing pitch angle + + # Find the 1D performance table when pitch is at the maximum part of the Cx surface: + performance_beta_max = np.ndarray.flatten(performance_table[:,self.max_ind[1][-1]]) # performance metric at the last maximizing pitch angle + + # If there is more than one max pitch angle: + if len(self.max_ind[1]) > 1: + print('ROSCO_toolbox Warning: repeated maximum values in a performance table and the last one @ pitch = {} rad. was taken...'.format(self.pitch_opt[-1])) + TSR_ind = np.arange(0,len(TSR_initial)) TSR_fine_ind = np.linspace(TSR_initial[0],TSR_initial[-1],int(TSR_initial[-1] - TSR_initial[0])*100) f_TSR = interpolate.interp1d(TSR_initial,TSR_initial,bounds_error='False',kind='quadratic') # interpolate function for Cp(tsr) values diff --git a/Test_Cases/5MW_Land_Simulink/NRELOffshrBsline5MW_Onshore_ServoDyn.dat b/Test_Cases/5MW_Land_Simulink/NRELOffshrBsline5MW_Onshore_ServoDyn.dat index 0da37026d..8599775b5 100644 --- a/Test_Cases/5MW_Land_Simulink/NRELOffshrBsline5MW_Onshore_ServoDyn.dat +++ b/Test_Cases/5MW_Land_Simulink/NRELOffshrBsline5MW_Onshore_ServoDyn.dat @@ -57,11 +57,15 @@ True GenTiStp - Method to stop the generator {T: timed using TimGen 9999.9 TYawManS - Time to start override yaw maneuver and end standard yaw control (s) 2 YawManRat - Yaw maneuver rate (in absolute value) (deg/s) 0 NacYawF - Final yaw angle for override yaw maneuvers (degrees) ----------------------- TUNED MASS DAMPER --------------------------------------- -False CompNTMD - Compute nacelle tuned mass damper {true/false} (flag) -"../5MW_Baseline/NRELOffshrBsline5MW_ServoDyn_TMD.dat" NTMDfile - Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false] -False CompTTMD - Compute tower tuned mass damper {true/false} (flag) -"../5MW_Baseline/NRELOffshrBsline5MW_ServoDyn_TMD.dat" TTMDfile - Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false] +---------------------- STRUCTURAL CONTROL -------------------------------------- +0 NumBStC - Number of blade structural controllers (integer) +"unused" BStCfiles - Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0] +0 NumNStC - Number of nacelle structural controllers (integer) +"unused" NStCfiles - Name of the files for nacelle structural controllers (quoted strings) [unused when NumNStC==0] +0 NumTStC - Number of tower structural controllers (integer) +"unused" TStCfiles - Name of the files for tower structural controllers (quoted strings) [unused when NumTStC==0] +0 NumSStC - Number of substructure structural controllers (integer) +"unused" SStCfiles - Name of the files for substructure structural controllers (quoted strings) [unused when NumSStC==0] ---------------------- BLADED INTERFACE ---------------------------------------- [used only with Bladed Interface] "../../ROSCO/build/libdiscon.dylib" DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] "DISCON.IN" DLL_InFile - Name of input file sent to the DLL (-) [used only with Bladed Interface] diff --git a/Test_Cases/BAR_10/BAR_10_AeroDyn15.dat b/Test_Cases/BAR_10/BAR_10_AeroDyn15.dat index d0bf68294..ed92372dc 100644 --- a/Test_Cases/BAR_10/BAR_10_AeroDyn15.dat +++ b/Test_Cases/BAR_10/BAR_10_AeroDyn15.dat @@ -6,7 +6,7 @@ False Echo - Echo the input to ".AD.ech"? (fl 1 WakeMod - Type of wake/induction model (switch) {0=none, 1=BEMT} 2 AFAeroMod - Type of blade airfoil aerodynamics model (switch) {1=steady model, 2=Beddoes-Leishman unsteady model} [must be 1 when linearizing] 1 TwrPotent - Type tower influence on wind based on potential flow around the tower (switch) {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} -True TwrShadow - Calculate tower influence on wind based on downstream tower shadow? (flag) +0 TwrShadow - Calculate tower influence on wind based on downstream tower shadow? (flag) True TwrAero - Calculate tower aerodynamic loads? (flag) False FrozenWake - Assume frozen wake during linearization? (flag) [used only when WakeMod=1 and when linearizing] False CavitCheck - Perform cavitation check? (flag) TRUE will turn off unsteady aerodynamics @@ -82,17 +82,17 @@ True UseBlCm - Include aerodynamic pitching moment in calc "BAR_10_AeroDyn15_blade.dat" ADBlFile(3) - Name of file containing distributed aerodynamic properties for Blade #3 (-) [unused if NumBl < 3] ====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] 9 NumTwrNds - Number of tower nodes used in the analysis (-) [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] -TwrElev TwrDiam TwrCd -(m) (m) (-) - 2.740000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 - 4.110000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 - 5.480000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 - 6.850000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 - 8.220000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 - 9.590000000000001e+01 6.000000000000000e+00 1.000000000000000e+00 - 1.096000000000000e+02 6.000000000000000e+00 1.000000000000000e+00 - 1.233000000000000e+02 5.890792130000000e+00 1.000000000000000e+00 - 1.370000000000000e+02 5.530325920000000e+00 1.000000000000000e+00 +TwrElev TwrDiam TwrCd TwrTI (used only with TwrShadow=2) +(m) (m) (-) (-) + 2.740000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 4.110000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 5.480000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 6.850000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 8.220000000000000e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 9.590000000000001e+01 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 1.096000000000000e+02 6.000000000000000e+00 1.000000000000000e+00 1.0e-1 + 1.233000000000000e+02 5.890792130000000e+00 1.000000000000000e+00 1.0e-1 + 1.370000000000000e+02 5.530325920000000e+00 1.000000000000000e+00 1.0e-1 ====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] True SumPrint - Generate a summary file listing input options and interpolated properties to ".AD.sum"? (flag) 9 NBlOuts - Number of blade node outputs [0 - 9] (-) diff --git a/Test_Cases/BAR_10/BAR_10_ServoDyn.dat b/Test_Cases/BAR_10/BAR_10_ServoDyn.dat index d5fc8d100..ebbbc9bf3 100644 --- a/Test_Cases/BAR_10/BAR_10_ServoDyn.dat +++ b/Test_Cases/BAR_10/BAR_10_ServoDyn.dat @@ -57,13 +57,17 @@ True GenTiStp - Method to stop the generator {T: timed usin 9999.9 TYawManS - Time to start override yaw maneuver and end standard yaw control (s) 2.0 YawManRat - Yaw maneuver rate (in absolute value) (deg/s) 0.0 NacYawF - Final yaw angle for override yaw maneuvers (degrees) ----------------------- TUNED MASS DAMPER --------------------------------------- -False CompNTMD - Compute nacelle tuned mass damper {true/false} (flag) -"a.dat" NTMDfile - Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false] -False CompTTMD - Compute tower tuned mass damper {true/false} (flag) -"b.dat" TTMDfile - Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false] +---------------------- STRUCTURAL CONTROL -------------------------------------- +0 NumBStC - Number of blade structural controllers (integer) +"unused" BStCfiles - Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0] +0 NumNStC - Number of nacelle structural controllers (integer) +"unused" NStCfiles - Name of the files for nacelle structural controllers (quoted strings) [unused when NumNStC==0] +0 NumTStC - Number of tower structural controllers (integer) +"unused" TStCfiles - Name of the files for tower structural controllers (quoted strings) [unused when NumTStC==0] +0 NumSStC - Number of substructure structural controllers (integer) +"unused" SStCfiles - Name of the files for substructure structural controllers (quoted strings) [unused when NumSStC==0] ---------------------- BLADED INTERFACE ---------------------------------------- [used only with Bladed Interface] -"../../ROSCO/install/lib/libdiscon.so" DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] +"../../ROSCO/install/lib/libdiscon.dylib" DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] "BAR_10_DISCON.IN" DLL_InFile - Name of input file sent to the DLL (-) [used only with Bladed Interface] "DISCON" DLL_ProcName - Name of procedure in DLL to be called (-) [case sensitive; used only with DLL Interface] "default" DLL_DT - Communication interval for dynamic library (s) (or "default") [used only with Bladed Interface] diff --git a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_HydroDyn.dat b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_HydroDyn.dat index cd3a3fa7b..fa88672b6 100644 --- a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_HydroDyn.dat +++ b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_HydroDyn.dat @@ -45,29 +45,33 @@ False Echo - Echo the input file data (flag) 0 CurrDIDir - Depth-independent current heading direction (degrees) [used only when CurrMod=1] ---------------------- FLOATING PLATFORM --------------------------------------- [unused with WaveMod=6] 1 PotMod - Potential-flow model {0: none=no potential flow, 1: frequency-to-time-domain transforms based on WAMIT output, 2: fluid-impulse theory (FIT)} (switch) + 1 ExctnMod - Wave-excitation model {0: no wave-excitation calculation, 1: DFT, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ssexctn INPUT FILE] + 1 RdtnMod - Radiation memory-effect model {0: no memory-effect calculation, 1: convolution, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ss INPUT FILE] + 60 RdtnTMax - Analysis time for wave radiation kernel calculations (sec) [only used when PotMod=1; determines RdtnDOmega=Pi/RdtnTMax in the cosine transform; MAKE SURE THIS IS LONG ENOUGH FOR THE RADIATION IMPULSE RESPONSE FUNCTIONS TO DECAY TO NEAR-ZERO FOR THE GIVEN PLATFORM!] + "DEFAULT" RdtnDT - Time step for wave radiation kernel calculations (sec) [only used when PotMod=1; DT<=RdtnDT<=0.1 recommended; determines RdtnOmegaMax=Pi/RdtnDT in the cosine transform] + 1 NBody - Number of WAMIT bodies to be used (-) [>=1; only used when PotMod=1. If NBodyMod=1, the WAMIT data contains a vector of size 6*NBody x 1 and matrices of size 6*NBody x 6*NBody; if NBodyMod>1, there are NBody sets of WAMIT data each with a vector of size 6 x 1 and matrices of size 6 x 6] + 1 NBodyMod - Body coupling model {1: include coupling terms between each body and NBody in HydroDyn equals NBODY in WAMIT, 2: neglect coupling terms between each body and NBODY=1 with XBODY=0 in WAMIT, 3: Neglect coupling terms between each body and NBODY=1 with XBODY=/0 in WAMIT} (switch) [only used when PotMod=1] "HydroData/IEA-15-240-RWT-UMaineSemi" PotFile - Root name of potential-flow model data; WAMIT output files containing the linear, nondimensionalized, hydrostatic restoring matrix (.hst), frequency-dependent hydrodynamic added mass matrix and damping matrix (.1), and frequency- and direction-dependent wave excitation force vector per unit wave amplitude (.3) (quoted string) [MAKE SURE THE FREQUENCIES INHERENT IN THESE WAMIT FILES SPAN THE PHYSICALLY-SIGNIFICANT RANGE OF FREQUENCIES FOR THE GIVEN PLATFORM; THEY MUST CONTAIN THE ZERO- AND INFINITE-FREQUENCY LIMITS!] 1 WAMITULEN - Characteristic body length scale used to redimensionalize WAMIT output (meters) [only used when PotMod=1] + 0.0 PtfmRefxt - The xt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1] + 0.0 PtfmRefyt - The yt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1] + 0.0 PtfmRefzt - The zt offset of the body reference point(s) from (0,0,0) (meters) [1 to NBody] [only used when PotMod=1. If NBodyMod=2,PtfmRefzt=0.0] + 0.0 PtfmRefztRot - The rotation about zt of the body reference frame(s) from xt/yt (degrees) [1 to NBody] [only used when PotMod=1] 20206.34889 PtfmVol0 - Displaced volume of water when the platform is in its undisplaced position (m^3) [only used when PotMod=1; USE THE SAME VALUE COMPUTED BY WAMIT AS OUTPUT IN THE .OUT FILE!] 0 PtfmCOBxt - The xt offset of the center of buoyancy (COB) from the platform reference point (meters) [only used when PotMod=1] 0 PtfmCOByt - The yt offset of the center of buoyancy (COB) from the platform reference point (meters) [only used when PotMod=1] - 0 ExctnMod - Wave Excitation model {0: None, 1: DFT, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ssexctn INPUT FILE] - 1 RdtnMod - Radiation memory-effect model {0: no memory-effect calculation, 1: convolution, 2: state-space} (switch) [only used when PotMod=1; STATE-SPACE REQUIRES *.ss INPUT FILE] - 60 RdtnTMax - Analysis time for wave radiation kernel calculations (sec) [only used when PotMod=1; determines RdtnDOmega=Pi/RdtnTMax in the cosine transform; MAKE SURE THIS IS LONG ENOUGH FOR THE RADIATION IMPULSE RESPONSE FUNCTIONS TO DECAY TO NEAR-ZERO FOR THE GIVEN PLATFORM!] - "DEFAULT" RdtnDT - Time step for wave radiation kernel calculations (sec) [only used when PotMod=1; DT<=RdtnDT<=0.1 recommended; determines RdtnOmegaMax=Pi/RdtnDT in the cosine transform] ---------------------- 2ND-ORDER FLOATING PLATFORM FORCES ---------------------- [unused with WaveMod=0 or 6, or PotMod=0 or 2] 0 MnDrift - Mean-drift 2nd-order forces computed {0: None; [7, 8, 9, 10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero] 0 NewmanApp - Mean- and slow-drift 2nd-order forces computed with Newman's approximation {0: None; [7, 8, 9, 10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero. Used only when WaveDirMod=0] 12 DiffQTF - Full difference-frequency 2nd-order forces computed with full QTF {0: None; [10, 11, or 12]: WAMIT file to use} [Only one of MnDrift, NewmanApp, or DiffQTF can be non-zero] 0 SumQTF - Full summation -frequency 2nd-order forces computed with full QTF {0: None; [10, 11, or 12]: WAMIT file to use} ----------------------- FLOATING PLATFORM FORCE FLAGS -------------------------- [unused with WaveMod=6] -True PtfmSgF - Platform horizontal surge translation force (flag) or DEFAULT -True PtfmSwF - Platform horizontal sway translation force (flag) or DEFAULT -True PtfmHvF - Platform vertical heave translation force (flag) or DEFAULT -True PtfmRF - Platform roll tilt rotation force (flag) or DEFAULT -True PtfmPF - Platform pitch tilt rotation force (flag) or DEFAULT -True PtfmYF - Platform yaw rotation force (flag) or DEFAULT ---------------------- PLATFORM ADDITIONAL STIFFNESS AND DAMPING -------------- - 0 0 0 0 0 0 AddF0 - Additional preload (N, N-m) + 0 AddF0 - Additional preload (N, N-m) [If NBodyMod=1, one size 6*NBody x 1 vector; if NBodyMod>1, NBody size 6 x 1 vectors] + 0 + 0 + 0 + 0 + 0 0 0 0 0 0 0 AddCLin - Additional linear stiffness (N/m, N/rad, N-m/m, N-m/rad) 0 0 0 0 0 0 0 0 0 0 0 0 @@ -102,10 +106,10 @@ JointID Jointxi Jointyi Jointzi JointAxID JointOvrlp [JointOvrlp= PropSetID PropD PropThck (-) (m) (m) 1 .00001 0.000001 ----------------------- SIMPLE HYDRODYNAMIC COEFFICIENTS (model 1) -------------- - SimplCd SimplCdMG SimplCa SimplCaMG SimplCp SimplCpMG SimplAxCa SimplAxCaMG SimplAxCp SimplAxCpMG - (-) (-) (-) (-) (-) (-) (-) (-) (-) (-) - 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 +---------------------- SIMPLE HYDRODYNAMIC COEFFICIENTS (model 1) -------------- + SimplCd SimplCdMG SimplCa SimplCaMG SimplCp SimplCpMG SimplAxCd SimplAxCdMG SimplAxCa SimplAxCaMG SimplAxCp SimplAxCpMG + (-) (-) (-) (-) (-) (-) (-) (-) (-) (-) (-) (-) + 1.00 1.00 1.00 1.00 1.00 1.00 1.00 0.00 0.00 1.00 1.00 1.00 ---------------------- DEPTH-BASED HYDRODYNAMIC COEFFICIENTS (model 2) --------- 0 NCoefDpth - Number of depth-dependent coefficients (-) Dpth DpthCd DpthCdMG DpthCa DpthCaMG DpthCp DpthCpMG DpthAxCa DpthAxCaMG DpthAxCp DpthAxCpMG diff --git a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ServoDyn.dat b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ServoDyn.dat index 2f068be12..2bde0d1bc 100644 --- a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ServoDyn.dat +++ b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT-UMaineSemi_ServoDyn.dat @@ -57,11 +57,15 @@ True GenTiStp - Method to stop the generator {T: timed usin 9999.9 TYawManS - Time to start override yaw maneuver and end standard yaw control (s) 2.0 YawManRat - Yaw maneuver rate (in absolute value) (deg/s) 0.0 NacYawF - Final yaw angle for override yaw maneuvers (degrees) ----------------------- TUNED MASS DAMPER --------------------------------------- -False CompNTMD - Compute nacelle tuned mass damper {true/false} (flag) -"unused" NTMDfile - Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false] -False CompTTMD - Compute tower tuned mass damper {true/false} (flag) -"unused" TTMDfile - Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false] +---------------------- STRUCTURAL CONTROL -------------------------------------- +0 NumBStC - Number of blade structural controllers (integer) +"unused" BStCfiles - Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0] +0 NumNStC - Number of nacelle structural controllers (integer) +"unused" NStCfiles - Name of the files for nacelle structural controllers (quoted strings) [unused when NumNStC==0] +0 NumTStC - Number of tower structural controllers (integer) +"unused" TStCfiles - Name of the files for tower structural controllers (quoted strings) [unused when NumTStC==0] +0 NumSStC - Number of substructure structural controllers (integer) +"unused" SStCfiles - Name of the files for substructure structural controllers (quoted strings) [unused when NumSStC==0] ---------------------- BLADED INTERFACE ---------------------------------------- [used only with Bladed Interface] "../../ROSCO/install/lib/libdiscon.so" DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] "ServoData/DISCON-UMaineSemi.IN" DLL_InFile - Name of input file sent to the DLL (-) [used only with Bladed Interface] diff --git a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT_AeroDyn15.dat b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT_AeroDyn15.dat index 182bc8353..ced863ef6 100644 --- a/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT_AeroDyn15.dat +++ b/Test_Cases/IEA-15-240-RWT-UMaineSemi/IEA-15-240-RWT_AeroDyn15.dat @@ -6,7 +6,7 @@ False Echo - Echo the input to ".AD.ech"? (fl 1 WakeMod - Type of wake/induction model (switch) {0=none, 1=BEMT, 2=DBEMT, 3=OLAF} [WakeMod cannot be 2 or 3 when linearizing] 2 AFAeroMod - Type of blade airfoil aerodynamics model (switch) {1=steady model, 2=Beddoes-Leishman unsteady model} [AFAeroMod must be 1 when linearizing] 1 TwrPotent - Type tower influence on wind based on potential flow around the tower (switch) {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} -False TwrShadow - Calculate tower influence on wind based on downstream tower shadow (switch) {0=none, 1=Powles model, 2=Eames model} +0 TwrShadow - Calculate tower influence on wind based on downstream tower shadow (switch) {0=none, 1=Powles model, 2=Eames model} True TwrAero - Calculate tower aerodynamic loads? (flag) False FrozenWake - Assume frozen wake during linearization? (flag) [used only when WakeMod=1 and when linearizing] False CavitCheck - Perform cavitation check? (flag) [AFAeroMod must be 1 when CavitCheck=true] @@ -102,19 +102,19 @@ True UseBlCm - Include aerodynamic pitching moment in calc "IEA-15-240-RWT_AeroDyn15_blade.dat" ADBlFile(3) - Name of file containing distributed aerodynamic properties for Blade #3 (-) [unused if NumBl < 3] ====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] 11 NumTwrNds - Number of tower nodes used in the analysis (-) [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] -TwrElev TwrDiam TwrCd -(m) (m) (-) - 15. 10. 1. - 28. 10. 1. - 41. 9.926 1. - 54. 9.443 1. - 67. 8.833 1. - 80. 8.151 1. - 93. 7.39 1. - 106. 6.909 1. - 119. 6.748 1. - 132. 6.572 1. - 144.495 6.5 1. +TwrElev TwrDiam TwrCd TwrTI (used only with TwrShadow=2) +(m) (m) (-) (-) + 15. 10. 1. 1.0e-1 + 28. 10. 1. 1.0e-1 + 41. 9.926 1. 1.0e-1 + 54. 9.443 1. 1.0e-1 + 67. 8.833 1. 1.0e-1 + 80. 8.151 1. 1.0e-1 + 93. 7.39 1. 1.0e-1 + 106. 6.909 1. 1.0e-1 + 119. 6.748 1. 1.0e-1 + 132. 6.572 1. 1.0e-1 + 144.495 6.5 1. 1.0e-1 ====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] True SumPrint - Generate a summary file listing input options and interpolated properties to ".AD.sum"? (flag) 9 NBlOuts - Number of blade node outputs [0 - 9] (-) diff --git a/Test_Cases/IEA-15-240-RWT-UMaineSemi/ServoData/DISCON-UMaineSemi.IN b/Test_Cases/IEA-15-240-RWT-UMaineSemi/ServoData/DISCON-UMaineSemi.IN index 308b0ae25..6a93ca7b6 100644 --- a/Test_Cases/IEA-15-240-RWT-UMaineSemi/ServoData/DISCON-UMaineSemi.IN +++ b/Test_Cases/IEA-15-240-RWT-UMaineSemi/ServoData/DISCON-UMaineSemi.IN @@ -1,5 +1,5 @@ ! Controller parameter input file for the IEA-15-240-RWT-UMaineSemi wind turbine -! - File written using ROSCO version 2.2.0 controller tuning logic on 05/21/21 +! - File written using ROSCO version 2.2.0 controller tuning logic on 06/02/21 !------- DEBUG ------------------------------------------------------------ 1 ! LoggingLevel - {0: write no debug files, 1: write standard output .dbg-file, 2: write standard output .dbg-file and complete avrSWAP-array .dbg2-file} @@ -28,12 +28,12 @@ 1.16240 1.00000 ! F_FlpCornerFreq - Corner frequency and damping in the second order low pass filter of the blade root bending moment for flap control [rad/s, -]. !------- BLADE PITCH CONTROL ---------------------------------------------- -29 ! PC_GS_n - Amount of gain-scheduling table entries -0.061302 0.088725 0.110460 0.129231 0.146101 0.161618 0.176096 0.189763 0.202765 0.215213 0.227190 0.238754 0.249961 0.260854 0.271463 0.281817 0.291944 0.301857 0.311577 0.321120 0.330501 0.339728 0.348811 0.357760 0.366583 0.375288 0.383879 0.392362 0.400744 ! PC_GS_angles - Gain-schedule table: pitch angles [rad]. --1.590144 -1.390427 -1.225842 -1.087870 -0.970537 -0.869535 -0.781676 -0.704552 -0.636308 -0.575495 -0.520961 -0.471781 -0.427204 -0.386613 -0.349495 -0.315424 -0.284039 -0.255034 -0.228149 -0.203159 -0.179871 -0.158116 -0.137749 -0.118640 -0.100676 -0.083758 -0.067796 -0.052712 -0.038435 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. --0.205073 -0.185297 -0.168999 -0.155336 -0.143717 -0.133716 -0.125016 -0.117378 -0.110621 -0.104599 -0.099198 -0.094328 -0.089914 -0.085895 -0.082219 -0.078845 -0.075737 -0.072865 -0.070203 -0.067728 -0.065422 -0.063268 -0.061251 -0.059359 -0.057580 -0.055905 -0.054324 -0.052831 -0.051417 ! PC_GS_KI - Gain-schedule table: pitch controller ki gains [-]. -0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ! PC_GS_KD - Gain-schedule table: pitch controller kd gains -0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ! PC_GS_TF - Gain-schedule table: pitch controller tf gains (derivative filter) +30 ! PC_GS_n - Amount of gain-scheduling table entries +0.060198 0.087134 0.108448 0.126859 0.143398 0.158602 0.172796 0.186189 0.198928 0.211120 0.222850 0.234173 0.245147 0.255807 0.266195 0.276325 0.286231 0.295933 0.305445 0.314779 0.323952 0.332975 0.341858 0.350608 0.359236 0.367748 0.376149 0.384447 0.392644 0.400744 ! PC_GS_angles - Gain-schedule table: pitch angles [rad]. +-1.598670 -1.403333 -1.241551 -1.105363 -0.989139 -0.888791 -0.801272 -0.724271 -0.655999 -0.595051 -0.540309 -0.490871 -0.446001 -0.405095 -0.367649 -0.333242 -0.301519 -0.272177 -0.244958 -0.219639 -0.196029 -0.173960 -0.153286 -0.133879 -0.115625 -0.098425 -0.082190 -0.066841 -0.052308 -0.038527 ! PC_GS_KP - Gain-schedule table: pitch controller kp gains [s]. +-0.206015 -0.186658 -0.170625 -0.157129 -0.145612 -0.135667 -0.126994 -0.119364 -0.112598 -0.106558 -0.101133 -0.096234 -0.091788 -0.087734 -0.084023 -0.080613 -0.077470 -0.074562 -0.071864 -0.069355 -0.067016 -0.064829 -0.062780 -0.060857 -0.059048 -0.057343 -0.055734 -0.054213 -0.052773 -0.051408 ! PC_GS_KI - Gain-schedule table: pitch controller ki gains [-]. +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ! PC_GS_KD - Gain-schedule table: pitch controller kd gains +0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ! PC_GS_TF - Gain-schedule table: pitch controller tf gains (derivative filter) 1.570800000000 ! PC_MaxPit - Maximum physical pitch limit, [rad]. 0.000000000000 ! PC_MinPit - Minimum physical pitch limit, [rad]. 0.034900000000 ! PC_MaxRat - Maximum pitch rate (in absolute value) in pitch controller, [rad/s]. @@ -71,16 +71,16 @@ !------- WIND SPEED ESTIMATOR --------------------------------------------- 120.000 ! WE_BladeRadius - Blade length (distance from hub center to blade tip), [m] 1 ! WE_CP_n - Amount of parameters in the Cp array -0.0 0.0 0.0 0.0 ! WE_CP - Parameters that define the parameterized CP(lambda) function +0.0 ! WE_CP - Parameters that define the parameterized CP(lambda) function 0.0 ! WE_Gamma - Adaption gain of the wind speed estimator algorithm [m/rad] 1.0 ! WE_GearboxRatio - Gearbox ratio [>=1], [-] 318628138.00000 ! WE_Jtot - Total drivetrain inertia, including blades, hub and casted generator inertia to LSS, [kg m^2] 1.225 ! WE_RhoAir - Air density, [kg m^-3] "Cp_Ct_Cq.IEA15MW.txt" ! PerfFileName - File containing rotor performance tables (Cp,Ct,Cq) 104 72 ! PerfTableSize - Size of rotor performance tables, first number refers to number of blade pitch angles, second number referse to number of tip-speed ratios -59 ! WE_FOPoles_N - Number of first-order system poles used in EKF -3.00 3.27 3.53 3.80 4.07 4.33 4.60 4.87 5.14 5.40 5.67 5.94 6.20 6.47 6.74 7.00 7.27 7.54 7.80 8.07 8.34 8.60 8.87 9.14 9.41 9.67 9.94 10.21 10.47 10.74 11.23 11.72 12.22 12.71 13.20 13.69 14.18 14.67 15.17 15.66 16.15 16.64 17.13 17.62 18.12 18.61 19.10 19.59 20.08 20.57 21.07 21.56 22.05 22.54 23.03 23.52 24.02 24.51 25.00 ! WE_FOPoles_v - Wind speeds corresponding to first-order system poles [m/s] --0.02366483 -0.02577018 -0.02787553 -0.02998089 -0.03208624 -0.03419159 -0.03629695 -0.03840230 -0.04050765 -0.04261301 -0.04471836 -0.04682371 -0.04892907 -0.05103442 -0.05313977 -0.05524513 -0.05735048 -0.05945583 -0.06156119 -0.06366654 -0.06577189 -0.06787725 -0.06998260 -0.07208795 -0.07419331 -0.07629866 -0.07840401 -0.08050937 -0.08261472 -0.07921295 -0.05358619 -0.05636426 -0.06307564 -0.07173987 -0.08172495 -0.09271927 -0.10454428 -0.11705643 -0.13017613 -0.14379976 -0.15793978 -0.17258746 -0.18766434 -0.20315149 -0.21909644 -0.23538854 -0.25208919 -0.26915631 -0.28659300 -0.30437969 -0.32249538 -0.34096095 -0.35974552 -0.37881117 -0.39822177 -0.41789494 -0.43785131 -0.45808118 -0.47857910 ! WE_FOPoles - First order system poles [1/s] +60 ! WE_FOPoles_N - Number of first-order system poles used in EKF +3.00 3.27 3.53 3.80 4.07 4.33 4.60 4.87 5.14 5.40 5.67 5.94 6.20 6.47 6.74 7.00 7.27 7.54 7.80 8.07 8.34 8.60 8.87 9.14 9.41 9.67 9.94 10.21 10.47 10.74 11.22 11.69 12.17 12.64 13.12 13.59 14.07 14.54 15.02 15.49 15.97 16.44 16.92 17.39 17.87 18.35 18.82 19.30 19.77 20.25 20.72 21.20 21.67 22.15 22.62 23.10 23.57 24.05 24.52 25.00 ! WE_FOPoles_v - Wind speeds corresponding to first-order system poles [m/s] +-0.02366483 -0.02577018 -0.02787553 -0.02998089 -0.03208624 -0.03419159 -0.03629695 -0.03840230 -0.04050765 -0.04261301 -0.04471836 -0.04682371 -0.04892907 -0.05103442 -0.05313977 -0.05524513 -0.05735048 -0.05945583 -0.06156119 -0.06366654 -0.06577189 -0.06787725 -0.06998260 -0.07208795 -0.07419331 -0.07629866 -0.07840401 -0.08050937 -0.08261472 -0.07921295 -0.05363855 -0.05601196 -0.06228621 -0.07050010 -0.08000290 -0.09048156 -0.10174863 -0.11365942 -0.12615707 -0.13917960 -0.15270665 -0.16669562 -0.18106141 -0.19588503 -0.21106595 -0.22664340 -0.24258187 -0.25886648 -0.27550565 -0.29248186 -0.30978187 -0.32738614 -0.34531736 -0.36353035 -0.38202289 -0.40082810 -0.41987220 -0.43918834 -0.45876266 -0.47857910 ! WE_FOPoles - First order system poles [1/s] !------- YAW CONTROL ------------------------------------------------------ 0.0 ! Y_ErrThresh - Yaw error threshold. Turbine begins to yaw when it passes this. [rad^2 s] @@ -97,20 +97,20 @@ !------- TOWER FORE-AFT DAMPING ------------------------------------------- -1 ! FA_KI - Integral gain for the fore-aft tower damper controller, -1 = off / >0 = on [rad s/m] - !NJA - Make this a flag -0.0 ! FA_HPF_CornerFreq - Corner frequency (-3dB point) in the high-pass filter on the fore-aft acceleration signal [rad/s] +0.0 ! FA_HPFCornerFreq - Corner frequency (-3dB point) in the high-pass filter on the fore-aft acceleration signal [rad/s] 0.0 ! FA_IntSat - Integrator saturation (maximum signal amplitude contribution to pitch from FA damper), [rad] !------- MINIMUM PITCH SATURATION ------------------------------------------- -59 ! PS_BldPitchMin_N - Number of values in minimum blade pitch lookup table (should equal number of values in PS_WindSpeeds and PS_BldPitchMin) -3.0000 3.2669 3.5338 3.8007 4.0676 4.3345 4.6014 4.8683 5.1352 5.4021 5.6690 5.9359 6.2028 6.4697 6.7366 7.0034 7.2703 7.5372 7.8041 8.0710 8.3379 8.6048 8.8717 9.1386 9.4055 9.6724 9.9393 10.2062 10.4731 10.7400 11.2317 11.7234 12.2152 12.7069 13.1986 13.6903 14.1821 14.6738 15.1655 15.6572 16.1490 16.6407 17.1324 17.6241 18.1159 18.6076 19.0993 19.5910 20.0828 20.5745 21.0662 21.5579 22.0497 22.5414 23.0331 23.5248 24.0166 24.5083 25.0000 ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s] -0.06981317 0.06981317 0.06981317 0.06544985 0.06108652 0.06108652 0.05672320 0.05235988 0.04363323 0.03926991 0.03054326 0.02617994 0.01745329 0.01308997 0.00436332 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00846242 0.02297908 0.03562095 0.04679173 0.05441817 0.06567599 0.07636750 0.08665379 0.09661840 0.10632055 0.11580528 0.12510305 0.13423733 0.14322816 0.15209108 0.16083933 0.16948469 0.17803618 0.18650204 0.19488866 0.20320255 0.21144779 0.21962944 0.22775102 0.23581588 0.24382366 0.25177837 0.25968454 0.26754229 0.27535494 0.28311982 0.29083869 0.29851690 0.30615320 ! PS_BldPitchMin - Minimum blade pitch angles [rad] +60 ! PS_BldPitchMin_N - Number of values in minimum blade pitch lookup table (should equal number of values in PS_WindSpeeds and PS_BldPitchMin) +3.0000 3.2669 3.5338 3.8007 4.0676 4.3345 4.6014 4.8683 5.1352 5.4021 5.6690 5.9359 6.2028 6.4697 6.7366 7.0034 7.2703 7.5372 7.8041 8.0710 8.3379 8.6048 8.8717 9.1386 9.4055 9.6724 9.9393 10.2062 10.4731 10.7400 11.2153 11.6907 12.1660 12.6413 13.1167 13.5920 14.0673 14.5427 15.0180 15.4933 15.9687 16.4440 16.9193 17.3947 17.8700 18.3453 18.8207 19.2960 19.7713 20.2467 20.7220 21.1973 21.6727 22.1480 22.6233 23.0987 23.5740 24.0493 24.5247 25.0000 ! PS_WindSpeeds - Wind speeds corresponding to minimum blade pitch angles [m/s] +0.06981317 0.06981317 0.06981317 0.06544985 0.06108652 0.06108652 0.05672320 0.05235988 0.04363323 0.03926991 0.03054326 0.02617994 0.01745329 0.01308997 0.00436332 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00846242 0.02297908 0.03562095 0.04679173 0.05441817 0.06531126 0.07566895 0.08563939 0.09530571 0.10472222 0.11392608 0.12294997 0.13181647 0.14054481 0.14914972 0.15764424 0.16603901 0.17434237 0.18256207 0.19070469 0.19877714 0.20678372 0.21472883 0.22261606 0.23044510 0.23822156 0.24594897 0.25362874 0.26126159 0.26884689 0.27639120 0.28389435 0.29135253 0.29877202 0.30615320 ! PS_BldPitchMin - Minimum blade pitch angles [rad] !------- SHUTDOWN ----------------------------------------------------------- 0.400740000000 ! SD_MaxPit - Maximum blade pitch angle to initiate shutdown, [rad] 0.418880000000 ! SD_CornerFreq - Cutoff Frequency for first order low-pass filter for blade pitch angle, [rad/s] !------- Floating ----------------------------------------------------------- --9.32577000000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] +-9.37521000000 ! Fl_Kp - Nacelle velocity proportional feedback gain [s] !------- FLAP ACTUATION ----------------------------------------------------- 0.000000000000 ! Flp_Angle - Initial or steady state flap angle [rad] diff --git a/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_AeroDyn15.dat b/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_AeroDyn15.dat index 91955de02..7a358d7fa 100644 --- a/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_AeroDyn15.dat +++ b/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_AeroDyn15.dat @@ -6,7 +6,7 @@ False Echo - Echo the input to ".AD.ech"? (flag 1 WakeMod - Type of wake/induction model (switch) {0=none, 1=BEMT, 2=DBEMT, 3=OLAF} [WakeMod cannot be 2 or 3 when linearizing] 2 AFAeroMod - Type of blade airfoil aerodynamics model (switch) {1=steady model, 2=Beddoes-Leishman unsteady model} [AFAeroMod must be 1 when linearizing] 1 TwrPotent - Type tower influence on wind based on potential flow around the tower (switch) {0=none, 1=baseline potential flow, 2=potential flow with Bak correction} -False TwrShadow - Calculate tower influence on wind based on downstream tower shadow? (flag) + 0 TwrShadow - Calculate tower influence on wind based on downstream tower shadow? (flag) True TwrAero - Calculate tower aerodynamic loads? (flag) False FrozenWake - Assume frozen wake during linearization? (flag) [used only when WakeMod=1 and when linearizing] False CavitCheck - Perform cavitation check? (flag) [AFAeroMod must be 1 when CavitCheck=true] @@ -60,20 +60,20 @@ True UseBlCm - Include aerodynamic pitching moment in calcul "NRELOffshrBsline5MW_AeroDyn_blade.dat" ADBlFile(3) - Name of file containing distributed aerodynamic properties for Blade #3 (-) [unused if NumBl < 3] ====== Tower Influence and Aerodynamics ============================================================= [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] 12 NumTwrNds - Number of tower nodes used in the analysis (-) [used only when TwrPotent/=0, TwrShadow=True, or TwrAero=True] -TwrElev TwrDiam TwrCd -(m) (m) (-) -0.0000000E+00 6.0000000E+00 1.0000000E+00 -8.5261000E+00 5.7870000E+00 1.0000000E+00 -1.7053000E+01 5.5740000E+00 1.0000000E+00 -2.5579000E+01 5.3610000E+00 1.0000000E+00 -3.4105000E+01 5.1480000E+00 1.0000000E+00 -4.2633000E+01 4.9350000E+00 1.0000000E+00 -5.1158000E+01 4.7220000E+00 1.0000000E+00 -5.9685000E+01 4.5090000E+00 1.0000000E+00 -6.8211000E+01 4.2960000E+00 1.0000000E+00 -7.6738000E+01 4.0830000E+00 1.0000000E+00 -8.5268000E+01 3.8700000E+00 1.0000000E+00 -8.7600000E+01 3.8700000E+00 1.0000000E+00 +TwrElev TwrDiam TwrCd TwrTI (used only with TwrShadow=2) +(m) (m) (-) (-) +0.0000000E+00 6.0000000E+00 1.0000000E+00 1.000000E-01 +8.5261000E+00 5.7870000E+00 1.0000000E+00 1.000000E-01 +1.7053000E+01 5.5740000E+00 1.0000000E+00 1.000000E-01 +2.5579000E+01 5.3610000E+00 1.0000000E+00 1.000000E-01 +3.4105000E+01 5.1480000E+00 1.0000000E+00 1.000000E-01 +4.2633000E+01 4.9350000E+00 1.0000000E+00 1.000000E-01 +5.1158000E+01 4.7220000E+00 1.0000000E+00 1.000000E-01 +5.9685000E+01 4.5090000E+00 1.0000000E+00 1.000000E-01 +6.8211000E+01 4.2960000E+00 1.0000000E+00 1.000000E-01 +7.6738000E+01 4.0830000E+00 1.0000000E+00 1.000000E-01 +8.5268000E+01 3.8700000E+00 1.0000000E+00 1.000000E-01 +8.7600000E+01 3.8700000E+00 1.0000000E+00 1.000000E-01 ====== Outputs ==================================================================================== True SumPrint - Generate a summary file listing input options and interpolated properties to ".AD.sum"? (flag) 0 NBlOuts - Number of blade node outputs [0 - 9] (-) diff --git a/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_ServoDyn.dat b/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_ServoDyn.dat index 3b223991e..d16d9f38d 100644 --- a/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_ServoDyn.dat +++ b/Test_Cases/NREL-5MW/NRELOffshrBsline5MW_Onshore_ServoDyn.dat @@ -57,11 +57,15 @@ True GenTiStp - Method to stop the generator {T: timed using TimGen 9999.9 TYawManS - Time to start override yaw maneuver and end standard yaw control (s) 2 YawManRat - Yaw maneuver rate (in absolute value) (deg/s) 0 NacYawF - Final yaw angle for override yaw maneuvers (degrees) ----------------------- TUNED MASS DAMPER --------------------------------------- -False CompNTMD - Compute nacelle tuned mass damper {true/false} (flag) -"../5MW_Baseline/NRELOffshrBsline5MW_ServoDyn_TMD.dat" NTMDfile - Name of the file for nacelle tuned mass damper (quoted string) [unused when CompNTMD is false] -False CompTTMD - Compute tower tuned mass damper {true/false} (flag) -"../5MW_Baseline/NRELOffshrBsline5MW_ServoDyn_TMD.dat" TTMDfile - Name of the file for tower tuned mass damper (quoted string) [unused when CompTTMD is false] +---------------------- STRUCTURAL CONTROL -------------------------------------- +0 NumBStC - Number of blade structural controllers (integer) +"unused" BStCfiles - Name of the files for blade structural controllers (quoted strings) [unused when NumBStC==0] +0 NumNStC - Number of nacelle structural controllers (integer) +"unused" NStCfiles - Name of the files for nacelle structural controllers (quoted strings) [unused when NumNStC==0] +0 NumTStC - Number of tower structural controllers (integer) +"unused" TStCfiles - Name of the files for tower structural controllers (quoted strings) [unused when NumTStC==0] +0 NumSStC - Number of substructure structural controllers (integer) +"unused" SStCfiles - Name of the files for substructure structural controllers (quoted strings) [unused when NumSStC==0] ---------------------- BLADED INTERFACE ---------------------------------------- [used only with Bladed Interface] "../../ROSCO/install/lib/libdiscon.so" DLL_FileName - Name/location of the dynamic library {.dll [Windows] or .so [Linux]} in the Bladed-DLL format (-) [used only with Bladed Interface] "DISCON.IN" DLL_InFile - Name of input file sent to the DLL (-) [used only with Bladed Interface] diff --git a/docs/conf.py b/docs/conf.py index 19f3e1839..c5e3f6679 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,9 +75,9 @@ # built documents. # # The short X.Y version. -version = '2.2' +version = '2.3' # The full version, including alpha/beta/rc tags. -release = 'v2.2.0' +release = 'v2.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/index.rst b/docs/index.rst index 13224e187..bc19a083e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,27 +20,38 @@ Figure :numref:`fig-RT` shows the general workflow for the ROSCO toolchain. **ROSCO Toolbox** -- Generic tuning of NREL's ROSCO controller -- Simple 1-DOF turbine simulations for quick controller capability verifications -- Parsing of OpenFAST input and output files -- Block diagrams of these capabilities can be seen in architecture.png. +* Generic tuning of NREL's ROSCO controller +* Simple 1-DOF turbine simulations for quick controller capability verifications +* Parsing of OpenFAST input and output files +* Block diagrams of these capabilities can be seen in architecture.png. **ROSCO Controller** -- Fortran based -- Follows Bladed-style control interface -- Modular +* Fortran based +* Follows Bladed-style control interface +* Modular -*Standard Use* +Standard Use +------------ For the standard use case in OpenFAST, ROSCO will need to be compiled. This is made possible via the instructions found in :ref:`install`. Once the controller is compiled, the turbine model needs to point to the compiled binary. In OpenFAST, this is ensured by changing the :code:`DLL_FileName` parameter in the ServoDyn input file. Additionally, an additional input file is needed for the ROSCO controller. Though the controller only needs to be compiled once, each individual turbine/controller tuning requires an input file. This input file is generically dubbed "DISCON.IN''. In OpenFAST, the :code:`DLL_InFile` parameter should be set to point to the desired input file. The ROSCO toolbox is used to automatically generate the input file. These instructions are provided in the instructions for :ref:`standard_use`. -**Technical Documentation** +Technical Documentation +----------------------- A publication highlighting much of the theory behind the controller tuning and implementation methods can be found at: https://wes.copernicus.org/preprints/wes-2021-19/ +Survey +------ +Please help us better understand the ROSCO user-base and how we can improve ROSCO through this brief survey: + +.. raw:: html + + + +| Directory --------- @@ -65,5 +76,4 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. - +limitations under the License. \ No newline at end of file diff --git a/setup.py b/setup.py index 64104f31a..87b108452 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ EMAIL = 'nikhar.abbas@nrel.gov' AUTHOR = 'NREL National Wind Technology Center' REQUIRES_PYTHON = '>=3.4' -VERSION = '2.2.0' +VERSION = '2.3.0' # These packages are required for all of the code to be executed. # - Maybe you can get away with older versions... @@ -51,6 +51,8 @@ 'pytest', 'scipy', 'pyYAML', + 'future', + 'pandas' ] # Read the docs, one day, so we'll throw it in here! @@ -174,7 +176,7 @@ def run(self): self.status('Uploading the package to PyPI via Twine...') os.system('twine upload dist/*') - self.status('Pushing git tagsā€¦') + self.status('Pushing git tags...') os.system('git tag v{0}'.format(about['__version__'])) os.system('git push --tags')