diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index 7da144a293..3567571a2d 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -41,12 +41,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 \ @@ -117,12 +127,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 \ @@ -159,13 +173,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 \ @@ -209,14 +226,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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: | @@ -240,14 +264,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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: | @@ -271,14 +302,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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: | @@ -304,12 +342,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 \ @@ -363,14 +404,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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: @@ -410,18 +460,20 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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} @@ -467,14 +519,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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" 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: | @@ -506,22 +567,28 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 run: | - ctest -VV -j8 \ + ctest -VV -j4 \ -L openfast \ -LE "cpp|linear|python|fastlib" \ -E "5MW_OC4Semi_WSt_WavesWN|5MW_OC3Mnpl_DLL_WTurb_WavesIrr|5MW_OC4Jckt_DLL_WTurb_WavesIrr_MGrowth|5MW_OC3Trpd_DLL_WSt_WavesReg|5MW_Land_BD_DLL_WTurb" @@ -553,17 +620,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 @@ -597,17 +670,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 @@ -641,17 +720,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 @@ -685,17 +770,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 @@ -729,17 +820,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 @@ -773,22 +870,28 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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 run: | - ctest -VV -j8 -L linear + ctest -VV -j4 -L linear - name: Failing test artifacts uses: actions/upload-artifact@v3 if: failure() @@ -817,17 +920,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.11' cache: 'pip' - name: Install dependencies 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 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/.readthedocs.yml b/.readthedocs.yml index 5b54f8b4a3..eed597b9ca 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,20 +5,20 @@ # Required version: 2 +# select the docker image to use: stable | latest +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + formats: - htmlzip # - pdf # - epub python: - version: 3.7 install: - requirements: docs/requirements.txt - system_packages: true - -# select the docker image to use: stable | latest -build: - image: stable sphinx: builder: html diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a8792b190..5c9dda9259 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 03146fa76a..ff41b567f5 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/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 12678ae2ce..1ee45ea21e 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -2710,6 +2710,17 @@ subroutine FARM_CalcOutput(t, farm, ErrStat, ErrMsg) !$OMP END PARALLEL DO if (ErrStat >= AbortErrLev) return + ! IO operation, not done using OpenMP + DO nt = 1,farm%p%NumTurbines + call WD_WritePlaneOutputs( t, farm%WD(nt)%u, farm%WD(nt)%p, farm%WD(nt)%x, farm%WD(nt)%xd, farm%WD(nt)%z, & + farm%WD(nt)%OtherSt, farm%WD(nt)%y, farm%WD(nt)%m, ErrStat2, ErrMsg2 ) + if (ErrStat2 >= AbortErrLev) then + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, 'T'//trim(num2lstr(nt))//':'//RoutineName) + endif + END DO + if (ErrStat >= AbortErrLev) return + + call Transfer_WD_to_AWAE(farm) if ( farm%p%UseSC ) then 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 2ef0eed64f..f1a94d11cb 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 2af1a7f720..8227a8252a 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 b8ab0babd8..24e56b0ab2 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 !------------------------------------------------------------------------------------------------- @@ -2114,49 +2140,37 @@ subroutine calcCantAngle(f, xi,stencilSize,n,cantAngle) implicit none integer(IntKi), intent(in) :: stencilSize, n integer(IntKi) :: i, j - integer(IntKi) :: sortInd(n) integer(IntKi) :: info real(ReKi), intent(in) :: f(n), xi(n) real(ReKi) :: cx(stencilSize), cf(stencilSize), xiIn(stencilSize) - real(ReKi) :: fIn(stencilSize), cPrime(n), fPrime(n), xiAbs(n) + real(ReKi) :: fIn(stencilSize), cPrime(n), fPrime(n) real(ReKi), intent(inout) :: cantAngle(n) do i = 1,size(xi) - xiAbs = abs(xi-xi(i)) - call hpsort_eps_epw (n, xiAbs, sortInd, 1e-6) - 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 @@ -2370,147 +2384,5 @@ subroutine r8vm_sl ( n, a, b, x, job, info ) return end subroutine r8vm_sl -! - ! Copyright (C) 2010-2016 Samuel Ponce', Roxana Margine, Carla Verdi, Feliciano Giustino - ! Copyright (C) 2007-2009 Jesse Noffsinger, Brad Malone, Feliciano Giustino - ! - ! This file is distributed under the terms of the GNU General Public - ! License. See the file `LICENSE' in the root directory of the - ! present distribution, or http://www.gnu.org/copyleft.gpl.txt . - ! - ! Adapted from flib/hpsort_eps - !--------------------------------------------------------------------- - subroutine hpsort_eps_epw (n, ra, ind, eps) - !--------------------------------------------------------------------- - ! sort an array ra(1:n) into ascending order using heapsort algorithm, - ! and considering two elements being equal if their values differ - ! for less than "eps". - ! n is input, ra is replaced on output by its sorted rearrangement. - ! create an index table (ind) by making an exchange in the index array - ! whenever an exchange is made on the sorted data array (ra). - ! in case of equal values in the data array (ra) the values in the - ! index array (ind) are used to order the entries. - ! if on input ind(1) = 0 then indices are initialized in the routine, - ! if on input ind(1) != 0 then indices are assumed to have been - ! initialized before entering the routine and these - ! indices are carried around during the sorting process - ! - ! no work space needed ! - ! free us from machine-dependent sorting-routines ! - ! - ! adapted from Numerical Recipes pg. 329 (new edition) - ! - !use kinds, ONLY : DP - implicit none - !-input/output variables - integer(IntKi), intent(in) :: n - real(ReKi), intent(in) :: eps - integer(IntKi) :: ind (n) - real(ReKi) :: ra (n) - !-local variables - integer(IntKi) :: i, ir, j, l, iind - real(ReKi) :: rra -! - ! initialize index array - IF (ind (1) .eq.0) then - DO i = 1, n - ind (i) = i - ENDDO - ENDIF - ! nothing to order - IF (n.lt.2) return - ! initialize indices for hiring and retirement-promotion phase - l = n / 2 + 1 - - ir = n - - sorting: do - - ! still in hiring phase - IF ( l .gt. 1 ) then - l = l - 1 - rra = ra (l) - iind = ind (l) - ! in retirement-promotion phase. - ELSE - ! clear a space at the end of the array - rra = ra (ir) - ! - iind = ind (ir) - ! retire the top of the heap into it - ra (ir) = ra (1) - ! - ind (ir) = ind (1) - ! decrease the size of the corporation - ir = ir - 1 - ! done with the last promotion - IF ( ir .eq. 1 ) then - ! the least competent worker at all ! - ra (1) = rra - ! - ind (1) = iind - exit sorting - ENDIF - ENDIF - ! wheter in hiring or promotion phase, we - i = l - ! set up to place rra in its proper level - j = l + l - ! - DO while ( j .le. ir ) - IF ( j .lt. ir ) then - ! compare to better underling - IF ( hslt( ra (j), ra (j + 1) ) ) then - j = j + 1 - !else if ( .not. hslt( ra (j+1), ra (j) ) ) then - ! this means ra(j) == ra(j+1) within tolerance - ! if (ind (j) .lt.ind (j + 1) ) j = j + 1 - ENDIF - ENDIF - ! demote rra - IF ( hslt( rra, ra (j) ) ) then - ra (i) = ra (j) - ind (i) = ind (j) - i = j - j = j + j - !else if ( .not. hslt ( ra(j) , rra ) ) then - !this means rra == ra(j) within tolerance - ! demote rra - ! if (iind.lt.ind (j) ) then - ! ra (i) = ra (j) - ! ind (i) = ind (j) - ! i = j - ! j = j + j - ! else - ! set j to terminate do-while loop - ! j = ir + 1 - ! endif - ! this is the right place for rra - ELSE - ! set j to terminate do-while loop - j = ir + 1 - ENDIF - ENDDO - ra (i) = rra - ind (i) = iind - - END DO sorting -contains - - ! internal function - ! compare two real number and return the result - - logical function hslt( a, b ) - REAL(ReKi) :: a, b - IF( abs(a-b) < eps ) then - hslt = .false. - ELSE - hslt = ( a < b ) - end if - end function hslt - - ! -end subroutine hpsort_eps_epw - !---------------------------------------------------------------------------------------------------------------------------------- END MODULE AeroDyn_IO 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 c4e40d272b..698c57fe12 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -3631,6 +3631,10 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile CALL Cleanup() RETURN 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/hydrodyn/src/HydroDyn.f90 b/modules/hydrodyn/src/HydroDyn.f90 index 2c05caa186..86d5b0927c 100644 --- a/modules/hydrodyn/src/HydroDyn.f90 +++ b/modules/hydrodyn/src/HydroDyn.f90 @@ -450,7 +450,11 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I InputFileData%Waves%WaveFieldMod = InitInp%WaveFieldMod InputFileData%Waves%PtfmLocationX = InitInp%PtfmLocationX InputFileData%Waves%PtfmLocationY = InitInp%PtfmLocationY - + + ! Were visualization meshes requested? + p%VisMeshes = InitInp%VisMeshes + + ! Now call each sub-module's *_Init subroutine ! to fully initialize each sub-module based on the necessary initialization data @@ -493,6 +497,7 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I RETURN END IF tmpWaveElevXY = InitInp%WaveElevXY + CALL MOVE_ALLOC(tmpWaveElevXY, InputFileData%Waves%WaveElevXY) ! move this back for waves2 later ENDIF @@ -1366,9 +1371,11 @@ SUBROUTINE HydroDyn_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, I ELSE InputFileData%Morison%OutSwtch = 0 END IF + + ! Were visualization meshes requested? + InputFileData%Morison%VisMeshes = p%VisMeshes ! Initialize the Morison Element Calculations - CALL Morison_Init(InputFileData%Morison, u%Morison, p%Morison, x%Morison, xd%Morison, z%Morison, OtherState%Morison, & y%Morison, m%Morison, Interval, InitOut%Morison, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -2103,7 +2110,7 @@ SUBROUTINE HydroDyn_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, ErrStat, indxStart = (iBody-1)*6+1 indxEnd = indxStart+5 - m%F_PtfmAdd(indxStart:indxEnd) = p%AddF0(:,1) - matmul(p%AddCLin(:,:,iBody), q(indxStart:indxEnd)) - matmul(p%AddBLin(:,:,iBody), qdot(indxStart:indxEnd)) - matmul(p%AddBQuad(:,:,iBody), qdotsq(indxStart:indxEnd)) + m%F_PtfmAdd(indxStart:indxEnd) = p%AddF0(:,iBody) - matmul(p%AddCLin(:,:,iBody), q(indxStart:indxEnd)) - matmul(p%AddBLin(:,:,iBody), qdot(indxStart:indxEnd)) - matmul(p%AddBQuad(:,:,iBody), qdotsq(indxStart:indxEnd)) ! Attach to the output point mesh y%WAMITMesh%Force (:,iBody) = m%F_PtfmAdd(indxStart:indxStart+2) diff --git a/modules/hydrodyn/src/HydroDyn.txt b/modules/hydrodyn/src/HydroDyn.txt index 541a6dbcce..45a63e0c65 100644 --- a/modules/hydrodyn/src/HydroDyn.txt +++ b/modules/hydrodyn/src/HydroDyn.txt @@ -87,6 +87,7 @@ typedef ^ ^ SiKi typedef ^ ^ INTEGER WaveFieldMod - - - "Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin" - typedef ^ ^ ReKi PtfmLocationX - - - "Supplied by Driver: X coordinate of platform location in the wave field" "m" typedef ^ ^ ReKi PtfmLocationY - - - "Supplied by Driver: Y coordinate of platform location in the wave field" "m" +typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" - # # # Define outputs from the initialization routine here: @@ -218,6 +219,7 @@ typedef ^ ^ Integer typedef ^ ^ R8Ki du {:} - - "vector that determines size of perturbation for u (inputs)" - typedef ^ ^ R8Ki dx {:} - - "vector that determines size of perturbation for x (continuous states)" - typedef ^ ^ Integer Jac_ny - - - "number of outputs in jacobian matrix" - +typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" - # # # ..... Inputs .................................................................................................................... diff --git a/modules/hydrodyn/src/HydroDyn_Types.f90 b/modules/hydrodyn/src/HydroDyn_Types.f90 index 4777387fd3..f0bbf9b23a 100644 --- a/modules/hydrodyn/src/HydroDyn_Types.f90 +++ b/modules/hydrodyn/src/HydroDyn_Types.f90 @@ -98,6 +98,7 @@ MODULE HydroDyn_Types INTEGER(IntKi) :: WaveFieldMod !< Wave field handling (-) (switch) 0: use individual HydroDyn inputs without adjustment, 1: adjust wave phases based on turbine offsets from farm origin [-] REAL(ReKi) :: PtfmLocationX !< Supplied by Driver: X coordinate of platform location in the wave field [m] REAL(ReKi) :: PtfmLocationY !< Supplied by Driver: Y coordinate of platform location in the wave field [m] + LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-] END TYPE HydroDyn_InitInputType ! ======================= ! ========= HydroDyn_InitOutputType ======= @@ -224,6 +225,7 @@ MODULE HydroDyn_Types REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: du !< vector that determines size of perturbation for u (inputs) [-] REAL(R8Ki) , DIMENSION(:), ALLOCATABLE :: dx !< vector that determines size of perturbation for x (continuous states) [-] INTEGER(IntKi) :: Jac_ny !< number of outputs in jacobian matrix [-] + LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-] END TYPE HydroDyn_ParameterType ! ======================= ! ========= HydroDyn_InputType ======= @@ -1963,6 +1965,7 @@ SUBROUTINE HydroDyn_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, DstInitInputData%WaveFieldMod = SrcInitInputData%WaveFieldMod DstInitInputData%PtfmLocationX = SrcInitInputData%PtfmLocationX DstInitInputData%PtfmLocationY = SrcInitInputData%PtfmLocationY + DstInitInputData%VisMeshes = SrcInitInputData%VisMeshes END SUBROUTINE HydroDyn_CopyInitInput SUBROUTINE HydroDyn_DestroyInitInput( InitInputData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -2064,6 +2067,7 @@ SUBROUTINE HydroDyn_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Int_BufSz = Int_BufSz + 1 ! WaveFieldMod Re_BufSz = Re_BufSz + 1 ! PtfmLocationX Re_BufSz = Re_BufSz + 1 ! PtfmLocationY + Int_BufSz = Int_BufSz + 1 ! VisMeshes IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -2169,6 +2173,8 @@ SUBROUTINE HydroDyn_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%PtfmLocationY Re_Xferred = Re_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE HydroDyn_PackInitInput SUBROUTINE HydroDyn_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -2292,6 +2298,8 @@ SUBROUTINE HydroDyn_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta Re_Xferred = Re_Xferred + 1 OutData%PtfmLocationY = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE HydroDyn_UnPackInitInput SUBROUTINE HydroDyn_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) @@ -8122,6 +8130,7 @@ SUBROUTINE HydroDyn_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, Er DstParamData%dx = SrcParamData%dx ENDIF DstParamData%Jac_ny = SrcParamData%Jac_ny + DstParamData%VisMeshes = SrcParamData%VisMeshes END SUBROUTINE HydroDyn_CopyParam SUBROUTINE HydroDyn_DestroyParam( ParamData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -8421,6 +8430,7 @@ SUBROUTINE HydroDyn_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Db_BufSz = Db_BufSz + SIZE(InData%dx) ! dx END IF Int_BufSz = Int_BufSz + 1 ! Jac_ny + Int_BufSz = Int_BufSz + 1 ! VisMeshes IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -8897,6 +8907,8 @@ SUBROUTINE HydroDyn_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM END IF IntKiBuf(Int_Xferred) = InData%Jac_ny Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE HydroDyn_PackParam SUBROUTINE HydroDyn_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -9479,6 +9491,8 @@ SUBROUTINE HydroDyn_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E END IF OutData%Jac_ny = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE HydroDyn_UnPackParam SUBROUTINE HydroDyn_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) diff --git a/modules/hydrodyn/src/Morison.f90 b/modules/hydrodyn/src/Morison.f90 index 0d834adfa5..35c1a11dbe 100644 --- a/modules/hydrodyn/src/Morison.f90 +++ b/modules/hydrodyn/src/Morison.f90 @@ -1892,6 +1892,7 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In p%NMOutputs = InitInp%NMOutputs ! Number of members to output [ >=0 and <10] p%OutSwtch = InitInp%OutSwtch p%MSL2SWL = InitInp%MSL2SWL + p%VisMeshes = InitInp%VisMeshes ! visualization mesh for morison elements ALLOCATE ( p%MOutLst(p%NMOutputs), STAT = errStat ) IF ( errStat /= ErrID_None ) THEN @@ -2180,11 +2181,18 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In END IF + ! visualization Line2 mesh + if (p%VisMeshes) then + call VisMeshSetup(u,p,y,m,InitOut,ErrStat2,ErrMsg2); call SetErrStat( ErrStat2, ErrMsg2, errStat, errMsg, 'Morison_Init' ) + if ( errStat >= AbortErrLev ) return + endif + ! We will call CalcOutput to compute the loads for the initial reference position ! Then we can use the computed load components in the Summary File ! NOTE: Morison module has no states, otherwise we could no do this. GJH call Morison_CalcOutput(0.0_DbKi, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) + IF ( errStat > AbortErrLev ) RETURN ! Write Summary information now that everything has been initialized. CALL WriteSummaryFile( InitInp%UnSum, InitInp%Gravity, InitInp%MSL2SWL, InitInp%WtrDpth, InitInp%NJoints, InitInp%NNodes, InitInp%Nodes, p%NMembers, p%Members, & @@ -2198,6 +2206,106 @@ SUBROUTINE Morison_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, In ! END SUBROUTINE END SUBROUTINE Morison_Init +subroutine VisMeshSetup(u,p,y,m,InitOut,ErrStat,ErrMsg) + type(Morison_InputType), intent(inout) :: u + type(Morison_ParameterType), intent(in ) :: p + type(Morison_OutputType), intent(inout) :: y + type(Morison_MiscVarType), intent(inout) :: m + type(Morison_InitOutputType), intent(inout) :: InitOut + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + + integer(IntKi) :: TotNodes ! total nodes in all elements (may differ from p%NNodes due to overlaps) + integer(IntKi) :: TotElems ! total number of elements + integer(IntKi) :: NdIdx, iMem, iNd, NdNum ! indexing + real(ReKi) :: NdPos(3),Pos1(3),Pos2(3) + real(R8Ki) :: MemberOrient(3,3) + real(R8Ki) :: Theta(3) ! Euler rotations + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'VisMeshSetup' + + ErrStat = ErrID_None + ErrMsg = "" + + ! Total number of nodes = sum of all member nodes + ! Total number of elements = sum of all member elements + TotNodes=0 + TotElems=0 + do iMem=1,size(p%Members) + TotElems = TotElems + p%Members(iMem)%NElements + TotNodes = TotNodes + size(p%Members(iMem)%NodeIndx) + enddo + + ! Storage for the radius associated with each node + call AllocAry( InitOut%MorisonVisRad, TotNodes, 'MorisonVisRad', ErrStat2, ErrMsg2) + if (Failed()) return + + call MeshCreate( BlankMesh = y%VisMesh, & + IOS = COMPONENT_OUTPUT, & + Nnodes = TotNodes, & + ErrStat = ErrStat2, & + ErrMess = ErrMsg2, & + TranslationDisp = .TRUE., & + Orientation = .TRUE. ) + if (Failed()) return + + ! Position the nodes + NdNum=0 ! node number in y%VisMesh + do iMem=1,size(p%Members) + +!FIXME:MemberOrient This is not correct for non-circular or curved members + ! calculate an orientation using yaw-pitch-roll sequence with roll defined as zero (insufficient info) + Pos1=u%Mesh%Position(:,p%Members(iMem)%NodeIndx(1)) ! start node position of member + Pos2=u%Mesh%Position(:,p%Members(iMem)%NodeIndx(size(p%Members(iMem)%NodeIndx))) ! end node position of member + Theta(1) = 0.0_R8Ki ! roll (assumed since insufficient info) + Theta(2) = acos(real((Pos2(3)-Pos1(3))/norm2(Pos2-Pos1),R8Ki)) ! pitch + Theta(3) = atan2(real(Pos2(2)-Pos1(2),R8Ki),real(Pos2(1)-Pos1(1),R8Ki)) ! yaw + MemberOrient=EulerConstructZYX(Theta) ! yaw-pitch-roll sequence + + ! Set mesh postion, orientation, and radius + do iNd=1,size(p%Members(iMem)%NodeIndx) + NdNum=NdNum+1 ! node number in y%VisMesh + NdIdx = p%Members(iMem)%NodeIndx(iNd) ! node number in u%Mesh + NdPos = u%Mesh%Position(:,NdIdx) ! node position + call MeshPositionNode (y%VisMesh, NdNum, u%Mesh%Position(:,NdIdx), ErrStat2, ErrMsg2, Orient=MemberOrient) + if (Failed()) return + InitOut%MorisonVisRad(NdNum) = p%Members(iMem)%RMG(iNd) ! radius (including marine growth) for visualization + enddo + enddo + + ! make elements (line nodes start at 0 index, so N+1 total nodes) + NdNum=0 ! node number in y%VisMesh + do iMem=1,size(p%Members) + do iNd=1,size(p%Members(iMem)%NodeIndx) + NdNum=NdNum+1 ! node number in y%VisMesh + if (iNd==1) cycle + call MeshConstructElement ( Mesh = y%VisMesh, & + Xelement = ELEMENT_LINE2, & + P1=NdNum-1, P2=NdNum, & ! nodes to connect + errStat = ErrStat2, & + ErrMess = ErrMsg2 ) + if (Failed()) return + enddo + enddo + + ! commit the assembled mesh + call MeshCommit ( y%VisMesh, ErrStat2, ErrMsg2) + if (Failed()) return + + ! map the mesh to u%Mesh + call MeshMapCreate( u%Mesh, y%VisMesh, m%VisMeshMap, ErrStat2, ErrMsg2 ) + if (Failed()) return + +contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + !if (Failed) then + ! call FailCleanup() + !endif + end function Failed +end subroutine VisMeshSetup SUBROUTINE RodrigMat(a, R, errStat, errMsg) @@ -3313,8 +3421,15 @@ SUBROUTINE Morison_CalcOutput( Time, u, p, x, xd, z, OtherState, y, m, errStat, CALL MrsnOut_WriteOutputs( p%UnOutFile, Time, y, p, errStat, errMsg ) END IF END IF - - + + + ! map the motion to the visulization mesh + if (p%VisMeshes) then + !FIXME: error handling is incorrect here (overwrites all previous errors/warnings) + call Transfer_Point_to_Line2( u%Mesh, y%VisMesh, m%VisMeshMap, ErrStat, ErrMsg ) + endif + + END SUBROUTINE Morison_CalcOutput subroutine LumpDistrHydroLoads( f_hydro, k_hat, dl, h_c, lumpedLoad ) diff --git a/modules/hydrodyn/src/Morison.txt b/modules/hydrodyn/src/Morison.txt index 2943d32c35..c59db0b043 100644 --- a/modules/hydrodyn/src/Morison.txt +++ b/modules/hydrodyn/src/Morison.txt @@ -256,12 +256,13 @@ typedef ^ ^ SiKi typedef ^ ^ SiKi WaveDynP {:}{:} - - "" - typedef ^ ^ SiKi WaveVel {:}{:}{:} - - "" - typedef ^ ^ INTEGER nodeInWater {:}{:} - - "Logical flag indicating if the node at the given time step is in the water, and hence needs to have hydrodynamic forces calculated" - +typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" - # # # Define outputs from the initialization routine here: # #typedef ^ InitOutputType MeshType Mesh - - - "Unused?" - -#typedef ^ ^ SiKi Morison_Rad {:} - - "radius of node (for FAST visualization)" (m) +typedef ^ InitOutputType SiKi MorisonVisRad {:} - - "radius of node (for FAST visualization)" (m) typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "User-requested Output channel names" - typedef ^ ^ CHARACTER(ChanLen) WriteOutputUnt {:} - - "" - # @@ -310,6 +311,7 @@ typedef ^ ^ ReKi typedef ^ ^ ReKi F_A_End {:}{:} - - "Lumped added mass loads at time t, which may not correspond to the WaveTime array of times" - typedef ^ ^ ReKi F_BF_End {:}{:} - - "" - typedef ^ ^ INTEGER LastIndWave - - - "Last time index used in the wave kinematics arrays" - +typedef ^ ^ MeshMapType VisMeshMap - - - "Mesh mapping for visualization mesh" - # ..... Parameters ................................................................................................................ # Define parameters here: @@ -349,6 +351,7 @@ typedef ^ ^ INTEGER typedef ^ ^ CHARACTER(20) OutFmt - - - "" - typedef ^ ^ CHARACTER(20) OutSFmt - - - "" - typedef ^ ^ CHARACTER(ChanLen) Delim - - - "" - +typedef ^ ^ logical VisMeshes - .false. - "Output visualization meshes" - # # # ..... Inputs .................................................................................................................... @@ -360,4 +363,5 @@ typedef ^ InputType MeshType # ..... Outputs ................................................................................................................... # Define outputs that are contained on the mesh here: typedef ^ OutputType MeshType Mesh - - - "Loads on each node output mesh" - +typedef ^ ^ MeshType VisMesh - - - "Line mesh for visualization" - typedef ^ ^ ReKi WriteOutput {:} - - "" - diff --git a/modules/hydrodyn/src/Morison_Types.f90 b/modules/hydrodyn/src/Morison_Types.f90 index 8f1ca39fd1..bfa9d65c53 100644 --- a/modules/hydrodyn/src/Morison_Types.f90 +++ b/modules/hydrodyn/src/Morison_Types.f90 @@ -319,10 +319,12 @@ MODULE Morison_Types REAL(SiKi) , DIMENSION(:,:), ALLOCATABLE :: WaveDynP !< [-] REAL(SiKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveVel !< [-] INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: nodeInWater !< Logical flag indicating if the node at the given time step is in the water, and hence needs to have hydrodynamic forces calculated [-] + LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-] END TYPE Morison_InitInputType ! ======================= ! ========= Morison_InitOutputType ======= TYPE, PUBLIC :: Morison_InitOutputType + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: MorisonVisRad !< radius of node (for FAST visualization) [(m)] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< User-requested Output channel names [-] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< [-] END TYPE Morison_InitOutputType @@ -362,6 +364,7 @@ MODULE Morison_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: F_A_End !< Lumped added mass loads at time t, which may not correspond to the WaveTime array of times [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: F_BF_End !< [-] INTEGER(IntKi) :: LastIndWave !< Last time index used in the wave kinematics arrays [-] + TYPE(MeshMapType) :: VisMeshMap !< Mesh mapping for visualization mesh [-] END TYPE Morison_MiscVarType ! ======================= ! ========= Morison_ParameterType ======= @@ -400,6 +403,7 @@ MODULE Morison_Types CHARACTER(20) :: OutFmt !< [-] CHARACTER(20) :: OutSFmt !< [-] CHARACTER(ChanLen) :: Delim !< [-] + LOGICAL :: VisMeshes = .false. !< Output visualization meshes [-] END TYPE Morison_ParameterType ! ======================= ! ========= Morison_InputType ======= @@ -410,6 +414,7 @@ MODULE Morison_Types ! ========= Morison_OutputType ======= TYPE, PUBLIC :: Morison_OutputType TYPE(MeshType) :: Mesh !< Loads on each node output mesh [-] + TYPE(MeshType) :: VisMesh !< Line mesh for visualization [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< [-] END TYPE Morison_OutputType ! ======================= @@ -6337,6 +6342,7 @@ SUBROUTINE Morison_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, END IF DstInitInputData%nodeInWater = SrcInitInputData%nodeInWater ENDIF + DstInitInputData%VisMeshes = SrcInitInputData%VisMeshes END SUBROUTINE Morison_CopyInitInput SUBROUTINE Morison_DestroyInitInput( InitInputData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -6813,6 +6819,7 @@ SUBROUTINE Morison_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E Int_BufSz = Int_BufSz + 2*2 ! nodeInWater upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%nodeInWater) ! nodeInWater END IF + Int_BufSz = Int_BufSz + 1 ! VisMeshes IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -7491,6 +7498,8 @@ SUBROUTINE Morison_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, E END DO END DO END IF + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE Morison_PackInitInput SUBROUTINE Morison_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -8358,6 +8367,8 @@ SUBROUTINE Morison_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat END DO END DO END IF + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE Morison_UnPackInitInput SUBROUTINE Morison_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) @@ -8375,6 +8386,18 @@ SUBROUTINE Morison_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCod ! ErrStat = ErrID_None ErrMsg = "" +IF (ALLOCATED(SrcInitOutputData%MorisonVisRad)) THEN + i1_l = LBOUND(SrcInitOutputData%MorisonVisRad,1) + i1_u = UBOUND(SrcInitOutputData%MorisonVisRad,1) + IF (.NOT. ALLOCATED(DstInitOutputData%MorisonVisRad)) THEN + ALLOCATE(DstInitOutputData%MorisonVisRad(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInitOutputData%MorisonVisRad.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstInitOutputData%MorisonVisRad = SrcInitOutputData%MorisonVisRad +ENDIF IF (ALLOCATED(SrcInitOutputData%WriteOutputHdr)) THEN i1_l = LBOUND(SrcInitOutputData%WriteOutputHdr,1) i1_u = UBOUND(SrcInitOutputData%WriteOutputHdr,1) @@ -8422,6 +8445,9 @@ SUBROUTINE Morison_DestroyInitOutput( InitOutputData, ErrStat, ErrMsg, DEALLOCAT DEALLOCATEpointers_local = .true. END IF +IF (ALLOCATED(InitOutputData%MorisonVisRad)) THEN + DEALLOCATE(InitOutputData%MorisonVisRad) +ENDIF IF (ALLOCATED(InitOutputData%WriteOutputHdr)) THEN DEALLOCATE(InitOutputData%WriteOutputHdr) ENDIF @@ -8465,6 +8491,11 @@ SUBROUTINE Morison_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Re_BufSz = 0 Db_BufSz = 0 Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! MorisonVisRad allocated yes/no + IF ( ALLOCATED(InData%MorisonVisRad) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! MorisonVisRad upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%MorisonVisRad) ! MorisonVisRad + END IF Int_BufSz = Int_BufSz + 1 ! WriteOutputHdr allocated yes/no IF ( ALLOCATED(InData%WriteOutputHdr) ) THEN Int_BufSz = Int_BufSz + 2*1 ! WriteOutputHdr upper/lower bounds for each dimension @@ -8502,6 +8533,21 @@ SUBROUTINE Morison_PackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Db_Xferred = 1 Int_Xferred = 1 + IF ( .NOT. ALLOCATED(InData%MorisonVisRad) ) 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%MorisonVisRad,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%MorisonVisRad,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%MorisonVisRad,1), UBOUND(InData%MorisonVisRad,1) + ReKiBuf(Re_Xferred) = InData%MorisonVisRad(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( .NOT. ALLOCATED(InData%WriteOutputHdr) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -8565,6 +8611,24 @@ SUBROUTINE Morison_UnPackInitOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta Re_Xferred = 1 Db_Xferred = 1 Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! MorisonVisRad 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%MorisonVisRad)) DEALLOCATE(OutData%MorisonVisRad) + ALLOCATE(OutData%MorisonVisRad(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%MorisonVisRad.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%MorisonVisRad,1), UBOUND(OutData%MorisonVisRad,1) + OutData%MorisonVisRad(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO + END IF IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutputHdr not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -9156,7 +9220,7 @@ SUBROUTINE Morison_UnPackOtherState( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrSta END SUBROUTINE Morison_UnPackOtherState SUBROUTINE Morison_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg ) - TYPE(Morison_MiscVarType), INTENT(IN) :: SrcMiscData + TYPE(Morison_MiscVarType), INTENT(INOUT) :: SrcMiscData TYPE(Morison_MiscVarType), INTENT(INOUT) :: DstMiscData INTEGER(IntKi), INTENT(IN ) :: CtrlCode INTEGER(IntKi), INTENT( OUT) :: ErrStat @@ -9338,6 +9402,9 @@ SUBROUTINE Morison_CopyMisc( SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg DstMiscData%F_BF_End = SrcMiscData%F_BF_End ENDIF DstMiscData%LastIndWave = SrcMiscData%LastIndWave + CALL NWTC_Library_Copymeshmaptype( SrcMiscData%VisMeshMap, DstMiscData%VisMeshMap, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN END SUBROUTINE Morison_CopyMisc SUBROUTINE Morison_DestroyMisc( MiscData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -9401,6 +9468,8 @@ SUBROUTINE Morison_DestroyMisc( MiscData, ErrStat, ErrMsg, DEALLOCATEpointers ) IF (ALLOCATED(MiscData%F_BF_End)) THEN DEALLOCATE(MiscData%F_BF_End) ENDIF + CALL NWTC_Library_Destroymeshmaptype( MiscData%VisMeshMap, ErrStat2, ErrMsg2, DEALLOCATEpointers_local ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) END SUBROUTINE Morison_DestroyMisc SUBROUTINE Morison_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) @@ -9518,6 +9587,23 @@ SUBROUTINE Morison_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Re_BufSz = Re_BufSz + SIZE(InData%F_BF_End) ! F_BF_End END IF Int_BufSz = Int_BufSz + 1 ! LastIndWave + Int_BufSz = Int_BufSz + 3 ! VisMeshMap: size of buffers for each call to pack subtype + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%VisMeshMap, ErrStat2, ErrMsg2, .TRUE. ) ! VisMeshMap + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisMeshMap + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisMeshMap + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisMeshMap + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -9798,6 +9884,34 @@ SUBROUTINE Morison_PackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg END IF IntKiBuf(Int_Xferred) = InData%LastIndWave Int_Xferred = Int_Xferred + 1 + CALL NWTC_Library_Packmeshmaptype( Re_Buf, Db_Buf, Int_Buf, InData%VisMeshMap, ErrStat2, ErrMsg2, OnlySize ) ! VisMeshMap + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF END SUBROUTINE Morison_PackMisc SUBROUTINE Morison_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -10129,6 +10243,46 @@ SUBROUTINE Morison_UnPackMisc( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err END IF OutData%LastIndWave = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL NWTC_Library_Unpackmeshmaptype( Re_Buf, Db_Buf, Int_Buf, OutData%VisMeshMap, ErrStat2, ErrMsg2 ) ! VisMeshMap + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END SUBROUTINE Morison_UnPackMisc SUBROUTINE Morison_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) @@ -10400,6 +10554,7 @@ SUBROUTINE Morison_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, Err DstParamData%OutFmt = SrcParamData%OutFmt DstParamData%OutSFmt = SrcParamData%OutSFmt DstParamData%Delim = SrcParamData%Delim + DstParamData%VisMeshes = SrcParamData%VisMeshes END SUBROUTINE Morison_CopyParam SUBROUTINE Morison_DestroyParam( ParamData, ErrStat, ErrMsg, DEALLOCATEpointers ) @@ -10695,6 +10850,7 @@ SUBROUTINE Morison_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs Int_BufSz = Int_BufSz + 1*LEN(InData%OutFmt) ! OutFmt Int_BufSz = Int_BufSz + 1*LEN(InData%OutSFmt) ! OutSFmt Int_BufSz = Int_BufSz + 1*LEN(InData%Delim) ! Delim + Int_BufSz = Int_BufSz + 1 ! VisMeshes IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -11173,6 +11329,8 @@ SUBROUTINE Morison_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMs IntKiBuf(Int_Xferred) = ICHAR(InData%Delim(I:I), IntKi) Int_Xferred = Int_Xferred + 1 END DO ! I + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE Morison_PackParam SUBROUTINE Morison_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) @@ -11751,6 +11909,8 @@ SUBROUTINE Morison_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Er OutData%Delim(I:I) = CHAR(IntKiBuf(Int_Xferred)) Int_Xferred = Int_Xferred + 1 END DO ! I + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 END SUBROUTINE Morison_UnPackParam SUBROUTINE Morison_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) @@ -11993,6 +12153,9 @@ SUBROUTINE Morison_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, CALL MeshCopy( SrcOutputData%Mesh, DstOutputData%Mesh, CtrlCode, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ErrStat>=AbortErrLev) RETURN + CALL MeshCopy( SrcOutputData%VisMesh, DstOutputData%VisMesh, CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN IF (ALLOCATED(SrcOutputData%WriteOutput)) THEN i1_l = LBOUND(SrcOutputData%WriteOutput,1) i1_u = UBOUND(SrcOutputData%WriteOutput,1) @@ -12030,6 +12193,8 @@ SUBROUTINE Morison_DestroyOutput( OutputData, ErrStat, ErrMsg, DEALLOCATEpointer CALL MeshDestroy( OutputData%Mesh, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL MeshDestroy( OutputData%VisMesh, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) IF (ALLOCATED(OutputData%WriteOutput)) THEN DEALLOCATE(OutputData%WriteOutput) ENDIF @@ -12088,6 +12253,23 @@ SUBROUTINE Morison_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Int_BufSz = Int_BufSz + SIZE( Int_Buf ) DEALLOCATE(Int_Buf) END IF + Int_BufSz = Int_BufSz + 3 ! VisMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%VisMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! VisMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF Int_BufSz = Int_BufSz + 1 ! WriteOutput allocated yes/no IF ( ALLOCATED(InData%WriteOutput) ) THEN Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension @@ -12148,6 +12330,34 @@ SUBROUTINE Morison_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM ELSE IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 ENDIF + CALL MeshPack( InData%VisMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! VisMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF IF ( .NOT. ALLOCATED(InData%WriteOutput) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -12232,6 +12442,46 @@ SUBROUTINE Morison_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%VisMesh, Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! VisMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WriteOutput not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -12503,6 +12753,8 @@ SUBROUTINE Morison_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, Er ScaleFactor = t_out / t(2) CALL MeshExtrapInterp1(y1%Mesh, y2%Mesh, tin, y_out%Mesh, tin_out, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp1(y1%VisMesh, y2%VisMesh, tin, y_out%VisMesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) b = -(y1%WriteOutput(i1) - y2%WriteOutput(i1)) @@ -12568,6 +12820,8 @@ SUBROUTINE Morison_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat ScaleFactor = t_out / (t(2) * t(3) * (t(2) - t(3))) CALL MeshExtrapInterp2(y1%Mesh, y2%Mesh, y3%Mesh, tin, y_out%Mesh, tin_out, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + CALL MeshExtrapInterp2(y1%VisMesh, y2%VisMesh, y3%VisMesh, tin, y_out%VisMesh, tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) IF (ALLOCATED(y_out%WriteOutput) .AND. ALLOCATED(y1%WriteOutput)) THEN DO i1 = LBOUND(y_out%WriteOutput,1),UBOUND(y_out%WriteOutput,1) b = (t(3)**2*(y1%WriteOutput(i1) - y2%WriteOutput(i1)) + t(2)**2*(-y1%WriteOutput(i1) + y3%WriteOutput(i1)))* scaleFactor diff --git a/modules/inflowwind/src/IfW_FlowField.f90 b/modules/inflowwind/src/IfW_FlowField.f90 index 0d07e55f5d..a71b75dffc 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,32 @@ 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 + ! Take modulus of negative grid to get positive value between 0 and NSteps + T_GRID = MODULO(T_GRID, real(G3D%NSteps, ReKi)) + ! For very small negative numbers, the above modulus will return exactly NSteps + ! so take modulus again to ensure that T_GRID is less than NSteps + 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,13 +1266,13 @@ 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 call SetErrStat(ErrID_Fatal, ' Error: GF wind array was exhausted at '// & TRIM(Num2LStr(TIME))//' seconds (trying to access data at '// & - TRIM(Num2LStr(TimeShifted))//' seconds).', & + TRIM(Num2LStr(TimeShifted))//' seconds). IT_Lo='//TRIM(Num2LStr(IT_Lo))// & + ', IT_HI='//TRIM(Num2LStr(IT_Hi)), & ErrStat, ErrMsg, RoutineName) end if @@ -1529,6 +1527,7 @@ subroutine IfW_Grid3DField_CalcVelAvgProfile(G3D, CalcAccel, ErrStat, ErrMsg) character(*), parameter :: RoutineName = 'IfW_Grid3DField_CalcVelAvgProfile' integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 + integer(IntKi) :: it, iz, ic ErrStat = ErrID_None ErrMsg = "" @@ -1543,7 +1542,13 @@ subroutine IfW_Grid3DField_CalcVelAvgProfile(G3D, CalcAccel, ErrStat, ErrMsg) end if ! Calculate average velocity for each component across grid (Y) - G3D%VelAvg = sum(G3D%Vel, dim=2)/G3D%NYGrids + do it = 1, G3D%NSteps + do iz = 1, G3D%NZGrids + do ic = 1, G3D%NComp + G3D%VelAvg(ic,iz,it) = sum(G3D%Vel(ic,:,iz,it))/real(G3D%NYGrids, SiKi) + end do + end do + end do ! If acceleration calculation not requested, return if (.not. CalcAccel) return @@ -1556,9 +1561,15 @@ subroutine IfW_Grid3DField_CalcVelAvgProfile(G3D, CalcAccel, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return G3D%AccAvg = 0.0_SiKi end if - + ! Calculate average acceleration for each component across grid (Y) - G3D%AccAvg = sum(G3D%Acc, dim=2)/G3D%NYGrids + do it = 1, G3D%NSteps + do iz = 1, G3D%NZGrids + do ic = 1, G3D%NComp + G3D%AccAvg(ic,iz,it) = sum(G3D%Acc(ic,:,iz,it))/real(G3D%NYGrids, SiKi) + end do + end do + end do end subroutine @@ -1589,7 +1600,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..103ddb948b 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() @@ -518,7 +516,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons end if ! Calculate field average if box is allowed to be exceeded - if (p%FlowField%Grid3D%BoxExceedAllowF .and. p%FlowField%Grid3D%BoxExceedAllowIdx > 0) then + if (p%FlowField%Grid3D%BoxExceedAllowF) then call IfW_Grid3DField_CalcVelAvgProfile(p%FlowField%Grid3D, p%FlowField%AccFieldValid, TmpErrStat, TmpErrMsg) call SetErrStat(TmpErrStat, TmpErrMsg, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return 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 122d8a5cec..e1b0f64547 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 ed69082636..de910b24c8 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/map/src/lineroutines.c b/modules/map/src/lineroutines.c index 30fad7a27e..ba89c7b5bd 100644 --- a/modules/map/src/lineroutines.c +++ b/modules/map/src/lineroutines.c @@ -667,7 +667,7 @@ MAP_ERROR_CODE solve_linear_spring_cable(Line* line, char* map_msg, MAP_ERROR_CO }; *(line->H.value) = sqrt(force.x*force.x + force.y*force.y); - *(line->V.value) = fabs(force.z); + *(line->V.value) = -force.z; /* vertical force can be positive or negative. Important for systems with the anchor point above the fairlead connection */ return MAP_SAFE; }; diff --git a/modules/moordyn/src/MoorDyn.f90 b/modules/moordyn/src/MoorDyn.f90 index d378015b22..3c6919ca45 100644 --- a/modules/moordyn/src/MoorDyn.f90 +++ b/modules/moordyn/src/MoorDyn.f90 @@ -194,6 +194,7 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er p%mu_kA = 0.0_DbKi p%mc = 1.0_DbKi p%cv = 200.0_DbKi + p%VisMeshes = InitInp%VisMeshes ! Visualization meshes requested by glue code DepthValue = "" ! Start off as empty string, to only be filled if MD setting is specified (otherwise InitInp%WtrDepth is used) ! DepthValue and InitInp%WtrDepth are processed later by setupBathymetry. WaterKinValue = "" @@ -931,8 +932,8 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er CALL Body_AddRod(m%GroundBody, l, tempArray) ! add rod l to Ground body - else if ((let1 == "PINNED") .or. (let1 == "PIN")) then - m%RodList(l)%typeNum = 1 + else if ((let1 == "PINNED") .or. (let1 == "PIN")) then + m%RodList(l)%typeNum = 1 CALL Body_AddRod(m%GroundBody, l, tempArray) ! add rod l to Ground body p%nFreeRods=p%nFreeRods+1 ! add this pinned rod to the free list because it is half free @@ -2212,6 +2213,19 @@ SUBROUTINE MD_Init(InitInp, u, p, x, xd, z, other, y, m, DTcoupling, InitOut, Er ! TODO: add feature for automatic water depth increase based on max anchor depth! + + !-------------------------------------------------- + ! initialize line visualization meshes if needed + if (p%VisMeshes) then + if (p%NLines > 0) then + call VisLinesMesh_Init(p,m,y,ErrStat2,ErrMsg2); if(Failed()) return + endif + if (p%NRods > 0) then + call VisRodsMesh_Init(p,m,y,ErrStat2,ErrMsg2); if(Failed()) return + endif + endif + + CONTAINS @@ -2257,12 +2271,12 @@ SUBROUTINE CheckError(ErrID,Msg) IF ( ErrStat >= AbortErrLev ) THEN - IF (ALLOCATED(m%CpldPointIs )) DEALLOCATE(m%CpldPointIs ) - IF (ALLOCATED(m%FreePointIs )) DEALLOCATE(m%FreePointIs ) + IF (ALLOCATED(m%CpldPointIs )) DEALLOCATE(m%CpldPointIs ) + IF (ALLOCATED(m%FreePointIs )) DEALLOCATE(m%FreePointIs ) IF (ALLOCATED(m%LineStateIs1 )) DEALLOCATE(m%LineStateIs1 ) IF (ALLOCATED(m%LineStateIsN )) DEALLOCATE(m%LineStateIsN ) - IF (ALLOCATED(m%PointStateIs1 )) DEALLOCATE(m%PointStateIs1 ) - IF (ALLOCATED(m%PointStateIsN )) DEALLOCATE(m%PointStateIsN ) + IF (ALLOCATED(m%PointStateIs1 )) DEALLOCATE(m%PointStateIs1 ) + IF (ALLOCATED(m%PointStateIsN )) DEALLOCATE(m%PointStateIsN ) IF (ALLOCATED(x%states )) DEALLOCATE(x%states ) IF (ALLOCATED(FairTensIC )) DEALLOCATE(FairTensIC ) @@ -2613,6 +2627,20 @@ SUBROUTINE MD_CalcOutput( t, u, p, x, xd, z, other, y, m, ErrStat, ErrMsg ) ! IF ( ErrStat >= AbortErrLev ) RETURN + !-------------------------------------------------- + ! update line visualization meshes if needed + if (p%VisMeshes) then + if (p%NLines > 0) then + call VisLinesMesh_Update(p,m,y,ErrStat2,ErrMsg2) + call CheckError(ErrStat2, ErrMsg2) + if ( ErrStat >= AbortErrLev ) return + endif + if (p%NRods > 0) then + call VisRodsMesh_Update(p,m,y,ErrStat2,ErrMsg2) + call CheckError(ErrStat2, ErrMsg2) + if ( ErrStat >= AbortErrLev ) return + endif + endif CONTAINS diff --git a/modules/moordyn/src/MoorDyn_Line.f90 b/modules/moordyn/src/MoorDyn_Line.f90 index 3235c4e738..21cd2d71ef 100644 --- a/modules/moordyn/src/MoorDyn_Line.f90 +++ b/modules/moordyn/src/MoorDyn_Line.f90 @@ -39,7 +39,8 @@ MODULE MoorDyn_Line PUBLIC :: Line_GetEndStuff PUBLIC :: Line_GetEndSegmentInfo PUBLIC :: Line_SetEndOrientation - + public :: VisLinesMesh_Init + public :: VisLinesMesh_Update CONTAINS @@ -1661,5 +1662,94 @@ SUBROUTINE Line_SetEndOrientation(Line, qin, topOfLine, rodEndB) END SUBROUTINE Line_SetEndOrientation !-------------------------------------------------------------- + subroutine VisLinesMesh_Init(p,m,y,ErrStat,ErrMsg) + type(MD_ParameterType), intent(in ) :: p + type(MD_MiscVarType), intent(in ) :: m + type(MD_OutputType), intent(inout) :: y + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + integer(IntKi) :: i,l + character(*), parameter :: RoutineName = 'VisLinesMesh_Init' + + ErrStat = ErrID_None + ErrMsg = '' + + ! allocate line2 mesh for all lines + allocate (y%VisLinesMesh(p%NLines), STAT=ErrStat2); if (Failed0('visualization mesh for lines')) return + + ! Initialize mesh for each line (line nodes start at 0 index, so N+1 total nodes) + do l=1,p%NLines + CALL MeshCreate( BlankMesh = y%VisLinesMesh(l), & + NNodes = m%LineList(l)%N+1, & + IOS = COMPONENT_OUTPUT, & + TranslationDisp = .true., & + ErrStat=ErrStat2, ErrMess=ErrMsg2) + if (Failed()) return + + ! Internal nodes (line nodes start at 0 index) + do i = 0,m%LineList(l)%N + call MeshPositionNode ( y%VisLinesMesh(l), i+1, real(m%LineList(l)%r(:,I),ReKi), ErrStat2, ErrMsg2 ) + if (Failed()) return + enddo + + ! make elements (line nodes start at 0 index, so N+1 total nodes) + do i = 2,m%LineList(l)%N+1 + call MeshConstructElement ( Mesh = y%VisLinesMesh(l) & + , Xelement = ELEMENT_LINE2 & + , P1 = i-1 & ! node1 number + , P2 = i & ! node2 number + , ErrStat = ErrStat2 & + , ErrMess = ErrMsg2 ) + if (Failed()) return + enddo + + ! Commit mesh + call MeshCommit ( y%VisLinesMesh(l), ErrStat2, ErrMsg2 ) + if (Failed()) return + enddo + contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + + ! check for failed where /= 0 is fatal + logical function Failed0(txt) + character(*), intent(in) :: txt + if (errStat /= 0) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "Could not allocate "//trim(txt) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif + Failed0 = ErrStat >= AbortErrLev + end function Failed0 + end subroutine VisLinesMesh_Init + + + + subroutine VisLinesMesh_Update(p,m,y,ErrStat,ErrMsg) + type(MD_ParameterType), intent(in ) :: p + type(MD_MiscVarType), intent(in ) :: m + type(MD_OutputType), intent(inout) :: y + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: i,l + character(*), parameter :: RoutineName = 'VisLinesMesh_Update' + + ErrStat = ErrID_None + ErrMsg = '' + + ! Initialize mesh for each line (line nodes start at 0 index, so N+1 total nodes) + do l=1,p%NLines + ! Update node positions nodes (line nodes start at 0 index) + do i = 0,m%LineList(l)%N + y%VisLinesMesh(l)%TranslationDisp(:,i+1) = real(m%LineList(l)%r(:,I),ReKi) - y%VisLinesMesh(l)%Position(:,i+1) + enddo + enddo + end subroutine VisLinesMesh_Update + + END MODULE MoorDyn_Line diff --git a/modules/moordyn/src/MoorDyn_Registry.txt b/modules/moordyn/src/MoorDyn_Registry.txt index 60a78f2676..e221bb7bfc 100644 --- a/modules/moordyn/src/MoorDyn_Registry.txt +++ b/modules/moordyn/src/MoorDyn_Registry.txt @@ -34,6 +34,7 @@ typedef ^ ^ FileInfoType PassedPrimaryInputData typedef ^ ^ LOGICAL Echo - "" - "echo parameter - do we want to echo the header line describing the input file?" typedef ^ ^ CHARACTER(ChanLen) OutList {:} "" - "string containing list of output channels requested in input file" typedef ^ ^ Logical Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - +typedef ^ ^ Logical VisMeshes - .FALSE. - "Glue code requesting visualization meshes" - #typedef ^ ^ DbKi UGrid {:}{:}{:} - - "water velocities time series at each grid point" - #typedef ^ ^ DbKi UdGrid {:}{:}{:} - - "water accelerations time series at each grid point" - @@ -282,6 +283,8 @@ typedef ^ ^ IntKi OType - typedef ^ ^ IntKi NodeID - - - "node number if OType=0. 0=anchor, -1=N=Fairlead" typedef ^ ^ IntKi ObjID - - - "number of Point or Line object" +## ============================== Visualization data storage for diameter ============================================================================================================================ +typedef ^ VisDiam SiKi Diam {:} - - "Diameter for visualization" - ## ============================== Define Initialization outputs here: ================================================================================================================================ typedef ^ InitOutputType CHARACTER(ChanLen) writeOutputHdr {:} "" - "first line output file contents: output variable names" @@ -422,6 +425,8 @@ typedef ^ ^ R8Ki dx {:} typedef ^ ^ Integer Jac_ny - - - "number of outputs in jacobian matrix" - typedef ^ ^ Integer Jac_nx - - - "number of continuous states in jacobian matrix" - typedef ^ ^ Integer dxIdx_map2_xStateIdx {:} - - "Mapping array from index of dX array to corresponding state index" - +typedef ^ ^ Logical VisMeshes - - - "Using visualization meshes as requested by glue code" - +typedef ^ ^ VisDiam VisRodsDiam {:} - - "Diameters for visualization of rods" - # ============================== Inputs ============================================================================================================================================ @@ -439,3 +444,7 @@ typedef ^ OutputType MeshType CoupledLoads {:} typedef ^ ^ ReKi WriteOutput {:} - - "output vector returned to glue code" "" # should CoupledLoads be an array? #typedef ^ ^ DbKi rAll {:}{:} - - "Mesh of all point positions: bodies, rods, points, line internal nodes" - +typedef ^ ^ MeshType VisLinesMesh {:} - - "Line2 mesh for visualizing mooring lines" - +typedef ^ ^ MeshType VisRodsMesh {:} - - "Line2 mesh for visualizing mooring rods" - +typedef ^ ^ MeshType VisBodiesMesh {:} - - "Point mesh for visualizing mooring bodies" - +typedef ^ ^ MeshType VisAnchsMesh {:} - - "Point mesh for visualizing mooring anchors" - diff --git a/modules/moordyn/src/MoorDyn_Rod.f90 b/modules/moordyn/src/MoorDyn_Rod.f90 index dca892ffff..f7f25e4d93 100644 --- a/modules/moordyn/src/MoorDyn_Rod.f90 +++ b/modules/moordyn/src/MoorDyn_Rod.f90 @@ -42,9 +42,11 @@ MODULE MoorDyn_Rod PUBLIC :: Rod_GetNetForceAndMass PUBLIC :: Rod_AddLine PUBLIC :: Rod_RemoveLine + public :: VisRodsMesh_Init + public :: VisRodsMesh_Update + - CONTAINS @@ -1190,5 +1192,102 @@ END SUBROUTINE Rod_RemoveLine + subroutine VisRodsMesh_Init(p,m,y,ErrStat,ErrMsg) + type(MD_ParameterType), intent(inout) :: p + type(MD_MiscVarType), intent(in ) :: m + type(MD_OutputType), intent(inout) :: y + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + integer(IntKi) :: i,l + character(*), parameter :: RoutineName = 'VisRodsMesh_Init' + + ErrStat = ErrID_None + ErrMsg = '' + + ! allocate line2 mesh for all lines + allocate (y%VisRodsMesh(p%NRods), STAT=ErrStat2); if (Failed0('visualization mesh for lines')) return + allocate (p%VisRodsDiam(p%NRods), STAT=ErrStat2); if (Failed0('visualization mesh for lines')) return + + ! Initialize mesh for each line (line nodes start at 0 index, so N+1 total nodes) + do l=1,p%NRods + CALL MeshCreate( BlankMesh = y%VisRodsMesh(l), & + NNodes = m%RodList(l)%N+1, & + IOS = COMPONENT_OUTPUT, & + TranslationDisp = .true., & + Orientation = .true., & + ErrStat=ErrStat2, ErrMess=ErrMsg2) + if (Failed()) return + + ! Internal nodes (line nodes start at 0 index) + do i = 0,m%RodList(l)%N + call MeshPositionNode ( y%VisRodsMesh(l), i+1, real(m%RodList(l)%r(:,I),ReKi), ErrStat2, ErrMsg2, Orient=real(m%RodList(l)%OrMat,R8Ki)) + if (Failed()) return + enddo + + ! make elements (line nodes start at 0 index, so N+1 total nodes) + do i = 2,m%RodList(l)%N+1 + call MeshConstructElement ( Mesh = y%VisRodsMesh(l) & + , Xelement = ELEMENT_LINE2 & + , P1 = i-1 & ! node1 number + , P2 = i & ! node2 number + , ErrStat = ErrStat2 & + , ErrMess = ErrMsg2 ) + if (Failed()) return + enddo + + ! Commit mesh + call MeshCommit ( y%VisRodsMesh(l), ErrStat2, ErrMsg2 ) + if (Failed()) return + + ! Set rod diameter for visualization + call AllocAry(p%VisRodsDiam(l)%Diam,m%RodList(l)%N+1,'',ErrStat2,ErrMsg2) + if (Failed()) return + p%VisRodsDiam(l)%Diam=real(m%RodTypeList(m%RodList(l)%PropsIdNum)%d,SiKi) + enddo + contains + logical function Failed() + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + Failed = ErrStat >= AbortErrLev + end function Failed + + ! check for failed where /= 0 is fatal + logical function Failed0(txt) + character(*), intent(in) :: txt + if (errStat /= 0) then + ErrStat2 = ErrID_Fatal + ErrMsg2 = "Could not allocate "//trim(txt) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + endif + Failed0 = ErrStat >= AbortErrLev + end function Failed0 + end subroutine VisRodsMesh_Init + + + + subroutine VisRodsMesh_Update(p,m,y,ErrStat,ErrMsg) + type(MD_ParameterType), intent(in ) :: p + type(MD_MiscVarType), intent(in ) :: m + type(MD_OutputType), intent(inout) :: y + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + integer(IntKi) :: i,l + character(*), parameter :: RoutineName = 'VisRodsMesh_Update' + + ErrStat = ErrID_None + ErrMsg = '' + + do l=1,p%NRods + ! Update rod positions/orientations + do i = 0,m%RodList(l)%N + y%VisRodsMesh(l)%TranslationDisp(:,i+1) = real(m%RodList(l)%r(:,I),ReKi) - y%VisRodsMesh(l)%Position(:,i+1) + y%VisRodsMesh(l)%Orientation(:,:,i+1) = real(m%RodList(l)%OrMat,R8Ki) + enddo + enddo + end subroutine VisRodsMesh_Update + + + END MODULE MoorDyn_Rod diff --git a/modules/moordyn/src/MoorDyn_Types.f90 b/modules/moordyn/src/MoorDyn_Types.f90 index a786b07300..6d00b2a689 100644 --- a/modules/moordyn/src/MoorDyn_Types.f90 +++ b/modules/moordyn/src/MoorDyn_Types.f90 @@ -57,6 +57,7 @@ MODULE MoorDyn_Types LOGICAL :: Echo !< echo parameter - do we want to echo the header line describing the input file? [-] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: OutList !< string containing list of output channels requested in input file [-] LOGICAL :: Linearize = .FALSE. !< Flag that tells this module if the glue code wants to linearize. [-] + LOGICAL :: VisMeshes = .FALSE. !< Glue code requesting visualization meshes [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveVel !< [-] REAL(ReKi) , DIMENSION(:,:,:), ALLOCATABLE :: WaveAcc !< [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: WavePDyn !< [-] @@ -306,6 +307,11 @@ MODULE MoorDyn_Types INTEGER(IntKi) :: ObjID !< number of Point or Line object [-] END TYPE MD_OutParmType ! ======================= +! ========= VisDiam ======= + TYPE, PUBLIC :: VisDiam + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: Diam !< Diameter for visualization [-] + END TYPE VisDiam +! ======================= ! ========= MD_InitOutputType ======= TYPE, PUBLIC :: MD_InitOutputType CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: writeOutputHdr !< first line output file contents: output variable names [-] @@ -451,6 +457,8 @@ MODULE MoorDyn_Types INTEGER(IntKi) :: Jac_ny !< number of outputs in jacobian matrix [-] INTEGER(IntKi) :: Jac_nx !< number of continuous states in jacobian matrix [-] INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: dxIdx_map2_xStateIdx !< Mapping array from index of dX array to corresponding state index [-] + LOGICAL :: VisMeshes !< Using visualization meshes as requested by glue code [-] + TYPE(VisDiam) , DIMENSION(:), ALLOCATABLE :: VisRodsDiam !< Diameters for visualization of rods [-] END TYPE MD_ParameterType ! ======================= ! ========= MD_InputType ======= @@ -464,6 +472,10 @@ MODULE MoorDyn_Types TYPE, PUBLIC :: MD_OutputType TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: CoupledLoads !< array of point meshes for mooring reaction forces (and moments) at coupling points [[N]] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< output vector returned to glue code [] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: VisLinesMesh !< Line2 mesh for visualizing mooring lines [-] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: VisRodsMesh !< Line2 mesh for visualizing mooring rods [-] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: VisBodiesMesh !< Point mesh for visualizing mooring bodies [-] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: VisAnchsMesh !< Point mesh for visualizing mooring anchors [-] END TYPE MD_OutputType ! ======================= CONTAINS @@ -700,6 +712,7 @@ SUBROUTINE MD_CopyInitInput( SrcInitInputData, DstInitInputData, CtrlCode, ErrSt DstInitInputData%OutList = SrcInitInputData%OutList ENDIF DstInitInputData%Linearize = SrcInitInputData%Linearize + DstInitInputData%VisMeshes = SrcInitInputData%VisMeshes IF (ALLOCATED(SrcInitInputData%WaveVel)) THEN i1_l = LBOUND(SrcInitInputData%WaveVel,1) i1_u = UBOUND(SrcInitInputData%WaveVel,1) @@ -901,6 +914,7 @@ SUBROUTINE MD_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg Int_BufSz = Int_BufSz + SIZE(InData%OutList)*LEN(InData%OutList) ! OutList END IF Int_BufSz = Int_BufSz + 1 ! Linearize + Int_BufSz = Int_BufSz + 1 ! VisMeshes Int_BufSz = Int_BufSz + 1 ! WaveVel allocated yes/no IF ( ALLOCATED(InData%WaveVel) ) THEN Int_BufSz = Int_BufSz + 2*3 ! WaveVel upper/lower bounds for each dimension @@ -1062,6 +1076,8 @@ SUBROUTINE MD_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg END IF IntKiBuf(Int_Xferred) = TRANSFER(InData%Linearize, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 IF ( .NOT. ALLOCATED(InData%WaveVel) ) THEN IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 @@ -1328,6 +1344,8 @@ SUBROUTINE MD_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Err END IF OutData%Linearize = TRANSFER(IntKiBuf(Int_Xferred), OutData%Linearize) Int_Xferred = Int_Xferred + 1 + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! WaveVel not allocated Int_Xferred = Int_Xferred + 1 ELSE @@ -6876,6 +6894,192 @@ SUBROUTINE MD_UnPackOutParmType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E Int_Xferred = Int_Xferred + 1 END SUBROUTINE MD_UnPackOutParmType + SUBROUTINE MD_CopyVisDiam( SrcVisDiamData, DstVisDiamData, CtrlCode, ErrStat, ErrMsg ) + TYPE(VisDiam), INTENT(IN) :: SrcVisDiamData + TYPE(VisDiam), INTENT(INOUT) :: DstVisDiamData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_CopyVisDiam' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcVisDiamData%Diam)) THEN + i1_l = LBOUND(SrcVisDiamData%Diam,1) + i1_u = UBOUND(SrcVisDiamData%Diam,1) + IF (.NOT. ALLOCATED(DstVisDiamData%Diam)) THEN + ALLOCATE(DstVisDiamData%Diam(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstVisDiamData%Diam.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DstVisDiamData%Diam = SrcVisDiamData%Diam +ENDIF + END SUBROUTINE MD_CopyVisDiam + + SUBROUTINE MD_DestroyVisDiam( VisDiamData, ErrStat, ErrMsg, DEALLOCATEpointers ) + TYPE(VisDiam), INTENT(INOUT) :: VisDiamData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL,INTENT(IN ) :: DEALLOCATEpointers + + INTEGER(IntKi) :: i, i1, i2, i3, i4, i5 + LOGICAL :: DEALLOCATEpointers_local + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_DestroyVisDiam' + + ErrStat = ErrID_None + ErrMsg = "" + + IF (PRESENT(DEALLOCATEpointers)) THEN + DEALLOCATEpointers_local = DEALLOCATEpointers + ELSE + DEALLOCATEpointers_local = .true. + END IF + +IF (ALLOCATED(VisDiamData%Diam)) THEN + DEALLOCATE(VisDiamData%Diam) +ENDIF + END SUBROUTINE MD_DestroyVisDiam + + SUBROUTINE MD_PackVisDiam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, SizeOnly ) + REAL(ReKi), ALLOCATABLE, INTENT( OUT) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT( OUT) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT( OUT) :: IntKiBuf(:) + TYPE(VisDiam), INTENT(IN) :: InData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + LOGICAL,OPTIONAL, INTENT(IN ) :: SizeOnly + ! Local variables + INTEGER(IntKi) :: Re_BufSz + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_BufSz + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_BufSz + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i,i1,i2,i3,i4,i5 + LOGICAL :: OnlySize ! if present and true, do not pack, just allocate buffers + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_PackVisDiam' + ! buffers to store subtypes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + + OnlySize = .FALSE. + IF ( PRESENT(SizeOnly) ) THEN + OnlySize = SizeOnly + ENDIF + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_BufSz = 0 + Db_BufSz = 0 + Int_BufSz = 0 + Int_BufSz = Int_BufSz + 1 ! Diam allocated yes/no + IF ( ALLOCATED(InData%Diam) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! Diam upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%Diam) ! Diam + END IF + IF ( Re_BufSz .GT. 0 ) THEN + ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating ReKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Db_BufSz .GT. 0 ) THEN + ALLOCATE( DbKiBuf( Db_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DbKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF ( Int_BufSz .GT. 0 ) THEN + ALLOCATE( IntKiBuf( Int_BufSz ), STAT=ErrStat2 ) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating IntKiBuf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + IF(OnlySize) RETURN ! return early if only trying to allocate buffers (not pack them) + + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + + IF ( .NOT. ALLOCATED(InData%Diam) ) 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%Diam,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%Diam,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%Diam,1), UBOUND(InData%Diam,1) + ReKiBuf(Re_Xferred) = InData%Diam(i1) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE MD_PackVisDiam + + SUBROUTINE MD_UnPackVisDiam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(VisDiam), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_UnPackVisDiam' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! Diam 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%Diam)) DEALLOCATE(OutData%Diam) + ALLOCATE(OutData%Diam(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%Diam.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%Diam,1), UBOUND(OutData%Diam,1) + OutData%Diam(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) + Re_Xferred = Re_Xferred + 1 + END DO + END IF + END SUBROUTINE MD_UnPackVisDiam + SUBROUTINE MD_CopyInitOutput( SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg ) TYPE(MD_InitOutputType), INTENT(IN) :: SrcInitOutputData TYPE(MD_InitOutputType), INTENT(INOUT) :: DstInitOutputData @@ -11197,6 +11401,23 @@ SUBROUTINE MD_CopyParam( SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg ) END IF END IF DstParamData%dxIdx_map2_xStateIdx = SrcParamData%dxIdx_map2_xStateIdx +ENDIF + DstParamData%VisMeshes = SrcParamData%VisMeshes +IF (ALLOCATED(SrcParamData%VisRodsDiam)) THEN + i1_l = LBOUND(SrcParamData%VisRodsDiam,1) + i1_u = UBOUND(SrcParamData%VisRodsDiam,1) + IF (.NOT. ALLOCATED(DstParamData%VisRodsDiam)) THEN + ALLOCATE(DstParamData%VisRodsDiam(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%VisRodsDiam.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcParamData%VisRodsDiam,1), UBOUND(SrcParamData%VisRodsDiam,1) + CALL MD_Copyvisdiam( SrcParamData%VisRodsDiam(i1), DstParamData%VisRodsDiam(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO ENDIF END SUBROUTINE MD_CopyParam @@ -11293,6 +11514,13 @@ SUBROUTINE MD_DestroyParam( ParamData, ErrStat, ErrMsg, DEALLOCATEpointers ) ENDIF IF (ALLOCATED(ParamData%dxIdx_map2_xStateIdx)) THEN DEALLOCATE(ParamData%dxIdx_map2_xStateIdx) +ENDIF +IF (ALLOCATED(ParamData%VisRodsDiam)) THEN +DO i1 = LBOUND(ParamData%VisRodsDiam,1), UBOUND(ParamData%VisRodsDiam,1) + CALL MD_Destroyvisdiam( ParamData%VisRodsDiam(i1), ErrStat2, ErrMsg2, DEALLOCATEpointers_local ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +ENDDO + DEALLOCATE(ParamData%VisRodsDiam) ENDIF END SUBROUTINE MD_DestroyParam @@ -11510,6 +11738,30 @@ SUBROUTINE MD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si IF ( ALLOCATED(InData%dxIdx_map2_xStateIdx) ) THEN Int_BufSz = Int_BufSz + 2*1 ! dxIdx_map2_xStateIdx upper/lower bounds for each dimension Int_BufSz = Int_BufSz + SIZE(InData%dxIdx_map2_xStateIdx) ! dxIdx_map2_xStateIdx + END IF + Int_BufSz = Int_BufSz + 1 ! VisMeshes + Int_BufSz = Int_BufSz + 1 ! VisRodsDiam allocated yes/no + IF ( ALLOCATED(InData%VisRodsDiam) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VisRodsDiam upper/lower bounds for each dimension + DO i1 = LBOUND(InData%VisRodsDiam,1), UBOUND(InData%VisRodsDiam,1) + Int_BufSz = Int_BufSz + 3 ! VisRodsDiam: size of buffers for each call to pack subtype + CALL MD_Packvisdiam( Re_Buf, Db_Buf, Int_Buf, InData%VisRodsDiam(i1), ErrStat2, ErrMsg2, .TRUE. ) ! VisRodsDiam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisRodsDiam + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisRodsDiam + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisRodsDiam + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) @@ -12131,6 +12383,49 @@ SUBROUTINE MD_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Si IntKiBuf(Int_Xferred) = InData%dxIdx_map2_xStateIdx(i1) Int_Xferred = Int_Xferred + 1 END DO + END IF + IntKiBuf(Int_Xferred) = TRANSFER(InData%VisMeshes, IntKiBuf(1)) + Int_Xferred = Int_Xferred + 1 + IF ( .NOT. ALLOCATED(InData%VisRodsDiam) ) 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%VisRodsDiam,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VisRodsDiam,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%VisRodsDiam,1), UBOUND(InData%VisRodsDiam,1) + CALL MD_Packvisdiam( Re_Buf, Db_Buf, Int_Buf, InData%VisRodsDiam(i1), ErrStat2, ErrMsg2, OnlySize ) ! VisRodsDiam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO END IF END SUBROUTINE MD_PackParam @@ -12839,46 +13134,104 @@ SUBROUTINE MD_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Int_Xferred = Int_Xferred + 1 END DO END IF - END SUBROUTINE MD_UnPackParam - - SUBROUTINE MD_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) - TYPE(MD_InputType), INTENT(INOUT) :: SrcInputData - TYPE(MD_InputType), INTENT(INOUT) :: DstInputData - INTEGER(IntKi), INTENT(IN ) :: CtrlCode - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg -! Local - INTEGER(IntKi) :: i,j,k - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'MD_CopyInput' -! - ErrStat = ErrID_None - ErrMsg = "" -IF (ALLOCATED(SrcInputData%CoupledKinematics)) THEN - i1_l = LBOUND(SrcInputData%CoupledKinematics,1) - i1_u = UBOUND(SrcInputData%CoupledKinematics,1) - IF (.NOT. ALLOCATED(DstInputData%CoupledKinematics)) THEN - ALLOCATE(DstInputData%CoupledKinematics(i1_l:i1_u),STAT=ErrStat2) + OutData%VisMeshes = TRANSFER(IntKiBuf(Int_Xferred), OutData%VisMeshes) + Int_Xferred = Int_Xferred + 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VisRodsDiam 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%VisRodsDiam)) DEALLOCATE(OutData%VisRodsDiam) + ALLOCATE(OutData%VisRodsDiam(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%CoupledKinematics.', ErrStat, ErrMsg,RoutineName) - RETURN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VisRodsDiam.', ErrStat, ErrMsg,RoutineName) + RETURN END IF - END IF - DO i1 = LBOUND(SrcInputData%CoupledKinematics,1), UBOUND(SrcInputData%CoupledKinematics,1) - CALL MeshCopy( SrcInputData%CoupledKinematics(i1), DstInputData%CoupledKinematics(i1), CtrlCode, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - IF (ErrStat>=AbortErrLev) RETURN - ENDDO -ENDIF -IF (ALLOCATED(SrcInputData%DeltaL)) THEN - i1_l = LBOUND(SrcInputData%DeltaL,1) - i1_u = UBOUND(SrcInputData%DeltaL,1) - IF (.NOT. ALLOCATED(DstInputData%DeltaL)) THEN - ALLOCATE(DstInputData%DeltaL(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%DeltaL.', ErrStat, ErrMsg,RoutineName) + DO i1 = LBOUND(OutData%VisRodsDiam,1), UBOUND(OutData%VisRodsDiam,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MD_Unpackvisdiam( Re_Buf, Db_Buf, Int_Buf, OutData%VisRodsDiam(i1), ErrStat2, ErrMsg2 ) ! VisRodsDiam + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF + END SUBROUTINE MD_UnPackParam + + SUBROUTINE MD_CopyInput( SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg ) + TYPE(MD_InputType), INTENT(INOUT) :: SrcInputData + TYPE(MD_InputType), INTENT(INOUT) :: DstInputData + INTEGER(IntKi), INTENT(IN ) :: CtrlCode + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg +! Local + INTEGER(IntKi) :: i,j,k + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_CopyInput' +! + ErrStat = ErrID_None + ErrMsg = "" +IF (ALLOCATED(SrcInputData%CoupledKinematics)) THEN + i1_l = LBOUND(SrcInputData%CoupledKinematics,1) + i1_u = UBOUND(SrcInputData%CoupledKinematics,1) + IF (.NOT. ALLOCATED(DstInputData%CoupledKinematics)) THEN + ALLOCATE(DstInputData%CoupledKinematics(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%CoupledKinematics.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcInputData%CoupledKinematics,1), UBOUND(SrcInputData%CoupledKinematics,1) + CALL MeshCopy( SrcInputData%CoupledKinematics(i1), DstInputData%CoupledKinematics(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcInputData%DeltaL)) THEN + i1_l = LBOUND(SrcInputData%DeltaL,1) + i1_u = UBOUND(SrcInputData%DeltaL,1) + IF (.NOT. ALLOCATED(DstInputData%DeltaL)) THEN + ALLOCATE(DstInputData%DeltaL(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstInputData%DeltaL.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF @@ -13266,6 +13619,70 @@ SUBROUTINE MD_CopyOutput( SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMs END IF END IF DstOutputData%WriteOutput = SrcOutputData%WriteOutput +ENDIF +IF (ALLOCATED(SrcOutputData%VisLinesMesh)) THEN + i1_l = LBOUND(SrcOutputData%VisLinesMesh,1) + i1_u = UBOUND(SrcOutputData%VisLinesMesh,1) + IF (.NOT. ALLOCATED(DstOutputData%VisLinesMesh)) THEN + ALLOCATE(DstOutputData%VisLinesMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VisLinesMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcOutputData%VisLinesMesh,1), UBOUND(SrcOutputData%VisLinesMesh,1) + CALL MeshCopy( SrcOutputData%VisLinesMesh(i1), DstOutputData%VisLinesMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcOutputData%VisRodsMesh)) THEN + i1_l = LBOUND(SrcOutputData%VisRodsMesh,1) + i1_u = UBOUND(SrcOutputData%VisRodsMesh,1) + IF (.NOT. ALLOCATED(DstOutputData%VisRodsMesh)) THEN + ALLOCATE(DstOutputData%VisRodsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VisRodsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcOutputData%VisRodsMesh,1), UBOUND(SrcOutputData%VisRodsMesh,1) + CALL MeshCopy( SrcOutputData%VisRodsMesh(i1), DstOutputData%VisRodsMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcOutputData%VisBodiesMesh)) THEN + i1_l = LBOUND(SrcOutputData%VisBodiesMesh,1) + i1_u = UBOUND(SrcOutputData%VisBodiesMesh,1) + IF (.NOT. ALLOCATED(DstOutputData%VisBodiesMesh)) THEN + ALLOCATE(DstOutputData%VisBodiesMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VisBodiesMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcOutputData%VisBodiesMesh,1), UBOUND(SrcOutputData%VisBodiesMesh,1) + CALL MeshCopy( SrcOutputData%VisBodiesMesh(i1), DstOutputData%VisBodiesMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO +ENDIF +IF (ALLOCATED(SrcOutputData%VisAnchsMesh)) THEN + i1_l = LBOUND(SrcOutputData%VisAnchsMesh,1) + i1_u = UBOUND(SrcOutputData%VisAnchsMesh,1) + IF (.NOT. ALLOCATED(DstOutputData%VisAnchsMesh)) THEN + ALLOCATE(DstOutputData%VisAnchsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstOutputData%VisAnchsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + END IF + DO i1 = LBOUND(SrcOutputData%VisAnchsMesh,1), UBOUND(SrcOutputData%VisAnchsMesh,1) + CALL MeshCopy( SrcOutputData%VisAnchsMesh(i1), DstOutputData%VisAnchsMesh(i1), CtrlCode, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat>=AbortErrLev) RETURN + ENDDO ENDIF END SUBROUTINE MD_CopyOutput @@ -13299,6 +13716,34 @@ SUBROUTINE MD_DestroyOutput( OutputData, ErrStat, ErrMsg, DEALLOCATEpointers ) ENDIF IF (ALLOCATED(OutputData%WriteOutput)) THEN DEALLOCATE(OutputData%WriteOutput) +ENDIF +IF (ALLOCATED(OutputData%VisLinesMesh)) THEN +DO i1 = LBOUND(OutputData%VisLinesMesh,1), UBOUND(OutputData%VisLinesMesh,1) + CALL MeshDestroy( OutputData%VisLinesMesh(i1), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +ENDDO + DEALLOCATE(OutputData%VisLinesMesh) +ENDIF +IF (ALLOCATED(OutputData%VisRodsMesh)) THEN +DO i1 = LBOUND(OutputData%VisRodsMesh,1), UBOUND(OutputData%VisRodsMesh,1) + CALL MeshDestroy( OutputData%VisRodsMesh(i1), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +ENDDO + DEALLOCATE(OutputData%VisRodsMesh) +ENDIF +IF (ALLOCATED(OutputData%VisBodiesMesh)) THEN +DO i1 = LBOUND(OutputData%VisBodiesMesh,1), UBOUND(OutputData%VisBodiesMesh,1) + CALL MeshDestroy( OutputData%VisBodiesMesh(i1), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +ENDDO + DEALLOCATE(OutputData%VisBodiesMesh) +ENDIF +IF (ALLOCATED(OutputData%VisAnchsMesh)) THEN +DO i1 = LBOUND(OutputData%VisAnchsMesh,1), UBOUND(OutputData%VisAnchsMesh,1) + CALL MeshDestroy( OutputData%VisAnchsMesh(i1), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) +ENDDO + DEALLOCATE(OutputData%VisAnchsMesh) ENDIF END SUBROUTINE MD_DestroyOutput @@ -13366,6 +13811,98 @@ SUBROUTINE MD_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Int_BufSz = Int_BufSz + 2*1 ! WriteOutput upper/lower bounds for each dimension Re_BufSz = Re_BufSz + SIZE(InData%WriteOutput) ! WriteOutput END IF + Int_BufSz = Int_BufSz + 1 ! VisLinesMesh allocated yes/no + IF ( ALLOCATED(InData%VisLinesMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VisLinesMesh upper/lower bounds for each dimension + DO i1 = LBOUND(InData%VisLinesMesh,1), UBOUND(InData%VisLinesMesh,1) + Int_BufSz = Int_BufSz + 3 ! VisLinesMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%VisLinesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! VisLinesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisLinesMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisLinesMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisLinesMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! VisRodsMesh allocated yes/no + IF ( ALLOCATED(InData%VisRodsMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VisRodsMesh upper/lower bounds for each dimension + DO i1 = LBOUND(InData%VisRodsMesh,1), UBOUND(InData%VisRodsMesh,1) + Int_BufSz = Int_BufSz + 3 ! VisRodsMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%VisRodsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! VisRodsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisRodsMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisRodsMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisRodsMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! VisBodiesMesh allocated yes/no + IF ( ALLOCATED(InData%VisBodiesMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VisBodiesMesh upper/lower bounds for each dimension + DO i1 = LBOUND(InData%VisBodiesMesh,1), UBOUND(InData%VisBodiesMesh,1) + Int_BufSz = Int_BufSz + 3 ! VisBodiesMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%VisBodiesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! VisBodiesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisBodiesMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisBodiesMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisBodiesMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF + Int_BufSz = Int_BufSz + 1 ! VisAnchsMesh allocated yes/no + IF ( ALLOCATED(InData%VisAnchsMesh) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! VisAnchsMesh upper/lower bounds for each dimension + DO i1 = LBOUND(InData%VisAnchsMesh,1), UBOUND(InData%VisAnchsMesh,1) + Int_BufSz = Int_BufSz + 3 ! VisAnchsMesh: size of buffers for each call to pack subtype + CALL MeshPack( InData%VisAnchsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, .TRUE. ) ! VisAnchsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN ! VisAnchsMesh + Re_BufSz = Re_BufSz + SIZE( Re_Buf ) + DEALLOCATE(Re_Buf) + END IF + IF(ALLOCATED(Db_Buf)) THEN ! VisAnchsMesh + Db_BufSz = Db_BufSz + SIZE( Db_Buf ) + DEALLOCATE(Db_Buf) + END IF + IF(ALLOCATED(Int_Buf)) THEN ! VisAnchsMesh + Int_BufSz = Int_BufSz + SIZE( Int_Buf ) + DEALLOCATE(Int_Buf) + END IF + END DO + END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) IF (ErrStat2 /= 0) THEN @@ -13449,49 +13986,213 @@ SUBROUTINE MD_PackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, S Re_Xferred = Re_Xferred + 1 END DO END IF - END SUBROUTINE MD_PackOutput + IF ( .NOT. ALLOCATED(InData%VisLinesMesh) ) 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%VisLinesMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VisLinesMesh,1) + Int_Xferred = Int_Xferred + 2 - SUBROUTINE MD_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) - REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) - REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) - INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) - TYPE(MD_OutputType), INTENT(INOUT) :: OutData - INTEGER(IntKi), INTENT( OUT) :: ErrStat - CHARACTER(*), INTENT( OUT) :: ErrMsg - ! Local variables - INTEGER(IntKi) :: Buf_size - INTEGER(IntKi) :: Re_Xferred - INTEGER(IntKi) :: Db_Xferred - INTEGER(IntKi) :: Int_Xferred - INTEGER(IntKi) :: i - INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 - INTEGER(IntKi) :: ErrStat2 - CHARACTER(ErrMsgLen) :: ErrMsg2 - CHARACTER(*), PARAMETER :: RoutineName = 'MD_UnPackOutput' - ! buffers to store meshes, if any - REAL(ReKi), ALLOCATABLE :: Re_Buf(:) - REAL(DbKi), ALLOCATABLE :: Db_Buf(:) - INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) - ! - ErrStat = ErrID_None - ErrMsg = "" - Re_Xferred = 1 - Db_Xferred = 1 - Int_Xferred = 1 - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CoupledLoads not allocated + DO i1 = LBOUND(InData%VisLinesMesh,1), UBOUND(InData%VisLinesMesh,1) + CALL MeshPack( InData%VisLinesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! VisLinesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF + IF ( .NOT. ALLOCATED(InData%VisRodsMesh) ) THEN + IntKiBuf( Int_Xferred ) = 0 Int_Xferred = Int_Xferred + 1 ELSE + IntKiBuf( Int_Xferred ) = 1 Int_Xferred = Int_Xferred + 1 - i1_l = IntKiBuf( Int_Xferred ) - i1_u = IntKiBuf( Int_Xferred + 1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%VisRodsMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VisRodsMesh,1) Int_Xferred = Int_Xferred + 2 - IF (ALLOCATED(OutData%CoupledLoads)) DEALLOCATE(OutData%CoupledLoads) - ALLOCATE(OutData%CoupledLoads(i1_l:i1_u),STAT=ErrStat2) - IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%CoupledLoads.', ErrStat, ErrMsg,RoutineName) - RETURN - END IF - DO i1 = LBOUND(OutData%CoupledLoads,1), UBOUND(OutData%CoupledLoads,1) + + DO i1 = LBOUND(InData%VisRodsMesh,1), UBOUND(InData%VisRodsMesh,1) + CALL MeshPack( InData%VisRodsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! VisRodsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF + IF ( .NOT. ALLOCATED(InData%VisBodiesMesh) ) 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%VisBodiesMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VisBodiesMesh,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%VisBodiesMesh,1), UBOUND(InData%VisBodiesMesh,1) + CALL MeshPack( InData%VisBodiesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! VisBodiesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF + IF ( .NOT. ALLOCATED(InData%VisAnchsMesh) ) 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%VisAnchsMesh,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%VisAnchsMesh,1) + Int_Xferred = Int_Xferred + 2 + + DO i1 = LBOUND(InData%VisAnchsMesh,1), UBOUND(InData%VisAnchsMesh,1) + CALL MeshPack( InData%VisAnchsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2, OnlySize ) ! VisAnchsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Re_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Re_Buf) > 0) ReKiBuf( Re_Xferred:Re_Xferred+SIZE(Re_Buf)-1 ) = Re_Buf + Re_Xferred = Re_Xferred + SIZE(Re_Buf) + DEALLOCATE(Re_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Db_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Db_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Db_Buf) > 0) DbKiBuf( Db_Xferred:Db_Xferred+SIZE(Db_Buf)-1 ) = Db_Buf + Db_Xferred = Db_Xferred + SIZE(Db_Buf) + DEALLOCATE(Db_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + IF(ALLOCATED(Int_Buf)) THEN + IntKiBuf( Int_Xferred ) = SIZE(Int_Buf); Int_Xferred = Int_Xferred + 1 + IF (SIZE(Int_Buf) > 0) IntKiBuf( Int_Xferred:Int_Xferred+SIZE(Int_Buf)-1 ) = Int_Buf + Int_Xferred = Int_Xferred + SIZE(Int_Buf) + DEALLOCATE(Int_Buf) + ELSE + IntKiBuf( Int_Xferred ) = 0; Int_Xferred = Int_Xferred + 1 + ENDIF + END DO + END IF + END SUBROUTINE MD_PackOutput + + SUBROUTINE MD_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg ) + REAL(ReKi), ALLOCATABLE, INTENT(IN ) :: ReKiBuf(:) + REAL(DbKi), ALLOCATABLE, INTENT(IN ) :: DbKiBuf(:) + INTEGER(IntKi), ALLOCATABLE, INTENT(IN ) :: IntKiBuf(:) + TYPE(MD_OutputType), INTENT(INOUT) :: OutData + INTEGER(IntKi), INTENT( OUT) :: ErrStat + CHARACTER(*), INTENT( OUT) :: ErrMsg + ! Local variables + INTEGER(IntKi) :: Buf_size + INTEGER(IntKi) :: Re_Xferred + INTEGER(IntKi) :: Db_Xferred + INTEGER(IntKi) :: Int_Xferred + INTEGER(IntKi) :: i + INTEGER(IntKi) :: i1, i1_l, i1_u ! bounds (upper/lower) for an array dimension 1 + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'MD_UnPackOutput' + ! buffers to store meshes, if any + REAL(ReKi), ALLOCATABLE :: Re_Buf(:) + REAL(DbKi), ALLOCATABLE :: Db_Buf(:) + INTEGER(IntKi), ALLOCATABLE :: Int_Buf(:) + ! + ErrStat = ErrID_None + ErrMsg = "" + Re_Xferred = 1 + Db_Xferred = 1 + Int_Xferred = 1 + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! CoupledLoads 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%CoupledLoads)) DEALLOCATE(OutData%CoupledLoads) + ALLOCATE(OutData%CoupledLoads(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%CoupledLoads.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%CoupledLoads,1), UBOUND(OutData%CoupledLoads,1) Buf_size=IntKiBuf( Int_Xferred ) Int_Xferred = Int_Xferred + 1 IF(Buf_size > 0) THEN @@ -13552,6 +14253,230 @@ SUBROUTINE MD_UnPackOutput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMsg Re_Xferred = Re_Xferred + 1 END DO END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VisLinesMesh 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%VisLinesMesh)) DEALLOCATE(OutData%VisLinesMesh) + ALLOCATE(OutData%VisLinesMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VisLinesMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VisLinesMesh,1), UBOUND(OutData%VisLinesMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%VisLinesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! VisLinesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VisRodsMesh 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%VisRodsMesh)) DEALLOCATE(OutData%VisRodsMesh) + ALLOCATE(OutData%VisRodsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VisRodsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VisRodsMesh,1), UBOUND(OutData%VisRodsMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%VisRodsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! VisRodsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VisBodiesMesh 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%VisBodiesMesh)) DEALLOCATE(OutData%VisBodiesMesh) + ALLOCATE(OutData%VisBodiesMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VisBodiesMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VisBodiesMesh,1), UBOUND(OutData%VisBodiesMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%VisBodiesMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! VisBodiesMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! VisAnchsMesh 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%VisAnchsMesh)) DEALLOCATE(OutData%VisAnchsMesh) + ALLOCATE(OutData%VisAnchsMesh(i1_l:i1_u),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%VisAnchsMesh.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + DO i1 = LBOUND(OutData%VisAnchsMesh,1), UBOUND(OutData%VisAnchsMesh,1) + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Re_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Re_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Re_Buf = ReKiBuf( Re_Xferred:Re_Xferred+Buf_size-1 ) + Re_Xferred = Re_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Db_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Db_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Db_Buf = DbKiBuf( Db_Xferred:Db_Xferred+Buf_size-1 ) + Db_Xferred = Db_Xferred + Buf_size + END IF + Buf_size=IntKiBuf( Int_Xferred ) + Int_Xferred = Int_Xferred + 1 + IF(Buf_size > 0) THEN + ALLOCATE(Int_Buf(Buf_size),STAT=ErrStat2) + IF (ErrStat2 /= 0) THEN + CALL SetErrStat(ErrID_Fatal, 'Error allocating Int_Buf.', ErrStat, ErrMsg,RoutineName) + RETURN + END IF + Int_Buf = IntKiBuf( Int_Xferred:Int_Xferred+Buf_size-1 ) + Int_Xferred = Int_Xferred + Buf_size + END IF + CALL MeshUnpack( OutData%VisAnchsMesh(i1), Re_Buf, Db_Buf, Int_Buf, ErrStat2, ErrMsg2 ) ! VisAnchsMesh + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + IF (ErrStat >= AbortErrLev) RETURN + + IF(ALLOCATED(Re_Buf )) DEALLOCATE(Re_Buf ) + IF(ALLOCATED(Db_Buf )) DEALLOCATE(Db_Buf ) + IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) + END DO + END IF END SUBROUTINE MD_UnPackOutput @@ -13852,6 +14777,30 @@ SUBROUTINE MD_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg b = -(y1%WriteOutput(i1) - y2%WriteOutput(i1)) y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b * ScaleFactor END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisLinesMesh) .AND. ALLOCATED(y1%VisLinesMesh)) THEN + DO i1 = LBOUND(y_out%VisLinesMesh,1),UBOUND(y_out%VisLinesMesh,1) + CALL MeshExtrapInterp1(y1%VisLinesMesh(i1), y2%VisLinesMesh(i1), tin, y_out%VisLinesMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisRodsMesh) .AND. ALLOCATED(y1%VisRodsMesh)) THEN + DO i1 = LBOUND(y_out%VisRodsMesh,1),UBOUND(y_out%VisRodsMesh,1) + CALL MeshExtrapInterp1(y1%VisRodsMesh(i1), y2%VisRodsMesh(i1), tin, y_out%VisRodsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisBodiesMesh) .AND. ALLOCATED(y1%VisBodiesMesh)) THEN + DO i1 = LBOUND(y_out%VisBodiesMesh,1),UBOUND(y_out%VisBodiesMesh,1) + CALL MeshExtrapInterp1(y1%VisBodiesMesh(i1), y2%VisBodiesMesh(i1), tin, y_out%VisBodiesMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisAnchsMesh) .AND. ALLOCATED(y1%VisAnchsMesh)) THEN + DO i1 = LBOUND(y_out%VisAnchsMesh,1),UBOUND(y_out%VisAnchsMesh,1) + CALL MeshExtrapInterp1(y1%VisAnchsMesh(i1), y2%VisAnchsMesh(i1), tin, y_out%VisAnchsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO END IF ! check if allocated END SUBROUTINE MD_Output_ExtrapInterp1 @@ -13922,6 +14871,30 @@ SUBROUTINE MD_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, Err c = ( (t(2)-t(3))*y1%WriteOutput(i1) + t(3)*y2%WriteOutput(i1) - t(2)*y3%WriteOutput(i1) ) * scaleFactor y_out%WriteOutput(i1) = y1%WriteOutput(i1) + b + c * t_out END DO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisLinesMesh) .AND. ALLOCATED(y1%VisLinesMesh)) THEN + DO i1 = LBOUND(y_out%VisLinesMesh,1),UBOUND(y_out%VisLinesMesh,1) + CALL MeshExtrapInterp2(y1%VisLinesMesh(i1), y2%VisLinesMesh(i1), y3%VisLinesMesh(i1), tin, y_out%VisLinesMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisRodsMesh) .AND. ALLOCATED(y1%VisRodsMesh)) THEN + DO i1 = LBOUND(y_out%VisRodsMesh,1),UBOUND(y_out%VisRodsMesh,1) + CALL MeshExtrapInterp2(y1%VisRodsMesh(i1), y2%VisRodsMesh(i1), y3%VisRodsMesh(i1), tin, y_out%VisRodsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisBodiesMesh) .AND. ALLOCATED(y1%VisBodiesMesh)) THEN + DO i1 = LBOUND(y_out%VisBodiesMesh,1),UBOUND(y_out%VisBodiesMesh,1) + CALL MeshExtrapInterp2(y1%VisBodiesMesh(i1), y2%VisBodiesMesh(i1), y3%VisBodiesMesh(i1), tin, y_out%VisBodiesMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO +END IF ! check if allocated +IF (ALLOCATED(y_out%VisAnchsMesh) .AND. ALLOCATED(y1%VisAnchsMesh)) THEN + DO i1 = LBOUND(y_out%VisAnchsMesh,1),UBOUND(y_out%VisAnchsMesh,1) + CALL MeshExtrapInterp2(y1%VisAnchsMesh(i1), y2%VisAnchsMesh(i1), y3%VisAnchsMesh(i1), tin, y_out%VisAnchsMesh(i1), tin_out, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg,RoutineName) + ENDDO END IF ! check if allocated END SUBROUTINE MD_Output_ExtrapInterp2 diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index de4fcd8def..2daf088cca 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -6313,7 +6313,13 @@ SUBROUTINE Angles_ExtrapInterp1_R4(Angle1, Angle2, tin, Angle_out, tin_out ) REAL(R8Ki) :: t_out ! Time to which to be extrap/interpd REAL(SiKi) :: Angle2_mod - + + ! If both inputs are the same, then the output must equal the input + if (Angle1 == Angle2) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6357,7 +6363,13 @@ SUBROUTINE Angles_ExtrapInterp1_R8(Angle1, Angle2, tin, Angle_out, tin_out) REAL(R8Ki) :: t_out ! Time to which to be extrap/interpd REAL(R8Ki) :: Angle2_mod - + + ! If both inputs are the same, then the output must equal the input + if (Angle1 == Angle2) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6400,7 +6412,13 @@ SUBROUTINE Angles_ExtrapInterp1_R4R(Angle1, Angle2, tin, Angle_out, tin_out ) REAL(SiKi) :: t_out ! Time to which to be extrap/interpd REAL(SiKi) :: Angle2_mod - + + ! If both inputs are the same, then the output must equal the input + if (Angle1 == Angle2) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6444,7 +6462,13 @@ SUBROUTINE Angles_ExtrapInterp1_R8R(Angle1, Angle2, tin, Angle_out, tin_out) REAL(SiKi) :: t_out ! Time to which to be extrap/interpd REAL(R8Ki) :: Angle2_mod - + + ! If both inputs are the same, then the output must equal the input + if (Angle1 == Angle2) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6490,7 +6514,13 @@ SUBROUTINE Angles_ExtrapInterp2_R4(Angle1, Angle2, Angle3, tin, Angle_out, tin_o REAL(DbKi) :: scaleFactor ! temporary for extrapolation/interpolation REAL(SiKi) :: Angle2_mod REAL(SiKi) :: Angle3_mod - + + ! If all inputs are the same, then the output must equal the input + if ((Angle1 == Angle2) .and. (Angle2 == Angle3)) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6553,7 +6583,13 @@ SUBROUTINE Angles_ExtrapInterp2_R8(Angle1, Angle2, Angle3, tin, Angle_out, tin_o REAL(DbKi) :: scaleFactor ! temporary for extrapolation/interpolation REAL(R8Ki) :: Angle2_mod REAL(R8Ki) :: Angle3_mod - + + ! If all inputs are the same, then the output must equal the input + if ((Angle1 == Angle2) .and. (Angle2 == Angle3)) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6616,7 +6652,13 @@ SUBROUTINE Angles_ExtrapInterp2_R4R(Angle1, Angle2, Angle3, tin, Angle_out, tin_ REAL(R8Ki) :: scaleFactor ! temporary for extrapolation/interpolation REAL(SiKi) :: Angle2_mod REAL(SiKi) :: Angle3_mod - + + ! If all inputs are the same, then the output must equal the input + if ((Angle1 == Angle2) .and. (Angle2 == Angle3)) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) @@ -6679,7 +6721,13 @@ SUBROUTINE Angles_ExtrapInterp2_R8R(Angle1, Angle2, Angle3, tin, Angle_out, tin_ REAL(R8Ki) :: scaleFactor ! temporary for extrapolation/interpolation REAL(R8Ki) :: Angle2_mod REAL(R8Ki) :: Angle3_mod - + + ! If all inputs are the same, then the output must equal the input + if ((Angle1 == Angle2) .and. (Angle2 == Angle3)) then + Angle_out = Angle1 + return + end if + ! we'll subtract a constant from the times to resolve some ! numerical issues when t gets large (and to simplify the equations) t = tin - tin(1) diff --git a/modules/openfast-library/src/FAST_Registry.txt b/modules/openfast-library/src/FAST_Registry.txt index f1b4e5504f..b869f5202f 100644 --- a/modules/openfast-library/src/FAST_Registry.txt +++ b/modules/openfast-library/src/FAST_Registry.txt @@ -69,7 +69,7 @@ typedef ^ FAST_VTK_SurfaceType IntKi NWaveElevPts {2} - - "number of points for typedef ^ FAST_VTK_SurfaceType SiKi WaveElevXY {:}{:} - - "X-Y locations for WaveElev output (for visualization). First dimension is the X (1) and Y (2) coordinate. Second dimension is the point number." "m,-" typedef ^ FAST_VTK_SurfaceType SiKi WaveElev {:}{:} - - "wave elevation at WaveElevXY; first dimension is time step; second dimension is point number" "m,-" typedef ^ FAST_VTK_SurfaceType FAST_VTK_BLSurfaceType BladeShape {:} - - "AirfoilCoords for each blade" m -typedef ^ FAST_VTK_SurfaceType SiKi MorisonRad {:} - - "radius of each Morison node" m +typedef ^ FAST_VTK_SurfaceType SiKi MorisonVisRad {:} - - "radius of each Morison node" m typedef ^ FAST_VTK_ModeShapeType CHARACTER(1024) CheckpointRoot - - - "name of the checkpoint file written by FAST when linearization data was produced" diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 2f99a720cf..9129d0555d 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -783,6 +783,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_HD%TMax = p_FAST%TMax Init%InData_HD%hasIce = p_FAST%CompIce /= Module_None Init%InData_HD%Linearize = p_FAST%Linearize + if (p_FAST%WrVTK /= VTK_None) Init%InData_HD%VisMeshes=.true. ! these values support wave field handling Init%InData_HD%WaveFieldMod = p_FAST%WaveFieldMod @@ -1011,7 +1012,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_MD%Tmax = p_FAST%TMax ! expected simulation duration (used by MoorDyn for wave kinematics preprocesing) Init%InData_MD%Linearize = p_FAST%Linearize - + if (p_FAST%WrVTK /= VTK_None) Init%InData_MD%VisMeshes=.true. CALL MD_Init( Init%InData_MD, MD%Input(1), MD%p, MD%x(STATE_CURR), MD%xd(STATE_CURR), MD%z(STATE_CURR), & MD%OtherSt(STATE_CURR), MD%y, MD%m, p_FAST%dt_module( MODULE_MD ), Init%OutData_MD, ErrStat2, ErrMsg2 ) @@ -3339,6 +3340,9 @@ SUBROUTINE SetVTKParameters_B4HD(p_FAST, InitOutData_ED, InitInData_HD, BD, ErrS if (ErrStat >= AbortErrLev) return Width = p_FAST%VTK_Surface%GroundRad * VTK_GroundFactor +!FIXME:ADP -- change test after merging to dev branch to compare to MHK_None + ! adjust to larger surface area for MHK since MHK turbines tend to be small compared to the platform + if (p_FAST%MHK /= 0_IntKi) Width = Width * 5.0_SiKi dx = Width / (p_FAST%VTK_surface%NWaveElevPts(1) - 1) dy = Width / (p_FAST%VTK_surface%NWaveElevPts(2) - 1) @@ -3420,6 +3424,9 @@ SUBROUTINE SetVTKParameters(p_FAST, InitOutData_ED, InitOutData_AD, InitInData_H RefPoint = p_FAST%TurbinePos if (p_FAST%CompHydro == MODULE_HD) then RefLengths = p_FAST%VTK_Surface%GroundRad*VTK_GroundFactor/2.0_SiKi +!FIXME: after merge to dev, change this test to use MHK_None + ! adjust to larger ground area for MHK since MHK turbines tend to be small compared to the platform + if (p_FAST%MHK /= 0_IntKi) RefLengths = RefLengths*4.0_SiKi ! note that p_FAST%TurbinePos(3) must be 0 for offshore turbines RefPoint(3) = p_FAST%TurbinePos(3) - InitOutData_HD%WtrDpth @@ -3556,10 +3563,8 @@ SUBROUTINE SetVTKParameters(p_FAST, InitOutData_ED, InitOutData_AD, InitInData_H ! morison surfaces !....................... - IF ( HD%Input(1)%Morison%Mesh%Committed ) THEN - !TODO: FIX for visualization GJH 4/23/20 - ! call move_alloc(InitOutData_HD%Morison%Morison_Rad, p_FAST%VTK_Surface%MorisonRad) - + IF ( HD%y%Morison%VisMesh%Committed ) THEN + call move_alloc(InitOutData_HD%Morison%MorisonVisRad, p_FAST%VTK_Surface%MorisonVisRad) END IF END SUBROUTINE SetVTKParameters @@ -5649,7 +5654,10 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H IF ( p_FAST%CompHydro == Module_HD .and. allocated(HD%Input)) THEN call MeshWrVTK(p_FAST%TurbinePos, HD%Input(1)%PRPMesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_PRP', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) call MeshWrVTK(p_FAST%TurbinePos, HD%y%WamitMesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_WAMIT', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%Input(1)%WAMITMesh ) - call MeshWrVTK(p_FAST%TurbinePos, HD%y%Morison%Mesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_Morison', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%Input(1)%Morison%Mesh ) + call MeshWrVTK(p_FAST%TurbinePos, HD%y%Morison%Mesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_MorisonPt', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%Input(1)%Morison%Mesh ) + if (HD%y%Morison%VisMesh%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, HD%y%Morison%VisMesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_Morison', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%Input(1)%Morison%Mesh ) + endif END IF ! SubDyn @@ -5677,6 +5685,20 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H call MeshWrVTK(p_FAST%TurbinePos, MD%y%CoupledLoads(1), trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFairlead', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, MD%Input(1)%CoupledKinematics(1) ) !call MeshWrVTK(p_FAST%TurbinePos, MD%Input(1)%CoupledKinematics, trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFair_motion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) end if + if (allocated(MD%y%VisLinesMesh)) then + do j=1,size(MD%y%VisLinesMesh) + if (MD%y%VisLinesMesh(j)%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, MD%y%VisLinesMesh(j), trim(p_FAST%VTK_OutFileRoot)//'.MD_Line'//trim(Num2LStr(j)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + enddo + endif + if (allocated(MD%y%VisRodsMesh)) then + do j=1,size(MD%y%VisRodsMesh) + if (MD%y%VisRodsMesh(j)%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, MD%y%VisRodsMesh(j), trim(p_FAST%VTK_OutFileRoot)//'.MD_Rod'//trim(Num2LStr(j)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + enddo + endif ! FEAMooring ELSEIF ( p_FAST%CompMooring == Module_FEAM ) THEN @@ -5739,7 +5761,7 @@ SUBROUTINE WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, TYPE(IceFloe_Data), INTENT(IN ) :: IceF !< IceFloe data TYPE(IceDyn_Data), INTENT(IN ) :: IceD !< All the IceDyn data used in time-step loop - INTEGER(IntKi) :: NumBl, k + INTEGER(IntKi) :: NumBl, k, j INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMSg2 CHARACTER(*), PARAMETER :: RoutineName = 'WrVTK_BasicMeshes' @@ -5799,16 +5821,35 @@ SUBROUTINE WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, IF ( p_FAST%CompHydro == Module_HD .and. ALLOCATED(HD%Input)) THEN call MeshWrVTK(p_FAST%TurbinePos, HD%Input(1)%WAMITMesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_WAMIT', y_FAST%VTK_count, & p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%y%WAMITMesh ) - call MeshWrVTK(p_FAST%TurbinePos, HD%Input(1)%Morison%Mesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_Morison', y_FAST%VTK_count, & + call MeshWrVTK(p_FAST%TurbinePos, HD%Input(1)%Morison%Mesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_MorisonPt', y_FAST%VTK_count, & p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%y%Morison%Mesh ) + if (HD%y%Morison%VisMesh%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, HD%y%Morison%VisMesh, trim(p_FAST%VTK_OutFileRoot)//'.HD_Morison', y_FAST%VTK_count, & + p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, HD%Input(1)%Morison%Mesh ) + endif END IF ! Mooring Lines? ! IF ( p_FAST%CompMooring == Module_MAP ) THEN ! call MeshWrVTK(p_FAST%TurbinePos, MAPp%Input(1)%PtFairDisplacement, trim(p_FAST%VTK_OutFileRoot)//'.MAP_PtFair_motion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) -! ELSEIF ( p_FAST%CompMooring == Module_MD ) THEN -! call MeshWrVTK(p_FAST%TurbinePos, MD%Input(1)%CoupledKinematics, trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFair_motion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + if ( p_FAST%CompMooring == Module_MD ) then + !call MeshWrVTK(p_FAST%TurbinePos, MD%Input(1)%CoupledKinematics, trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFair_motion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + if (allocated(MD%y%VisLinesMesh)) then + do j=1,size(MD%y%VisLinesMesh) + if (MD%y%VisLinesMesh(j)%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, MD%y%VisLinesMesh(j), trim(p_FAST%VTK_OutFileRoot)//'.MD_Line'//trim(Num2LStr(j)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + enddo + endif + if (allocated(MD%y%VisRodsMesh)) then + do j=1,size(MD%y%VisRodsMesh) + if (MD%y%VisRodsMesh(j)%Committed) then + call MeshWrVTK(p_FAST%TurbinePos, MD%y%VisRodsMesh(j), trim(p_FAST%VTK_OutFileRoot)//'.MD_Rod'//trim(Num2LStr(j)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + enddo + endif + endif ! ELSEIF ( p_FAST%CompMooring == Module_FEAM ) THEN ! call MeshWrVTK(p_FAST%TurbinePos, FEAM%Input(1)%PtFairleadDisplacement, trim(p_FAST%VTK_OutFileRoot)//'FEAM_PtFair_motion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) ! END IF @@ -5843,7 +5884,7 @@ SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW logical, parameter :: OutputFields = .FALSE. ! due to confusion about what fields mean on a surface, we are going to just output the basic meshes if people ask for fields - INTEGER(IntKi) :: NumBl, k + INTEGER(IntKi) :: NumBl, k, l INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMSg2 CHARACTER(*), PARAMETER :: RoutineName = 'WrVTK_Surfaces' @@ -5916,26 +5957,38 @@ SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW ! call MeshWrVTK(p_FAST%TurbinePos, SD%y%y2Mesh, trim(p_FAST%VTK_OutFileRoot)//'.SD_y2Mesh_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) ! call MeshWrVTK(p_FAST%TurbinePos, SD%y%y3Mesh, trim(p_FAST%VTK_OutFileRoot)//'.SD_y3Mesh_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) ! END IF -!TODO: Fix below section for new Morison GJH 4/23/20 - ! - !IF ( HD%Input(1)%Morison%Mesh%Committed ) THEN - ! !if ( p_FAST%CompSub == Module_NONE ) then ! floating - ! ! OutputFields = .false. - ! !else - ! ! OutputFields = p_FAST%VTK_fields - ! !end if - ! - ! call MeshWrVTK_Ln2Surface (p_FAST%TurbinePos, HD%Input(1)%Morison%Mesh, trim(p_FAST%VTK_OutFileRoot)//'.MorisonSurface', & - ! y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, p_FAST%VTK_Surface%NumSectors, & - ! p_FAST%VTK_Surface%MorisonRad, Sib=HD%y%Morison%Mesh ) - !END IF + + +! HydroDyn + IF ( HD%y%Morison%VisMesh%Committed ) THEN + call MeshWrVTK_Ln2Surface (p_FAST%TurbinePos, HD%y%Morison%VisMesh, trim(p_FAST%VTK_OutFileRoot)//'.MorisonSurface', & + y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, p_FAST%VTK_Surface%NumSectors, & + p_FAST%VTK_Surface%MorisonVisRad ) + END IF ! Mooring Lines? ! IF ( p_FAST%CompMooring == Module_MAP ) THEN ! call MeshWrVTK(p_FAST%TurbinePos, MAPp%Input(1)%PtFairDisplacement, trim(p_FAST%VTK_OutFileRoot)//'.MAP_PtFair_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) -! ELSEIF ( p_FAST%CompMooring == Module_MD ) THEN -! call MeshWrVTK(p_FAST%TurbinePos, MD%Input(1)%CoupledKinematics, trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFair_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) + if ( p_FAST%CompMooring == Module_MD ) THEN + !call MeshWrVTK(p_FAST%TurbinePos, MD%Input(1)%CoupledKinematics, trim(p_FAST%VTK_OutFileRoot)//'.MD_PtFair_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) + if (allocated(MD%y%VisLinesMesh)) then + do l=1,size(MD%y%VisLinesMesh) + if (MD%y%VisLinesMesh(l)%Committed) then ! No orientation data, so surface representation not possible + call MeshWrVTK(p_FAST%TurbinePos, MD%y%VisLinesMesh(l), trim(p_FAST%VTK_OutFileRoot)//'.MD_Line'//trim(Num2LStr(l)), y_FAST%VTK_count, p_FAST%VTK_fields, & + ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth ) + endif + enddo + endif + if (allocated(MD%y%VisRodsMesh)) then + do l=1,size(MD%y%VisRodsMesh) + if (MD%y%VisRodsMesh(l)%Committed) then ! No orientation data, so surface representation not possible + call MeshWrVTK_Ln2Surface(p_FAST%TurbinePos, MD%y%VisRodsMesh(l), trim(p_FAST%VTK_OutFileRoot)//'.MD_Rod'//trim(Num2LStr(l))//'Surface', y_FAST%VTK_count, p_FAST%VTK_fields, & + ErrSTat2, ErrMsg2, p_FAST%VTK_tWidth, NumSegments=p_FAST%VTK_Surface%NumSectors, Radius=MD%p%VisRodsDiam(l)%Diam ) + endif + enddo + endif + endif ! ELSEIF ( p_FAST%CompMooring == Module_FEAM ) THEN ! call MeshWrVTK(p_FAST%TurbinePos, FEAM%Input(1)%PtFairleadDisplacement, trim(p_FAST%VTK_OutFileRoot)//'FEAM_PtFair_motion', y_FAST%VTK_count, OutputFields, ErrStat2, ErrMsg2 ) ! END IF @@ -6142,8 +6195,8 @@ SUBROUTINE WriteInputMeshesToFile(u_ED, u_AD, u_SD, u_HD, u_MAP, u_BD, FileName, CALL MeshWrBin( unOut, u_ED%PlatformPtMesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, u_SD%TPMesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, u_SD%LMesh, ErrStat, ErrMsg ) - CALL MeshWrBin( unOut, u_HD%Morison%Mesh, ErrStat, ErrMsg ) - CALL MeshWrBin( unOut, u_HD%WAMITMesh, ErrStat, ErrMsg ) + CALL MeshWrBin( unOut, u_HD%Morison%Mesh, ErrStat, ErrMsg ) + CALL MeshWrBin( unOut, u_HD%WAMITMesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, u_MAP%PtFairDisplacement, ErrStat, ErrMsg ) ! Add how many BD blade meshes there are: NumBl = SIZE(u_BD,1) ! Note that NumBl is B4Ki @@ -6225,8 +6278,8 @@ SUBROUTINE WriteMotionMeshesToFile(time, y_ED, u_SD, y_SD, u_HD, u_MAP, y_BD, u_ CALL MeshWrBin( unOut, u_SD%TPMesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, y_SD%y2Mesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, y_SD%y3Mesh, ErrStat, ErrMsg ) - CALL MeshWrBin( unOut, u_HD%Morison%Mesh, ErrStat, ErrMsg ) - CALL MeshWrBin( unOut, u_HD%WAMITMesh, ErrStat, ErrMsg ) + CALL MeshWrBin( unOut, u_HD%Morison%Mesh, ErrStat, ErrMsg ) + CALL MeshWrBin( unOut, u_HD%WAMITMesh, ErrStat, ErrMsg ) CALL MeshWrBin( unOut, u_MAP%PtFairDisplacement, ErrStat, ErrMsg ) DO K_local = 1,SIZE(y_BD,1) CALL MeshWrBin( unOut, u_BD(K_local)%RootMotion, ErrStat, ErrMsg ) diff --git a/modules/openfast-library/src/FAST_Types.f90 b/modules/openfast-library/src/FAST_Types.f90 index afe11cb45c..fc8eac4b86 100644 --- a/modules/openfast-library/src/FAST_Types.f90 +++ b/modules/openfast-library/src/FAST_Types.f90 @@ -88,7 +88,7 @@ MODULE FAST_Types REAL(SiKi) , DIMENSION(:,:), ALLOCATABLE :: WaveElevXY !< X-Y locations for WaveElev output (for visualization). First dimension is the X (1) and Y (2) coordinate. Second dimension is the point number. [m,-] REAL(SiKi) , DIMENSION(:,:), ALLOCATABLE :: WaveElev !< wave elevation at WaveElevXY; first dimension is time step; second dimension is point number [m,-] TYPE(FAST_VTK_BLSurfaceType) , DIMENSION(:), ALLOCATABLE :: BladeShape !< AirfoilCoords for each blade [m] - REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: MorisonRad !< radius of each Morison node [m] + REAL(SiKi) , DIMENSION(:), ALLOCATABLE :: MorisonVisRad !< radius of each Morison node [m] END TYPE FAST_VTK_SurfaceType ! ======================= ! ========= FAST_VTK_ModeShapeType ======= @@ -763,7 +763,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 ======= @@ -1084,17 +1084,17 @@ SUBROUTINE FAST_CopyVTK_SurfaceType( SrcVTK_SurfaceTypeData, DstVTK_SurfaceTypeD IF (ErrStat>=AbortErrLev) RETURN ENDDO ENDIF -IF (ALLOCATED(SrcVTK_SurfaceTypeData%MorisonRad)) THEN - i1_l = LBOUND(SrcVTK_SurfaceTypeData%MorisonRad,1) - i1_u = UBOUND(SrcVTK_SurfaceTypeData%MorisonRad,1) - IF (.NOT. ALLOCATED(DstVTK_SurfaceTypeData%MorisonRad)) THEN - ALLOCATE(DstVTK_SurfaceTypeData%MorisonRad(i1_l:i1_u),STAT=ErrStat2) +IF (ALLOCATED(SrcVTK_SurfaceTypeData%MorisonVisRad)) THEN + i1_l = LBOUND(SrcVTK_SurfaceTypeData%MorisonVisRad,1) + i1_u = UBOUND(SrcVTK_SurfaceTypeData%MorisonVisRad,1) + IF (.NOT. ALLOCATED(DstVTK_SurfaceTypeData%MorisonVisRad)) THEN + ALLOCATE(DstVTK_SurfaceTypeData%MorisonVisRad(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating DstVTK_SurfaceTypeData%MorisonRad.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating DstVTK_SurfaceTypeData%MorisonVisRad.', ErrStat, ErrMsg,RoutineName) RETURN END IF END IF - DstVTK_SurfaceTypeData%MorisonRad = SrcVTK_SurfaceTypeData%MorisonRad + DstVTK_SurfaceTypeData%MorisonVisRad = SrcVTK_SurfaceTypeData%MorisonVisRad ENDIF END SUBROUTINE FAST_CopyVTK_SurfaceType @@ -1135,8 +1135,8 @@ SUBROUTINE FAST_DestroyVTK_SurfaceType( VTK_SurfaceTypeData, ErrStat, ErrMsg, DE ENDDO DEALLOCATE(VTK_SurfaceTypeData%BladeShape) ENDIF -IF (ALLOCATED(VTK_SurfaceTypeData%MorisonRad)) THEN - DEALLOCATE(VTK_SurfaceTypeData%MorisonRad) +IF (ALLOCATED(VTK_SurfaceTypeData%MorisonVisRad)) THEN + DEALLOCATE(VTK_SurfaceTypeData%MorisonVisRad) ENDIF END SUBROUTINE FAST_DestroyVTK_SurfaceType @@ -1219,10 +1219,10 @@ SUBROUTINE FAST_PackVTK_SurfaceType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat END IF END DO END IF - Int_BufSz = Int_BufSz + 1 ! MorisonRad allocated yes/no - IF ( ALLOCATED(InData%MorisonRad) ) THEN - Int_BufSz = Int_BufSz + 2*1 ! MorisonRad upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%MorisonRad) ! MorisonRad + Int_BufSz = Int_BufSz + 1 ! MorisonVisRad allocated yes/no + IF ( ALLOCATED(InData%MorisonVisRad) ) THEN + Int_BufSz = Int_BufSz + 2*1 ! MorisonVisRad upper/lower bounds for each dimension + Re_BufSz = Re_BufSz + SIZE(InData%MorisonVisRad) ! MorisonVisRad END IF IF ( Re_BufSz .GT. 0 ) THEN ALLOCATE( ReKiBuf( Re_BufSz ), STAT=ErrStat2 ) @@ -1363,18 +1363,18 @@ SUBROUTINE FAST_PackVTK_SurfaceType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat ENDIF END DO END IF - IF ( .NOT. ALLOCATED(InData%MorisonRad) ) THEN + IF ( .NOT. ALLOCATED(InData%MorisonVisRad) ) 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%MorisonRad,1) - IntKiBuf( Int_Xferred + 1) = UBOUND(InData%MorisonRad,1) + IntKiBuf( Int_Xferred ) = LBOUND(InData%MorisonVisRad,1) + IntKiBuf( Int_Xferred + 1) = UBOUND(InData%MorisonVisRad,1) Int_Xferred = Int_Xferred + 2 - DO i1 = LBOUND(InData%MorisonRad,1), UBOUND(InData%MorisonRad,1) - ReKiBuf(Re_Xferred) = InData%MorisonRad(i1) + DO i1 = LBOUND(InData%MorisonVisRad,1), UBOUND(InData%MorisonVisRad,1) + ReKiBuf(Re_Xferred) = InData%MorisonVisRad(i1) Re_Xferred = Re_Xferred + 1 END DO END IF @@ -1550,21 +1550,21 @@ SUBROUTINE FAST_UnPackVTK_SurfaceType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrS IF(ALLOCATED(Int_Buf)) DEALLOCATE(Int_Buf) END DO END IF - IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! MorisonRad not allocated + IF ( IntKiBuf( Int_Xferred ) == 0 ) THEN ! MorisonVisRad 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%MorisonRad)) DEALLOCATE(OutData%MorisonRad) - ALLOCATE(OutData%MorisonRad(i1_l:i1_u),STAT=ErrStat2) + IF (ALLOCATED(OutData%MorisonVisRad)) DEALLOCATE(OutData%MorisonVisRad) + ALLOCATE(OutData%MorisonVisRad(i1_l:i1_u),STAT=ErrStat2) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%MorisonRad.', ErrStat, ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal, 'Error allocating OutData%MorisonVisRad.', ErrStat, ErrMsg,RoutineName) RETURN END IF - DO i1 = LBOUND(OutData%MorisonRad,1), UBOUND(OutData%MorisonRad,1) - OutData%MorisonRad(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) + DO i1 = LBOUND(OutData%MorisonVisRad,1), UBOUND(OutData%MorisonVisRad,1) + OutData%MorisonVisRad(i1) = REAL(ReKiBuf(Re_Xferred), SiKi) Re_Xferred = Re_Xferred + 1 END DO END IF diff --git a/modules/openfoam/CMakeLists.txt b/modules/openfoam/CMakeLists.txt index c92947ccee..4e4cbd9885 100644 --- a/modules/openfoam/CMakeLists.txt +++ b/modules/openfoam/CMakeLists.txt @@ -18,10 +18,10 @@ if (GENERATE_TYPES) generate_f90_types(src/OpenFOAM_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/OpenFOAM_Types.f90 -ccode) endif() -add_library(foamtypeslib src/OpenFOAM_Types.f90) +add_library(foamtypeslib STATIC src/OpenFOAM_Types.f90) target_link_libraries(foamtypeslib nwtclibs) -add_library(foamfastlib src/OpenFOAM.f90) +add_library(foamfastlib STATIC src/OpenFOAM.f90) target_link_libraries(foamfastlib openfast_prelib) target_include_directories(foamfastlib PUBLIC $ diff --git a/modules/openfoam/src/OpenFOAM_Types.f90 b/modules/openfoam/src/OpenFOAM_Types.f90 index a3a92c86e5..3613f4b483 100644 --- a/modules/openfoam/src/OpenFOAM_Types.f90 +++ b/modules/openfoam/src/OpenFOAM_Types.f90 @@ -104,7 +104,7 @@ MODULE OpenFOAM_Types REAL(KIND=C_FLOAT) :: BladeLength REAL(KIND=C_FLOAT) :: TowerHeight REAL(KIND=C_FLOAT) :: TowerBaseHeight - LOGICAL(KIND=C_BOOL) :: NodeClusterType + INTEGER(KIND=C_INT) :: NodeClusterType END TYPE OpFM_ParameterType_C TYPE, PUBLIC :: OpFM_ParameterType TYPE( OpFM_ParameterType_C ) :: C_obj @@ -419,7 +419,7 @@ SUBROUTINE OpFM_PackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrM Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%TowerBaseHeight Re_Xferred = Re_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%NodeClusterType, IntKiBuf(1)) + IntKiBuf(Int_Xferred) = InData%NodeClusterType Int_Xferred = Int_Xferred + 1 END SUBROUTINE OpFM_PackInitInput @@ -507,7 +507,7 @@ SUBROUTINE OpFM_UnPackInitInput( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, E OutData%TowerBaseHeight = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%C_obj%TowerBaseHeight = OutData%TowerBaseHeight - OutData%NodeClusterType = TRANSFER(IntKiBuf(Int_Xferred), OutData%NodeClusterType) + OutData%NodeClusterType = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 OutData%C_obj%NodeClusterType = OutData%NodeClusterType END SUBROUTINE OpFM_UnPackInitInput @@ -1957,7 +1957,7 @@ SUBROUTINE OpFM_PackParam( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%TowerBaseHeight Re_Xferred = Re_Xferred + 1 - IntKiBuf(Int_Xferred) = TRANSFER(InData%NodeClusterType, IntKiBuf(1)) + IntKiBuf(Int_Xferred) = InData%NodeClusterType Int_Xferred = Int_Xferred + 1 END SUBROUTINE OpFM_PackParam @@ -2060,7 +2060,7 @@ SUBROUTINE OpFM_UnPackParam( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrMs OutData%TowerBaseHeight = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%C_obj%TowerBaseHeight = OutData%TowerBaseHeight - OutData%NodeClusterType = TRANSFER(IntKiBuf(Int_Xferred), OutData%NodeClusterType) + OutData%NodeClusterType = IntKiBuf(Int_Xferred) Int_Xferred = Int_Xferred + 1 OutData%C_obj%NodeClusterType = OutData%NodeClusterType END SUBROUTINE OpFM_UnPackParam 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/modules/wakedynamics/src/WakeDynamics.f90 b/modules/wakedynamics/src/WakeDynamics.f90 index afa31e4304..017d2e00e7 100644 --- a/modules/wakedynamics/src/WakeDynamics.f90 +++ b/modules/wakedynamics/src/WakeDynamics.f90 @@ -42,6 +42,7 @@ module WakeDynamics public :: WD_UpdateStates ! Loose coupling routine for solving for constraint states, integrating ! continuous states, and updating discrete states public :: WD_CalcOutput ! Routine for computing outputs + public :: WD_WritePlaneOutputs ! Routine for IO Operation public :: WD_CalcConstrStateResidual ! Tight coupling routine for returning the constraint state residual public :: WD_TEST_Axi2Cart @@ -427,7 +428,6 @@ subroutine WD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! Define parameters !............................................................................................ p%TurbNum = InitInp%TurbNum - p%OutFileRoot = InitInp%OutFileRoot p%DT_low = interval ! Parameters from input file p%Mod_Wake = InitInp%InputFileData%Mod_Wake @@ -479,10 +479,9 @@ subroutine WD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut end do ! Path for VTK outputs - call GetPath( p%OutFileRoot, rootDir, baseName ) + call GetPath( InitInp%OutFileRoot, rootDir, baseName ) + p%OutFileRoot = baseName p%OutFileVTKDir = trim(rootDir) // 'vtk_ff_planes' - - p%filtParam = exp(-2.0_ReKi*pi*p%dt_low*InitInp%InputFileData%f_c) p%oneMinusFiltParam = 1.0_ReKi - p%filtParam @@ -1224,7 +1223,6 @@ subroutine AddSwirl(r, Vt_wake, y, z, Vy_curl, Vz_curl) real(ReKi), dimension(:,:), intent(inout) :: Vy_curl !< Curl velocity in the y direction (m/s) real(ReKi), dimension(:,:), intent(inout) :: Vz_curl !< Curl velocity in the z direction (m/s) - real(ReKi) :: alpha integer(IntKi) :: iz, iy, iLow, nr real(ReKi) :: r_tmp, r_max real(ReKi) :: Vt, S, C ! Sine and cosine @@ -1257,9 +1255,7 @@ end subroutine AddSwirl subroutine WD_TEST_AddVelocityCurl() real(ReKi) :: Vy_curl(2,2)=0.0_ReKi - real(ReKi) :: Vy_curl_ref(2,2) real(ReKi) :: Vz_curl(2,2)=0.0_ReKi - real(ReKi) :: Vz_curl_ref(2,2) real(ReKi) :: y(2)=(/ 0., 2./) real(ReKi) :: z(2)=(/-1.,1./) real(ReKi) :: Gamma0 @@ -1287,7 +1283,6 @@ subroutine filter_angles2(psi_filt, chi_filt, psi, chi, alpha, alpha_bar) real(ReKi), intent(in) :: chi !< skew angle real(ReKi), intent(in) :: alpha !< filter weight real(ReKi), intent(in) :: alpha_bar !< 1-alpha - real(ReKi) :: t_filt !< output real(ReKi) :: x,y real(ReKi) :: lambda(3,2) real(ReKi) :: theta_out(3) @@ -1391,7 +1386,6 @@ subroutine Axisymmetric2CartesianVx(Vx_axi, r, y, z, Vx) real(ReKi), dimension(:,:), intent(inout) :: Vx !< Axial velocity, distributed across the plane (m/s) integer(IntKi) :: iz, iy, nr, iLow real(ReKi) :: r_tmp, r_max - real(ReKi) :: Vr, S, C ! Sine and cosine nr = size(r) r_max = r(nr) do iz = 1,size(z) @@ -1498,16 +1492,12 @@ subroutine WD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) CHARACTER(*), INTENT( OUT) :: errMsg !< Error message if errStat /= ErrID_None - integer, parameter :: indx = 1 integer(intKi) :: n, i, iy, iz, maxPln integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'WD_CalcOutput' real(ReKi) :: correction(3) real(ReKi) :: C, S, dvdr, dvdtheta_r, R, r_tmp - character(1024) :: Filename - type(VTK_Misc) :: mvtk - real(ReKi), dimension(3) :: dx errStat = ErrID_None errMsg = "" @@ -1550,7 +1540,10 @@ subroutine WD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) ! Misc approx m%Ct_avg = get_Ctavg(p%r, u%Ct_azavg, u%D_rotor) m%GammaCurl = u%D_Rotor/2. * u%Vx_wind_disk * m%Ct_avg * sin(u%chi_skew) * cos(u%chi_skew) - + + if ( p%OutAllPlanes ) then + call mkdir(p%OutFileVTKDir) + endif else y%x_plane = xd%x_plane @@ -1616,13 +1609,40 @@ subroutine WD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) end if +end subroutine WD_CalcOutput + +!---------------------------------------------------------------------------------------------------------------------------------- +!> +subroutine WD_WritePlaneOutputs( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) + use VTK ! + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + TYPE(WD_InputType), INTENT(IN ) :: u !< Inputs at Time t + TYPE(WD_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(WD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at t + TYPE(WD_DiscreteStateType), INTENT(IN ) :: xd !< Discrete states at t + TYPE(WD_ConstraintStateType), INTENT(IN ) :: z !< Constraint states at t + TYPE(WD_OtherStateType), INTENT(IN ) :: OtherState !< Other states at t + TYPE(WD_OutputType), INTENT(IN ) :: y !< Outputs computed at t (Input only so that mesh con- + type(WD_MiscVarType), intent(IN ) :: m !< Misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: errStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: errMsg !< Error message if errStat /= ErrID_None + integer(intKi) :: n, i + integer(intKi) :: ErrStat2 + character(ErrMsgLen) :: ErrMsg2 + character(*), parameter :: RoutineName = 'WD_WritePlaneOutputs' + real(ReKi) :: correction(3) + character(1024) :: Filename + type(VTK_Misc) :: mvtk + real(ReKi), dimension(3) :: dx + real(ReKi), dimension(3) :: x0 + errStat = ErrID_None + errMsg = "" + + n = nint(t/p%DT_low) ! --- VTK outputs per plane if (p%OutAllPlanes) then call vtk_misc_init(mvtk) call set_vtk_binary_format(.false., mvtk) - if ( OtherState%firstPass ) then - call MKDIR(p%OutFileVTKDir) - endif do i = 0, min(n-1,p%NumPlanes-1), 1 ! if (EqualRealNos(t,0.0_DbKi) ) then ! write(Filename,'(A,I4.4,A)') trim(p%OutFileVTKDir)//'/PlaneOutputsAtPlane_',i,'_Init.vtk' @@ -1647,11 +1667,14 @@ subroutine WD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) dx(1) = 0.0 dx(2) = p%dr dx(3) = p%dr - call vtk_dataset_structured_points((/xd%p_plane(1,i),-dx*p%NumRadii,-dx*p%NumRadii/),dx,(/1,p%NumRadii*2-1,p%NumRadii*2-1/),mvtk) + x0(1) = xd%p_plane(1,i) + x0(2) = xd%p_plane(2,i) - p%dr*p%NumRadii + x0(3) = xd%p_plane(3,i) - p%dr*p%NumRadii + call vtk_dataset_structured_points(x0, dx, (/1,p%NumRadii*2-1,p%NumRadii*2-1/),mvtk) call vtk_point_data_init(mvtk) - call vtk_point_data_scalar(xd%Vx_wake2(:,:,i),'Vx',mvtk) - call vtk_point_data_scalar(xd%Vy_wake2(:,:,i),'Vy',mvtk) - call vtk_point_data_scalar(xd%Vz_wake2(:,:,i),'Vz',mvtk) + call vtk_point_data_scalar(y%Vx_wake2(:,:,i),'Vx',mvtk) + call vtk_point_data_scalar(y%Vy_wake2(:,:,i),'Vy',mvtk) + call vtk_point_data_scalar(y%Vz_wake2(:,:,i),'Vz',mvtk) call vtk_point_data_scalar(m%vt_amb2(:,:,i),'vt_amb2', mvtk) call vtk_point_data_scalar(m%vt_shr2(:,:,i),'vt_shr2', mvtk) call vtk_point_data_scalar(m%vt_tot2(:,:,i),'vt_tot2', mvtk) @@ -1664,11 +1687,14 @@ subroutine WD_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, errStat, errMsg ) call vtk_point_data_scalar(y%WAT_k_mt(:,:,i),'k_mt', mvtk) endif call vtk_close_file(mvtk) + else + call SetErrStat(ErrID_Fatal, '[INFO] Failed to write: '//trim(filename), errStat, errMsg, RoutineName) endif enddo ! loop on planes endif -end subroutine WD_CalcOutput +end subroutine WD_WritePlaneOutputs + !---------------------------------------------------------------------------------------------------------------------------------- !> Tight coupling routine for solving for the residual of the constraint state equations @@ -1691,10 +1717,10 @@ subroutine WD_CalcConstrStateResidual( Time, u, p, x, xd, z, OtherState, m, z_re ! Local variables - integer, parameter :: indx = 1 - integer(intKi) :: ErrStat2 - character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'WD_CalcConstrStateResidual' + !integer, parameter :: indx = 1 + !integer(intKi) :: ErrStat2 + !character(ErrMsgLen) :: ErrMsg2 + !character(*), parameter :: RoutineName = 'WD_CalcConstrStateResidual' @@ -1779,8 +1805,6 @@ SUBROUTINE ValidateInitInputData( DT_low, InitInp, InputFileData, errStat, errMs ! local variables - integer(IntKi) :: k ! Blade number - integer(IntKi) :: j ! node number character(*), parameter :: RoutineName = 'ValidateInitInputData' errStat = ErrID_None diff --git a/reg_tests/CTestList.cmake b/reg_tests/CTestList.cmake index 0e04de8a9f..3c4588f3b0 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -282,6 +282,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) @@ -306,6 +307,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") @@ -386,6 +389,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 ef6ab57591..091660bef2 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit ef6ab575919f1db597702f1c3f86a16bdc2b4338 +Subproject commit 091660bef274e3057c9cb32f9a10131f0021b843 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 @@ - +