diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index f8e2b398c0..aa613778cc 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -47,6 +47,8 @@ jobs: run: | python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" + sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - name: Configure build @@ -57,6 +59,8 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBLA_VENDOR:STRING=OpenBLAS \ -DCMAKE_BUILD_TYPE:STRING=DEBUG \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DGENERATE_TYPES=ON \ @@ -85,6 +89,10 @@ jobs: uses: actions/checkout@main with: submodules: recursive + - name: Install dependencies + run: | + sudo apt-get update -y + sudo apt-get install -y libopenblas-dev - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - name: Configure build @@ -95,6 +103,8 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBLA_VENDOR:STRING=OpenBLAS \ -DCMAKE_BUILD_TYPE:STRING=DEBUG \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DVARIABLE_TRACKING=OFF \ @@ -123,6 +133,8 @@ jobs: run: | python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" + sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - name: Configure build @@ -133,6 +145,8 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBLA_VENDOR:STRING=OpenBLAS \ -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ -DVARIABLE_TRACKING=OFF \ -DBUILD_TESTING:BOOL=ON \ @@ -166,6 +180,7 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev # gcovr - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build @@ -177,6 +192,8 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBLA_VENDOR:STRING=OpenBLAS \ -DCMAKE_BUILD_TYPE:STRING=RELWITHDEBINFO \ -DOPENMP:BOOL=ON \ -DDOUBLE_PRECISION=ON \ @@ -216,7 +233,14 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure build + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + ${GITHUB_WORKSPACE} - name: Build OpenFAST C-Interfaces working-directory: ${{runner.workspace}}/openfast/build run: | @@ -247,7 +271,14 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure build + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + ${GITHUB_WORKSPACE} - name: Build OpenFAST glue-code working-directory: ${{runner.workspace}}/openfast/build run: | @@ -278,7 +309,14 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure build + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + ${GITHUB_WORKSPACE} - name: Build FAST.Farm working-directory: ${{runner.workspace}}/openfast/build run: | @@ -310,6 +348,8 @@ jobs: run: | python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" + sudo apt-get update -y + sudo apt-get install -y libopenblas-dev - name: Setup workspace run: cmake -E make_directory ${{runner.workspace}}/openfast/build - name: Configure build @@ -320,6 +360,7 @@ jobs: -DCMAKE_Fortran_COMPILER:STRING=${{env.FORTRAN_COMPILER}} \ -DCMAKE_CXX_COMPILER:STRING=${{env.CXX_COMPILER}} \ -DCMAKE_C_COMPILER:STRING=${{env.C_COMPILER}} \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ -DCMAKE_BUILD_TYPE:STRING=DEBUG \ -DBUILD_SHARED_LIBS:BOOL=OFF \ -DGENERATE_TYPES=ON \ @@ -370,7 +411,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} - name: Run AeroDyn tests uses: ./.github/actions/tests-module-aerodyn with: @@ -419,11 +469,13 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ ${GITHUB_WORKSPACE} @@ -478,7 +530,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" vtk sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev + - name: Configure Tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} - name: Run Interface / API tests working-directory: ${{runner.workspace}}/openfast/build run: | @@ -517,10 +578,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -564,10 +631,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -608,10 +681,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -652,10 +731,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -696,10 +781,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -740,10 +831,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -784,10 +881,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run OpenFAST linearization tests working-directory: ${{runner.workspace}}/openfast/build @@ -828,10 +931,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run FAST.Farm tests working-directory: ${{runner.workspace}}/openfast/build diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ae72886d1..899e0d3571 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,10 +108,18 @@ include(${CMAKE_SOURCE_DIR}/cmake/set_rpath.cmake) if (OPENMP OR BUILD_FASTFARM OR BUILD_OPENFAST_CPP_API) FIND_PACKAGE(OpenMP REQUIRED) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS} ${OpenMP_FORTRAN_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + if (OpenMP_Fortran_FOUND) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") + link_libraries("${OpenMP_Fortran_LIBRARIES}") + endif() + if (OpenMP_C_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + link_libraries("${OpenMP_C_LIBRARIES}") + endif() + if (OpenMP_CXX_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + link_libraries("${OpenMP_CXX_LIBRARIES}") + endif() endif() #------------------------------------------------------------------------------- @@ -130,11 +138,13 @@ if (USE_LOCAL_STATIC_LAPACK) include(ExternalProject) ExternalProject_Add(lapack URL http://www.netlib.org/lapack/lapack.tgz - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/install + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/install + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON PREFIX ${CMAKE_BINARY_DIR}/dependencies BUILD_BYPRODUCTS ${BLAS_LIB_PATH} ${LAPACK_LIB_PATH} ) - set(LAPACK_LIBRARIES ${BLAS_LIB_PATH} ${LAPACK_LIB_PATH} CACHE STRING "LAPACK library" FORCE) + set(LAPACK_LIBRARIES ${LAPACK_LIB_PATH} ${BLAS_LIB_PATH} CACHE STRING "LAPACK library" FORCE) install(FILES ${LAPACK_LIBRARIES} DESTINATION ${CMAKE_SOURCE_DIR}/install/lib) message(STATUS "Using LAPACK libraries: ${LAPACK_LIBRARIES}") else() diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index c63c101d77..af0848d30f 100644 Binary files a/docs/OtherSupporting/OutListParameters.xlsx and b/docs/OtherSupporting/OutListParameters.xlsx differ diff --git a/docs/changelogs/v3.5.0.md b/docs/changelogs/v3.5.0.md index 03185c77f7..27d5ac8792 100644 --- a/docs/changelogs/v3.5.0.md +++ b/docs/changelogs/v3.5.0.md @@ -98,6 +98,12 @@ See GitHub Actions #1493 Allow Non-Uniform Force Point Distribution on Blades @mchurchf +### SubDyn + +#1413 Implementing directional cosine matrices and section properties for rectangular members +#1526 Remove static improvement method (SIM) from the SubDyn elastic output mesh (y3mesh) +#1531 BugFix - diameter not set properly for rectangular beams + ## API changes diff --git a/docs/source/user/aerodyn/appendix.rst b/docs/source/user/aerodyn/appendix.rst index 6fd5b7f22b..0f60e7cf7d 100644 --- a/docs/source/user/aerodyn/appendix.rst +++ b/docs/source/user/aerodyn/appendix.rst @@ -51,27 +51,34 @@ The blade data input file contains the nodal discretization, geometry, twist, ch AeroDyn List of Output Channels ------------------------------- -This is a list of output parameters for the AeroDyn module. The names are grouped by meaning, but can be ordered in the OUTPUTS section of the AeroDyn input file as you see fit. :math:`B \alpha N \beta`, refers to output node :math:`\beta` of blade :math:`\alpha`, where :math:`\alpha` is a number in the range [1,3] and :math:`\beta` is a number in the range [1,9], corresponding to entry :math:`\beta` in the :math:`\textit{BlOutNd}` list. :math:`\textit{TwN}\beta` refers to output node :math:`\beta` of the tower and is in the range [1,9], corresponding to entry :math:`\beta` in the :math:`\textit{TwOutNd}` list. A comprehensive, up-to-date list of all possible output parameters is given in the Excel file :download:`OutListParameters.xlsx <../../../OtherSupporting/OutListParameters.xlsx>`. -The local tower coordinate system is shown in :numref:`ad_tower_geom` and the local blade coordinate system is shown in :numref:`ad_blade_local_cs` below. Figure :numref:`ad_blade_local_cs` also shows the direction of the local angles and force components. +AeroDyn has regular outputs (see :numref:`AD-Outputs`) and nodal outputs (see :numref:`AD-Nodal-Outputs`). -.. _ad_blade_local_cs: +The coordinate systems used for the outputs (labeled, i, h, p, l, a) are described in :numref:`ad_coordsys`. -.. figure:: figs/aerodyn_blade_local_cs.png - :width: 80% - :align: center - :alt: aerodyn_blade_local_cs.png - AeroDyn Local Blade Coordinate System (Looking Toward the Tip, - from the Root) – l: Lift, d: Drag, m: Pitching, x: Normal (to Plane), - y: Tangential (to Plane), n: Normal (to Chord), - and t: Tangential (to Chord) +A comprehensive, up-to-date list of all possible output parameters is given in the Excel file :download:`OutListParameters.xlsx <../../../OtherSupporting/OutListParameters.xlsx>`, in the tab `AeroDyn` and `AeroDyn_Nodes` for the regular and nodal outputs, respectively. +The names in the Excel file are grouped by meaning, but can be ordered in the OUTPUTS section of the AeroDyn input file as you see fit. -.. _ad-output-channel: -.. figure:: figs/aerodyn_output_channel.pdf - :width: 500px - :align: center - :alt: aerodyn_output_channel.pdf - AeroDyn Output Channel List +**Regular outputs** +Some examples of regular outputs are given below (see :download:`OutListParameters.xlsx <../../../OtherSupporting/OutListParameters.xlsx>` for an exhaustive list): + + + - `RtAeroCp` : aerodynamic power coefficient. + + + - :math:`B \alpha N \beta`, refers to output node :math:`\beta` of blade :math:`\alpha`, where :math:`\alpha` is a number in the range [1,3] and :math:`\beta` is a number in the range [1,9], corresponding to entry :math:`\beta` in the :math:`\textit{BlOutNd}` list. + + - :math:`\textit{TwN}\beta` refers to output node :math:`\beta` of the tower and is in the range [1,9], corresponding to entry :math:`\beta` in the :math:`\textit{TwOutNd}` list. + + +**Nodal outputs** + +An example of nodal outputs is described below (see :download:`OutListParameters.xlsx <../../../OtherSupporting/OutListParameters.xlsx>` for an exhaustive list). + +The x-component of the undisturbed flow velocity (`VUnd`) at all blade nodes in the inertial frame (:math:`i`) is requested by placing :math:`VUndxi` in the AeroDyn nodal output list. +This will result in output channels of the form `AB`:math:`\alpha N\beta` `Vundxi`, for node :math:`\beta` of blade :math:`\alpha`, where :math:`\alpha` is a number in the range [1,3] and :math:`\beta` is a number in the range [1,999] corresponding to the index of the AeroDyn blade node. + + diff --git a/docs/source/user/aerodyn/conf.py b/docs/source/user/aerodyn/conf.py index 330c0dfcef..f6bd61d28b 100644 --- a/docs/source/user/aerodyn/conf.py +++ b/docs/source/user/aerodyn/conf.py @@ -21,10 +21,36 @@ import subprocess import re - from sphinx.highlighting import PygmentsBridge from pygments.formatters.latex import LatexFormatter +#sys.path.append(os.path.abspath('_extensions/')) + +readTheDocs = os.environ.get('READTHEDOCS', None) == 'True' +builddir = sys.argv[-1] +sourcedir = sys.argv[-2] + +# Use this to turn Doxygen on or off +useDoxygen = False + +# This function was adapted from https://gitlab.kitware.com/cmb/smtk +# Only run when on readthedocs +def runDoxygen(sourcfile, doxyfileIn, doxyfileOut): + dx = open(os.path.join(sourcedir, doxyfileIn), 'r') + cfg = dx.read() + srcdir = os.path.abspath(os.path.join(os.getcwd(), '..')) + bindir = srcdir + c2 = re.sub('@CMAKE_SOURCE_DIR@', srcdir, re.sub('@CMAKE_BINARY_DIR@', bindir, cfg)) + doxname = os.path.join(sourcedir, doxyfileOut) + dox = open(doxname, 'w') + print(c2, file=dox) + dox.close() + print("Running Doxygen on {}".format(doxyfileOut)) + doxproc = subprocess.call(('doxygen', doxname)) + +if readTheDocs and useDoxygen: + runDoxygen(sourcedir, 'Doxyfile.in', 'Doxyfile') + class CustomLatexFormatter(LatexFormatter): def __init__(self, **options): super(CustomLatexFormatter, self).__init__(**options) @@ -32,12 +58,6 @@ def __init__(self, **options): PygmentsBridge.latex_formatter = CustomLatexFormatter -#sys.path.append(os.path.abspath('_extensions/')) - -readTheDocs = os.environ.get('READTHEDOCS', None) == 'True' -sourcedir = sys.argv[-2] -builddir = sys.argv[-1] - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -56,13 +76,32 @@ def __init__(self, **options): 'sphinxcontrib.bibtex', ] -autodoc_default_flags = ['members','show-inheritance','undoc-members'] +autodoc_default_flags = [ + 'members', + 'show-inheritance', + 'undoc-members' +] autoclass_content = 'both' mathjax_path = 'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' # FIXME: Naively assuming build directory one level up locally, and two up on readthedocs +if useDoxygen: + if readTheDocs: + doxylink = { + 'openfast': ( + os.path.join(builddir, '..', '..', 'openfast.tag'), + os.path.join('html') + ) + } + else: + doxylink = { + 'openfast': ( + os.path.join(builddir, '..', 'openfast.tag'), + os.path.join('html') + ) + } # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -79,7 +118,7 @@ def __init__(self, **options): # General information about the project. project = u'AeroDyn' filename = project.replace(' ','_') -copyright = u'2017, National Renewable Energy Laboratory' +copyright = u'2023, National Renewable Energy Laboratory' author = u'OpenFAST Team' # The version info for the project you're documenting, acts as replacement for @@ -96,7 +135,7 @@ def __init__(self, **options): # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +# language = None # Default is English and None is not a valid option #If true, figures, tables and code-blocks are automatically numbered if they #have a caption. At same time, the numref role is enabled. For now, it works @@ -108,6 +147,13 @@ def __init__(self, **options): # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +# FIXME: Naively assuming build directory one level up locally, and two up on readthedocs +if useDoxygen: + if readTheDocs: + html_extra_path = [os.path.join(builddir, '..', '..', 'doxygen')] + else: + html_extra_path = [os.path.join(builddir, '..', 'doxygen')] + # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -147,12 +193,15 @@ def __init__(self, **options): # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. # # 'preamble': '', + # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -162,8 +211,13 @@ def __init__(self, **options): # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, '{}.tex'.format(filename), u'{} Documentation'.format(project), - u'National Renewable Energy Laboratory', 'manual'), + ( + master_doc, + '{}.tex'.format(filename), + u'{} Documentation'.format(project), + u'National Renewable Energy Laboratory', + 'manual' + ), ] @@ -172,8 +226,13 @@ def __init__(self, **options): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, project, u'{} Documentation'.format(project), - [author], 1) + ( + master_doc, + project, + u'{} Documentation'.format(project), + [author], + 1 + ) ] @@ -183,19 +242,34 @@ def __init__(self, **options): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, filename, u'{} Documentation'.format(project), - author, project, 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + filename, + u'{} Documentation'.format(project), + author, + project, + 'One line description of project.', + 'Miscellaneous' + ), ] def setup(app): - app.add_object_type("confval", "confval", - objname="input file parameter", - indextemplate="pair: %s; input file parameter") - app.add_object_type("cmakeval", "cmakeval", - objname="CMake configuration value", - indextemplate="pair: %s; CMake configuration") - + try: + app.add_css_file('css/math_eq.css') + except: + pass + app.add_object_type( + "confval", + "confval", + objname="input file parameter", + indextemplate="pair: %s; input file parameter" + ) + app.add_object_type( + "cmakeval", + "cmakeval", + objname="CMake configuration value", + indextemplate="pair: %s; CMake configuration" + ) # --- Prolog that will be included at the top of every rst file # Here: defining the role :red: for html and latex rst_prolog = r""" @@ -216,3 +290,4 @@ def setup(app): .. role:: red """ + diff --git a/docs/source/user/aerodyn/coordsys.rst b/docs/source/user/aerodyn/coordsys.rst new file mode 100644 index 0000000000..060e480c61 --- /dev/null +++ b/docs/source/user/aerodyn/coordsys.rst @@ -0,0 +1,304 @@ + +.. _ad_coordsys: + +Coordinate systems +================== + +AeroDyn uses different coordinate system for its internal computations and its outputs. +The output channels are typically suffixed with a letter corresponding to the coordinate system being used: + +* (i): inertial system +* (h): hub system +* (p): polar system +* (l): local-polar system +* None or (w): the legacy output system. +* (n-t): the legacy airfoil system. + +The different systems are described below. + + + + +Inertial system (i) +------------------- + +The inertial system :math:`(i)` is the global system used by OpenFAST (see ElastoDyn documentation). + + + +Hub system (h) +-------------- + +The hub system :math:`(h)` rotates along the :math:`x_h` axis based on the shaft azimuthal position :math:`\psi` (see ElastoDyn documentation). + + +Polar system (p) +---------------- + +The polar system :math:`(p_k)` is constructed from the hub coordinate system :math:`(h)` +by rotating the :math:`x_h` axis by the azimuthal offset of each blade :math:`\psi_{0,k}` (the blades are distributed evenly across the azimuth). +For conciseness we refer to this system as the :math:`(p)` system. +If the number of blade is written :math:`n_B`, the azimuthal offset for blade :math:`k` is: + +.. math:: + + \begin{aligned} + \psi_{0,k} = 2 \pi \frac{k-1}{n_B} + \end{aligned} + +For blade 1, :math:`\psi_{0,1}=0`, therefore :math:`y_{p,1}=y_h` and :math:`z_{p,1}=z_h`. + +The :math:`x_{p,k}` axis is along the hub x-axis. + + +In the absence of coning, the :math:`z_{p,k}` axis corresponds to the :math:`z_{b,k}` axis of the blade. + + +Cone system (c) +--------------- + +The cone system :math:`(c)` is obtained from the polar system by a rotation about the :math:`y_{p,k}` axis of each blade :math:`k`. +See ElastoDyn/FAST8 documentation for more details. +AeroDyn uses this system to estimate the blade pitch angle (by comparing the :math:`(c)` and :math:`(b)` systems). + + + +Blade system (b) +---------------- + +The blade system :math:`(b)` is otbained from the cone system by a rotation (pitching) about the :math:`z_c` axis. +It is used to define the location of the aerodynamic center, the local twist of the blade along the span of the blade. +See :numref:`blade_data_input_file` and :numref:`ad_blade_geom`. + + + + +Airfoil system (a) +------------------ + +**Currently the user specifies the prebend orientation in the input file and it is used to orient the airfoil** (i.e. the axis :math:`z_a`). In the future, this orientation may be computed automatically from the AC-line. + + +The airfoil section system :math:`(a_{_{kj}})`, or :math:`(a)` for short, is the coordinate system where Blade Element Theory is applied, and where the airfoil shape and polar data are given. +The airfoil coordinate system, :math:`(a_{_{kj}})` is defined for each blade :math:`k` and each blade node :math:`j`. +The :math:`y_a` axis is along the airfoil chord (tangential to chord), towards the trailing +edge. +The :math:`x_a` axis is normal to chord, towards the suction side (for an asymmetric airfoil). +See :numref:`ad_cs_airfoil`. + + + +.. _ad_cs_airfoil: + +.. figure:: figs/FASTAirfoilSystem.svg + :width: 80% + :align: center + + The airfoil (a) coordinate system. + + +The :math:`(a)` system is where Blade Element Theory (BET) is applied: the angle of attack, :math:`\alpha`, the lift, :math:`L`, and drag, :math:`D`, are all defined in the :math:`x_a-y_a` plane. +The lifting line loads are computed in this system. +The relative wind in this system is the projection of the 3D +relative wind into the 2D plane of the :math:`(a)`-system, noted :math:`{}^{\perp_a}\boldsymbol{V}_\text{rel}` or :math:`\boldsymbol{V}_\text{rel,a}`. + +In the airfoil system, we have: + +.. math:: + + \begin{aligned} + C_{x_a} = C_l(\alpha) \cos\alpha + C_d(\alpha)\sin\alpha % that's Cn + ,\quad + C_{y_a} = -C_l(\alpha) \sin\alpha + C_d(\alpha)\cos\alpha % that's -Ct for the t of AeroDyn + ,\quad + C_{m_a} = C_m(\alpha) + \end{aligned} + +and the loads (per unit length) are: + +.. math:: + + \begin{aligned} + f_{x_a} = \frac{1}{2}\rho V_{\text{rel},a}^2 c C_{x_a} + ,\quad + f_{y_a} = \frac{1}{2}\rho V_{\text{rel},a}^2 c C_{y_a} + ,\quad + m_{z_a} = \frac{1}{2}\rho V_{\text{rel},a}^2 c^2 C_{m_a} + \end{aligned} + + + +Legacy (n-t) system +------------------- + +In legacy AeroDyn code and documentation, the :math:`(n-t)` system is sometimes used. +The :math:`n`-axis corresponds to the :math:`x_a` axis (normal to chord). +The :math:`t`-axis corresponds to the :math:`-y_a` axis (opposite direction). + + + + +Local polar system (l) +---------------------- + +**Currently the local polar system is only used for output purposes. It will be used in the BEM implementation in future releases.** + + +The local polar coordinate system :math:`(l_{_{kj}})`, or :math:`(l)` for short, is similar to the polar coordinate system, but is rotated about the :math:`x_h` axis, such that the :math:`z_{l,kj}` axis passes through the deflected position of node :math:`j` of blade :math:`k`. + +:math:`x_l` is along the hub :math:`x_h` axis, +and :math:`z_l` is the radial coordinate in the plane normal to the shaft axis. +The coordinate system is illustrated in :numref:`ad_cs_localpolar` for a case with prebend only (left) and presweep only (right). + + + +.. _ad_cs_localpolar: + +.. figure:: figs/FASTLocalPolarSystem.svg + :width: 70% + :align: center + + The polar (p) and local polar (l) coordinate systems. + Left: pure prebend. + Right: pure sweep. + + +The local polar coordinate system is defined for each blade node as follows. The position of a deflected blade node :math:`A_j` with respect to the hub :math:`H` is : + + .. math:: + + \begin{aligned} + \boldsymbol{r}_{HA_j} = \boldsymbol{r}_{A_j}-\boldsymbol{r}_H + \end{aligned} + +This vector is projected onto the rotor plane as follows: + + .. math:: + + \begin{aligned} + \boldsymbol{r}_{HA_j}^\perp = \mathop{\mathrm{\boldsymbol{\mathrm{P}}}}_{\boldsymbol{\hat{x}}_h}(\boldsymbol{r}_{HA_j}) = \boldsymbol{r}_{HA_j} - (\boldsymbol{\hat{x}}_h \cdot {\boldsymbol{r}_{HA_j}}) \boldsymbol{\hat{x}}_h + \end{aligned} + + +The vectors of the local polar coordinate system are then defined as: + + .. math:: + + \begin{aligned} + \boldsymbol{\hat{x}}_{l} = \boldsymbol{\hat{x}}_h + ,\quad + \boldsymbol{\hat{z}}_{l} = \frac{ \boldsymbol{r}_{HA_j}^\perp }{\lVert\boldsymbol{r}_{HA_j}\rVert} + ,\quad + \boldsymbol{\hat{y}}_{l} = \boldsymbol{\hat{z}}_h \times \boldsymbol{\hat{x}}_h + \end{aligned} + +The local polar coordinate systems of the different blade nodes differ from +an azimuthal rotation about the :math:`x_h` axis (and a translation +of origin about the :math:`x_h`-axis, which is mostly irrelevant). + + +Legacy local output system (w) +------------------------------ + +**Outputs of AeroDyn labeled "x" or "y" without any other letters defining the coordinate system are currently provided in the legacy output system.** (for instance :math:`F_x`, :math:`V_x`, or :math:`V_{dis,y}`). + +We write :math:`(w)` the legacy output system of OpenFAST. The legacy output system has previously been documented using Figure :numref:`ad_blade_local_cs`. +The figure also shows the direction of the local angles and force components. +In this figure, :math:`x` should be understood as :math:`x_w` and :math:`y` as :math:`y_w`. +The figure is mostly valid if there is no prebend, precone or presweep. + + + +.. _ad_blade_local_cs: + +.. figure:: figs/aerodyn_blade_local_cs.png + :width: 80% + :align: center + :alt: aerodyn_blade_local_cs.png + + AeroDyn Legacy Local Output Coordinate System (Looking Toward the Tip, + from the Root) – l: Lift, d: Drag, m: Pitching, x: Normal (to Plane), + y: Tangential (to Plane), n: Normal (to Chord), + and t: Tangential (to Chord) + + + + + +The :math:`(w_{kj})` is defined for each blade :math:`k` and node :math:`j`, written :math:`(w)` for conciseness. +The :math:`(w)` system is a transformation of the airfoil system such that this system has no +rotation about the :math:`x` (sweep) or :math:`z` (pitch/twist) axis compared to the coned coordinate system. + + - The :math:`y_w`-axis (in plane) of this system is orthogonal to + the pitch axis, neglecting presweep and in-plane deflection. + + - The :math:`x_w`-axis (out of plane) is normal to the deflected + blade, including precurve and out-of-plane deflection. + + - The :math:`z_w`-axis (radial) is tangent to the deflected blade, + including precurve and out-of-plane deflection. + +The system is constructed as follows in AeroDyn. First, the coned +coordinate system :math:`(c)` (located at the blade root, coned, but +without pitching) is defined using the following substeps and +matrices: + + - :math:`\boldsymbol{R}_{bi}`: from inertial to blade root (the + blade root is pitched by :math:`\theta_p`). + + - :math:`\boldsymbol{R}_{hi}`: from inertial to hub. + + - :math:`\boldsymbol{R}_{bh} = \boldsymbol{R}_{bi} \boldsymbol{R}_{hi}^t=\mathop{\mathrm{Euler}}(\theta_1, \theta_2, -\theta_p)`: + from hub to blade. The third Euler angle from + :math:`\boldsymbol{R}_{bh}` is the opposite of the pitch angle + :math:`\theta_p` (wind turbines use a negative convention of pitch + and twist about the :math:`z` axis). By setting this Euler angle + to zero and constructing the transformation matrix from the two + first angles, one obtains: + + - :math:`\boldsymbol{R}_{ch}=\mathop{\mathrm{Euler}}(\theta_1, \theta_2,0)`: + from hub to the coned coordinate system. + + - :math:`\boldsymbol{R}_{ci}=\boldsymbol{R}_{ch} \boldsymbol{R}_{hi}`: + from inertial to coned coordinate system. + +Then, the :math:`(w)` system is defined for each airfoil cross +section: + + - :math:`\boldsymbol{R}_{ai}`: from inertial to blade airfoil + section (include elastic motions) + + - From coned system to blade airfoil section: + + .. math:: + + \begin{aligned} + \boldsymbol{R}_{ac}=\boldsymbol{R}_{ai}\boldsymbol{R}_{ci}^t=\mathop{\mathrm{Euler}}({}^w\!\tau,{}^w\!\kappa,-{}^w\!\beta) + \label{eq:R_acBetaFull} + \end{aligned} + + where :math:`{}^w\!\beta` contains the full twist (aerodynamic, + elastic and pitch), :math:`{}^w\!\tau` would be the toe angle (but + it is not used) :math:`{}^w\!\kappa` is the cant angle (stored as + ``Curve``). We use the supperscript :math:`w` because these angles + are defined as part of the :math:`(w)` system. + + - :math:`\boldsymbol{R}_{wc}=\mathop{\mathrm{Euler}}(0,{}^w\!\kappa,0)`: + from coned system to :math:`w`-system. The :math:`(w)` system + keeps only the rotation about :math:`y_c` + (:math:`\approx`\ prebend), thereby neglecting the ones about + :math:`x` (sweep) and :math:`z` (:math:`\approx` twist+pitch). + + - :math:`\boldsymbol{R}_{wi}=\boldsymbol{R}_{wc}\boldsymbol{R}_{ci}`: + from inertial system to :math:`w`-system + + + + + + + +Tower system +------------ + +The local tower coordinate system is shown in :numref:`ad_tower_geom`. diff --git a/docs/source/user/aerodyn/figs/FASTAirfoilSystem.svg b/docs/source/user/aerodyn/figs/FASTAirfoilSystem.svg new file mode 100644 index 0000000000..5777caa96d --- /dev/null +++ b/docs/source/user/aerodyn/figs/FASTAirfoilSystem.svg @@ -0,0 +1,705 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + α + + n + t + xa + ya + + Chord axis + AC + L + D + aVrel + + diff --git a/docs/source/user/aerodyn/figs/FASTLocalPolarSystem.svg b/docs/source/user/aerodyn/figs/FASTLocalPolarSystem.svg new file mode 100644 index 0000000000..ffbae8227a --- /dev/null +++ b/docs/source/user/aerodyn/figs/FASTLocalPolarSystem.svg @@ -0,0 +1,611 @@ + + + +shaft axisAjxpxlzpzlypHBzpHBylzlAj diff --git a/docs/source/user/aerodyn/figs/UAAirfoilSystem.png b/docs/source/user/aerodyn/figs/UAAirfoilSystem.png deleted file mode 100644 index e123b10289..0000000000 Binary files a/docs/source/user/aerodyn/figs/UAAirfoilSystem.png and /dev/null differ diff --git a/docs/source/user/aerodyn/figs/UAAirfoilSystem.svg b/docs/source/user/aerodyn/figs/UAAirfoilSystem.svg index 9247086220..ec6f2d2cc2 100644 --- a/docs/source/user/aerodyn/figs/UAAirfoilSystem.svg +++ b/docs/source/user/aerodyn/figs/UAAirfoilSystem.svg @@ -2,19 +2,19 @@ + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + sodipodi:docname="UAAirfoilSystem.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + showguides="false" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1"> + originx="58.972191" + originy="-154.73952" /> + is_visible="true" + lpeversion="0" /> + is_visible="true" + lpeversion="0" /> + effect="spiro" + lpeversion="0" /> + is_visible="true" + lpeversion="0" /> + is_visible="true" + lpeversion="0" /> @@ -118,7 +126,7 @@ inkscape:stockid="Arrow1Lend"> @@ -132,7 +140,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -146,7 +154,7 @@ inkscape:stockid="Arrow1Lend"> @@ -160,7 +168,7 @@ inkscape:stockid="Arrow1Lend"> @@ -174,7 +182,7 @@ inkscape:stockid="Arrow1Lend"> @@ -188,7 +196,7 @@ inkscape:stockid="Arrow1Lend"> @@ -202,7 +210,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -216,7 +224,7 @@ inkscape:stockid="Arrow1Lend"> @@ -230,7 +238,7 @@ inkscape:stockid="Arrow1Lend"> @@ -244,7 +252,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -258,7 +266,7 @@ inkscape:stockid="Arrow1Lend"> @@ -272,7 +280,7 @@ inkscape:stockid="Arrow1Lend"> @@ -286,7 +294,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -300,7 +308,7 @@ inkscape:stockid="Arrow1Lend"> @@ -314,7 +322,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -328,7 +336,7 @@ inkscape:stockid="Arrow1Lend"> @@ -342,7 +350,7 @@ inkscape:stockid="Arrow1Lstart"> @@ -356,7 +364,7 @@ inkscape:stockid="Arrow1Lend"> @@ -370,7 +378,7 @@ inkscape:stockid="Arrow1Lend"> @@ -384,7 +392,7 @@ inkscape:stockid="Arrow1Lend"> @@ -398,7 +406,7 @@ inkscape:stockid="Arrow1Lend"> @@ -412,7 +420,7 @@ inkscape:stockid="Arrow1Lend"> @@ -426,7 +434,7 @@ inkscape:stockid="Arrow1Lend"> @@ -440,12 +448,12 @@ image/svg+xml - + @@ -453,7 +461,7 @@ inkscape:groupmode="layer" id="layer3" inkscape:label="Text" - transform="translate(-782.14697,-510.0731)" + transform="translate(-777.46056,-510.40982)" style="display:inline"> + style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:4, 2, 1, 2;stroke-dashoffset:0;stroke-opacity:1" /> + sodipodi:type="arc" + sodipodi:arc-type="arc" /> - xs ys - Chord axis + sodipodi:open="true" + sodipodi:arc-type="arc" /> - vy vx - 3/4 - ac - t n - α ω + x="1050.411" + y="566.16785" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.4763px;font-family:'Cambria Math';-inkscape-font-specification:'Cambria Math, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:1">ω + + + + v + y="89.350891" + style="stroke-width:0.931917" />+ + + n + t + xa + ya + + Chord axis + ac + αac + 3/4 + vy,ac + vx,ac + diff --git a/docs/source/user/aerodyn/index.rst b/docs/source/user/aerodyn/index.rst index 9fafc5a5e6..7b414b4b28 100644 --- a/docs/source/user/aerodyn/index.rst +++ b/docs/source/user/aerodyn/index.rst @@ -26,6 +26,7 @@ The documentation here was derived from AeroDyn Manual for AeroDyn version 15.04 :maxdepth: 2 introduction.rst + coordsys.rst input.rst output.rst modeling.rst diff --git a/docs/source/user/aerodyn/introduction.rst b/docs/source/user/aerodyn/introduction.rst index 6a1a380e80..c743fc2875 100644 --- a/docs/source/user/aerodyn/introduction.rst +++ b/docs/source/user/aerodyn/introduction.rst @@ -199,3 +199,6 @@ file, and the results file. using AeroDyn. Example input files are included in :numref:`ad_input_files`. A summary of available output channels are found :numref:`ad_output_channels`. + + + diff --git a/docs/source/user/aerodyn/theory_ua.rst b/docs/source/user/aerodyn/theory_ua.rst index d55699d5b5..005e478fdd 100644 --- a/docs/source/user/aerodyn/theory_ua.rst +++ b/docs/source/user/aerodyn/theory_ua.rst @@ -45,8 +45,8 @@ the inputs present in the profile input file (including some of the ones repeate The airfoil section coordinate system and main variables are presented in :numref:`fig:UAAirfoilSystem` and further described below: -.. figure:: figs/UAAirfoilSystem.png - :width: 60% +.. figure:: figs/UAAirfoilSystem.svg + :width: 70% :name: fig:UAAirfoilSystem Definition of aifoil section coordinate system used in the unsteady aerodynamics module diff --git a/glue-codes/simulink/CMakeLists.txt b/glue-codes/simulink/CMakeLists.txt index f4251c35cd..1da4052938 100644 --- a/glue-codes/simulink/CMakeLists.txt +++ b/glue-codes/simulink/CMakeLists.txt @@ -14,6 +14,33 @@ # limitations under the License. # +# List of module libraries to be linked into the MEX shared library. +# This list will be linked twice to resolve undefined symbols due to linking order. +set(MEX_LIBS + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ # MATLAB Specific + $ + $ + $ + $ + $ + $ + $ # MATLAB Specific +) + # Build the matlab shared library (mex) using the current toolchain. # Recommpiles FAST_* files with COMPILE_SIMULINK defined. # Links directly to library files, bypassing dependencies so MATLAB specific @@ -30,28 +57,8 @@ matlab_add_mex( ${PROJECT_SOURCE_DIR}/modules/openfast-library/src/FAST_Solver.f90 ${PROJECT_SOURCE_DIR}/modules/openfast-library/src/FAST_Library.f90 LINK_TO - $ # MATLAB Specific - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ - $ # MATLAB Specific - $ - $ - $ - $ + ${MEX_LIBS} + ${MEX_LIBS} # DO NOT REMOVE (needed to ensure no unresolved symbols) ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES} diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index be39679134..c867913b1a 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -604,9 +604,11 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) errStat = ErrID_None errMsg = "" - call AllocAry( m%DisturbedInflow, 3_IntKi, p%NumBlNds, p%numBlades, 'OtherState%DisturbedInflow', ErrStat2, ErrMsg2 ) ! must be same size as u%InflowOnBlade + call AllocAry( m%DisturbedInflow, 3_IntKi, p%NumBlNds, p%numBlades, 'm%DisturbedInflow', ErrStat2, ErrMsg2 ) ! must be same size as u%InflowOnBlade call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) - call AllocAry( m%orientationAnnulus, 3_IntKi, 3_IntKi, p%NumBlNds, p%numBlades, 'OtherState%orientationAnnulus', ErrStat2, ErrMsg2 ) + call AllocAry( m%orientationAnnulus, 3_IntKi, 3_IntKi, p%NumBlNds, p%numBlades, 'm%orientationAnnulus', ErrStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + call AllocAry( m%R_li, 3_IntKi, 3_IntKi, p%NumBlNds, p%numBlades, 'm%R_li', ErrStat2, ErrMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) call allocAry( m%SigmaCavit, p%NumBlNds, p%numBlades, 'm%SigmaCavit', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -652,6 +654,8 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) call AllocAry( m%Mz, p%NumBlNds, p%NumBlades, 'm%Mz', ErrStat2, ErrMsg2 ) call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) + call AllocAry( m%Vind_i, 3, p%NumBlNds, p%NumBlades, 'm%Vind_i', ErrStat2, ErrMsg2 ) + call SetErrStat( errStat2, errMsg2, errStat, errMsg, RoutineName ) ! mesh mapping data for integrating load over entire rotor: allocate( m%B_L_2_H_P(p%NumBlades), Stat = ErrStat2) if (ErrStat2 /= 0) then @@ -1836,11 +1840,12 @@ subroutine RotWriteOutputs( t, u, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRo ! NOTE: m%BEMT_u(i) indices are set differently from the way OpenFAST typically sets up the u and uTimes arrays integer, parameter :: indx = 1 ! m%BEMT_u(1) is at t; m%BEMT_u(2) is t+dt - integer(intKi) :: i + integer(intKi) :: i, k integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'RotCalcOutput' + real(R8Ki) :: x_hat_disk(3) ! LOGICAL :: CalcWriteOutput !------------------------------------------------------- ! get values to output to file: @@ -1864,6 +1869,14 @@ subroutine RotWriteOutputs( t, u, p, p_AD, x, xd, z, OtherState, y, m, m_AD, iRo ! Now we need to populate the blade node outputs here if (p%NumBlades > 0) then + ! For all methods (BEM/FVW), computes R_li: from inertial system to local-polar system + ! NOTE: this could be placed either in AeroDyn_IO* or in SetInputs + ! The issue right now is the Calculate_MeshOrientation_Rel2Hub is in AeroDyn.f90 + x_hat_disk = u%HubMotion%Orientation(1,:,1) + do k=1,p%NumBlades + ! Compute R_li for all nodes + call Calculate_MeshOrientation_Rel2Hub(u%BladeMotion(k), u%HubMotion, x_hat_disk, m%R_li(:,:,:,k)) + enddo call Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, indx, iRot, ErrStat2, ErrMsg2 ) ! Call after normal writeoutput. Will just postpend data on here. call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end if @@ -2102,16 +2115,16 @@ subroutine CalcBuoyantLoads( u, p, m, y, ErrStat, ErrMsg ) BlmomentBplus(3) = BlmomentBplus(3) + BlglobCBplus(1) * BlforceBplus(2) - BlglobCBplus(2) * BlforceBplus(1) ! Sum loads at each node - BlFBtmp(j,k,:) = BlFBtmp(j,k,:) + BlforceB + BlFBtmp(j,k,:) = BlFBtmp(j ,k,:) + BlforceB BlFBtmp(j+1,k,:) = BlFBtmp(j+1,k,:) + BlforceBplus - BlMBtmp(j,k,:) = BlMBtmp(j,k,:) + BlmomentB + BlMBtmp(j,k,:) = BlMBtmp(j ,k,:) + BlmomentB BlMBtmp(j+1,k,:) = BlMBtmp(j+1,k,:) + BlmomentBplus end do ! j = nodes ! Assign loads to point mesh do j = 1,p%NumBlNds - m%BladeBuoyLoadPoint(k)%Force(:,j) = BlFBtmp(j,k,:) + m%BladeBuoyLoadPoint(k)%Force(:,j) = BlFBtmp(j,k,:) m%BladeBuoyLoadPoint(k)%Moment(:,j) = BlMBtmp(j,k,:) end do ! j = nodes @@ -2630,7 +2643,7 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) !.......................... if (p%AeroProjMod==APM_BEM_NoSweepPitchTwist .or. p%AeroProjMod==APM_LiftingLine) then - m%BEMT_u(indx)%psi = Azimuth + m%BEMT_u(indx)%psi_s = Azimuth elseif (p%AeroProjMod==APM_BEM_Polar) then do k=1,p%NumBlades @@ -2640,7 +2653,7 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) ! Extract azimuth angle for blade k ! NOTE: EB, this might need improvements (express wrt hub, also deal with case hubRad=0). This is likely not psi_skew. theta = -EulerExtract( transpose(orientationBladeAzimuth(:,:,1)) ) - m%BEMT_u(indx)%psi(k) = theta(1) + m%BEMT_u(indx)%psi_s(k) = theta(1) end do !k=blades ! Find the most-downwind azimuth angle needed by the skewed wake correction model @@ -2776,8 +2789,9 @@ subroutine SetInputsForBEMT(p, u, m, indx, errStat, errMsg) m%BEMT_u(indx)%Vz(j,k) = dot_product( tmp, m%orientationAnnulus(3,:,j,k) ) ! radial component (tangential to the plane, not chord) of the inflow velocity of the jth node in the kth blade ! NOTE: We'll likely remove that: - m%BEMT_u(indx)%xVelCorr(j,k) = TwoNorm(m%DisturbedInflow(:,j,k))*( sin(yaw)*sin(-m%BEMT_u(indx)%cantAngle(j,k))*sin(m%BEMT_u(indx)%psi(k)) & - + sin(tilt)*cos(yaw)*sin(-m%BEMT_u(indx)%cantAngle(j,k))*cos(m%BEMT_u(indx)%psi(k)) ) !m%BEMT_u(indx)%Vy(j,k)*sin(-theta(2))*sin(m%BEMT_u(indx)%psi(k)) + !m%BEMT_u(indx)%xVelCorr(j,k) = TwoNorm(m%DisturbedInflow(:,j,k))*( sin(yaw)*sin(-m%BEMT_u(indx)%cantAngle(j,k))*sin(m%BEMT_u(indx)%psi_s(k)) & + ! + sin(tilt)*cos(yaw)*sin(-m%BEMT_u(indx)%cantAngle(j,k))*cos(m%BEMT_u(indx)%psi_s(k)) ) !m%BEMT_u(indx)%Vy(j,k)*sin(-theta(2))*sin(m%BEMT_u(indx)%psi(k)) + m%BEMT_u(indx)%xVelCorr(j,k) = 0.0_ReKi ! TODO end do !j=nodes end do !k=blades @@ -4003,6 +4017,8 @@ SUBROUTINE Init_BEMTmodule( InputFileData, RotInputFileData, u_AD, u, p, p_AD, x rMax = 0.0_ReKi do k=1,p%numBlades + ! --- Curvilinear coordinates + ! TODO place this in a function InitInp%zHub(k) = TwoNorm( u_AD%BladeRootMotion(k)%Position(:,1) - u_AD%HubMotion%Position(:,1) ) !if (EqualRealNos(InitInp%zHub(k),0.0_ReKi) ) & ! call SetErrStat( ErrID_Fatal, "zHub for blade "//trim(num2lstr(k))//" is zero.", ErrStat, ErrMsg, RoutineName) @@ -4015,6 +4031,8 @@ SUBROUTINE Init_BEMTmodule( InputFileData, RotInputFileData, u_AD, u, p, p_AD, x InitInp%zTip(k) = InitInp%zLocal(p%NumBlNds,k) + ! --- Projected radius onto plane normal to x_hat_disk + ! Note this is the same as local-polar radial position y_hat_disk = u_AD%HubMotion%Orientation(2,:,1) z_hat_disk = u_AD%HubMotion%Orientation(3,:,1) @@ -4353,7 +4371,7 @@ SUBROUTINE TFin_CalcOutput(p, p_AD, u, m, y, ErrStat, ErrMsg ) force_tf(:) = 0.0_ReKi moment_tf(:) = 0.0_ReKi force_tf(1) = Cx * q - force_tf(2) = Cy * q * p%TFin%TFinChord + force_tf(2) = Cy * q force_tf(3) = 0.0_ReKi moment_tf(1:2) = 0.0_ReKi moment_tf(3) = AFI_interp%Cm * q * p%TFin%TFinChord @@ -4628,13 +4646,16 @@ FUNCTION CalculateTowerInfluence(p, xbar_in, ybar, zbar, W_tower, TwrCd, TwrTI) v_TwrPotent = ( -2.0*xbar * ybar ) / denom elseif (p%TwrPotent == TwrPotent_Bak) then - xbar = xbar + 0.1 + ! Reference: Bak, Madsen, Johansen (2001): Influence from Blade-Tower Interaction on Fatigue Loads and Dynamics (poster); + ! Proceedings: EWEC'01; Copenhagen (DK) + xbar = xbar + 0.1 ! offset added as part of the original model of Bak et al. denom = (xbar**2 + ybar**2)**2 u_TwrPotent = ( -1.0*xbar**2 + ybar**2 ) / denom v_TwrPotent = ( -2.0*xbar * ybar ) / denom denom = TwoPi*(xbar**2 + ybar**2) u_TwrPotent = u_TwrPotent + TwrCd*xbar / denom v_TwrPotent = v_TwrPotent + TwrCd*ybar / denom + xbar = xbar - 0.1 ! removing offset end if end if diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index 72a199cce9..1318ab04e2 100644 --- a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 @@ -35,78 +35,163 @@ MODULE AeroDyn_AllBldNdOuts_IO ! Blade: - INTEGER(IntKi), PARAMETER :: BldNd_VUndx = 1 - INTEGER(IntKi), PARAMETER :: BldNd_VUndy = 2 - INTEGER(IntKi), PARAMETER :: BldNd_VUndz = 3 - INTEGER(IntKi), PARAMETER :: BldNd_Vundxi = 4 - INTEGER(IntKi), PARAMETER :: BldNd_Vundyi = 5 - INTEGER(IntKi), PARAMETER :: BldNd_Vundzi = 6 - INTEGER(IntKi), PARAMETER :: BldNd_VDisx = 7 - INTEGER(IntKi), PARAMETER :: BldNd_VDisy = 8 - INTEGER(IntKi), PARAMETER :: BldNd_VDisz = 9 - INTEGER(IntKi), PARAMETER :: BldNd_STVx = 10 - INTEGER(IntKi), PARAMETER :: BldNd_STVy = 11 - INTEGER(IntKi), PARAMETER :: BldNd_STVz = 12 - INTEGER(IntKi), PARAMETER :: BldNd_VRel = 13 - INTEGER(IntKi), PARAMETER :: BldNd_DynP = 14 - INTEGER(IntKi), PARAMETER :: BldNd_Re = 15 - INTEGER(IntKi), PARAMETER :: BldNd_M = 16 - INTEGER(IntKi), PARAMETER :: BldNd_Vindx = 17 - INTEGER(IntKi), PARAMETER :: BldNd_Vindy = 18 - INTEGER(IntKi), PARAMETER :: BldNd_AxInd = 19 - INTEGER(IntKi), PARAMETER :: BldNd_TnInd = 20 - INTEGER(IntKi), PARAMETER :: BldNd_Alpha = 21 - INTEGER(IntKi), PARAMETER :: BldNd_Theta = 22 - INTEGER(IntKi), PARAMETER :: BldNd_Phi = 23 - INTEGER(IntKi), PARAMETER :: BldNd_Curve = 24 - INTEGER(IntKi), PARAMETER :: BldNd_Cl = 25 - INTEGER(IntKi), PARAMETER :: BldNd_Cd = 26 - INTEGER(IntKi), PARAMETER :: BldNd_Cm = 27 - INTEGER(IntKi), PARAMETER :: BldNd_Cx = 28 - INTEGER(IntKi), PARAMETER :: BldNd_Cy = 29 - INTEGER(IntKi), PARAMETER :: BldNd_Cn = 30 - INTEGER(IntKi), PARAMETER :: BldNd_Ct = 31 - INTEGER(IntKi), PARAMETER :: BldNd_Fl = 32 - INTEGER(IntKi), PARAMETER :: BldNd_Fd = 33 - INTEGER(IntKi), PARAMETER :: BldNd_Mm = 34 - INTEGER(IntKi), PARAMETER :: BldNd_Fx = 35 - INTEGER(IntKi), PARAMETER :: BldNd_Fy = 36 - INTEGER(IntKi), PARAMETER :: BldNd_Fn = 37 - INTEGER(IntKi), PARAMETER :: BldNd_Ft = 38 - INTEGER(IntKi), PARAMETER :: BldNd_Clrnc = 39 - INTEGER(IntKi), PARAMETER :: BldNd_Vx = 40 - INTEGER(IntKi), PARAMETER :: BldNd_Vy = 41 - INTEGER(IntKi), PARAMETER :: BldNd_GeomPhi = 42 - INTEGER(IntKi), PARAMETER :: BldNd_Chi = 43 - INTEGER(IntKi), PARAMETER :: BldNd_UA_Flag = 44 - INTEGER(IntKi), PARAMETER :: BldNd_UA_x1 = 45 - INTEGER(IntKi), PARAMETER :: BldNd_UA_x2 = 46 - INTEGER(IntKi), PARAMETER :: BldNd_UA_x3 = 47 - INTEGER(IntKi), PARAMETER :: BldNd_UA_x4 = 48 - INTEGER(IntKi), PARAMETER :: BldNd_UA_x5 = 49 - INTEGER(IntKi), PARAMETER :: BldNd_Debug1 = 50 - INTEGER(IntKi), PARAMETER :: BldNd_Debug2 = 51 - INTEGER(IntKi), PARAMETER :: BldNd_Debug3 = 52 - INTEGER(IntKi), PARAMETER :: BldNd_CpMin = 53 - INTEGER(IntKi), PARAMETER :: BldNd_SgCav = 54 - INTEGER(IntKi), PARAMETER :: BldNd_SigCr = 55 - INTEGER(IntKi), PARAMETER :: BldNd_Gam = 56 - INTEGER(IntKi), PARAMETER :: BldNd_Cl_Static = 57 - INTEGER(IntKi), PARAMETER :: BldNd_Cd_Static = 58 - INTEGER(IntKi), PARAMETER :: BldNd_Cm_Static = 59 - INTEGER(IntKi), PARAMETER :: BldNd_Uin = 60 - INTEGER(IntKi), PARAMETER :: BldNd_Uit = 61 - INTEGER(IntKi), PARAMETER :: BldNd_Uir = 62 - INTEGER(IntKi), PARAMETER :: BldNd_Fbn = 63 - INTEGER(IntKi), PARAMETER :: BldNd_Fbt = 64 - INTEGER(IntKi), PARAMETER :: BldNd_Fbs = 65 - INTEGER(IntKi), PARAMETER :: BldNd_Mbn = 66 - INTEGER(IntKi), PARAMETER :: BldNd_Mbt = 67 - INTEGER(IntKi), PARAMETER :: BldNd_Mbs = 68 + INTEGER(IntKi), PARAMETER :: BldNd_VUndx = 1 + INTEGER(IntKi), PARAMETER :: BldNd_VUndy = 2 + INTEGER(IntKi), PARAMETER :: BldNd_VUndz = 3 + INTEGER(IntKi), PARAMETER :: BldNd_VUndxi = 4 + INTEGER(IntKi), PARAMETER :: BldNd_VUndyi = 5 + INTEGER(IntKi), PARAMETER :: BldNd_VUndzi = 6 + INTEGER(IntKi), PARAMETER :: BldNd_VUndxp = 7 + INTEGER(IntKi), PARAMETER :: BldNd_VUndyp = 8 + INTEGER(IntKi), PARAMETER :: BldNd_VUndzp = 9 + INTEGER(IntKi), PARAMETER :: BldNd_VUndxl = 10 + INTEGER(IntKi), PARAMETER :: BldNd_VUndyl = 11 + INTEGER(IntKi), PARAMETER :: BldNd_VUndzl = 12 + INTEGER(IntKi), PARAMETER :: BldNd_VUndxa = 13 + INTEGER(IntKi), PARAMETER :: BldNd_VUndya = 14 + INTEGER(IntKi), PARAMETER :: BldNd_VUndza = 15 + INTEGER(IntKi), PARAMETER :: BldNd_VDisx = 16 + INTEGER(IntKi), PARAMETER :: BldNd_VDisy = 17 + INTEGER(IntKi), PARAMETER :: BldNd_VDisz = 18 + INTEGER(IntKi), PARAMETER :: BldNd_VDisxi = 19 + INTEGER(IntKi), PARAMETER :: BldNd_VDisyi = 20 + INTEGER(IntKi), PARAMETER :: BldNd_VDiszi = 21 + INTEGER(IntKi), PARAMETER :: BldNd_VDisxp = 22 + INTEGER(IntKi), PARAMETER :: BldNd_VDisyp = 23 + INTEGER(IntKi), PARAMETER :: BldNd_VDiszp = 24 + INTEGER(IntKi), PARAMETER :: BldNd_VDisxl = 25 + INTEGER(IntKi), PARAMETER :: BldNd_VDisyl = 26 + INTEGER(IntKi), PARAMETER :: BldNd_VDiszl = 27 + INTEGER(IntKi), PARAMETER :: BldNd_VDisxa = 28 + INTEGER(IntKi), PARAMETER :: BldNd_VDisya = 29 + INTEGER(IntKi), PARAMETER :: BldNd_VDisza = 30 + INTEGER(IntKi), PARAMETER :: BldNd_STVx = 31 + INTEGER(IntKi), PARAMETER :: BldNd_STVy = 32 + INTEGER(IntKi), PARAMETER :: BldNd_STVz = 33 + INTEGER(IntKi), PARAMETER :: BldNd_STVxi = 34 + INTEGER(IntKi), PARAMETER :: BldNd_STVyi = 35 + INTEGER(IntKi), PARAMETER :: BldNd_STVzi = 36 + INTEGER(IntKi), PARAMETER :: BldNd_STVxp = 37 + INTEGER(IntKi), PARAMETER :: BldNd_STVyp = 38 + INTEGER(IntKi), PARAMETER :: BldNd_STVzp = 39 + INTEGER(IntKi), PARAMETER :: BldNd_STVxl = 40 + INTEGER(IntKi), PARAMETER :: BldNd_STVyl = 41 + INTEGER(IntKi), PARAMETER :: BldNd_STVzl = 42 + INTEGER(IntKi), PARAMETER :: BldNd_STVxa = 43 + INTEGER(IntKi), PARAMETER :: BldNd_STVya = 44 + INTEGER(IntKi), PARAMETER :: BldNd_STVza = 45 + INTEGER(IntKi), PARAMETER :: BldNd_Vindx = 46 + INTEGER(IntKi), PARAMETER :: BldNd_Vindy = 47 + INTEGER(IntKi), PARAMETER :: BldNd_Vindxi = 48 + INTEGER(IntKi), PARAMETER :: BldNd_Vindyi = 49 + INTEGER(IntKi), PARAMETER :: BldNd_Vindzi = 50 + INTEGER(IntKi), PARAMETER :: BldNd_Vindxp = 51 + INTEGER(IntKi), PARAMETER :: BldNd_Vindyp = 52 + INTEGER(IntKi), PARAMETER :: BldNd_Vindzp = 53 + INTEGER(IntKi), PARAMETER :: BldNd_Vindxl = 54 + INTEGER(IntKi), PARAMETER :: BldNd_Vindyl = 55 + INTEGER(IntKi), PARAMETER :: BldNd_Vindzl = 56 + INTEGER(IntKi), PARAMETER :: BldNd_Vindxa = 57 + INTEGER(IntKi), PARAMETER :: BldNd_Vindya = 58 + INTEGER(IntKi), PARAMETER :: BldNd_Vindza = 59 + INTEGER(IntKi), PARAMETER :: BldNd_Vx = 60 + INTEGER(IntKi), PARAMETER :: BldNd_Vy = 61 + INTEGER(IntKi), PARAMETER :: BldNd_VRel = 62 + INTEGER(IntKi), PARAMETER :: BldNd_DynP = 63 + INTEGER(IntKi), PARAMETER :: BldNd_Re = 64 + INTEGER(IntKi), PARAMETER :: BldNd_M = 65 + INTEGER(IntKi), PARAMETER :: BldNd_AxInd = 66 + INTEGER(IntKi), PARAMETER :: BldNd_TnInd = 67 + INTEGER(IntKi), PARAMETER :: BldNd_AxInd_qs = 68 + INTEGER(IntKi), PARAMETER :: BldNd_TnInd_qs = 69 + INTEGER(IntKi), PARAMETER :: BldNd_Alpha = 70 + INTEGER(IntKi), PARAMETER :: BldNd_Phi = 71 + INTEGER(IntKi), PARAMETER :: BldNd_Theta = 72 + INTEGER(IntKi), PARAMETER :: BldNd_Curve = 73 + INTEGER(IntKi), PARAMETER :: BldNd_Toe = 74 + INTEGER(IntKi), PARAMETER :: BldNd_Cl = 75 + INTEGER(IntKi), PARAMETER :: BldNd_Cd = 76 + INTEGER(IntKi), PARAMETER :: BldNd_Cm = 77 + INTEGER(IntKi), PARAMETER :: BldNd_Cx = 78 + INTEGER(IntKi), PARAMETER :: BldNd_Cy = 79 + INTEGER(IntKi), PARAMETER :: BldNd_Cn = 80 + INTEGER(IntKi), PARAMETER :: BldNd_Ct = 81 + INTEGER(IntKi), PARAMETER :: BldNd_Fxi = 82 + INTEGER(IntKi), PARAMETER :: BldNd_Fyi = 83 + INTEGER(IntKi), PARAMETER :: BldNd_Fzi = 84 + INTEGER(IntKi), PARAMETER :: BldNd_Mxi = 85 + INTEGER(IntKi), PARAMETER :: BldNd_Myi = 86 + INTEGER(IntKi), PARAMETER :: BldNd_Mzi = 87 + INTEGER(IntKi), PARAMETER :: BldNd_Fxp = 88 + INTEGER(IntKi), PARAMETER :: BldNd_Fyp = 89 + INTEGER(IntKi), PARAMETER :: BldNd_Fzp = 90 + INTEGER(IntKi), PARAMETER :: BldNd_Mxp = 91 + INTEGER(IntKi), PARAMETER :: BldNd_Myp = 92 + INTEGER(IntKi), PARAMETER :: BldNd_Mzp = 93 + INTEGER(IntKi), PARAMETER :: BldNd_Fxl = 94 + INTEGER(IntKi), PARAMETER :: BldNd_Fyl = 95 + INTEGER(IntKi), PARAMETER :: BldNd_Fzl = 96 + INTEGER(IntKi), PARAMETER :: BldNd_Mxl = 97 + INTEGER(IntKi), PARAMETER :: BldNd_Myl = 98 + INTEGER(IntKi), PARAMETER :: BldNd_Mzl = 99 + INTEGER(IntKi), PARAMETER :: BldNd_Fl = 100 + INTEGER(IntKi), PARAMETER :: BldNd_Fd = 101 + INTEGER(IntKi), PARAMETER :: BldNd_Mm = 102 + INTEGER(IntKi), PARAMETER :: BldNd_Fx = 103 + INTEGER(IntKi), PARAMETER :: BldNd_Fy = 104 + INTEGER(IntKi), PARAMETER :: BldNd_Fn = 105 + INTEGER(IntKi), PARAMETER :: BldNd_Ft = 106 + INTEGER(IntKi), PARAMETER :: BldNd_Gam = 107 + INTEGER(IntKi), PARAMETER :: BldNd_Clrnc = 108 + INTEGER(IntKi), PARAMETER :: BldNd_GeomPhi = 109 + INTEGER(IntKi), PARAMETER :: BldNd_Chi = 110 + INTEGER(IntKi), PARAMETER :: BldNd_UA_Flag = 111 + INTEGER(IntKi), PARAMETER :: BldNd_UA_x1 = 112 + INTEGER(IntKi), PARAMETER :: BldNd_UA_x2 = 113 + INTEGER(IntKi), PARAMETER :: BldNd_UA_x3 = 114 + INTEGER(IntKi), PARAMETER :: BldNd_UA_x4 = 115 + INTEGER(IntKi), PARAMETER :: BldNd_UA_x5 = 116 + INTEGER(IntKi), PARAMETER :: BldNd_Debug1 = 117 + INTEGER(IntKi), PARAMETER :: BldNd_Debug2 = 118 + INTEGER(IntKi), PARAMETER :: BldNd_Debug3 = 119 + INTEGER(IntKi), PARAMETER :: BldNd_CpMin = 120 + INTEGER(IntKi), PARAMETER :: BldNd_SgCav = 121 + INTEGER(IntKi), PARAMETER :: BldNd_SigCr = 122 + INTEGER(IntKi), PARAMETER :: BldNd_BEM_F_qs = 123 + INTEGER(IntKi), PARAMETER :: BldNd_BEM_k_qs = 124 + INTEGER(IntKi), PARAMETER :: BldNd_BEM_kp_qs = 125 + INTEGER(IntKi), PARAMETER :: BldNd_BEM_CT_qs = 126 + INTEGER(IntKi), PARAMETER :: BldNd_Cl_qs = 127 + INTEGER(IntKi), PARAMETER :: BldNd_Cd_qs = 128 + INTEGER(IntKi), PARAMETER :: BldNd_Cm_qs = 129 + INTEGER(IntKi), PARAMETER :: BldNd_Fbxi = 130 + INTEGER(IntKi), PARAMETER :: BldNd_Fbyi = 131 + INTEGER(IntKi), PARAMETER :: BldNd_Fbzi = 132 + INTEGER(IntKi), PARAMETER :: BldNd_Mbxi = 133 + INTEGER(IntKi), PARAMETER :: BldNd_Mbyi = 134 + INTEGER(IntKi), PARAMETER :: BldNd_Mbzi = 135 + INTEGER(IntKi), PARAMETER :: BldNd_Fbxp = 136 + INTEGER(IntKi), PARAMETER :: BldNd_Fbyp = 137 + INTEGER(IntKi), PARAMETER :: BldNd_Fbzp = 138 + INTEGER(IntKi), PARAMETER :: BldNd_Mbxp = 139 + INTEGER(IntKi), PARAMETER :: BldNd_Mbyp = 140 + INTEGER(IntKi), PARAMETER :: BldNd_Mbzp = 141 + INTEGER(IntKi), PARAMETER :: BldNd_Fbxl = 142 + INTEGER(IntKi), PARAMETER :: BldNd_Fbyl = 143 + INTEGER(IntKi), PARAMETER :: BldNd_Fbzl = 144 + INTEGER(IntKi), PARAMETER :: BldNd_Mbxl = 145 + INTEGER(IntKi), PARAMETER :: BldNd_Mbyl = 146 + INTEGER(IntKi), PARAMETER :: BldNd_Mbzl = 147 + INTEGER(IntKi), PARAMETER :: BldNd_Fbxa = 148 + INTEGER(IntKi), PARAMETER :: BldNd_Fbya = 149 + INTEGER(IntKi), PARAMETER :: BldNd_Fbza = 150 + INTEGER(IntKi), PARAMETER :: BldNd_Mbxa = 151 + INTEGER(IntKi), PARAMETER :: BldNd_Mbya = 152 + INTEGER(IntKi), PARAMETER :: BldNd_Mbza = 153 ! The maximum number of output channels which can be output by the code. - INTEGER(IntKi), PARAMETER, PUBLIC :: BldNd_MaxOutPts = 68 + INTEGER(IntKi), PARAMETER, PUBLIC :: BldNd_MaxOutPts = 153 !End of code generated by Matlab script Write_ChckOutLst ! =================================================================================================== @@ -181,9 +266,9 @@ END SUBROUTINE AllBldNdOuts_InitOut SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx, iRot, ErrStat, ErrMsg ) TYPE(RotParameterType), INTENT(IN ) :: p ! The rotor parameters - TYPE(AD_ParameterType), INTENT(IN ) :: p_AD ! The module parameters - TYPE(RotInputType), INTENT(IN ) :: u ! inputs - TYPE(RotMiscVarType), INTENT(IN ) :: m ! misc variables + TYPE(AD_ParameterType),target,INTENT(IN ) :: p_AD ! The module parameters + TYPE(RotInputType), target, INTENT(IN ) :: u ! inputs + TYPE(RotMiscVarType), target, INTENT(IN ) :: m ! misc variables TYPE(AD_MiscVarType), INTENT(IN ) :: m_AD ! misc variables ! NOTE: temporary TYPE(RotContinuousStateType), INTENT(IN ) :: x ! rotor Continuous states TYPE(RotOutputType), INTENT(INOUT) :: y ! outputs (updates y%WriteOutput) @@ -195,20 +280,28 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! local variables - INTEGER(IntKi) :: OutIdx ! Index count within WriteOutput - INTEGER(IntKi) :: IdxBlade, iW ! Counter to which blade we are on, and Wing - INTEGER(IntKi) :: IdxNode ! Counter to the blade node we ae on + INTEGER(IntKi) :: iOut ! Index count within WriteOutput + INTEGER(IntKi) :: iB, iW ! Counter to which blade we are on, and Wing + INTEGER(IntKi) :: iNd ! Counter to the blade node we ae on INTEGER(IntKi) :: IdxChan ! Counter to the channel we are outputting. + INTEGER(IntKi) :: nB, nNd ! number of blades, number of nodes INTEGER(IntKi) :: compIndx ! index for array component (x,y,z) CHARACTER(*), PARAMETER :: RoutineName = 'Calc_WriteAllBldNdOutput' REAL(ReKi) :: ct, st ! cosine, sine of theta REAL(ReKi) :: cp, sp ! cosine, sine of phi - real(ReKi) :: M_ph(3,3) ! Transformation from hub to "blade-rotor-plane": n,t,r (not the same as AeroDyn) - real(ReKi) :: M_pg(3,3,p%NumBlades) ! Transformation from global to "blade-rotor-plane" (n,t,r), with same x at hub coordinate system + real(ReKi) :: R_ph(3,3) ! Transformation from polar to hub (azimuth rotation along x hub) + real(ReKi) :: R_pi(3,3,p%NumBlades) ! Transformation from inertial to polar (same x at hub coordinate system, blade-azimuth rotated) real(ReKi) :: psi_hub ! Azimuth wrt hub - real(ReKi) :: Vind_g(3) ! Induced velocity vector in global coordinates - real(ReKi) :: Vind_s(3) ! Induced velocity vector in section coordinates (AeroDyn "x-y") - + real(R8Ki), dimension(:,:,:,:), pointer :: R_li ! Alias. Transformation from inertial to local-polar to airfoil (3x3xnNodesxnBlades) + real(R8Ki), dimension(:,:,:,:), pointer :: R_wi ! Alias. Transformation from inertial to "WithoutSweepPitchTwist" or "orientationAnnulus". TODO: deprecate me. + integer(Intki), dimension(:) , pointer :: W2B ! Alias. Index from Wing index to Blade + + ! Alias to shorten notations + nB = p%BldNd_BladesOut + nNd = p%NumBlNds + R_li => m%R_li ! inertial to local-polar + R_wi => m%orientationAnnulus ! inertial to without-sweep-pitch-twist or orientation annulus (TODO: deprecate me) + W2B => p_AD%FVW%Bld2Wings(iRot, :) ! From Wing index to blade index ! Initialize some things ErrMsg = '' @@ -218,20 +311,18 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx return endif - - ! Precalculate the M_ph matrix -- no reason to recalculate for each output - DO IdxBlade=1,p%NumBlades - psi_hub = TwoPi*(real(IdxBlade-1,ReKi))/real(p%NumBlades,ReKi) - M_ph(1,1:3) = (/ 1.0_ReKi, 0.0_ReKi , 0.0_ReKi /) - M_ph(2,1:3) = (/ 0.0_ReKi, cos(psi_hub), sin(psi_hub) /) - M_ph(3,1:3) = (/ 0.0_ReKi,-sin(psi_hub), cos(psi_hub) /) - M_pg(1:3,1:3,IdxBlade) = matmul(M_ph, u%HubMotion%Orientation(1:3,1:3,1) ) - ENDDO - + ! Precalculate the R_pi matrix -- no reason to recalculate for each output + do iB=1,p%NumBlades + psi_hub = TwoPi*(real(iB-1,ReKi))/real(p%NumBlades,ReKi) + R_ph(1,1:3) = (/ 1.0_ReKi, 0.0_ReKi , 0.0_ReKi /) + R_ph(2,1:3) = (/ 0.0_ReKi, cos(psi_hub), sin(psi_hub) /) + R_ph(3,1:3) = (/ 0.0_ReKi,-sin(psi_hub), cos(psi_hub) /) + R_pi(1:3,1:3,iB) = matmul(R_ph, u%HubMotion%Orientation(1:3,1:3,1) ) + enddo ! Populate the header an unit lines for all blades and nodes ! First set a counter so we know where in the output array we are in - OutIdx = p%NumOuts + 1 ! p%NumOuts is the number of outputs from the normal AeroDyn output. The WriteOutput array is sized to p%NumOuts + num(AllBldNdOuts) + iOut = p%NumOuts + 1 ! p%NumOuts is the number of outputs from the normal AeroDyn output. The WriteOutput array is sized to p%NumOuts + num(AllBldNdOuts) ! Case to assign output to this channel and populate based on Indx value (this indicates what the channel is) @@ -239,138 +330,150 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx DO IdxChan=1,p%BldNd_NumOuts SELECT CASE( p%BldNd_OutParam(IdxChan)%Indx ) ! Indx contains the information on what channel should be output - CASE (0) ! Invalid channel - ! We still have headers for invalid channels. Need to account for that - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 - END DO - END DO - - ! ***** Undisturbed wind velocity in local blade coord system ***** - CASE ( BldNd_VUndx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(1,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO - - - CASE ( BldNd_VUndy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(2,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_VUndz ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(3,:,IdxNode,IdxBlade), u%InflowOnBlade(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO - - - ! ***** Undisturbed wind velocity in inertial/global coord system ***** - CASE ( BldNd_VUndxi ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = u%InflowOnBlade(1,IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO - - - CASE ( BldNd_VUndyi ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = u%InflowOnBlade(2,IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_VUndzi ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = u%InflowOnBlade(3,IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO - - + ! Invalid channel, we still have headers for invalid channels. Need to account for that + CASE (0 ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = 0.0_ReKi; iOut = iOut + 1; enddo;enddo - ! ***** Disturbed wind velocity in the local blade coordinate system ***** - CASE ( BldNd_VDisx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(1,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO + ! ***** Undisturbed wind velocity in inertial, polar, local and airfoil systems***** + CASE( BldNd_VUndxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%InflowOnBlade(1,iNd,iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%InflowOnBlade(2,iNd,iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%InflowOnBlade(3,iNd,iB); iOut = iOut + 1; enddo;enddo - CASE ( BldNd_VDisy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(2,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO + CASE( BldNd_VUndxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo - CASE ( BldNd_VDisz ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(3,:,IdxNode,IdxBlade), m%DisturbedInflow(:,IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 - END DO - END DO + CASE( BldNd_VUndxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo - - ! ***** Structural translational velocity in the local blade coordinate system ***** - CASE ( BldNd_STVx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(1,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_STVy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(2,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - OutIdx = OutIdx + 1 + CASE( BldNd_VUndxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + + ! TODO: deprecate this + CASE( BldNd_VUndx ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_wi(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndy ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_wi(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndz ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%InflowOnBlade(:,iNd,iB), R_wi(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + + ! ***** Disturbed wind velocity in inertial, polar, local and airfoil systems***** + CASE( BldNd_VDisxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%DisturbedInflow(1,iNd,iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%DisturbedInflow(2,iNd,iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDiszi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%DisturbedInflow(3,iNd,iB); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_VDisxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDiszp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_VDisxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDiszl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_VDisxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + + ! TODO: deprecate this + CASE( BldNd_VDisx ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_wi(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisy ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_wi(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VDisz ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%DisturbedInflow(:,iNd,iB), R_wi(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + + ! ***** Structural translational velocity inertial, polar, local and airfoil systems***** + CASE( BldNd_STVxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%BladeMotion(iB)%TranslationVel(1,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%BladeMotion(iB)%TranslationVel(2,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%BladeMotion(iB)%TranslationVel(3,iNd); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_STVxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_STVxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_STVxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + + ! TODO: deprecate this + CASE( BldNd_STVx ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_wi(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVy ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_wi(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_STVz ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( u%BladeMotion(iB)%TranslationVel(:,iNd), R_wi(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + ! ***** Induced velocities in inertial, polar, local and airfoil systems***** + ! Axial and tangential induced wind velocity + ! TODO use m%Vind_i and R_wi + CASE ( BldNd_Vindx ) + if (p_AD%WakeMod /= WakeMod_FVW) then + do iB=1,nB + do iNd=1,nNd + y%WriteOutput(iOut) = - m%BEMT_u(Indx)%Vx(iNd,iB) * m%BEMT_y%axInduction( iNd,iB) + iOut = iOut + 1 + enddo + enddo + else + do iB=1,nB + iW = W2B(iB) + do iNd=1,nNd; + y%WriteOutput(iOut) = -m_AD%FVW%W(iW)%BN_UrelWind_s(1,iNd) * m_AD%FVW%W(iW)%BN_AxInd(iNd) + iOut = iOut + 1 + enddo + enddo + endif + + CASE ( BldNd_Vindy ) + if (p_AD%WakeMod /= WakeMod_FVW) then + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_u(Indx)%Vy(iNd,iB) * m%BEMT_y%tanInduction(iNd,iB) + iOut = iOut + 1 + END DO END DO - END DO - - CASE ( BldNd_STVz ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( m%orientationAnnulus(3,:,IdxNode,IdxBlade), u%BladeMotion(IdxBlade)%TranslationVel(:,IdxNode) ) - OutIdx = OutIdx + 1 + else + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_UrelWind_s(2,iNd) * m_AD%FVW%W(iW)%BN_TanInd(iNd) + iOut = iOut + 1 + END DO END DO - END DO + endif + + CASE( BldNd_Vindxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%Vind_i(1, iNd, iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%Vind_i(2, iNd, iB); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%Vind_i(3, iNd, iB); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Vindxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Vindxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Vindxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Vindza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%Vind_i(:, iNd, iB), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + ! TODO: Vrel, DynP, Re, Ma - should be unified across lifting-line implementations. Vrel should be computed based on velocities in (a)-system ! Relative wind speed CASE ( BldNd_VRel ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Vrel(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Vrel(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Vrel(iNd) + iOut = iOut + 1 END DO END DO endif @@ -378,18 +481,18 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! Dynamic pressure CASE ( BldNd_DynP ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.5 * p%airDens * m%BEMT_y%Vrel(IdxNode,IdxBlade)**2 - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = 0.5 * p%airDens * m%BEMT_y%Vrel(iNd,iB)**2 + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.5 * p%airDens * m_AD%FVW%W(iW)%BN_Vrel(IdxNode)**2 - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = 0.5 * p%airDens * m_AD%FVW%W(iW)%BN_Vrel(iNd)**2 + iOut = iOut + 1 END DO END DO endif @@ -397,18 +500,18 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! Reynolds number (in millions) CASE ( BldNd_Re ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = p%BEMT%chord(IdxNode,IdxBlade) * m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%KinVisc / 1.0E6 - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = p%BEMT%chord(iNd,iB) * m%BEMT_y%Vrel(iNd,iB) / p%KinVisc / 1.0E6 + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Re(IdxNode) / 1.0E6 - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Re(iNd) / 1.0E6 + iOut = iOut + 1 END DO END DO endif @@ -416,263 +519,282 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! Mach number CASE ( BldNd_M ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Vrel(IdxNode,IdxBlade) / p%SpdSound - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Vrel(iNd,iB) / p%SpdSound + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Vrel(IdxNode) / p%SpdSound - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Vrel(iNd) / p%SpdSound + iOut = iOut + 1 END DO END DO endif - - - ! Axial and tangential induced wind velocity - CASE ( BldNd_Vindx ) + + ! Axial and tangential induction factors + CASE ( BldNd_AxInd ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = - m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) * m%BEMT_y%axInduction( IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%axInduction(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = -m_AD%FVW%W(iW)%BN_UrelWind_s(1,IdxNode) * m_AD%FVW%W(iW)%BN_AxInd(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_AxInd(iNd) + iOut = iOut + 1 END DO END DO endif - - CASE ( BldNd_Vindy ) + + CASE ( BldNd_TnInd ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) * m%BEMT_y%tanInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%tanInduction(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_UrelWind_s(2,IdxNode) * m_AD%FVW%W(iW)%BN_TanInd(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_TanInd(iNd) + iOut = iOut + 1 END DO END DO endif - - ! Axial and tangential induction factors - CASE ( BldNd_AxInd ) + ! Quasi-steady Axial and tangential induction factors + CASE ( BldNd_AxInd_qs ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%axInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%axInduction_qs(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_AxInd(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_AxInd(iNd) ! TODO + iOut = iOut + 1 END DO END DO endif - CASE ( BldNd_TnInd ) + CASE ( BldNd_TnInd_qs ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%tanInduction(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%tanInduction_qs(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_TanInd(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_TanInd(iNd) ! TODO + iOut = iOut + 1 END DO END DO endif - + ! AoA, pitch+twist angle, inflow angle, and curvature angle CASE ( BldNd_Alpha ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = Rad2M180to180Deg( m%BEMT_y%phi(IdxNode,IdxBlade) - m%BEMT_u(Indx)%theta(IdxNode,IdxBlade) ) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + ! TODO Change this + y%WriteOutput(iOut) = Rad2M180to180Deg( m%BEMT_y%phi(iNd,iB) - m%BEMT_u(Indx)%theta(iNd,iB) ) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_alpha(IdxNode)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_alpha(iNd)*R2D + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Theta ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_u(Indx)%theta(iNd,iB)*R2D + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%PitchAndTwist(iNd)*R2D + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Phi ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%phi(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%phi(iNd,iB)*R2D + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) =m_AD%FVW%W(iW)%BN_phi(IdxNode)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) =m_AD%FVW%W(iW)%BN_phi(iNd)*R2D + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Curve ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%Curve(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%Curve(iNd,iB)*R2D + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd !NOT available in FVW yet - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 + END DO + END DO + endif + + CASE ( BldNd_Toe ) + if (p_AD%WakeMod /= WakeMod_FVW) then + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_u(Indx)%toeAngle(iNd,iB)*R2D + iOut = iOut + 1 + END DO + END DO + else + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 END DO END DO endif - ! Lift force, drag force, pitching moment coefficients + ! Unsteady lift force, drag force, pitching moment coefficients + ! TODO this should be somehow unified across lifting-line implementations CASE ( BldNd_Cl ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cl(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Cl(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cl(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cl(iNd) + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Cd ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cd(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Cd(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cd(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cd(iNd) + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Cm ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cm(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Cm(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cm(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cm(iNd) + iOut = iOut + 1 END DO END DO endif ! Normal force (to plane), tangential force (to plane) coefficients + ! TODO deprecate CASE ( BldNd_Cx ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Cx(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cx(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cx(iNd) + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Cy ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%Cy(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%Cy(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cy(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cy(iNd) + iOut = iOut + 1 END DO END DO endif @@ -680,44 +802,44 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! Normal force (to chord), and tangential force (to chord) coefficients CASE ( BldNd_Cn ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%BEMT_y%Cx(IdxNode,IdxBlade)*ct + m%BEMT_y%Cy(IdxNode,IdxBlade)*st - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + ct=cos(m%BEMT_u(Indx)%theta(iNd,iB)) + st=sin(m%BEMT_u(Indx)%theta(iNd,iB)) + y%WriteOutput(iOut) = m%BEMT_y%Cx(iNd,iB)*ct + m%BEMT_y%Cy(iNd,iB)*st + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! cos(theta) - st=sin(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! sin(theta) - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cx(IdxNode)*ct + m_AD%FVW%W(iW)%BN_Cy(IdxNode)*st - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! cos(theta) + st=sin(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! sin(theta) + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cx(iNd)*ct + m_AD%FVW%W(iW)%BN_Cy(iNd)*st + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Ct ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = -m%BEMT_y%Cx(IdxNode,IdxBlade)*st + m%BEMT_y%Cy(IdxNode,IdxBlade)*ct - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + ct=cos(m%BEMT_u(Indx)%theta(iNd,iB)) + st=sin(m%BEMT_u(Indx)%theta(iNd,iB)) + y%WriteOutput(iOut) = -m%BEMT_y%Cx(iNd,iB)*st + m%BEMT_y%Cy(iNd,iB)*ct + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! cos(theta) - st=sin(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! sin(theta) - y%WriteOutput( OutIdx ) = -m_AD%FVW%W(iW)%BN_Cx(IdxNode)*st + m_AD%FVW%W(iW)%BN_Cy(IdxNode)*ct - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! cos(theta) + st=sin(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! sin(theta) + y%WriteOutput(iOut) = -m_AD%FVW%W(iW)%BN_Cx(iNd)*st + m_AD%FVW%W(iW)%BN_Cy(iNd)*ct + iOut = iOut + 1 END DO END DO endif @@ -726,169 +848,181 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx ! Lift force, drag force, pitching moment CASE ( BldNd_Fl ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) - sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*cp - m%Y(IdxNode,IdxBlade)*sp - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + cp=cos(m%BEMT_y%phi(iNd,iB)) + sp=sin(m%BEMT_y%phi(iNd,iB)) + y%WriteOutput(iOut) = m%X(iNd,iB)*cp - m%Y(iNd,iB)*sp + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - cp=cos(m_AD%FVW%W(iW)%BN_phi(IdxNode)) - sp=sin(m_AD%FVW%W(iW)%BN_phi(IdxNode)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*cp - m%Y(IdxNode,IdxBlade)*sp - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + cp=cos(m_AD%FVW%W(iW)%BN_phi(iNd)) + sp=sin(m_AD%FVW%W(iW)%BN_phi(iNd)) + y%WriteOutput(iOut) = m%X(iNd,iB)*cp - m%Y(iNd,iB)*sp + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Fd ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - cp=cos(m%BEMT_y%phi(IdxNode,IdxBlade)) - sp=sin(m%BEMT_y%phi(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*sp + m%Y(IdxNode,IdxBlade)*cp - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + cp=cos(m%BEMT_y%phi(iNd,iB)) + sp=sin(m%BEMT_y%phi(iNd,iB)) + y%WriteOutput(iOut) = m%X(iNd,iB)*sp + m%Y(iNd,iB)*cp + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - cp=cos(m_AD%FVW%W(iW)%BN_phi(IdxNode)) - sp=sin(m_AD%FVW%W(iW)%BN_phi(IdxNode)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*sp + m%Y(IdxNode,IdxBlade)*cp - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + cp=cos(m_AD%FVW%W(iW)%BN_phi(iNd)) + sp=sin(m_AD%FVW%W(iW)%BN_phi(iNd)) + y%WriteOutput(iOut) = m%X(iNd,iB)*sp + m%Y(iNd,iB)*cp + iOut = iOut + 1 END DO END DO endif - CASE ( BldNd_Mm ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%M(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO - - ! Normal force (to plane), tangential force (to plane) - CASE ( BldNd_Fx ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO + CASE ( BldNd_Mm ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%M(iNd,iB); iOut = iOut + 1; enddo;enddo - CASE ( BldNd_Fy ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = -m%Y(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - END DO - END DO + ! Normal force (to plane), tangential force (to plane) + ! TODO deprecate + CASE ( BldNd_Fx ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%X(iNd,iB); iOut = iOut + 1; enddo;enddo + CASE ( BldNd_Fy ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = -m%Y(iNd,iB); iOut = iOut + 1; enddo;enddo ! Normal force (to chord), and tangential force (to chord) per unit length + !CASE( BldNd_Fn ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), u%BladeMotion(iB)%Orientation(1,:,iNd)); iOut = iOut + 1; enddo;enddo CASE ( BldNd_Fn ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*ct - m%Y(IdxNode,IdxBlade)*st - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + ct=cos(m%BEMT_u(Indx)%theta(iNd,iB)) + st=sin(m%BEMT_u(Indx)%theta(iNd,iB)) + y%WriteOutput(iOut) = m%X(iNd,iB)*ct - m%Y(iNd,iB)*st + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! cos(theta) - st=sin(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! sin(theta) - y%WriteOutput( OutIdx ) = m%X(IdxNode,IdxBlade)*ct - m%Y(IdxNode,IdxBlade)*st - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! cos(theta) + st=sin(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! sin(theta) + y%WriteOutput(iOut) = m%X(iNd,iB)*ct - m%Y(iNd,iB)*st + iOut = iOut + 1 END DO END DO endif + !CASE( BldNd_Ft ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = -dot_product( y%BladeLoad(iB)%Force (:, iNd), u%BladeMotion(iB)%Orientation(2,:,iNd)); iOut = iOut + 1; enddo;enddo CASE ( BldNd_Ft ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - ct=cos(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - st=sin(m%BEMT_u(Indx)%theta(IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = -m%X(IdxNode,IdxBlade)*st - m%Y(IdxNode,IdxBlade)*ct - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + ct=cos(m%BEMT_u(Indx)%theta(iNd,iB)) + st=sin(m%BEMT_u(Indx)%theta(iNd,iB)) + y%WriteOutput(iOut) = -m%X(iNd,iB)*st - m%Y(iNd,iB)*ct + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! cos(theta) - st=sin(m_AD%FVW%W(iW)%PitchAndTwist(IdxNode)) ! sin(theta) - y%WriteOutput( OutIdx ) = -m%X(IdxNode,IdxBlade)*st - m%Y(IdxNode,IdxBlade)*ct - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + ct=cos(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! cos(theta) + st=sin(m_AD%FVW%W(iW)%PitchAndTwist(iNd)) ! sin(theta) + y%WriteOutput(iOut) = -m%X(iNd,iB)*st - m%Y(iNd,iB)*ct + iOut = iOut + 1 END DO END DO endif - ! Tower clearance (requires tower influence calculation): + ! ******* Force/Moment in: global, polar, local-polar and airfoil system + CASE( BldNd_Fxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Force (1, iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Force (2, iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Force (3, iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Moment(1, iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Myi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Moment(2, iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = y%BladeLoad(iB)%Moment(3, iNd); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Fxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_pi(1,:,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_pi(2,:,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_pi(3,:,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_pi(1,:,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Myp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_pi(2,:,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_pi(3,:,iB)); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Fxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_li(1,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_li(2,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), R_li(3,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_li(1,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Myl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_li(2,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), R_li(3,:,iNd,iB)); iOut = iOut + 1; enddo;enddo + + ! NOTE: BldNd_Fn=BldNd_Fxa, BldNd_Ft=-BldNd_Fya (minus sign!), BldNd_Mm=BldNd_Mza BldNdMxa=0 + !CASE( BldNd_Fxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), u%BladeMotion(iB)%Orientation(1,:,iNd)); iOut = iOut + 1; enddo;enddo + !CASE( BldNd_Fya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Force (:, iNd), u%BladeMotion(iB)%Orientation(2,:,iNd)); iOut = iOut + 1; enddo;enddo + !CASE( BldNd_Mza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( y%BladeLoad(iB)%Moment(:, iNd), u%BladeMotion(iB)%Orientation(3,:,iNd)); iOut = iOut + 1; enddo;enddo + + ! Tower clearance (requires tower influence calculation): CASE ( BldNd_Clrnc ) if (.not. allocated(m%TwrClrnc)) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%TwrClrnc(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%TwrClrnc(iNd,iB) + iOut = iOut + 1 END DO END DO end if + ! TODO: remove me, Vx, Vy can be computed from other outputs (and they are in legacy coordinate system) CASE ( BldNd_Vx ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_u(Indx)%Vx(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_UrelWind_s(1,IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_UrelWind_s(1,iNd) + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_Vy ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_u(Indx)%Vy(iNd,iB) + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_UrelWind_s(2,IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_UrelWind_s(2,iNd) + iOut = iOut + 1 END DO END DO endif @@ -896,48 +1030,48 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx CASE ( BldNd_GeomPhi ) if (p_AD%WakeMod /= WakeMod_FVW) then if (allocated(OtherState%BEMT%ValidPhi)) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - if (OtherState%BEMT%ValidPhi(IdxNode,IdxBlade)) then - y%WriteOutput( OutIdx ) = 1.0_ReKi - m%BEMT%BEM_weight + DO iB=1,nB + DO iNd=1,nNd + if (OtherState%BEMT%ValidPhi(iNd,iB)) then + y%WriteOutput(iOut) = 1.0_ReKi - m%BEMT%BEM_weight else - y%WriteOutput( OutIdx ) = 1.0_ReKi + y%WriteOutput(iOut) = 1.0_ReKi end if - OutIdx = OutIdx + 1 + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 1.0_ReKi - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,nNd + y%WriteOutput(iOut) = 1.0_ReKi + iOut = iOut + 1 END DO END DO end if else - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = 0.0_ReKi ! Not valid for FVW - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = 0.0_ReKi ! Not valid for FVW + iOut = iOut + 1 END DO END DO endif CASE ( BldNd_chi ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = m%BEMT_y%chi(IdxNode,IdxBlade)*R2D - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,nNd + y%WriteOutput(iOut) = m%BEMT_y%chi(iNd,iB)*R2D + iOut = iOut + 1 END DO END DO else - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds + DO iB=1,nB + DO iNd=1,nNd !NOT available in FVW yet - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 END DO END DO endif @@ -945,26 +1079,26 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx CASE ( BldNd_UA_Flag ) IF (p_AD%UA_Flag) THEN if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m%BEMT%UA%weight(IdxNode, IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m%BEMT%UA%weight(iNd, iB) + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%m_UA%weight(IdxNode, 1) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%m_UA%weight(iNd, 1) + iOut = iOut + 1 ENDDO ENDDO end if ELSE - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 ENDDO ENDDO END IF @@ -986,291 +1120,187 @@ SUBROUTINE Calc_WriteAllBldNdOutput( p, p_AD, u, m, m_AD, x, y, OtherState, Indx END SELECT !if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = x%BEMT%UA%element(IdxNode, IdxBlade)%x(compIndx) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = x%BEMT%UA%element(iNd, iB)%x(compIndx) + iOut = iOut + 1 ENDDO ENDDO !else - ! DO IdxBlade=1,p%BldNd_BladesOut - ! iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - ! DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - ! y%WriteOutput( OutIdx ) = x_AD%FVW%UA(iW)%element(IdxNode, IdxBlade)%x(compIndx) - ! OutIdx = OutIdx + 1 + ! DO iB=1,nB + ! iW = W2B(iB) + ! DO iNd=1,u%BladeMotion(iB)%NNodes + ! y%WriteOutput(iOut) = x_AD%FVW%UA(iW)%element(iNd, iB)%x(compIndx) + ! iOut = iOut + 1 ! ENDDO ! ENDDO !end if ELSE - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 ENDDO ENDDO END IF - - CASE ( BldNd_Debug1 ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.0_ReKi ! something here - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Debug2 ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.0_ReKi ! something here - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Debug3 ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.0_ReKi ! something here - OutIdx = OutIdx + 1 - END DO - END DO - ! CpMin CASE ( BldNd_CpMin ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m%BEMT_y%Cpmin(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m%BEMT_y%Cpmin(iNd,iB) + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cpmin(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cpmin(iNd) + iOut = iOut + 1 ENDDO ENDDO endif ! Cavitation - CASE ( BldNd_SgCav ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m%SigmaCavit(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - ENDDO - ENDDO - - CASE ( BldNd_SigCr ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m%SigmaCavitCrit(IdxNode,IdxBlade) - OutIdx = OutIdx + 1 - ENDDO - ENDDO + CASE ( BldNd_SgCav ); do iB=1,nB; do iNd=1,u%BladeMotion(iB)%NNodes; y%WriteOutput(iOut) = m%SigmaCavit(iNd,iB); iOut = iOut + 1; enddo;enddo + CASE ( BldNd_SigCr ); do iB=1,nB; do iNd=1,u%BladeMotion(iB)%NNodes; y%WriteOutput(iOut) = m%SigmaCavitCrit(iNd,iB); iOut = iOut + 1; enddo;enddo ! circulation on blade CASE ( BldNd_Gam ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.5_ReKi * p%BEMT%chord(IdxNode,IdxBlade) * m%BEMT_y%Vrel(IdxNode,IdxBlade) * m%BEMT_y%Cl(IdxNode,IdxBlade) ! "Gam" [m^2/s] - OutIdx = OutIdx + 1 + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = 0.5_ReKi * p%BEMT%chord(iNd,iB) * m%BEMT_y%Vrel(iNd,iB) * m%BEMT_y%Cl(iNd,iB) ! "Gam" [m^2/s] + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = 0.5_ReKi * p_AD%FVW%W(iW)%chord_LL(IdxNode) * m_AD%FVW%W(iW)%BN_Vrel(IdxNode) * m_AD%FVW%W(iW)%BN_Cl(IdxNode) ! "Gam" [m^2/s] - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = 0.5_ReKi * p_AD%FVW%W(iW)%chord_LL(iNd) * m_AD%FVW%W(iW)%BN_Vrel(iNd) * m_AD%FVW%W(iW)%BN_Cl(iNd) ! "Gam" [m^2/s] + iOut = iOut + 1 ENDDO ENDDO endif - !================================================ - ! Static portion of Cl, Cd, Cm (ignoring unsteady effects) - ! Cl_Static - CASE ( BldNd_Cl_Static ) + !================================================ OLAF ONLY + ! Static portion of Cl, Cd, Cm (ignoring unsteady effects) + ! TODO this should be provided by all lifting-line codes + ! Cl_Static + CASE ( BldNd_Cl_qs ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes !NOT available in BEMT/DBEMT yet - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cl_Static(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cl_Static(iNd) + iOut = iOut + 1 ENDDO ENDDO endif ! Cd_Static - CASE ( BldNd_Cd_Static ) + CASE ( BldNd_Cd_qs ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes !NOT available in BEMT/DBEMT yet - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cd_Static(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cd_Static(iNd) + iOut = iOut + 1 ENDDO ENDDO endif ! Cm_Static - CASE ( BldNd_Cm_Static ) + CASE ( BldNd_Cm_qs ) if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes + DO iB=1,nB + DO iNd=1,u%BladeMotion(iB)%NNodes !NOT available in BEMT/DBEMT yet - y%WriteOutput( OutIdx ) = 0.0_ReKi - OutIdx = OutIdx + 1 + y%WriteOutput(iOut) = 0.0_ReKi + iOut = iOut + 1 ENDDO ENDDO else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = m_AD%FVW%W(iW)%BN_Cm_Static(IdxNode) - OutIdx = OutIdx + 1 + DO iB=1,nB + iW = W2B(iB) + DO iNd=1,u%BladeMotion(iB)%NNodes + y%WriteOutput(iOut) = m_AD%FVW%W(iW)%BN_Cm_Static(iNd) + iOut = iOut + 1 ENDDO ENDDO endif - - - !================================================ - ! Inductions in polar rotating hub coordinates - ! Axial induction, polar rotating hub coordinates - CASE ( BldNd_Uin ) - if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) - Vind_g = matmul(Vind_s, m%orientationAnnulus(:,:,IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = dot_product(M_pg(1,1:3,IdxBlade), Vind_g(1:3) ) ! Uihn, hub normal - OutIdx = OutIdx + 1 - ENDDO - ENDDO - else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = dot_product(M_pg(1,1:3,IdxBlade), m_AD%FVW_y%W(iW)%Vind(1:3,IdxNode) ) ! Uihn, hub normal - OutIdx = OutIdx + 1 - ENDDO - ENDDO - endif - - ! Tangential induction, polar rotating hub coordinates - CASE ( BldNd_Uit ) - if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) - Vind_g = matmul(Vind_s, m%orientationAnnulus(:,:,IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = dot_product(M_pg(2,1:3,IdxBlade), Vind_g(1:3) ) ! Uiht, hub tangential - OutIdx = OutIdx + 1 - ENDDO - ENDDO - else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = dot_product(M_pg(2,1:3,IdxBlade), m_AD%FVW_y%W(iW)%Vind(1:3,IdxNode) ) ! Uiht, hub tangential - OutIdx = OutIdx + 1 - ENDDO - ENDDO - endif - - ! Radial induction, polar rotating hub coordinates - CASE ( BldNd_Uir ) - if (p_AD%WakeMod /= WakeMod_FVW) then - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - Vind_s = (/ -m%BEMT_u(Indx)%Vx(IdxNode,IdxBlade)*m%BEMT_y%axInduction(IdxNode,IdxBlade), m%BEMT_u(Indx)%Vy(IdxNode,IdxBlade)*m%BEMT_y%tanInduction(IdxNode,IdxBlade), 0.0_ReKi /) - Vind_g = matmul(Vind_s, m%orientationAnnulus(:,:,IdxNode,IdxBlade)) - y%WriteOutput( OutIdx ) = dot_product(M_pg(3,1:3,IdxBlade), Vind_g(1:3) ) ! Uihr, hub radial - OutIdx = OutIdx + 1 - ENDDO - ENDDO - else - DO IdxBlade=1,p%BldNd_BladesOut - iW = p_AD%FVW%Bld2Wings(iRot, IdxBlade) - DO IdxNode=1,u%BladeMotion(IdxBlade)%NNodes - y%WriteOutput( OutIdx ) = dot_product(M_pg(3,1:3,IdxBlade), m_AD%FVW_y%W(iW)%Vind(1:3,IdxNode) ) ! Uihr, hub radial - OutIdx = OutIdx + 1 - ENDDO - ENDDO - endif - - ! Normal buoyant force (to chord), tangential buoyant force (to chord), spanwise buoyant force - CASE ( BldNd_Fbn ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(1,:,IdxNode), m%BlFB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Fbt ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(2,:,IdxNode), m%BlFB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Fbs ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(3,:,IdxNode), m%BlFB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO - - ! Normal buoyant moment (to chord), tangential buoyant moment (to chord), spanwise buoyant moment - CASE ( BldNd_Mbn ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(1,:,IdxNode), m%BlMB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Mbt ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(2,:,IdxNode), m%BlMB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO - - CASE ( BldNd_Mbs ) - DO IdxBlade=1,p%BldNd_BladesOut - DO IdxNode=1,p%NumBlNds - y%WriteOutput( OutIdx ) = dot_product( u%BladeMotion(IdxBlade)%Orientation(3,:,IdxNode), m%BlMB(IdxNode,IdxBlade,:) ) - OutIdx = OutIdx + 1 - END DO - END DO + !================================================ BEM ONLY + + ! BEM variables: F: Hub/Tip-loss factor, k/kp: load factors, CT: thrust coefficient in CT-a relationship + CASE(BldNd_BEM_F_qs ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BEMT_y%F(iNd,iB); iOut = iOut + 1; enddo;enddo + CASE(BldNd_BEM_k_qs ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BEMT_y%k(iNd,iB); iOut = iOut + 1; enddo;enddo + CASE(BldNd_BEM_kp_qs ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BEMT_y%k_p(iNd,iB); iOut = iOut + 1; enddo;enddo + CASE(BldNd_BEM_CT_qs ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = 4*m%BEMT_y%F(iNd,iB)*m%BEMT_y%k(iNd,iB)*(1._ReKi-m%BEMT_y%axInduction_qs(iNd,iB))**2; iOut = iOut + 1; enddo;enddo + + !================================================ MHK only + + ! Buoyant force in inertial, polar, local and airfoil systems + CASE( BldNd_Fbxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Force (1,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Force (2,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Force (3,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbxi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Moment(1,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Moment(2,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = m%BladeBuoyLoad(iB)%Moment(3,iNd); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Fbxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbxp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_pi(1,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbyp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_pi(2,:,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbzp ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_pi(3,:,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Fbxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbxl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_li(1,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbyl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_li(2,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbzl ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), R_li(3,:,iNd,iB) ); iOut = iOut + 1; enddo;enddo + + CASE( BldNd_Fbxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Fbza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Force (:,iNd), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbxa ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), u%BladeMotion(iB)%Orientation(1,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbya ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), u%BladeMotion(iB)%Orientation(2,:,iNd) ); iOut = iOut + 1; enddo;enddo + CASE( BldNd_Mbza ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = dot_product( m%BladeBuoyLoad(iB)%Moment(:,iNd), u%BladeMotion(iB)%Orientation(3,:,iNd) ); iOut = iOut + 1; enddo;enddo + + !================================================ DEBUG ONLY + + ! Convenient placeholders for debuging + CASE ( BldNd_Debug1 ); do iB=1,nB; do iNd=1,u%BladeMotion(iB)%NNodes; y%WriteOutput(iOut) = 0.0_ReKi; iOut = iOut + 1; enddo;enddo + CASE ( BldNd_Debug2 ); do iB=1,nB; do iNd=1,u%BladeMotion(iB)%NNodes; y%WriteOutput(iOut) = 0.0_ReKi; iOut = iOut + 1; enddo;enddo + CASE ( BldNd_Debug3 ); do iB=1,nB; do iNd=1,u%BladeMotion(iB)%NNodes; y%WriteOutput(iOut) = 0.0_ReKi; iOut = iOut + 1; enddo;enddo + + CASE DEFAULT + ! Should never happen, this is a programmer's error + CALL SetErrStat( ErrID_Fatal, "The channel was not implemented, index: "//trim(num2lstr(p%BldNd_OutParam(IdxChan)%Indx)), ErrStat, ErrMsg, RoutineName ) END SELECT @@ -1373,7 +1403,7 @@ END SUBROUTINE AllBldNdOuts_SetParameters !! the sign is set to 0 if the channel is invalid. !! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here. !! -!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 07-Sep-2022 16:16:13. +!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx. SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, p_AD, ErrStat, ErrMsg ) !.................................................................................................................................. @@ -1396,37 +1426,73 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, p_AD, ErrStat, ErrMsg ) LOGICAL :: InvalidOutput(1:BldNd_MaxOutPts) ! This array determines if the output channel is valid for this configuration CHARACTER(*), PARAMETER :: RoutineName = "BldNdOuts_SetOutParam" - - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(68) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically - "ALPHA ","AXIND ","CD ","CD_STATIC","CHI ","CL ","CLRNC ","CL_STATIC", & - "CM ","CM_STATIC","CN ","CPMIN ","CT ","CURVE ","CX ","CY ", & - "DEBUG1 ","DEBUG2 ","DEBUG3 ","DYNP ","FBN ","FBS ","FBT ","FD ", & - "FL ","FN ","FT ","FX ","FY ","GAM ","GEOMPHI ","M ", & - "MBN ","MBS ","MBT ","MM ","PHI ","RE ","SGCAV ","SIGCR ", & - "STVX ","STVY ","STVZ ","THETA ","TNIND ","UA_FLAG ","UA_X1 ","UA_X2 ", & - "UA_X3 ","UA_X4 ","UA_X5 ","UIN ","UIR ","UIT ","VDISX ","VDISY ", & - "VDISZ ","VINDX ","VINDY ","VREL ","VUNDX ","VUNDXI ","VUNDY ","VUNDYI ", & - "VUNDZ ","VUNDZI ","VX ","VY "/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(68) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) - BldNd_Alpha , BldNd_AxInd , BldNd_Cd , BldNd_Cd_Static , BldNd_Chi , BldNd_Cl , BldNd_Clrnc , BldNd_Cl_Static , & - BldNd_Cm , BldNd_Cm_Static , BldNd_Cn , BldNd_CpMin , BldNd_Ct , BldNd_Curve , BldNd_Cx , BldNd_Cy , & - BldNd_Debug1 , BldNd_Debug2 , BldNd_Debug3 , BldNd_DynP , BldNd_Fbn , BldNd_Fbs , BldNd_Fbt , BldNd_Fd , & - BldNd_Fl , BldNd_Fn , BldNd_Ft , BldNd_Fx , BldNd_Fy , BldNd_Gam , BldNd_GeomPhi , BldNd_M , & - BldNd_Mbn , BldNd_Mbs , BldNd_Mbt , BldNd_Mm , BldNd_Phi , BldNd_Re , BldNd_SgCav , BldNd_SigCr , & - BldNd_STVx , BldNd_STVy , BldNd_STVz , BldNd_Theta , BldNd_TnInd , BldNd_UA_Flag , BldNd_UA_x1 , BldNd_UA_x2 , & - BldNd_UA_x3 , BldNd_UA_x4 , BldNd_UA_x5 , BldNd_Uin , BldNd_Uir , BldNd_Uit , BldNd_VDisx , BldNd_VDisy , & - BldNd_VDisz , BldNd_Vindx , BldNd_Vindy , BldNd_VRel , BldNd_VUndx , BldNd_Vundxi , BldNd_VUndy , BldNd_Vundyi , & - BldNd_VUndz , BldNd_Vundzi , BldNd_Vx , BldNd_Vy /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(68) = (/ & ! This lists the units corresponding to the allowed parameters - "(deg) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(m) ","(-) ", & - "(-) ","(-) ","(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ", & - "(-) ","(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(m^2/s)","(1/0) ","(-) ", & - "(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(deg) ","(-) ","(-) ","(-) ", & - "(m/s) ","(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(rad) ","(rad) ", & + + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(166) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "ALPHA ","AXIND ","AXIND_QS ","BEM_CT_QS","BEM_F_QS ","BEM_KP_QS","BEM_K_QS ","CD ", & + "CD_QS ","CHI ","CL ","CLRNC ","CL_QS ","CM ","CMA ","CM_QS ", & + "CN ","CPMIN ","CT ","CURVE ","CX ","CXA ","CY ","DEBUG1 ", & + "DEBUG2 ","DEBUG3 ","DYNP ","FBN ","FBS ","FBT ","FBXA ","FBXI ", & + "FBXL ","FBXP ","FBYA ","FBYI ","FBYL ","FBYP ","FBZA ","FBZI ", & + "FBZL ","FBZP ","FD ","FL ","FN ","FT ","FX ","FXA ", & + "FXI ","FXL ","FXP ","FY ","FYI ","FYL ","FYP ","FZI ", & + "FZL ","FZP ","GAM ","GEOMPHI ","M ","MBN ","MBS ","MBT ", & + "MBXA ","MBXI ","MBXL ","MBXP ","MBYA ","MBYI ","MBYL ","MBYP ", & + "MBZA ","MBZI ","MBZL ","MBZP ","MM ","MXI ","MXL ","MXP ", & + "MYI ","MYL ","MYP ","MZA ","MZI ","MZL ","MZP ","PHI ", & + "RE ","SGCAV ","SIGCR ","STVX ","STVXA ","STVXI ","STVXL ","STVXP ", & + "STVY ","STVYA ","STVYI ","STVYL ","STVYP ","STVZ ","STVZA ","STVZI ", & + "STVZL ","STVZP ","THETA ","TNIND ","TNIND_QS ","TOE ","UA_FLAG ","UA_X1 ", & + "UA_X2 ","UA_X3 ","UA_X4 ","UA_X5 ","UIN ","UIR ","UIT ","VDISX ", & + "VDISXA ","VDISXI ","VDISXL ","VDISXP ","VDISY ","VDISYA ","VDISYI ","VDISYL ", & + "VDISYP ","VDISZ ","VDISZA ","VDISZI ","VDISZL ","VDISZP ","VINDX ","VINDXA ", & + "VINDXI ","VINDXL ","VINDXP ","VINDY ","VINDYA ","VINDYI ","VINDYL ","VINDYP ", & + "VINDZA ","VINDZI ","VINDZL ","VINDZP ","VREL ","VUNDX ","VUNDXA ","VUNDXI ", & + "VUNDXL ","VUNDXP ","VUNDY ","VUNDYA ","VUNDYI ","VUNDYL ","VUNDYP ","VUNDZ ", & + "VUNDZA ","VUNDZI ","VUNDZL ","VUNDZP ","VX ","VY "/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(166) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + BldNd_Alpha , BldNd_AxInd , BldNd_AxInd_qs , BldNd_BEM_CT_qs , BldNd_BEM_F_qs , BldNd_BEM_kp_qs , BldNd_BEM_k_qs , BldNd_Cd , & + BldNd_Cd_qs , BldNd_Chi , BldNd_Cl , BldNd_Clrnc , BldNd_Cl_qs , BldNd_Cm , BldNd_Cm , BldNd_Cm_qs , & + BldNd_Cn , BldNd_CpMin , BldNd_Ct , BldNd_Curve , BldNd_Cx , BldNd_Cn , BldNd_Cy , BldNd_Debug1 , & + BldNd_Debug2 , BldNd_Debug3 , BldNd_DynP , BldNd_Fbxa , BldNd_Fbza , BldNd_Fbya , BldNd_Fbxa , BldNd_Fbxi , & + BldNd_Fbxl , BldNd_Fbxp , BldNd_Fbya , BldNd_Fbyi , BldNd_Fbyl , BldNd_Fbyp , BldNd_Fbza , BldNd_Fbzi , & + BldNd_Fbzl , BldNd_Fbzp , BldNd_Fd , BldNd_Fl , BldNd_Fn , BldNd_Ft , BldNd_Fx , BldNd_Fn , & + BldNd_Fxi , BldNd_Fxl , BldNd_Fxp , BldNd_Fy , BldNd_Fyi , BldNd_Fyl , BldNd_Fyp , BldNd_Fzi , & + BldNd_Fzl , BldNd_Fzp , BldNd_Gam , BldNd_GeomPhi , BldNd_M , BldNd_Mbxa , BldNd_Mbza , BldNd_Mbya , & + BldNd_Mbxa , BldNd_Mbxi , BldNd_Mbxl , BldNd_Mbxp , BldNd_Mbya , BldNd_Mbyi , BldNd_Mbyl , BldNd_Mbyp , & + BldNd_Mbza , BldNd_Mbzi , BldNd_Mbzl , BldNd_Mbzp , BldNd_Mm , BldNd_Mxi , BldNd_Mxl , BldNd_Mxp , & + BldNd_Myi , BldNd_Myl , BldNd_Myp , BldNd_Mm , BldNd_Mzi , BldNd_Mzl , BldNd_Mzp , BldNd_Phi , & + BldNd_Re , BldNd_SgCav , BldNd_SigCr , BldNd_STVx , BldNd_STVxa , BldNd_STVxi , BldNd_STVxl , BldNd_STVxp , & + BldNd_STVy , BldNd_STVya , BldNd_STVyi , BldNd_STVyl , BldNd_STVyp , BldNd_STVz , BldNd_STVza , BldNd_STVzi , & + BldNd_STVzl , BldNd_STVzp , BldNd_Theta , BldNd_TnInd , BldNd_TnInd_qs , BldNd_Toe , BldNd_UA_Flag , BldNd_UA_x1 , & + BldNd_UA_x2 , BldNd_UA_x3 , BldNd_UA_x4 , BldNd_UA_x5 , BldNd_Vindxp , BldNd_Vindzp , BldNd_Vindyp , BldNd_VDisx , & + BldNd_VDisxa , BldNd_VDisxi , BldNd_VDisxl , BldNd_VDisxp , BldNd_VDisy , BldNd_VDisya , BldNd_VDisyi , BldNd_VDisyl , & + BldNd_VDisyp , BldNd_VDisz , BldNd_VDisza , BldNd_VDiszi , BldNd_VDiszl , BldNd_VDiszp , BldNd_Vindx , BldNd_Vindxa , & + BldNd_Vindxi , BldNd_Vindxl , BldNd_Vindxp , BldNd_Vindy , BldNd_Vindya , BldNd_Vindyi , BldNd_Vindyl , BldNd_Vindyp , & + BldNd_Vindza , BldNd_Vindzi , BldNd_Vindzl , BldNd_Vindzp , BldNd_VRel , BldNd_VUndx , BldNd_VUndxa , BldNd_VUndxi , & + BldNd_VUndxl , BldNd_VUndxp , BldNd_VUndy , BldNd_VUndya , BldNd_VUndyi , BldNd_VUndyl , BldNd_VUndyp , BldNd_VUndz , & + BldNd_VUndza , BldNd_VUndzi , BldNd_VUndzl , BldNd_VUndzp , BldNd_Vx , BldNd_Vy /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(166) = (/ character(ChanLen) :: & ! This lists the units corresponding to the allowed parameters + "(deg) ","(-) ","(-) ","(-) ","(-) ","(-) ","(-) ","(-) ", & + "(-) ","(deg) ","(-) ","(m) ","(-) ","(-) ","(-) ","(-) ", & + "(-) ","(-) ","(-) ","(deg) ","(-) ","(-) ","(-) ","(-) ", & + "(-) ","(-) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & + "(N/m) ","(N/m) ","(m^2/s)","(1/0) ","(-) ","(N-m/m)","(N-m/m)","(N-m/m)", & + "(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)", & + "(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)", & + "(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(N-m/m)","(deg) ", & "(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) "/) + "(m/s) ","(m/s) ","(deg) ","(-) ","(-) ","(deg) ","(-) ","(rad) ", & + "(rad) ","(-) ","(-) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) "/) ! Initialize values @@ -1438,26 +1504,54 @@ SUBROUTINE BldNdOuts_SetOutParam(BldNd_OutList, p, p_AD, ErrStat, ErrMsg ) ! ..... Developer must add checking for invalid inputs here: ..... if (.not. p%Buoyancy) then - InvalidOutput( BldNd_Fbn ) = .true. - InvalidOutput( BldNd_Fbt ) = .true. - InvalidOutput( BldNd_Fbs ) = .true. - InvalidOutput( BldNd_Mbn ) = .true. - InvalidOutput( BldNd_Mbt ) = .true. - InvalidOutput( BldNd_Mbs ) = .true. + InvalidOutput( BldNd_Fbxi ) = .true. + InvalidOutput( BldNd_Fbyi ) = .true. + InvalidOutput( BldNd_Fbzi ) = .true. + InvalidOutput( BldNd_Mbxi ) = .true. + InvalidOutput( BldNd_Mbyi ) = .true. + InvalidOutput( BldNd_Mbzi ) = .true. + InvalidOutput( BldNd_Fbxp ) = .true. + InvalidOutput( BldNd_Fbyp ) = .true. + InvalidOutput( BldNd_Fbzp ) = .true. + InvalidOutput( BldNd_Mbxp ) = .true. + InvalidOutput( BldNd_Mbyp ) = .true. + InvalidOutput( BldNd_Mbzp ) = .true. + InvalidOutput( BldNd_Fbxl ) = .true. + InvalidOutput( BldNd_Fbyl ) = .true. + InvalidOutput( BldNd_Fbzl ) = .true. + InvalidOutput( BldNd_Mbxl ) = .true. + InvalidOutput( BldNd_Mbyl ) = .true. + InvalidOutput( BldNd_Mbzl ) = .true. + InvalidOutput( BldNd_Fbxa ) = .true. + InvalidOutput( BldNd_Fbya ) = .true. + InvalidOutput( BldNd_Fbza ) = .true. + InvalidOutput( BldNd_Mbxa ) = .true. + InvalidOutput( BldNd_Mbya ) = .true. + InvalidOutput( BldNd_Mbza ) = .true. end if ! The following are valid only for BEMT/DBEMT if (p_AD%WakeMod /= WakeMod_FVW) then - InvalidOutput( BldNd_Cl_Static ) = .true. - InvalidOutput( BldNd_Cd_Static ) = .true. - InvalidOutput( BldNd_Cm_Static ) = .true. + InvalidOutput( BldNd_Cl_qs ) = .true. + InvalidOutput( BldNd_Cd_qs ) = .true. + InvalidOutput( BldNd_Cm_qs ) = .true. else - ! The following are invalid for free vortex wake + ! The following are invalid for free vortex wake + InvalidOutput( BldNd_Toe ) = .true. InvalidOutput( BldNd_Chi ) = .true. InvalidOutput( BldNd_Curve ) = .true. - InvalidOutput( BldNd_GeomPhi ) = .true. ! applies only to BEM + InvalidOutput( BldNd_GeomPhi ) = .true. + endif + + ! The following are valid only for BEMT/DBEMT + if (p_AD%WakeMod /= WakeMod_BEMT) then + InvalidOutput( BldNd_BEM_F_qs ) = .true. + InvalidOutput( BldNd_BEM_k_qs ) = .true. + InvalidOutput( BldNd_BEM_kp_qs ) = .true. + InvalidOutput( BldNd_BEM_CT_qs ) = .true. endif + ! it's going to be very difficult to get the FVW states without rewriting a bunch of code if (.not. p_AD%UA_Flag .or. p_AD%WakeMod == WakeMod_FVW) then ! also invalid if AFAeroMod is not 4,5,6 InvalidOutput( BldNd_UA_x1 ) = .true. diff --git a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 index f4c037d0d4..0a26aee469 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -391,7 +391,9 @@ subroutine Dvr_CleanUp(dvr, ADI, FED, initialized, errStat, errMsg) call Dvr_EndCase(dvr, ADI, initialized, errStat2, errMsg2); call SetErrStat(errStat2, errMsg2, errStat, errMsg, RoutineName) ! End modules - call ADI_End( ADI%u(:), ADI%p, ADI%x(1), ADI%xd(1), ADI%z(1), ADI%OtherState(1), ADI%y, ADI%m, errStat2, errMsg2); call SetErrStat(errStat2, errMsg2, errStat, errMsg, RoutineName); + if (allocated(ADI%x)) then + call ADI_End( ADI%u(:), ADI%p, ADI%x(1), ADI%xd(1), ADI%z(1), ADI%OtherState(1), ADI%y, ADI%m, errStat2, errMsg2); call SetErrStat(errStat2, errMsg2, errStat, errMsg, RoutineName); + endif call AD_Dvr_DestroyDvr_SimData (dvr , errStat2, errMsg2); call SetErrStat(errStat2, errMsg2, errStat, errMsg, RoutineName) diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 6450bbc614..9a95dc4aa3 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -288,28 +288,28 @@ subroutine Calc_WriteOutput_AD() force = force + m%HubLoad%force( :,1) moment = moment + m%HubLoad%moment(:,1) - if (k<=size(BAeroFxg)) then + if (k<=size(BAeroFxi)) then ! Power contribution of blade wrt hub tmp = matmul( u%HubMotion%Orientation(:,:,1), m%HubLoad%moment(:,1) ) m%AllOuts( BAeroPwr(k) ) = omega * tmp(1) ! In global, wrt hub! - m%AllOuts( BAeroFxg(k) ) = m%HubLoad%force(1,1) - m%AllOuts( BAeroFyg(k) ) = m%HubLoad%force(2,1) - m%AllOuts( BAeroFzg(k) ) = m%HubLoad%force(3,1) - m%AllOuts( BAeroMxg(k) ) = m%HubLoad%moment(1,1) - m%AllOuts( BAeroMyg(k) ) = m%HubLoad%moment(2,1) - m%AllOuts( BAeroMzg(k) ) = m%HubLoad%moment(3,1) + m%AllOuts( BAeroFxi(k) ) = m%HubLoad%force(1,1) + m%AllOuts( BAeroFyi(k) ) = m%HubLoad%force(2,1) + m%AllOuts( BAeroFzi(k) ) = m%HubLoad%force(3,1) + m%AllOuts( BAeroMxi(k) ) = m%HubLoad%moment(1,1) + m%AllOuts( BAeroMyi(k) ) = m%HubLoad%moment(2,1) + m%AllOuts( BAeroMzi(k) ) = m%HubLoad%moment(3,1) end if end do ! In global - m%AllOuts( RtAeroFxg ) = force(1) - m%AllOuts( RtAeroFyg ) = force(2) - m%AllOuts( RtAeroFzg ) = force(3) - m%AllOuts( RtAeroMxg ) = moment(1) - m%AllOuts( RtAeroMyg ) = moment(2) - m%AllOuts( RtAeroMzg ) = moment(3) + m%AllOuts( RtAeroFxi ) = force(1) + m%AllOuts( RtAeroFyi ) = force(2) + m%AllOuts( RtAeroFzi ) = force(3) + m%AllOuts( RtAeroMxi ) = moment(1) + m%AllOuts( RtAeroMyi ) = moment(2) + m%AllOuts( RtAeroMzi ) = moment(3) tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) m%AllOuts( RtAeroFxh ) = tmp(1) m%AllOuts( RtAeroFyh ) = tmp(2) @@ -378,17 +378,28 @@ end subroutine Calc_WriteOutput_AD subroutine Calc_WriteOutput_BEMT() REAL(R8Ki) :: orient(3,3) REAL(R8Ki) :: theta(3) + REAL(ReKi) :: Vind_s(3) ! Induced velocity in "w" or "p" system REAL(ReKi) :: denom !, rmax REAL(ReKi) :: ct, st ! cosine, sine of theta REAL(ReKi) :: cp, sp ! cosine, sine of phi + ! Induced velocity in Global + do k=1,min(p%numBlades,3) + do j=1,u%BladeMotion(k)%NNodes + !if(p%BEM_Mod==BEMMod_2D) then + ! NOTE: if BEMMod_2D: x & y are in "w" system (WithoutSweepPitchTwist) + ! if BEMMod_3D: x & y are in "l" system (local-polar system) + Vind_s = (/ -m%BEMT_u(indx)%Vx(j,k)*m%BEMT_y%axInduction(j,k), m%BEMT_u(indx)%Vy(j,k)*m%BEMT_y%tanInduction(j,k), 0.0_ReKi /) + m%Vind_i(:,j,k) = matmul(Vind_s, m%orientationAnnulus(:,:,j,k)) ! TODO rename orientationAnnulus + enddo + enddo ! blade outputs do k=1,min(p%numBlades,AD_MaxBl_Out) ! limit this - m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi(k)*R2D, 360.0_ReKi ) + m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi_s(k)*R2D, 360.0_ReKi ) ! m%AllOuts( BPitch( k) ) = calculated in SetInputsForBEMT do beta=1,p%NBlOuts @@ -462,6 +473,17 @@ end subroutine Calc_WriteOutput_BEMT subroutine Calc_WriteOutput_FVW integer :: iW + ! Induced velocity in global + ! FVW already return this, we do a simple copy from Wings to Blades + do k=1,min(p%numBlades,3) + iW = p_AD%FVW%Bld2Wings(iRot, k) + do j=1,u%BladeMotion(k)%NNodes + m%Vind_i(:,j,k) = m_AD%FVW_y%W(iW)%Vind(1:3,j) + enddo + enddo + + ! TODO TODO TODO ALL THIS SHOULD BE COMPUTED IN THE SAME MEMORY FORMAT AS AERODYN + ! blade outputs do k=1,min(p%numBlades,3) iW=p_AD%FVW%Bld2Wings(iRot, k) @@ -993,6 +1015,10 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade call ReadOutputListFromFileInfo( FileInfo_In, CurLine, InputFileData%BldNd_OutList, InputFileData%BldNd_NumOuts, ErrStat2, ErrMsg2, UnEc ) if (FailedNodal()) return; +!FIXME: improve logic on the node outputs + ! Prevent segfault when no blades specified. All logic tests on BldNd_NumOuts at present. + if (InputFileData%BldNd_BladesOut <= 0) InputFileData%BldNd_NumOuts = 0 + RETURN CONTAINS !------------------------------------------------------------------------------------------------- @@ -2130,34 +2156,26 @@ subroutine calcCantAngle(f, xi,stencilSize,n,cantAngle) if (i.eq.1) then fIn = f(1:stencilSize) xiIn = xi(1:stencilSize) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case elseif (i.eq.size(xi)) then fIn = f(size(xi)-stencilSize +1:size(xi)) xiIn = xi(size(xi)-stencilSize+1:size(xi)) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case else fIn = f(i-1:i+1) xiIn = xi(i-1:i+1) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case endif - - cPrime(i) = 0.0 - fPrime(i) = 0.0 - - do j = 1,size(cx) - cPrime(i) = cPrime(i) + cx(j)*xiIn(j) - fPrime(i) = fPrime(i) + cx(j)*fIn(j) - end do - cantAngle(i) = atan2(fPrime(i),cPrime(i))*180_ReKi/pi + call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) + !call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) + if (info /= 0) then + print*,'Cant Calc failed at i=',i + else + cPrime(i) = 0.0 + fPrime(i) = 0.0 + do j = 1,size(cx) + cPrime(i) = cPrime(i) + cx(j)*xiIn(j) + fPrime(i) = fPrime(i) + cx(j)*fIn(j) + end do + cantAngle(i) = atan2(fPrime(i),cPrime(i))*180_ReKi/pi + endif end do end subroutine calcCantAngle diff --git a/modules/aerodyn/src/AeroDyn_IO_Params.f90 b/modules/aerodyn/src/AeroDyn_IO_Params.f90 index 34ea815754..3568cd8b32 100644 --- a/modules/aerodyn/src/AeroDyn_IO_Params.f90 +++ b/modules/aerodyn/src/AeroDyn_IO_Params.f90 @@ -228,30 +228,30 @@ module AeroDyn_IO_Params INTEGER(IntKi), PARAMETER :: B4AeroMy = 194 INTEGER(IntKi), PARAMETER :: B4AeroMz = 195 INTEGER(IntKi), PARAMETER :: B4AeroPwr = 196 - INTEGER(IntKi), PARAMETER :: B1AeroFxg = 197 - INTEGER(IntKi), PARAMETER :: B1AeroFyg = 198 - INTEGER(IntKi), PARAMETER :: B1AeroFzg = 199 - INTEGER(IntKi), PARAMETER :: B1AeroMxg = 200 - INTEGER(IntKi), PARAMETER :: B1AeroMyg = 201 - INTEGER(IntKi), PARAMETER :: B1AeroMzg = 202 - INTEGER(IntKi), PARAMETER :: B2AeroFxg = 203 - INTEGER(IntKi), PARAMETER :: B2AeroFyg = 204 - INTEGER(IntKi), PARAMETER :: B2AeroFzg = 205 - INTEGER(IntKi), PARAMETER :: B2AeroMxg = 206 - INTEGER(IntKi), PARAMETER :: B2AeroMyg = 207 - INTEGER(IntKi), PARAMETER :: B2AeroMzg = 208 - INTEGER(IntKi), PARAMETER :: B3AeroFxg = 209 - INTEGER(IntKi), PARAMETER :: B3AeroFyg = 210 - INTEGER(IntKi), PARAMETER :: B3AeroFzg = 211 - INTEGER(IntKi), PARAMETER :: B3AeroMxg = 212 - INTEGER(IntKi), PARAMETER :: B3AeroMyg = 213 - INTEGER(IntKi), PARAMETER :: B3AeroMzg = 214 - INTEGER(IntKi), PARAMETER :: B4AeroFxg = 215 - INTEGER(IntKi), PARAMETER :: B4AeroFyg = 216 - INTEGER(IntKi), PARAMETER :: B4AeroFzg = 217 - INTEGER(IntKi), PARAMETER :: B4AeroMxg = 218 - INTEGER(IntKi), PARAMETER :: B4AeroMyg = 219 - INTEGER(IntKi), PARAMETER :: B4AeroMzg = 220 + INTEGER(IntKi), PARAMETER :: B1AeroFxi = 197 + INTEGER(IntKi), PARAMETER :: B1AeroFyi = 198 + INTEGER(IntKi), PARAMETER :: B1AeroFzi = 199 + INTEGER(IntKi), PARAMETER :: B1AeroMxi = 200 + INTEGER(IntKi), PARAMETER :: B1AeroMyi = 201 + INTEGER(IntKi), PARAMETER :: B1AeroMzi = 202 + INTEGER(IntKi), PARAMETER :: B2AeroFxi = 203 + INTEGER(IntKi), PARAMETER :: B2AeroFyi = 204 + INTEGER(IntKi), PARAMETER :: B2AeroFzi = 205 + INTEGER(IntKi), PARAMETER :: B2AeroMxi = 206 + INTEGER(IntKi), PARAMETER :: B2AeroMyi = 207 + INTEGER(IntKi), PARAMETER :: B2AeroMzi = 208 + INTEGER(IntKi), PARAMETER :: B3AeroFxi = 209 + INTEGER(IntKi), PARAMETER :: B3AeroFyi = 210 + INTEGER(IntKi), PARAMETER :: B3AeroFzi = 211 + INTEGER(IntKi), PARAMETER :: B3AeroMxi = 212 + INTEGER(IntKi), PARAMETER :: B3AeroMyi = 213 + INTEGER(IntKi), PARAMETER :: B3AeroMzi = 214 + INTEGER(IntKi), PARAMETER :: B4AeroFxi = 215 + INTEGER(IntKi), PARAMETER :: B4AeroFyi = 216 + INTEGER(IntKi), PARAMETER :: B4AeroFzi = 217 + INTEGER(IntKi), PARAMETER :: B4AeroMxi = 218 + INTEGER(IntKi), PARAMETER :: B4AeroMyi = 219 + INTEGER(IntKi), PARAMETER :: B4AeroMzi = 220 ! Blade Nodal outputs: @@ -1520,12 +1520,12 @@ module AeroDyn_IO_Params INTEGER(IntKi), PARAMETER :: RtAeroCq = 1478 INTEGER(IntKi), PARAMETER :: RtAeroCt = 1479 INTEGER(IntKi), PARAMETER :: DBEMTau1 = 1480 - INTEGER(IntKi), PARAMETER :: RtAeroFxg = 1481 - INTEGER(IntKi), PARAMETER :: RtAeroFyg = 1482 - INTEGER(IntKi), PARAMETER :: RtAeroFzg = 1483 - INTEGER(IntKi), PARAMETER :: RtAeroMxg = 1484 - INTEGER(IntKi), PARAMETER :: RtAeroMyg = 1485 - INTEGER(IntKi), PARAMETER :: RtAeroMzg = 1486 + INTEGER(IntKi), PARAMETER :: RtAeroFxi = 1481 + INTEGER(IntKi), PARAMETER :: RtAeroFyi = 1482 + INTEGER(IntKi), PARAMETER :: RtAeroFzi = 1483 + INTEGER(IntKi), PARAMETER :: RtAeroMxi = 1484 + INTEGER(IntKi), PARAMETER :: RtAeroMyi = 1485 + INTEGER(IntKi), PARAMETER :: RtAeroMzi = 1486 ! Hub: @@ -1626,12 +1626,12 @@ module AeroDyn_IO_Params INTEGER, PARAMETER :: BAeroMy(4) = (/B1AeroMy, B2AeroMy, B3AeroMy, B4AeroMy/) ! total blade aero/hydro load (moment in y-direction) INTEGER, PARAMETER :: BAeroMz(4) = (/B1AeroMz, B2AeroMz, B3AeroMz, B4AeroMz/) ! total blade aero/hydro load (moment in z-direction) INTEGER, PARAMETER :: BAeroPwr(4) = (/B1AeroPwr, B2AeroPwr, B3AeroPwr, B4AeroPwr/) ! total blade aero/hydro power - INTEGER, PARAMETER :: BAeroFxg(4) = (/B1AeroFxg, B2AeroFxg, B3AeroFxg, B4AeroFxg/) ! total blade aero/hydro load (force in x-direction) in global - INTEGER, PARAMETER :: BAeroFyg(4) = (/B1AeroFyg, B2AeroFyg, B3AeroFyg, B4AeroFyg/) ! total blade aero/hydro load (force in y-direction) in global - INTEGER, PARAMETER :: BAeroFzg(4) = (/B1AeroFzg, B2AeroFzg, B3AeroFzg, B4AeroFzg/) ! total blade aero/hydro load (force in z-direction) in global - INTEGER, PARAMETER :: BAeroMxg(4) = (/B1AeroMxg, B2AeroMxg, B3AeroMxg, B4AeroMxg/) ! total blade aero/hydro load (moment in x-direction) in global - INTEGER, PARAMETER :: BAeroMyg(4) = (/B1AeroMyg, B2AeroMyg, B3AeroMyg, B4AeroMyg/) ! total blade aero/hydro load (moment in y-direction) in global - INTEGER, PARAMETER :: BAeroMzg(4) = (/B1AeroMzg, B2AeroMzg, B3AeroMzg, B4AeroMzg/) ! total blade aero/hydro load (moment in z-direction) in global + INTEGER, PARAMETER :: BAeroFxi(4) = (/B1AeroFxi, B2AeroFxi, B3AeroFxi, B4AeroFxi/) ! total blade aero/hydro load (force in x-direction) in global + INTEGER, PARAMETER :: BAeroFyi(4) = (/B1AeroFyi, B2AeroFyi, B3AeroFyi, B4AeroFyi/) ! total blade aero/hydro load (force in y-direction) in global + INTEGER, PARAMETER :: BAeroFzi(4) = (/B1AeroFzi, B2AeroFzi, B3AeroFzi, B4AeroFzi/) ! total blade aero/hydro load (force in z-direction) in global + INTEGER, PARAMETER :: BAeroMxi(4) = (/B1AeroMxi, B2AeroMxi, B3AeroMxi, B4AeroMxi/) ! total blade aero/hydro load (moment in x-direction) in global + INTEGER, PARAMETER :: BAeroMyi(4) = (/B1AeroMyi, B2AeroMyi, B3AeroMyi, B4AeroMyi/) ! total blade aero/hydro load (moment in y-direction) in global + INTEGER, PARAMETER :: BAeroMzi(4) = (/B1AeroMzi, B2AeroMzi, B3AeroMzi, B4AeroMzi/) ! total blade aero/hydro load (moment in z-direction) in global INTEGER, PARAMETER :: BNVUndx(9, 3) = RESHAPE( (/ & ! undisturbed wind velocity (x component) B1N1VUndx,B1N2VUndx,B1N3VUndx,B1N4VUndx,B1N5VUndx,B1N6VUndx,B1N7VUndx,B1N8VUndx,B1N9VUndx, & @@ -1874,11 +1874,11 @@ module AeroDyn_IO_Params - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1588) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically - "B1AEROFX ","B1AEROFXG","B1AEROFY ","B1AEROFYG","B1AEROFZ ","B1AEROFZG","B1AEROMX ","B1AEROMXG", & - "B1AEROMY ","B1AEROMYG","B1AEROMZ ","B1AEROMZG","B1AEROPWR","B1AZIMUTH","B1FLDFX ","B1FLDFXG ", & - "B1FLDFY ","B1FLDFYG ","B1FLDFZ ","B1FLDFZG ","B1FLDMX ","B1FLDMXG ","B1FLDMY ","B1FLDMYG ", & - "B1FLDMZ ","B1FLDMZG ","B1FLDPWR ","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC", & + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1594) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "B1AEROFX ","B1AEROFXI","B1AEROFY ","B1AEROFYI","B1AEROFZ ","B1AEROFZI","B1AEROMX ","B1AEROMXI", & + "B1AEROMY ","B1AEROMYI","B1AEROMZ ","B1AEROMZI","B1AEROPWR","B1AZIMUTH","B1FLDFX ","B1FLDFXI ", & + "B1FLDFY ","B1FLDFYI ","B1FLDFZ ","B1FLDFZI ","B1FLDMX ","B1FLDMXI ","B1FLDMY ","B1FLDMYI ", & + "B1FLDMZ ","B1FLDMZI ","B1FLDPWR ","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC", & "B1N1CM ","B1N1CN ","B1N1CPMIN","B1N1CT ","B1N1CURVE","B1N1CX ","B1N1CY ","B1N1DYNP ", & "B1N1FBN ","B1N1FBS ","B1N1FBT ","B1N1FD ","B1N1FL ","B1N1FN ","B1N1FT ","B1N1FX ", & "B1N1FY ","B1N1GAM ","B1N1M ","B1N1MBN ","B1N1MBS ","B1N1MBT ","B1N1MM ","B1N1PHI ", & @@ -1930,10 +1930,10 @@ module AeroDyn_IO_Params "B1N9FY ","B1N9GAM ","B1N9M ","B1N9MBN ","B1N9MBS ","B1N9MBT ","B1N9MM ","B1N9PHI ", & "B1N9RE ","B1N9SGCAV","B1N9SIGCR","B1N9STVX ","B1N9STVY ","B1N9STVZ ","B1N9THETA","B1N9TNIND", & "B1N9VDISX","B1N9VDISY","B1N9VDISZ","B1N9VINDX","B1N9VINDY","B1N9VREL ","B1N9VUNDX","B1N9VUNDY", & - "B1N9VUNDZ","B1PITCH ","B2AEROFX ","B2AEROFXG","B2AEROFY ","B2AEROFYG","B2AEROFZ ","B2AEROFZG", & - "B2AEROMX ","B2AEROMXG","B2AEROMY ","B2AEROMYG","B2AEROMZ ","B2AEROMZG","B2AEROPWR","B2AZIMUTH", & - "B2FLDFX ","B2FLDFXG ","B2FLDFY ","B2FLDFYG ","B2FLDFZ ","B2FLDFZG ","B2FLDMX ","B2FLDMXG ", & - "B2FLDMY ","B2FLDMYG ","B2FLDMZ ","B2FLDMZG ","B2FLDPWR ","B2N1ALPHA","B2N1AXIND","B2N1CD ", & + "B1N9VUNDZ","B1PITCH ","B2AEROFX ","B2AEROFXI","B2AEROFY ","B2AEROFYI","B2AEROFZ ","B2AEROFZI", & + "B2AEROMX ","B2AEROMXI","B2AEROMY ","B2AEROMYI","B2AEROMZ ","B2AEROMZI","B2AEROPWR","B2AZIMUTH", & + "B2FLDFX ","B2FLDFXI ","B2FLDFY ","B2FLDFYI ","B2FLDFZ ","B2FLDFZI ","B2FLDMX ","B2FLDMXI ", & + "B2FLDMY ","B2FLDMYI ","B2FLDMZ ","B2FLDMZI ","B2FLDPWR ","B2N1ALPHA","B2N1AXIND","B2N1CD ", & "B2N1CL ","B2N1CLRNC","B2N1CM ","B2N1CN ","B2N1CPMIN","B2N1CT ","B2N1CURVE","B2N1CX ", & "B2N1CY ","B2N1DYNP ","B2N1FBN ","B2N1FBS ","B2N1FBT ","B2N1FD ","B2N1FL ","B2N1FN ", & "B2N1FT ","B2N1FX ","B2N1FY ","B2N1GAM ","B2N1M ","B2N1MBN ","B2N1MBS ","B2N1MBT ", & @@ -1985,10 +1985,10 @@ module AeroDyn_IO_Params "B2N9FT ","B2N9FX ","B2N9FY ","B2N9GAM ","B2N9M ","B2N9MBN ","B2N9MBS ","B2N9MBT ", & "B2N9MM ","B2N9PHI ","B2N9RE ","B2N9SGCAV","B2N9SIGCR","B2N9STVX ","B2N9STVY ","B2N9STVZ ", & "B2N9THETA","B2N9TNIND","B2N9VDISX","B2N9VDISY","B2N9VDISZ","B2N9VINDX","B2N9VINDY","B2N9VREL ", & - "B2N9VUNDX","B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AEROFX ","B3AEROFXG","B3AEROFY ","B3AEROFYG", & - "B3AEROFZ ","B3AEROFZG","B3AEROMX ","B3AEROMXG","B3AEROMY ","B3AEROMYG","B3AEROMZ ","B3AEROMZG", & - "B3AEROPWR","B3AZIMUTH","B3FLDFX ","B3FLDFXG ","B3FLDFY ","B3FLDFYG ","B3FLDFZ ","B3FLDFZG ", & - "B3FLDMX ","B3FLDMXG ","B3FLDMY ","B3FLDMYG ","B3FLDMZ ","B3FLDMZG ","B3FLDPWR ","B3N1ALPHA", & + "B2N9VUNDX","B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AEROFX ","B3AEROFXI","B3AEROFY ","B3AEROFYI", & + "B3AEROFZ ","B3AEROFZI","B3AEROMX ","B3AEROMXI","B3AEROMY ","B3AEROMYI","B3AEROMZ ","B3AEROMZI", & + "B3AEROPWR","B3AZIMUTH","B3FLDFX ","B3FLDFXI ","B3FLDFY ","B3FLDFYI ","B3FLDFZ ","B3FLDFZI ", & + "B3FLDMX ","B3FLDMXI ","B3FLDMY ","B3FLDMYI ","B3FLDMZ ","B3FLDMZI ","B3FLDPWR ","B3N1ALPHA", & "B3N1AXIND","B3N1CD ","B3N1CL ","B3N1CLRNC","B3N1CM ","B3N1CN ","B3N1CPMIN","B3N1CT ", & "B3N1CURVE","B3N1CX ","B3N1CY ","B3N1DYNP ","B3N1FBN ","B3N1FBS ","B3N1FBT ","B3N1FD ", & "B3N1FL ","B3N1FN ","B3N1FT ","B3N1FX ","B3N1FY ","B3N1GAM ","B3N1M ","B3N1MBN ", & @@ -2040,45 +2040,46 @@ module AeroDyn_IO_Params "B3N9FL ","B3N9FN ","B3N9FT ","B3N9FX ","B3N9FY ","B3N9GAM ","B3N9M ","B3N9MBN ", & "B3N9MBS ","B3N9MBT ","B3N9MM ","B3N9PHI ","B3N9RE ","B3N9SGCAV","B3N9SIGCR","B3N9STVX ", & "B3N9STVY ","B3N9STVZ ","B3N9THETA","B3N9TNIND","B3N9VDISX","B3N9VDISY","B3N9VDISZ","B3N9VINDX", & - "B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ","B3PITCH ","B4AEROFX ","B4AEROFXG", & - "B4AEROFY ","B4AEROFYG","B4AEROFZ ","B4AEROFZG","B4AEROMX ","B4AEROMXG","B4AEROMY ","B4AEROMYG", & - "B4AEROMZ ","B4AEROMZG","B4AEROPWR","B4FLDFX ","B4FLDFXG ","B4FLDFY ","B4FLDFYG ","B4FLDFZ ", & - "B4FLDFZG ","B4FLDMX ","B4FLDMXG ","B4FLDMY ","B4FLDMYG ","B4FLDMZ ","B4FLDMZG ","B4FLDPWR ", & + "B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ","B3PITCH ","B4AEROFX ","B4AEROFXI", & + "B4AEROFY ","B4AEROFYI","B4AEROFZ ","B4AEROFZI","B4AEROMX ","B4AEROMXI","B4AEROMY ","B4AEROMYI", & + "B4AEROMZ ","B4AEROMZI","B4AEROPWR","B4FLDFX ","B4FLDFXI ","B4FLDFY ","B4FLDFYI ","B4FLDFZ ", & + "B4FLDFZI ","B4FLDMX ","B4FLDMXI ","B4FLDMY ","B4FLDMYI ","B4FLDMZ ","B4FLDMZI ","B4FLDPWR ", & "DBEMTAU1 ","HBFBX ","HBFBY ","HBFBZ ","HBMBX ","HBMBY ","HBMBZ ","NCFBX ", & "NCFBY ","NCFBZ ","NCMBX ","NCMBY ","NCMBZ ","RTAEROCP ","RTAEROCQ ","RTAEROCT ", & - "RTAEROFXG","RTAEROFXH","RTAEROFYG","RTAEROFYH","RTAEROFZG","RTAEROFZH","RTAEROMXG","RTAEROMXH", & - "RTAEROMYG","RTAEROMYH","RTAEROMZG","RTAEROMZH","RTAEROPWR","RTAREA ","RTFLDCP ","RTFLDCQ ", & - "RTFLDCT ","RTFLDFXG ","RTFLDFXH ","RTFLDFYG ","RTFLDFYH ","RTFLDFZG ","RTFLDFZH ","RTFLDMXG ", & - "RTFLDMXH ","RTFLDMYG ","RTFLDMYH ","RTFLDMZG ","RTFLDMZH ","RTFLDPWR ","RTSKEW ","RTSPEED ", & - "RTTSR ","RTVAVGXH ","RTVAVGYH ","RTVAVGZH ","TFALPHA ","TFFXI ","TFFYI ","TFFZI ", & - "TFMACH ","TFMXI ","TFMYI ","TFMZI ","TFRE ","TFSTVXI ","TFSTVYI ","TFSTVZI ", & - "TFVINDXI ","TFVINDYI ","TFVINDZI ","TFVREL ","TFVRELXI ","TFVRELYI ","TFVRELZI ","TFVUNDXI ", & - "TFVUNDYI ","TFVUNDZI ","TWN1DYNP ","TWN1FBX ","TWN1FBY ","TWN1FBZ ","TWN1FDX ","TWN1FDY ", & - "TWN1M ","TWN1MBX ","TWN1MBY ","TWN1MBZ ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ", & - "TWN1VREL ","TWN1VUNDX","TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FBX ","TWN2FBY ","TWN2FBZ ", & - "TWN2FDX ","TWN2FDY ","TWN2M ","TWN2MBX ","TWN2MBY ","TWN2MBZ ","TWN2RE ","TWN2STVX ", & - "TWN2STVY ","TWN2STVZ ","TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ","TWN3DYNP ","TWN3FBX ", & - "TWN3FBY ","TWN3FBZ ","TWN3FDX ","TWN3FDY ","TWN3M ","TWN3MBX ","TWN3MBY ","TWN3MBZ ", & - "TWN3RE ","TWN3STVX ","TWN3STVY ","TWN3STVZ ","TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ", & - "TWN4DYNP ","TWN4FBX ","TWN4FBY ","TWN4FBZ ","TWN4FDX ","TWN4FDY ","TWN4M ","TWN4MBX ", & - "TWN4MBY ","TWN4MBZ ","TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ","TWN4VUNDX", & - "TWN4VUNDY","TWN4VUNDZ","TWN5DYNP ","TWN5FBX ","TWN5FBY ","TWN5FBZ ","TWN5FDX ","TWN5FDY ", & - "TWN5M ","TWN5MBX ","TWN5MBY ","TWN5MBZ ","TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ", & - "TWN5VREL ","TWN5VUNDX","TWN5VUNDY","TWN5VUNDZ","TWN6DYNP ","TWN6FBX ","TWN6FBY ","TWN6FBZ ", & - "TWN6FDX ","TWN6FDY ","TWN6M ","TWN6MBX ","TWN6MBY ","TWN6MBZ ","TWN6RE ","TWN6STVX ", & - "TWN6STVY ","TWN6STVZ ","TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ","TWN7DYNP ","TWN7FBX ", & - "TWN7FBY ","TWN7FBZ ","TWN7FDX ","TWN7FDY ","TWN7M ","TWN7MBX ","TWN7MBY ","TWN7MBZ ", & - "TWN7RE ","TWN7STVX ","TWN7STVY ","TWN7STVZ ","TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ", & - "TWN8DYNP ","TWN8FBX ","TWN8FBY ","TWN8FBZ ","TWN8FDX ","TWN8FDY ","TWN8M ","TWN8MBX ", & - "TWN8MBY ","TWN8MBZ ","TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX", & - "TWN8VUNDY","TWN8VUNDZ","TWN9DYNP ","TWN9FBX ","TWN9FBY ","TWN9FBZ ","TWN9FDX ","TWN9FDY ", & - "TWN9M ","TWN9MBX ","TWN9MBY ","TWN9MBZ ","TWN9RE ","TWN9STVX ","TWN9STVY ","TWN9STVZ ", & - "TWN9VREL ","TWN9VUNDX","TWN9VUNDY","TWN9VUNDZ"/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(1588) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) - B1AeroFx , B1AeroFxg , B1AeroFy , B1AeroFyg , B1AeroFz , B1AeroFzg , B1AeroMx , B1AeroMxg , & - B1AeroMy , B1AeroMyg , B1AeroMz , B1AeroMzg , B1AeroPwr , B1Azimuth , B1AeroFx , B1AeroFxg , & - B1AeroFy , B1AeroFyg , B1AeroFz , B1AeroFzg , B1AeroMx , B1AeroMxg , B1AeroMy , B1AeroMyg , & - B1AeroMz , B1AeroMzg , B1AeroPwr , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , & + "RTAEROFXH","RTAEROFXI","RTAEROFYH","RTAEROFYI","RTAEROFZH","RTAEROFZI","RTAEROMXH","RTAEROMXI", & + "RTAEROMYH","RTAEROMYI","RTAEROMZH","RTAEROMZI","RTAEROPWR","RTAREA ","RTFLDCP ","RTFLDCQ ", & + "RTFLDCT ","RTFLDFXG ","RTFLDFXH ","RTFLDFXI ","RTFLDFYG ","RTFLDFYH ","RTFLDFYI ","RTFLDFZG ", & + "RTFLDFZH ","RTFLDFZI ","RTFLDMXG ","RTFLDMXH ","RTFLDMXI ","RTFLDMYG ","RTFLDMYH ","RTFLDMYI ", & + "RTFLDMZG ","RTFLDMZH ","RTFLDMZI ","RTFLDPWR ","RTSKEW ","RTSPEED ","RTTSR ","RTVAVGXH ", & + "RTVAVGYH ","RTVAVGZH ","TFALPHA ","TFFXI ","TFFYI ","TFFZI ","TFMACH ","TFMXI ", & + "TFMYI ","TFMZI ","TFRE ","TFSTVXI ","TFSTVYI ","TFSTVZI ","TFVINDXI ","TFVINDYI ", & + "TFVINDZI ","TFVREL ","TFVRELXI ","TFVRELYI ","TFVRELZI ","TFVUNDXI ","TFVUNDYI ","TFVUNDZI ", & + "TWN1DYNP ","TWN1FBX ","TWN1FBY ","TWN1FBZ ","TWN1FDX ","TWN1FDY ","TWN1M ","TWN1MBX ", & + "TWN1MBY ","TWN1MBZ ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ","TWN1VREL ","TWN1VUNDX", & + "TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FBX ","TWN2FBY ","TWN2FBZ ","TWN2FDX ","TWN2FDY ", & + "TWN2M ","TWN2MBX ","TWN2MBY ","TWN2MBZ ","TWN2RE ","TWN2STVX ","TWN2STVY ","TWN2STVZ ", & + "TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ","TWN3DYNP ","TWN3FBX ","TWN3FBY ","TWN3FBZ ", & + "TWN3FDX ","TWN3FDY ","TWN3M ","TWN3MBX ","TWN3MBY ","TWN3MBZ ","TWN3RE ","TWN3STVX ", & + "TWN3STVY ","TWN3STVZ ","TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ","TWN4DYNP ","TWN4FBX ", & + "TWN4FBY ","TWN4FBZ ","TWN4FDX ","TWN4FDY ","TWN4M ","TWN4MBX ","TWN4MBY ","TWN4MBZ ", & + "TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ","TWN4VUNDX","TWN4VUNDY","TWN4VUNDZ", & + "TWN5DYNP ","TWN5FBX ","TWN5FBY ","TWN5FBZ ","TWN5FDX ","TWN5FDY ","TWN5M ","TWN5MBX ", & + "TWN5MBY ","TWN5MBZ ","TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ","TWN5VREL ","TWN5VUNDX", & + "TWN5VUNDY","TWN5VUNDZ","TWN6DYNP ","TWN6FBX ","TWN6FBY ","TWN6FBZ ","TWN6FDX ","TWN6FDY ", & + "TWN6M ","TWN6MBX ","TWN6MBY ","TWN6MBZ ","TWN6RE ","TWN6STVX ","TWN6STVY ","TWN6STVZ ", & + "TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ","TWN7DYNP ","TWN7FBX ","TWN7FBY ","TWN7FBZ ", & + "TWN7FDX ","TWN7FDY ","TWN7M ","TWN7MBX ","TWN7MBY ","TWN7MBZ ","TWN7RE ","TWN7STVX ", & + "TWN7STVY ","TWN7STVZ ","TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ","TWN8DYNP ","TWN8FBX ", & + "TWN8FBY ","TWN8FBZ ","TWN8FDX ","TWN8FDY ","TWN8M ","TWN8MBX ","TWN8MBY ","TWN8MBZ ", & + "TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX","TWN8VUNDY","TWN8VUNDZ", & + "TWN9DYNP ","TWN9FBX ","TWN9FBY ","TWN9FBZ ","TWN9FDX ","TWN9FDY ","TWN9M ","TWN9MBX ", & + "TWN9MBY ","TWN9MBZ ","TWN9RE ","TWN9STVX ","TWN9STVY ","TWN9STVZ ","TWN9VREL ","TWN9VUNDX", & + "TWN9VUNDY","TWN9VUNDZ"/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(1594) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + B1AeroFx , B1AeroFxi , B1AeroFy , B1AeroFyi , B1AeroFz , B1AeroFzi , B1AeroMx , B1AeroMxi , & + B1AeroMy , B1AeroMyi , B1AeroMz , B1AeroMzi , B1AeroPwr , B1Azimuth , B1AeroFx , B1AeroFxi , & + B1AeroFy , B1AeroFyi , B1AeroFz , B1AeroFzi , B1AeroMx , B1AeroMxi , B1AeroMy , B1AeroMyi , & + B1AeroMz , B1AeroMzi , B1AeroPwr , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , & B1N1Cm , B1N1Cn , B1N1Cpmin , B1N1Ct , B1N1Curve , B1N1Cx , B1N1Cy , B1N1DynP , & B1N1Fbn , B1N1Fbs , B1N1Fbt , B1N1Fd , B1N1Fl , B1N1Fn , B1N1Ft , B1N1Fx , & B1N1Fy , B1N1Gam , B1N1M , B1N1Mbn , B1N1Mbs , B1N1Mbt , B1N1Mm , B1N1Phi , & @@ -2130,10 +2131,10 @@ module AeroDyn_IO_Params B1N9Fy , B1N9Gam , B1N9M , B1N9Mbn , B1N9Mbs , B1N9Mbt , B1N9Mm , B1N9Phi , & B1N9Re , B1N9SgCav , B1N9SigCr , B1N9STVx , B1N9STVy , B1N9STVz , B1N9Theta , B1N9TnInd , & B1N9VDisx , B1N9VDisy , B1N9VDisz , B1N9Vindx , B1N9Vindy , B1N9VRel , B1N9VUndx , B1N9VUndy , & - B1N9VUndz , B1Pitch , B2AeroFx , B2AeroFxg , B2AeroFy , B2AeroFyg , B2AeroFz , B2AeroFzg , & - B2AeroMx , B2AeroMxg , B2AeroMy , B2AeroMyg , B2AeroMz , B2AeroMzg , B2AeroPwr , B2Azimuth , & - B2AeroFx , B2AeroFxg , B2AeroFy , B2AeroFyg , B2AeroFz , B2AeroFzg , B2AeroMx , B2AeroMxg , & - B2AeroMy , B2AeroMyg , B2AeroMz , B2AeroMzg , B2AeroPwr , B2N1Alpha , B2N1AxInd , B2N1Cd , & + B1N9VUndz , B1Pitch , B2AeroFx , B2AeroFxi , B2AeroFy , B2AeroFyi , B2AeroFz , B2AeroFzi , & + B2AeroMx , B2AeroMxi , B2AeroMy , B2AeroMyi , B2AeroMz , B2AeroMzi , B2AeroPwr , B2Azimuth , & + B2AeroFx , B2AeroFxi , B2AeroFy , B2AeroFyi , B2AeroFz , B2AeroFzi , B2AeroMx , B2AeroMxi , & + B2AeroMy , B2AeroMyi , B2AeroMz , B2AeroMzi , B2AeroPwr , B2N1Alpha , B2N1AxInd , B2N1Cd , & B2N1Cl , B2N1Clrnc , B2N1Cm , B2N1Cn , B2N1Cpmin , B2N1Ct , B2N1Curve , B2N1Cx , & B2N1Cy , B2N1DynP , B2N1Fbn , B2N1Fbs , B2N1Fbt , B2N1Fd , B2N1Fl , B2N1Fn , & B2N1Ft , B2N1Fx , B2N1Fy , B2N1Gam , B2N1M , B2N1Mbn , B2N1Mbs , B2N1Mbt , & @@ -2185,10 +2186,10 @@ module AeroDyn_IO_Params B2N9Ft , B2N9Fx , B2N9Fy , B2N9Gam , B2N9M , B2N9Mbn , B2N9Mbs , B2N9Mbt , & B2N9Mm , B2N9Phi , B2N9Re , B2N9SgCav , B2N9SigCr , B2N9STVx , B2N9STVy , B2N9STVz , & B2N9Theta , B2N9TnInd , B2N9VDisx , B2N9VDisy , B2N9VDisz , B2N9Vindx , B2N9Vindy , B2N9VRel , & - B2N9VUndx , B2N9VUndy , B2N9VUndz , B2Pitch , B3AeroFx , B3AeroFxg , B3AeroFy , B3AeroFyg , & - B3AeroFz , B3AeroFzg , B3AeroMx , B3AeroMxg , B3AeroMy , B3AeroMyg , B3AeroMz , B3AeroMzg , & - B3AeroPwr , B3Azimuth , B3AeroFx , B3AeroFxg , B3AeroFy , B3AeroFyg , B3AeroFz , B3AeroFzg , & - B3AeroMx , B3AeroMxg , B3AeroMy , B3AeroMyg , B3AeroMz , B3AeroMzg , B3AeroPwr , B3N1Alpha , & + B2N9VUndx , B2N9VUndy , B2N9VUndz , B2Pitch , B3AeroFx , B3AeroFxi , B3AeroFy , B3AeroFyi , & + B3AeroFz , B3AeroFzi , B3AeroMx , B3AeroMxi , B3AeroMy , B3AeroMyi , B3AeroMz , B3AeroMzi , & + B3AeroPwr , B3Azimuth , B3AeroFx , B3AeroFxi , B3AeroFy , B3AeroFyi , B3AeroFz , B3AeroFzi , & + B3AeroMx , B3AeroMxi , B3AeroMy , B3AeroMyi , B3AeroMz , B3AeroMzi , B3AeroPwr , B3N1Alpha , & B3N1AxInd , B3N1Cd , B3N1Cl , B3N1Clrnc , B3N1Cm , B3N1Cn , B3N1Cpmin , B3N1Ct , & B3N1Curve , B3N1Cx , B3N1Cy , B3N1DynP , B3N1Fbn , B3N1Fbs , B3N1Fbt , B3N1Fd , & B3N1Fl , B3N1Fn , B3N1Ft , B3N1Fx , B3N1Fy , B3N1Gam , B3N1M , B3N1Mbn , & @@ -2240,41 +2241,42 @@ module AeroDyn_IO_Params B3N9Fl , B3N9Fn , B3N9Ft , B3N9Fx , B3N9Fy , B3N9Gam , B3N9M , B3N9Mbn , & B3N9Mbs , B3N9Mbt , B3N9Mm , B3N9Phi , B3N9Re , B3N9SgCav , B3N9SigCr , B3N9STVx , & B3N9STVy , B3N9STVz , B3N9Theta , B3N9TnInd , B3N9VDisx , B3N9VDisy , B3N9VDisz , B3N9Vindx , & - B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , B3Pitch , B4AeroFx , B4AeroFxg , & - B4AeroFy , B4AeroFyg , B4AeroFz , B4AeroFzg , B4AeroMx , B4AeroMxg , B4AeroMy , B4AeroMyg , & - B4AeroMz , B4AeroMzg , B4AeroPwr , B4AeroFx , B4AeroFxg , B4AeroFy , B4AeroFyg , B4AeroFz , & - B4AeroFzg , B4AeroMx , B4AeroMxg , B4AeroMy , B4AeroMyg , B4AeroMz , B4AeroMzg , B4AeroPwr , & + B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , B3Pitch , B4AeroFx , B4AeroFxi , & + B4AeroFy , B4AeroFyi , B4AeroFz , B4AeroFzi , B4AeroMx , B4AeroMxi , B4AeroMy , B4AeroMyi , & + B4AeroMz , B4AeroMzi , B4AeroPwr , B4AeroFx , B4AeroFxi , B4AeroFy , B4AeroFyi , B4AeroFz , & + B4AeroFzi , B4AeroMx , B4AeroMxi , B4AeroMy , B4AeroMyi , B4AeroMz , B4AeroMzi , B4AeroPwr , & DBEMTau1 , HbFbx , HbFby , HbFbz , HbMbx , HbMby , HbMbz , NcFbx , & NcFby , NcFbz , NcMbx , NcMby , NcMbz , RtAeroCp , RtAeroCq , RtAeroCt , & - RtAeroFxg , RtAeroFxh , RtAeroFyg , RtAeroFyh , RtAeroFzg , RtAeroFzh , RtAeroMxg , RtAeroMxh , & - RtAeroMyg , RtAeroMyh , RtAeroMzg , RtAeroMzh , RtAeroPwr , RtArea , RtAeroCp , RtAeroCq , & - RtAeroCt , RtAeroFxg , RtAeroFxh , RtAeroFyg , RtAeroFyh , RtAeroFzg , RtAeroFzh , RtAeroMxg , & - RtAeroMxh , RtAeroMyg , RtAeroMyh , RtAeroMzg , RtAeroMzh , RtAeroPwr , RtSkew , RtSpeed , & - RtTSR , RtVAvgxh , RtVAvgyh , RtVAvgzh , TFAlpha , TFFxi , TFFyi , TFFzi , & - TFMach , TFMxi , TFMyi , TFMzi , TFRe , TFSTVxi , TFSTVyi , TFSTVzi , & - TFVindxi , TFVindyi , TFVindzi , TFVrel , TFVrelxi , TFVrelyi , TFVrelzi , TFVundxi , & - TFVundyi , TFVundzi , TwN1DynP , TwN1Fbx , TwN1Fby , TwN1Fbz , TwN1Fdx , TwN1Fdy , & - TwN1M , TwN1Mbx , TwN1Mby , TwN1Mbz , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , & - TwN1Vrel , TwN1VUndx , TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fbx , TwN2Fby , TwN2Fbz , & - TwN2Fdx , TwN2Fdy , TwN2M , TwN2Mbx , TwN2Mby , TwN2Mbz , TwN2Re , TwN2STVx , & - TwN2STVy , TwN2STVz , TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , TwN3DynP , TwN3Fbx , & - TwN3Fby , TwN3Fbz , TwN3Fdx , TwN3Fdy , TwN3M , TwN3Mbx , TwN3Mby , TwN3Mbz , & - TwN3Re , TwN3STVx , TwN3STVy , TwN3STVz , TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , & - TwN4DynP , TwN4Fbx , TwN4Fby , TwN4Fbz , TwN4Fdx , TwN4Fdy , TwN4M , TwN4Mbx , & - TwN4Mby , TwN4Mbz , TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , TwN4VUndx , & - TwN4VUndy , TwN4VUndz , TwN5DynP , TwN5Fbx , TwN5Fby , TwN5Fbz , TwN5Fdx , TwN5Fdy , & - TwN5M , TwN5Mbx , TwN5Mby , TwN5Mbz , TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , & - TwN5Vrel , TwN5VUndx , TwN5VUndy , TwN5VUndz , TwN6DynP , TwN6Fbx , TwN6Fby , TwN6Fbz , & - TwN6Fdx , TwN6Fdy , TwN6M , TwN6Mbx , TwN6Mby , TwN6Mbz , TwN6Re , TwN6STVx , & - TwN6STVy , TwN6STVz , TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , TwN7DynP , TwN7Fbx , & - TwN7Fby , TwN7Fbz , TwN7Fdx , TwN7Fdy , TwN7M , TwN7Mbx , TwN7Mby , TwN7Mbz , & - TwN7Re , TwN7STVx , TwN7STVy , TwN7STVz , TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , & - TwN8DynP , TwN8Fbx , TwN8Fby , TwN8Fbz , TwN8Fdx , TwN8Fdy , TwN8M , TwN8Mbx , & - TwN8Mby , TwN8Mbz , TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , & - TwN8VUndy , TwN8VUndz , TwN9DynP , TwN9Fbx , TwN9Fby , TwN9Fbz , TwN9Fdx , TwN9Fdy , & - TwN9M , TwN9Mbx , TwN9Mby , TwN9Mbz , TwN9Re , TwN9STVx , TwN9STVy , TwN9STVz , & - TwN9Vrel , TwN9VUndx , TwN9VUndy , TwN9VUndz /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1588) = (/ & ! This lists the units corresponding to the allowed parameters + RtAeroFxh , RtAeroFxi , RtAeroFyh , RtAeroFyi , RtAeroFzh , RtAeroFzi , RtAeroMxh , RtAeroMxi , & + RtAeroMyh , RtAeroMyi , RtAeroMzh , RtAeroMzi , RtAeroPwr , RtArea , RtAeroCp , RtAeroCq , & + RtAeroCt , RtAeroFxi , RtAeroFxh , RtAeroFxi , RtAeroFyi , RtAeroFyh , RtAeroFyi , RtAeroFzi , & + RtAeroFzh , RtAeroFzi , RtAeroMxi , RtAeroMxh , RtAeroMxi , RtAeroMyi , RtAeroMyh , RtAeroMyi , & + RtAeroMzi , RtAeroMzh , RtAeroMzi , RtAeroPwr , RtSkew , RtSpeed , RtTSR , RtVAvgxh , & + RtVAvgyh , RtVAvgzh , TFAlpha , TFFxi , TFFyi , TFFzi , TFMach , TFMxi , & + TFMyi , TFMzi , TFRe , TFSTVxi , TFSTVyi , TFSTVzi , TFVindxi , TFVindyi , & + TFVindzi , TFVrel , TFVrelxi , TFVrelyi , TFVrelzi , TFVundxi , TFVundyi , TFVundzi , & + TwN1DynP , TwN1Fbx , TwN1Fby , TwN1Fbz , TwN1Fdx , TwN1Fdy , TwN1M , TwN1Mbx , & + TwN1Mby , TwN1Mbz , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , TwN1Vrel , TwN1VUndx , & + TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fbx , TwN2Fby , TwN2Fbz , TwN2Fdx , TwN2Fdy , & + TwN2M , TwN2Mbx , TwN2Mby , TwN2Mbz , TwN2Re , TwN2STVx , TwN2STVy , TwN2STVz , & + TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , TwN3DynP , TwN3Fbx , TwN3Fby , TwN3Fbz , & + TwN3Fdx , TwN3Fdy , TwN3M , TwN3Mbx , TwN3Mby , TwN3Mbz , TwN3Re , TwN3STVx , & + TwN3STVy , TwN3STVz , TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , TwN4DynP , TwN4Fbx , & + TwN4Fby , TwN4Fbz , TwN4Fdx , TwN4Fdy , TwN4M , TwN4Mbx , TwN4Mby , TwN4Mbz , & + TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , TwN4VUndx , TwN4VUndy , TwN4VUndz , & + TwN5DynP , TwN5Fbx , TwN5Fby , TwN5Fbz , TwN5Fdx , TwN5Fdy , TwN5M , TwN5Mbx , & + TwN5Mby , TwN5Mbz , TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , TwN5Vrel , TwN5VUndx , & + TwN5VUndy , TwN5VUndz , TwN6DynP , TwN6Fbx , TwN6Fby , TwN6Fbz , TwN6Fdx , TwN6Fdy , & + TwN6M , TwN6Mbx , TwN6Mby , TwN6Mbz , TwN6Re , TwN6STVx , TwN6STVy , TwN6STVz , & + TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , TwN7DynP , TwN7Fbx , TwN7Fby , TwN7Fbz , & + TwN7Fdx , TwN7Fdy , TwN7M , TwN7Mbx , TwN7Mby , TwN7Mbz , TwN7Re , TwN7STVx , & + TwN7STVy , TwN7STVz , TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , TwN8DynP , TwN8Fbx , & + TwN8Fby , TwN8Fbz , TwN8Fdx , TwN8Fdy , TwN8M , TwN8Mbx , TwN8Mby , TwN8Mbz , & + TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , TwN8VUndy , TwN8VUndz , & + TwN9DynP , TwN9Fbx , TwN9Fby , TwN9Fbz , TwN9Fdx , TwN9Fdy , TwN9M , TwN9Mbx , & + TwN9Mby , TwN9Mbz , TwN9Re , TwN9STVx , TwN9STVy , TwN9STVz , TwN9Vrel , TwN9VUndx , & + TwN9VUndy , TwN9VUndz /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1594) = (/ character(ChanLen) :: & ! This lists the units corresponding to the allowed parameters "(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ", & "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(N) ","(N) ", & "(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ", & @@ -2448,11 +2450,14 @@ module AeroDyn_IO_Params "(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(-) ","(-) ","(-) ", & "(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ", & "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(m^2) ","(-) ","(-) ", & - "(-) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ", & - "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(rpm) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(N) ","(N) ","(N) ", & - "(-) ","(N-m) ","(N-m) ","(N-m) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(-) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ", & + "(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ", & + "(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(rpm) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(N) ","(N) ","(N) ","(-) ","(N-m) ", & + "(N-m) ","(N-m) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ","(N-m/m)", & + "(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & "(-) ","(N-m/m)","(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ", & @@ -2471,9 +2476,7 @@ module AeroDyn_IO_Params "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ","(N-m/m)", & "(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(-) ","(N-m/m)","(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) "/) + "(m/s) ","(m/s) "/) end module AeroDyn_IO_Params diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index 441e24f6a1..5f763c8a6c 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -263,6 +263,7 @@ typedef ^ RotMiscVarType AA_InputType AA_u - - - "Inputs to the AA module" - typedef ^ RotMiscVarType ReKi DisturbedInflow {:}{:}{:} - - "InflowOnBlade values modified by tower influence" m/s typedef ^ RotMiscVarType R8Ki orientationAnnulus {:}{:}{:}{:} - - "Coordinate system equivalent to BladeMotion Orientation, but without live sweep, blade-pitch, and twist angles" - +typedef ^ RotMiscVarType R8Ki R_li {:}{:}{:}{:} - - "Transformation matrix from inertial system to the staggered polar coordinate system of a given section" - typedef ^ RotMiscVarType ReKi AllOuts {:} - - "An array holding the value of all of the calculated (not only selected) output channels" - typedef ^ RotMiscVarType ReKi W_Twr {:} - - "relative wind speed normal to the tower at node j" m/s typedef ^ RotMiscVarType ReKi X_Twr {:} - - "local x-component of force per unit length of the jth node in the tower" m/s @@ -276,6 +277,7 @@ typedef ^ RotMiscVarType ReKi M {:}{:} - - "pitching moment per unit length of t typedef ^ RotMiscVarType ReKi Mx {:}{:} - - "pitching moment per unit length of the jth node in the kth blade (in x direction)" Nm/m typedef ^ RotMiscVarType ReKi My {:}{:} - - "pitching moment per unit length of the jth node in the kth blade (in y direction)" Nm/m typedef ^ RotMiscVarType ReKi Mz {:}{:} - - "pitching moment per unit length of the jth node in the kth blade (in z direction)" Nm/m +typedef ^ RotMiscVarType ReKi Vind_i {:}{:}{:} - - "Induced velocities at jth node and kth blade (3xnSpanxnB)" m/s typedef ^ RotMiscVarType ReKi V_DiskAvg {3} - - "disk-average relative wind speed" m/s typedef ^ RotMiscVarType ReKi yaw - - - "Yaw calculated in SetInputsForBEMT" rad typedef ^ RotMiscVarType ReKi tilt - - - "tilt calculated in SetInputsForBEMT" rad @@ -286,8 +288,6 @@ typedef ^ RotMiscVarType MeshMapType B_L_2_H_P {:} - - "mapping data structure t typedef ^ RotMiscVarType ReKi SigmaCavitCrit {:}{:} - - "critical cavitation number- inception value (above which cavit will occur)" - typedef ^ RotMiscVarType ReKi SigmaCavit {:}{:} - - "cavitation number at node " - typedef ^ RotMiscVarType Logical CavitWarnSet {:}{:} - - "cavitation warning issued " - -typedef ^ RotMiscVarType ReKi BlFB {:}{:}{:} - - "buoyant force per unit length at blade node" N/m -typedef ^ RotMiscVarType ReKi BlMB {:}{:}{:} - - "buoyant moment per unit length at blade node" Nm/m typedef ^ RotMiscVarType ReKi TwrFB {:}{:} - - "buoyant force per unit length at tower node" N/m typedef ^ RotMiscVarType ReKi TwrMB {:}{:} - - "buoyant moment per unit length at tower node" Nm/m typedef ^ RotMiscVarType ReKi HubFB {:} - - "buoyant force at hub node" N diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 77135b3b37..c26eef9940 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -303,6 +303,7 @@ MODULE AeroDyn_Types TYPE(AA_InputType) :: AA_u !< Inputs to the AA module [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: DisturbedInflow !< InflowOnBlade values modified by tower influence [m/s] REAL(R8Ki) , DIMENSION(:,:,:,:), ALLOCATABLE :: orientationAnnulus !< Coordinate system equivalent to BladeMotion Orientation, but without live sweep, blade-pitch, and twist angles [-] + REAL(R8Ki) , DIMENSION(:,:,:,:), ALLOCATABLE :: R_li !< Transformation matrix from inertial system to the staggered polar coordinate system of a given section [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: AllOuts !< An array holding the value of all of the calculated (not only selected) output channels [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: W_Twr !< relative wind speed normal to the tower at node j [m/s] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: X_Twr !< local x-component of force per unit length of the jth node in the tower [m/s] @@ -316,6 +317,7 @@ MODULE AeroDyn_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Mx !< pitching moment per unit length of the jth node in the kth blade (in x direction) [Nm/m] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: My !< pitching moment per unit length of the jth node in the kth blade (in y direction) [Nm/m] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Mz !< pitching moment per unit length of the jth node in the kth blade (in z direction) [Nm/m] + REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: Vind_i !< Induced velocities at jth node and kth blade (3xnSpanxnB) [m/s] REAL(ReKi) , DIMENSION(1:3) :: V_DiskAvg !< disk-average relative wind speed [m/s] REAL(ReKi) :: yaw !< Yaw calculated in SetInputsForBEMT [rad] REAL(ReKi) :: tilt !< tilt calculated in SetInputsForBEMT [rad] @@ -326,8 +328,6 @@ MODULE AeroDyn_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SigmaCavitCrit !< critical cavitation number- inception value (above which cavit will occur) [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SigmaCavit !< cavitation number at node [-] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: CavitWarnSet !< cavitation warning issued [-] - REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: BlFB !< buoyant force per unit length at blade node [N/m] - REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: BlMB !< buoyant moment per unit length at blade node [Nm/m] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TwrFB !< buoyant force per unit length at tower node [N/m] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: TwrMB !< buoyant moment per unit length at tower node [Nm/m] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: HubFB !< buoyant force at hub node [N] @@ -8892,6 +8892,24 @@ SUBROUTINE AD_CopyRotMiscVarType( SrcRotMiscVarTypeData, DstRotMiscVarTypeData, END IF DstRotMiscVarTypeData%orientationAnnulus = SrcRotMiscVarTypeData%orientationAnnulus ENDIF +IF (ALLOCATED(SrcRotMiscVarTypeData%R_li)) THEN + i1_l = LBOUND(SrcRotMiscVarTypeData%R_li,1) + i1_u = UBOUND(SrcRotMiscVarTypeData%R_li,1) + i2_l = LBOUND(SrcRotMiscVarTypeData%R_li,2) + i2_u = UBOUND(SrcRotMiscVarTypeData%R_li,2) + i3_l = LBOUND(SrcRotMiscVarTypeData%R_li,3) + i3_u = UBOUND(SrcRotMiscVarTypeData%R_li,3) + i4_l = LBOUND(SrcRotMiscVarTypeData%R_li,4) + i4_u = UBOUND(SrcRotMiscVarTypeData%R_li,4) + IF (.NOT. ALLOCATED(DstRotMiscVarTypeData%R_li)) THEN + ALLOCATE(DstRotMiscVarTypeData%R_li(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstRotMiscVarTypeData%R_li.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstRotMiscVarTypeData%R_li = SrcRotMiscVarTypeData%R_li +ENDIF IF (ALLOCATED(SrcRotMiscVarTypeData%AllOuts)) THEN i1_l = LBOUND(SrcRotMiscVarTypeData%AllOuts,1) i1_u = UBOUND(SrcRotMiscVarTypeData%AllOuts,1) @@ -9065,6 +9083,22 @@ SUBROUTINE AD_CopyRotMiscVarType( SrcRotMiscVarTypeData, DstRotMiscVarTypeData, END IF END IF DstRotMiscVarTypeData%Mz = SrcRotMiscVarTypeData%Mz +ENDIF +IF (ALLOCATED(SrcRotMiscVarTypeData%Vind_i)) THEN + i1_l = LBOUND(SrcRotMiscVarTypeData%Vind_i,1) + i1_u = UBOUND(SrcRotMiscVarTypeData%Vind_i,1) + i2_l = LBOUND(SrcRotMiscVarTypeData%Vind_i,2) + i2_u = UBOUND(SrcRotMiscVarTypeData%Vind_i,2) + i3_l = LBOUND(SrcRotMiscVarTypeData%Vind_i,3) + i3_u = UBOUND(SrcRotMiscVarTypeData%Vind_i,3) + IF (.NOT. ALLOCATED(DstRotMiscVarTypeData%Vind_i)) THEN + ALLOCATE(DstRotMiscVarTypeData%Vind_i(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstRotMiscVarTypeData%Vind_i.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstRotMiscVarTypeData%Vind_i = SrcRotMiscVarTypeData%Vind_i ENDIF DstRotMiscVarTypeData%V_DiskAvg = SrcRotMiscVarTypeData%V_DiskAvg DstRotMiscVarTypeData%yaw = SrcRotMiscVarTypeData%yaw @@ -9143,38 +9177,6 @@ SUBROUTINE AD_CopyRotMiscVarType( SrcRotMiscVarTypeData, DstRotMiscVarTypeData, END IF DstRotMiscVarTypeData%CavitWarnSet = SrcRotMiscVarTypeData%CavitWarnSet ENDIF -IF (ALLOCATED(SrcRotMiscVarTypeData%BlFB)) THEN - i1_l = LBOUND(SrcRotMiscVarTypeData%BlFB,1) - i1_u = UBOUND(SrcRotMiscVarTypeData%BlFB,1) - i2_l = LBOUND(SrcRotMiscVarTypeData%BlFB,2) - i2_u = UBOUND(SrcRotMiscVarTypeData%BlFB,2) - i3_l = LBOUND(SrcRotMiscVarTypeData%BlFB,3) - i3_u = UBOUND(SrcRotMiscVarTypeData%BlFB,3) - IF (.NOT. ALLOCATED(DstRotMiscVarTypeData%BlFB)) THEN - ALLOCATE(DstRotMiscVarTypeData%BlFB(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstRotMiscVarTypeData%BlFB.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstRotMiscVarTypeData%BlFB = SrcRotMiscVarTypeData%BlFB -ENDIF -IF (ALLOCATED(SrcRotMiscVarTypeData%BlMB)) THEN - i1_l = LBOUND(SrcRotMiscVarTypeData%BlMB,1) - i1_u = UBOUND(SrcRotMiscVarTypeData%BlMB,1) - i2_l = LBOUND(SrcRotMiscVarTypeData%BlMB,2) - i2_u = UBOUND(SrcRotMiscVarTypeData%BlMB,2) - i3_l = LBOUND(SrcRotMiscVarTypeData%BlMB,3) - i3_u = UBOUND(SrcRotMiscVarTypeData%BlMB,3) - IF (.NOT. ALLOCATED(DstRotMiscVarTypeData%BlMB)) THEN - ALLOCATE(DstRotMiscVarTypeData%BlMB(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstRotMiscVarTypeData%BlMB.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - END IF - DstRotMiscVarTypeData%BlMB = SrcRotMiscVarTypeData%BlMB -ENDIF IF (ALLOCATED(SrcRotMiscVarTypeData%TwrFB)) THEN i1_l = LBOUND(SrcRotMiscVarTypeData%TwrFB,1) i1_u = UBOUND(SrcRotMiscVarTypeData%TwrFB,1) @@ -9395,6 +9397,9 @@ SUBROUTINE AD_DestroyRotMiscVarType( RotMiscVarTypeData, ErrStat, ErrMsg, DEALLO IF (ALLOCATED(RotMiscVarTypeData%orientationAnnulus)) THEN DEALLOCATE(RotMiscVarTypeData%orientationAnnulus) ENDIF +IF (ALLOCATED(RotMiscVarTypeData%R_li)) THEN + DEALLOCATE(RotMiscVarTypeData%R_li) +ENDIF IF (ALLOCATED(RotMiscVarTypeData%AllOuts)) THEN DEALLOCATE(RotMiscVarTypeData%AllOuts) ENDIF @@ -9434,6 +9439,9 @@ SUBROUTINE AD_DestroyRotMiscVarType( RotMiscVarTypeData, ErrStat, ErrMsg, DEALLO IF (ALLOCATED(RotMiscVarTypeData%Mz)) THEN DEALLOCATE(RotMiscVarTypeData%Mz) ENDIF +IF (ALLOCATED(RotMiscVarTypeData%Vind_i)) THEN + DEALLOCATE(RotMiscVarTypeData%Vind_i) +ENDIF IF (ALLOCATED(RotMiscVarTypeData%hub_theta_x_root)) THEN DEALLOCATE(RotMiscVarTypeData%hub_theta_x_root) ENDIF @@ -9455,12 +9463,6 @@ SUBROUTINE AD_DestroyRotMiscVarType( RotMiscVarTypeData, ErrStat, ErrMsg, DEALLO IF (ALLOCATED(RotMiscVarTypeData%CavitWarnSet)) THEN DEALLOCATE(RotMiscVarTypeData%CavitWarnSet) ENDIF -IF (ALLOCATED(RotMiscVarTypeData%BlFB)) THEN - DEALLOCATE(RotMiscVarTypeData%BlFB) -ENDIF -IF (ALLOCATED(RotMiscVarTypeData%BlMB)) THEN - DEALLOCATE(RotMiscVarTypeData%BlMB) -ENDIF IF (ALLOCATED(RotMiscVarTypeData%TwrFB)) THEN DEALLOCATE(RotMiscVarTypeData%TwrFB) ENDIF @@ -9672,6 +9674,11 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Int_BufSz = Int_BufSz + 2*4 ! orientationAnnulus upper/lower bounds for each dimension Db_BufSz = Db_BufSz + SIZE(InData%orientationAnnulus) ! orientationAnnulus END IF + Int_BufSz = Int_BufSz + 1 ! R_li allocated yes/no + IF ( ALLOCATED(InData%R_li) ) THEN + Int_BufSz = Int_BufSz + 2*4 ! R_li upper/lower bounds for each dimension + Db_BufSz = Db_BufSz + SIZE(InData%R_li) ! R_li + END IF Int_BufSz = Int_BufSz + 1 ! AllOuts allocated yes/no IF ( ALLOCATED(InData%AllOuts) ) THEN Int_BufSz = Int_BufSz + 2*1 ! AllOuts upper/lower bounds for each dimension @@ -9736,6 +9743,11 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E IF ( ALLOCATED(InData%Mz) ) THEN Int_BufSz = Int_BufSz + 2*2 ! Mz upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%Mz) ! Mz + END IF + Int_BufSz = Int_BufSz + 1 ! Vind_i allocated yes/no + IF ( ALLOCATED(InData%Vind_i) ) THEN + Int_BufSz = Int_BufSz + 2*3 ! Vind_i upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Vind_i) ! Vind_i END IF Re_BufSz = Re_BufSz + SIZE(InData%V_DiskAvg) ! V_DiskAvg Re_BufSz = Re_BufSz + 1 ! yaw @@ -9801,16 +9813,6 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Int_BufSz = Int_BufSz + 2*2 ! CavitWarnSet upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%CavitWarnSet) ! CavitWarnSet END IF - Int_BufSz = Int_BufSz + 1 ! BlFB allocated yes/no - IF ( ALLOCATED(InData%BlFB) ) THEN - Int_BufSz = Int_BufSz + 2*3 ! BlFB upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%BlFB) ! BlFB - END IF - Int_BufSz = Int_BufSz + 1 ! BlMB allocated yes/no - IF ( ALLOCATED(InData%BlMB) ) THEN - Int_BufSz = Int_BufSz + 2*3 ! BlMB upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%BlMB) ! BlMB - END IF Int_BufSz = Int_BufSz + 1 ! TwrFB allocated yes/no IF ( ALLOCATED(InData%TwrFB) ) THEN Int_BufSz = Int_BufSz + 2*2 ! TwrFB upper/lower bounds for each dimension @@ -10271,6 +10273,36 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E END DO END DO END IF + IF ( .NOT. ALLOCATED(InData%R_li) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%R_li,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%R_li,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%R_li,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%R_li,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%R_li,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%R_li,3) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%R_li,4) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%R_li,4) + Int_Xferred = Int_Xferred + 2 + + DO i4 = LBOUND(InData%R_li,4), UBOUND(InData%R_li,4) + DO i3 = LBOUND(InData%R_li,3), UBOUND(InData%R_li,3) + DO i2 = LBOUND(InData%R_li,2), UBOUND(InData%R_li,2) + DO i1 = LBOUND(InData%R_li,1), UBOUND(InData%R_li,1) + DbKiBuf(Db_Xferred) = InData%R_li(i1,i2,i3,i4) + Db_Xferred = Db_Xferred + 1 + END DO + END DO + END DO + END DO + END IF IF ( .NOT. ALLOCATED(InData%AllOuts) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -10510,6 +10542,31 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Re_Xferred = Re_Xferred + 1 END DO END DO + END IF + IF ( .NOT. ALLOCATED(InData%Vind_i) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_i,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_i,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_i,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_i,2) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%Vind_i,3) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Vind_i,3) + Int_Xferred = Int_Xferred + 2 + + DO i3 = LBOUND(InData%Vind_i,3), UBOUND(InData%Vind_i,3) + DO i2 = LBOUND(InData%Vind_i,2), UBOUND(InData%Vind_i,2) + DO i1 = LBOUND(InData%Vind_i,1), UBOUND(InData%Vind_i,1) + ReKiBuf(Re_Xferred) = InData%Vind_i(i1,i2,i3) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO END IF DO i1 = LBOUND(InData%V_DiskAvg,1), UBOUND(InData%V_DiskAvg,1) ReKiBuf(Re_Xferred) = InData%V_DiskAvg(i1) @@ -10665,56 +10722,6 @@ SUBROUTINE AD_PackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E END DO END DO END IF - IF ( .NOT. ALLOCATED(InData%BlFB) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlFB,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlFB,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlFB,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlFB,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlFB,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlFB,3) - Int_Xferred = Int_Xferred + 2 - - DO i3 = LBOUND(InData%BlFB,3), UBOUND(InData%BlFB,3) - DO i2 = LBOUND(InData%BlFB,2), UBOUND(InData%BlFB,2) - DO i1 = LBOUND(InData%BlFB,1), UBOUND(InData%BlFB,1) - ReKiBuf(Re_Xferred) = InData%BlFB(i1,i2,i3) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - IF ( .NOT. ALLOCATED(InData%BlMB) ) THEN - IntKiBuf( Int_Xferred ) = 0 - Int_Xferred = Int_Xferred + 1 - ELSE - IntKiBuf( Int_Xferred ) = 1 - Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlMB,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlMB,1) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlMB,2) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlMB,2) - Int_Xferred = Int_Xferred + 2 - IntKiBuf( Int_Xferred ) = LBOUND(InData%BlMB,3) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%BlMB,3) - Int_Xferred = Int_Xferred + 2 - - DO i3 = LBOUND(InData%BlMB,3), UBOUND(InData%BlMB,3) - DO i2 = LBOUND(InData%BlMB,2), UBOUND(InData%BlMB,2) - DO i1 = LBOUND(InData%BlMB,1), UBOUND(InData%BlMB,1) - ReKiBuf(Re_Xferred) = InData%BlMB(i1,i2,i3) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF IF ( .NOT. ALLOCATED(InData%TwrFB) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -11481,6 +11488,39 @@ SUBROUTINE AD_UnPackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat END DO END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! R_li not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i4_l = IntKiBuf( Int_Xferred ) + i4_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%R_li)) DEALLOCATE(OutData%R_li) + ALLOCATE(OutData%R_li(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u,i4_l:i4_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%R_li.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i4 = LBOUND(OutData%R_li,4), UBOUND(OutData%R_li,4) + DO i3 = LBOUND(OutData%R_li,3), UBOUND(OutData%R_li,3) + DO i2 = LBOUND(OutData%R_li,2), UBOUND(OutData%R_li,2) + DO i1 = LBOUND(OutData%R_li,1), UBOUND(OutData%R_li,1) + OutData%R_li(i1,i2,i3,i4) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 + END DO + END DO + END DO + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! AllOuts not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -11759,6 +11799,34 @@ SUBROUTINE AD_UnPackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat Re_Xferred = Re_Xferred + 1 END DO END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Vind_i not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i3_l = IntKiBuf( Int_Xferred ) + i3_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%Vind_i)) DEALLOCATE(OutData%Vind_i) + ALLOCATE(OutData%Vind_i(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vind_i.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i3 = LBOUND(OutData%Vind_i,3), UBOUND(OutData%Vind_i,3) + DO i2 = LBOUND(OutData%Vind_i,2), UBOUND(OutData%Vind_i,2) + DO i1 = LBOUND(OutData%Vind_i,1), UBOUND(OutData%Vind_i,1) + OutData%Vind_i(i1,i2,i3) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END DO END IF i1_l = LBOUND(OutData%V_DiskAvg,1) i1_u = UBOUND(OutData%V_DiskAvg,1) @@ -11955,62 +12023,6 @@ SUBROUTINE AD_UnPackRotMiscVarType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat END DO END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BlFB not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%BlFB)) DEALLOCATE(OutData%BlFB) - ALLOCATE(OutData%BlFB(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlFB.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i3 = LBOUND(OutData%BlFB,3), UBOUND(OutData%BlFB,3) - DO i2 = LBOUND(OutData%BlFB,2), UBOUND(OutData%BlFB,2) - DO i1 = LBOUND(OutData%BlFB,1), UBOUND(OutData%BlFB,1) - OutData%BlFB(i1,i2,i3) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! BlMB not allocated - Int_Xferred = Int_Xferred + 1 - ELSE - Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i2_l = IntKiBuf( Int_Xferred ) - i2_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - i3_l = IntKiBuf( Int_Xferred ) - i3_u = IntKiBuf( Int_Xferred + 1) - Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%BlMB)) DEALLOCATE(OutData%BlMB) - ALLOCATE(OutData%BlMB(i1_l:i1_u,i2_l:i2_u,i3_l:i3_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlMB.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i3 = LBOUND(OutData%BlMB,3), UBOUND(OutData%BlMB,3) - DO i2 = LBOUND(OutData%BlMB,2), UBOUND(OutData%BlMB,2) - DO i1 = LBOUND(OutData%BlMB,1), UBOUND(OutData%BlMB,1) - OutData%BlMB(i1,i2,i3) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 - END DO - END DO - END DO - END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! TwrFB not allocated Int_Xferred = Int_Xferred + 1 ELSE diff --git a/modules/aerodyn/src/BEMT.f90 b/modules/aerodyn/src/BEMT.f90 index d62b855be5..33fe5d2821 100644 --- a/modules/aerodyn/src/BEMT.f90 +++ b/modules/aerodyn/src/BEMT.f90 @@ -348,12 +348,12 @@ subroutine BEMT_AllocInput( u, p, errStat, errMsg ) end if u%theta = 0.0_ReKi - allocate ( u%psi( p%numBlades ), STAT = errStat2 ) + allocate ( u%psi_s( p%numBlades ), STAT = errStat2 ) if ( errStat2 /= 0 ) then - call SetErrStat( ErrID_Fatal, 'Error allocating memory for u%psi.', errStat, errMsg, RoutineName ) + call SetErrStat( ErrID_Fatal, 'Error allocating memory for u%psi_s.', errStat, errMsg, RoutineName ) return end if - u%psi = 0.0_ReKi + u%psi_s = 0.0_ReKi allocate ( u%Vx( p%numBladeNodes, p%numBlades ), STAT = errStat2 ) if ( errStat2 /= 0 ) then @@ -459,6 +459,11 @@ subroutine BEMT_AllocOutput( y, p, errStat, errMsg ) call allocAry( y%Re, p%numBladeNodes, p%numBlades, 'y%Re', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( y%axInduction, p%numBladeNodes, p%numBlades, 'y%axInduction', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( y%tanInduction, p%numBladeNodes, p%numBlades, 'y%tanInduction', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call allocAry( y%axInduction_qs, p%numBladeNodes, p%numBlades, 'y%axInduction_qs', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call allocAry( y%tanInduction_qs, p%numBladeNodes, p%numBlades, 'y%tanInduction_qs', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call allocAry( y%F, p%numBladeNodes, p%numBlades, 'y%F', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call allocAry( y%k, p%numBladeNodes, p%numBlades, 'y%k', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call allocAry( y%k_p, p%numBladeNodes, p%numBlades, 'y%k_p', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( y%AOA, p%numBladeNodes, p%numBlades, 'y%AOA', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( y%Cx, p%numBladeNodes, p%numBlades, 'y%Cx', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) call allocAry( y%Cy, p%numBladeNodes, p%numBlades, 'y%Cy', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -489,6 +494,11 @@ subroutine BEMT_AllocOutput( y, p, errStat, errMsg ) y%Re = 0.0_ReKi y%axInduction = 0.0_ReKi y%tanInduction = 0.0_ReKi + y%axInduction_qs = 0.0_ReKi + y%tanInduction_qs = 0.0_ReKi + y%F = 0.0_ReKi + y%k = 0.0_ReKi + y%k_p = 0.0_ReKi y%AOA = 0.0_ReKi y%Cl = 0.0_ReKi y%Cd = 0.0_ReKi @@ -1059,7 +1069,7 @@ subroutine GetRTip( u, p, RTip ) end subroutine GetRTip !.................................................................................................................................. -subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction,tanInduction, ErrStat,ErrMsg) +subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction,tanInduction, ErrStat,ErrMsg, k_out, kp_out, F_out) type(BEMT_ParameterType), intent(in ) :: p !< Parameters real(ReKi), intent(in ) :: phi(:,:) !< phi @@ -1070,6 +1080,9 @@ subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction, real(ReKi), intent(inout) :: tanInduction(:,:) !< tangential induction integer(IntKi), intent( out) :: errStat !< Error status of the operation character(*), intent( out) :: errMsg !< Error message if ErrStat /= ErrID_None + real(ReKi), optional, intent(inout) :: k_out(:,:) !< + real(ReKi), optional, intent(inout) :: kp_out(:,:) !< + real(ReKi), optional, intent(inout) :: F_out(:,:) !< hub/tip loss factor integer(IntKi) :: i !< blade node counter integer(IntKi) :: j !< blade counter @@ -1079,6 +1092,7 @@ subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction, integer(IntKi) :: errStat2 !< Error status of the operation character(ErrMsgLen) :: errMsg2 !< Error message if ErrStat /= ErrID_None character(*), parameter :: RoutineName = 'calculate_Inductions_from_BEMT' + real(ReKi) :: kp, k, F !< Optional variables returned by BEM ErrStat = ErrID_None ErrMsg = "" @@ -1091,7 +1105,10 @@ subroutine calculate_Inductions_from_BEMT(p,phi,u,OtherState,AFInfo,axInduction, ! Need to get the induction factors for these conditions without skewed wake correction and without UA ! COMPUTE: axInduction, tanInduction - fzero = BEMTU_InductionWithResidual(p, u, i, j, phi(i,j), AFInfo(p%AFIndx(i,j)), IsValidSolution, ErrStat2, ErrMsg2, a=axInduction(i,j), ap=tanInduction(i,j)) + fzero = BEMTU_InductionWithResidual(p, u, i, j, phi(i,j), AFInfo(p%AFIndx(i,j)), IsValidSolution, ErrStat2, ErrMsg2, a=axInduction(i,j), ap=tanInduction(i,j), kp_out=kp, k_out=k, F_out=F) + if (present(kp_out)) kp_out(i,j) = kp + if (present(k_out)) k_out(i,j) = k + if (present(F_out)) F_out(i,j) = F if (ErrStat2 /= ErrID_None) then call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) @@ -1383,7 +1400,8 @@ subroutine BEMT_InitStates(t, u, p, x, xd, z, OtherState, m, AFInfo, ErrStat, Er end subroutine BEMT_InitStates !---------------------------------------------------------------------------------------------------------------------------------- !> Routine for computing inductions outputs, used in both loose and tight coupling. -subroutine BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, ApplyCorrections, phi, u, p, x, xd, z, OtherState, AFInfo, axInduction, tanInduction, chi, m, errStat, errMsg ) +subroutine BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, ApplyCorrections, phi, u, p, x, xd, z, OtherState, AFInfo, axInduction, tanInduction, chi, m, errStat, errMsg, & + axInduction_qs_out, tanInduction_qs_out, k_out, kp_out, F_out) !.................................................................................................................................. REAL(DbKi), intent(in ) :: t ! current simulation time @@ -1404,6 +1422,11 @@ subroutine BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, Appl REAL(ReKi), intent(inout) :: chi(:,:) ! value used in skewed wake correction integer(IntKi), intent( out) :: errStat ! Error status of the operation character(*), intent( out) :: errMsg ! Error message if ErrStat /= ErrID_None + REAL(ReKi), optional, intent( out) :: axInduction_qs_out(:,:) !Quasi steady axial induction. + REAL(ReKi), optional, intent( out) :: tanInduction_qs_out(:,:) + REAL(ReKi), optional, intent( out) :: k_out(:,:) ! NOTE: if provided, kp_out and F_out should be provided + REAL(ReKi), optional, intent( out) :: kp_out(:,:) + REAL(ReKi), optional, intent( out) :: F_out(:,:) ! Local variables: @@ -1452,9 +1475,17 @@ subroutine BEMT_CalcOutput_Inductions( InputIndex, t, CalculateDBEMTInputs, Appl !............................................ ! get BEMT inductions (axInduction and tanInduction): !............................................ - call calculate_Inductions_from_BEMT(p, phi, u, OtherState, AFInfo, axInduction, tanInduction, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (errStat >= AbortErrLev) return + ! NOTE: we assume that all optional arguments (k/kp/F) are provided or none at all. + if (present(k_out)) then + call calculate_Inductions_from_BEMT(p, phi, u, OtherState, AFInfo, axInduction, tanInduction, ErrStat2, ErrMsg2, k_out, kp_out, F_out) + else + call calculate_Inductions_from_BEMT(p, phi, u, OtherState, AFInfo, axInduction, tanInduction, ErrStat2, ErrMsg2) + endif + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (errStat >= AbortErrLev) return + ! Backup optional variables + if (present(axInduction_qs_out)) axInduction_qs_out = axInduction + if (present(tanInduction_qs_out)) tanInduction_qs_out = tanInduction !............................................ ! apply DBEMT correction to axInduction and tanInduction: @@ -1554,7 +1585,7 @@ subroutine ApplySkewedWakeCorrection_AllNodes(p, u, m, x, phi, OtherState, axInd do i = 1,p%numBladeNodes ! Loop through the blade nodes / elements if ( .not. p%FixedInductions(i,j) ) then F = getHubTipLossCorrection(p%BEM_Mod, p%useHubLoss, p%useTipLoss, p%hubLossConst(i,j), p%tipLossConst(i,j), phi(i,j), u%cantAngle(i,j) ) - call ApplySkewedWakeCorrection( p%BEM_Mod, p%skewWakeMod, p%yawCorrFactor, F, u%psi(j), u%psiSkewOffset, u%chi0, u%rlocal(i,j)/m%Rtip(j), axInduction(i,j), chi(i,j), m%FirstWarn_Skew ) + call ApplySkewedWakeCorrection( p%BEM_Mod, p%skewWakeMod, p%yawCorrFactor, F, u%psi_s(j), u%psiSkewOffset, u%chi0, u%rlocal(i,j)/m%Rtip(j), axInduction(i,j), chi(i,j), m%FirstWarn_Skew ) end if ! .not. p%FixedInductions (special case for tip and/or hub loss) enddo ! I - Blade nodes / elements enddo ! J - All blades @@ -2395,7 +2426,7 @@ subroutine WriteDEBUGValuesToFile(t, u, p, x, xd, z, OtherState, m, AFInfo) , z%phi( DEBUG_BLADENODE,DEBUG_BLADE)*R2D & ! remember this does not have any corrections , u%chi0, u%omega, u%Un_disk, u%TSR & , u%theta( DEBUG_BLADENODE,DEBUG_BLADE) & - , u%psi( DEBUG_BLADE) & + , u%psi_s( DEBUG_BLADE) & , u%Vx( DEBUG_BLADENODE,DEBUG_BLADE) & , u%Vy( DEBUG_BLADENODE,DEBUG_BLADE) & , u%Vz( DEBUG_BLADENODE,DEBUG_BLADE) & diff --git a/modules/aerodyn/src/BEMTUncoupled.f90 b/modules/aerodyn/src/BEMTUncoupled.f90 index 5d4b9a34fe..e8f65c6961 100644 --- a/modules/aerodyn/src/BEMTUncoupled.f90 +++ b/modules/aerodyn/src/BEMTUncoupled.f90 @@ -63,15 +63,9 @@ module BEMTUnCoupled !.................................................................................................................................. function VelocityIsZero ( v ) - - ! passed variables - REAL(ReKi), INTENT(IN ) :: v !< the velocity that needs to be compared with zero - LOGICAL :: VelocityIsZero !< .true. if and only if the velocity is (almost) equal to zero - - - + VelocityIsZero = abs(v) < 0.001_ReKi ! tolerance in m/s for what we consider zero velocity for BEM computations end function VelocityIsZero @@ -135,7 +129,7 @@ subroutine GetRelativeVelocity( axInduction, tanInduction, Vx, Vy, cantAngle, xV end subroutine GetRelativeVelocity !.................................................................................................................................. -!> getAirfoilOrientation = R_ap = transformation from from polar coordinate system of the section to the airfoil coordinate system +!> getAirfoilOrientation = R_al = transformation from from local-polar coordinate system of the section to the airfoil coordinate system subroutine getAirfoilOrientation( theta, cantAngle, toeAngle, afAxialVec, afNormalVec, afRadialVec ) ! Routine for creating the airfoil orientation vectors @@ -153,7 +147,7 @@ subroutine getAirfoilOrientation( theta, cantAngle, toeAngle, afAxialVec, afNorm orientation(1) = toeAngle orientation(2) = cantAngle orientation(3) = -theta - rotMat = EulerConstruct( orientation ) ! = R_ap: from polar to airfoil + rotMat = EulerConstruct( orientation ) ! = R_al: from local-polar to airfoil ! unit vector normal to the chord line in the airfoil plane afNormalVec = rotMat(1,:) @@ -167,7 +161,7 @@ subroutine getAirfoilOrientation( theta, cantAngle, toeAngle, afAxialVec, afNorm end subroutine getAirfoilOrientation !.................................................................................................................................. -!> getAirfoilOrientation = R_ap = transformation from from polar coordinate system of the section to the airfoil coordinate system +!> getAirfoilOrientation = R_al = transformation from from local-polar coordinate system of the section to the airfoil coordinate system subroutine getAirfoilOrientationMatrix( theta, cantAngle, toeAngle, rotMat) ! Routine for creating the airfoil orientation vectors @@ -182,7 +176,7 @@ subroutine getAirfoilOrientationMatrix( theta, cantAngle, toeAngle, rotMat) orientation(1) = toeAngle orientation(2) = cantAngle orientation(3) = -theta - rotMat = EulerConstruct( orientation ) ! = R_ap: from polar to airfoil + rotMat = EulerConstruct( orientation ) ! = R_al: from local-polar to airfoil end subroutine getAirfoilOrientationMatrix !.................................................................................................................................. subroutine computeAirfoilOperatingAOA( BEM_Mod, phi, theta, cantAngle, toeAngle, AoA ) @@ -234,6 +228,9 @@ subroutine computeAirfoilOperatingAOA( BEM_Mod, phi, theta, cantAngle, toeAngle, end subroutine computeAirfoilOperatingAOA !.................................................................................................................................. +!> Transform the aerodynamic coefficients (Cl,Cd,Cm) (directed based on Vrel_xy_a ) +!! from the airfoil coordinate system (a) to the without sweep pitch coordinate system (w) +!! NOTE: "Cy" is currently "-Cyw" subroutine Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, Cl, Cd, Cx, Cy ) real(ReKi), intent(in ) :: phi logical, intent(in ) :: useAIDrag @@ -249,12 +246,14 @@ subroutine Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, Cl, Cd, Cx, Cy ) sphi = sin(phi) ! resolve into normal (x) and tangential (y) forces + ! Cx = Cxw if ( useAIDrag ) then Cx = Cl*cphi + Cd*sphi else Cx = Cl*cphi end if + ! Cy = -Cyw if ( useTIDrag ) then Cy = Cl*sphi - Cd*cphi else @@ -263,6 +262,9 @@ subroutine Transform_ClCd_to_CxCy( phi, useAIDrag, useTIDrag, Cl, Cd, Cx, Cy ) end subroutine Transform_ClCd_to_CxCy !---------------------------------------------------------------------------------------------------------------------------------- +!> Transform the aerodynamic coefficients (Cl,Cd,Cm) (directed based on Vrel_xy_a ) +!! from the airfoil coordinate system (a) to the local-polar coordinate system (l) +!! NOTE: "Cy" is currently "-Cyl" subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz( phi, theta, cant,toeAngle ,useAIDrag, useTIDrag, AOA, Cl, Cd, Cm, Cx, Cy, Cz, Cmx, Cmy, Cmz ) implicit none @@ -279,9 +281,9 @@ subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz( phi, theta, cant,toeAngle ,useAI real(ReKi), intent(in ) :: Cm real(ReKi), intent( out) :: Cx, Cy, Cz real(ReKi), intent( out) :: Cmx, Cmy, Cmz - real(ReKi) :: afAxialVec(3) - real(ReKi) :: afNormalVec(3) - real(ReKi) :: afRadialVec(3) + real(ReKi) :: afAxialVec(3) !xhat_a_in_l + real(ReKi) :: afNormalVec(3) !yhat_a_in_l + real(ReKi) :: afRadialVec(3) !zhat_a_in_l real(ReKi) :: coeffVec(3) real(ReKi) :: Cn real(ReKi) :: Ct @@ -290,11 +292,13 @@ subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz( phi, theta, cant,toeAngle ,useAI call getAirfoilOrientation( theta, cant, toeAngle, afAxialVec, afNormalVec, afRadialVec ) ! transform force coefficients into airfoil frame + ! Cn = Cxa if ( useAIDrag ) then Cn = Cl*cos(AOA) + Cd*sin(AOA) else Cn = Cl*cos(AOA) end if + ! Ct = Cya if ( useTIDrag ) then Ct = -Cl*sin(AOA) + Cd*cos(AOA) else @@ -303,9 +307,9 @@ subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz( phi, theta, cant,toeAngle ,useAI ! Put force coefficients back into rotor plane reference frame coeffVec = Cn*afNormalVec + Ct*afAxialVec - Cx = coeffVec(1) - Cy = -coeffVec(2) - Cz = coeffVec(3) + Cx = coeffVec(1) ! Cxl and cn + Cy = -coeffVec(2) ! -Cyl ct + Cz = coeffVec(3) ! Czl ! Put moment coefficients into the rotor reference frame coeffVec = Cm * afRadialVec @@ -315,7 +319,7 @@ subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz( phi, theta, cant,toeAngle ,useAI end subroutine Transform_ClCdCm_to_CxCyCzCmxCmyCmz !---------------------------------------------------------------------------------------------------------------------------------- !>This is the residual calculation for the uncoupled BEM solve -real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValidSolution, ErrStat, ErrMsg, a, ap, k, kp, Cx_out, Cy_out ) result (ResidualVal) +real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValidSolution, ErrStat, ErrMsg, a, ap, k_out, kp_out, F_out, Cx_out, Cy_out ) result (ResidualVal) type(BEMT_ParameterType),intent(in ) :: p !< parameters @@ -330,8 +334,10 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None real(ReKi), optional, intent( out) :: a ! computed axial induction real(ReKi), optional, intent( out) :: ap ! computed tangential induction - real(ReKi), optional, intent( out) :: k ! k in the induction factors routine - real(ReKi), optional, intent( out) :: kp ! kp in the induction factors routine + real(ReKi), optional, intent( out) :: k_out ! k in the induction factors routine + real(ReKi), optional, intent( out) :: kp_out ! kp in the induction factors routine + real(ReKi), optional, intent( out) :: F_out ! Tip/hub loss factor + real(ReKi), optional, intent( out) :: Cx_out, Cy_out !< cn and ct ! Local variables @@ -344,11 +350,12 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid real(ReKi) :: axInduction real(ReKi) :: tanInduction - real(ReKi) :: F ! tip/hub loss factor + real(ReKi) :: F !< tip/hub loss factor real(ReKi) :: Re - real(ReKi) :: Cx, Cy, Cz - real(ReKi), optional, intent( out) :: Cx_out, Cy_out - real(ReKi) :: dumX,dumY,dumZ, k_out, kp_out + real(ReKi) :: Cx !< Projected airfoil coefficient used in BET, cn + real(ReKi) :: Cy !< Projected airfoil coefficient used in BET, ct + real(ReKi) :: Cz + real(ReKi) :: dumX,dumY,dumZ, k, kp TYPE(AFI_OutputType) :: AFI_interp ErrStat = ErrID_None @@ -356,8 +363,12 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid ResidualVal = 0.0_ReKi IsValidSolution = .true. - k_out = 0 - kp_out = 0 + ! Optional outputs + F = 1._ReKi + k = 0._ReKi + kp = 0._ReKi + Cx = 0._ReKi + Cy = 0._ReKi ! make these return values consistent with what is returned in inductionFactors routine: ! Set the local version of the induction factors @@ -382,6 +393,8 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid if (ErrStat >= AbortErrLev) return ! Compute Cx, Cy given Cl, Cd and phi, we honor the useAIDrag and useTIDrag flag because Cx,Cy are only used for the solution of inductions + ! BEMMod_2D: Cx = Cxw and Cy = - Cyw + ! BEMMod_3D: Cx = cn = Cxp and Cy = ct =-Cyp if(p%BEM_Mod==BEMMod_2D) then call Transform_ClCd_to_CxCy( phi, p%useAIDrag, p%useTIDrag, AFI_interp%Cl, AFI_interp%Cd, Cx, Cy ) else @@ -401,10 +414,10 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid ! Determine axInduction, tanInduction for the current Cl, Cd, phi if(p%BEM_Mod==BEMMod_2D) then call inductionFactors0(p%numBlades, u%rlocal(i,j), p%chord(i,j), phi, Cx, Cy, u%Vx(i,j), u%Vy(i,j), F, p%useTanInd, & - ResidualVal, axInduction, tanInduction, IsValidSolution) + ResidualVal, axInduction, tanInduction, IsValidSolution, k, kp) else call inductionFactors2(p%BEM_Mod, p%numBlades, u%rlocal(i,j), p%chord(i,j), phi, Cx, Cy, u%Vx(i,j), u%Vy(i,j), u%drdz(i,j), u%cantAngle(i,j), F, u%CHI0, p%useTanInd, & - ResidualVal, axInduction, tanInduction, p%MomentumCorr, u%xVelCorr(i,j), IsValidSolution, k_out, kp_out ) + ResidualVal, axInduction, tanInduction, p%MomentumCorr, u%xVelCorr(i,j), IsValidSolution, k, kp ) endif @@ -412,10 +425,11 @@ real(ReKi) function BEMTU_InductionWithResidual(p, u, i, j, phi, AFInfo, IsValid if (present(a )) a = axInduction if (present(ap)) ap = tanInduction - if (present(k )) k = k_out - if (present(kp)) kp = kp_out + if (present(k_out )) k_out = k + if (present(kp_out)) kp_out = kp if (present(Cx_out)) Cx_out = Cx if (present(Cy_out)) Cy_out = Cy + if (present(F_out)) F_out = F end function BEMTU_InductionWithResidual !----------------------------------------------------------------------------------------- @@ -439,14 +453,12 @@ subroutine ApplySkewedWakeCorrection(BEM_Mod, SkewMod, yawCorrFactor, F, azimuth ! Skewed wake correction - IF (.true.) then - if(BEM_Mod==BEMMod_2D) then - chi = (0.6_ReKi*a + 1.0_ReKi)*chi0 - else - chi = (0.6_ReKi*a + 1.0_ReKi)*abs(chi0) - endif - END IF - + if(BEM_Mod==BEMMod_2D) then + chi = (0.6_ReKi*a + 1.0_ReKi)*chi0 + else + chi = (0.6_ReKi*a + 1.0_ReKi)*abs(chi0) + endif + call MPi2Pi( chi ) ! make sure chi is in [-pi, pi] before testing if it's outside a valid range if (abs(chi) > piBy2) then @@ -473,7 +485,7 @@ end subroutine ApplySkewedWakeCorrection !----------------------------------------------------------------------------------------- !> This subroutine computes the induction factors (a) and (ap) along with the residual (fzero) subroutine inductionFactors0(B, r, chord, phi, cn, ct, Vx, Vy, F, wakerotation, & - fzero, a_out, ap_out, IsValidSolution) + fzero, a_out, ap_out, IsValidSolution, k_out, kp_out) implicit none @@ -494,6 +506,8 @@ subroutine inductionFactors0(B, r, chord, phi, cn, ct, Vx, Vy, F, wakerotation, real(ReKi), intent(out) :: a_out !< axial induction [y%axInduction] real(ReKi), intent(out) :: ap_out !< tangential induction, i.e., a-prime [y%tanInduction] logical, intent(out) :: IsValidSolution !< this is set to false if k<=1 in the propeller brake region or k<-1 in the momentum region, indicating an invalid solution + real(ReKi), intent(out) :: k_out + real(ReKi), intent(out) :: kp_out ! local @@ -621,14 +635,14 @@ subroutine inductionFactors0(B, r, chord, phi, cn, ct, Vx, Vy, F, wakerotation, ap_out = real( ap, ReKi ) end subroutine inductionFactors0 -subroutine getTangentialInduction(a, cphi, sphi, Vx, F, kCorrectionFactor, sigma_p, ct, VxCorrected, effectiveYaw, H, MomentumCorr, ap, kp) +subroutine getTangentialInduction(a, cphi, sphi, Vx, F, kpCorrectionFactor, sigma_p, ct, VxCorrected, effectiveYaw, H, MomentumCorr, ap, kp) real(ReKi), intent(in) :: Vx !< velocity component [u%Vx] real(ReKi), intent(in) :: F !< hub/tip loss correction factor logical, intent(in) :: MomentumCorr !< Include tangential induction in BEMT calculations [flag] [p%useTanInd] real(ReKi), intent(in) :: ct !< tangential force coefficient (tangential to the plane, not chord) of the jth node in the kth blade; [y%cy] real(R8Ki), intent(in) :: sigma_p ! local solidity (B*chord/(TwoPi*r)) real(R8Ki), intent(in) :: sphi, cphi ! sin(phi), cos(phi) - real(R8Ki), intent(in) :: VxCorrected, kCorrectionFactor + real(R8Ki), intent(in) :: VxCorrected, kpCorrectionFactor real(R8Ki), intent(in) :: effectiveYaw ! real(R8Ki), intent(in) :: H ! scaling factor to gradually phase out tangential induction when axial induction is near 1.0 real(R8Ki), intent(in) :: a ! double precision versions of output variables of similar name @@ -644,15 +658,15 @@ subroutine getTangentialInduction(a, cphi, sphi, Vx, F, kCorrectionFactor, sigma else !H = smoothStep( real(a,ReKi), 0.8, 1.0, 1.0, 0.0 ) + smoothStep( real(a,ReKi), 1.0, 0.0, 1.2, 1.0 ) - !kp = sigma_p*( cl*sphi - H*cd*cphi )/( 4.0*F*sphi*cphi )*kCorrectionFactor + !kp = sigma_p*( cl*sphi - H*cd*cphi )/( 4.0*F*sphi*cphi )*kpCorrectionFactor if (MomentumCorr) then if (equalrealnos(a,1.0_R8Ki)) then - kp = 0.0_R8Ki !H*sigma_p*ct/( 4.0*F*sphi*cphi )*(kCorrectionFactor) + kp = 0.0_R8Ki !H*sigma_p*ct/( 4.0*F*sphi*cphi )*(kpCorrectionFactor) else - kp = H*sigma_p*ct/( 4.0*F*sphi*cphi )*(kCorrectionFactor)/sqrt(1+(tan(effectiveYaw)/(1.0_ReKi-a))**2) + kp = H*sigma_p*ct/( 4.0*F*sphi*cphi )*(kpCorrectionFactor)/sqrt(1+(tan(effectiveYaw)/(1.0_ReKi-a))**2) endif else - kp = H*sigma_p*ct/( 4.0*F*sphi*cphi )*kCorrectionFactor + kp = H*sigma_p*ct/( 4.0*F*sphi*cphi )*kpCorrectionFactor endif if ( VxCorrected < 0.0_ReKi ) then @@ -705,11 +719,12 @@ subroutine inductionFactors2( BEM_Mod, B, r, chord, phi, cn, ct, Vx, Vy, drdz,ca real(R8Ki) :: sigma_p ! local solidity (B*chord/(TwoPi*r)) real(R8Ki) :: sphi, cphi ! sin(phi), cos(phi) real(R8Ki) :: k, kp ! non-dimensional parameters - real(R8Ki) :: VxCorrected, kCorrectionFactor + real(R8Ki) :: VxCorrected, kCorrectionFactor, kpCorrectionFactor real(R8Ki) :: effectiveYaw ! real(R8Ki) :: k0 + real(R8Ki) :: ac !< Critical axial induction factor value above which the high thrust correction is used real(R8Ki) :: H ! scaling factor to gradually phase out tangential induction when axial induction is near 1.0 real(R8Ki) :: fzero, a, ap ! double precision versions of output variables of similar name @@ -741,10 +756,12 @@ subroutine inductionFactors2( BEM_Mod, B, r, chord, phi, cn, ct, Vx, Vy, drdz,ca ! "corrections" VxCorrected = Vx*cos(cantAngle)+xVelCorr kCorrectionFactor = 1.0_R8Ki + xVelCorr/(Vx*cos(real(cantAngle,R8Ki))) + kpCorrectionFactor = kCorrectionFactor k = k*kCorrectionFactor**2 - !k = sign( k, real(phi,R8Ki) ) - k0 = a0(effectiveYaw) / (1.0-a0(effectiveYaw)) + + ac = ac_val(effectiveYaw) + k0 = ac / (1.0_R8Ki-ac) if (.not.MomentumCorr) then if (k <= k0 ) then if (VxCorrected > 0.0) then @@ -754,10 +771,11 @@ subroutine inductionFactors2( BEM_Mod, B, r, chord, phi, cn, ct, Vx, Vy, drdz,ca end if H = 1.0_R8Ki else - call axialInductionFromEmpiricalThrust( effectiveYaw, phi, k, F, a, H, MomentumCorr ) + call axialInductionFromEmpiricalThrust( effectiveYaw, phi, k, F, a, H, skewConvention=MomentumCorr, quarticVersion=MomentumCorr ) endif else - call axialInductionFromGlauertMomentum(effectiveYaw, phi, k, F, a, H, MomentumCorr) + ! --- Using convention of axial induction where "a" is "an" (Wn = -an Un) + call axialInductionFromGlauertMomentum(effectiveYaw, phi, k, F, a, H) a = sign(a,k) endif @@ -766,7 +784,7 @@ subroutine inductionFactors2( BEM_Mod, B, r, chord, phi, cn, ct, Vx, Vy, drdz,ca ! compute tangential induction factor: !..................................................... if (wakerotation) then - call getTangentialInduction(a, cphi, sphi, Vx, F, kCorrectionFactor, sigma_p, ct, VxCorrected, effectiveYaw, H, MomentumCorr, ap, kp) + call getTangentialInduction(a, cphi, sphi, Vx, F, kpCorrectionFactor, sigma_p, ct, VxCorrected, effectiveYaw, H, MomentumCorr, ap, kp) else ! we're not computing tangential induction: @@ -800,21 +818,43 @@ subroutine inductionFactors2( BEM_Mod, B, r, chord, phi, cn, ct, Vx, Vy, drdz,ca end subroutine inductionFactors2 -real(R8Ki) function a0(chi0) +!> Return critical value above which the high thrust correction is applied +!! Note: since we use the convention for a such that "Wn =- an Un" (and not Wn = - a0 U0) +!! Then an = a0/cos(chi) +real(R8Ki) function ac_val(chi) implicit none - real(R8Ki), intent(in) :: chi0 - a0 = 0.5*cos(45.0*D2R)/cos(chi0) - a0 = min( a0, 0.5_R8Ki ) -end function a0 + real(R8Ki), intent(in) :: chi + ac_val = 0.35/cos(chi) ! See e.g. Spera + ! NOTE: since we use continuation at a=1, we want ac_val to remain far away from 1, so we clip it + ac_val = min( ac_val, 0.5_R8Ki ) +end function ac_val !----------------------------------------------------------------------------------------- -subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentumCorr ) +!> Solve for `a` by equating thrust between +!! - blade element theory (BET) and +!! - an empirical-hight-thrust (HT) function. +!! +!! Assumes that the HT CT is a second order polynomial. +!! BET = HT +!! CT = 4kF (1-a^2) = c2 a^2 + c1 a + c0 (CT defined using Vxp) (1) +!! +!! Two methods of solutions are used: +!! +!! - Equate them and solve for a: +!! (A-c2)a^2 - (2A +c1) a + (1-c0) =0 with A = 4kf (2) +!! +!! - Square (2) and solve for a in the following quartic equation: +!! (A^2-c_2^2)a^4 + (-4A^2 - 2c_1 c_2) a^3 + (6A^2 - 2c_0 c_2 - c_1^2)a^2 + (-4A^2 -2c_0 c_1) a + (A^2-c_0^2) = 0 (3) +!! +!! T +subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, quarticVersion, skewConvention ) implicit none real(R8Ki), intent(in) :: chi0 real(ReKi), intent(in) :: phi real(R8Ki), intent(in) :: k real(ReKi), intent(in) :: F - logical, intent(in) :: momentumCorr + logical, intent(in) :: skewConvention !< If True, assumes that "a" is "an" (Wn=-an Un) and use Glauert skew momentum. Otherwise "a" is "a0" (Wn = -a0 U0) + logical, intent(in) :: quarticVersion !< If True, solves for the quartic version real(R8Ki), intent(out) :: axInd real(R8Ki), intent(out) :: H @@ -825,11 +865,11 @@ subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentu complex(R8Ki) :: roots(4) real(R8Ki) :: tan_chi0 ! Get Coefficients for Empirical CT - call getEmpiricalCoefficients( chi0 ,F , c0, c1, c2,momentumCorr ) + call getEmpiricalCoefficients( chi0 ,F , c0, c1, c2, skewConvention ) ! Solve for axial induction A = 4.0*F*k - if (.NOT.momentumCorr) then + if (.not.quarticVersion) then y1 = 2.0*A + c1 y2 = 4.0*A*(c2+c1+c0) + c1*c1 - 4.0*c0*c2 y3 = 2.0*(A-c2) @@ -843,7 +883,7 @@ subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentu end if end if - if ((axInd>a0(chi0)).AND.(axInd<=1.0)) then + if ((axInd>ac_val(chi0)).AND.(axInd<=1.0)) then H = (4.0*axInd*(1.0-axInd)*F)/(c0+c1*axInd+c2*axInd*axInd) elseif (axInd>1.0) then H = (-4.0*axInd*(1.0-axInd)*F)/(c0+c1*axInd+c2*axInd*axInd) @@ -877,7 +917,7 @@ subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentu if (equalrealnos(axInd,1.0_R8Ki)) then H = 0 - elseif ((axInd>a0(chi0)).AND.(axInd<=1.0)) then + elseif ((axInd>ac_val(chi0)).AND.(axInd<=1.0)) then H = 4.0_R8Ki*axInd*(1.0_R8Ki-axInd)*F*sqrt(1 + (tan_chi0/(1.0_R8Ki-axInd)*F)**2)/sqrt((c0+c1*axInd+c2*axInd*axInd)**2 + (4.0_R8Ki*axInd*tan_chi0)**2) ! Alternatively following implemention can be used but it keeps H from approaching zero as a -> 1 !H = (4.0_R8Ki*axInd*sqrt(((1.0_R8Ki-axInd)*F)**2 + tan(chi0)**2))/sqrt((c0+c1*axInd+c2*axInd*axInd)**2 + (4.0_R8Ki*axInd*tan(chi0))**2) @@ -895,92 +935,134 @@ subroutine axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentu end subroutine axialInductionFromEmpiricalThrust -subroutine axialInductionFromGlauertMomentum(chi0, phi, k, F, axInd, H,momentumCorr) - ! axialInductionFromGlauertMomentum calculates axial induction using Glauert Momentum Theory - implicit none - real(R8Ki), intent(in) :: chi0 - real(R8Ki), intent(in) :: k - real(ReKi), intent(in) :: F - real(ReKi), intent(in) :: phi - logical, intent(in) :: momentumCorr - real(R8Ki), intent(out):: axInd - real(R8Ki), intent(out):: H - real(R8Ki) :: c11, c12, coeffs(5), previousRoot - complex(R8Ki) :: roots(4) - real(R8Ki) :: a0_local - real(R8Ki) :: c2, c1, c0 ! Empirical CT = c2*a^2 + c1*a + c0 for a > a0 - real(R8Ki) :: k0 - real(R8Ki) :: tan_chi0 - - ! Get Coefficients for Empirical CT - call getEmpiricalCoefficients( chi0, F, c0, c1, c2,momentumCorr) - - a0_local = a0(chi0) - k0 = a0_local / (1.0-a0_local) - - tan_chi0 = min(MaxTanChi0, max(-MaxTanChi0, tan(chi0))) - if (abs(k) <= k0*sqrt(1+(tan_chi0/(1-a0_local))**2)) then - c11 = tan_chi0**2 - c12 = k**2 - coeffs(5) = 1.0_R8Ki-c12 - coeffs(4) = 4.0_R8Ki*c12-2.0_R8Ki - coeffs(3) = 1.0_R8Ki+c11 -6.0_R8Ki*c12 - coeffs(2) = 4.0_R8Ki*c12 - coeffs(1) = -c12 - - call QuarticRoots(coeffs,roots) - call sortRoots(roots) - if (phi >= 0.0) then - if (real(roots(1))<0.0_R8Ki) then - axInd = real(roots(2)) - else - axInd = real(roots(1))!min(real(roots(1)),real(roots(2))) - endif - else - axInd = min(real(roots(1)),real(roots(2))) - endif - - previousRoot = axInd - H = 1.0_R8Ki - else !if (k > k0) then ! High induction/ empirical correction - call axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, momentumCorr ) - endif + +!> Solve for `a` by equating thrust between: +!! - blade element theory (BET) and +!! - momentum theory (MT) function +!! or +!! - a empirical high-thrust (HT) function. +!! +!! At low loading, |k|kc, a hight thrust correction (2nd order polynomial) is used for "MT" +!! +subroutine axialInductionFromGlauertMomentum(chi0, phi, k, F, axInd, H) + implicit none + real(R8Ki), intent(in) :: chi0 + real(R8Ki), intent(in) :: k + real(ReKi), intent(in) :: F + real(ReKi), intent(in) :: phi + real(R8Ki), intent(out):: axInd + real(R8Ki), intent(out):: H + real(R8Ki) :: c11, c12, coeffs(5) + complex(R8Ki) :: roots(4) + real(R8Ki) :: ac !< Critical value of the axial induction above which the high-thrust correction is applied + real(R8Ki) :: kc !< Critical value of the k-factor above which the high-thrust correction is applied + real(R8Ki) :: tan_chi0 + + tan_chi0 = min(MaxTanChi0, max(-MaxTanChi0, tan(chi0))) + ac = ac_val(chi0) + kc = ac / (1.0-ac) *sqrt(1+(tan_chi0/(1-ac))**2) + if (abs(k) <= kc) then + ! Use Glauert Skew Momentum (Equation 1&2), and solve for equation (3) above + c11 = tan_chi0**2 + c12 = k**2 + coeffs(5) = 1.0_R8Ki-c12 + coeffs(4) = 4.0_R8Ki*c12-2.0_R8Ki + coeffs(3) = 1.0_R8Ki+c11 -6.0_R8Ki*c12 + coeffs(2) = 4.0_R8Ki*c12 + coeffs(1) = -c12 + + call QuarticRoots(coeffs,roots) + call sortRoots(roots) + if (phi >= 0.0) then + if (real(roots(1))<0.0_R8Ki) then + ! Will happen when k \in [0,1], we chose the solution of a in [0,1] + axInd = real(roots(2)) + else + axInd = real(roots(1))!min(real(roots(1)),real(roots(2))) + endif + else + axInd = min(real(roots(1)),real(roots(2))) + endif + H = 1.0_R8Ki + else !if (k > kc) then ! High induction/ empirical correction + call axialInductionFromEmpiricalThrust( chi0, phi, k, F, axInd, H, skewConvention=.true., quarticVersion=.true. ) + endif end subroutine axialInductionFromGlauertMomentum -subroutine getEmpiricalCoefficients( chi0, F, c0, c1, c2, MomentumCorr ) +!> Compute the coefficients of a second order polynomial that extends the Momenutm relationship CT(a) +!! above a value a>ac. The continuation is done such that the slope and value at a=a_c match +!! the momentum relation. The last constraint is the value of CT at a=1. +!! Currently a hard-coded model is used for the value at at=1. +!! The polynomial is: +!! CT(a) = c0 + c1*a + c2*a2 a>ac +!! obtained with the constraints: +!! CT(a_c) = CT_c +!! CT(1) = CT_1 +!! dCT/da(a_c) = s_c +subroutine getEmpiricalCoefficients( chi0, F, c0, c1, c2, skewConvention ) real(R8Ki), intent(in) :: chi0 real(ReKi), intent(in) :: F - logical, intent(in) :: MomentumCorr + logical, intent(in) :: skewConvention !< If True, assumes that "a" is "an" (Wn=-an Un) and use Glauert Skew Momentum. Otherwise "a" is "a0" (Wn = -a0 U0) real(R8Ki), intent(inout) :: c0, c1, c2 ! Empirical CT = c2*a^2 + c1*a + c0 for a > a0 - real(R8Ki) :: a0_local - real(R8Ki) :: CTata1 - real(R8Ki) :: denom, temp1, temp2 + real(R8Ki):: c0b, c1b, c2b ! Empirical CT = c2*a^2 + c1*a + c0 for a > a0 + real(R8Ki) :: ac + real(R8Ki) :: CT_1, CT_c + real(R8Ki) :: s_c !< Slope at a=ac + real(R8Ki) :: denom, tanchi2 ! Empirical CT = 4*a*(1-a)*F = c2*a^2 + c1*a + c0 for a > a0 - ! third Boundary condition (CT@a=1) is based on equations from Bladed. - a0_local = a0(chi0) - denom = (a0_local**2 - 2.0_R8Ki*a0_local + 1.0_R8Ki) - if (MomentumCorr) then - temp2 = (min(MaxTanChi0, max(-MaxTanChi0, tan(chi0))))**2 - temp1 = sqrt((a0_local-1)**2 +temp2) - - CTata1 = sqrt(((-0.64755/(cos(chi0)*cos(chi0)) - 0.8509/cos(chi0) + 3.4984)*F)**2 + 16*temp2) - CTata1 = max( 1.0_R8Ki, CTata1 ) - - c2 = (CTata1 - 4*F/temp1 + 16*F*a0_local/temp1 - 4*F*a0_local*temp1 - 4*temp2*F/temp1 - 20*F*(a0_local**2)/temp1 + 8*F*(a0_local**3)/temp1 + 4*temp2*F*a0_local/temp1 ) /denom - c1 = 2*( 2*F/temp1 - a0_local*CTata1 - 6*F*a0_local/temp1 + 2*temp2*F/temp1 + 2*F*(a0_local**2)/temp1 + 4*F*(a0_local**2)*temp1 + 6*F*(a0_local**3)/temp1 - 4*F*(a0_local**4)/temp1 - 2*temp2*F*(a0_local**2)/temp1 )/denom - c0 = a0_local*( a0_local*CTata1 - 4*F/temp1 + 4*F*temp1 + 16*F*a0_local/temp1 - 8*F*a0_local*temp1 - 4*temp2*F/temp1 - 20*F*(a0_local**2)/temp1 + 8*F*(a0_local**3)/temp1 + 4*temp2*F*a0_local/temp1 )/denom - + ac = ac_val(chi0) ! critical value above which we extent momentum theory with a 2nd order polynomial + if (skewConvention) then + ! Continuation of Glauert Skew Momentum CT= 4 a F sqrt( (1-a)^2 + tan(chi)^2 ) + ! Using a second + tanchi2 = (min(MaxTanChi0, max(-MaxTanChi0, tan(chi0))))**2 + CT_c = 4._R8Ki*F*ac * sqrt( (1._R8Ki-ac)**2 + tanchi2 ) ! CT(ac) + s_c = 4._R8Ki*F*(1._R8Ki-3*ac+2._R8Ki*ac**2+tanchi2)/sqrt( (1-ac)**2 + tanchi2 ) ! dCT/da(ac) (slope) + ! Note: model below may change + CT_1 = 2.0_R8Ki + 2.113_R8Ki*tanchi2**0.7635 ! CT(1) + CT_1 = max(CT_1, CT_c + s_c * (1._R8Ki-ac) + 0.001_R8Ki ) ! Make sure c2>0 else - CTata1 = (-0.64755/(cos(chi0)*cos(chi0)) - 0.8509/cos(chi0) + 3.4984)*F - CTata1 = max( 1.0_R8Ki, CTata1 ) - c2 = (-4.0_R8Ki*F*a0_local**2 + 8.0_R8Ki*F*a0_local - 4.0_R8Ki*F + CTata1)/denom - c1 = 2.0_R8Ki*(2.0_R8Ki*F*a0_local**2 - CTata1*a0_local - 4.0_R8Ki*F*a0_local + 2.0_R8Ki*F)/denom - c0 = CTata1*(a0_local**2)/denom + ! Continuation of Glauert Momentum CT= 4 a F (1-a) + CT_c = 4._R8Ki*F*ac * (1._R8Ki-ac) ! CT(ac) + s_c = 4._R8Ki*F*(1._R8Ki-2._R8Ki*ac) ! dCT/da(ac) (slope) + ! Note: model below may change + CT_1 = 2.0_R8Ki ! CT(1) endif - + call secondOrderCoeffC1(ac, s_c, CT_c, CT_1, c0, c1, c2) end subroutine getEmpiricalCoefficients + +!> Compute the polynomial coefficients for a second-order polynomial such that: +!! CT(a) = c0 + c1*a + c2*a2 +!! with the following constraints to make it C1-continuous at a=ac +!! CT(a_c) = CT_c +!! dCT/da(a_c) = s_c +!! and a constraint at a=1 +!! CT(1) = CT_1 +!! The 3 coefficients are entirely determined from the three constraints +subroutine secondOrderCoeffC1(a_c, s_c, CT_c, CT_1, c0, c1,c2) + real(R8Ki), intent(in ) :: a_c !< value of a above which C1-continuation is sought + real(R8Ki), intent(in ) :: s_c !< dCT/da(a_c), slope at a=a_c + real(R8Ki), intent(in ) :: CT_c !< CT(a_c), value at a=a_c + real(R8Ki), intent(in ) :: CT_1 !< CT(1), value at a=1 + real(R8Ki), intent(out) :: c0, c1, c2 !< coefficients of the second order polynomial + real(R8Ki) :: denom + denom = (a_c**2 - 2._R8Ki*a_c + 1.0_R8Ki) + c0 = (CT_1*a_c**2 - 2._R8Ki*CT_c*a_c + CT_c + a_c**2*s_c - a_c*s_c)/denom + c1 = (-2._R8Ki*CT_1*a_c + 2._R8Ki*CT_c*a_c - a_c**2*s_c + s_c)/denom + c2 = (CT_1 - CT_c + a_c*s_c - s_c)/denom +end subroutine secondOrderCoeffC1 + subroutine limitInductionFactors(a,ap) real(ReKi), intent(inout) :: a ! axial induction real(ReKi), intent(inout), optional :: ap ! tangential induction diff --git a/modules/aerodyn/src/BEMT_Registry.txt b/modules/aerodyn/src/BEMT_Registry.txt index cd98adc864..893fc7fdda 100644 --- a/modules/aerodyn/src/BEMT_Registry.txt +++ b/modules/aerodyn/src/BEMT_Registry.txt @@ -173,8 +173,8 @@ typedef ^ ^ IntKi # typedef ^ InputType ReKi theta {:}{:} - - "Twist angle (includes all sources of twist) [Array of size (NumBlNds,numBlades)]" rad typedef ^ ^ ReKi chi0 - - - "Angle between the vector normal to the rotor plane and the wind vector (e.g., the yaw angle in the case of no tilt)" rad -typedef ^ ^ ReKi psiSkewOffset - - - "Azimuth angle offset (relative to 90 deg) of the most downwind blade when chi0 is non-zero" rad -typedef ^ ^ ReKi psi {:} - - "Azimuth angle" rad +typedef ^ ^ ReKi psiSkewOffset - - - "Skew azimuth angle offset (relative to 90 deg) of the most downwind blade when chi0 is non-zero" rad +typedef ^ ^ ReKi psi_s {:} - - "Skew azimuth angle" rad typedef ^ ^ ReKi omega - - - "Angular velocity of rotor" rad/s typedef ^ ^ ReKi TSR - - - "Tip-speed ratio (to check if BEM should be turned off)" - typedef ^ ^ ReKi Vx {:}{:} - - "Local axial velocity at node" m/s @@ -197,6 +197,11 @@ typedef ^ OutputType ReKi typedef ^ ^ ReKi phi {:}{:} - - "angle between the plane of rotation and the direction of the local wind" rad typedef ^ ^ ReKi axInduction {:}{:} - - "axial induction" - typedef ^ ^ ReKi tanInduction {:}{:} - - "tangential induction" - +typedef ^ ^ ReKi axInduction_qs {:}{:} - - "axial induction quasi steady" - +typedef ^ ^ ReKi tanInduction_qs {:}{:} - - "tangential induction quasi steady" - +typedef ^ ^ ReKi k {:}{:} - - "Factor k in blade element theory thrust coefficient" - +typedef ^ ^ ReKi k_p {:}{:} - - "Factor kp in blade element theory torque coefficient" - +typedef ^ ^ ReKi F {:}{:} - - "Tip/hub loss factor" - typedef ^ ^ ReKi Re {:}{:} - - "Reynold's number" - typedef ^ ^ ReKi AOA {:}{:} - - "angle of attack" rad typedef ^ ^ ReKi Cx {:}{:} - - "normal force coefficient (normal to the plane, not chord) of the jth node in the kth blade" - diff --git a/modules/aerodyn/src/BEMT_Types.f90 b/modules/aerodyn/src/BEMT_Types.f90 index afc972c2b4..13536b274c 100644 --- a/modules/aerodyn/src/BEMT_Types.f90 +++ b/modules/aerodyn/src/BEMT_Types.f90 @@ -181,8 +181,8 @@ MODULE BEMT_Types TYPE, PUBLIC :: BEMT_InputType REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: theta !< Twist angle (includes all sources of twist) [Array of size (NumBlNds,numBlades)] [rad] REAL(ReKi) :: chi0 !< Angle between the vector normal to the rotor plane and the wind vector (e.g., the yaw angle in the case of no tilt) [rad] - REAL(ReKi) :: psiSkewOffset !< Azimuth angle offset (relative to 90 deg) of the most downwind blade when chi0 is non-zero [rad] - REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: psi !< Azimuth angle [rad] + REAL(ReKi) :: psiSkewOffset !< Skew azimuth angle offset (relative to 90 deg) of the most downwind blade when chi0 is non-zero [rad] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: psi_s !< Skew azimuth angle [rad] REAL(ReKi) :: omega !< Angular velocity of rotor [rad/s] REAL(ReKi) :: TSR !< Tip-speed ratio (to check if BEM should be turned off) [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vx !< Local axial velocity at node [m/s] @@ -206,6 +206,11 @@ MODULE BEMT_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: phi !< angle between the plane of rotation and the direction of the local wind [rad] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: axInduction !< axial induction [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: tanInduction !< tangential induction [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: axInduction_qs !< axial induction quasi steady [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: tanInduction_qs !< tangential induction quasi steady [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: k !< Factor k in blade element theory thrust coefficient [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: k_p !< Factor kp in blade element theory torque coefficient [-] + REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: F !< Tip/hub loss factor [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Re !< Reynold's number [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: AOA !< angle of attack [rad] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Cx !< normal force coefficient (normal to the plane, not chord) of the jth node in the kth blade [-] @@ -4912,17 +4917,17 @@ SUBROUTINE BEMT_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ENDIF DstInputData%chi0 = SrcInputData%chi0 DstInputData%psiSkewOffset = SrcInputData%psiSkewOffset -IF (ALLOCATED(SrcInputData%psi)) THEN - i1_l = LBOUND(SrcInputData%psi,1) - i1_u = UBOUND(SrcInputData%psi,1) - IF (.NOT. ALLOCATED(DstInputData%psi)) THEN - ALLOCATE(DstInputData%psi(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcInputData%psi_s)) THEN + i1_l = LBOUND(SrcInputData%psi_s,1) + i1_u = UBOUND(SrcInputData%psi_s,1) + IF (.NOT. ALLOCATED(DstInputData%psi_s)) THEN + ALLOCATE(DstInputData%psi_s(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%psi.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%psi_s.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstInputData%psi = SrcInputData%psi + DstInputData%psi_s = SrcInputData%psi_s ENDIF DstInputData%omega = SrcInputData%omega DstInputData%TSR = SrcInputData%TSR @@ -5095,8 +5100,8 @@ SUBROUTINE BEMT_DestroyInput( InputData, ErrStat, ErrMsg, DEALLOCATEpointers ) IF (ALLOCATED(InputData%theta)) THEN DEALLOCATE(InputData%theta) ENDIF -IF (ALLOCATED(InputData%psi)) THEN - DEALLOCATE(InputData%psi) +IF (ALLOCATED(InputData%psi_s)) THEN + DEALLOCATE(InputData%psi_s) ENDIF IF (ALLOCATED(InputData%Vx)) THEN DEALLOCATE(InputData%Vx) @@ -5172,10 +5177,10 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, END IF Re_BufSz = Re_BufSz + 1 ! chi0 Re_BufSz = Re_BufSz + 1 ! psiSkewOffset - Int_BufSz = Int_BufSz + 1 ! psi allocated yes/no - IF ( ALLOCATED(InData%psi) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! psi upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%psi) ! psi + Int_BufSz = Int_BufSz + 1 ! psi_s allocated yes/no + IF ( ALLOCATED(InData%psi_s) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! psi_s upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%psi_s) ! psi_s END IF Re_BufSz = Re_BufSz + 1 ! omega Re_BufSz = Re_BufSz + 1 ! TSR @@ -5283,18 +5288,18 @@ SUBROUTINE BEMT_PackInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%psiSkewOffset Re_Xferred = Re_Xferred + 1 - IF ( .NOT. ALLOCATED(InData%psi) ) THEN + IF ( .NOT. ALLOCATED(InData%psi_s) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - IntKiBuf( Int_Xferred ) = LBOUND(InData%psi,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%psi,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%psi_s,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%psi_s,1) Int_Xferred = Int_Xferred + 2 - DO i1 = LBOUND(InData%psi,1), UBOUND(InData%psi,1) - ReKiBuf(Re_Xferred) = InData%psi(i1) + DO i1 = LBOUND(InData%psi_s,1), UBOUND(InData%psi_s,1) + ReKiBuf(Re_Xferred) = InData%psi_s(i1) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -5569,21 +5574,21 @@ SUBROUTINE BEMT_UnPackInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs Re_Xferred = Re_Xferred + 1 OutData%psiSkewOffset = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! psi not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! psi_s not allocated Int_Xferred = Int_Xferred + 1 ELSE Int_Xferred = Int_Xferred + 1 i1_l = IntKiBuf( Int_Xferred ) i1_u = IntKiBuf( Int_Xferred + 1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%psi)) DEALLOCATE(OutData%psi) - ALLOCATE(OutData%psi(i1_l:i1_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%psi_s)) DEALLOCATE(OutData%psi_s) + ALLOCATE(OutData%psi_s(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%psi.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%psi_s.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%psi,1), UBOUND(OutData%psi,1) - OutData%psi(i1) = ReKiBuf(Re_Xferred) + DO i1 = LBOUND(OutData%psi_s,1), UBOUND(OutData%psi_s,1) + OutData%psi_s(i1) = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -5909,6 +5914,76 @@ SUBROUTINE BEMT_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, Err END IF DstOutputData%tanInduction = SrcOutputData%tanInduction ENDIF +IF (ALLOCATED(SrcOutputData%axInduction_qs)) THEN + i1_l = LBOUND(SrcOutputData%axInduction_qs,1) + i1_u = UBOUND(SrcOutputData%axInduction_qs,1) + i2_l = LBOUND(SrcOutputData%axInduction_qs,2) + i2_u = UBOUND(SrcOutputData%axInduction_qs,2) + IF (.NOT. ALLOCATED(DstOutputData%axInduction_qs)) THEN + ALLOCATE(DstOutputData%axInduction_qs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%axInduction_qs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%axInduction_qs = SrcOutputData%axInduction_qs +ENDIF +IF (ALLOCATED(SrcOutputData%tanInduction_qs)) THEN + i1_l = LBOUND(SrcOutputData%tanInduction_qs,1) + i1_u = UBOUND(SrcOutputData%tanInduction_qs,1) + i2_l = LBOUND(SrcOutputData%tanInduction_qs,2) + i2_u = UBOUND(SrcOutputData%tanInduction_qs,2) + IF (.NOT. ALLOCATED(DstOutputData%tanInduction_qs)) THEN + ALLOCATE(DstOutputData%tanInduction_qs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%tanInduction_qs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%tanInduction_qs = SrcOutputData%tanInduction_qs +ENDIF +IF (ALLOCATED(SrcOutputData%k)) THEN + i1_l = LBOUND(SrcOutputData%k,1) + i1_u = UBOUND(SrcOutputData%k,1) + i2_l = LBOUND(SrcOutputData%k,2) + i2_u = UBOUND(SrcOutputData%k,2) + IF (.NOT. ALLOCATED(DstOutputData%k)) THEN + ALLOCATE(DstOutputData%k(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%k.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%k = SrcOutputData%k +ENDIF +IF (ALLOCATED(SrcOutputData%k_p)) THEN + i1_l = LBOUND(SrcOutputData%k_p,1) + i1_u = UBOUND(SrcOutputData%k_p,1) + i2_l = LBOUND(SrcOutputData%k_p,2) + i2_u = UBOUND(SrcOutputData%k_p,2) + IF (.NOT. ALLOCATED(DstOutputData%k_p)) THEN + ALLOCATE(DstOutputData%k_p(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%k_p.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%k_p = SrcOutputData%k_p +ENDIF +IF (ALLOCATED(SrcOutputData%F)) THEN + i1_l = LBOUND(SrcOutputData%F,1) + i1_u = UBOUND(SrcOutputData%F,1) + i2_l = LBOUND(SrcOutputData%F,2) + i2_u = UBOUND(SrcOutputData%F,2) + IF (.NOT. ALLOCATED(DstOutputData%F)) THEN + ALLOCATE(DstOutputData%F(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%F.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstOutputData%F = SrcOutputData%F +ENDIF IF (ALLOCATED(SrcOutputData%Re)) THEN i1_l = LBOUND(SrcOutputData%Re,1) i1_u = UBOUND(SrcOutputData%Re,1) @@ -6126,6 +6201,21 @@ SUBROUTINE BEMT_DestroyOutput( OutputData, ErrStat, ErrMsg, DEALLOCATEpointers ) IF (ALLOCATED(OutputData%tanInduction)) THEN DEALLOCATE(OutputData%tanInduction) ENDIF +IF (ALLOCATED(OutputData%axInduction_qs)) THEN + DEALLOCATE(OutputData%axInduction_qs) +ENDIF +IF (ALLOCATED(OutputData%tanInduction_qs)) THEN + DEALLOCATE(OutputData%tanInduction_qs) +ENDIF +IF (ALLOCATED(OutputData%k)) THEN + DEALLOCATE(OutputData%k) +ENDIF +IF (ALLOCATED(OutputData%k_p)) THEN + DEALLOCATE(OutputData%k_p) +ENDIF +IF (ALLOCATED(OutputData%F)) THEN + DEALLOCATE(OutputData%F) +ENDIF IF (ALLOCATED(OutputData%Re)) THEN DEALLOCATE(OutputData%Re) ENDIF @@ -6222,6 +6312,31 @@ SUBROUTINE BEMT_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + 2*2 ! tanInduction upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%tanInduction) ! tanInduction END IF + Int_BufSz = Int_BufSz + 1 ! axInduction_qs allocated yes/no + IF ( ALLOCATED(InData%axInduction_qs) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! axInduction_qs upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%axInduction_qs) ! axInduction_qs + END IF + Int_BufSz = Int_BufSz + 1 ! tanInduction_qs allocated yes/no + IF ( ALLOCATED(InData%tanInduction_qs) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! tanInduction_qs upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%tanInduction_qs) ! tanInduction_qs + END IF + Int_BufSz = Int_BufSz + 1 ! k allocated yes/no + IF ( ALLOCATED(InData%k) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! k upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%k) ! k + END IF + Int_BufSz = Int_BufSz + 1 ! k_p allocated yes/no + IF ( ALLOCATED(InData%k_p) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! k_p upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%k_p) ! k_p + END IF + Int_BufSz = Int_BufSz + 1 ! F allocated yes/no + IF ( ALLOCATED(InData%F) ) THEN + Int_BufSz = Int_BufSz + 2*2 ! F upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%F) ! F + END IF Int_BufSz = Int_BufSz + 1 ! Re allocated yes/no IF ( ALLOCATED(InData%Re) ) THEN Int_BufSz = Int_BufSz + 2*2 ! Re upper/lower bounds for each dimension @@ -6394,6 +6509,106 @@ SUBROUTINE BEMT_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, END DO END DO END IF + IF ( .NOT. ALLOCATED(InData%axInduction_qs) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%axInduction_qs,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%axInduction_qs,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%axInduction_qs,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%axInduction_qs,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%axInduction_qs,2), UBOUND(InData%axInduction_qs,2) + DO i1 = LBOUND(InData%axInduction_qs,1), UBOUND(InData%axInduction_qs,1) + ReKiBuf(Re_Xferred) = InData%axInduction_qs(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%tanInduction_qs) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%tanInduction_qs,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%tanInduction_qs,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%tanInduction_qs,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%tanInduction_qs,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%tanInduction_qs,2), UBOUND(InData%tanInduction_qs,2) + DO i1 = LBOUND(InData%tanInduction_qs,1), UBOUND(InData%tanInduction_qs,1) + ReKiBuf(Re_Xferred) = InData%tanInduction_qs(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%k) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%k,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%k,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%k,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%k,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%k,2), UBOUND(InData%k,2) + DO i1 = LBOUND(InData%k,1), UBOUND(InData%k,1) + ReKiBuf(Re_Xferred) = InData%k(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%k_p) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%k_p,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%k_p,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%k_p,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%k_p,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%k_p,2), UBOUND(InData%k_p,2) + DO i1 = LBOUND(InData%k_p,1), UBOUND(InData%k_p,1) + ReKiBuf(Re_Xferred) = InData%k_p(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( .NOT. ALLOCATED(InData%F) ) THEN + IntKiBuf( Int_Xferred ) = 0 + Int_Xferred = Int_Xferred + 1 + ELSE + IntKiBuf( Int_Xferred ) = 1 + Int_Xferred = Int_Xferred + 1 + IntKiBuf( Int_Xferred ) = LBOUND(InData%F,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%F,1) + Int_Xferred = Int_Xferred + 2 + IntKiBuf( Int_Xferred ) = LBOUND(InData%F,2) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%F,2) + Int_Xferred = Int_Xferred + 2 + + DO i2 = LBOUND(InData%F,2), UBOUND(InData%F,2) + DO i1 = LBOUND(InData%F,1), UBOUND(InData%F,1) + ReKiBuf(Re_Xferred) = InData%F(i1,i2) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF IF ( .NOT. ALLOCATED(InData%Re) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -6776,6 +6991,121 @@ SUBROUTINE BEMT_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM END DO END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! axInduction_qs not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%axInduction_qs)) DEALLOCATE(OutData%axInduction_qs) + ALLOCATE(OutData%axInduction_qs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%axInduction_qs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%axInduction_qs,2), UBOUND(OutData%axInduction_qs,2) + DO i1 = LBOUND(OutData%axInduction_qs,1), UBOUND(OutData%axInduction_qs,1) + OutData%axInduction_qs(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! tanInduction_qs not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%tanInduction_qs)) DEALLOCATE(OutData%tanInduction_qs) + ALLOCATE(OutData%tanInduction_qs(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%tanInduction_qs.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%tanInduction_qs,2), UBOUND(OutData%tanInduction_qs,2) + DO i1 = LBOUND(OutData%tanInduction_qs,1), UBOUND(OutData%tanInduction_qs,1) + OutData%tanInduction_qs(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! k not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%k)) DEALLOCATE(OutData%k) + ALLOCATE(OutData%k(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%k.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%k,2), UBOUND(OutData%k,2) + DO i1 = LBOUND(OutData%k,1), UBOUND(OutData%k,1) + OutData%k(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! k_p not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%k_p)) DEALLOCATE(OutData%k_p) + ALLOCATE(OutData%k_p(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%k_p.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%k_p,2), UBOUND(OutData%k_p,2) + DO i1 = LBOUND(OutData%k_p,1), UBOUND(OutData%k_p,1) + OutData%k_p(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! F not allocated + Int_Xferred = Int_Xferred + 1 + ELSE + Int_Xferred = Int_Xferred + 1 + i1_l = IntKiBuf( Int_Xferred ) + i1_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + i2_l = IntKiBuf( Int_Xferred ) + i2_u = IntKiBuf( Int_Xferred + 1) + Int_Xferred = Int_Xferred + 2 + IF (ALLOCATED(OutData%F)) DEALLOCATE(OutData%F) + ALLOCATE(OutData%F(i1_l:i1_u,i2_l:i2_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%F.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i2 = LBOUND(OutData%F,2), UBOUND(OutData%F,2) + DO i1 = LBOUND(OutData%F,1), UBOUND(OutData%F,1) + OutData%F(i1,i2) = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + END DO + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Re not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -7186,10 +7516,10 @@ SUBROUTINE BEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg u_out%chi0 = u1%chi0 + b * ScaleFactor b = -(u1%psiSkewOffset - u2%psiSkewOffset) u_out%psiSkewOffset = u1%psiSkewOffset + b * ScaleFactor -IF (ALLOCATED(u_out%psi) .AND. ALLOCATED(u1%psi)) THEN - DO i1 = LBOUND(u_out%psi,1),UBOUND(u_out%psi,1) - b = -(u1%psi(i1) - u2%psi(i1)) - u_out%psi(i1) = u1%psi(i1) + b * ScaleFactor +IF (ALLOCATED(u_out%psi_s) .AND. ALLOCATED(u1%psi_s)) THEN + DO i1 = LBOUND(u_out%psi_s,1),UBOUND(u_out%psi_s,1) + b = -(u1%psi_s(i1) - u2%psi_s(i1)) + u_out%psi_s(i1) = u1%psi_s(i1) + b * ScaleFactor END DO END IF ! check if allocated b = -(u1%omega - u2%omega) @@ -7360,11 +7690,11 @@ SUBROUTINE BEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er b = (t(3)**2*(u1%psiSkewOffset - u2%psiSkewOffset) + t(2)**2*(-u1%psiSkewOffset + u3%psiSkewOffset))* scaleFactor c = ( (t(2)-t(3))*u1%psiSkewOffset + t(3)*u2%psiSkewOffset - t(2)*u3%psiSkewOffset ) * scaleFactor u_out%psiSkewOffset = u1%psiSkewOffset + b + c * t_out -IF (ALLOCATED(u_out%psi) .AND. ALLOCATED(u1%psi)) THEN - DO i1 = LBOUND(u_out%psi,1),UBOUND(u_out%psi,1) - b = (t(3)**2*(u1%psi(i1) - u2%psi(i1)) + t(2)**2*(-u1%psi(i1) + u3%psi(i1)))* scaleFactor - c = ( (t(2)-t(3))*u1%psi(i1) + t(3)*u2%psi(i1) - t(2)*u3%psi(i1) ) * scaleFactor - u_out%psi(i1) = u1%psi(i1) + b + c * t_out +IF (ALLOCATED(u_out%psi_s) .AND. ALLOCATED(u1%psi_s)) THEN + DO i1 = LBOUND(u_out%psi_s,1),UBOUND(u_out%psi_s,1) + b = (t(3)**2*(u1%psi_s(i1) - u2%psi_s(i1)) + t(2)**2*(-u1%psi_s(i1) + u3%psi_s(i1)))* scaleFactor + c = ( (t(2)-t(3))*u1%psi_s(i1) + t(3)*u2%psi_s(i1) - t(2)*u3%psi_s(i1) ) * scaleFactor + u_out%psi_s(i1) = u1%psi_s(i1) + b + c * t_out END DO END IF ! check if allocated b = (t(3)**2*(u1%omega - u2%omega) + t(2)**2*(-u1%omega + u3%omega))* scaleFactor @@ -7607,6 +7937,46 @@ SUBROUTINE BEMT_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMs END DO END DO END IF ! check if allocated +IF (ALLOCATED(y_out%axInduction_qs) .AND. ALLOCATED(y1%axInduction_qs)) THEN + DO i2 = LBOUND(y_out%axInduction_qs,2),UBOUND(y_out%axInduction_qs,2) + DO i1 = LBOUND(y_out%axInduction_qs,1),UBOUND(y_out%axInduction_qs,1) + b = -(y1%axInduction_qs(i1,i2) - y2%axInduction_qs(i1,i2)) + y_out%axInduction_qs(i1,i2) = y1%axInduction_qs(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%tanInduction_qs) .AND. ALLOCATED(y1%tanInduction_qs)) THEN + DO i2 = LBOUND(y_out%tanInduction_qs,2),UBOUND(y_out%tanInduction_qs,2) + DO i1 = LBOUND(y_out%tanInduction_qs,1),UBOUND(y_out%tanInduction_qs,1) + b = -(y1%tanInduction_qs(i1,i2) - y2%tanInduction_qs(i1,i2)) + y_out%tanInduction_qs(i1,i2) = y1%tanInduction_qs(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%k) .AND. ALLOCATED(y1%k)) THEN + DO i2 = LBOUND(y_out%k,2),UBOUND(y_out%k,2) + DO i1 = LBOUND(y_out%k,1),UBOUND(y_out%k,1) + b = -(y1%k(i1,i2) - y2%k(i1,i2)) + y_out%k(i1,i2) = y1%k(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%k_p) .AND. ALLOCATED(y1%k_p)) THEN + DO i2 = LBOUND(y_out%k_p,2),UBOUND(y_out%k_p,2) + DO i1 = LBOUND(y_out%k_p,1),UBOUND(y_out%k_p,1) + b = -(y1%k_p(i1,i2) - y2%k_p(i1,i2)) + y_out%k_p(i1,i2) = y1%k_p(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%F) .AND. ALLOCATED(y1%F)) THEN + DO i2 = LBOUND(y_out%F,2),UBOUND(y_out%F,2) + DO i1 = LBOUND(y_out%F,1),UBOUND(y_out%F,1) + b = -(y1%F(i1,i2) - y2%F(i1,i2)) + y_out%F(i1,i2) = y1%F(i1,i2) + b * ScaleFactor + END DO + END DO +END IF ! check if allocated IF (ALLOCATED(y_out%Re) .AND. ALLOCATED(y1%Re)) THEN DO i2 = LBOUND(y_out%Re,2),UBOUND(y_out%Re,2) DO i1 = LBOUND(y_out%Re,1),UBOUND(y_out%Re,1) @@ -7806,6 +8176,51 @@ SUBROUTINE BEMT_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, E END DO END DO END IF ! check if allocated +IF (ALLOCATED(y_out%axInduction_qs) .AND. ALLOCATED(y1%axInduction_qs)) THEN + DO i2 = LBOUND(y_out%axInduction_qs,2),UBOUND(y_out%axInduction_qs,2) + DO i1 = LBOUND(y_out%axInduction_qs,1),UBOUND(y_out%axInduction_qs,1) + b = (t(3)**2*(y1%axInduction_qs(i1,i2) - y2%axInduction_qs(i1,i2)) + t(2)**2*(-y1%axInduction_qs(i1,i2) + y3%axInduction_qs(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%axInduction_qs(i1,i2) + t(3)*y2%axInduction_qs(i1,i2) - t(2)*y3%axInduction_qs(i1,i2) ) * scaleFactor + y_out%axInduction_qs(i1,i2) = y1%axInduction_qs(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%tanInduction_qs) .AND. ALLOCATED(y1%tanInduction_qs)) THEN + DO i2 = LBOUND(y_out%tanInduction_qs,2),UBOUND(y_out%tanInduction_qs,2) + DO i1 = LBOUND(y_out%tanInduction_qs,1),UBOUND(y_out%tanInduction_qs,1) + b = (t(3)**2*(y1%tanInduction_qs(i1,i2) - y2%tanInduction_qs(i1,i2)) + t(2)**2*(-y1%tanInduction_qs(i1,i2) + y3%tanInduction_qs(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%tanInduction_qs(i1,i2) + t(3)*y2%tanInduction_qs(i1,i2) - t(2)*y3%tanInduction_qs(i1,i2) ) * scaleFactor + y_out%tanInduction_qs(i1,i2) = y1%tanInduction_qs(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%k) .AND. ALLOCATED(y1%k)) THEN + DO i2 = LBOUND(y_out%k,2),UBOUND(y_out%k,2) + DO i1 = LBOUND(y_out%k,1),UBOUND(y_out%k,1) + b = (t(3)**2*(y1%k(i1,i2) - y2%k(i1,i2)) + t(2)**2*(-y1%k(i1,i2) + y3%k(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%k(i1,i2) + t(3)*y2%k(i1,i2) - t(2)*y3%k(i1,i2) ) * scaleFactor + y_out%k(i1,i2) = y1%k(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%k_p) .AND. ALLOCATED(y1%k_p)) THEN + DO i2 = LBOUND(y_out%k_p,2),UBOUND(y_out%k_p,2) + DO i1 = LBOUND(y_out%k_p,1),UBOUND(y_out%k_p,1) + b = (t(3)**2*(y1%k_p(i1,i2) - y2%k_p(i1,i2)) + t(2)**2*(-y1%k_p(i1,i2) + y3%k_p(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%k_p(i1,i2) + t(3)*y2%k_p(i1,i2) - t(2)*y3%k_p(i1,i2) ) * scaleFactor + y_out%k_p(i1,i2) = y1%k_p(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%F) .AND. ALLOCATED(y1%F)) THEN + DO i2 = LBOUND(y_out%F,2),UBOUND(y_out%F,2) + DO i1 = LBOUND(y_out%F,1),UBOUND(y_out%F,1) + b = (t(3)**2*(y1%F(i1,i2) - y2%F(i1,i2)) + t(2)**2*(-y1%F(i1,i2) + y3%F(i1,i2)))* scaleFactor + c = ( (t(2)-t(3))*y1%F(i1,i2) + t(3)*y2%F(i1,i2) - t(2)*y3%F(i1,i2) ) * scaleFactor + y_out%F(i1,i2) = y1%F(i1,i2) + b + c * t_out + END DO + END DO +END IF ! check if allocated IF (ALLOCATED(y_out%Re) .AND. ALLOCATED(y1%Re)) THEN DO i2 = LBOUND(y_out%Re,2),UBOUND(y_out%Re,2) DO i1 = LBOUND(y_out%Re,1),UBOUND(y_out%Re,1) diff --git a/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index b640d50397..beecc09957 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -1455,7 +1455,7 @@ subroutine AWAE_UpdateStates( t, n, u, p, x, xd, z, OtherState, m, errStat, errM end do do n_hl=0, n_high_low ! Set the hub position and orientation to pass to IfW (IfW always calculates hub and disk avg vel) - m%u_IfW_High%HubPosition = (/ p%X0_high(nt) + 0.5*p%nX_high*p%dX_high(nt), p%Y0_high(nt) + 0.5*p%nY_high*p%dY_high(nt), p%Z0_high(nt) + 0.5*p%nZ_high*p%dZ_high(nt) /) + m%u_IfW_High%HubPosition = (/ p%X0_high(nt) + 0.5*p%nX_high*p%dX_high(nt), p%Y0_high(nt) + 0.5*p%nY_high*p%dY_high(nt), p%Z0_high(nt) + 0.5*p%nZ_high*p%dZ_high(nt) /) - p%WT_Position(:,nt) call Eye(m%u_IfW_High%HubOrientation,ErrStat2,ErrMsg2) call InflowWind_CalcOutput(t+p%dt_low+n_hl*p%DT_high, m%u_IfW_High, p%IfW(nt), x%IfW(nt), xd%IfW(nt), z%IfW(nt), OtherState%IfW(nt), m%y_IfW_High, m%IfW(nt), errStat2, errMsg2) call SetErrStat( ErrStat2, ErrMsg2, errStat, errMsg, RoutineName ) diff --git a/modules/elastodyn/src/ElastoDyn_IO.f90 b/modules/elastodyn/src/ElastoDyn_IO.f90 index 45348664e6..286ab30aac 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -3627,6 +3627,10 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile ELSE CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ENDIF + +!FIXME: this is a hack to fix a segfault. Better logic is really needed for the nodal outputs. + ! Node outputs. If no blades specified set BldNd_Outs to 0 (all checks are currently done on NumOuts, not BladesOut). + if (InputFileData%BldNd_BladesOut <= 0) InputFileData%BldNd_NumOuts = 0 !---------------------- END OF FILE ----------------------------------------- call cleanup() diff --git a/modules/inflowwind/src/IfW_FlowField.f90 b/modules/inflowwind/src/IfW_FlowField.f90 index 0d07e55f5d..7e10ffddd7 100644 --- a/modules/inflowwind/src/IfW_FlowField.f90 +++ b/modules/inflowwind/src/IfW_FlowField.f90 @@ -261,11 +261,11 @@ subroutine IfW_FlowField_GetVelAcc(FF, IStart, Time, PositionXYZ, VelocityUVW, A cycle end if - call Grid4DField_GetVel(FF%Grid4D, Time, Position(:, i), VelocityUVW(:, i), TmpErrStat, TmpErrMsg) - if (TmpErrStat >= AbortErrLev) then - call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) - return - end if + call Grid4DField_GetVel(FF%Grid4D, Time, Position(:, i), VelocityUVW(:, i), TmpErrStat, TmpErrMsg) + if (TmpErrStat >= AbortErrLev) then + call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) + return + end if end do case (Point_FieldType) @@ -1232,34 +1232,28 @@ subroutine GetBoundsT(PosX, DT) ! In distance, X: InputInfo%PosX - p%InitXPosition - TIME*p%MeanWS TimeShifted = real(Time, ReKi) + (G3D%InitXPosition - PosX)*G3D%InvMWS + ! Get position on T grid + T_GRID = TimeShifted*G3D%Rate + ! If field is periodic if (G3D%Periodic) then - TimeShifted = MODULO(TimeShifted, G3D%TotalTime) - ! If TimeShifted is a very small negative number, - ! modulo returns the incorrect value due to internal rounding errors. - ! See bug report #471 - if (TimeShifted == G3D%TotalTime) TimeShifted = 0.0_ReKi + T_GRID = MODULO(T_GRID, real(G3D%NSteps, ReKi)) end if - ! Get position on T grid - T_GRID = TimeShifted*G3D%Rate + 1 - ! Calculate bounding grid indices - IT_LO = floor(T_GRID, IntKi) - IT_HI = ceiling(T_GRID, IntKi) + IT_LO = floor(T_GRID, IntKi) + 1 + IT_HI = IT_LO + 1 ! Position location within interval [0,1] - DT = T_GRID - aint(T_GRID) + DT = 2.0_ReKi*(T_GRID - aint(T_GRID)) - 1.0_ReKi ! Adjust indices and interpolant if (IT_LO >= 1 .and. IT_HI <= G3D%NSteps) then ! Point is within grid - DT = 2.0_ReKi*DT - 1.0_ReKi else if (IT_LO == G3D%NSteps) then if (G3D%Periodic) then ! Time wraps back to beginning IT_HI = 1 - DT = 2.0_ReKi*DT - 1.0_ReKi else if (DT <= GridTol) then ! Within tolerance of last time IT_HI = IT_LO @@ -1268,7 +1262,6 @@ subroutine GetBoundsT(PosX, DT) ! Extrapolate IT_LO = G3D%NSteps - 1 IT_HI = G3D%NSteps - DT = DT + 1.0_ReKi end if else ! Time exceeds array bounds @@ -1589,7 +1582,7 @@ subroutine Grid4DField_GetVel(G4D, Time, Position, Velocity, ErrStat, ErrMsg) !---------------------------------------------------------------------------- do i = 1, 3 - tmp = (Position(i) - G4D%pZero(i))/G4D%delta(i) + tmp = (Position(i) - G4D%pZero(i))/real(G4D%delta(i),Reki) Indx_Lo(i) = INT(tmp) + 1 ! convert REAL to INTEGER, then add one since our grid indices start at 1, not 0 xi(i) = 2.0_ReKi*(tmp - aint(tmp)) - 1.0_ReKi ! convert to value between -1 and 1 end do diff --git a/modules/inflowwind/src/IfW_FlowField.txt b/modules/inflowwind/src/IfW_FlowField.txt index cb890684f4..dafaa1871f 100644 --- a/modules/inflowwind/src/IfW_FlowField.txt +++ b/modules/inflowwind/src/IfW_FlowField.txt @@ -95,10 +95,10 @@ typedef ^ ^ LOGICAL BoxExceedWarn #---------------------------------------------------------------------------------------------------------------------------------- typedef ^ Grid4DFieldType IntKi n 4 - - "number of evenly-spaced grid points in the x, y, z, and t directions" - -typedef ^ ^ ReKi delta 4 - - "size between 2 consecutive grid points in each grid direction" "m,m,m,s" +typedef ^ ^ DbKi delta 4 - - "size between 2 consecutive grid points in each grid direction" "m,m,m,s" typedef ^ ^ ReKi pZero 3 - - "fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:))" "m" typedef ^ ^ SiKi Vel ::::: - - "this is the 4-d velocity field for each wind component [{uvw},nx,ny,nz,nt]" - -typedef ^ ^ ReKi TimeStart - - - "this is the time where the first time grid in m%V starts (i.e, the time associated with m%V(:,:,:,:,1))" s +typedef ^ ^ DbKi TimeStart - - - "this is the time where the first time grid in m%V starts (i.e, the time associated with m%V(:,:,:,:,1))" s typedef ^ ^ ReKi RefHeight - - - "reference height; used to center the wind" meters #---------------------------------------------------------------------------------------------------------------------------------- diff --git a/modules/inflowwind/src/IfW_FlowField_Types.f90 b/modules/inflowwind/src/IfW_FlowField_Types.f90 index c8a8055785..9ae7a192f6 100644 --- a/modules/inflowwind/src/IfW_FlowField_Types.f90 +++ b/modules/inflowwind/src/IfW_FlowField_Types.f90 @@ -130,10 +130,10 @@ MODULE IfW_FlowField_Types ! ========= Grid4DFieldType ======= TYPE, PUBLIC :: Grid4DFieldType INTEGER(IntKi) , DIMENSION(1:4) :: n !< number of evenly-spaced grid points in the x, y, z, and t directions [-] - REAL(ReKi) , DIMENSION(1:4) :: delta !< size between 2 consecutive grid points in each grid direction [m,m,m,s] + REAL(DbKi) , DIMENSION(1:4) :: delta !< size between 2 consecutive grid points in each grid direction [m,m,m,s] REAL(ReKi) , DIMENSION(1:3) :: pZero !< fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:)) [m] REAL(SiKi) , DIMENSION(:,:,:,:,:), ALLOCATABLE :: Vel !< this is the 4-d velocity field for each wind component [{uvw},nx,ny,nz,nt] [-] - REAL(ReKi) :: TimeStart !< this is the time where the first time grid in m%V starts (i.e, the time associated with m%V(:,:,:,:,1)) [s] + REAL(DbKi) :: TimeStart !< this is the time where the first time grid in m%V starts (i.e, the time associated with m%V(:,:,:,:,1)) [s] REAL(ReKi) :: RefHeight !< reference height; used to center the wind [meters] END TYPE Grid4DFieldType ! ======================= @@ -2390,14 +2390,14 @@ SUBROUTINE IfW_FlowField_PackGrid4DFieldType( ReKiBuf, DbKiBuf, IntKiBuf, Indata Db_BufSz = 0 Int_BufSz = 0 Int_BufSz = Int_BufSz + SIZE(InData%n) ! n - Re_BufSz = Re_BufSz + SIZE(InData%delta) ! delta + Db_BufSz = Db_BufSz + SIZE(InData%delta) ! delta Re_BufSz = Re_BufSz + SIZE(InData%pZero) ! pZero Int_BufSz = Int_BufSz + 1 ! Vel allocated yes/no IF ( ALLOCATED(InData%Vel) ) THEN Int_BufSz = Int_BufSz + 2*5 ! Vel upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%Vel) ! Vel END IF - Re_BufSz = Re_BufSz + 1 ! TimeStart + Db_BufSz = Db_BufSz + 1 ! TimeStart Re_BufSz = Re_BufSz + 1 ! RefHeight IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) @@ -2431,8 +2431,8 @@ SUBROUTINE IfW_FlowField_PackGrid4DFieldType( ReKiBuf, DbKiBuf, IntKiBuf, Indata Int_Xferred = Int_Xferred + 1 END DO DO i1 = LBOUND(InData%delta,1), UBOUND(InData%delta,1) - ReKiBuf(Re_Xferred) = InData%delta(i1) - Re_Xferred = Re_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%delta(i1) + Db_Xferred = Db_Xferred + 1 END DO DO i1 = LBOUND(InData%pZero,1), UBOUND(InData%pZero,1) ReKiBuf(Re_Xferred) = InData%pZero(i1) @@ -2473,8 +2473,8 @@ SUBROUTINE IfW_FlowField_PackGrid4DFieldType( ReKiBuf, DbKiBuf, IntKiBuf, Indata END DO END DO END IF - ReKiBuf(Re_Xferred) = InData%TimeStart - Re_Xferred = Re_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%TimeStart + Db_Xferred = Db_Xferred + 1 ReKiBuf(Re_Xferred) = InData%RefHeight Re_Xferred = Re_Xferred + 1 END SUBROUTINE IfW_FlowField_PackGrid4DFieldType @@ -2519,8 +2519,8 @@ SUBROUTINE IfW_FlowField_UnPackGrid4DFieldType( ReKiBuf, DbKiBuf, IntKiBuf, Outd i1_l = LBOUND(OutData%delta,1) i1_u = UBOUND(OutData%delta,1) DO i1 = LBOUND(OutData%delta,1), UBOUND(OutData%delta,1) - OutData%delta(i1) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + OutData%delta(i1) = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 END DO i1_l = LBOUND(OutData%pZero,1) i1_u = UBOUND(OutData%pZero,1) @@ -2566,8 +2566,8 @@ SUBROUTINE IfW_FlowField_UnPackGrid4DFieldType( ReKiBuf, DbKiBuf, IntKiBuf, Outd END DO END DO END IF - OutData%TimeStart = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + OutData%TimeStart = DbKiBuf(Db_Xferred) + Db_Xferred = Db_Xferred + 1 OutData%RefHeight = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 END SUBROUTINE IfW_FlowField_UnPackGrid4DFieldType diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 46bf3325d9..f2d467f222 100644 --- a/modules/inflowwind/src/InflowWind.f90 +++ b/modules/inflowwind/src/InflowWind.f90 @@ -128,8 +128,6 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons Type(User_InitInputType) :: User_InitInput Type(Grid4D_InitInputType) :: Grid4D_InitInput Type(Points_InitInputType) :: Points_InitInput - - Type(WindFileDat) :: FileDat ! TYPE(InflowWind_IO_InitInputType) :: FlowField_InitData !< initialization info @@ -301,7 +299,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons Steady_InitInput%PLExp = InputFileData%Steady_PLexp p%FlowField%FieldType = Uniform_FieldType - call IfW_SteadyWind_Init(Steady_InitInput, SumFileUnit, p%FlowField%Uniform, FileDat, TmpErrStat, TmpErrMsg) + call IfW_SteadyWind_Init(Steady_InitInput, SumFileUnit, p%FlowField%Uniform, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -321,7 +319,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons Uniform_InitInput%PassedFileData = InitInp%WindType2Data p%FlowField%FieldType = Uniform_FieldType - call IfW_UniformWind_Init(Uniform_InitInput, SumFileUnit, p%FlowField%Uniform, FileDat, TmpErrStat, TmpErrMsg) + call IfW_UniformWind_Init(Uniform_InitInput, SumFileUnit, p%FlowField%Uniform, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -336,7 +334,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons TurbSim_InitInput%WindFileName = InputFileData%TSFF_FileName p%FlowField%FieldType = Grid3D_FieldType - call IfW_TurbSim_Init(TurbSim_InitInput, SumFileUnit, p%FlowField%Grid3D, FileDat, TmpErrStat, TmpErrMsg) + call IfW_TurbSim_Init(TurbSim_InitInput, SumFileUnit, p%FlowField%Grid3D, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -362,7 +360,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons Bladed_InitInput%NativeBladedFmt = .false. p%FlowField%FieldType = Grid3D_FieldType - call IfW_Bladed_Init(Bladed_InitInput, SumFileUnit, Bladed_InitOutput, p%FlowField%Grid3D, FileDat, TmpErrStat, TmpErrMsg) + call IfW_Bladed_Init(Bladed_InitInput, SumFileUnit, Bladed_InitOutput, p%FlowField%Grid3D, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -371,7 +369,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons ! Set reference position for wind rotation p%FlowField%RefPosition = [0.0_ReKi, 0.0_ReKi, p%FlowField%Grid3D%RefHeight] - + case (BladedFF_Shr_WindNumber) Bladed_InitInput%WindType = BladedFF_Shr_WindNumber @@ -381,7 +379,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons Bladed_InitInput%NativeBladedFmt = .true. p%FlowField%FieldType = Grid3D_FieldType - call IfW_Bladed_Init(Bladed_InitInput, SumFileUnit, Bladed_InitOutput, p%FlowField%Grid3D, FileDat, TmpErrStat, TmpErrMsg) + call IfW_Bladed_Init(Bladed_InitInput, SumFileUnit, Bladed_InitOutput, p%FlowField%Grid3D, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -417,7 +415,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons HAWC_InitInput%G3D%XOffset = InputFileData%FF%XOffset p%FlowField%FieldType = Grid3D_FieldType - call IfW_HAWC_Init(HAWC_InitInput, SumFileUnit, p%FlowField%Grid3D, FileDat, TmpErrStat, TmpErrMsg) + call IfW_HAWC_Init(HAWC_InitInput, SumFileUnit, p%FlowField%Grid3D, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() @@ -430,7 +428,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons case (User_WindNumber) p%FlowField%FieldType = User_FieldType - call IfW_User_Init(User_InitInput, SumFileUnit, p%FlowField%User, FileDat, TmpErrStat, TmpErrMsg) + call IfW_User_Init(User_InitInput, SumFileUnit, p%FlowField%User, InitOutData%WindFileInfo, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) then call Cleanup() diff --git a/modules/inflowwind/src/InflowWind_Driver.f90 b/modules/inflowwind/src/InflowWind_Driver.f90 index 77beb83a58..a2c83478b9 100644 --- a/modules/inflowwind/src/InflowWind_Driver.f90 +++ b/modules/inflowwind/src/InflowWind_Driver.f90 @@ -734,8 +734,7 @@ PROGRAM InflowWind_Driver IF ( IfWDriver_Verbose >= 5_IntKi ) CALL WrScr(NewLine//'Calling InflowWind_CalcOutput...'//NewLine) - DO ITime = 0, MAX( Settings%NumTimeSteps, 1_IntKi ) - + DO ITime = 0, MAX( Settings%NumTimeSteps, 0_IntKi ) TimeNow = Settings%TStart + Settings%DT*(ITime) IF ( SettingsFlags%WindGrid ) THEN diff --git a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 index d7033445b2..186b3435df 100644 --- a/modules/inflowwind/src/InflowWind_Driver_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Driver_Subs.f90 @@ -1413,8 +1413,8 @@ SUBROUTINE UpdateSettingsWithCL( DvrFlags, DvrSettings, CLFlags, CLSettings, DVR DvrFlags%NumTimeStepsDefault = .FALSE. ENDIF - ! Make sure there is at least one timestep - DvrSettings%NumTimeSteps = MAX(DvrSettings%NumTimeSteps,1_IntKi) + ! Make sure there is at least one timestep (start at index 0) + DvrSettings%NumTimeSteps = MAX(DvrSettings%NumTimeSteps,0_IntKi) !-------------------------------------------- diff --git a/modules/inflowwind/src/InflowWind_IO.f90 b/modules/inflowwind/src/InflowWind_IO.f90 index 5863024344..6f4a62c9a2 100644 --- a/modules/inflowwind/src/InflowWind_IO.f90 +++ b/modules/inflowwind/src/InflowWind_IO.f90 @@ -1031,7 +1031,7 @@ subroutine IfW_Grid4D_Init(InitInp, G4D, ErrStat, ErrMsg) ! Initialize field from inputs G4D%n = InitInp%n - G4D%delta = InitInp%delta + G4D%delta = real(InitInp%delta, DbKi) G4D%pZero = InitInp%pZero G4D%TimeStart = 0.0_ReKi G4D%RefHeight = InitInp%pZero(3) + (InitInp%n(3)/2) * InitInp%delta(3) @@ -2540,8 +2540,8 @@ subroutine Grid3D_ScaleTurbulence(InitInp, Vel, ScaleFactors, ErrStat, ErrMsg) iy = (ny + 1)/2 ! integer division ! compute the actual sigma at the point specified by (iy,iz). (This sigma should be close to 1.) - vSum = sum(Vel(:, iy, iz, :), dim=2) - vSum2 = sum(Vel(:, iy, iz, :)**2, dim=2) + vSum = sum(real(Vel(:, iy, iz, :),R8Ki), dim=2) + vSum2 = sum(real(Vel(:, iy, iz, :),R8Ki)**2, dim=2) vMean = vSum/nt ActualSigma = real(SQRT(ABS((vSum2/nt) - vMean**2)), ReKi) diff --git a/modules/inflowwind/src/InflowWind_Subs.f90 b/modules/inflowwind/src/InflowWind_Subs.f90 index 2432939b72..b9666db259 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -1733,7 +1733,7 @@ SUBROUTINE InflowWind_GetHubValues( Time, InputData, p, x, xd, z, OtherStates, m IMPLICIT NONE - CHARACTER(*), PARAMETER :: RoutineName="InflowWind_GetSpatialAverage" + CHARACTER(*), PARAMETER :: RoutineName="InflowWind_GetHubValues" ! Inputs / Outputs diff --git a/modules/inflowwind/src/Lidar.f90 b/modules/inflowwind/src/Lidar.f90 index ec35b2a3f7..9a83c4ce9b 100644 --- a/modules/inflowwind/src/Lidar.f90 +++ b/modules/inflowwind/src/Lidar.f90 @@ -118,7 +118,7 @@ SUBROUTINE Lidar_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, Init RETURN ENDIF - CALL AllocAry(p%lidar%MsrPosition , 3, p%lidar%NumBeam, 'Array for measurement coordinates', TmpErrStat, TmpErrMsg ) + CALL AllocAry(p%lidar%MsrPosition , 3, max(1,p%lidar%NumBeam), 'Array for measurement coordinates', TmpErrStat, TmpErrMsg ) CALL SetErrStat( TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) IF ( ErrStat>= AbortErrLev ) RETURN @@ -362,7 +362,8 @@ SUBROUTINE Lidar_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMs MeasurementCurrentStep = INT(t / p%lidar%MeasurementInterval) IF ( (p%lidar%MeasurementInterval * MeasurementCurrentStep) /= t ) THEN - Output%VelocityUVW(:,1) = 0 +!This isn't returned, so don't set it. +! Output%VelocityUVW(:,1) = 0 RETURN ENDIF diff --git a/modules/openfast-library/src/FAST_Types.f90 b/modules/openfast-library/src/FAST_Types.f90 index 7e2ec05633..ea4bea95c0 100644 --- a/modules/openfast-library/src/FAST_Types.f90 +++ b/modules/openfast-library/src/FAST_Types.f90 @@ -774,7 +774,7 @@ MODULE FAST_Types CHARACTER(1024) :: RootName !< Root name of FAST output files (overrides normal operation) [-] INTEGER(IntKi) :: NumActForcePtsBlade !< number of actuator line force points in blade [-] INTEGER(IntKi) :: NumActForcePtsTower !< number of actuator line force points in tower [-] - INTEGER(IntKi) :: NodeClusterType !< Node clustering for actuator line (0 - Uniform, 1 - Non-uniform clustered towards tip) [-] + LOGICAL :: NodeClusterType !< Node clustering for actuator line (0 - Uniform, 1 - Non-uniform clustered towards tip) [-] END TYPE FAST_ExternInitType ! ======================= ! ========= FAST_TurbineType ======= diff --git a/modules/servodyn/src/BladedInterface_EX.f90 b/modules/servodyn/src/BladedInterface_EX.f90 index 5775ffa6a3..4604a787fe 100644 --- a/modules/servodyn/src/BladedInterface_EX.f90 +++ b/modules/servodyn/src/BladedInterface_EX.f90 @@ -375,25 +375,33 @@ end subroutine InitStCCtrl subroutine InitLidarMeas() integer :: I,J if (p%NumBeam == 0) return ! Nothing to set - ! Allocate arrays for inputs - if (allocated(InitInp%LidSpeed)) then ! make sure we have the array allocated before setting it - CALL AllocAry(u%LidSpeed, size(InitInp%LidSpeed), 'u%LidSpeed', errStat2, ErrMsg2) - if (Failed()) return + ! Allocate arrays for inputs -- these may have been set in ServoDyn already + if (allocated(InitInp%LidSpeed)) then ! make sure we have the array allocated before setting it + if (.not. allocated(u%LidSpeed)) then + CALL AllocAry(u%LidSpeed, size(InitInp%LidSpeed), 'u%LidSpeed', errStat2, ErrMsg2) + if (Failed()) return + endif u%LidSpeed = InitInp%LidSpeed endif if (allocated(InitInp%MsrPositionsX)) then ! make sure we have the array allocated before setting it - CALL AllocAry(u%MsrPositionsX, size(InitInp%MsrPositionsX), 'u%MsrPositionsX', errStat2, ErrMsg2) - if (Failed()) return + if (.not. allocated(u%MsrPositionsX)) then + CALL AllocAry(u%MsrPositionsX, size(InitInp%MsrPositionsX), 'u%MsrPositionsX', errStat2, ErrMsg2) + if (Failed()) return + endif u%MsrPositionsX = InitInp%MsrPositionsX endif if (allocated(InitInp%MsrPositionsY)) then ! make sure we have the array allocated before setting it - CALL AllocAry(u%MsrPositionsY, size(InitInp%MsrPositionsY), 'u%MsrPositionsY', errStat2, ErrMsg2) - if (Failed()) return + if (.not. allocated(u%MsrPositionsY)) then + CALL AllocAry(u%MsrPositionsY, size(InitInp%MsrPositionsY), 'u%MsrPositionsY', errStat2, ErrMsg2) + if (Failed()) return + endif u%MsrPositionsY = InitInp%MsrPositionsY endif if (allocated(InitInp%MsrPositionsZ)) then ! make sure we have the array allocated before setting it - CALL AllocAry(u%MsrPositionsZ, size(InitInp%MsrPositionsZ), 'u%MsrPositionsZ', errStat2, ErrMsg2) - if (Failed()) return + if (.not. allocated(u%MsrPositionsZ)) then + CALL AllocAry(u%MsrPositionsZ, size(InitInp%MsrPositionsZ), 'u%MsrPositionsZ', errStat2, ErrMsg2) + if (Failed()) return + endif u%MsrPositionsZ = InitInp%MsrPositionsZ endif ! Write summary info to summary file diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 428b149b41..05eb0b8187 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -291,6 +291,7 @@ of_regression("EllipticalWing_OLAF" "openfast;aerodyn15;olaf" of_regression("StC_test_OC4Semi" "openfast;servodyn;hydrodyn;moordyn;offshore;stc") of_regression("MHK_RM1_Fixed" "openfast;elastodyn;aerodyn15;mhk") of_regression("MHK_RM1_Floating" "openfast;elastodyn;aerodyn15;hydrodyn;moordyn;mhk") +of_regression("Tailfin_FreeYaw1DOF_PolarBased" "openfast;elastodyn;aerodyn15") # OpenFAST C++ API test if(BUILD_OPENFAST_CPP_API) @@ -315,6 +316,8 @@ of_regression_py("EllipticalWing_OLAF_py" "openfast;fastlib;p of_regression_aeroacoustic("IEA_LB_RWT-AeroAcoustics" "openfast;aerodyn15;aeroacoustics") # Linearized OpenFAST regression tests +of_regression_linear("Fake5MW_AeroLin_B1_UA4_DBEMT3" "openfast;linear;elastodyn") #Also: aerodyn +of_regression_linear("Fake5MW_AeroLin_B3_UA6" "openfast;linear;elastodyn") #Also: aerodyn of_regression_linear("WP_Stationary_Linear" "openfast;linear;elastodyn") of_regression_linear("Ideal_Beam_Fixed_Free_Linear" "openfast;linear;beamdyn") of_regression_linear("Ideal_Beam_Free_Free_Linear" "openfast;linear;beamdyn") @@ -395,6 +398,7 @@ ifw_regression("ifw_uniform" "inflowwind") ifw_regression("ifw_nativeBladed" "inflowwind") ifw_regression("ifw_BoxExceed" "inflowwind") ifw_regression("ifw_BoxExceedTwr" "inflowwind") +ifw_regression("ifw_HAWC" "inflowwind") # Py-InflowWind regression tests py_ifw_regression("py_ifw_turbsimff" "inflowwind;python") diff --git a/reg_tests/executeInflowwindRegressionCase.py b/reg_tests/executeInflowwindRegressionCase.py index 3979d641c8..fd940feec7 100644 --- a/reg_tests/executeInflowwindRegressionCase.py +++ b/reg_tests/executeInflowwindRegressionCase.py @@ -94,6 +94,7 @@ os.makedirs(testBuildDirectory) for file in (glob.glob(os.path.join(inputsDirectory,"*.inp")) + glob.glob(os.path.join(inputsDirectory,"*.bts"))+ + glob.glob(os.path.join(inputsDirectory,"*.bin"))+ glob.glob(os.path.join(inputsDirectory,"*.wnd"))+ glob.glob(os.path.join(inputsDirectory,"*.hh"))+ glob.glob(os.path.join(inputsDirectory,"*.sum"))): diff --git a/reg_tests/executeOpenfastLinearRegressionCase.py b/reg_tests/executeOpenfastLinearRegressionCase.py index 4eed9f259e..2e88bd67e4 100644 --- a/reg_tests/executeOpenfastLinearRegressionCase.py +++ b/reg_tests/executeOpenfastLinearRegressionCase.py @@ -30,13 +30,16 @@ import numpy as np import shutil import subprocess +from eva import eigA, eig import rtestlib as rtl import openfastDrivers import pass_fail from errorPlotting import exportCaseSummary +from fast_linearization_file import FASTLinearizationFile +# from weio.fast_linearization_file import FASTLinearizationFile ##### Helper functions -excludeExt=['.out','.outb','.ech','.yaml','.sum','.log'] +excludeExt=['.out','.outb','.ech','.yaml','.sum','.log','.md'] def file_line_count(filename): file_handle = open(filename, 'r') @@ -45,8 +48,8 @@ def file_line_count(filename): file_handle.close() return i + 1 -def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): - return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) +def isclose(a, b, rtol=1e-09, atol=0.0): + return abs(a-b) <= max(rtol * max(abs(a), abs(b)), atol) ##### Main program @@ -77,12 +80,32 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): noExec = args.noExec verbose = args.verbose -# Tolerance have not been tuned for linearization case outputs. -# This is using 1e-5 since that seemed like a decent value prior to -# switching to relative and absolute tolerance. -rtol = 1e-5 +# --- Tolerances for matrix comparison +# Outputs of lin matrices have 3 decimal digits leading to minimum error of 0.001 +# Therefore the relative error to detect a change in the third decimal place +# is between 1e-3 and 1e-4. We allow a bit of margin and use rtol=2e-3 +# Lin matrices have a lot of small values, so atol is quite important +rtol = 2e-3 atol = 1e-5 +# --- Tolerances for frequencies +# Low frequencies are hard to match, so we use a high atol +rtol_f=1e-2 +atol_f=1e-2 + +# --- Tolerances for damping +# damping ratio is in [%] so we relax the atol +rtol_d=1e-2 +atol_d=1e-1 + + +CasePrefix=' Case: {}: '.format(caseName) +def exitWithError(msg): + rtl.exitWithError(CasePrefix+msg) +def indent(msg, sindent='\t'): + return '\n'.join([sindent+s for s in msg.split('\n')]) + + # validate inputs rtl.validateExeOrExit(executable) rtl.validateDirOrExit(sourceDirectory) @@ -100,11 +123,11 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): # verify all the required directories exist if not os.path.isdir(rtest): - rtl.exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) + exitWithError("The test data directory, {}, does not exist. If you haven't already, run `git submodule update --init --recursive`".format(rtest)) if not os.path.isdir(targetOutputDirectory): - rtl.exitWithError("The test data outputs directory, {}, does not exist. Try running `git submodule update`".format(targetOutputDirectory)) + exitWithError("The test data outputs directory, {}, does not exist. Try running `git submodule update`".format(targetOutputDirectory)) if not os.path.isdir(inputsDirectory): - rtl.exitWithError("The test data inputs directory, {}, does not exist. Verify your local repository is up to date.".format(inputsDirectory)) + exitWithError("The test data inputs directory, {}, does not exist. Verify your local repository is up to date.".format(inputsDirectory)) # create the local output directory if it does not already exist # and initialize it with input files for all test cases @@ -130,9 +153,10 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): rtl.copyTree(srcname, dstname, excludeExt=excludeExt) else: shutil.copy2(srcname, dstname) - -if not os.path.isdir(testBuildDirectory): - rtl.copyTree(inputsDirectory, testBuildDirectory, excludeExt=excludeExt) +# +# Copying the actual test directory +# if not os.path.isdir(testBuildDirectory): +rtl.copyTree(inputsDirectory, testBuildDirectory, excludeExt=excludeExt, renameExtDict={'.lin':'.ref_lin'}) ### Run openfast on the test case if not noExec: @@ -143,108 +167,140 @@ def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): ### Get a all the .lin files in the baseline directory baselineOutFiles = [f for f in os.listdir(targetOutputDirectory) if '.lin' in f] +if len(baselineOutFiles)==0: + exitWithError("No lin files present in baseline.") + # these should all exist in the local outputs directory localFiles = os.listdir(testBuildDirectory) localOutFiles = [f for f in localFiles if f in baselineOutFiles] if len(localOutFiles) != len(baselineOutFiles): - print("Error in case {}: an expected local solution file does not exist.".format(caseName)) - sys.exit(1) - -### test for regression -for i, f in enumerate(localOutFiles): - local_file = os.path.join(testBuildDirectory, f) - baseline_file = os.path.join(targetOutputDirectory, f) - - # verify both files have the same number of lines - local_file_line_count = file_line_count(local_file) - baseline_file_line_count = file_line_count(baseline_file) - if local_file_line_count != baseline_file_line_count: - print("Error in case {}: local and baseline solutions have different line counts in".format(caseName)) - print("\t{}".format(local_file)) - print("\t{}".format(baseline_file)) - sys.exit(1) - - # open both files - local_handle = open(local_file, 'r') - baseline_handle = open(baseline_file, 'r') - - # parse the files - - # skip the first 6 lines since they are headers and may change without conseequence - for i in range(6): - baseline_handle.readline() - local_handle.readline() - - # the next 10 lines are simulation info; save what we need - for i in range(11): - b_line = baseline_handle.readline() - l_line = local_handle.readline() - if i == 5: - b_num_continuous_states = int(b_line.split()[-1]) - l_num_continuous_states = int(l_line.split()[-1]) - elif i == 8: - b_num_inputs = int(b_line.split()[-1]) - l_num_inputs = int(l_line.split()[-1]) - elif i == 9: - b_num_outputs = int(b_line.split()[-1]) - l_num_outputs = int(l_line.split()[-1]) - - # find the "Jacobian matrices:" line - for i in range(local_file_line_count): - b_line = baseline_handle.readline() - l_line = local_handle.readline() - if "Jacobian matrices:" in l_line: - break - - # skip 1 empty/header lines - for i in range(1): - baseline_handle.readline() - local_handle.readline() - - # read and compare Jacobian matrices - for i in range(local_file_line_count): - b_line = baseline_handle.readline() - l_line = local_handle.readline() - if ":" in l_line: - continue - if len(l_line) < 5: - break - b_elements = b_line.split() - l_elements = l_line.split() - for j, l_element in enumerate(l_elements): - l_float = float(l_element) - b_float = float(b_elements[j]) - if not isclose(l_float, b_float, rtol, atol): - print(f"Failed in Jacobian matrix comparison:") - print(f"{l_float} in {local_file}") - print(f"{b_float} in {baseline_file}") - sys.exit(1) - - # skip 2 empty/header lines - for i in range(2): - baseline_handle.readline() - local_handle.readline() - - # read and compare Linearized state matrices - for i in range(local_file_line_count): - b_line = baseline_handle.readline() - l_line = local_handle.readline() - if ":" in l_line: - continue - if len(l_line) < 5: - break - b_elements = b_line.split() - l_elements = l_line.split() - for j, l_element in enumerate(l_elements): - l_float = float(l_element) - b_float = float(b_elements[j]) - if not isclose(l_float, b_float, rtol, atol): - print(f"Failed in state matrix comparison: {l_float} and {b_float}") - sys.exit(1) - - local_handle.close() - baseline_handle.close() + exitWithError("An expected local solution file does not exist:") + +### test for regression (compare lin files only) +try: + for i, f in enumerate(localOutFiles): + local_file = os.path.join(testBuildDirectory, f) + baseline_file = os.path.join(targetOutputDirectory, f) + if verbose: + print(CasePrefix+'ref:', baseline_file) + print(CasePrefix+'new:', local_file) + + # verify both files have the same number of lines + local_file_line_count = file_line_count(local_file) + baseline_file_line_count = file_line_count(baseline_file) + if local_file_line_count != baseline_file_line_count: + Err="Local and baseline solutions have different line counts in" + Err+="\n\tFile1:{}".format(local_file) + Err+="\n\tFile2:{}\n\n".format(baseline_file) + raise Exception(Err) + + # open both files + floc = FASTLinearizationFile(local_file) + fbas = FASTLinearizationFile(baseline_file) + + # --- Test that they have the same variables + kloc = floc.keys() + kbas = fbas.keys() + try: + np.testing.assert_equal(kloc, kbas) + except Exception as e: + Err = 'Different keys in local linfile.\n' + Err+= '\tNew:{}\n'.format(kloc) + Err+= '\tRef:{}\n'.format(kbas) + Err+= '\tin linfile: {}.\n'.format(local_file) + raise Exception(Err) + + # --- Compare 10 first frequencies and damping ratios in 'A' matrix + if 'A' in fbas.keys(): + Abas = fbas['A'] + Aloc = floc['A'] + # Note: we could potentially reorder states like MBC does, but no need for freq/damping + _, zeta_bas, _, freq_bas = eigA(Abas, nq=None, nq1=None, sort=True) + _, zeta_loc, _, freq_loc = eigA(Aloc, nq=None, nq1=None, sort=True) + + if len(freq_bas)==0: + # We use complex eigenvalues instead of frequencies/damping + # If this fails often, we should discard this test. + _, Lambda = eig(Abas, sort=False) + v_bas = np.diag(Lambda) + _, Lambda = eig(Aloc, sort=False) + v_loc = np.diag(Lambda) + + if verbose: + print(CasePrefix+'val_ref:', v_bas[:7]) + print(CasePrefix+'val_new:', v_loc[:7]) + try: + np.testing.assert_allclose(v_bas[:10], v_loc[:10], rtol=rtol_f, atol=atol_f) + except Exception as e: + raise Exception('Failed to compare A-matrix frequencies\n\tLinfile: {}.\n\tException: {}'.format(local_file, indent(e.args[0]))) + else: + + #if verbose: + print(CasePrefix+'freq_ref:', np.around(freq_bas[:8] ,5), '[Hz]') + print(CasePrefix+'freq_new:', np.around(freq_loc[:8] ,5),'[Hz]') + print(CasePrefix+'damp_ref:', np.around(zeta_bas[:8]*100,5), '[%]') + print(CasePrefix+'damp_new:', np.around(zeta_loc[:8]*100,5), '[%]') + + try: + np.testing.assert_allclose(freq_loc[:10], freq_bas[:10], rtol=rtol_f, atol=atol_f) + except Exception as e: + raise Exception('Failed to compare A-matrix frequencies\n\tLinfile: {}.\n\tException: {}'.format(local_file, indent(e.args[0]))) + + + if caseName=='Ideal_Beam_Free_Free_Linear': + # The free-free case is a bit weird, smae frequencies but dampings are +/- a value + zeta_loc=np.abs(zeta_loc) + zeta_bas=np.abs(zeta_bas) + + + try: + # Note: damping ratios in [%] + np.testing.assert_allclose(zeta_loc[:10]*100, zeta_bas[:10]*100, rtol=rtol_d, atol=atol_d) + except Exception as e: + raise Exception('Failed to compare A-matrix damping ratios\n\tLinfile: {}.\n\tException: {}'.format(local_file, indent(e.args[0]))) + + + + # --- Compare individual matrices/vectors + KEYS= ['A','B','C','D','dUdu','dUdy'] + KEYS+=['x','y','u','xdot'] + for k,v in fbas.items(): + if k in KEYS and v is not None: + if verbose: + print(CasePrefix+'key:', k) + # Arrays + Mloc=np.atleast_2d(floc[k]) + Mbas=np.atleast_2d(fbas[k]) + + # --- Compare dimensions + try: + np.testing.assert_equal(Mloc.shape, Mbas.shape) + except Exception as e: + Err = 'Different dimensions for variable `{}`.\n'.format(k) + Err+= '\tNew:{}\n'.format(Mloc.shape) + Err+= '\tRef:{}\n'.format(Mbas.shape) + Err+= '\tLinfile: {}.\n'.format(local_file) + raise Exception(Err) + + + # We for loop below to get the first element that mismatch + # Otherwise, do: np.testing.assert_allclose(floc[k], fbas[k], rtol=rtol, atol=atol) + for i in range(Mbas.shape[0]): + for j in range(Mbas.shape[1]): + # Old method: + #if not isclose(Mloc[i,j], Mbas[i,j], rtol=rtol, atol=atol): + # sElem = 'Element [{},{}], new : {}, baseline: {}'.format(i+1,j+1,Mloc[i,j], Mbas[i,j]) + # raise Exception('Failed to compare variable `{}`, {} \n\tLinfile: {}.'.format(k, sElem, local_file)) #, e.args[0])) + try: + np.testing.assert_allclose(Mloc[i,j], Mbas[i,j], rtol=rtol, atol=atol) + except Exception as e: + sElem = 'Element [{},{}], new : {}, baseline: {}'.format(i+1,j+1,Mloc[i,j], Mbas[i,j]) + raise Exception('Failed to compare variable `{}`, {} \n\tLinfile: {}.\n\tException: {}'.format(k, sElem, local_file, indent(e.args[0]))) + +except Exception as e: + exitWithError(e.args[0]) # passing case sys.exit(0) + diff --git a/reg_tests/executeOpenfastRegressionCase.py b/reg_tests/executeOpenfastRegressionCase.py index a0cae63e6b..c4aa6c23a2 100644 --- a/reg_tests/executeOpenfastRegressionCase.py +++ b/reg_tests/executeOpenfastRegressionCase.py @@ -93,7 +93,7 @@ # create the local output directory if it does not already exist # and initialize it with input files for all test cases -for data in ["AOC", "AWT27", "SWRT", "UAE_VI", "WP_Baseline"]: +for data in ["AOC", "AWT27", "_DummyTurbineData", "SWRT", "UAE_VI", "WP_Baseline"]: dataDir = os.path.join(buildDirectory, data) if not os.path.isdir(dataDir): rtl.copyTree(os.path.join(moduleDirectory, data), dataDir, excludeExt=excludeExt) diff --git a/reg_tests/lib/eva.py b/reg_tests/lib/eva.py new file mode 100644 index 0000000000..3908729b94 --- /dev/null +++ b/reg_tests/lib/eva.py @@ -0,0 +1,334 @@ +""" +Taken from python-toolbox https://github.com/openfast/python-toolbox + +Eigenvalue analyses (EVA) tools for: + - arbitrary systems: system matrix (A) + - and mechnical systems: mass (M), stiffness (K) and damping (C) matrices + +Some definitions: + + - zeta: damping ratio + + - delta/log_dec: logarithmic decrement + + - xi: approximation of logarithmic decrement: xi = 2 pi zeta + + - omega0 : natural frequency + + - omega_d : damped frequency omega_d = omega_0 sqrt(1-zeta^2) + + +""" +import pandas as pd +import numpy as np +# from scipy import linalg +from numpy import linalg + +def polyeig(*A, sort=False, normQ=None): + """ + Solve the polynomial eigenvalue problem: + (A0 + e A1 +...+ e**p Ap)x = 0 + + Return the eigenvectors [x_i] and eigenvalues [e_i] that are solutions. + + Usage: + X,e = polyeig(A0,A1,..,Ap) + + Most common usage, to solve a second order system: (K + C e + M e**2) x =0 + X,e = polyeig(K,C,M) + + """ + if len(A)<=0: + raise Exception('Provide at least one matrix') + for Ai in A: + if Ai.shape[0] != Ai.shape[1]: + raise Exception('Matrices must be square') + if Ai.shape != A[0].shape: + raise Exception('All matrices must have the same shapes'); + + n = A[0].shape[0] + l = len(A)-1 + # Assemble matrices for generalized problem + C = np.block([ + [np.zeros((n*(l-1),n)), np.eye(n*(l-1))], + [-np.column_stack( A[0:-1])] + ]) + D = np.block([ + [np.eye(n*(l-1)), np.zeros((n*(l-1), n))], + [np.zeros((n, n*(l-1))), A[-1] ] + ]); + # Solve generalized eigenvalue problem + e, X = linalg.eig(C, D); + if np.all(np.isreal(e)): + e=np.real(e) + X=X[:n,:] + + # Sort eigen values + if sort: + I = np.argsort(e) + X = X[:,I] + e = e[I] + + # Scaling each mode by max + if normQ=='byMax': + X /= np.tile(np.max(np.abs(X),axis=0), (n,1)) + + return X, e + + +def eig(K, M=None, freq_out=False, sort=True, normQ=None, discardIm=False, massScaling=True): + """ performs eigenvalue analysis and return same values as matlab + + returns: + Q : matrix of column eigenvectors + Lambda: matrix where diagonal values are eigenvalues + frequency = np.sqrt(np.diag(Lambda))/(2*np.pi) + or + frequencies (if freq_out is True) + """ + if M is not None: + D,Q = linalg.eig(K,M) + # --- rescaling using mass matrix to be consistent with Matlab + # TODO, this can be made smarter + # TODO this should be a normQ + if massScaling: + for j in range(M.shape[1]): + q_j = Q[:,j] + modalmass_j = np.dot(q_j.T,M).dot(q_j) + Q[:,j]= Q[:,j]/np.sqrt(modalmass_j) + Lambda=np.dot(Q.T,K).dot(Q) + else: + D,Q = linalg.eig(K) + Lambda = np.diag(D) + + # --- Sort + lambdaDiag=np.diag(Lambda) + if sort: + I = np.argsort(lambdaDiag) + Q = Q[:,I] + lambdaDiag = lambdaDiag[I] + if freq_out: + Lambda = np.sqrt(lambdaDiag)/(2*np.pi) # frequencies [Hz] + else: + Lambda = np.diag(lambdaDiag) # enforcing purely diagonal + + # --- Renormalize modes if users wants to + if normQ == 'byMax': + for j in range(Q.shape[1]): + q_j = Q[:,j] + iMax = np.argmax(np.abs(q_j)) + scale = q_j[iMax] # not using abs to normalize to "1" and not "+/-1" + Q[:,j]= Q[:,j]/scale + + # --- Sanitization, ensure real values + if discardIm: + Q_im = np.imag(Q) + Q = np.real(Q) + imm = np.mean(np.abs(Q_im),axis = 0) + bb = imm>0 + if sum(bb)>0: + W=list(np.where(bb)[0]) + print('[WARN] Found {:d} complex eigenvectors at positions {}/{}'.format(sum(bb),W,Q.shape[0])) + Lambda = np.real(Lambda) + + return Q,Lambda + + +def eigA(A, nq=None, nq1=None, fullEV=False, normQ=None, sort=True): + """ + Perform eigenvalue analysis on a "state" matrix A + where states are assumed to be ordered as {q, q_dot, q1} + This order is only relevant for returning the eigenvectors. + + INPUTS: + - A : square state matrix + - nq: number of second order states, optional, relevant if fullEV is False + - nq1: number of first order states, optional, relevant if fullEV is False + - fullEV: if True, the entire eigenvectors are returned, otherwise, + only the part associated with q and q1 are returned + - normQ: 'byMax': normalize by maximum + None: do not normalize + OUPUTS: + - freq_d: damped frequencies [Hz] + - zeta : damping ratios [-] + - Q : column eigenvectors + - freq_0: natural frequencies [Hz] + """ + n,m = A.shape + + if m!=n: + raise Exception('Matrix needs to be squared') + if nq is None: + if nq1 is None: + nq1=0 + nq = int((n-nq1)/2) + else: + nq1 = n-2*nq + if n!=2*nq+nq1 or nq1<0: + raise Exception('Number of 1st and second order dofs should match the matrix shape (n= 2*nq + nq1') + Q, Lambda = eig(A, sort=False) + v = np.diag(Lambda) + + if not fullEV: + Q=np.delete(Q, slice(nq,2*nq), axis=0) + + # Selecting eigenvalues with positive imaginary part (frequency) + Ipos = np.imag(v)>0 + Q = Q[:,Ipos] + v = v[Ipos] + + # Frequencies and damping based on compled eigenvalues + omega_0 = np.abs(v) # natural cylic frequency [rad/s] + freq_d = np.imag(v)/(2*np.pi) # damped frequency [Hz] + zeta = - np.real(v)/omega_0 # damping ratio + freq_0 = omega_0/(2*np.pi) # natural frequency [Hz] + + # Sorting + if sort: + I = np.argsort(freq_0) + freq_d = freq_d[I] + freq_0 = freq_0[I] + zeta = zeta[I] + Q = Q[:,I] + + # Normalize Q + if normQ=='byMax': + for j in range(Q.shape[1]): + q_j = Q[:,j] + scale = np.max(np.abs(q_j)) + Q[:,j]= Q[:,j]/scale + return freq_d, zeta, Q, freq_0 + + + +def eigMK(M, K, sort=True, normQ=None, discardIm=False, freq_out=True, massScaling=True): + """ + Eigenvalue analysis of a mechanical system + M, K: mass, and stiffness matrices respectively + + Should be equivalent to calling eig(K, M) in Matlab (NOTE: argument swap) + except that frequencies are returned instead of "Lambda" + + OUTPUTS: + Q, freq_0 if freq_out + Q, Lambda otherwise + """ + return eig(K, M, sort=sort, normQ=normQ, discardIm=discardIm, freq_out=freq_out, massScaling=massScaling) + + +def eigMCK(M, C, K, method='full_matrix', sort=True, normQ=None): + """ + Eigenvalue analysis of a mechanical system + M, C, K: mass, damping, and stiffness matrices respectively + + NOTE: full_matrix, state_space and state_space_gen should return the same + when damping is present + """ + if np.linalg.norm(C)<1e-14: + if method.lower() not in ['state_space', 'state_space_gen']: + # No damping + Q, freq_0 = eigMK(M, K, sort=sort, freq_out=True, normQ=normQ) + freq_d = freq_0 + zeta = freq_0*0 + return freq_d, zeta, Q, freq_0 + + + n = M.shape[0] # Number of DOFs + + if method.lower()=='diag_beta': + ## using K, M and damping assuming diagonal beta matrix (Rayleigh Damping) + Q, Lambda = eig(K,M, sort=False) # provide scaled EV, important, no sorting here! + freq_0 = np.sqrt(np.diag(Lambda))/(2*np.pi) + betaMat = np.dot(Q,C).dot(Q.T) + xi = (np.diag(betaMat)*np.pi/(2*np.pi*freq_0)) + xi[xi>2*np.pi] = np.NAN + zeta = xi/(2*np.pi) + freq_d = freq_0*np.sqrt(1-zeta**2) + + elif method.lower()=='full_matrix': + ## Method 2 - Damping based on K, M and full D matrix + Q,v = polyeig(K,C,M, sort=sort, normQ=normQ) + #omega0 = np.abs(e) + zeta = - np.real(v) / np.abs(v) + freq_d = np.imag(v) / (2*np.pi) + # Keeping only positive frequencies + bValid = freq_d > 1e-08 + freq_d = freq_d[bValid] + zeta = zeta[bValid] + Q = Q[:,bValid] + # logdec2 = 2*pi*dampratio_sorted./sqrt(1-dampratio_sorted.^2); + + elif method.lower()=='state_space': + # See welib.system.statespace.StateMatrix + Minv = np.linalg.inv(M) + I = np.eye(n) + Z = np.zeros((n, n)) + A = np.block([[np.zeros((n, n)), np.eye(n)], + [ -Minv@K , -Minv@C ]]) + return eigA(A, normQ=normQ, sort=sort) + + elif method.lower()=='state_space_gen': + I = np.eye(n) + Z = np.zeros((n, n)) + A = np.block([[Z, I], + [-K, -C]]) + B = np.block([[I, Z], + [Z, M]]) + # solve the generalized eigenvalue problem + D, Q = linalg.eig(A, B) + # Keeping every other states (assuming pairs..) + v = D[::2] + Q = Q[:n, ::2] + + # calculate natural frequencies and damping + omega_0 = np.abs(v) # natural cyclic frequency [rad/s] + freq_d = np.imag(v)/(2*np.pi) # damped frequency [Hz] + zeta = - np.real(v)/omega_0 # damping ratio + + else: + raise NotImplementedError() + + # Sorting + if sort: + I = np.argsort(freq_d) + freq_d = freq_d[I] + zeta = zeta[I] + Q = Q[:,I] + # Undamped frequency + freq_0 = freq_d / np.sqrt(1 - zeta**2) + #xi = 2 * np.pi * zeta # pseudo log-dec + return freq_d, zeta, Q, freq_0 + + +if __name__=='__main__': + np.set_printoptions(linewidth=300, precision=4) + nDOF = 2 + M = np.zeros((nDOF,nDOF)) + K = np.zeros((nDOF,nDOF)) + C = np.zeros((nDOF,nDOF)) + M[0,0] = 430000; + M[1,1] = 42000000; + C[0,0] = 7255; + C[1,1] = M[1,1]*0.001; + K[0,0] = 2700000.; + K[1,1] = 200000000.; + + freq_d, zeta, Q, freq, xi = eigMCK(M,C,K) + print(freq_d) + print(Q) + + + #M = diag([3,0,0,0], [0, 1,0,0], [0,0,3,0],[0,0,0, 1]) + M = np.diag([3,1,3,1]) + C = np.array([[0.4 , 0 , -0.3 , 0] , [0 , 0 , 0 , 0] , [-0.3 , 0 , 0.5 , -0.2 ] , [ 0 , 0 , -0.2 , 0.2]]) + K = np.array([[-7 , 2 , 4 , 0] , [2 , -4 , 2 , 0] , [4 , 2 , -9 , 3 ] , [ 0 , 0 , 3 , -3]]) + + X,e = polyeig(K,C,M) + print('X:\n',X) + print('e:\n',e) + # Test taht first eigenvector and valur satisfy eigenvalue problem: + s = e[0]; + x = X[:,0]; + res = (M*s**2 + C*s + K).dot(x) # residuals + assert(np.all(np.abs(res)<1e-12)) + diff --git a/reg_tests/lib/fast_linearization_file.py b/reg_tests/lib/fast_linearization_file.py new file mode 100644 index 0000000000..3606e6699f --- /dev/null +++ b/reg_tests/lib/fast_linearization_file.py @@ -0,0 +1,391 @@ +""" +Taken from python-toolbox https://github.com/openfast/python-toolbox +""" +import os +import numpy as np +import re +class BrokenFormatError(Exception): pass + +class FASTLinearizationFile(dict): + """ + Read/write an OpenFAST linearization file. The object behaves like a dictionary. + + Main keys + --------- + - 'x', 'xdot' 'u', 'y', 'A', 'B', 'C', 'D' + + Main methods + ------------ + - read, write, toDataFrame, keys, xdescr, ydescr, udescr + + Examples + -------- + + f = FASTLinearizationFile('5MW.1.lin') + print(f.keys()) + print(f['u']) # input operating point + print(f.udescr()) # description of inputs + + # use a dataframe with "named" columns and rows + df = f.toDataFrame() + print(df['A'].columns) + print(df['A']) + + """ + @staticmethod + def defaultExtensions(): + return ['.lin'] + + @staticmethod + def formatName(): + return 'FAST linearization output' + + def __init__(self, filename=None, **kwargs): + """ Class constructor. If a `filename` is given, the file is read. """ + self.filename = filename + if filename: + self.read(**kwargs) + + def read(self, filename=None, **kwargs): + """ Reads the file self.filename, or `filename` if provided """ + + # --- Standard tests and exceptions (generic code) + if filename: + self.filename = filename + if not self.filename: + raise Exception('No filename provided') + if not os.path.isfile(self.filename): + raise OSError(2,'File not found:',self.filename) + if os.stat(self.filename).st_size == 0: + raise EmptyFileError('File is empty:',self.filename) + # --- Calling (children) function to read + self._read(**kwargs) + + def _read(self, *args, **kwargs): + self['header']=[] + + def extractVal(lines, key): + for l in lines: + if l.find(key)>=0: + return l.split(key)[1].split()[0] + return None + + def readToMarker(fid, marker, nMax): + lines=[] + for i, line in enumerate(fid): + if i>nMax: + raise BrokenFormatError('`{}` not found in file'.format(marker)) + if line.find(marker)>=0: + break + lines.append(line.strip()) + return lines, line + + def readOP(fid, n, name=''): + OP=[] + Var = {'RotatingFrame': [], 'DerivativeOrder': [], 'Description': []} + colNames=fid.readline().strip() + dummy= fid.readline().strip() + bHasDeriv= colNames.find('Derivative Order')>=0 + for i, line in enumerate(fid): + sp=line.strip().split() + if sp[1].find(',')>=0: + # Most likely this OP has three values (e.g. orientation angles) + # For now we discard the two other values + OP.append(float(sp[1][:-1])) + iRot=4 + else: + OP.append(float(sp[1])) + iRot=2 + Var['RotatingFrame'].append(sp[iRot]) + if bHasDeriv: + Var['DerivativeOrder'].append(int(sp[iRot+1])) + Var['Description'].append(' '.join(sp[iRot+2:]).strip()) + else: + Var['DerivativeOrder'].append(-1) + Var['Description'].append(' '.join(sp[iRot+1:]).strip()) + if i>=n-1: + break + OP=np.asarray(OP) + return OP, Var + + def readMat(fid, n, m, name=''): + pattern = re.compile(r"[\*]+") + vals=[pattern.sub(' inf ', fid.readline().strip() ).split() for i in np.arange(n)] + vals = np.array(vals) + try: + vals = np.array(vals).astype(float) # This could potentially fail + except: + raise Exception('Failed to convert into an array of float the matrix `{}`\n\tin linfile: {}'.format(name, self.filename)) + if vals.shape[0]!=n or vals.shape[1]!=m: + shape1 = vals.shape + shape2 = (n,m) + raise Exception('Shape of matrix `{}` has wrong dimension ({} instead of {})\n\tin linfile: {}'.format(name, shape1, shape2, name, self.filename)) + + nNaN = sum(np.isnan(vals.ravel())) + nInf = sum(np.isinf(vals.ravel())) + if nInf>0: + raise Exception('Some ill-formated/infinite values (e.g. `*******`) were found in the matrix `{}`\n\tin linflile: {}'.format(name, self.filename)) + if nNaN>0: + raise Exception('Some NaN values were found in the matrix `{}`\n\tin linfile: `{}`.'.format(name, self.filename)) + return vals + + + # Reading + with open(self.filename, 'r', errors="surrogateescape") as f: + # --- Reader header + self['header'], lastLine=readToMarker(f, 'Jacobians included', 30) + self['header'].append(lastLine) + nx = int(extractVal(self['header'],'Number of continuous states:')) + nxd = int(extractVal(self['header'],'Number of discrete states:' )) + nz = int(extractVal(self['header'],'Number of constraint states:')) + nu = int(extractVal(self['header'],'Number of inputs:' )) + ny = int(extractVal(self['header'],'Number of outputs:' )) + bJac = extractVal(self['header'],'Jacobians included in this file?') + try: + self['Azimuth'] = float(extractVal(self['header'],'Azimuth:')) + except: + self['Azimuth'] = None + try: + self['RotSpeed'] = float(extractVal(self['header'],'Rotor Speed:')) # rad/s + except: + self['RotSpeed'] = None + try: + self['WindSpeed'] = float(extractVal(self['header'],'Wind Speed:')) + except: + self['WindSpeed'] = None + + for i, line in enumerate(f): + line = line.strip() + if line.find('Order of continuous states:')>=0: + self['x'], self['x_info'] = readOP(f, nx, 'x') + elif line.find('Order of continuous state derivatives:')>=0: + self['xdot'], self['xdot_info'] = readOP(f, nx, 'xdot') + elif line.find('Order of inputs')>=0: + self['u'], self['u_info'] = readOP(f, nu, 'u') + elif line.find('Order of outputs')>=0: + self['y'], self['y_info'] = readOP(f, ny, 'y') + elif line.find('A:')>=0: + self['A'] = readMat(f, nx, nx, 'A') + elif line.find('B:')>=0: + self['B'] = readMat(f, nx, nu, 'B') + elif line.find('C:')>=0: + self['C'] = readMat(f, ny, nx, 'C') + elif line.find('D:')>=0: + self['D'] = readMat(f, ny, nu, 'D') + elif line.find('dUdu:')>=0: + self['dUdu'] = readMat(f, nu, nu,'dUdu') + elif line.find('dUdy:')>=0: + self['dUdy'] = readMat(f, nu, ny,'dUdy') + elif line.find('StateRotation:')>=0: + pass + # TODO + #StateRotation: + elif line.find('ED M:')>=0: + self['EDDOF'] = line[5:].split() + self['M'] = readMat(f, 24, 24,'M') + + def toString(self): + s='' + return s + + def _write(self): + with open(self.filename,'w') as f: + f.write(self.toString()) + + def short_descr(self,slist): + def shortname(s): + s=s.strip() + s = s.replace('(m/s)' , '_[m/s]' ); + s = s.replace('(kW)' , '_[kW]' ); + s = s.replace('(deg)' , '_[deg]' ); + s = s.replace('(N)' , '_[N]' ); + s = s.replace('(kN-m)' , '_[kNm]' ); + s = s.replace('(N-m)' , '_[Nm]' ); + s = s.replace('(kN)' , '_[kN]' ); + s = s.replace('(rpm)' , '_[rpm]' ); + s = s.replace('(rad)' , '_[rad]' ); + s = s.replace('(rad/s)' , '_[rad/s]' ); + s = s.replace('(rad/s^2)', '_[rad/s^2]' ); + s = s.replace('(m/s^2)' , '_[m/s^2]'); + s = s.replace('(deg/s^2)','_[deg/s^2]'); + s = s.replace('(m)' , '_[m]' ); + s = s.replace(', m/s/s','_[m/s^2]'); + s = s.replace(', m/s^2','_[m/s^2]'); + s = s.replace(', m/s','_[m/s]'); + s = s.replace(', m','_[m]'); + s = s.replace(', rad/s/s','_[rad/s^2]'); + s = s.replace(', rad/s^2','_[rad/s^2]'); + s = s.replace(', rad/s','_[rad/s]'); + s = s.replace(', rad','_[rad]'); + s = s.replace(', -','_[-]'); + s = s.replace(', Nm/m','_[Nm/m]'); + s = s.replace(', Nm','_[Nm]'); + s = s.replace(', N/m','_[N/m]'); + s = s.replace(', N','_[N]'); + s = s.replace('(1)','1') + s = s.replace('(2)','2') + s = s.replace('(3)','3') + s= re.sub(r'\([^)]*\)','', s) # remove parenthesis + s = s.replace('ED ',''); + s = s.replace('BD_','BD_B'); + s = s.replace('IfW ',''); + s = s.replace('Extended input: ','') + s = s.replace('1st tower ','qt1'); + s = s.replace('2nd tower ','qt2'); + nd = s.count('First time derivative of ') + if nd>=0: + s = s.replace('First time derivative of ' ,''); + if nd==1: + s = 'd_'+s.strip() + elif nd==2: + s = 'dd_'+s.strip() + s = s.replace('Variable speed generator DOF ','psi_rot'); # NOTE: internally in FAST this is the azimuth of the rotor + s = s.replace('fore-aft bending mode DOF ' ,'FA' ); + s = s.replace('side-to-side bending mode DOF','SS' ); + s = s.replace('bending-mode DOF of blade ' ,'' ); + s = s.replace(' rotational-flexibility DOF, rad','-ROT' ); + s = s.replace('rotational displacement in ','rot' ); + s = s.replace('Drivetrain','DT' ); + s = s.replace('translational displacement in ','trans' ); + s = s.replace('finite element node ','N' ); + s = s.replace('-component position of node ','posN') + s = s.replace('-component inflow on tower node','TwrN') + s = s.replace('-component inflow on blade 1, node','Bld1N') + s = s.replace('-component inflow on blade 2, node','Bld2N') + s = s.replace('-component inflow on blade 3, node','Bld3N') + s = s.replace('-component inflow velocity at node','N') + s = s.replace('X translation displacement, node','TxN') + s = s.replace('Y translation displacement, node','TyN') + s = s.replace('Z translation displacement, node','TzN') + s = s.replace('X translation velocity, node','TVxN') + s = s.replace('Y translation velocity, node','TVyN') + s = s.replace('Z translation velocity, node','TVzN') + s = s.replace('X translation acceleration, node','TAxN') + s = s.replace('Y translation acceleration, node','TAyN') + s = s.replace('Z translation acceleration, node','TAzN') + s = s.replace('X orientation angle, node' ,'RxN') + s = s.replace('Y orientation angle, node' ,'RyN') + s = s.replace('Z orientation angle, node' ,'RzN') + s = s.replace('X rotation velocity, node' ,'RVxN') + s = s.replace('Y rotation velocity, node' ,'RVyN') + s = s.replace('Z rotation velocity, node' ,'RVzN') + s = s.replace('X rotation acceleration, node' ,'RAxN') + s = s.replace('Y rotation acceleration, node' ,'RAyN') + s = s.replace('Z rotation acceleration, node' ,'RAzN') + s = s.replace('X force, node','FxN') + s = s.replace('Y force, node','FyN') + s = s.replace('Z force, node','FzN') + s = s.replace('X moment, node','MxN') + s = s.replace('Y moment, node','MyN') + s = s.replace('Z moment, node','MzN') + s = s.replace('FX', 'Fx') + s = s.replace('FY', 'Fy') + s = s.replace('FZ', 'Fz') + s = s.replace('MX', 'Mx') + s = s.replace('MY', 'My') + s = s.replace('MZ', 'Mz') + s = s.replace('FKX', 'FKx') + s = s.replace('FKY', 'FKy') + s = s.replace('FKZ', 'FKz') + s = s.replace('MKX', 'MKx') + s = s.replace('MKY', 'MKy') + s = s.replace('MKZ', 'MKz') + s = s.replace('Nodes motion','') + s = s.replace('cosine','cos' ); + s = s.replace('sine','sin' ); + s = s.replace('collective','coll.'); + s = s.replace('Blade','Bld'); + s = s.replace('rotZ','TORS-R'); + s = s.replace('transX','FLAP-D'); + s = s.replace('transY','EDGE-D'); + s = s.replace('rotX','EDGE-R'); + s = s.replace('rotY','FLAP-R'); + s = s.replace('flapwise','FLAP'); + s = s.replace('edgewise','EDGE'); + s = s.replace('horizontal surge translation DOF','Surge'); + s = s.replace('horizontal sway translation DOF','Sway'); + s = s.replace('vertical heave translation DOF','Heave'); + s = s.replace('roll tilt rotation DOF','Roll'); + s = s.replace('pitch tilt rotation DOF','Pitch'); + s = s.replace('yaw rotation DOF','Yaw'); + s = s.replace('vertical power-law shear exponent','alpha') + s = s.replace('horizontal wind speed ','WS') + s = s.replace('propagation direction','WD') + s = s.replace(' pitch command','pitch') + s = s.replace('HSS_','HSS') + s = s.replace('Bld','B') + s = s.replace('tower','Twr') + s = s.replace('Tower','Twr') + s = s.replace('Nacelle','Nac') + s = s.replace('Platform','Ptfm') + s = s.replace('SrvD','SvD') + s = s.replace('Generator torque','Qgen') + s = s.replace('coll. blade-pitch command','PitchColl') + s = s.replace('wave elevation at platform ref point','WaveElevRefPoint') + s = s.replace('1)','1'); + s = s.replace('2)','2'); + s = s.replace('3)','3'); + s = s.replace(',',''); + s = s.replace(' ',''); + s=s.strip() + return s + return [shortname(s) for s in slist] + + def xdescr(self): + if 'x_info' in self.keys(): + return self.short_descr(self['x_info']['Description']) + else: + return [] + + def xdotdescr(self): + if 'xdot_info' in self.keys(): + return self.short_descr(self['xdot_info']['Description']) + else: + return [] + + def ydescr(self): + if 'y_info' in self.keys(): + return self.short_descr(self['y_info']['Description']) + else: + return [] + def udescr(self): + if 'u_info' in self.keys(): + return self.short_descr(self['u_info']['Description']) + else: + return [] + + def toDataFrame(self): + import pandas as pd + dfs={} + + xdescr_short = self.xdescr() + xdotdescr_short = self.xdotdescr() + ydescr_short = self.ydescr() + udescr_short = self.udescr() + + if 'A' in self.keys(): + dfs['A'] = pd.DataFrame(data = self['A'], index=xdescr_short, columns=xdescr_short) + if 'B' in self.keys(): + dfs['B'] = pd.DataFrame(data = self['B'], index=xdescr_short, columns=udescr_short) + if 'C' in self.keys(): + dfs['C'] = pd.DataFrame(data = self['C'], index=ydescr_short, columns=xdescr_short) + if 'D' in self.keys(): + dfs['D'] = pd.DataFrame(data = self['D'], index=ydescr_short, columns=udescr_short) + if 'x' in self.keys(): + dfs['x'] = pd.DataFrame(data = np.asarray(self['x']).reshape((1,-1)), columns=xdescr_short) + if 'xdot' in self.keys(): + dfs['xdot'] = pd.DataFrame(data = np.asarray(self['xdot']).reshape((1,-1)), columns=xdotdescr_short) + if 'u' in self.keys(): + dfs['u'] = pd.DataFrame(data = np.asarray(self['u']).reshape((1,-1)), columns=udescr_short) + if 'y' in self.keys(): + dfs['y'] = pd.DataFrame(data = np.asarray(self['y']).reshape((1,-1)), columns=ydescr_short) + if 'M' in self.keys(): + dfs['M'] = pd.DataFrame(data = self['M'], index=self['EDDOF'], columns=self['EDDOF']) + if 'dUdu' in self.keys(): + dfs['dUdu'] = pd.DataFrame(data = self['dUdu'], index=udescr_short, columns=udescr_short) + if 'dUdy' in self.keys(): + dfs['dUdy'] = pd.DataFrame(data = self['dUdy'], index=udescr_short, columns=ydescr_short) + + return dfs + + diff --git a/reg_tests/lib/rtestlib.py b/reg_tests/lib/rtestlib.py index 59dc4deaac..e90ca95820 100644 --- a/reg_tests/lib/rtestlib.py +++ b/reg_tests/lib/rtestlib.py @@ -25,7 +25,9 @@ import shutil def exitWithError(error, code=1): - print(error) + # Making errors a bit more visible. + # The best would be colors. I tried with termcolor.cprint but failed. + print('\n\n'+'Error: '+error+'\n\n') sys.exit(code) def validInput(argv, nArgsExpected): diff --git a/reg_tests/r-test b/reg_tests/r-test index a59aa3ff18..8ef3817690 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit a59aa3ff180ba9347b27b3ff02e39155f997b8b4 +Subproject commit 8ef381769054319db890abb737d380f710a5a634 diff --git a/vs-build/AeroDyn/AeroDyn_Driver.vfproj b/vs-build/AeroDyn/AeroDyn_Driver.vfproj index e4b75a5c98..08ce82b7ec 100644 --- a/vs-build/AeroDyn/AeroDyn_Driver.vfproj +++ b/vs-build/AeroDyn/AeroDyn_Driver.vfproj @@ -26,7 +26,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -76,7 +76,7 @@ - +