diff --git a/.github/workflows/automated-dev-tests.yml b/.github/workflows/automated-dev-tests.yml index ad8507476f..ef764833db 100644 --- a/.github/workflows/automated-dev-tests.yml +++ b/.github/workflows/automated-dev-tests.yml @@ -41,12 +41,16 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 - 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,12 +61,15 @@ 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 \ -DVARIABLE_TRACKING=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ + -DBUILD_OPENFAST_SIMULINK_API=ON \ ${GITHUB_WORKSPACE} # -DDOUBLE_PRECISION=OFF \ - name: Build all @@ -85,6 +92,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 +106,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 +130,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 +148,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 +176,16 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + python-version: '3.11' cache: 'pip' + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 - 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 +197,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 \ @@ -186,6 +208,7 @@ jobs: -DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_TESTING:BOOL=ON \ -DCTEST_PLOT_ERRORS:BOOL=ON \ + -DBUILD_OPENFAST_SIMULINK_API=ON \ ${GITHUB_WORKSPACE} - name: Build openfast-postlib working-directory: ${{runner.workspace}}/openfast/build @@ -209,14 +232,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 +270,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 +308,21 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 +348,14 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 +366,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 +410,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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: @@ -412,18 +468,20 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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} @@ -471,14 +529,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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: | @@ -510,24 +577,30 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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" \ + -LE "cpp|linear|python|fastlib|aeromap" \ -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" - name: Failing test artifacts uses: actions/upload-artifact@v3 @@ -545,6 +618,85 @@ jobs: !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + rtest-OF-simulink: + runs-on: ubuntu-22.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Install dependencies + run: | + sudo apt-get update -y + sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev libopenblas-dev libopenblas-openmp-dev + - name: Set up MATLAB + uses: matlab-actions/setup-matlab@v1 + - name: Build FAST_SFunc + working-directory: ${{runner.workspace}}/openfast/build + run: | + cmake \ + -DUSE_LOCAL_STATIC_LAPACK:BOOL=ON \ + ${GITHUB_WORKSPACE} + cmake --build . --target FAST_SFunc + - name: Run MATLAB tests and generate artifacts + uses: matlab-actions/run-tests@v1 + with: + source-folder: ${{runner.workspace}}/openfast/build/glue-codes/simulink; ${{runner.workspace}}/openfast/glue-codes/simulink/examples + test-results-junit: test-results/results.xml + code-coverage-cobertura: code-coverage/coverage.xml + + + rtest-OF-5MW_Land_AeroMap: + runs-on: ubuntu-22.04 + needs: build-openfast-release + steps: + - name: Cache the workspace + uses: actions/cache@v3.0.4 + with: + path: ${{runner.workspace}} + key: build-openfast-release-${{ github.sha }} + - name: Setup Python + uses: actions/setup-python@v3 + with: + 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 5MW aero map tests + working-directory: ${{runner.workspace}}/openfast/build + run: | + ctest -VV -L aeromap -LE "cpp|linear|python" -R 5MW_Land_AeroMap + - name: Failing test artifacts + uses: actions/upload-artifact@v3 + if: failure() + with: + name: rtest-OF-5MW_Land_AeroMap + path: | + ${{runner.workspace}}/openfast/build/reg_tests/modules + ${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/5MW_Baseline + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AOC + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/AWT27 + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/SWRT + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/UAE_VI + !${{runner.workspace}}/openfast/build/reg_tests/glue-codes/openfast/WP_Baseline + + rtest-OF-5MW_OC4Semi_WSt_WavesWN: runs-on: ubuntu-22.04 needs: build-openfast-release @@ -564,10 +716,16 @@ jobs: python -m pip install --upgrade pip pip install numpy "Bokeh>=2.4,!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3" sudo apt-get update -y + sudo apt-get install -y libopenblas-dev libopenblas-openmp-dev sudo apt-get install -y libhdf5-dev libopenmpi-dev libyaml-cpp-dev - name: Configure Tests working-directory: ${{runner.workspace}}/openfast/build run: | + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} cmake --build . --target regression_test_controllers - name: Run 5MW tests working-directory: ${{runner.workspace}}/openfast/build @@ -601,17 +759,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 @@ -645,17 +809,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 @@ -689,17 +859,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 @@ -733,17 +909,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 @@ -777,22 +959,27 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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 --build . --target regression_test_controllers + cmake \ + -DPython_ROOT_DIR:STRING=${{env.pythonLocation}} \ + -DBUILD_TESTING:BOOL=ON \ + -DCTEST_PLOT_ERRORS:BOOL=ON \ + ${GITHUB_WORKSPACE} - 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() @@ -821,17 +1008,23 @@ jobs: - name: Setup Python uses: actions/setup-python@v4 with: - python-version: '3.10' + 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/CMakeLists.txt b/CMakeLists.txt index 5b14d3dd8d..899e0d3571 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,10 +108,18 @@ include(${CMAKE_SOURCE_DIR}/cmake/set_rpath.cmake) if (OPENMP OR BUILD_FASTFARM OR BUILD_OPENFAST_CPP_API) FIND_PACKAGE(OpenMP REQUIRED) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set(CMAKE_FORTRAN_FLAGS "${CMAKE_FORTRAN_FLAGS} ${OpenMP_FORTRAN_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") + if (OpenMP_Fortran_FOUND) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") + link_libraries("${OpenMP_Fortran_LIBRARIES}") + endif() + if (OpenMP_C_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + link_libraries("${OpenMP_C_LIBRARIES}") + endif() + if (OpenMP_CXX_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + link_libraries("${OpenMP_CXX_LIBRARIES}") + endif() endif() #------------------------------------------------------------------------------- @@ -130,11 +138,13 @@ if (USE_LOCAL_STATIC_LAPACK) include(ExternalProject) ExternalProject_Add(lapack URL http://www.netlib.org/lapack/lapack.tgz - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/install + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/install + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON PREFIX ${CMAKE_BINARY_DIR}/dependencies BUILD_BYPRODUCTS ${BLAS_LIB_PATH} ${LAPACK_LIB_PATH} ) - set(LAPACK_LIBRARIES ${BLAS_LIB_PATH} ${LAPACK_LIB_PATH} CACHE STRING "LAPACK library" FORCE) + set(LAPACK_LIBRARIES ${LAPACK_LIB_PATH} ${BLAS_LIB_PATH} CACHE STRING "LAPACK library" FORCE) install(FILES ${LAPACK_LIBRARIES} DESTINATION ${CMAKE_SOURCE_DIR}/install/lib) message(STATUS "Using LAPACK libraries: ${LAPACK_LIBRARIES}") else() @@ -192,7 +202,7 @@ set(OPENFAST_MODULES map turbsim supercontroller - openfoam + externalinflow openfast-library ) diff --git a/docs/OtherSupporting/OutListParameters.xlsx b/docs/OtherSupporting/OutListParameters.xlsx index c63c101d77..af0848d30f 100644 Binary files a/docs/OtherSupporting/OutListParameters.xlsx and b/docs/OtherSupporting/OutListParameters.xlsx differ diff --git a/docs/OtherSupporting/TurbSim/Corrections.md b/docs/OtherSupporting/TurbSim/Corrections.md new file mode 100644 index 0000000000..8e735b0800 --- /dev/null +++ b/docs/OtherSupporting/TurbSim/Corrections.md @@ -0,0 +1,5 @@ +# Corrections to TurbSim_v2.00.pdf DRAFT + +## p. 34: Input file for User-Defined Profiles +The User-Defined profiles listed in the "Profiles" section contain horizontal angles, not wind direction, so it should say + `3. Horizontal wind angle (degrees, measured counter-clockwise from above)` \ No newline at end of file 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/docs/source/user/aeromap/examples/AeroMap.dvr b/docs/source/user/aeromap/examples/AeroMap.dvr new file mode 100644 index 0000000000..303e9fe5f3 --- /dev/null +++ b/docs/source/user/aeromap/examples/AeroMap.dvr @@ -0,0 +1,40 @@ +------- OpenFAST AeroMap INPUT FILE ---------------------------------------------- +AeroMap generation for FAST Certification Test #18: NREL 5.0 MW Baseline Wind Turbine (Onshore) +---------------------- OpenFAST MODEL FILE --------------------------------------- +"openfast.fst" FstFile - Name of the primary OpenFAST input file (-) +---------------------- STEADY-STATE SIMULATION CONTROL -------------------------------------- +false Echo - Echo input data to .ech (flag) + 1e-4 Toler - Convergence tolerance for nonlinear solve residual equation [>0] (-) + 50 MaxIter - Maximum number of iteration steps for nonlinear solve [>0] (-) + 1 N_SSJac - Number of iteration steps to recalculate steady-state Jacobian (-) [1=every iteration step, 2=every other step] (Note: for large flexible blades, this almost always needs to be 1) + 1E+05 SSJacSclFact - Scaling factor used in steady-state Jacobians (-) [on order of blade mass in kg] +---------------------- STEADY-STATE CASES -------------------------------------- + 1 WindSpeedOrTSR - Choice of swept parameter (switch) { 1:wind speed; 2: TSR } + 25 NumCases - Number of cases to run +RotSpeed WndSpeedOrTSR Pitch +(rpm) (m/s or -) (deg) + 8.0000 3.0000 0.0000 + 8.0000 6.0000 0.0000 + 8.0000 9.0000 0.0000 + 8.0000 12.0000 0.0000 + 8.0000 15.0000 0.0000 + 8.0000 15.0000 3.0000 + 8.0000 12.0000 3.0000 + 8.0000 9.0000 3.0000 + 8.0000 6.0000 3.0000 + 8.0000 3.0000 3.0000 + 8.0000 3.0000 6.0000 + 8.0000 6.0000 6.0000 + 8.0000 9.0000 6.0000 + 8.0000 12.0000 6.0000 + 8.0000 15.0000 6.0000 + 8.0000 15.0000 9.0000 + 8.0000 12.0000 9.0000 + 8.0000 9.0000 9.0000 + 8.0000 6.0000 9.0000 + 8.0000 3.0000 9.0000 + 8.0000 3.0000 12.0000 + 8.0000 6.0000 12.0000 + 8.0000 9.0000 12.0000 + 8.0000 12.0000 12.0000 + 8.0000 15.0000 12.0000 diff --git a/docs/source/user/turbsim/examples/TurbSim_User.profiles b/docs/source/user/turbsim/examples/TurbSim_User.profiles index 3063d952bb..63af934660 100644 --- a/docs/source/user/turbsim/examples/TurbSim_User.profiles +++ b/docs/source/user/turbsim/examples/TurbSim_User.profiles @@ -6,8 +6,8 @@ Made up profiles 1.0 StdScale2 - v-component scaling factor for the input standard deviation 0.534 StdScale3 - w-component scaling factor for the input standard deviation ----------------------------------------------------------------------------------- -Height Wind Speed Wind --Direction-- Standard Deviation Length Scale - (m) (m/s) (deg, cntr-clockwise ) (m/s) (m) +Height Wind Speed Wind --Angle-- Standard Deviation Length Scale + (m) (m/s) (deg, cntr-clockwise ) (m/s) (m) ----------------------------------------------------------------------------------- 15.0 3 00 .100 3 25.0 4 00 .200 4 diff --git a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 index 6eaf96b93f..144aea8635 100644 --- a/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 +++ b/glue-codes/fast-farm/src/FAST_Farm_Subs.f90 @@ -2690,6 +2690,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/openfast-cpp/CMakeLists.txt b/glue-codes/openfast-cpp/CMakeLists.txt index 1b9cc76bf0..2d23a99790 100644 --- a/glue-codes/openfast-cpp/CMakeLists.txt +++ b/glue-codes/openfast-cpp/CMakeLists.txt @@ -29,7 +29,10 @@ find_package(ZLIB REQUIRED) find_package(HDF5 REQUIRED COMPONENTS C HL) find_package(yaml-cpp REQUIRED) -add_library(openfastcpplib src/OpenFAST.cpp src/SC.cpp) +add_library(openfastcpplib + src/OpenFAST.cpp + src/SC.cpp +) set_property(TARGET openfastcpplib PROPERTY POSITION_INDEPENDENT_CODE ON) target_link_libraries(openfastcpplib openfastlib diff --git a/glue-codes/openfast-cpp/src/OpenFAST.H b/glue-codes/openfast-cpp/src/OpenFAST.H index 21ed980aa3..b744b3eacb 100644 --- a/glue-codes/openfast-cpp/src/OpenFAST.H +++ b/glue-codes/openfast-cpp/src/OpenFAST.H @@ -9,7 +9,7 @@ #include #include #include "dlfcn.h" -//TODO: The skip MPICXX is put in place primarily to get around errors in OpenFOAM. This will cause problems if the driver program uses C++ API for MPI. +//TODO: The skip MPICXX is put in place primarily to get around errors in ExternalInflow. This will cause problems if the driver program uses C++ API for MPI. #ifndef OMPI_SKIP_MPICXX #define OMPI_SKIP_MPICXX #endif @@ -115,8 +115,8 @@ class OpenFAST { std::vector > velNodeData; // Position and velocity data at the velocity (aerodyn) nodes - (nTurbines, nTimesteps * nPoints * 6) hid_t velNodeDataFile; // HDF-5 tag of file containing velocity (aerodyn) node data file - std::vector cDriver_Input_from_FAST; - std::vector cDriver_Output_to_FAST; + std::vector cDriver_Input_from_FAST; + std::vector cDriver_Output_to_FAST; // Turbine Number is DIFFERENT from TurbID. Turbine Number simply runs from 0:n-1 locally and globally. std::map turbineMapGlobToProc; // Mapping global turbine number to processor number @@ -171,7 +171,7 @@ class OpenFAST { hid_t openVelocityDataFile(bool createFile); void readVelocityData(int nTimesteps); - void writeVelocityData(hid_t h5file, int iTurb, int iTimestep, OpFM_InputType_t iData, OpFM_OutputType_t oData); + void writeVelocityData(hid_t h5file, int iTurb, int iTimestep, ExtInfw_InputType_t iData, ExtInfw_OutputType_t oData); herr_t closeVelocityDataFile(int nt_global, hid_t velDataFile); void backupVelocityDataFile(int curTimeStep, hid_t & velDataFile); @@ -286,8 +286,8 @@ class OpenFAST { void loadSuperController(const fastInputs & fi); - void setOutputsToFAST(OpFM_InputType_t cDriver_Input_from_FAST, OpFM_OutputType_t cDriver_Output_to_FAST) ; // An example to set velocities at the Aerodyn nodes - void applyVelocityData(int iPrestart, int iTurb, OpFM_OutputType_t cDriver_Output_to_FAST, std::vector & velData) ; + void setOutputsToFAST(ExtInfw_InputType_t cDriver_Input_from_FAST, ExtInfw_OutputType_t cDriver_Output_to_FAST) ; // An example to set velocities at the Aerodyn nodes + void applyVelocityData(int iPrestart, int iTurb, ExtInfw_OutputType_t cDriver_Output_to_FAST, std::vector & velData) ; }; diff --git a/glue-codes/openfast-cpp/src/OpenFAST.cpp b/glue-codes/openfast-cpp/src/OpenFAST.cpp index 7a26e2017d..b8b34dd6fa 100644 --- a/glue-codes/openfast-cpp/src/OpenFAST.cpp +++ b/glue-codes/openfast-cpp/src/OpenFAST.cpp @@ -62,7 +62,7 @@ void fast::OpenFAST::init() { CheckpointFileRoot[iTurb].data() + (CheckpointFileRoot[iTurb].size() + 1), currentFileName ); - FAST_OpFM_Restart( + FAST_ExtInfw_Restart( &iTurb, currentFileName, &AbortErrLev, @@ -116,7 +116,7 @@ void fast::OpenFAST::init() { FASTInputFileName[iTurb].data() + (FASTInputFileName[iTurb].size() + 1), currentFileName ); - FAST_OpFM_Init( + FAST_ExtInfw_Init( &iTurb, &tMax, currentFileName, @@ -186,7 +186,7 @@ void fast::OpenFAST::init() { FASTInputFileName[iTurb].data() + (FASTInputFileName[iTurb].size() + 1), currentFileName ); - FAST_OpFM_Init( + FAST_ExtInfw_Init( &iTurb, &tMax, currentFileName, @@ -275,7 +275,7 @@ void fast::OpenFAST::solution0() { } for (int iTurb=0; iTurb < nTurbinesProc; iTurb++) { - FAST_OpFM_Solution0(&iTurb, &ErrStat, ErrMsg); + FAST_ExtInfw_Solution0(&iTurb, &ErrStat, ErrMsg); checkError(ErrStat, ErrMsg); } @@ -301,7 +301,7 @@ void fast::OpenFAST::step() { // setOutputsToFAST(cDriver_Input_from_FAST[iTurb], cDriver_Output_to_FAST[iTurb]); // this advances the states, calls CalcOutput, and solves for next inputs. Predictor-corrector loop is imbeded here: - // (note OpenFOAM could do subcycling around this step) + // (note ExternalInflow could do subcycling around this step) writeVelocityData(velNodeDataFile, iTurb, nt_global, cDriver_Input_from_FAST[iTurb], cDriver_Output_to_FAST[iTurb]); @@ -316,7 +316,7 @@ void fast::OpenFAST::step() { fastcpp_velocity_file.close() ; } - FAST_OpFM_Step(&iTurb, &ErrStat, ErrMsg); + FAST_ExtInfw_Step(&iTurb, &ErrStat, ErrMsg); checkError(ErrStat, ErrMsg); // Compute the force from the nacelle only if the drag coefficient is @@ -394,8 +394,8 @@ void fast::OpenFAST::stepNoWrite() { // setOutputsToFAST(cDriver_Input_from_FAST[iTurb], cDriver_Output_to_FAST[iTurb]); // this advances the states, calls CalcOutput, and solves for next inputs. Predictor-corrector loop is imbeded here: - // (note OpenFOAM could do subcycling around this step) - FAST_OpFM_Step(&iTurb, &ErrStat, ErrMsg); + // (note ExternalInflow could do subcycling around this step) + FAST_ExtInfw_Step(&iTurb, &ErrStat, ErrMsg); checkError(ErrStat, ErrMsg); } @@ -480,7 +480,7 @@ void fast::OpenFAST::checkError(const int ErrStat, const char * ErrMsg){ } } -void fast::OpenFAST::setOutputsToFAST(OpFM_InputType_t cDriver_Input_from_FAST, OpFM_OutputType_t cDriver_Output_to_FAST){ +void fast::OpenFAST::setOutputsToFAST(ExtInfw_InputType_t cDriver_Input_from_FAST, ExtInfw_OutputType_t cDriver_Output_to_FAST){ // routine sets the u-v-w wind speeds used in FAST and the SuperController inputs @@ -848,7 +848,7 @@ void fast::OpenFAST::allocateMemory() { // Allocate memory for Turbine datastructure for all turbines FAST_AllocateTurbines(&nTurbinesProc, &ErrStat, ErrMsg); - // Allocate memory for OpFM Input types in FAST + // Allocate memory for ExtInfw Input types in FAST cDriver_Input_from_FAST.resize(nTurbinesProc) ; cDriver_Output_to_FAST.resize(nTurbinesProc) ; @@ -994,7 +994,7 @@ void fast::OpenFAST::backupVelocityDataFile(int curTimeStep, hid_t & velDataFile velDataFile = openVelocityDataFile(false); } -void fast::OpenFAST::writeVelocityData(hid_t h5File, int iTurb, int iTimestep, OpFM_InputType_t iData, OpFM_OutputType_t oData) { +void fast::OpenFAST::writeVelocityData(hid_t h5File, int iTurb, int iTimestep, ExtInfw_InputType_t iData, ExtInfw_OutputType_t oData) { hsize_t start[3]; start[0] = iTimestep; start[1] = 0; start[2] = 0; int nVelPts = get_numVelPtsLoc(iTurb) ; @@ -1028,7 +1028,7 @@ void fast::OpenFAST::writeVelocityData(hid_t h5File, int iTurb, int iTimestep, O } -void fast::OpenFAST::applyVelocityData(int iPrestart, int iTurb, OpFM_OutputType_t cDriver_Output_to_FAST, std::vector & velData) { +void fast::OpenFAST::applyVelocityData(int iPrestart, int iTurb, ExtInfw_OutputType_t cDriver_Output_to_FAST, std::vector & velData) { int nVelPts = get_numVelPtsLoc(iTurb); for (int j = 0; j < nVelPts; j++){ cDriver_Output_to_FAST.u[j] = velData[(iPrestart*nVelPts+j)*6 + 3]; diff --git a/glue-codes/openfast/src/FAST_Prog.f90 b/glue-codes/openfast/src/FAST_Prog.f90 index fb08b019cd..f4e9b2bfe2 100644 --- a/glue-codes/openfast/src/FAST_Prog.f90 +++ b/glue-codes/openfast/src/FAST_Prog.f90 @@ -32,7 +32,8 @@ PROGRAM FAST USE FAST_Subs ! all of the ModuleName and ModuleName_types modules are inherited from FAST_Subs - +USE FAST_SS_Subs, ONLY : FAST_RunSteadyStateDriver + IMPLICIT NONE ! Local parameters: @@ -58,7 +59,7 @@ PROGRAM FAST ! determine if this is a restart from checkpoint !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CALL NWTC_Init() ! initialize NWTC library (set some global constants and if necessary, open console for writing) - ProgName = 'OpenFAST' + ProgName = FAST_Ver%Name InputFile = "" CheckpointRoot = "" @@ -76,6 +77,11 @@ PROGRAM FAST Restart_step = Turbine(1)%p_FAST%n_TMax_m1 + 1 CALL ExitThisProgram_T( Turbine(1), ErrID_None, .true., SkipRunTimeMsg = .TRUE. ) + ELSE IF ( TRIM(FlagArg) == 'STEADYSTATE' ) THEN ! Do steady-state analysis, not time-marching -- this works for only 1 turbine (i.e., NumTurbines==1)! + + ! this runs the steady-state solver driver and ENDS the program: + CALL FAST_RunSteadyStateDriver( Turbine(1) ) + ELSEIF ( LEN( TRIM(FlagArg) ) > 0 ) THEN ! Any other flag, end normally CALL NormStop() diff --git a/glue-codes/simulink/CMakeLists.txt b/glue-codes/simulink/CMakeLists.txt index dbb1fa9a2f..b84ee0d80d 100644 --- a/glue-codes/simulink/CMakeLists.txt +++ b/glue-codes/simulink/CMakeLists.txt @@ -14,6 +14,34 @@ # 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,30 +58,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} @@ -64,7 +70,7 @@ set_target_properties(FAST_SFunc PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_Fortran_MODULE_DIRECTORY}/matlab) target_include_directories(FAST_SFunc PUBLIC $ - $ + $ $ ) if(APPLE OR UNIX) diff --git a/glue-codes/simulink/examples/test_openfast_simulink.m b/glue-codes/simulink/examples/test_openfast_simulink.m new file mode 100644 index 0000000000..0686b125bd --- /dev/null +++ b/glue-codes/simulink/examples/test_openfast_simulink.m @@ -0,0 +1,31 @@ +%% Test OpenFAST Simulink Interface +classdef test_openfast_simulink < matlab.unittest.TestCase + + %% Test Method Block + methods (Test) + + function testOpenLoopRuns(testCase) + + workspace_root = getenv("GITHUB_WORKSPACE"); + + this_file_path = fileparts(which(mfilename())); + + cd(this_file_path); + + % these variables are defined in the OpenLoop model's FAST_SFunc block: + FAST_InputFileName = fullfile(workspace_root, 'reg_tests', 'r-test', 'glue-codes', 'openfast', 'AOC_WSt', 'AOC_WSt.fst'); + TMax = 5; % seconds + + mdl = "OpenLoop"; + + %simIn = Simulink.SimulationInput(mdl); + %simIn = setBlockParameter(simIn, "sldemo_househeat/Set Point", "Value", FAST_InputFileName); + + assignin("base", "FAST_InputFileName", FAST_InputFileName); + assignin("base", "TMax", TMax); + + sim(mdl, [0,TMax]); + + end + end +end diff --git a/modules/aerodyn/CMakeLists.txt b/modules/aerodyn/CMakeLists.txt index 0248f647e8..7d5f9e4f03 100644 --- a/modules/aerodyn/CMakeLists.txt +++ b/modules/aerodyn/CMakeLists.txt @@ -27,7 +27,7 @@ if (GENERATE_TYPES) endif() # AeroDyn Library -add_library(aerodynlib +add_library(aerodynlib STATIC src/AeroDyn.f90 src/AeroDyn_IO_Params.f90 src/AeroDyn_IO.f90 @@ -71,7 +71,7 @@ add_library(aerodynlib target_link_libraries(aerodynlib ifwlib nwtclibs) # AeroDyn Driver Subs Library -add_library(aerodyn_driver_subs +add_library(aerodyn_driver_subs STATIC src/AeroDyn_Driver_Subs.f90 src/AeroDyn_Driver_Types.f90 ) diff --git a/modules/aerodyn/src/AeroDyn.f90 b/modules/aerodyn/src/AeroDyn.f90 index 5373bd0f28..c622f0d12e 100644 --- a/modules/aerodyn/src/AeroDyn.f90 +++ b/modules/aerodyn/src/AeroDyn.f90 @@ -183,7 +183,7 @@ subroutine AD_SetInitOut(MHK, WtrDpth, p, p_AD, InputFileData, InitOut, errStat, CALL SetErrStat(ErrID_Fatal,"Error allocating memory for TwrElev.", ErrStat, ErrMsg, RoutineName) RETURN END IF - IF ( MHK == 1 ) THEN + IF ( MHK == MHK_FixedBottom ) THEN InitOut%TwrElev(:) = InputFileData%TwrElev(:) - WtrDpth ELSE InitOut%TwrElev(:) = InputFileData%TwrElev(:) @@ -337,7 +337,27 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut !FIXME: add handling for passing of blade files and other types of files. call ReadInputFiles( InitInp%InputFile, InputFileData, interval, p%RootName, NumBlades, AeroProjMod, UnEcho, ErrStat2, ErrMsg2 ) if (Failed()) return; - + + ! override some parameters to simplify for aero maps + ! bjj: do we put a warning here if any of these values aren't currently set this way? + if (InitInp%CompAeroMaps) then + InputFileData%DTAero = interval ! we're not using this, so set it to something "safe" + do iR = 1, nRotors + InputFileData%AFAeroMod = AFAeroMod_Steady + InputFileData%TwrPotent = TwrPotent_none + InputFileData%TwrShadow = TwrShadow_none + InputFileData%TwrAero = .false. + InputFileData%FrozenWake = .false. + !InputFileData%CavitCheck = .false. + !InputFileData%TFinAero = .false. ! not sure if this needs to be set or not + end do + + if (InputFileData%WakeMod == WakeMod_DBEMT) then + ! these models (DBEMT and BEMT) should be the same at the first time step, so we'll simplify here + InputFileData%WakeMod = WakeMod_BEMT + end if + end if + ! Validate the inputs call ValidateInputData( InitInp, InputFileData, NumBlades, ErrStat2, ErrMsg2 ) if (Failed()) return; @@ -483,7 +503,7 @@ subroutine AD_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut !............................................................................................ ! Initialize Jacobian: !............................................................................................ - if (InitInp%Linearize) then + if (InitInp%Linearize .or. InitInp%CompAeroMaps) then do iR = 1, nRotors call Init_Jacobian(InputFileData%rotors(iR), p%rotors(iR), p, u%rotors(iR), y%rotors(iR), m%rotors(iR), InitOut%rotors(iR), errStat2, errMsg2) if (Failed()) return; @@ -598,12 +618,13 @@ subroutine Init_MiscVars(m, p, u, y, errStat, errMsg) errStat = ErrID_None errMsg = "" - - + 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, '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) call allocAry( m%SigmaCavitCrit, p%NumBlNds, p%numBlades, 'm%SigmaCavitCrit', errStat2, errMsg2); call setErrStat(errStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -648,6 +669,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 @@ -1072,6 +1095,7 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er u%InflowOnHub = 0.0_ReKi u%InflowOnNacelle = 0.0_ReKi u%InflowOnTailFin = 0.0_ReKi + u%AvgDiskVel = 0.0_ReKi ! Meshes for motion inputs (ElastoDyn and/or BeamDyn) !................ @@ -1098,7 +1122,7 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er ! set node initial position/orientation position = 0.0_ReKi do j=1,p%NumTwrNds - IF ( MHK == 1 ) THEN + IF ( MHK == MHK_FixedBottom ) THEN position(3) = InputFileData%TwrElev(j) - WtrDpth ELSE position(3) = InputFileData%TwrElev(j) @@ -1235,6 +1259,11 @@ subroutine Init_u( u, p, p_AD, InputFileData, MHK, WtrDpth, InitInp, errStat, er u%BladeMotion(k)%RotationVel = 0.0_ReKi u%BladeMotion(k)%TranslationAcc = 0.0_ReKi + if (p_AD%CompAeroMaps) then + do j=1,InputFileData%BladeProps(k)%NumBlNds + u%BladeMotion(k)%TranslationVel(:,j) = cross_product(u%HubMotion%RefOrientation(1,:,1)*InitInp%RotSpeed, u%BladeMotion(k)%Position(:,j)-u%HubMotion%Position(:,1)) + end do + end if end do !k=numBlades @@ -1277,7 +1306,11 @@ subroutine SetParameters( InitInp, InputFileData, RotData, p, p_AD, ErrStat, Err ErrStat = ErrID_None ErrMsg = "" + ! NOTE: p_AD%FlowField is set in the glue code (or ADI module); seems like FlowField should be an initialization input so that would be clearer for new developers... + p_AD%UA_Flag = InputFileData%AFAeroMod == AFAeroMod_BL_unsteady + p_AD%CompAeroMaps = InitInp%CompAeroMaps + p%MHK = InitInp%MHK p_AD%DT = InputFileData%DTAero @@ -1580,12 +1613,12 @@ subroutine AD_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, m, errStat ! local variables integer(intKi) :: iR ! Counter on rotors - integer(IntKi) :: i, node - real(DbKi) :: BEMT_utimes(2) !< Times associated with m%BEMT_u(:), in seconds - type(AD_InputType) :: uInterp ! Interpolated/Extrapolated input - integer(intKi) :: ErrStat2 ! temporary Error status - character(ErrMsgLen) :: ErrMsg2 ! temporary Error message - character(*), parameter :: RoutineName = 'AD_UpdateStates' + integer :: i + real(DbKi) :: BEMT_utimes(2) !< Times associated with m%BEMT_u(:), in seconds + type(AD_InputType) :: uInterp ! Interpolated/Extrapolated input + integer(intKi) :: ErrStat2 ! temporary Error status + character(ErrMsgLen) :: ErrMsg2 ! temporary Error message + character(*), parameter :: RoutineName = 'AD_UpdateStates' ErrStat = ErrID_None ErrMsg = "" @@ -1682,6 +1715,9 @@ subroutine AD_CalcWind(t, u, p, o, m, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = "" + if (.not. associated(p%FlowField)) return ! use the initial (or input) values for these inputs + ! bjj: if the previous line is not appropriate, then some other check for if FlowField has been set should be used. + ! Initialize node. The StartNode is used for OpenFOAM to provide the wind ! velocities. The node ordering in OpenFOAM must match that used in here. StartNode = 1 @@ -1968,11 +2004,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: @@ -1996,6 +2033,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 @@ -2234,16 +2279,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 @@ -2764,7 +2809,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 @@ -2774,7 +2819,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 @@ -2910,8 +2955,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 @@ -3226,7 +3272,7 @@ subroutine SetInputsForFVW(p, u, m, errStat, errMsg) integer(intKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'SetInputsForFVW' - integer :: iW + integer :: iW ErrStat = ErrID_None ErrMsg = "" @@ -3638,11 +3684,11 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) enddo endif - if (InitInp%MHK == 0 .and. InputFileData%CavitCheck) call SetErrStat ( ErrID_Fatal, 'A cavitation check can only be performed for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) - if (InitInp%MHK == 0 .and. InputFileData%Buoyancy) call SetErrStat ( ErrID_Fatal, 'Buoyancy can only be calculated for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) - if (InitInp%MHK == 1 .and. InputFileData%CompAA .or. InitInp%MHK == 2 .and. InputFileData%CompAA) call SetErrStat ( ErrID_Fatal, 'The aeroacoustics module cannot be used with an MHK turbine.', ErrStat, ErrMsg, RoutineName ) + if (InitInp%MHK == MHK_None .and. InputFileData%CavitCheck) call SetErrStat ( ErrID_Fatal, 'A cavitation check can only be performed for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) + if (InitInp%MHK == MHK_None .and. InputFileData%Buoyancy) call SetErrStat ( ErrID_Fatal, 'Buoyancy can only be calculated for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) + if (InitInp%MHK /= MHK_None .and. InputFileData%CompAA ) call SetErrStat ( ErrID_Fatal, 'The aeroacoustics module cannot be used with an MHK turbine.', ErrStat, ErrMsg, RoutineName ) do iR = 1,size(NumBl) - if (InitInp%MHK == 1 .and. InputFileData%rotors(iR)%TFinAero .or. InitInp%MHK == 2 .and. InputFileData%rotors(iR)%TFinAero) call SetErrStat ( ErrID_Fatal, 'A tail fin cannot be modeled for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) + if (InitInp%MHK /= MHK_None .and. InputFileData%rotors(iR)%TFinAero) call SetErrStat ( ErrID_Fatal, 'A tail fin cannot be modeled for an MHK turbine.', ErrStat, ErrMsg, RoutineName ) enddo if (InputFileData%AirDens <= 0.0) call SetErrStat ( ErrID_Fatal, 'The density of the working fluid must be greater than zero.', ErrStat, ErrMsg, RoutineName ) @@ -3750,12 +3796,12 @@ SUBROUTINE ValidateInputData( InitInp, InputFileData, NumBl, ErrStat, ErrMsg ) ! check that the elevation is increasing: do j=2,InputFileData%rotors(iR)%NumTwrNds - if ( InitInp%MHK /= 2 ) then + if ( InitInp%MHK /= MHK_Floating ) then if ( InputFileData%rotors(iR)%TwrElev(j) <= InputFileData%rotors(iR)%TwrElev(j-1) ) then call SetErrStat( ErrID_Fatal, 'The tower nodes must be entered in increasing elevation.', ErrStat, ErrMsg, RoutineName ) exit end if - else if ( InitInp%MHK == 2 ) then + else if ( InputFileData%rotors(iR)%TwrElev(j) >= InputFileData%rotors(iR)%TwrElev(j-1) ) then call SetErrStat( ErrID_Fatal, 'The tower nodes must be entered in decreasing elevation for a floating MHK turbine.', ErrStat, ErrMsg, RoutineName ) exit @@ -4135,6 +4181,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) @@ -4147,6 +4195,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) @@ -4251,6 +4301,7 @@ SUBROUTINE Init_BEMTmodule( InputFileData, RotInputFileData, u_AD, u, p, p_AD, x call SetErrStat( ErrID_Fatal, "DTAero was changed in Init_BEMTmodule(); this is not allowed.", ErrStat2, ErrMsg2, RoutineName) !m%UseFrozenWake = .FALSE. !BJJ: set this in BEMT + if (p_AD%CompAeroMaps) p%BEMT%lin_nx = 0 ! we are going to ignore this call Cleanup() return @@ -4485,7 +4536,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 @@ -4760,13 +4811,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 @@ -6180,7 +6234,7 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, REAL(ReKi), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: xd_op(:) !< values of linearized discrete states REAL(ReKi), ALLOCATABLE, OPTIONAL, INTENT(INOUT) :: z_op(:) !< values of linearized constraint states - INTEGER(IntKi) :: index, i, j, k + INTEGER(IntKi) :: index, i, j, k, n INTEGER(IntKi) :: nu INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -6195,14 +6249,19 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, ErrMsg = '' IF ( PRESENT( u_op ) ) THEN - - nu = size(p%Jac_u_indx,1) + u%TowerMotion%NNodes * 6 & ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM - + u%hubMotion%NNodes * 6 ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM - do i=1,p%NumBlades - nu = nu + u%BladeMotion(i)%NNodes * 6 & ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM - + u%BladeRootMotion(i)%NNodes * 6 ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM + nu = size(p%Jac_u_indx,1) + do i=1,p%NumBl_Lin + nu = nu + u%BladeMotion(i)%NNodes * 6 ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM end do - + + if (.not. p_AD%CompAeroMaps) then + nu = nu + u%TowerMotion%NNodes * 6 & ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM + + u%hubMotion%NNodes * 6 ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM + do i=1,p%NumBlades + nu = nu + u%BladeRootMotion(i)%NNodes * 6 ! Jac_u_indx has 3 orientation angles, but the OP needs the full 9 elements of the DCM + end do + end if + if (.not. allocated(u_op)) then call AllocAry(u_op, nu, 'u_op', ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -6211,55 +6270,70 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, index = 1 - FieldMask = .false. - FieldMask(MASKID_TRANSLATIONDISP) = .true. - FieldMask(MASKID_Orientation) = .true. - FieldMask(MASKID_TRANSLATIONVel) = .true. - call PackMotionMesh(u%TowerMotion, u_op, index, FieldMask=FieldMask) - - FieldMask(MASKID_TRANSLATIONVel) = .false. - FieldMask(MASKID_RotationVel) = .true. - call PackMotionMesh(u%HubMotion, u_op, index, FieldMask=FieldMask) - - FieldMask = .false. - FieldMask(MASKID_Orientation) = .true. - do k = 1,p%NumBlades - call PackMotionMesh(u%BladeRootMotion(k), u_op, index, FieldMask=FieldMask) - end do + if (.not. p_AD%CompAeroMaps) then + FieldMask = .false. + FieldMask(MASKID_TRANSLATIONDISP) = .true. + FieldMask(MASKID_Orientation) = .true. + FieldMask(MASKID_TRANSLATIONVel) = .true. + call PackMotionMesh(u%TowerMotion, u_op, index, FieldMask=FieldMask) + + FieldMask(MASKID_TRANSLATIONVel) = .false. + FieldMask(MASKID_RotationVel) = .true. + call PackMotionMesh(u%HubMotion, u_op, index, FieldMask=FieldMask) + + FieldMask = .false. + FieldMask(MASKID_Orientation) = .true. + do k = 1,p%NumBlades + call PackMotionMesh(u%BladeRootMotion(k), u_op, index, FieldMask=FieldMask) + end do - FieldMask(MASKID_TRANSLATIONDISP) = .true. - FieldMask(MASKID_Orientation) = .true. - FieldMask(MASKID_TRANSLATIONVel) = .true. - FieldMask(MASKID_RotationVel) = .true. - FieldMask(MASKID_TRANSLATIONAcc) = .true. - do k=1,p%NumBlades + FieldMask(MASKID_TRANSLATIONDISP) = .true. + FieldMask(MASKID_Orientation) = .true. + FieldMask(MASKID_TRANSLATIONVel) = .true. + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TRANSLATIONAcc) = .true. + else + FieldMask = .false. + FieldMask(MASKID_TRANSLATIONDISP) = .true. + FieldMask(MASKID_Orientation) = .true. + FieldMask(MASKID_TRANSLATIONVel) = .true. + end if + + do k=1,p%NumBl_Lin call PackMotionMesh(u%BladeMotion(k), u_op, index, FieldMask=FieldMask) end do - do k=1,p%NumBlades - do i=1,p%NumBlNds + if (.not. p_AD%CompAeroMaps) then + do k=1,p%NumBlades + do i=1,p%NumBlNds + do j=1,3 + u_op(index) = u%Bld(k)%InflowOnBlade(j,i) + index = index + 1 + end do + end do + end do + + do i=1,p%NumTwrNds do j=1,3 - u_op(index) = u%Bld(k)%InflowOnBlade(j,i) + u_op(index) = u%InflowOnTower(j,i) index = index + 1 end do end do - end do - - do i=1,p%NumTwrNds - do j=1,3 - u_op(index) = u%InflowOnTower(j,i) - index = index + 1 - end do - end do - - do k=1,p%NumBlades - do j = 1, size(u%UserProp,1) ! Number of nodes for a blade - u_op(index) = u%UserProp(j,k) - index = index + 1 + ! UserProp + do k=1,p%NumBlades + do j = 1, size(u%UserProp,1) ! Number of nodes for a blade + u_op(index) = u%UserProp(j,k) + index = index + 1 + end do end do - end do - - ! I'm not including this in the linearization yet + + ! AvgDiskVel + !do i=1,3 + ! u_op(index) = u%AvgDiskVel(i) + ! index = index + 1 + !end do + + ! I'm not including this in the linearization yet !do i=1,u%NacelleMotion%NNodes ! 1 or 0 ! do j=1,3 ! u_op(index) = u%InflowOnNacelle(j) @@ -6274,6 +6348,7 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, ! end do !end do + end if END IF IF ( PRESENT( y_op ) ) THEN @@ -6287,23 +6362,24 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, index = 1 - call PackLoadMesh(y%TowerLoad, y_op, index) - do k=1,p%NumBlades + if (.not. p_AD%CompAeroMaps) call PackLoadMesh(y%TowerLoad, y_op, index) + do k=1,p%NumBl_Lin call PackLoadMesh(y%BladeLoad(k), y_op, index) end do - index = index - 1 - do i=1,p%NumOuts + p%BldNd_TotNumOuts - y_op(i+index) = y%WriteOutput(i) - end do - + if (.not. p_AD%CompAeroMaps) then + index = index - 1 + do i=1,p%NumOuts + p%BldNd_TotNumOuts + y_op(i+index) = y%WriteOutput(i) + end do + end if END IF IF ( PRESENT( x_op ) ) THEN if (.not. allocated(x_op)) then - call AllocAry(x_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx,'x_op',ErrStat2,ErrMsg2) + call AllocAry(x_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + p%BEMT%lin_nx,'x_op',ErrStat2,ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return end if @@ -6330,34 +6406,32 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, end do end if - + ! UA states if (p%BEMT%UA%lin_nx>0) then - if (p%BEMT%UA%UAMod==UA_OYE) then - do j=1,p%NumBlades ! size(x%BEMT%UA%element,2) - do i=1,p%NumBlNds ! size(x%BEMT%UA%element,1) - x_op(index) = x%BEMT%UA%element(i,j)%x(4) - index = index + 1 - end do - end do - else - do j=1,p%NumBlades ! size(x%BEMT%UA%element,2) - do i=1,p%NumBlNds ! size(x%BEMT%UA%element,1) - do k=1,4 !size(x%BEMT%UA%element(i,j)%x) !linearize only first 4 states (5th is vortex) - x_op(index) = x%BEMT%UA%element(i,j)%x(k) - index = index + 1 - end do - end do - end do - endif + do n=1,p%BEMT%UA%lin_nx + i = p%BEMT%UA%lin_xIndx(n,1) + j = p%BEMT%UA%lin_xIndx(n,2) + k = p%BEMT%UA%lin_xIndx(n,3) + x_op(index) = x%BEMT%UA%element(i,j)%x(k) + + index = index + 1 + end do end if - + ! BEMT states + if (p%BEMT%lin_nx>0) then + !do k = 1,size(x%BEMT%V_w) + ! x_op(index) = x%BEMT%v_w(k) + ! index = index + 1 + !end do + end if + END IF IF ( PRESENT( dx_op ) ) THEN if (.not. allocated(dx_op)) then - call AllocAry(dx_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx,'dx_op',ErrStat2,ErrMsg2) + call AllocAry(dx_op, p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + p%BEMT%lin_nx,'dx_op',ErrStat2,ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return end if @@ -6392,25 +6466,25 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, end do end if - + ! UA states derivatives if (p%BEMT%UA%lin_nx>0) then - if (p%BEMT%UA%UAMod==UA_OYE) then - do j=1,p%NumBlades ! size(dxdt%BEMT%UA%element,2) - do i=1,p%NumBlNds ! size(dxdt%BEMT%UA%element,1) - dx_op(index) = dxdt%BEMT%UA%element(i,j)%x(4) - index = index + 1 - end do - end do - else - do j=1,p%NumBlades ! size(dxdt%BEMT%UA%element,2) - do i=1,p%NumBlNds ! size(dxdt%BEMT%UA%element,1) - do k=1,4 !size(dxdt%BEMT%UA%element(i,j)%x) don't linearize 5th state - dx_op(index) = dxdt%BEMT%UA%element(i,j)%x(k) - index = index + 1 - end do - end do - end do - endif + do n=1,p%BEMT%UA%lin_nx + i = p%BEMT%UA%lin_xIndx(n,1) + j = p%BEMT%UA%lin_xIndx(n,2) + k = p%BEMT%UA%lin_xIndx(n,3) + dx_op(index) = dxdt%BEMT%UA%element(i,j)%x(k) + + index = index + 1 + end do + end if + ! BEMT states derivatives + if (p%BEMT%lin_nx>0) then + call SetErrStat(ErrID_Fatal,'Number of lin states for bem should be zero for now.', ErrStat, ErrMsg, RoutineName) + return + !do k = 1,size(x%BEMT%V_w) + ! dx_op(index) = dxdt%BEMT%v_w(k) + ! index = index + 1 + !end do end if call AD_DestroyRotContinuousStateType( dxdt, ErrStat2, ErrMsg2) @@ -6442,9 +6516,10 @@ SUBROUTINE RotGetOP( t, u, p, p_AD, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, END SUBROUTINE RotGetOP !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) +SUBROUTINE Init_Jacobian_y( p, p_AD, y, InitOut, ErrStat, ErrMsg) TYPE(RotParameterType) , INTENT(INOUT) :: p !< parameters + TYPE(AD_ParameterType) , INTENT(INOUT) :: p_AD !< parameters TYPE(RotOutputType) , INTENT(IN ) :: y !< outputs TYPE(RotInitOutputType) , INTENT(INOUT) :: InitOut !< Initialization output data (for Jacobian row/column names) @@ -6463,11 +6538,15 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) ErrMsg = "" - ! determine how many outputs there are in the Jacobians - p%Jac_ny = y%TowerLoad%NNodes * 6 & ! 3 forces + 3 moments at each node - + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values - - do k=1,p%NumBlades + ! determine how many outputs there are in the Jacobians + if (p_AD%CompAeroMaps) then + p%Jac_ny = 0 ! we skip tower and writeOutput values in the solve (note: y%TowerLoad%NNodes=0) + else + p%Jac_ny = y%TowerLoad%NNodes * 6 & ! 3 forces + 3 moments at each node + + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values + end if + + do k=1,p%NumBl_Lin p%Jac_ny = p%Jac_ny + y%BladeLoad(k)%NNodes * 6 ! 3 forces + 3 moments at each node end do @@ -6480,97 +6559,102 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) InitOut%RotFrame_y = .false. ! default all to false, then set the true ones below indx_next = 1 - call PackLoadMesh_Names(y%TowerLoad, 'Tower', InitOut%LinNames_y, indx_next) + if (.not. p_AD%CompAeroMaps) call PackLoadMesh_Names(y%TowerLoad, 'Tower', InitOut%LinNames_y, indx_next) ! note: y%TowerLoad%NNodes=0 for aeroMaps indx_last = indx_next - do k=1,p%NumBlades + do k=1,p%NumBl_Lin call PackLoadMesh_Names(y%BladeLoad(k), 'Blade '//trim(num2lstr(k)), InitOut%LinNames_y, indx_next) end do ! InitOut%RotFrame_y(indx_last:indx_next-1) = .true. ! The mesh fields are in the global frame, so are not in the rotating frame - do i=1,p%NumOuts + p%BldNd_TotNumOuts - InitOut%LinNames_y(i+indx_next-1) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) !trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units - end do + if (.not. p_AD%CompAeroMaps) then - - ! check for all the WriteOutput values that are functions of blade number: - allocate( AllOut(0:MaxOutPts), STAT=ErrStat2 ) ! allocate starting at zero to account for invalid output channels - if (ErrStat2 /=0 ) then - call SetErrStat(ErrID_Info, 'error allocating temporary space for AllOut',ErrStat,ErrMsg,RoutineName) - return; - end if + do i=1,p%NumOuts + p%BldNd_TotNumOuts + InitOut%LinNames_y(i+indx_next-1) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) !trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units + end do - AllOut = .false. - do k=1,3 - AllOut( BAzimuth(k)) = .true. - AllOut( BPitch (k)) = .true. - - ! AllOut( BFldFx( k)) = .true. - ! AllOut( BFldFy( k)) = .true. - ! AllOut( BFldFz( k)) = .true. - ! AllOut( BFldMx( k)) = .true. - ! AllOut( BFldMy( k)) = .true. - ! AllOut( BFldMz( k)) = .true. - - do j=1,9 - AllOut(BNVUndx(j,k)) = .true. - AllOut(BNVUndy(j,k)) = .true. - AllOut(BNVUndz(j,k)) = .true. - AllOut(BNVDisx(j,k)) = .true. - AllOut(BNVDisy(j,k)) = .true. - AllOut(BNVDisz(j,k)) = .true. - AllOut(BNSTVx (j,k)) = .true. - AllOut(BNSTVy (j,k)) = .true. - AllOut(BNSTVz (j,k)) = .true. - AllOut(BNVRel (j,k)) = .true. - AllOut(BNDynP (j,k)) = .true. - AllOut(BNRe (j,k)) = .true. - AllOut(BNM (j,k)) = .true. - AllOut(BNVIndx(j,k)) = .true. - AllOut(BNVIndy(j,k)) = .true. - AllOut(BNAxInd(j,k)) = .true. - AllOut(BNTnInd(j,k)) = .true. - AllOut(BNAlpha(j,k)) = .true. - AllOut(BNTheta(j,k)) = .true. - AllOut(BNPhi (j,k)) = .true. - AllOut(BNCurve(j,k)) = .true. - AllOut(BNCl (j,k)) = .true. - AllOut(BNCd (j,k)) = .true. - AllOut(BNCm (j,k)) = .true. - AllOut(BNCx (j,k)) = .true. - AllOut(BNCy (j,k)) = .true. - AllOut(BNCn (j,k)) = .true. - AllOut(BNCt (j,k)) = .true. - AllOut(BNFl (j,k)) = .true. - AllOut(BNFd (j,k)) = .true. - AllOut(BNMm (j,k)) = .true. - AllOut(BNFx (j,k)) = .true. - AllOut(BNFy (j,k)) = .true. - AllOut(BNFn (j,k)) = .true. - AllOut(BNFt (j,k)) = .true. - AllOut(BNClrnc(j,k)) = .true. + ! check for all the WriteOutput values that are functions of blade number: + allocate( AllOut(0:MaxOutPts), STAT=ErrStat2 ) ! allocate starting at zero to account for invalid output channels + if (ErrStat2 /=0 ) then + call SetErrStat(ErrID_Info, 'error allocating temporary space for AllOut',ErrStat,ErrMsg,RoutineName) + return; + end if + + AllOut = .false. + do k=1,3 + AllOut( BAzimuth(k)) = .true. + AllOut( BPitch (k)) = .true. + + AllOut( BAeroFx( k)) = .true. + AllOut( BAeroFy( k)) = .true. + AllOut( BAeroFz( k)) = .true. + AllOut( BAeroMx( k)) = .true. + AllOut( BAeroMy( k)) = .true. + AllOut( BAeroMz( k)) = .true. + !AllOut( TipClrnc(k)) = .true. + + do j=1,9 + AllOut(BNVUndx(j,k)) = .true. + AllOut(BNVUndy(j,k)) = .true. + AllOut(BNVUndz(j,k)) = .true. + AllOut(BNVDisx(j,k)) = .true. + AllOut(BNVDisy(j,k)) = .true. + AllOut(BNVDisz(j,k)) = .true. + AllOut(BNSTVx (j,k)) = .true. + AllOut(BNSTVy (j,k)) = .true. + AllOut(BNSTVz (j,k)) = .true. + AllOut(BNVRel (j,k)) = .true. + AllOut(BNDynP (j,k)) = .true. + AllOut(BNRe (j,k)) = .true. + AllOut(BNM (j,k)) = .true. + AllOut(BNVIndx(j,k)) = .true. + AllOut(BNVIndy(j,k)) = .true. + AllOut(BNAxInd(j,k)) = .true. + AllOut(BNTnInd(j,k)) = .true. + AllOut(BNAlpha(j,k)) = .true. + AllOut(BNTheta(j,k)) = .true. + AllOut(BNPhi (j,k)) = .true. + AllOut(BNCurve(j,k)) = .true. + AllOut(BNCl (j,k)) = .true. + AllOut(BNCd (j,k)) = .true. + AllOut(BNCm (j,k)) = .true. + AllOut(BNCx (j,k)) = .true. + AllOut(BNCy (j,k)) = .true. + AllOut(BNCn (j,k)) = .true. + AllOut(BNCt (j,k)) = .true. + AllOut(BNFl (j,k)) = .true. + AllOut(BNFd (j,k)) = .true. + AllOut(BNMm (j,k)) = .true. + AllOut(BNFx (j,k)) = .true. + AllOut(BNFy (j,k)) = .true. + AllOut(BNFn (j,k)) = .true. + AllOut(BNFt (j,k)) = .true. + AllOut(BNClrnc(j,k)) = .true. + end do end do - end do - do i=1,p%NumOuts - InitOut%RotFrame_y(i+indx_next-1) = AllOut( p%OutParam(i)%Indx ) - end do + do i=1,p%NumOuts + InitOut%RotFrame_y(i+indx_next-1) = AllOut( p%OutParam(i)%Indx ) + end do - do i=1,p%BldNd_TotNumOuts - InitOut%RotFrame_y(i+p%NumOuts+indx_next-1) = .true. - !AbsCant, AbsToe, AbsTwist should probably be set to .false. - end do + do i=1,p%BldNd_TotNumOuts + InitOut%RotFrame_y(i+p%NumOuts+indx_next-1) = .true. + !AbsCant, AbsToe, AbsTwist should probably be set to .false. + end do - deallocate(AllOut) + deallocate(AllOut) + + end if END SUBROUTINE Init_Jacobian_y !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) +SUBROUTINE Init_Jacobian_u( InputFileData, p, p_AD, u, InitOut, ErrStat, ErrMsg) TYPE(RotInputFile) , INTENT(IN ) :: InputFileData !< input file data (for default blade perturbation) TYPE(RotParameterType) , INTENT(INOUT) :: p !< parameters + TYPE(AD_ParameterType) , INTENT(INOUT) :: p_AD !< parameters TYPE(RotInputType) , INTENT(IN ) :: u !< inputs TYPE(RotInitOutputType) , INTENT(INOUT) :: InitOut !< Initialization output data (for Jacobian row/column names) @@ -6579,6 +6663,7 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) ! local variables: INTEGER(IntKi) :: i, j, k, index, index_last, nu, i_meshField + INTEGER(IntKi) :: NumFieldsForLinearization REAL(ReKi) :: perturb, perturb_t, perturb_b(MaxBl) LOGICAL :: FieldMask(FIELDMASK_SIZE) CHARACTER(1), PARAMETER :: UVW(3) = (/'U','V','W'/) @@ -6591,17 +6676,32 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) ! determine how many inputs there are in the Jacobians - nu = u%TowerMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities at each node - + u%hubMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Rotation velocities at each node - ! + size( m%InflowOnBlade) & ! TODO: FIXLIN - ! + size( m%InflowOnTower) & !note that we are not passing the inflow on nacelle or hub here ! TODO: FIXLIN - + size( u%UserProp) - - do i=1,p%NumBlades - nu = nu + u%BladeMotion(i)%NNodes * 15 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities + 3 Rotation velocities + 3 TranslationAcc at each node - + u%BladeRootMotion(i)%NNodes * 3 ! 3 orientations at each node - end do + if (p_AD%CompAeroMaps) then + nu = 0 + + NumFieldsForLinearization = 3 ! Translation Displacements + orientations + Translation velocities at each node on the blade mesh + else + nu = u%TowerMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Translation velocities at each node + + u%hubMotion%NNodes * 9 & ! 3 Translation Displacements + 3 orientations + 3 Rotation velocities at each node + ! + size( u%InflowOnBlade) & + + size( u%InflowOnTower) & !note that we are not passing the inflow on nacelle or hub here + + size( u%UserProp) + !+ 3 ! 3 velocity components in AvgDiskVel; note that we are not passing the inflow on nacelle or hub here + + do k=1,size(u%Bld) ! hopefully this is allocated + nu = nu + size(u%Bld(k)%InflowOnBlade) + end do + NumFieldsForLinearization = 5 ! Translation Displacements + orientations + Translation velocities + Rotation velocities + TranslationAcc at each node on the blade mesh + do i=1,p%NumBlades + nu = nu + u%BladeRootMotion(i)%NNodes * 3 ! 3 orientations at each node + end do + end if + + do i=1,p%NumBl_Lin + nu = nu + u%BladeMotion(i)%NNodes * 3*NumFieldsForLinearization ! 3 components per field + end do + ! all other inputs ignored @@ -6619,54 +6719,59 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) !............... ! AD input mappings stored in p%Jac_u_indx: - !............... + !............... index = 1 - !Module/Mesh/Field: u%TowerMotion%TranslationDisp = 1; - !Module/Mesh/Field: u%TowerMotion%Orientation = 2; - !Module/Mesh/Field: u%TowerMotion%TranslationVel = 3; - do i_meshField = 1,3 - do i=1,u%TowerMotion%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField - p%Jac_u_indx(index,2) = j !component index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do - !Module/Mesh/Field: u%HubMotion%TranslationDisp = 4; - !Module/Mesh/Field: u%HubMotion%Orientation = 5; - !Module/Mesh/Field: u%HubMotion%RotationVel = 6; - do i_meshField = 4,6 - do i=1,u%HubMotion%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField - p%Jac_u_indx(index,2) = j !component index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + if (.not. p_AD%CompAeroMaps) then - !bjj: if MaxBl (max blades) changes, we need to modify this - !Module/Mesh/Field: u%BladeRootMotion(1)%Orientation = 7; - !Module/Mesh/Field: u%BladeRootMotion(2)%Orientation = 8; - !Module/Mesh/Field: u%BladeRootMotion(3)%Orientation = 9; - do k=1,p%NumBlades - do i_meshField = 6,6 - do i=1,u%BladeRootMotion(k)%NNodes + !Module/Mesh/Field: u%TowerMotion%TranslationDisp = 1; + !Module/Mesh/Field: u%TowerMotion%Orientation = 2; + !Module/Mesh/Field: u%TowerMotion%TranslationVel = 3; + do i_meshField = 1,3 + do i=1,u%TowerMotion%NNodes do j=1,3 - p%Jac_u_indx(index,1) = i_meshField + k + p%Jac_u_indx(index,1) = i_meshField p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 end do !j end do !i + end do + + !Module/Mesh/Field: u%HubMotion%TranslationDisp = 4; + !Module/Mesh/Field: u%HubMotion%Orientation = 5; + !Module/Mesh/Field: u%HubMotion%RotationVel = 6; + do i_meshField = 4,6 + do i=1,u%HubMotion%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField + p%Jac_u_indx(index,2) = j !component index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do + + !bjj: if MaxBl (max blades) changes, we need to modify this + !Module/Mesh/Field: u%BladeRootMotion(1)%Orientation = 7; + !Module/Mesh/Field: u%BladeRootMotion(2)%Orientation = 8; + !Module/Mesh/Field: u%BladeRootMotion(3)%Orientation = 9; + do k=1,p%NumBlades + do i_meshField = 6,6 + do i=1,u%BladeRootMotion(k)%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField + k + p%Jac_u_indx(index,2) = j !component index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i - end do !i_meshField - end do !k + end do !i_meshField + end do !k + end if ! .not. compAeroMaps + !bjj: if MaxBl (max blades) changes, we need to modify this !Module/Mesh/Field: u%BladeMotion(1)%TranslationDisp = 10; !Module/Mesh/Field: u%BladeMotion(1)%Orientation = 11; @@ -6685,54 +6790,67 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) !Module/Mesh/Field: u%BladeMotion(3)%TranslationVel = 22; !Module/Mesh/Field: u%BladeMotion(3)%RotationVel = 23; !Module/Mesh/Field: u%BladeMotion(3)%TranslationAcc = 24; - do k=1,p%NumBlades - do i_meshField = 1,5 + do k=1,p%NumBl_Lin + do i_meshField = 1,NumFieldsForLinearization do i=1,u%BladeMotion(k)%NNodes do j=1,3 - p%Jac_u_indx(index,1) = 9 + i_meshField + (k-1)*5 + p%Jac_u_indx(index,1) = 9 + i_meshField + (k-1)*5 ! this should use the MAX possible NumFieldsForLinearization = 5 (so that it's consistent for all cases) p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 end do !j end do !i - end do !i_meshField + end do !i_meshField end do !k - !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 25; - !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 26; - !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 27; - do k=1,size(u%Bld) ! p%NumBlades - do i=1,size(u%Bld(k)%InflowOnBlade,2) ! numNodes + if (.not. p_AD%CompAeroMaps) then + + !Module/Mesh/Field: u%InflowOnBlade(:,:,1) = 25; + !Module/Mesh/Field: u%InflowOnBlade(:,:,2) = 26; + !Module/Mesh/Field: u%InflowOnBlade(:,:,3) = 27; + do k=1,size(u%Bld) ! p%NumBlades + do i=1,size(u%Bld(k)%InflowOnBlade,2) ! numNodes + do j=1,3 + p%Jac_u_indx(index,1) = 24 + k + p%Jac_u_indx(index,2) = j !component index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do !k + + !Module/Mesh/Field: u%InflowOnTower(:,:) = 28; + do i=1,size(u%InflowOnTower,2) ! numNodes do j=1,3 - p%Jac_u_indx(index,1) = 24 + k + p%Jac_u_indx(index,1) = 28 p%Jac_u_indx(index,2) = j !component index: j p%Jac_u_indx(index,3) = i !Node: i index = index + 1 - end do !j + end do !j end do !i - end do !k + + !Module/Mesh/Field: u%UserProp(:,:) = 29,30,31; + do k=1,size(u%UserProp,2) ! p%NumBlades + do i=1,size(u%UserProp,1) ! numNodes + p%Jac_u_indx(index,1) = 28 + k + p%Jac_u_indx(index,2) = 1 !component index: this is a scalar, so 1, but is never used + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !i + end do !k + + !Module/Mesh/Field: u%AvgDiskVel(:,:) = 32; + !do j=1,3 + ! p%Jac_u_indx(index,1) = 32 + ! p%Jac_u_indx(index,2) = j !component index: j + ! p%Jac_u_indx(index,3) = 1 !Node: 1 (not really necessary here, since we have only a 1 dimensional array) + ! index = index + 1 + !end do !j + + + end if ! .not. compAeroMaps - !Module/Mesh/Field: u%InflowOnTower(:,:) = 28; - do i=1,size(u%InflowOnTower,2) ! numNodes - do j=1,3 - p%Jac_u_indx(index,1) = 28 - p%Jac_u_indx(index,2) = j !component index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - - !Module/Mesh/Field: u%UserProp(:,:) = 29,30,31; - - do k=1,size(u%UserProp,2) ! p%NumBlades - do i=1,size(u%UserProp,1) ! numNodes - p%Jac_u_indx(index,1) = 28 + k - p%Jac_u_indx(index,2) = 1 !component index: this is a scalar, so 1, but is never used - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !i - end do !k !...................................... ! default perturbations, p%du: !...................................... @@ -6771,9 +6889,12 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) p%du(24 + k) = perturb_b(k) ! u%InflowOnBlade(:,:,k) = 24 + k end do p%du(28) = perturb_t ! u%InflowOnTower(:,:) = 28 - do k=1,p%NumBlades + do k=1,p%NumBl_Lin p%du(28+k) = perturb ! u%UserProp(:,:) = 29,30,31 end do + !p%du(32) = minval(perturb_b(1:p%numBlades)) ! u%AvgDiskVel(:) = 32 + + !..................... ! get names of linearized inputs !..................... @@ -6787,60 +6908,77 @@ SUBROUTINE Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat, ErrMsg) InitOut%IsLoad_u = .false. ! None of AeroDyn's inputs are loads InitOut%RotFrame_u = .false. - do k=0,p%NumBlades*p%NumBlNds-1 - InitOut%RotFrame_u(nu - k ) = .true. ! UserProp(:,:) - end do + if (.not. p_AD%CompAeroMaps) then + do k=0,p%NumBl_Lin*p%NumBlNds-1 + InitOut%RotFrame_u(nu - k ) = .true. ! UserProp(:,:) ! TODO TODO TODO add -3 due to DiskAvgVel + end do + endif + index = 1 FieldMask = .false. FieldMask(MASKID_TRANSLATIONDISP) = .true. FieldMask(MASKID_Orientation) = .true. FieldMask(MASKID_TRANSLATIONVel) = .true. - call PackMotionMesh_Names(u%TowerMotion, 'Tower', InitOut%LinNames_u, index, FieldMask=FieldMask) + if (.not. p_AD%CompAeroMaps) call PackMotionMesh_Names(u%TowerMotion, 'Tower', InitOut%LinNames_u, index, FieldMask=FieldMask) FieldMask(MASKID_TRANSLATIONVel) = .false. FieldMask(MASKID_RotationVel) = .true. - call PackMotionMesh_Names(u%HubMotion, 'Hub', InitOut%LinNames_u, index, FieldMask=FieldMask) + if (.not. p_AD%CompAeroMaps) call PackMotionMesh_Names(u%HubMotion, 'Hub', InitOut%LinNames_u, index, FieldMask=FieldMask) index_last = index FieldMask = .false. FieldMask(MASKID_Orientation) = .true. - do k = 1,p%NumBlades - call PackMotionMesh_Names(u%BladeRootMotion(k), 'Blade root '//trim(num2lstr(k)), InitOut%LinNames_u, index, FieldMask=FieldMask) - end do + if (.not. p_AD%CompAeroMaps) then + do k = 1,p%NumBlades + call PackMotionMesh_Names(u%BladeRootMotion(k), 'Blade root '//trim(num2lstr(k)), InitOut%LinNames_u, index, FieldMask=FieldMask) + end do + + + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TRANSLATIONAcc) = .true. + end if FieldMask(MASKID_TRANSLATIONDISP) = .true. FieldMask(MASKID_TRANSLATIONVel) = .true. - FieldMask(MASKID_RotationVel) = .true. - FieldMask(MASKID_TRANSLATIONAcc) = .true. - do k=1,p%NumBlades + do k=1,p%NumBl_Lin call PackMotionMesh_Names(u%BladeMotion(k), 'Blade '//trim(num2lstr(k)), InitOut%LinNames_u, index, FieldMask=FieldMask) end do - do k=1,p%NumBlades - do i=1,p%NumBlNds - do j=1,3 - InitOut%LinNames_u(index) = UVW(j)//'-component inflow on blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', m/s' - index = index + 1 + if (.not. p_AD%CompAeroMaps) then + do k=1,p%NumBlades + do i=1,p%NumBlNds + do j=1,3 + InitOut%LinNames_u(index) = UVW(j)//'-component inflow on blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', m/s' + index = index + 1 + end do end do end do - end do - !InitOut%RotFrame_u(index_last:index-1) = .true. ! values on the mesh (and from IfW) are in global coordinates, thus not in the rotating frame + !InitOut%RotFrame_u(index_last:index-1) = .true. ! values on the mesh (and from IfW) are in global coordinates, thus not in the rotating frame - do i=1,p%NumTwrNds - do j=1,3 - InitOut%LinNames_u(index) = UVW(j)//'-component inflow on tower node '//trim(num2lstr(i))//', m/s' - index = index + 1 + do i=1,p%NumTwrNds + do j=1,3 + InitOut%LinNames_u(index) = UVW(j)//'-component inflow on tower node '//trim(num2lstr(i))//', m/s' + index = index + 1 + end do end do - end do - - do k=1,p%NumBlades - do i=1,p%NumBlNds - InitOut%LinNames_u(index) = 'User property on blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', -' - index = index + 1 + + ! UserProp + do k=1,p%NumBl_Lin + do i=1,p%NumBlNds + InitOut%LinNames_u(index) = 'User property on blade '//trim(num2lstr(k))//', node '//trim(num2lstr(i))//', -' + index = index + 1 + end do end do - end do - - END SUBROUTINE Init_Jacobian_u + + ! AvgDiskVel + !do j=1,3 + ! InitOut%LinNames_u(index) = UVW(j)//'-component inflow of average disk velocity, m/s' + ! index = index + 1 + !end do + + end if + +END SUBROUTINE Init_Jacobian_u !---------------------------------------------------------------------------------------------------------------------------------- SUBROUTINE Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) @@ -6855,7 +6993,7 @@ SUBROUTINE Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) CHARACTER(*), PARAMETER :: RoutineName = 'Init_Jacobian_x' ! local variables: - INTEGER(IntKi) :: i, j, k + INTEGER(IntKi) :: i, j, k, n, state INTEGER(IntKi) :: nx INTEGER(IntKi) :: nx1 CHARACTER(25) :: NodeTxt @@ -6864,7 +7002,7 @@ SUBROUTINE Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) ErrMsg = "" - nx = p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + nx = p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + p%BEMT%lin_nx ! allocate space for the row/column names and for perturbation sizes ! always allocate this in case it is size zero ... (we use size(p%dx) for many calculations) @@ -6904,34 +7042,46 @@ SUBROUTINE Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) InitOut%RotFrame_x(i+nx1) = InitOut%RotFrame_x(i) end do end if - + ! UA states if (p%BEMT%UA%lin_nx>0) then InitOut%DerivOrder_x(1+p%BEMT%DBEMT%lin_nx:nx) = 1 InitOut%RotFrame_x( 1+p%BEMT%DBEMT%lin_nx:nx) = .true. k = 1 + p%BEMT%DBEMT%lin_nx - do j=1,p%NumBlades ! size(x%BEMT%DBEMT%element,2) - do i=1,p%NumBlNds ! size(x%BEMT%DBEMT%element,1) - NodeTxt = 'blade '//trim(num2lstr(j))//', node '//trim(num2lstr(i)) - if (p%BEMT%UA%UAMod/=UA_OYE) then - - InitOut%LinNames_x(k) = 'x1 '//trim(NodeTxt)//', rad' - k = k + 1 + do n=1,p%BEMT%UA%lin_nx + i = p%BEMT%UA%lin_xIndx(n,1) + j = p%BEMT%UA%lin_xIndx(n,2) + state = p%BEMT%UA%lin_xIndx(n,3) - InitOut%LinNames_x(k) = 'x2 '//trim(NodeTxt)//', rad' - k = k + 1 - - InitOut%LinNames_x(k) = 'x3 '//trim(NodeTxt)//', -' - k = k + 1 - endif - - InitOut%LinNames_x(k) = 'x4 '//trim(NodeTxt)//', -' - p%dx(k) = 0.001 ! x4 is a number between 0 and 1, so we need this to be small - k = k + 1 - end do + p%dx(k) = p%BEMT%UA%dx(state) + + NodeTxt = 'x'//trim(num2lstr(state))//' blade '//trim(num2lstr(j))//', node '//trim(num2lstr(i)) + if (state<3) then + InitOut%LinNames_x(k) = trim(NodeTxt)//', rad' ! x1 and x2 are radians + else + InitOut%LinNames_x(k) = trim(NodeTxt)//', -' ! x3, x4 (and x5) are units of cl or cn + end if + InitOut%DerivOrder_x(k) = 1 + InitOut%RotFrame_x(k) = .true. + + k = k + 1 end do end if + ! BEMT states + if (p%BEMT%lin_nx>0) then + call SetErrStat(ErrID_Fatal,'Number of lin states for bem should be zero for now.', ErrStat, ErrMsg, RoutineName) + return + !k = 1 + p%BEMT%DBEMT%lin_nx + p%BEMT%UA%lin_nx + + !InitOut%DerivOrder_x(k:nx) = 1 + !InitOut%RotFrame_x( k:nx) = .false. + ! + !InitOut%LinNames_x(k ) = 'X-component of wake velocity, m/s' + !InitOut%LinNames_x(k+1) = 'Y-component of wake velocity, m/s' + !InitOut%LinNames_x(k+2) = 'Z-component of wake velocity, m/s' + end if + END SUBROUTINE Init_Jacobian_x !---------------------------------------------------------------------------------------------------------------------------------- @@ -6958,8 +7108,13 @@ SUBROUTINE Init_Jacobian( InputFileData, p, p_AD, u, y, m, InitOut, ErrStat, Err ErrStat = ErrID_None ErrMsg = "" -!FIXME: add logic to check that p%NumBlades is not greater than MaxBl. Cannot linearize if that is true. - call Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) + if (p_AD%CompAeroMaps) then + p%NumBl_Lin = 1 + else + p%NumBl_Lin = p%NumBlades + end if + + call Init_Jacobian_y( p, p_AD, y, InitOut, ErrStat, ErrMsg) ! these matrices will be needed for linearization with frozen wake feature if (p%FrozenWake) then @@ -6967,7 +7122,7 @@ SUBROUTINE Init_Jacobian( InputFileData, p, p_AD, u, y, m, InitOut, ErrStat, Err call AllocAry(m%BEMT%TnInd_op,p%NumBlNds,p%numBlades,'m%BEMT%TnInd_op', ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end if - call Init_Jacobian_u( InputFileData, p, u, InitOut, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call Init_Jacobian_u( InputFileData, p, p_AD, u, InitOut, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call Init_Jacobian_x( p, InitOut, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -7061,12 +7216,17 @@ SUBROUTINE Perturb_u( p, n, perturb_sign, u, du ) CASE (28) !Module/Mesh/Field: u%InflowOnTower(:,:) = 28; u%InflowOnTower(fieldIndx,node) = u%InflowOnTower(fieldIndx,node) + du * perturb_sign + CASE (29) !Module/Mesh/Field: u%UserProp(:,1) = 29; u%UserProp(node,1) = u%UserProp(node,1) + du * perturb_sign CASE (30) !Module/Mesh/Field: u%UserProp(:,2) = 30; u%UserProp(node,2) = u%UserProp(node,2) + du * perturb_sign CASE (31) !Module/Mesh/Field: u%UserProp(:,3) = 31; u%UserProp(node,3) = u%UserProp(node,3) + du * perturb_sign + + !CASE (32) !Module/Mesh/Field: u%AvgDiskVel(:) = 32; + ! u%AvgDiskVel(fieldIndx) = u%AvgDiskVel(fieldIndx) + du * perturb_sign + END SELECT END SUBROUTINE Perturb_u @@ -7085,7 +7245,8 @@ SUBROUTINE Perturb_x( p, n, perturb_sign, x, dx ) ! local variables INTEGER(IntKi) :: Blade ! loop over blade nodes INTEGER(IntKi) :: BladeNode ! loop over blades - INTEGER(IntKi) :: StateIndex ! loop over blades + INTEGER(IntKi) :: StateIndex ! which state we are perturbing + INTEGER(IntKi) :: n_tmp ! dx = p%dx( n ) @@ -7101,16 +7262,19 @@ SUBROUTINE Perturb_x( p, n, perturb_sign, x, dx ) endif else - !call GetStateIndices( n - p%BEMT%DBEMT%lin_nx, size(x%BEMT%UA%element,2), size(x%BEMT%UA%element,1), size(x%BEMT%UA%element(1,1)%x), Blade, BladeNode, StateIndex ) - if (p%BEMT%UA%UAMod==UA_OYE) then - call GetStateIndices( n - p%BEMT%DBEMT%lin_nx, size(x%BEMT%UA%element,2), size(x%BEMT%UA%element,1), 1, Blade, BladeNode, StateIndex ) - StateIndex=4 ! Always the 4th one + n_tmp = n - p%BEMT%DBEMT%lin_nx + + if (n_tmp <= p%BEMT%UA%lin_nx) then + BladeNode = p%BEMT%UA%lin_xIndx(n_tmp,1) ! node + Blade = p%BEMT%UA%lin_xIndx(n_tmp,2) ! blade + StateIndex = p%BEMT%UA%lin_xIndx(n_tmp,3) ! state + + x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) = x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) + dx * perturb_sign else - call GetStateIndices( n - p%BEMT%DBEMT%lin_nx, size(x%BEMT%UA%element,2), size(x%BEMT%UA%element,1), 4, Blade, BladeNode, StateIndex ) - endif - x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) = x%BEMT%UA%element(BladeNode,Blade)%x(StateIndex) + dx * perturb_sign - + StateIndex = n_tmp - p%BEMT%UA%lin_nx + x%BEMT%V_w(StateIndex) = x%BEMT%V_w(StateIndex) + dx * perturb_sign + end if end if contains @@ -7157,17 +7321,17 @@ SUBROUTINE Compute_dY(p, p_AD, y_p, y_m, delta_p, delta_m, dY) indx_first = 1 - call PackLoadMesh_dY(y_p%TowerLoad, y_m%TowerLoad, dY, indx_first) + if (.not. p_AD%CompAeroMaps) call PackLoadMesh_dY(y_p%TowerLoad, y_m%TowerLoad, dY, indx_first) - do k=1,p%NumBlades + do k=1,p%NumBl_Lin call PackLoadMesh_dY(y_p%BladeLoad(k), y_m%BladeLoad(k), dY, indx_first) end do - - do k=1,p%NumOuts + p%BldNd_TotNumOuts - dY(k+indx_first-1) = y_p%WriteOutput(k) - y_m%WriteOutput(k) - end do - + if (.not. p_AD%CompAeroMaps) then + do k=1,p%NumOuts + p%BldNd_TotNumOuts + dY(k+indx_first-1) = y_p%WriteOutput(k) - y_m%WriteOutput(k) + end do + end if dY = dY / (delta_p + delta_m) @@ -7187,6 +7351,8 @@ SUBROUTINE Compute_dX(p, x_p, x_m, delta_p, delta_m, dX) ! local variables: INTEGER(IntKi) :: i ! loop over blade nodes INTEGER(IntKi) :: j ! loop over blades + INTEGER(IntKi) :: k ! loop over states + INTEGER(IntKi) :: n ! loop over active UA states INTEGER(IntKi) :: indx_first ! index indicating next value of dY to be filled @@ -7211,25 +7377,23 @@ SUBROUTINE Compute_dX(p, x_p, x_m, delta_p, delta_m, dX) end if if (p%BEMT%UA%lin_nx>0) then - - if (p%BEMT%UA%UAMod==UA_OYE) then - do j=1,size(x_p%BEMT%UA%element,2) ! number of blades - do i=1,size(x_p%BEMT%UA%element,1) ! number of nodes per blade - dX(indx_first) = x_p%BEMT%UA%element(i,j)%x(4) - x_m%BEMT%UA%element(i,j)%x(4) - indx_first = indx_first + 1 ! = index_first += 4 - end do - end do - else - do j=1,size(x_p%BEMT%UA%element,2) ! number of blades - do i=1,size(x_p%BEMT%UA%element,1) ! number of nodes per blade - dX(indx_first:indx_first+3) = x_p%BEMT%UA%element(i,j)%x(1:4) - x_m%BEMT%UA%element(i,j)%x(1:4) - indx_first = indx_first + 4 ! = index_first += 4 - end do - end do - endif + do n=1,p%BEMT%UA%lin_nx + i = p%BEMT%UA%lin_xIndx(n,1) + j = p%BEMT%UA%lin_xIndx(n,2) + k = p%BEMT%UA%lin_xIndx(n,3) + dX(indx_first) = x_p%BEMT%UA%element(i,j)%x(k) - x_m%BEMT%UA%element(i,j)%x(k) + indx_first = indx_first + 1 + end do + end if + if (p%BEMT%lin_nx>0) then ! skewWake + !do j=1,size(x_p%BEMT%v_w) + ! dX(indx_first) = x_p%BEMT%v_w(j) - x_m%BEMT%v_w(j) + ! indx_first = indx_first + 1 + !end do + end if dX = dX / (delta_p + delta_m) END SUBROUTINE Compute_dX diff --git a/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 b/modules/aerodyn/src/AeroDyn_AllBldNdOuts_IO.f90 index b4662527a9..b17cf094f6 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%Bld(IdxBlade)%InflowOnBlade(:,IdxNode) ) - 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%Bld(IdxBlade)%InflowOnBlade(:,IdxNode) ) - 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%Bld(IdxBlade)%InflowOnBlade(:,IdxNode) ) - 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%Bld(IdxBlade)%InflowOnBlade(1,IdxNode) - 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%Bld(IdxBlade)%InflowOnBlade(2,IdxNode) - 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%Bld(IdxBlade)%InflowOnBlade(3,IdxNode) - 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%Bld(iB)%InflowOnBlade(1,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndyi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%Bld(iB)%InflowOnBlade(2,iNd); iOut = iOut + 1; enddo;enddo + CASE( BldNd_VUndzi ); do iB=1,nB; do iNd=1,nNd; y%WriteOutput(iOut) = u%Bld(iB)%InflowOnBlade(3,iNd); 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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%Bld(iB)%InflowOnBlade(:,iNd), 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 ae77356f95..40d4b71039 100644 --- a/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 +++ b/modules/aerodyn/src/AeroDyn_Driver_Subs.f90 @@ -388,7 +388,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) @@ -1021,7 +1023,7 @@ subroutine Dvr_ReadInputFile(fileName, dvr, errStat, errMsg ) if (wt%BasicHAWTFormat) then ! --- Basic Geometry call ParseAry(FileInfo_In, CurLine, 'baseOriginInit'//sWT , wt%originInit , 3 , errStat2, errMsg2 , unEc); if(Failed()) return - if ( dvr%MHK == 1 ) then + if ( dvr%MHK == MHK_FixedBottom ) then wt%originInit(3) = wt%originInit(3) - dvr%WtrDpth end if call ParseVar(FileInfo_In, CurLine, 'numBlades'//sWT , wt%numBlades , errStat2, errMsg2 , unEc); if(Failed()) return @@ -1059,7 +1061,7 @@ subroutine Dvr_ReadInputFile(fileName, dvr, errStat, errMsg ) ! --- Advanced geometry ! Rotor origin and orientation call ParseAry(FileInfo_In, CurLine, 'baseOriginInit'//sWT , wt%originInit, 3 , errStat2, errMsg2, unEc); if(Failed()) return - if ( dvr%MHK == 1 ) then + if ( dvr%MHK == MHK_FixedBottom ) then wt%originInit(3) = wt%originInit(3) - dvr%WtrDpth end if call ParseAry(FileInfo_In, CurLine, 'baseOrientationInit'//sWT, wt%orientationInit, 3 , errStat2, errMsg2, unEc); if(Failed()) return @@ -1345,7 +1347,7 @@ subroutine ValidateInputs(dvr, errStat, errMsg) ! Turbine Data: !if ( dvr%numBlades < 1 ) call SetErrStat( ErrID_Fatal, "There must be at least 1 blade (numBlades).", errStat, ErrMsg, RoutineName) ! Combined-Case Analysis: - if (dvr%MHK /= 0 .and. dvr%MHK /= 1 .and. dvr%MHK /= 2) call SetErrStat(ErrID_Fatal, 'MHK switch must be 0, 1, or 2.', ErrStat, ErrMsg, RoutineName) + if (dvr%MHK /= MHK_None .and. dvr%MHK /= MHK_FixedBottom .and. dvr%MHK /= MHK_Floating) call SetErrStat(ErrID_Fatal, 'MHK switch must be 0, 1, or 2.', ErrStat, ErrMsg, RoutineName) if (dvr%DT < epsilon(0.0_ReKi) ) call SetErrStat(ErrID_Fatal,'dT must be larger than 0.',errStat, errMsg,RoutineName) if (Check(.not.(ANY((/0,1/) == dvr%IW_InitInp%compInflow) ), 'CompInflow needs to be 0 or 1')) return diff --git a/modules/aerodyn/src/AeroDyn_IO.f90 b/modules/aerodyn/src/AeroDyn_IO.f90 index 0f9440844b..f92d717b8c 100644 --- a/modules/aerodyn/src/AeroDyn_IO.f90 +++ b/modules/aerodyn/src/AeroDyn_IO.f90 @@ -288,28 +288,28 @@ subroutine Calc_WriteOutput_AD() force = force + m%HubLoad%force( :,1) moment = moment + m%HubLoad%moment(:,1) - if (k<=size(BAeroFxg)) then + if (k<=size(BAeroFxi)) then ! Power contribution of blade wrt hub tmp = matmul( u%HubMotion%Orientation(:,:,1), m%HubLoad%moment(:,1) ) m%AllOuts( BAeroPwr(k) ) = omega * tmp(1) ! In global, wrt hub! - m%AllOuts( BAeroFxg(k) ) = m%HubLoad%force(1,1) - m%AllOuts( BAeroFyg(k) ) = m%HubLoad%force(2,1) - m%AllOuts( BAeroFzg(k) ) = m%HubLoad%force(3,1) - m%AllOuts( BAeroMxg(k) ) = m%HubLoad%moment(1,1) - m%AllOuts( BAeroMyg(k) ) = m%HubLoad%moment(2,1) - m%AllOuts( BAeroMzg(k) ) = m%HubLoad%moment(3,1) + m%AllOuts( BAeroFxi(k) ) = m%HubLoad%force(1,1) + m%AllOuts( BAeroFyi(k) ) = m%HubLoad%force(2,1) + m%AllOuts( BAeroFzi(k) ) = m%HubLoad%force(3,1) + m%AllOuts( BAeroMxi(k) ) = m%HubLoad%moment(1,1) + m%AllOuts( BAeroMyi(k) ) = m%HubLoad%moment(2,1) + m%AllOuts( BAeroMzi(k) ) = m%HubLoad%moment(3,1) end if end do ! In global - m%AllOuts( RtAeroFxg ) = force(1) - m%AllOuts( RtAeroFyg ) = force(2) - m%AllOuts( RtAeroFzg ) = force(3) - m%AllOuts( RtAeroMxg ) = moment(1) - m%AllOuts( RtAeroMyg ) = moment(2) - m%AllOuts( RtAeroMzg ) = moment(3) + m%AllOuts( RtAeroFxi ) = force(1) + m%AllOuts( RtAeroFyi ) = force(2) + m%AllOuts( RtAeroFzi ) = force(3) + m%AllOuts( RtAeroMxi ) = moment(1) + m%AllOuts( RtAeroMyi ) = moment(2) + m%AllOuts( RtAeroMzi ) = moment(3) tmp = matmul( u%HubMotion%Orientation(:,:,1), force ) m%AllOuts( RtAeroFxh ) = tmp(1) m%AllOuts( RtAeroFyh ) = tmp(2) @@ -378,17 +378,28 @@ end subroutine Calc_WriteOutput_AD subroutine Calc_WriteOutput_BEMT() REAL(R8Ki) :: orient(3,3) REAL(R8Ki) :: theta(3) + REAL(ReKi) :: Vind_s(3) ! Induced velocity in "w" or "p" system REAL(ReKi) :: denom !, rmax REAL(ReKi) :: ct, st ! cosine, sine of theta REAL(ReKi) :: cp, sp ! cosine, sine of phi + ! Induced velocity in Global + do k=1,min(p%numBlades,3) + do j=1,u%BladeMotion(k)%NNodes + !if(p%BEM_Mod==BEMMod_2D) then + ! NOTE: if BEMMod_2D: x & y are in "w" system (WithoutSweepPitchTwist) + ! if BEMMod_3D: x & y are in "l" system (local-polar system) + Vind_s = (/ -m%BEMT_u(indx)%Vx(j,k)*m%BEMT_y%axInduction(j,k), m%BEMT_u(indx)%Vy(j,k)*m%BEMT_y%tanInduction(j,k), 0.0_ReKi /) + m%Vind_i(:,j,k) = matmul(Vind_s, m%orientationAnnulus(:,:,j,k)) ! TODO rename orientationAnnulus + enddo + enddo ! blade outputs do k=1,min(p%numBlades,AD_MaxBl_Out) ! limit this - m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi(k)*R2D, 360.0_ReKi ) + m%AllOuts( BAzimuth(k) ) = MODULO( m%BEMT_u(indx)%psi_s(k)*R2D, 360.0_ReKi ) ! m%AllOuts( BPitch( k) ) = calculated in SetInputsForBEMT do beta=1,p%NBlOuts @@ -462,6 +473,17 @@ end subroutine Calc_WriteOutput_BEMT subroutine Calc_WriteOutput_FVW integer :: iW + ! Induced velocity in global + ! FVW already return this, we do a simple copy from Wings to Blades + do k=1,min(p%numBlades,3) + iW = p_AD%FVW%Bld2Wings(iRot, k) + do j=1,u%BladeMotion(k)%NNodes + m%Vind_i(:,j,k) = m_AD%FVW_y%W(iW)%Vind(1:3,j) + enddo + enddo + + ! TODO TODO TODO ALL THIS SHOULD BE COMPUTED IN THE SAME MEMORY FORMAT AS AERODYN + ! blade outputs do k=1,min(p%numBlades,3) iW=p_AD%FVW%Bld2Wings(iRot, k) @@ -993,6 +1015,10 @@ SUBROUTINE ParsePrimaryFileInfo( PriPath, InitInp, InputFile, RootName, NumBlade call ReadOutputListFromFileInfo( FileInfo_In, CurLine, InputFileData%BldNd_OutList, InputFileData%BldNd_NumOuts, ErrStat2, ErrMsg2, UnEc ) if (FailedNodal()) return; +!FIXME: improve logic on the node outputs + ! Prevent segfault when no blades specified. All logic tests on BldNd_NumOuts at present. + if (InputFileData%BldNd_BladesOut <= 0) InputFileData%BldNd_NumOuts = 0 + RETURN CONTAINS !------------------------------------------------------------------------------------------------- @@ -2130,34 +2156,26 @@ subroutine calcCantAngle(f, xi,stencilSize,n,cantAngle) if (i.eq.1) then fIn = f(1:stencilSize) xiIn = xi(1:stencilSize) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case elseif (i.eq.size(xi)) then fIn = f(size(xi)-stencilSize +1:size(xi)) xiIn = xi(size(xi)-stencilSize+1:size(xi)) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case else fIn = f(i-1:i+1) xiIn = xi(i-1:i+1) - call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) - if (info /= 0) return ! use default cantAngle in this case - call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) - if (info /= 0) return ! use default cantAngle in this case endif - - cPrime(i) = 0.0 - fPrime(i) = 0.0 - - do j = 1,size(cx) - cPrime(i) = cPrime(i) + cx(j)*xiIn(j) - fPrime(i) = fPrime(i) + cx(j)*fIn(j) - end do - cantAngle(i) = atan2(fPrime(i),cPrime(i))*180_ReKi/pi + call differ_stencil ( xi(i), 1, 2, xiIn, cx, info ) + !call differ_stencil ( xi(i), 1, 2, fIn, cf, info ) + if (info /= 0) then + print*,'Cant Calc failed at i=',i + else + cPrime(i) = 0.0 + fPrime(i) = 0.0 + do j = 1,size(cx) + cPrime(i) = cPrime(i) + cx(j)*xiIn(j) + fPrime(i) = fPrime(i) + cx(j)*fIn(j) + end do + cantAngle(i) = atan2(fPrime(i),cPrime(i))*180_ReKi/pi + endif end do end subroutine calcCantAngle diff --git a/modules/aerodyn/src/AeroDyn_IO_Params.f90 b/modules/aerodyn/src/AeroDyn_IO_Params.f90 index 34ea815754..3568cd8b32 100644 --- a/modules/aerodyn/src/AeroDyn_IO_Params.f90 +++ b/modules/aerodyn/src/AeroDyn_IO_Params.f90 @@ -228,30 +228,30 @@ module AeroDyn_IO_Params INTEGER(IntKi), PARAMETER :: B4AeroMy = 194 INTEGER(IntKi), PARAMETER :: B4AeroMz = 195 INTEGER(IntKi), PARAMETER :: B4AeroPwr = 196 - INTEGER(IntKi), PARAMETER :: B1AeroFxg = 197 - INTEGER(IntKi), PARAMETER :: B1AeroFyg = 198 - INTEGER(IntKi), PARAMETER :: B1AeroFzg = 199 - INTEGER(IntKi), PARAMETER :: B1AeroMxg = 200 - INTEGER(IntKi), PARAMETER :: B1AeroMyg = 201 - INTEGER(IntKi), PARAMETER :: B1AeroMzg = 202 - INTEGER(IntKi), PARAMETER :: B2AeroFxg = 203 - INTEGER(IntKi), PARAMETER :: B2AeroFyg = 204 - INTEGER(IntKi), PARAMETER :: B2AeroFzg = 205 - INTEGER(IntKi), PARAMETER :: B2AeroMxg = 206 - INTEGER(IntKi), PARAMETER :: B2AeroMyg = 207 - INTEGER(IntKi), PARAMETER :: B2AeroMzg = 208 - INTEGER(IntKi), PARAMETER :: B3AeroFxg = 209 - INTEGER(IntKi), PARAMETER :: B3AeroFyg = 210 - INTEGER(IntKi), PARAMETER :: B3AeroFzg = 211 - INTEGER(IntKi), PARAMETER :: B3AeroMxg = 212 - INTEGER(IntKi), PARAMETER :: B3AeroMyg = 213 - INTEGER(IntKi), PARAMETER :: B3AeroMzg = 214 - INTEGER(IntKi), PARAMETER :: B4AeroFxg = 215 - INTEGER(IntKi), PARAMETER :: B4AeroFyg = 216 - INTEGER(IntKi), PARAMETER :: B4AeroFzg = 217 - INTEGER(IntKi), PARAMETER :: B4AeroMxg = 218 - INTEGER(IntKi), PARAMETER :: B4AeroMyg = 219 - INTEGER(IntKi), PARAMETER :: B4AeroMzg = 220 + INTEGER(IntKi), PARAMETER :: B1AeroFxi = 197 + INTEGER(IntKi), PARAMETER :: B1AeroFyi = 198 + INTEGER(IntKi), PARAMETER :: B1AeroFzi = 199 + INTEGER(IntKi), PARAMETER :: B1AeroMxi = 200 + INTEGER(IntKi), PARAMETER :: B1AeroMyi = 201 + INTEGER(IntKi), PARAMETER :: B1AeroMzi = 202 + INTEGER(IntKi), PARAMETER :: B2AeroFxi = 203 + INTEGER(IntKi), PARAMETER :: B2AeroFyi = 204 + INTEGER(IntKi), PARAMETER :: B2AeroFzi = 205 + INTEGER(IntKi), PARAMETER :: B2AeroMxi = 206 + INTEGER(IntKi), PARAMETER :: B2AeroMyi = 207 + INTEGER(IntKi), PARAMETER :: B2AeroMzi = 208 + INTEGER(IntKi), PARAMETER :: B3AeroFxi = 209 + INTEGER(IntKi), PARAMETER :: B3AeroFyi = 210 + INTEGER(IntKi), PARAMETER :: B3AeroFzi = 211 + INTEGER(IntKi), PARAMETER :: B3AeroMxi = 212 + INTEGER(IntKi), PARAMETER :: B3AeroMyi = 213 + INTEGER(IntKi), PARAMETER :: B3AeroMzi = 214 + INTEGER(IntKi), PARAMETER :: B4AeroFxi = 215 + INTEGER(IntKi), PARAMETER :: B4AeroFyi = 216 + INTEGER(IntKi), PARAMETER :: B4AeroFzi = 217 + INTEGER(IntKi), PARAMETER :: B4AeroMxi = 218 + INTEGER(IntKi), PARAMETER :: B4AeroMyi = 219 + INTEGER(IntKi), PARAMETER :: B4AeroMzi = 220 ! Blade Nodal outputs: @@ -1520,12 +1520,12 @@ module AeroDyn_IO_Params INTEGER(IntKi), PARAMETER :: RtAeroCq = 1478 INTEGER(IntKi), PARAMETER :: RtAeroCt = 1479 INTEGER(IntKi), PARAMETER :: DBEMTau1 = 1480 - INTEGER(IntKi), PARAMETER :: RtAeroFxg = 1481 - INTEGER(IntKi), PARAMETER :: RtAeroFyg = 1482 - INTEGER(IntKi), PARAMETER :: RtAeroFzg = 1483 - INTEGER(IntKi), PARAMETER :: RtAeroMxg = 1484 - INTEGER(IntKi), PARAMETER :: RtAeroMyg = 1485 - INTEGER(IntKi), PARAMETER :: RtAeroMzg = 1486 + INTEGER(IntKi), PARAMETER :: RtAeroFxi = 1481 + INTEGER(IntKi), PARAMETER :: RtAeroFyi = 1482 + INTEGER(IntKi), PARAMETER :: RtAeroFzi = 1483 + INTEGER(IntKi), PARAMETER :: RtAeroMxi = 1484 + INTEGER(IntKi), PARAMETER :: RtAeroMyi = 1485 + INTEGER(IntKi), PARAMETER :: RtAeroMzi = 1486 ! Hub: @@ -1626,12 +1626,12 @@ module AeroDyn_IO_Params INTEGER, PARAMETER :: BAeroMy(4) = (/B1AeroMy, B2AeroMy, B3AeroMy, B4AeroMy/) ! total blade aero/hydro load (moment in y-direction) INTEGER, PARAMETER :: BAeroMz(4) = (/B1AeroMz, B2AeroMz, B3AeroMz, B4AeroMz/) ! total blade aero/hydro load (moment in z-direction) INTEGER, PARAMETER :: BAeroPwr(4) = (/B1AeroPwr, B2AeroPwr, B3AeroPwr, B4AeroPwr/) ! total blade aero/hydro power - INTEGER, PARAMETER :: BAeroFxg(4) = (/B1AeroFxg, B2AeroFxg, B3AeroFxg, B4AeroFxg/) ! total blade aero/hydro load (force in x-direction) in global - INTEGER, PARAMETER :: BAeroFyg(4) = (/B1AeroFyg, B2AeroFyg, B3AeroFyg, B4AeroFyg/) ! total blade aero/hydro load (force in y-direction) in global - INTEGER, PARAMETER :: BAeroFzg(4) = (/B1AeroFzg, B2AeroFzg, B3AeroFzg, B4AeroFzg/) ! total blade aero/hydro load (force in z-direction) in global - INTEGER, PARAMETER :: BAeroMxg(4) = (/B1AeroMxg, B2AeroMxg, B3AeroMxg, B4AeroMxg/) ! total blade aero/hydro load (moment in x-direction) in global - INTEGER, PARAMETER :: BAeroMyg(4) = (/B1AeroMyg, B2AeroMyg, B3AeroMyg, B4AeroMyg/) ! total blade aero/hydro load (moment in y-direction) in global - INTEGER, PARAMETER :: BAeroMzg(4) = (/B1AeroMzg, B2AeroMzg, B3AeroMzg, B4AeroMzg/) ! total blade aero/hydro load (moment in z-direction) in global + INTEGER, PARAMETER :: BAeroFxi(4) = (/B1AeroFxi, B2AeroFxi, B3AeroFxi, B4AeroFxi/) ! total blade aero/hydro load (force in x-direction) in global + INTEGER, PARAMETER :: BAeroFyi(4) = (/B1AeroFyi, B2AeroFyi, B3AeroFyi, B4AeroFyi/) ! total blade aero/hydro load (force in y-direction) in global + INTEGER, PARAMETER :: BAeroFzi(4) = (/B1AeroFzi, B2AeroFzi, B3AeroFzi, B4AeroFzi/) ! total blade aero/hydro load (force in z-direction) in global + INTEGER, PARAMETER :: BAeroMxi(4) = (/B1AeroMxi, B2AeroMxi, B3AeroMxi, B4AeroMxi/) ! total blade aero/hydro load (moment in x-direction) in global + INTEGER, PARAMETER :: BAeroMyi(4) = (/B1AeroMyi, B2AeroMyi, B3AeroMyi, B4AeroMyi/) ! total blade aero/hydro load (moment in y-direction) in global + INTEGER, PARAMETER :: BAeroMzi(4) = (/B1AeroMzi, B2AeroMzi, B3AeroMzi, B4AeroMzi/) ! total blade aero/hydro load (moment in z-direction) in global INTEGER, PARAMETER :: BNVUndx(9, 3) = RESHAPE( (/ & ! undisturbed wind velocity (x component) B1N1VUndx,B1N2VUndx,B1N3VUndx,B1N4VUndx,B1N5VUndx,B1N6VUndx,B1N7VUndx,B1N8VUndx,B1N9VUndx, & @@ -1874,11 +1874,11 @@ module AeroDyn_IO_Params - CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1588) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically - "B1AEROFX ","B1AEROFXG","B1AEROFY ","B1AEROFYG","B1AEROFZ ","B1AEROFZG","B1AEROMX ","B1AEROMXG", & - "B1AEROMY ","B1AEROMYG","B1AEROMZ ","B1AEROMZG","B1AEROPWR","B1AZIMUTH","B1FLDFX ","B1FLDFXG ", & - "B1FLDFY ","B1FLDFYG ","B1FLDFZ ","B1FLDFZG ","B1FLDMX ","B1FLDMXG ","B1FLDMY ","B1FLDMYG ", & - "B1FLDMZ ","B1FLDMZG ","B1FLDPWR ","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC", & + CHARACTER(OutStrLenM1), PARAMETER :: ValidParamAry(1594) = (/ & ! This lists the names of the allowed parameters, which must be sorted alphabetically + "B1AEROFX ","B1AEROFXI","B1AEROFY ","B1AEROFYI","B1AEROFZ ","B1AEROFZI","B1AEROMX ","B1AEROMXI", & + "B1AEROMY ","B1AEROMYI","B1AEROMZ ","B1AEROMZI","B1AEROPWR","B1AZIMUTH","B1FLDFX ","B1FLDFXI ", & + "B1FLDFY ","B1FLDFYI ","B1FLDFZ ","B1FLDFZI ","B1FLDMX ","B1FLDMXI ","B1FLDMY ","B1FLDMYI ", & + "B1FLDMZ ","B1FLDMZI ","B1FLDPWR ","B1N1ALPHA","B1N1AXIND","B1N1CD ","B1N1CL ","B1N1CLRNC", & "B1N1CM ","B1N1CN ","B1N1CPMIN","B1N1CT ","B1N1CURVE","B1N1CX ","B1N1CY ","B1N1DYNP ", & "B1N1FBN ","B1N1FBS ","B1N1FBT ","B1N1FD ","B1N1FL ","B1N1FN ","B1N1FT ","B1N1FX ", & "B1N1FY ","B1N1GAM ","B1N1M ","B1N1MBN ","B1N1MBS ","B1N1MBT ","B1N1MM ","B1N1PHI ", & @@ -1930,10 +1930,10 @@ module AeroDyn_IO_Params "B1N9FY ","B1N9GAM ","B1N9M ","B1N9MBN ","B1N9MBS ","B1N9MBT ","B1N9MM ","B1N9PHI ", & "B1N9RE ","B1N9SGCAV","B1N9SIGCR","B1N9STVX ","B1N9STVY ","B1N9STVZ ","B1N9THETA","B1N9TNIND", & "B1N9VDISX","B1N9VDISY","B1N9VDISZ","B1N9VINDX","B1N9VINDY","B1N9VREL ","B1N9VUNDX","B1N9VUNDY", & - "B1N9VUNDZ","B1PITCH ","B2AEROFX ","B2AEROFXG","B2AEROFY ","B2AEROFYG","B2AEROFZ ","B2AEROFZG", & - "B2AEROMX ","B2AEROMXG","B2AEROMY ","B2AEROMYG","B2AEROMZ ","B2AEROMZG","B2AEROPWR","B2AZIMUTH", & - "B2FLDFX ","B2FLDFXG ","B2FLDFY ","B2FLDFYG ","B2FLDFZ ","B2FLDFZG ","B2FLDMX ","B2FLDMXG ", & - "B2FLDMY ","B2FLDMYG ","B2FLDMZ ","B2FLDMZG ","B2FLDPWR ","B2N1ALPHA","B2N1AXIND","B2N1CD ", & + "B1N9VUNDZ","B1PITCH ","B2AEROFX ","B2AEROFXI","B2AEROFY ","B2AEROFYI","B2AEROFZ ","B2AEROFZI", & + "B2AEROMX ","B2AEROMXI","B2AEROMY ","B2AEROMYI","B2AEROMZ ","B2AEROMZI","B2AEROPWR","B2AZIMUTH", & + "B2FLDFX ","B2FLDFXI ","B2FLDFY ","B2FLDFYI ","B2FLDFZ ","B2FLDFZI ","B2FLDMX ","B2FLDMXI ", & + "B2FLDMY ","B2FLDMYI ","B2FLDMZ ","B2FLDMZI ","B2FLDPWR ","B2N1ALPHA","B2N1AXIND","B2N1CD ", & "B2N1CL ","B2N1CLRNC","B2N1CM ","B2N1CN ","B2N1CPMIN","B2N1CT ","B2N1CURVE","B2N1CX ", & "B2N1CY ","B2N1DYNP ","B2N1FBN ","B2N1FBS ","B2N1FBT ","B2N1FD ","B2N1FL ","B2N1FN ", & "B2N1FT ","B2N1FX ","B2N1FY ","B2N1GAM ","B2N1M ","B2N1MBN ","B2N1MBS ","B2N1MBT ", & @@ -1985,10 +1985,10 @@ module AeroDyn_IO_Params "B2N9FT ","B2N9FX ","B2N9FY ","B2N9GAM ","B2N9M ","B2N9MBN ","B2N9MBS ","B2N9MBT ", & "B2N9MM ","B2N9PHI ","B2N9RE ","B2N9SGCAV","B2N9SIGCR","B2N9STVX ","B2N9STVY ","B2N9STVZ ", & "B2N9THETA","B2N9TNIND","B2N9VDISX","B2N9VDISY","B2N9VDISZ","B2N9VINDX","B2N9VINDY","B2N9VREL ", & - "B2N9VUNDX","B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AEROFX ","B3AEROFXG","B3AEROFY ","B3AEROFYG", & - "B3AEROFZ ","B3AEROFZG","B3AEROMX ","B3AEROMXG","B3AEROMY ","B3AEROMYG","B3AEROMZ ","B3AEROMZG", & - "B3AEROPWR","B3AZIMUTH","B3FLDFX ","B3FLDFXG ","B3FLDFY ","B3FLDFYG ","B3FLDFZ ","B3FLDFZG ", & - "B3FLDMX ","B3FLDMXG ","B3FLDMY ","B3FLDMYG ","B3FLDMZ ","B3FLDMZG ","B3FLDPWR ","B3N1ALPHA", & + "B2N9VUNDX","B2N9VUNDY","B2N9VUNDZ","B2PITCH ","B3AEROFX ","B3AEROFXI","B3AEROFY ","B3AEROFYI", & + "B3AEROFZ ","B3AEROFZI","B3AEROMX ","B3AEROMXI","B3AEROMY ","B3AEROMYI","B3AEROMZ ","B3AEROMZI", & + "B3AEROPWR","B3AZIMUTH","B3FLDFX ","B3FLDFXI ","B3FLDFY ","B3FLDFYI ","B3FLDFZ ","B3FLDFZI ", & + "B3FLDMX ","B3FLDMXI ","B3FLDMY ","B3FLDMYI ","B3FLDMZ ","B3FLDMZI ","B3FLDPWR ","B3N1ALPHA", & "B3N1AXIND","B3N1CD ","B3N1CL ","B3N1CLRNC","B3N1CM ","B3N1CN ","B3N1CPMIN","B3N1CT ", & "B3N1CURVE","B3N1CX ","B3N1CY ","B3N1DYNP ","B3N1FBN ","B3N1FBS ","B3N1FBT ","B3N1FD ", & "B3N1FL ","B3N1FN ","B3N1FT ","B3N1FX ","B3N1FY ","B3N1GAM ","B3N1M ","B3N1MBN ", & @@ -2040,45 +2040,46 @@ module AeroDyn_IO_Params "B3N9FL ","B3N9FN ","B3N9FT ","B3N9FX ","B3N9FY ","B3N9GAM ","B3N9M ","B3N9MBN ", & "B3N9MBS ","B3N9MBT ","B3N9MM ","B3N9PHI ","B3N9RE ","B3N9SGCAV","B3N9SIGCR","B3N9STVX ", & "B3N9STVY ","B3N9STVZ ","B3N9THETA","B3N9TNIND","B3N9VDISX","B3N9VDISY","B3N9VDISZ","B3N9VINDX", & - "B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ","B3PITCH ","B4AEROFX ","B4AEROFXG", & - "B4AEROFY ","B4AEROFYG","B4AEROFZ ","B4AEROFZG","B4AEROMX ","B4AEROMXG","B4AEROMY ","B4AEROMYG", & - "B4AEROMZ ","B4AEROMZG","B4AEROPWR","B4FLDFX ","B4FLDFXG ","B4FLDFY ","B4FLDFYG ","B4FLDFZ ", & - "B4FLDFZG ","B4FLDMX ","B4FLDMXG ","B4FLDMY ","B4FLDMYG ","B4FLDMZ ","B4FLDMZG ","B4FLDPWR ", & + "B3N9VINDY","B3N9VREL ","B3N9VUNDX","B3N9VUNDY","B3N9VUNDZ","B3PITCH ","B4AEROFX ","B4AEROFXI", & + "B4AEROFY ","B4AEROFYI","B4AEROFZ ","B4AEROFZI","B4AEROMX ","B4AEROMXI","B4AEROMY ","B4AEROMYI", & + "B4AEROMZ ","B4AEROMZI","B4AEROPWR","B4FLDFX ","B4FLDFXI ","B4FLDFY ","B4FLDFYI ","B4FLDFZ ", & + "B4FLDFZI ","B4FLDMX ","B4FLDMXI ","B4FLDMY ","B4FLDMYI ","B4FLDMZ ","B4FLDMZI ","B4FLDPWR ", & "DBEMTAU1 ","HBFBX ","HBFBY ","HBFBZ ","HBMBX ","HBMBY ","HBMBZ ","NCFBX ", & "NCFBY ","NCFBZ ","NCMBX ","NCMBY ","NCMBZ ","RTAEROCP ","RTAEROCQ ","RTAEROCT ", & - "RTAEROFXG","RTAEROFXH","RTAEROFYG","RTAEROFYH","RTAEROFZG","RTAEROFZH","RTAEROMXG","RTAEROMXH", & - "RTAEROMYG","RTAEROMYH","RTAEROMZG","RTAEROMZH","RTAEROPWR","RTAREA ","RTFLDCP ","RTFLDCQ ", & - "RTFLDCT ","RTFLDFXG ","RTFLDFXH ","RTFLDFYG ","RTFLDFYH ","RTFLDFZG ","RTFLDFZH ","RTFLDMXG ", & - "RTFLDMXH ","RTFLDMYG ","RTFLDMYH ","RTFLDMZG ","RTFLDMZH ","RTFLDPWR ","RTSKEW ","RTSPEED ", & - "RTTSR ","RTVAVGXH ","RTVAVGYH ","RTVAVGZH ","TFALPHA ","TFFXI ","TFFYI ","TFFZI ", & - "TFMACH ","TFMXI ","TFMYI ","TFMZI ","TFRE ","TFSTVXI ","TFSTVYI ","TFSTVZI ", & - "TFVINDXI ","TFVINDYI ","TFVINDZI ","TFVREL ","TFVRELXI ","TFVRELYI ","TFVRELZI ","TFVUNDXI ", & - "TFVUNDYI ","TFVUNDZI ","TWN1DYNP ","TWN1FBX ","TWN1FBY ","TWN1FBZ ","TWN1FDX ","TWN1FDY ", & - "TWN1M ","TWN1MBX ","TWN1MBY ","TWN1MBZ ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ", & - "TWN1VREL ","TWN1VUNDX","TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FBX ","TWN2FBY ","TWN2FBZ ", & - "TWN2FDX ","TWN2FDY ","TWN2M ","TWN2MBX ","TWN2MBY ","TWN2MBZ ","TWN2RE ","TWN2STVX ", & - "TWN2STVY ","TWN2STVZ ","TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ","TWN3DYNP ","TWN3FBX ", & - "TWN3FBY ","TWN3FBZ ","TWN3FDX ","TWN3FDY ","TWN3M ","TWN3MBX ","TWN3MBY ","TWN3MBZ ", & - "TWN3RE ","TWN3STVX ","TWN3STVY ","TWN3STVZ ","TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ", & - "TWN4DYNP ","TWN4FBX ","TWN4FBY ","TWN4FBZ ","TWN4FDX ","TWN4FDY ","TWN4M ","TWN4MBX ", & - "TWN4MBY ","TWN4MBZ ","TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ","TWN4VUNDX", & - "TWN4VUNDY","TWN4VUNDZ","TWN5DYNP ","TWN5FBX ","TWN5FBY ","TWN5FBZ ","TWN5FDX ","TWN5FDY ", & - "TWN5M ","TWN5MBX ","TWN5MBY ","TWN5MBZ ","TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ", & - "TWN5VREL ","TWN5VUNDX","TWN5VUNDY","TWN5VUNDZ","TWN6DYNP ","TWN6FBX ","TWN6FBY ","TWN6FBZ ", & - "TWN6FDX ","TWN6FDY ","TWN6M ","TWN6MBX ","TWN6MBY ","TWN6MBZ ","TWN6RE ","TWN6STVX ", & - "TWN6STVY ","TWN6STVZ ","TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ","TWN7DYNP ","TWN7FBX ", & - "TWN7FBY ","TWN7FBZ ","TWN7FDX ","TWN7FDY ","TWN7M ","TWN7MBX ","TWN7MBY ","TWN7MBZ ", & - "TWN7RE ","TWN7STVX ","TWN7STVY ","TWN7STVZ ","TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ", & - "TWN8DYNP ","TWN8FBX ","TWN8FBY ","TWN8FBZ ","TWN8FDX ","TWN8FDY ","TWN8M ","TWN8MBX ", & - "TWN8MBY ","TWN8MBZ ","TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX", & - "TWN8VUNDY","TWN8VUNDZ","TWN9DYNP ","TWN9FBX ","TWN9FBY ","TWN9FBZ ","TWN9FDX ","TWN9FDY ", & - "TWN9M ","TWN9MBX ","TWN9MBY ","TWN9MBZ ","TWN9RE ","TWN9STVX ","TWN9STVY ","TWN9STVZ ", & - "TWN9VREL ","TWN9VUNDX","TWN9VUNDY","TWN9VUNDZ"/) - INTEGER(IntKi), PARAMETER :: ParamIndxAry(1588) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) - B1AeroFx , B1AeroFxg , B1AeroFy , B1AeroFyg , B1AeroFz , B1AeroFzg , B1AeroMx , B1AeroMxg , & - B1AeroMy , B1AeroMyg , B1AeroMz , B1AeroMzg , B1AeroPwr , B1Azimuth , B1AeroFx , B1AeroFxg , & - B1AeroFy , B1AeroFyg , B1AeroFz , B1AeroFzg , B1AeroMx , B1AeroMxg , B1AeroMy , B1AeroMyg , & - B1AeroMz , B1AeroMzg , B1AeroPwr , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , & + "RTAEROFXH","RTAEROFXI","RTAEROFYH","RTAEROFYI","RTAEROFZH","RTAEROFZI","RTAEROMXH","RTAEROMXI", & + "RTAEROMYH","RTAEROMYI","RTAEROMZH","RTAEROMZI","RTAEROPWR","RTAREA ","RTFLDCP ","RTFLDCQ ", & + "RTFLDCT ","RTFLDFXG ","RTFLDFXH ","RTFLDFXI ","RTFLDFYG ","RTFLDFYH ","RTFLDFYI ","RTFLDFZG ", & + "RTFLDFZH ","RTFLDFZI ","RTFLDMXG ","RTFLDMXH ","RTFLDMXI ","RTFLDMYG ","RTFLDMYH ","RTFLDMYI ", & + "RTFLDMZG ","RTFLDMZH ","RTFLDMZI ","RTFLDPWR ","RTSKEW ","RTSPEED ","RTTSR ","RTVAVGXH ", & + "RTVAVGYH ","RTVAVGZH ","TFALPHA ","TFFXI ","TFFYI ","TFFZI ","TFMACH ","TFMXI ", & + "TFMYI ","TFMZI ","TFRE ","TFSTVXI ","TFSTVYI ","TFSTVZI ","TFVINDXI ","TFVINDYI ", & + "TFVINDZI ","TFVREL ","TFVRELXI ","TFVRELYI ","TFVRELZI ","TFVUNDXI ","TFVUNDYI ","TFVUNDZI ", & + "TWN1DYNP ","TWN1FBX ","TWN1FBY ","TWN1FBZ ","TWN1FDX ","TWN1FDY ","TWN1M ","TWN1MBX ", & + "TWN1MBY ","TWN1MBZ ","TWN1RE ","TWN1STVX ","TWN1STVY ","TWN1STVZ ","TWN1VREL ","TWN1VUNDX", & + "TWN1VUNDY","TWN1VUNDZ","TWN2DYNP ","TWN2FBX ","TWN2FBY ","TWN2FBZ ","TWN2FDX ","TWN2FDY ", & + "TWN2M ","TWN2MBX ","TWN2MBY ","TWN2MBZ ","TWN2RE ","TWN2STVX ","TWN2STVY ","TWN2STVZ ", & + "TWN2VREL ","TWN2VUNDX","TWN2VUNDY","TWN2VUNDZ","TWN3DYNP ","TWN3FBX ","TWN3FBY ","TWN3FBZ ", & + "TWN3FDX ","TWN3FDY ","TWN3M ","TWN3MBX ","TWN3MBY ","TWN3MBZ ","TWN3RE ","TWN3STVX ", & + "TWN3STVY ","TWN3STVZ ","TWN3VREL ","TWN3VUNDX","TWN3VUNDY","TWN3VUNDZ","TWN4DYNP ","TWN4FBX ", & + "TWN4FBY ","TWN4FBZ ","TWN4FDX ","TWN4FDY ","TWN4M ","TWN4MBX ","TWN4MBY ","TWN4MBZ ", & + "TWN4RE ","TWN4STVX ","TWN4STVY ","TWN4STVZ ","TWN4VREL ","TWN4VUNDX","TWN4VUNDY","TWN4VUNDZ", & + "TWN5DYNP ","TWN5FBX ","TWN5FBY ","TWN5FBZ ","TWN5FDX ","TWN5FDY ","TWN5M ","TWN5MBX ", & + "TWN5MBY ","TWN5MBZ ","TWN5RE ","TWN5STVX ","TWN5STVY ","TWN5STVZ ","TWN5VREL ","TWN5VUNDX", & + "TWN5VUNDY","TWN5VUNDZ","TWN6DYNP ","TWN6FBX ","TWN6FBY ","TWN6FBZ ","TWN6FDX ","TWN6FDY ", & + "TWN6M ","TWN6MBX ","TWN6MBY ","TWN6MBZ ","TWN6RE ","TWN6STVX ","TWN6STVY ","TWN6STVZ ", & + "TWN6VREL ","TWN6VUNDX","TWN6VUNDY","TWN6VUNDZ","TWN7DYNP ","TWN7FBX ","TWN7FBY ","TWN7FBZ ", & + "TWN7FDX ","TWN7FDY ","TWN7M ","TWN7MBX ","TWN7MBY ","TWN7MBZ ","TWN7RE ","TWN7STVX ", & + "TWN7STVY ","TWN7STVZ ","TWN7VREL ","TWN7VUNDX","TWN7VUNDY","TWN7VUNDZ","TWN8DYNP ","TWN8FBX ", & + "TWN8FBY ","TWN8FBZ ","TWN8FDX ","TWN8FDY ","TWN8M ","TWN8MBX ","TWN8MBY ","TWN8MBZ ", & + "TWN8RE ","TWN8STVX ","TWN8STVY ","TWN8STVZ ","TWN8VREL ","TWN8VUNDX","TWN8VUNDY","TWN8VUNDZ", & + "TWN9DYNP ","TWN9FBX ","TWN9FBY ","TWN9FBZ ","TWN9FDX ","TWN9FDY ","TWN9M ","TWN9MBX ", & + "TWN9MBY ","TWN9MBZ ","TWN9RE ","TWN9STVX ","TWN9STVY ","TWN9STVZ ","TWN9VREL ","TWN9VUNDX", & + "TWN9VUNDY","TWN9VUNDZ"/) + INTEGER(IntKi), PARAMETER :: ParamIndxAry(1594) = (/ & ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:) + B1AeroFx , B1AeroFxi , B1AeroFy , B1AeroFyi , B1AeroFz , B1AeroFzi , B1AeroMx , B1AeroMxi , & + B1AeroMy , B1AeroMyi , B1AeroMz , B1AeroMzi , B1AeroPwr , B1Azimuth , B1AeroFx , B1AeroFxi , & + B1AeroFy , B1AeroFyi , B1AeroFz , B1AeroFzi , B1AeroMx , B1AeroMxi , B1AeroMy , B1AeroMyi , & + B1AeroMz , B1AeroMzi , B1AeroPwr , B1N1Alpha , B1N1AxInd , B1N1Cd , B1N1Cl , B1N1Clrnc , & B1N1Cm , B1N1Cn , B1N1Cpmin , B1N1Ct , B1N1Curve , B1N1Cx , B1N1Cy , B1N1DynP , & B1N1Fbn , B1N1Fbs , B1N1Fbt , B1N1Fd , B1N1Fl , B1N1Fn , B1N1Ft , B1N1Fx , & B1N1Fy , B1N1Gam , B1N1M , B1N1Mbn , B1N1Mbs , B1N1Mbt , B1N1Mm , B1N1Phi , & @@ -2130,10 +2131,10 @@ module AeroDyn_IO_Params B1N9Fy , B1N9Gam , B1N9M , B1N9Mbn , B1N9Mbs , B1N9Mbt , B1N9Mm , B1N9Phi , & B1N9Re , B1N9SgCav , B1N9SigCr , B1N9STVx , B1N9STVy , B1N9STVz , B1N9Theta , B1N9TnInd , & B1N9VDisx , B1N9VDisy , B1N9VDisz , B1N9Vindx , B1N9Vindy , B1N9VRel , B1N9VUndx , B1N9VUndy , & - B1N9VUndz , B1Pitch , B2AeroFx , B2AeroFxg , B2AeroFy , B2AeroFyg , B2AeroFz , B2AeroFzg , & - B2AeroMx , B2AeroMxg , B2AeroMy , B2AeroMyg , B2AeroMz , B2AeroMzg , B2AeroPwr , B2Azimuth , & - B2AeroFx , B2AeroFxg , B2AeroFy , B2AeroFyg , B2AeroFz , B2AeroFzg , B2AeroMx , B2AeroMxg , & - B2AeroMy , B2AeroMyg , B2AeroMz , B2AeroMzg , B2AeroPwr , B2N1Alpha , B2N1AxInd , B2N1Cd , & + B1N9VUndz , B1Pitch , B2AeroFx , B2AeroFxi , B2AeroFy , B2AeroFyi , B2AeroFz , B2AeroFzi , & + B2AeroMx , B2AeroMxi , B2AeroMy , B2AeroMyi , B2AeroMz , B2AeroMzi , B2AeroPwr , B2Azimuth , & + B2AeroFx , B2AeroFxi , B2AeroFy , B2AeroFyi , B2AeroFz , B2AeroFzi , B2AeroMx , B2AeroMxi , & + B2AeroMy , B2AeroMyi , B2AeroMz , B2AeroMzi , B2AeroPwr , B2N1Alpha , B2N1AxInd , B2N1Cd , & B2N1Cl , B2N1Clrnc , B2N1Cm , B2N1Cn , B2N1Cpmin , B2N1Ct , B2N1Curve , B2N1Cx , & B2N1Cy , B2N1DynP , B2N1Fbn , B2N1Fbs , B2N1Fbt , B2N1Fd , B2N1Fl , B2N1Fn , & B2N1Ft , B2N1Fx , B2N1Fy , B2N1Gam , B2N1M , B2N1Mbn , B2N1Mbs , B2N1Mbt , & @@ -2185,10 +2186,10 @@ module AeroDyn_IO_Params B2N9Ft , B2N9Fx , B2N9Fy , B2N9Gam , B2N9M , B2N9Mbn , B2N9Mbs , B2N9Mbt , & B2N9Mm , B2N9Phi , B2N9Re , B2N9SgCav , B2N9SigCr , B2N9STVx , B2N9STVy , B2N9STVz , & B2N9Theta , B2N9TnInd , B2N9VDisx , B2N9VDisy , B2N9VDisz , B2N9Vindx , B2N9Vindy , B2N9VRel , & - B2N9VUndx , B2N9VUndy , B2N9VUndz , B2Pitch , B3AeroFx , B3AeroFxg , B3AeroFy , B3AeroFyg , & - B3AeroFz , B3AeroFzg , B3AeroMx , B3AeroMxg , B3AeroMy , B3AeroMyg , B3AeroMz , B3AeroMzg , & - B3AeroPwr , B3Azimuth , B3AeroFx , B3AeroFxg , B3AeroFy , B3AeroFyg , B3AeroFz , B3AeroFzg , & - B3AeroMx , B3AeroMxg , B3AeroMy , B3AeroMyg , B3AeroMz , B3AeroMzg , B3AeroPwr , B3N1Alpha , & + B2N9VUndx , B2N9VUndy , B2N9VUndz , B2Pitch , B3AeroFx , B3AeroFxi , B3AeroFy , B3AeroFyi , & + B3AeroFz , B3AeroFzi , B3AeroMx , B3AeroMxi , B3AeroMy , B3AeroMyi , B3AeroMz , B3AeroMzi , & + B3AeroPwr , B3Azimuth , B3AeroFx , B3AeroFxi , B3AeroFy , B3AeroFyi , B3AeroFz , B3AeroFzi , & + B3AeroMx , B3AeroMxi , B3AeroMy , B3AeroMyi , B3AeroMz , B3AeroMzi , B3AeroPwr , B3N1Alpha , & B3N1AxInd , B3N1Cd , B3N1Cl , B3N1Clrnc , B3N1Cm , B3N1Cn , B3N1Cpmin , B3N1Ct , & B3N1Curve , B3N1Cx , B3N1Cy , B3N1DynP , B3N1Fbn , B3N1Fbs , B3N1Fbt , B3N1Fd , & B3N1Fl , B3N1Fn , B3N1Ft , B3N1Fx , B3N1Fy , B3N1Gam , B3N1M , B3N1Mbn , & @@ -2240,41 +2241,42 @@ module AeroDyn_IO_Params B3N9Fl , B3N9Fn , B3N9Ft , B3N9Fx , B3N9Fy , B3N9Gam , B3N9M , B3N9Mbn , & B3N9Mbs , B3N9Mbt , B3N9Mm , B3N9Phi , B3N9Re , B3N9SgCav , B3N9SigCr , B3N9STVx , & B3N9STVy , B3N9STVz , B3N9Theta , B3N9TnInd , B3N9VDisx , B3N9VDisy , B3N9VDisz , B3N9Vindx , & - B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , B3Pitch , B4AeroFx , B4AeroFxg , & - B4AeroFy , B4AeroFyg , B4AeroFz , B4AeroFzg , B4AeroMx , B4AeroMxg , B4AeroMy , B4AeroMyg , & - B4AeroMz , B4AeroMzg , B4AeroPwr , B4AeroFx , B4AeroFxg , B4AeroFy , B4AeroFyg , B4AeroFz , & - B4AeroFzg , B4AeroMx , B4AeroMxg , B4AeroMy , B4AeroMyg , B4AeroMz , B4AeroMzg , B4AeroPwr , & + B3N9Vindy , B3N9VRel , B3N9VUndx , B3N9VUndy , B3N9VUndz , B3Pitch , B4AeroFx , B4AeroFxi , & + B4AeroFy , B4AeroFyi , B4AeroFz , B4AeroFzi , B4AeroMx , B4AeroMxi , B4AeroMy , B4AeroMyi , & + B4AeroMz , B4AeroMzi , B4AeroPwr , B4AeroFx , B4AeroFxi , B4AeroFy , B4AeroFyi , B4AeroFz , & + B4AeroFzi , B4AeroMx , B4AeroMxi , B4AeroMy , B4AeroMyi , B4AeroMz , B4AeroMzi , B4AeroPwr , & DBEMTau1 , HbFbx , HbFby , HbFbz , HbMbx , HbMby , HbMbz , NcFbx , & NcFby , NcFbz , NcMbx , NcMby , NcMbz , RtAeroCp , RtAeroCq , RtAeroCt , & - RtAeroFxg , RtAeroFxh , RtAeroFyg , RtAeroFyh , RtAeroFzg , RtAeroFzh , RtAeroMxg , RtAeroMxh , & - RtAeroMyg , RtAeroMyh , RtAeroMzg , RtAeroMzh , RtAeroPwr , RtArea , RtAeroCp , RtAeroCq , & - RtAeroCt , RtAeroFxg , RtAeroFxh , RtAeroFyg , RtAeroFyh , RtAeroFzg , RtAeroFzh , RtAeroMxg , & - RtAeroMxh , RtAeroMyg , RtAeroMyh , RtAeroMzg , RtAeroMzh , RtAeroPwr , RtSkew , RtSpeed , & - RtTSR , RtVAvgxh , RtVAvgyh , RtVAvgzh , TFAlpha , TFFxi , TFFyi , TFFzi , & - TFMach , TFMxi , TFMyi , TFMzi , TFRe , TFSTVxi , TFSTVyi , TFSTVzi , & - TFVindxi , TFVindyi , TFVindzi , TFVrel , TFVrelxi , TFVrelyi , TFVrelzi , TFVundxi , & - TFVundyi , TFVundzi , TwN1DynP , TwN1Fbx , TwN1Fby , TwN1Fbz , TwN1Fdx , TwN1Fdy , & - TwN1M , TwN1Mbx , TwN1Mby , TwN1Mbz , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , & - TwN1Vrel , TwN1VUndx , TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fbx , TwN2Fby , TwN2Fbz , & - TwN2Fdx , TwN2Fdy , TwN2M , TwN2Mbx , TwN2Mby , TwN2Mbz , TwN2Re , TwN2STVx , & - TwN2STVy , TwN2STVz , TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , TwN3DynP , TwN3Fbx , & - TwN3Fby , TwN3Fbz , TwN3Fdx , TwN3Fdy , TwN3M , TwN3Mbx , TwN3Mby , TwN3Mbz , & - TwN3Re , TwN3STVx , TwN3STVy , TwN3STVz , TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , & - TwN4DynP , TwN4Fbx , TwN4Fby , TwN4Fbz , TwN4Fdx , TwN4Fdy , TwN4M , TwN4Mbx , & - TwN4Mby , TwN4Mbz , TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , TwN4VUndx , & - TwN4VUndy , TwN4VUndz , TwN5DynP , TwN5Fbx , TwN5Fby , TwN5Fbz , TwN5Fdx , TwN5Fdy , & - TwN5M , TwN5Mbx , TwN5Mby , TwN5Mbz , TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , & - TwN5Vrel , TwN5VUndx , TwN5VUndy , TwN5VUndz , TwN6DynP , TwN6Fbx , TwN6Fby , TwN6Fbz , & - TwN6Fdx , TwN6Fdy , TwN6M , TwN6Mbx , TwN6Mby , TwN6Mbz , TwN6Re , TwN6STVx , & - TwN6STVy , TwN6STVz , TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , TwN7DynP , TwN7Fbx , & - TwN7Fby , TwN7Fbz , TwN7Fdx , TwN7Fdy , TwN7M , TwN7Mbx , TwN7Mby , TwN7Mbz , & - TwN7Re , TwN7STVx , TwN7STVy , TwN7STVz , TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , & - TwN8DynP , TwN8Fbx , TwN8Fby , TwN8Fbz , TwN8Fdx , TwN8Fdy , TwN8M , TwN8Mbx , & - TwN8Mby , TwN8Mbz , TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , & - TwN8VUndy , TwN8VUndz , TwN9DynP , TwN9Fbx , TwN9Fby , TwN9Fbz , TwN9Fdx , TwN9Fdy , & - TwN9M , TwN9Mbx , TwN9Mby , TwN9Mbz , TwN9Re , TwN9STVx , TwN9STVy , TwN9STVz , & - TwN9Vrel , TwN9VUndx , TwN9VUndy , TwN9VUndz /) - CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1588) = (/ & ! This lists the units corresponding to the allowed parameters + RtAeroFxh , RtAeroFxi , RtAeroFyh , RtAeroFyi , RtAeroFzh , RtAeroFzi , RtAeroMxh , RtAeroMxi , & + RtAeroMyh , RtAeroMyi , RtAeroMzh , RtAeroMzi , RtAeroPwr , RtArea , RtAeroCp , RtAeroCq , & + RtAeroCt , RtAeroFxi , RtAeroFxh , RtAeroFxi , RtAeroFyi , RtAeroFyh , RtAeroFyi , RtAeroFzi , & + RtAeroFzh , RtAeroFzi , RtAeroMxi , RtAeroMxh , RtAeroMxi , RtAeroMyi , RtAeroMyh , RtAeroMyi , & + RtAeroMzi , RtAeroMzh , RtAeroMzi , RtAeroPwr , RtSkew , RtSpeed , RtTSR , RtVAvgxh , & + RtVAvgyh , RtVAvgzh , TFAlpha , TFFxi , TFFyi , TFFzi , TFMach , TFMxi , & + TFMyi , TFMzi , TFRe , TFSTVxi , TFSTVyi , TFSTVzi , TFVindxi , TFVindyi , & + TFVindzi , TFVrel , TFVrelxi , TFVrelyi , TFVrelzi , TFVundxi , TFVundyi , TFVundzi , & + TwN1DynP , TwN1Fbx , TwN1Fby , TwN1Fbz , TwN1Fdx , TwN1Fdy , TwN1M , TwN1Mbx , & + TwN1Mby , TwN1Mbz , TwN1Re , TwN1STVx , TwN1STVy , TwN1STVz , TwN1Vrel , TwN1VUndx , & + TwN1VUndy , TwN1VUndz , TwN2DynP , TwN2Fbx , TwN2Fby , TwN2Fbz , TwN2Fdx , TwN2Fdy , & + TwN2M , TwN2Mbx , TwN2Mby , TwN2Mbz , TwN2Re , TwN2STVx , TwN2STVy , TwN2STVz , & + TwN2Vrel , TwN2VUndx , TwN2VUndy , TwN2VUndz , TwN3DynP , TwN3Fbx , TwN3Fby , TwN3Fbz , & + TwN3Fdx , TwN3Fdy , TwN3M , TwN3Mbx , TwN3Mby , TwN3Mbz , TwN3Re , TwN3STVx , & + TwN3STVy , TwN3STVz , TwN3Vrel , TwN3VUndx , TwN3VUndy , TwN3VUndz , TwN4DynP , TwN4Fbx , & + TwN4Fby , TwN4Fbz , TwN4Fdx , TwN4Fdy , TwN4M , TwN4Mbx , TwN4Mby , TwN4Mbz , & + TwN4Re , TwN4STVx , TwN4STVy , TwN4STVz , TwN4Vrel , TwN4VUndx , TwN4VUndy , TwN4VUndz , & + TwN5DynP , TwN5Fbx , TwN5Fby , TwN5Fbz , TwN5Fdx , TwN5Fdy , TwN5M , TwN5Mbx , & + TwN5Mby , TwN5Mbz , TwN5Re , TwN5STVx , TwN5STVy , TwN5STVz , TwN5Vrel , TwN5VUndx , & + TwN5VUndy , TwN5VUndz , TwN6DynP , TwN6Fbx , TwN6Fby , TwN6Fbz , TwN6Fdx , TwN6Fdy , & + TwN6M , TwN6Mbx , TwN6Mby , TwN6Mbz , TwN6Re , TwN6STVx , TwN6STVy , TwN6STVz , & + TwN6Vrel , TwN6VUndx , TwN6VUndy , TwN6VUndz , TwN7DynP , TwN7Fbx , TwN7Fby , TwN7Fbz , & + TwN7Fdx , TwN7Fdy , TwN7M , TwN7Mbx , TwN7Mby , TwN7Mbz , TwN7Re , TwN7STVx , & + TwN7STVy , TwN7STVz , TwN7Vrel , TwN7VUndx , TwN7VUndy , TwN7VUndz , TwN8DynP , TwN8Fbx , & + TwN8Fby , TwN8Fbz , TwN8Fdx , TwN8Fdy , TwN8M , TwN8Mbx , TwN8Mby , TwN8Mbz , & + TwN8Re , TwN8STVx , TwN8STVy , TwN8STVz , TwN8Vrel , TwN8VUndx , TwN8VUndy , TwN8VUndz , & + TwN9DynP , TwN9Fbx , TwN9Fby , TwN9Fbz , TwN9Fdx , TwN9Fdy , TwN9M , TwN9Mbx , & + TwN9Mby , TwN9Mbz , TwN9Re , TwN9STVx , TwN9STVy , TwN9STVz , TwN9Vrel , TwN9VUndx , & + TwN9VUndy , TwN9VUndz /) + CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(1594) = (/ character(ChanLen) :: & ! This lists the units corresponding to the allowed parameters "(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ", & "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(N) ","(N) ", & "(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ", & @@ -2448,11 +2450,14 @@ module AeroDyn_IO_Params "(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(-) ","(-) ","(-) ", & "(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ","(N-m) ", & "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(m^2) ","(-) ","(-) ", & - "(-) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N-m) ", & - "(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(rpm) ", & - "(-) ","(m/s) ","(m/s) ","(m/s) ","(deg) ","(N) ","(N) ","(N) ", & - "(-) ","(N-m) ","(N-m) ","(N-m) ","(-) ","(m/s) ","(m/s) ","(m/s) ", & + "(-) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ","(N) ", & + "(N) ","(N) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ","(N-m) ", & + "(N-m) ","(N-m) ","(N-m) ","(W) ","(deg) ","(rpm) ","(-) ","(m/s) ", & + "(m/s) ","(m/s) ","(deg) ","(N) ","(N) ","(N) ","(-) ","(N-m) ", & + "(N-m) ","(N-m) ","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & + "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ","(N-m/m)", & + "(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & "(-) ","(N-m/m)","(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ", & "(m/s) ","(m/s) ","(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ", & @@ -2471,9 +2476,7 @@ module AeroDyn_IO_Params "(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & "(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(-) ","(N-m/m)", & "(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(Pa) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ","(N/m) ", & - "(-) ","(N-m/m)","(N-m/m)","(N-m/m)","(-) ","(m/s) ","(m/s) ","(m/s) ", & - "(m/s) ","(m/s) ","(m/s) ","(m/s) "/) + "(m/s) ","(m/s) "/) end module AeroDyn_IO_Params diff --git a/modules/aerodyn/src/AeroDyn_Inflow.f90 b/modules/aerodyn/src/AeroDyn_Inflow.f90 index e77646ca3d..cf44e7dfcd 100644 --- a/modules/aerodyn/src/AeroDyn_Inflow.f90 +++ b/modules/aerodyn/src/AeroDyn_Inflow.f90 @@ -500,7 +500,7 @@ subroutine Init_MeshMap_For_ADI(FED, p, uAD, errStat, errMsg) if (y_ED%hasTower) then twrHeightAD=uAD%rotors(iWT)%TowerMotion%Position(3,uAD%rotors(iWT)%TowerMotion%nNodes)-uAD%rotors(iWT)%TowerMotion%Position(3,1) ! Check tower height - if ( p%MHK==2 ) then + if ( p%MHK==MHK_Floating ) then if (twrHeightAD>0) then errStat=ErrID_Fatal errMsg='First AeroDyn tower height should be larger than last AD tower height for a floating MHK turbine' @@ -513,9 +513,9 @@ subroutine Init_MeshMap_For_ADI(FED, p, uAD, errStat, errMsg) endif twrHeightAD=uAD%rotors(iWT)%TowerMotion%Position(3,uAD%rotors(iWT)%TowerMotion%nNodes) ! NOTE: assuming start a z=0 - if ( p%MHK==1 ) then + if ( p%MHK==MHK_FixedBottom ) then twrHeightAD = twrHeightAD + p%WtrDpth - elseif ( p%MHK==2 ) then + elseif ( p%MHK==MHK_Floating ) then twrHeightAD = abs(twrHeightAD) endif @@ -531,13 +531,13 @@ subroutine Init_MeshMap_For_ADI(FED, p, uAD, errStat, errMsg) ! Adjust tower position (AeroDyn return values assuming (0,0,0) for tower base Pbase = y_ED%TwrPtMesh%Position(:,1) Ptop = y_ED%NacelleMotion%Position(:,1) - if ( p%MHK==2 ) then + if ( p%MHK==MHK_Floating ) then DeltaP = Pbase-Ptop else DeltaP = Ptop-Pbase endif do i = 1, uAD%rotors(iWT)%TowerMotion%nNodes - if ( p%MHK==1 ) then + if ( p%MHK==MHK_FixedBottom ) then zBar = (uAD%rotors(iWT)%TowerMotion%Position(3,i) + p%WtrDpth) / twrHeight else zBar = uAD%rotors(iWT)%TowerMotion%Position(3,i)/twrHeight diff --git a/modules/aerodyn/src/AeroDyn_Registry.txt b/modules/aerodyn/src/AeroDyn_Registry.txt index e24324836e..86142df842 100644 --- a/modules/aerodyn/src/AeroDyn_Registry.txt +++ b/modules/aerodyn/src/AeroDyn_Registry.txt @@ -85,6 +85,7 @@ typedef ^ RotInitInputType R8Ki NacellePosition {3} - - "X-Y-Z reference positio typedef ^ RotInitInputType R8Ki NacelleOrientation {3}{3} - - "DCM reference orientation of nacelle" - typedef ^ RotInitInputType IntKi AeroProjMod - 1 - "Flag to switch between different projection models" - typedef ^ RotInitInputType IntKi AeroBEM_Mod - -1 - "Flag to switch between different BEM Model" - +typedef ^ RotInitInputType ReKi RotSpeed - - 0 "Rotor speed used when AeroDyn is computing aero maps" "rad/s" typedef ^ InitInputType RotInitInputType rotors {:} - - "Init Input Types for rotors" - typedef ^ InitInputType CHARACTER(1024) InputFile - - - "Name of the input file" - @@ -92,6 +93,7 @@ typedef ^ InitInputType CHARACTER(1024) RootName - - - "RootName for writing out typedef ^ InitInputType LOGICAL UsePrimaryInputFile - .TRUE. - "Read input file instead of passed data" - typedef ^ InitInputType FileInfoType PassedPrimaryInputData - - - "Primary input file as FileInfoType (set by driver/glue code)" - typedef ^ InitInputType Logical Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - +typedef ^ InitInputType LOGICAL CompAeroMaps - .FALSE. - "flag to determine if AeroDyn is computing aero maps (true) or running a normal simulation (false)" - typedef ^ InitInputType ReKi Gravity - - - "Gravity force" Nm/s^2 typedef ^ InitInputType IntKi MHK - - - "MHK turbine type switch" - typedef ^ InitInputType ReKi defFldDens - - - "Default fluid density from the driver; may be overwritten" kg/m^3 @@ -264,6 +266,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 @@ -277,6 +280,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 @@ -287,8 +291,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 @@ -429,6 +431,7 @@ typedef ^ RotInputType ReKi AccelOnTower {:}{:} - - "Wind acceleration at nodes typedef ^ RotInputType ReKi InflowOnHub {3}{1} - - "U,V,W at hub" m/s typedef ^ RotInputType ReKi InflowOnNacelle {3}{1} - - "U,V,W at nacelle" m/s typedef ^ RotInputType ReKi InflowOnTailFin {3}{1} - - "U,V,W at tailfin" m/s +typedef ^ RotInputType ReKi AvgDiskVel {3} - 0.0 "disk-averaged U,V,W" m/s typedef ^ RotInputType ReKi UserProp {:}{:} - - "Optional user property for interpolating airfoils (per element per blade)" - diff --git a/modules/aerodyn/src/AeroDyn_Types.f90 b/modules/aerodyn/src/AeroDyn_Types.f90 index 47acb4d235..0bbcb29b27 100644 --- a/modules/aerodyn/src/AeroDyn_Types.f90 +++ b/modules/aerodyn/src/AeroDyn_Types.f90 @@ -102,6 +102,7 @@ MODULE AeroDyn_Types REAL(R8Ki) , DIMENSION(1:3,1:3) :: NacelleOrientation = 0.0_R8Ki !< DCM reference orientation of nacelle [-] INTEGER(IntKi) :: AeroProjMod = 1 !< Flag to switch between different projection models [-] INTEGER(IntKi) :: AeroBEM_Mod = -1 !< Flag to switch between different BEM Model [-] + REAL(ReKi) :: RotSpeed = 0.0_ReKi !< Rotor speed used when AeroDyn is computing aero maps [rad/s] END TYPE RotInitInputType ! ======================= ! ========= AD_InitInputType ======= @@ -112,6 +113,7 @@ MODULE AeroDyn_Types LOGICAL :: UsePrimaryInputFile = .TRUE. !< Read input file instead of passed data [-] TYPE(FileInfoType) :: PassedPrimaryInputData !< Primary input file as FileInfoType (set by driver/glue code) [-] LOGICAL :: Linearize = .FALSE. !< Flag that tells this module if the glue code wants to linearize. [-] + LOGICAL :: CompAeroMaps = .FALSE. !< flag to determine if AeroDyn is computing aero maps (true) or running a normal simulation (false) [-] REAL(ReKi) :: Gravity = 0.0_ReKi !< Gravity force [Nm/s^2] INTEGER(IntKi) :: MHK = 0_IntKi !< MHK turbine type switch [-] REAL(ReKi) :: defFldDens = 0.0_ReKi !< Default fluid density from the driver; may be overwritten [kg/m^3] @@ -304,6 +306,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] @@ -317,6 +320,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 = 0.0_ReKi !< disk-average relative wind speed [m/s] REAL(ReKi) :: yaw = 0.0_ReKi !< Yaw calculated in SetInputsForBEMT [rad] REAL(ReKi) :: tilt = 0.0_ReKi !< tilt calculated in SetInputsForBEMT [rad] @@ -327,8 +331,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] @@ -469,6 +471,7 @@ MODULE AeroDyn_Types REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnHub = 0.0_ReKi !< U,V,W at hub [m/s] REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnNacelle = 0.0_ReKi !< U,V,W at nacelle [m/s] REAL(ReKi) , DIMENSION(1:3,1:1) :: InflowOnTailFin = 0.0_ReKi !< U,V,W at tailfin [m/s] + REAL(ReKi) , DIMENSION(1:3) :: AvgDiskVel = 0.0_ReKi !< disk-averaged U,V,W [m/s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: UserProp !< Optional user property for interpolating airfoils (per element per blade) [-] END TYPE RotInputType ! ======================= @@ -861,6 +864,7 @@ subroutine AD_CopyRotInitInputType(SrcRotInitInputTypeData, DstRotInitInputTypeD DstRotInitInputTypeData%NacelleOrientation = SrcRotInitInputTypeData%NacelleOrientation DstRotInitInputTypeData%AeroProjMod = SrcRotInitInputTypeData%AeroProjMod DstRotInitInputTypeData%AeroBEM_Mod = SrcRotInitInputTypeData%AeroBEM_Mod + DstRotInitInputTypeData%RotSpeed = SrcRotInitInputTypeData%RotSpeed end subroutine subroutine AD_DestroyRotInitInputType(RotInitInputTypeData, ErrStat, ErrMsg) @@ -900,6 +904,7 @@ subroutine AD_PackRotInitInputType(Buf, Indata) call RegPack(Buf, InData%NacelleOrientation) call RegPack(Buf, InData%AeroProjMod) call RegPack(Buf, InData%AeroBEM_Mod) + call RegPack(Buf, InData%RotSpeed) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -953,6 +958,8 @@ subroutine AD_UnPackRotInitInputType(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%AeroBEM_Mod) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%RotSpeed) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine AD_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg) @@ -991,6 +998,7 @@ subroutine AD_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrSta call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return DstInitInputData%Linearize = SrcInitInputData%Linearize + DstInitInputData%CompAeroMaps = SrcInitInputData%CompAeroMaps DstInitInputData%Gravity = SrcInitInputData%Gravity DstInitInputData%MHK = SrcInitInputData%MHK DstInitInputData%defFldDens = SrcInitInputData%defFldDens @@ -1047,6 +1055,7 @@ subroutine AD_PackInitInput(Buf, Indata) call RegPack(Buf, InData%UsePrimaryInputFile) call NWTC_Library_PackFileInfoType(Buf, InData%PassedPrimaryInputData) call RegPack(Buf, InData%Linearize) + call RegPack(Buf, InData%CompAeroMaps) call RegPack(Buf, InData%Gravity) call RegPack(Buf, InData%MHK) call RegPack(Buf, InData%defFldDens) @@ -1092,6 +1101,8 @@ subroutine AD_UnPackInitInput(Buf, OutData) call NWTC_Library_UnpackFileInfoType(Buf, OutData%PassedPrimaryInputData) ! PassedPrimaryInputData call RegUnpack(Buf, OutData%Linearize) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%Gravity) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%MHK) @@ -3696,6 +3707,18 @@ subroutine AD_CopyRotMiscVarType(SrcRotMiscVarTypeData, DstRotMiscVarTypeData, C end if DstRotMiscVarTypeData%orientationAnnulus = SrcRotMiscVarTypeData%orientationAnnulus end if + if (allocated(SrcRotMiscVarTypeData%R_li)) then + LB(1:4) = lbound(SrcRotMiscVarTypeData%R_li) + UB(1:4) = ubound(SrcRotMiscVarTypeData%R_li) + if (.not. allocated(DstRotMiscVarTypeData%R_li)) then + allocate(DstRotMiscVarTypeData%R_li(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3),LB(4):UB(4)), 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 + end if if (allocated(SrcRotMiscVarTypeData%AllOuts)) then LB(1:1) = lbound(SrcRotMiscVarTypeData%AllOuts) UB(1:1) = ubound(SrcRotMiscVarTypeData%AllOuts) @@ -3852,6 +3875,18 @@ subroutine AD_CopyRotMiscVarType(SrcRotMiscVarTypeData, DstRotMiscVarTypeData, C end if DstRotMiscVarTypeData%Mz = SrcRotMiscVarTypeData%Mz end if + if (allocated(SrcRotMiscVarTypeData%Vind_i)) then + LB(1:3) = lbound(SrcRotMiscVarTypeData%Vind_i) + UB(1:3) = ubound(SrcRotMiscVarTypeData%Vind_i) + if (.not. allocated(DstRotMiscVarTypeData%Vind_i)) then + allocate(DstRotMiscVarTypeData%Vind_i(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)), 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 + end if DstRotMiscVarTypeData%V_DiskAvg = SrcRotMiscVarTypeData%V_DiskAvg DstRotMiscVarTypeData%yaw = SrcRotMiscVarTypeData%yaw DstRotMiscVarTypeData%tilt = SrcRotMiscVarTypeData%tilt @@ -3923,30 +3958,6 @@ subroutine AD_CopyRotMiscVarType(SrcRotMiscVarTypeData, DstRotMiscVarTypeData, C end if DstRotMiscVarTypeData%CavitWarnSet = SrcRotMiscVarTypeData%CavitWarnSet end if - if (allocated(SrcRotMiscVarTypeData%BlFB)) then - LB(1:3) = lbound(SrcRotMiscVarTypeData%BlFB) - UB(1:3) = ubound(SrcRotMiscVarTypeData%BlFB) - if (.not. allocated(DstRotMiscVarTypeData%BlFB)) then - allocate(DstRotMiscVarTypeData%BlFB(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)), 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 - end if - if (allocated(SrcRotMiscVarTypeData%BlMB)) then - LB(1:3) = lbound(SrcRotMiscVarTypeData%BlMB) - UB(1:3) = ubound(SrcRotMiscVarTypeData%BlMB) - if (.not. allocated(DstRotMiscVarTypeData%BlMB)) then - allocate(DstRotMiscVarTypeData%BlMB(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)), 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 - end if if (allocated(SrcRotMiscVarTypeData%TwrFB)) then LB(1:2) = lbound(SrcRotMiscVarTypeData%TwrFB) UB(1:2) = ubound(SrcRotMiscVarTypeData%TwrFB) @@ -4155,6 +4166,9 @@ subroutine AD_DestroyRotMiscVarType(RotMiscVarTypeData, ErrStat, ErrMsg) if (allocated(RotMiscVarTypeData%orientationAnnulus)) then deallocate(RotMiscVarTypeData%orientationAnnulus) end if + if (allocated(RotMiscVarTypeData%R_li)) then + deallocate(RotMiscVarTypeData%R_li) + end if if (allocated(RotMiscVarTypeData%AllOuts)) then deallocate(RotMiscVarTypeData%AllOuts) end if @@ -4194,6 +4208,9 @@ subroutine AD_DestroyRotMiscVarType(RotMiscVarTypeData, ErrStat, ErrMsg) if (allocated(RotMiscVarTypeData%Mz)) then deallocate(RotMiscVarTypeData%Mz) end if + if (allocated(RotMiscVarTypeData%Vind_i)) then + deallocate(RotMiscVarTypeData%Vind_i) + end if if (allocated(RotMiscVarTypeData%hub_theta_x_root)) then deallocate(RotMiscVarTypeData%hub_theta_x_root) end if @@ -4217,12 +4234,6 @@ subroutine AD_DestroyRotMiscVarType(RotMiscVarTypeData, ErrStat, ErrMsg) if (allocated(RotMiscVarTypeData%CavitWarnSet)) then deallocate(RotMiscVarTypeData%CavitWarnSet) end if - if (allocated(RotMiscVarTypeData%BlFB)) then - deallocate(RotMiscVarTypeData%BlFB) - end if - if (allocated(RotMiscVarTypeData%BlMB)) then - deallocate(RotMiscVarTypeData%BlMB) - end if if (allocated(RotMiscVarTypeData%TwrFB)) then deallocate(RotMiscVarTypeData%TwrFB) end if @@ -4321,6 +4332,11 @@ subroutine AD_PackRotMiscVarType(Buf, Indata) call RegPackBounds(Buf, 4, lbound(InData%orientationAnnulus), ubound(InData%orientationAnnulus)) call RegPack(Buf, InData%orientationAnnulus) end if + call RegPack(Buf, allocated(InData%R_li)) + if (allocated(InData%R_li)) then + call RegPackBounds(Buf, 4, lbound(InData%R_li), ubound(InData%R_li)) + call RegPack(Buf, InData%R_li) + end if call RegPack(Buf, allocated(InData%AllOuts)) if (allocated(InData%AllOuts)) then call RegPackBounds(Buf, 1, lbound(InData%AllOuts), ubound(InData%AllOuts)) @@ -4386,6 +4402,11 @@ subroutine AD_PackRotMiscVarType(Buf, Indata) call RegPackBounds(Buf, 2, lbound(InData%Mz), ubound(InData%Mz)) call RegPack(Buf, InData%Mz) end if + call RegPack(Buf, allocated(InData%Vind_i)) + if (allocated(InData%Vind_i)) then + call RegPackBounds(Buf, 3, lbound(InData%Vind_i), ubound(InData%Vind_i)) + call RegPack(Buf, InData%Vind_i) + end if call RegPack(Buf, InData%V_DiskAvg) call RegPack(Buf, InData%yaw) call RegPack(Buf, InData%tilt) @@ -4420,16 +4441,6 @@ subroutine AD_PackRotMiscVarType(Buf, Indata) call RegPackBounds(Buf, 2, lbound(InData%CavitWarnSet), ubound(InData%CavitWarnSet)) call RegPack(Buf, InData%CavitWarnSet) end if - call RegPack(Buf, allocated(InData%BlFB)) - if (allocated(InData%BlFB)) then - call RegPackBounds(Buf, 3, lbound(InData%BlFB), ubound(InData%BlFB)) - call RegPack(Buf, InData%BlFB) - end if - call RegPack(Buf, allocated(InData%BlMB)) - if (allocated(InData%BlMB)) then - call RegPackBounds(Buf, 3, lbound(InData%BlMB), ubound(InData%BlMB)) - call RegPack(Buf, InData%BlMB) - end if call RegPack(Buf, allocated(InData%TwrFB)) if (allocated(InData%TwrFB)) then call RegPackBounds(Buf, 2, lbound(InData%TwrFB), ubound(InData%TwrFB)) @@ -4570,6 +4581,20 @@ subroutine AD_UnPackRotMiscVarType(Buf, OutData) call RegUnpack(Buf, OutData%orientationAnnulus) if (RegCheckErr(Buf, RoutineName)) return end if + if (allocated(OutData%R_li)) deallocate(OutData%R_li) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 4, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%R_li(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3),LB(4):UB(4)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%R_li.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%R_li) + if (RegCheckErr(Buf, RoutineName)) return + end if if (allocated(OutData%AllOuts)) deallocate(OutData%AllOuts) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -4752,6 +4777,20 @@ subroutine AD_UnPackRotMiscVarType(Buf, OutData) call RegUnpack(Buf, OutData%Mz) if (RegCheckErr(Buf, RoutineName)) return end if + if (allocated(OutData%Vind_i)) deallocate(OutData%Vind_i) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 3, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%Vind_i(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%Vind_i.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%Vind_i) + if (RegCheckErr(Buf, RoutineName)) return + end if call RegUnpack(Buf, OutData%V_DiskAvg) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%yaw) @@ -4832,34 +4871,6 @@ subroutine AD_UnPackRotMiscVarType(Buf, OutData) call RegUnpack(Buf, OutData%CavitWarnSet) if (RegCheckErr(Buf, RoutineName)) return end if - if (allocated(OutData%BlFB)) deallocate(OutData%BlFB) - call RegUnpack(Buf, IsAllocAssoc) - if (RegCheckErr(Buf, RoutineName)) return - if (IsAllocAssoc) then - call RegUnpackBounds(Buf, 3, LB, UB) - if (RegCheckErr(Buf, RoutineName)) return - allocate(OutData%BlFB(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)),stat=stat) - if (stat /= 0) then - call SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlFB.', Buf%ErrStat, Buf%ErrMsg, RoutineName) - return - end if - call RegUnpack(Buf, OutData%BlFB) - if (RegCheckErr(Buf, RoutineName)) return - end if - if (allocated(OutData%BlMB)) deallocate(OutData%BlMB) - call RegUnpack(Buf, IsAllocAssoc) - if (RegCheckErr(Buf, RoutineName)) return - if (IsAllocAssoc) then - call RegUnpackBounds(Buf, 3, LB, UB) - if (RegCheckErr(Buf, RoutineName)) return - allocate(OutData%BlMB(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)),stat=stat) - if (stat /= 0) then - call SetErrStat(ErrID_Fatal, 'Error allocating OutData%BlMB.', Buf%ErrStat, Buf%ErrMsg, RoutineName) - return - end if - call RegUnpack(Buf, OutData%BlMB) - if (RegCheckErr(Buf, RoutineName)) return - end if if (allocated(OutData%TwrFB)) deallocate(OutData%TwrFB) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -6699,6 +6710,7 @@ subroutine AD_CopyRotInputType(SrcRotInputTypeData, DstRotInputTypeData, CtrlCod DstRotInputTypeData%InflowOnHub = SrcRotInputTypeData%InflowOnHub DstRotInputTypeData%InflowOnNacelle = SrcRotInputTypeData%InflowOnNacelle DstRotInputTypeData%InflowOnTailFin = SrcRotInputTypeData%InflowOnTailFin + DstRotInputTypeData%AvgDiskVel = SrcRotInputTypeData%AvgDiskVel if (allocated(SrcRotInputTypeData%UserProp)) then LB(1:2) = lbound(SrcRotInputTypeData%UserProp) UB(1:2) = ubound(SrcRotInputTypeData%UserProp) @@ -6821,6 +6833,7 @@ subroutine AD_PackRotInputType(Buf, Indata) call RegPack(Buf, InData%InflowOnHub) call RegPack(Buf, InData%InflowOnNacelle) call RegPack(Buf, InData%InflowOnTailFin) + call RegPack(Buf, InData%AvgDiskVel) call RegPack(Buf, allocated(InData%UserProp)) if (allocated(InData%UserProp)) then call RegPackBounds(Buf, 2, lbound(InData%UserProp), ubound(InData%UserProp)) @@ -6921,6 +6934,8 @@ subroutine AD_UnPackRotInputType(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%InflowOnTailFin) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%AvgDiskVel) + if (RegCheckErr(Buf, RoutineName)) return if (allocated(OutData%UserProp)) deallocate(OutData%UserProp) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -7494,6 +7509,9 @@ SUBROUTINE AD_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) u_out%rotors(i01)%InflowOnTailFin = a1*u1%rotors(i01)%InflowOnTailFin + a2*u2%rotors(i01)%InflowOnTailFin END DO + DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) + u_out%rotors(i01)%AvgDiskVel = a1*u1%rotors(i01)%AvgDiskVel + a2*u2%rotors(i01)%AvgDiskVel + END DO DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) IF (ALLOCATED(u_out%rotors(i01)%UserProp) .AND. ALLOCATED(u1%rotors(i01)%UserProp)) THEN u_out%rotors(i01)%UserProp = a1*u1%rotors(i01)%UserProp + a2*u2%rotors(i01)%UserProp @@ -7630,6 +7648,9 @@ SUBROUTINE AD_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrM DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) u_out%rotors(i01)%InflowOnTailFin = a1*u1%rotors(i01)%InflowOnTailFin + a2*u2%rotors(i01)%InflowOnTailFin + a3*u3%rotors(i01)%InflowOnTailFin END DO + DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) + u_out%rotors(i01)%AvgDiskVel = a1*u1%rotors(i01)%AvgDiskVel + a2*u2%rotors(i01)%AvgDiskVel + a3*u3%rotors(i01)%AvgDiskVel + END DO DO i01 = LBOUND(u_out%rotors,1),UBOUND(u_out%rotors,1) IF (ALLOCATED(u_out%rotors(i01)%UserProp) .AND. ALLOCATED(u1%rotors(i01)%UserProp)) THEN u_out%rotors(i01)%UserProp = a1*u1%rotors(i01)%UserProp + a2*u2%rotors(i01)%UserProp + a3*u3%rotors(i01)%UserProp diff --git a/modules/aerodyn/src/BEMT.f90 b/modules/aerodyn/src/BEMT.f90 index d62b855be5..c71362ca7f 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 @@ -872,7 +882,7 @@ subroutine BEMT_UpdateStates( t, n, u, utimes, p, x, xd, z, OtherState, AFInfo, !........................ do j = 1,p%numBlades do i = 1,p%numBladeNodes - call DBEMT_UpdateStates(i, j, t, n, m%u_DBEMT, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, errStat2, errMsg2) + call DBEMT_UpdateStates(i, j, t, n, m%u_DBEMT, uTimes, p%DBEMT, x%DBEMT, OtherState%DBEMT, m%DBEMT, errStat2, errMsg2) if (ErrStat2 /= ErrID_None) then call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//trim(NodeText(i,j))) if (errStat >= AbortErrLev) return @@ -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..bd825bc739 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 @@ -619,16 +633,18 @@ subroutine inductionFactors0(B, r, chord, phi, cn, ct, Vx, Vy, F, wakerotation, ! Convert from double to ReKi a_out = real( a, ReKi ) ap_out = real( ap, ReKi ) + k_out = real( k, ReKi ) + kp_out = real( kp, 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 +660,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 +721,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 +758,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 +773,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 +786,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 +820,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 +867,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 +885,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 +919,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 +937,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 7f863d8a46..9242628999 100644 --- a/modules/aerodyn/src/BEMT_Types.f90 +++ b/modules/aerodyn/src/BEMT_Types.f90 @@ -182,8 +182,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 = 0.0_ReKi !< 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 = 0.0_ReKi !< 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 = 0.0_ReKi !< 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 = 0.0_ReKi !< Angular velocity of rotor [rad/s] REAL(ReKi) :: TSR = 0.0_ReKi !< Tip-speed ratio (to check if BEM should be turned off) [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: Vx !< Local axial velocity at node [m/s] @@ -207,6 +207,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 [-] @@ -1949,17 +1954,17 @@ subroutine BEMT_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) end if DstInputData%chi0 = SrcInputData%chi0 DstInputData%psiSkewOffset = SrcInputData%psiSkewOffset - if (allocated(SrcInputData%psi)) then - LB(1:1) = lbound(SrcInputData%psi) - UB(1:1) = ubound(SrcInputData%psi) - if (.not. allocated(DstInputData%psi)) then - allocate(DstInputData%psi(LB(1):UB(1)), stat=ErrStat2) + if (allocated(SrcInputData%psi_s)) then + LB(1:1) = lbound(SrcInputData%psi_s) + UB(1:1) = ubound(SrcInputData%psi_s) + if (.not. allocated(DstInputData%psi_s)) then + allocate(DstInputData%psi_s(LB(1):UB(1)), 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 end if DstInputData%omega = SrcInputData%omega DstInputData%TSR = SrcInputData%TSR @@ -2098,8 +2103,8 @@ subroutine BEMT_DestroyInput(InputData, ErrStat, ErrMsg) if (allocated(InputData%theta)) then deallocate(InputData%theta) end if - if (allocated(InputData%psi)) then - deallocate(InputData%psi) + if (allocated(InputData%psi_s)) then + deallocate(InputData%psi_s) end if if (allocated(InputData%Vx)) then deallocate(InputData%Vx) @@ -2145,10 +2150,10 @@ subroutine BEMT_PackInput(Buf, Indata) end if call RegPack(Buf, InData%chi0) call RegPack(Buf, InData%psiSkewOffset) - call RegPack(Buf, allocated(InData%psi)) - if (allocated(InData%psi)) then - call RegPackBounds(Buf, 1, lbound(InData%psi), ubound(InData%psi)) - call RegPack(Buf, InData%psi) + call RegPack(Buf, allocated(InData%psi_s)) + if (allocated(InData%psi_s)) then + call RegPackBounds(Buf, 1, lbound(InData%psi_s), ubound(InData%psi_s)) + call RegPack(Buf, InData%psi_s) end if call RegPack(Buf, InData%omega) call RegPack(Buf, InData%TSR) @@ -2234,18 +2239,18 @@ subroutine BEMT_UnPackInput(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%psiSkewOffset) if (RegCheckErr(Buf, RoutineName)) return - if (allocated(OutData%psi)) deallocate(OutData%psi) + if (allocated(OutData%psi_s)) deallocate(OutData%psi_s) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return if (IsAllocAssoc) then call RegUnpackBounds(Buf, 1, LB, UB) if (RegCheckErr(Buf, RoutineName)) return - allocate(OutData%psi(LB(1):UB(1)),stat=stat) + allocate(OutData%psi_s(LB(1):UB(1)),stat=stat) if (stat /= 0) then - call SetErrStat(ErrID_Fatal, 'Error allocating OutData%psi.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%psi_s.', Buf%ErrStat, Buf%ErrMsg, RoutineName) return end if - call RegUnpack(Buf, OutData%psi) + call RegUnpack(Buf, OutData%psi_s) if (RegCheckErr(Buf, RoutineName)) return end if call RegUnpack(Buf, OutData%omega) @@ -2459,6 +2464,66 @@ subroutine BEMT_CopyOutput(SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrM end if DstOutputData%tanInduction = SrcOutputData%tanInduction end if + if (allocated(SrcOutputData%axInduction_qs)) then + LB(1:2) = lbound(SrcOutputData%axInduction_qs) + UB(1:2) = ubound(SrcOutputData%axInduction_qs) + if (.not. allocated(DstOutputData%axInduction_qs)) then + allocate(DstOutputData%axInduction_qs(LB(1):UB(1),LB(2):UB(2)), 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 + end if + if (allocated(SrcOutputData%tanInduction_qs)) then + LB(1:2) = lbound(SrcOutputData%tanInduction_qs) + UB(1:2) = ubound(SrcOutputData%tanInduction_qs) + if (.not. allocated(DstOutputData%tanInduction_qs)) then + allocate(DstOutputData%tanInduction_qs(LB(1):UB(1),LB(2):UB(2)), 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 + end if + if (allocated(SrcOutputData%k)) then + LB(1:2) = lbound(SrcOutputData%k) + UB(1:2) = ubound(SrcOutputData%k) + if (.not. allocated(DstOutputData%k)) then + allocate(DstOutputData%k(LB(1):UB(1),LB(2):UB(2)), 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 + end if + if (allocated(SrcOutputData%k_p)) then + LB(1:2) = lbound(SrcOutputData%k_p) + UB(1:2) = ubound(SrcOutputData%k_p) + if (.not. allocated(DstOutputData%k_p)) then + allocate(DstOutputData%k_p(LB(1):UB(1),LB(2):UB(2)), 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 + end if + if (allocated(SrcOutputData%F)) then + LB(1:2) = lbound(SrcOutputData%F) + UB(1:2) = ubound(SrcOutputData%F) + if (.not. allocated(DstOutputData%F)) then + allocate(DstOutputData%F(LB(1):UB(1),LB(2):UB(2)), 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 + end if if (allocated(SrcOutputData%Re)) then LB(1:2) = lbound(SrcOutputData%Re) UB(1:2) = ubound(SrcOutputData%Re) @@ -2636,6 +2701,21 @@ subroutine BEMT_DestroyOutput(OutputData, ErrStat, ErrMsg) if (allocated(OutputData%tanInduction)) then deallocate(OutputData%tanInduction) end if + if (allocated(OutputData%axInduction_qs)) then + deallocate(OutputData%axInduction_qs) + end if + if (allocated(OutputData%tanInduction_qs)) then + deallocate(OutputData%tanInduction_qs) + end if + if (allocated(OutputData%k)) then + deallocate(OutputData%k) + end if + if (allocated(OutputData%k_p)) then + deallocate(OutputData%k_p) + end if + if (allocated(OutputData%F)) then + deallocate(OutputData%F) + end if if (allocated(OutputData%Re)) then deallocate(OutputData%Re) end if @@ -2702,6 +2782,31 @@ subroutine BEMT_PackOutput(Buf, Indata) call RegPackBounds(Buf, 2, lbound(InData%tanInduction), ubound(InData%tanInduction)) call RegPack(Buf, InData%tanInduction) end if + call RegPack(Buf, allocated(InData%axInduction_qs)) + if (allocated(InData%axInduction_qs)) then + call RegPackBounds(Buf, 2, lbound(InData%axInduction_qs), ubound(InData%axInduction_qs)) + call RegPack(Buf, InData%axInduction_qs) + end if + call RegPack(Buf, allocated(InData%tanInduction_qs)) + if (allocated(InData%tanInduction_qs)) then + call RegPackBounds(Buf, 2, lbound(InData%tanInduction_qs), ubound(InData%tanInduction_qs)) + call RegPack(Buf, InData%tanInduction_qs) + end if + call RegPack(Buf, allocated(InData%k)) + if (allocated(InData%k)) then + call RegPackBounds(Buf, 2, lbound(InData%k), ubound(InData%k)) + call RegPack(Buf, InData%k) + end if + call RegPack(Buf, allocated(InData%k_p)) + if (allocated(InData%k_p)) then + call RegPackBounds(Buf, 2, lbound(InData%k_p), ubound(InData%k_p)) + call RegPack(Buf, InData%k_p) + end if + call RegPack(Buf, allocated(InData%F)) + if (allocated(InData%F)) then + call RegPackBounds(Buf, 2, lbound(InData%F), ubound(InData%F)) + call RegPack(Buf, InData%F) + end if call RegPack(Buf, allocated(InData%Re)) if (allocated(InData%Re)) then call RegPackBounds(Buf, 2, lbound(InData%Re), ubound(InData%Re)) @@ -2834,6 +2939,76 @@ subroutine BEMT_UnPackOutput(Buf, OutData) call RegUnpack(Buf, OutData%tanInduction) if (RegCheckErr(Buf, RoutineName)) return end if + if (allocated(OutData%axInduction_qs)) deallocate(OutData%axInduction_qs) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%axInduction_qs(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%axInduction_qs.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%axInduction_qs) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%tanInduction_qs)) deallocate(OutData%tanInduction_qs) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%tanInduction_qs(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%tanInduction_qs.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%tanInduction_qs) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%k)) deallocate(OutData%k) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%k(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%k.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%k) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%k_p)) deallocate(OutData%k_p) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%k_p(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%k_p.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%k_p) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%F)) deallocate(OutData%F) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%F(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%F.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%F) + if (RegCheckErr(Buf, RoutineName)) return + end if if (allocated(OutData%Re)) deallocate(OutData%Re) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -3122,8 +3297,8 @@ SUBROUTINE BEMT_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg END IF ! check if allocated u_out%chi0 = a1*u1%chi0 + a2*u2%chi0 u_out%psiSkewOffset = a1*u1%psiSkewOffset + a2*u2%psiSkewOffset - IF (ALLOCATED(u_out%psi) .AND. ALLOCATED(u1%psi)) THEN - u_out%psi = a1*u1%psi + a2*u2%psi + IF (ALLOCATED(u_out%psi_s) .AND. ALLOCATED(u1%psi_s)) THEN + u_out%psi_s = a1*u1%psi_s + a2*u2%psi_s END IF ! check if allocated u_out%omega = a1*u1%omega + a2*u2%omega u_out%TSR = a1*u1%TSR + a2*u2%TSR @@ -3224,8 +3399,8 @@ SUBROUTINE BEMT_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er END IF ! check if allocated u_out%chi0 = a1*u1%chi0 + a2*u2%chi0 + a3*u3%chi0 u_out%psiSkewOffset = a1*u1%psiSkewOffset + a2*u2%psiSkewOffset + a3*u3%psiSkewOffset - IF (ALLOCATED(u_out%psi) .AND. ALLOCATED(u1%psi)) THEN - u_out%psi = a1*u1%psi + a2*u2%psi + a3*u3%psi + IF (ALLOCATED(u_out%psi_s) .AND. ALLOCATED(u1%psi_s)) THEN + u_out%psi_s = a1*u1%psi_s + a2*u2%psi_s + a3*u3%psi_s END IF ! check if allocated u_out%omega = a1*u1%omega + a2*u2%omega + a3*u3%omega u_out%TSR = a1*u1%TSR + a2*u2%TSR + a3*u3%TSR @@ -3375,6 +3550,21 @@ SUBROUTINE BEMT_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMs IF (ALLOCATED(y_out%tanInduction) .AND. ALLOCATED(y1%tanInduction)) THEN y_out%tanInduction = a1*y1%tanInduction + a2*y2%tanInduction END IF ! check if allocated + IF (ALLOCATED(y_out%axInduction_qs) .AND. ALLOCATED(y1%axInduction_qs)) THEN + y_out%axInduction_qs = a1*y1%axInduction_qs + a2*y2%axInduction_qs + END IF ! check if allocated + IF (ALLOCATED(y_out%tanInduction_qs) .AND. ALLOCATED(y1%tanInduction_qs)) THEN + y_out%tanInduction_qs = a1*y1%tanInduction_qs + a2*y2%tanInduction_qs + END IF ! check if allocated + IF (ALLOCATED(y_out%k) .AND. ALLOCATED(y1%k)) THEN + y_out%k = a1*y1%k + a2*y2%k + END IF ! check if allocated + IF (ALLOCATED(y_out%k_p) .AND. ALLOCATED(y1%k_p)) THEN + y_out%k_p = a1*y1%k_p + a2*y2%k_p + END IF ! check if allocated + IF (ALLOCATED(y_out%F) .AND. ALLOCATED(y1%F)) THEN + y_out%F = a1*y1%F + a2*y2%F + END IF ! check if allocated IF (ALLOCATED(y_out%Re) .AND. ALLOCATED(y1%Re)) THEN y_out%Re = a1*y1%Re + a2*y2%Re END IF ! check if allocated @@ -3485,6 +3675,21 @@ SUBROUTINE BEMT_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, E IF (ALLOCATED(y_out%tanInduction) .AND. ALLOCATED(y1%tanInduction)) THEN y_out%tanInduction = a1*y1%tanInduction + a2*y2%tanInduction + a3*y3%tanInduction END IF ! check if allocated + IF (ALLOCATED(y_out%axInduction_qs) .AND. ALLOCATED(y1%axInduction_qs)) THEN + y_out%axInduction_qs = a1*y1%axInduction_qs + a2*y2%axInduction_qs + a3*y3%axInduction_qs + END IF ! check if allocated + IF (ALLOCATED(y_out%tanInduction_qs) .AND. ALLOCATED(y1%tanInduction_qs)) THEN + y_out%tanInduction_qs = a1*y1%tanInduction_qs + a2*y2%tanInduction_qs + a3*y3%tanInduction_qs + END IF ! check if allocated + IF (ALLOCATED(y_out%k) .AND. ALLOCATED(y1%k)) THEN + y_out%k = a1*y1%k + a2*y2%k + a3*y3%k + END IF ! check if allocated + IF (ALLOCATED(y_out%k_p) .AND. ALLOCATED(y1%k_p)) THEN + y_out%k_p = a1*y1%k_p + a2*y2%k_p + a3*y3%k_p + END IF ! check if allocated + IF (ALLOCATED(y_out%F) .AND. ALLOCATED(y1%F)) THEN + y_out%F = a1*y1%F + a2*y2%F + a3*y3%F + END IF ! check if allocated IF (ALLOCATED(y_out%Re) .AND. ALLOCATED(y1%Re)) THEN y_out%Re = a1*y1%Re + a2*y2%Re + a3*y3%Re END IF ! check if allocated diff --git a/modules/aerodyn/src/DBEMT.f90 b/modules/aerodyn/src/DBEMT.f90 index 3c12e5c3b4..a80c2c0a09 100644 --- a/modules/aerodyn/src/DBEMT.f90 +++ b/modules/aerodyn/src/DBEMT.f90 @@ -25,6 +25,7 @@ ! [2] R. Damiani, J.Jonkman ! DBEMT Theory Rev. 3 ! Unpublished +! module DBEMT use NWTC_Library @@ -328,13 +329,14 @@ end subroutine DBEMT_InitStates !!---------------------------------------------------------------------------------------------------------------------------------- !> Loose coupling routine for solving for constraint states, integrating continuous states, and updating discrete and other states. !! Continuous, constraint, discrete, and other states are updated for t + Interval -subroutine DBEMT_UpdateStates( i, j, t, n, u, p, x, OtherState, m, errStat, errMsg ) +subroutine DBEMT_UpdateStates( i, j, t, n, u, uTimes, p, x, OtherState, m, errStat, errMsg ) !.................................................................................................................................. integer(IntKi), intent(in ) :: i !< blade node counter integer(IntKi), intent(in ) :: j !< blade counter real(DbKi), intent(in ) :: t !< Current simulation time in seconds integer(IntKi), intent(in ) :: n !< Current simulation time step n = 0,1,... type(DBEMT_InputType), intent(in ) :: u(2) !< Inputs at t and t+dt + real(DbKi), intent(in ) :: uTimes(2) ! Times associated with u(:), in seconds type(DBEMT_ParameterType), intent(in ) :: p !< Parameters type(DBEMT_ContinuousStateType), intent(inout) :: x !< Input: Continuous states at t; !! Output: Continuous states at t + Interval @@ -346,7 +348,6 @@ subroutine DBEMT_UpdateStates( i, j, t, n, u, p, x, OtherState, m, errStat, errM ! local variables real(ReKi) :: A, B, C0, k_tau, C0_2 ! tau1_plus1, C_tau1, C, K1 integer(IntKi) :: indx - real(DbKi) :: utimes(2) TYPE(DBEMT_ElementInputType) :: u_elem(2) !< Inputs at utimes @@ -364,9 +365,6 @@ subroutine DBEMT_UpdateStates( i, j, t, n, u, p, x, OtherState, m, errStat, errM call DBEMT_InitStates( i, j, u(1), p, x, OtherState ) if (p%DBEMT_Mod == DBEMT_cont_tauConst) then ! continuous formulation: - utimes(1) = t - utimes(2) = t + p%dt - u_elem(1) = u(1)%element(i,j) u_elem(2) = u(2)%element(i,j) call DBEMT_ABM4( i, j, t, n, u_elem, utimes, p, x, OtherState, m, ErrStat, ErrMsg ) @@ -924,4 +922,4 @@ subroutine DBEMT_End( u, p, x, OtherState, m, ErrStat, ErrMsg ) END SUBROUTINE DBEMT_End -end module DBEMT +end module DBEMT \ No newline at end of file diff --git a/modules/aerodyn/src/FVW_Subs.f90 b/modules/aerodyn/src/FVW_Subs.f90 index 69e45094d8..bf53755c2b 100644 --- a/modules/aerodyn/src/FVW_Subs.f90 +++ b/modules/aerodyn/src/FVW_Subs.f90 @@ -480,11 +480,11 @@ logical function have_nan(p, m, x, z, u, label) have_nan=.True. endif if (any(isnan(x%W(iW)%Eps_NW))) then - print*,trim(label),'NaN in G_FW'//trim(num2lstr(iW)) + print*,trim(label),'NaN in E_NW'//trim(num2lstr(iW)) have_nan=.True. endif if (any(isnan(x%W(iW)%Eps_FW))) then - print*,trim(label),'NaN in G_FW'//trim(num2lstr(iW)) + print*,trim(label),'NaN in E_FW'//trim(num2lstr(iW)) have_nan=.True. endif if (any(isnan(z%W(iW)%Gamma_LL))) then @@ -1625,7 +1625,7 @@ subroutine FakeGroundEffect(p, x, m, ErrStat, ErrMsg) ErrStat = ErrID_None ErrMsg = "" - if ( p%MHK == 1 .or. p%MHK == 2 ) then + if ( p%MHK /= MHK_None ) then GROUND = 1.e-4_ReKi - p%WtrDpth ABOVE_GROUND = 0.1_ReKi - p%WtrDpth else diff --git a/modules/aerodyn/src/UnsteadyAero.f90 b/modules/aerodyn/src/UnsteadyAero.f90 index dce8be0f54..a0f2144368 100644 --- a/modules/aerodyn/src/UnsteadyAero.f90 +++ b/modules/aerodyn/src/UnsteadyAero.f90 @@ -42,6 +42,7 @@ module UnsteadyAero use NWTC_Library use UnsteadyAero_Types use AirfoilInfo + use NWTC_LAPACK implicit none @@ -723,8 +724,9 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) integer(IntKi) :: ErrStat2 character(*), parameter :: RoutineName = 'UA_SetParameters' logical :: IsUsed(size(AFInfo)) + INTEGER :: UA_NumLinStates ! potentially put in p, number of states per blade node that are linearized - INTEGER(IntKi) :: i, j + INTEGER(IntKi) :: i, j, k, n @@ -746,19 +748,29 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) p%ShedEffect = InitInp%ShedEffect if (p%UAMod==UA_HGM .or. p%UAMod==UA_HGMV) then - p%lin_nx = p%numBlades*p%nNodesPerBlade*4 ! 4 continuous states per node per blade (5th state isn't currently linearizable) + UA_NumLinStates = 4 + ! set the maximum number of states + ! note: we will subtract states for nodes where UA is off for good, below + p%lin_nx = p%numBlades*p%nNodesPerBlade*UA_NumLinStates ! 4 continuous states per node per blade (5th state isn't currently linearizable) else if (p%UAMod==UA_OYE) then - p%lin_nx = p%numBlades*p%nNodesPerBlade*1 ! continuous state per node per blade, but stored at position 4 + UA_NumLinStates = 1 + p%lin_nx = p%numBlades*p%nNodesPerBlade*UA_NumLinStates ! continuous state per node per blade, but stored at position 4 else p%lin_nx = 0 + UA_NumLinStates = 0 end if + ! Compute derivative step size + p%dx = 0.5_R8Ki * D2R_D + p%dx(4) = 0.0001_R8Ki + p%UA_off_forGood = .false. ! flag that determines if UA should be turned off for the whole simulation if (allocated(InitInp%UAOff_innerNode)) then do j=1,min(size(p%UA_off_forGood,2), size(InitInp%UAOff_innerNode)) !blade do i=1,min(InitInp%UAOff_innerNode(j),size(p%UA_off_forGood,1)) !node ! call WrScr( 'Warning: Turning off Unsteady Aerodynamics on inner node (node '//trim(num2lstr(i))//', blade '//trim(num2lstr(j))//')' ) p%UA_off_forGood(i,j) = .true. + p%lin_nx = p%lin_nx - UA_NumLinStates end do end do end if @@ -767,7 +779,10 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) do j=1,min(size(p%UA_off_forGood,2), size(InitInp%UAOff_outerNode)) !blade do i=InitInp%UAOff_outerNode(j), size(p%UA_off_forGood,1) !node ! call WrScr( 'Warning: Turning off Unsteady Aerodynamics on outer node (node '//trim(num2lstr(i))//', blade '//trim(num2lstr(j))//')' ) - p%UA_off_forGood(i,j) = .true. + if (.not. p%UA_off_forGood(i,j)) then + p%UA_off_forGood(i,j) = .true. + p%lin_nx = p%lin_nx - UA_NumLinStates + end if end do end do end if @@ -780,12 +795,40 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) if (ErrStat2 > ErrID_None) then call WrScr( 'Warning: Turning off Unsteady Aerodynamics because '//trim(ErrMsg2)//' (node '//trim(num2lstr(i))//', blade '//trim(num2lstr(j))//')' ) p%UA_off_forGood(i,j) = .true. + p%lin_nx = p%lin_nx - UA_NumLinStates end if end if end do end do + + ! set up index array for linearization + p%lin_nx = max(0, p%lin_nx) + call AllocAry(p%lin_xIndx,p%lin_nx,3,'p%lin_xIndx',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + if (p%lin_nx > 0) then + n = 1 + do j=1,size(p%UA_off_forGood,2) !blade + do i=1,size(p%UA_off_forGood,1) !node + if (.not. p%UA_off_forGood(i,j)) then + do k=1,UA_NumLinStates + p%lin_xIndx(n,1) = i ! node + p%lin_xIndx(n,2) = j ! blade + + if (p%UAMod==UA_OYE) then + p%lin_xIndx(n,3) = 4 ! Hack for UA_Oye, state is 4 instead of 1 for now + else + p%lin_xIndx(n,3) = k ! state + endif + n = n + 1 + end do + end if + end do + end do + end if + ! check that the airfoils have appropriate data for UA IsUsed = .false. do j=1,size(p%UA_off_forGood,2) !blade @@ -798,7 +841,7 @@ subroutine UA_SetParameters( dt, InitInp, p, AFInfo, AFIndx, ErrStat, ErrMsg ) do i=1,size(AFInfo,1) if (IsUsed(i)) then - call UA_ValidateAFI(InitInp%UAMod, AFInfo(i), ErrStat2, ErrMsg2) + call UA_ValidateAFI(p%UAMod, p%Flookup, AFInfo(i), ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end if end do @@ -971,6 +1014,8 @@ subroutine UA_ReInit( p, x, xd, OtherState, m, ErrStat, ErrMsg ) do i = 1, size(OtherState%xdot) call UA_CopyContState( x, OtherState%xdot(i), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! there are no meshes, so the control code is irrelevant call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call UA_CopyContState( x, OtherState%xHistory(i), MESH_UPDATECOPY, ErrStat2, ErrMsg2) ! there are no meshes, so the control code is irrelevant + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) end do if (p%UAMod == UA_HGMV) then @@ -1315,8 +1360,8 @@ subroutine UA_Init( InitInp, u, p, x, xd, OtherState, y, m, Interval, & InitOut%WriteOutputUnt(iOffset+41) ='(-)' InitOut%WriteOutputUnt(iOffset+42) ='(-)' InitOut%WriteOutputUnt(iOffset+43) ='(-)' - InitOut%WriteOutputUnt(iOffset+44) ='(deg)' - InitOut%WriteOutputUnt(iOffset+45) ='(-)' + InitOut%WriteOutputUnt(iOffset+44) ='(-)' + InitOut%WriteOutputUnt(iOffset+45) ='(deg)' end if @@ -1388,8 +1433,9 @@ subroutine UA_ValidateInput(InitInp, ErrStat, ErrMsg) end subroutine UA_ValidateInput !============================================================================== -subroutine UA_ValidateAFI(UAMod, AFInfo, ErrStat, ErrMsg) +subroutine UA_ValidateAFI(UAMod, FLookup, AFInfo, ErrStat, ErrMsg) integer(IntKi), intent(in ) :: UAMod ! which UA model we are using + logical, intent(in ) :: FLookup ! lookup table type(AFI_ParameterType), target, intent(in ) :: AFInfo ! The airfoil parameter data integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -1419,6 +1465,8 @@ subroutine UA_ValidateAFI(UAMod, AFInfo, ErrStat, ErrMsg) call SetErrStat(ErrID_Fatal, 'UA St_sh parameter must not be 0 in "'//trim(AFInfo%FileName)//'".', ErrStat, ErrMsg, RoutineName ) end if + ! we won't check alpha1 or alph2 validity if we aren't using them for the lookup (curve fit) + if (.not. Flookup) then if ( AFInfo%Table(j)%UA_BL%alpha1 > pi .or. AFInfo%Table(j)%UA_BL%alpha1 < -pi ) then call SetErrStat(ErrID_Fatal, 'UA alpha1 parameter must be between -180 and 180 degrees in "'//trim(AFInfo%FileName)//'".', ErrStat, ErrMsg, RoutineName ) end if @@ -1438,7 +1486,7 @@ subroutine UA_ValidateAFI(UAMod, AFInfo, ErrStat, ErrMsg) if ( AFInfo%Table(j)%UA_BL%alpha2 > AFInfo%Table(j)%UA_BL%alpha0 ) then call SetErrStat(ErrID_Fatal, 'UA alpha0 parameter must be greater than alpha2 in "'//trim(AFInfo%FileName)//'".', ErrStat, ErrMsg, RoutineName ) end if - + end if ! don't check alpha1 and alpha2 unless they are going to be used if ( AFInfo%Table(j)%UA_BL%filtCutOff < 0.0_ReKi ) then call SetErrStat(ErrID_Fatal, 'UA filtCutOff parameter must be greater than 0 in "'//trim(AFInfo%FileName)//'".', ErrStat, ErrMsg, RoutineName ) end if @@ -1634,7 +1682,6 @@ subroutine UA_UpdateDiscOtherState_BV( i, j, u, p, xd, OtherState, AFInfo, m, Er real(ReKi) :: alpha_minus1 !< 3/4 chord angle of attack at real(ReKi) :: alpha_filt_cur !< real(ReKi) :: alpha_filt_minus1 !< - real(ReKi) :: Tu !< Time constant based on u=Vrel and chord real(ReKi) :: dynamicFilterCutoffHz !< find frequency based on reduced frequency of k = BL_p%filtCutOff real(ReKi) :: LowPassConst !< ! @@ -1758,7 +1805,7 @@ subroutine BV_getAlphas(i, j, u, p, xd, BL_p, tc, alpha_34, alphaE_L, alphaLag_D alphaLag_D = alpha_34 - dalphaD*isgn ! NOTE: not effective alpha yet for drag end subroutine BV_getAlphas !============================================================================== -!> Calculate gamma for lift and drag based rel thickness. See CACTUS BV_DynStall.f95 +!> Calculate gamma for lift and drag based rel thickness. See CACTUS BV_DynStall.f95 subroutine BV_getGammas(tc, umach, gammaL, gammaD) real(ReKi), intent(in) :: tc !< Relative thickness of airfoil real(ReKi), intent(in) :: umach !< Mach number of Urel, = Urel*MinfMinf (freestrem Mach), 0 for incompressible @@ -2214,7 +2261,7 @@ subroutine UA_UpdateStates( i, j, t, n, u, uTimes, p, x, xd, OtherState, AFInfo, type(UA_InputType) :: u_interp_raw ! Input at current timestep, t and t+dt type(UA_InputType) :: u_interp ! Input at current timestep, t and t+dt type(AFI_UA_BL_Type) :: BL_p ! airfoil UA parameters retrieved in Kelvin Chain - real(ReKi) :: Tu + real(R8Ki) :: Tu ! Initialize variables @@ -2235,6 +2282,7 @@ subroutine UA_UpdateStates( i, j, t, n, u, uTimes, p, x, xd, OtherState, AFInfo, call UA_fixInputs(u_interp_raw, u_interp, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (p%UAMod == UA_HGM .or. p%UAMod == UA_HGMV) then @@ -2243,7 +2291,19 @@ subroutine UA_UpdateStates( i, j, t, n, u, uTimes, p, x, xd, OtherState, AFInfo, call HGM_Steady( i, j, u_interp, p, x%element(i,j), AFInfo, ErrStat2, ErrMsg2 ) end if + ! get inputs at t+dt + CALL UA_Input_ExtrapInterp( u, utimes, u_interp_raw, t+p%dt, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + IF ( ErrStat >= AbortErrLev ) RETURN + + ! make sure that u%u is not zero (this previously turned off UA for the entire simulation. + ! Now, we keep it on, but we don't want the math to blow up when we divide by u%u) + call UA_fixInputs(u_interp_raw, u_interp, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! update states to value at t+dt: call UA_ABM4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) + !call UA_BDF2( i, j, t, n, u_interp, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (.not. p%ShedEffect) then @@ -2421,7 +2481,7 @@ SUBROUTINE HGM_Steady( i, j, u, p, x, AFInfo, ErrStat, ErrMsg ) integer(IntKi) :: errStat2 character(*), parameter :: RoutineName = 'HGM_Steady' - real(ReKi) :: Tu + real(R8Ki) :: Tu real(ReKi) :: alphaE real(ReKi) :: alphaF real(ReKi) :: alpha_34 @@ -2486,10 +2546,12 @@ SUBROUTINE HGM_Steady( i, j, u, p, x, AFInfo, ErrStat, ErrMsg ) !call AFI_ComputeAirfoilCoefs( alphaF, u%Re, u%UserProp, AFInfo, AFI_interp, ErrStat, ErrMsg) !x%x(4) = AFI_interp%f_st else - print*,'HGM_steady, should never happen' - STOP + call WrScr('>>> HGM_steady logic error: should never happen.') + call SetErrStat(ErrID_FATAL,"Programming error.",ErrStat,ErrMsg,RoutineName) + return end if + ! calculate x%x(4) = fs_aF = f_st(alphaF): x%x(4) = AFI_interp%f_st x%x(5) = 0.0_R8Ki @@ -2521,14 +2583,14 @@ subroutine UA_CalcContStateDeriv( i, j, t, u_in, p, x, OtherState, AFInfo, m, dx integer(IntKi) :: errStat2 character(*), parameter :: RoutineName = 'UA_CalcContStateDeriv' - real(ReKi) :: Tu + real(R8Ki) :: Tu real(ReKi) :: alphaE real(ReKi) :: alphaF - real(ReKi) :: Clp + real(R8Ki) :: Clp real(ReKi) :: cRate ! slope of the piecewise linear region of fully attached polar real(R8Ki) :: x4 real(ReKi) :: alpha_34 - real(ReKi), parameter :: U_dot = 0.0_ReKi ! at some point we may add this term + real(R8Ki), parameter :: U_dot = 0.0_R8Ki ! at some point we may add this term TYPE(UA_InputType) :: u ! Inputs at t real(R8Ki) :: CnC_dot, One_Plus_Sqrt_x4, cv_dot, CnC @@ -2654,8 +2716,9 @@ subroutine UA_CalcContStateDeriv( i, j, t, u_in, p, x, OtherState, AFInfo, m, dx dxdt%x(5) = cv_dot - x%x(5)/(BL_p%T_V0 * Tu) else - print*,'>>> UA_CalcContStateDeriv, should never happen.' - STOP ! should never happen + call WrScr('>>> UA_CalcContStateDeriv logic error: should never happen.') + call SetErrStat(ErrID_FATAL,"Programming error.",ErrStat,ErrMsg,RoutineName) + return end if END SUBROUTINE UA_CalcContStateDeriv @@ -2668,14 +2731,10 @@ SUBROUTINE Get_HGM_constants(i, j, p, u, x, BL_p, Tu, alpha_34, alphaE) TYPE(UA_ElementContinuousStateType), INTENT(IN ) :: x ! Continuous states at t TYPE(AFI_UA_BL_Type), INTENT(IN ) :: BL_p ! potentially interpolated UA parameters + REAL(R8Ki), INTENT( OUT) :: Tu REAL(ReKi), optional, INTENT( OUT) :: alpha_34 - REAL(ReKi), INTENT( OUT) :: Tu REAL(ReKi), optional, INTENT( OUT) :: alphaE - ! Local variables - real(ReKi) :: vx_34 - - ! Variables derived from inputs !u%u = U_ac = TwoNorm(u%v_ac) ! page 4 definitions Tu = Get_Tu(u%u, p%c(i,j)) @@ -2795,7 +2854,7 @@ SUBROUTINE UA_RK4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, k1%x = p%dt * k1%x - x_tmp%x = x%element(i,j)%x + 0.5 * k1%x + x_tmp%x = x%element(i,j)%x + 0.5_R8Ki * k1%x ! interpolate u to find u_interp = u(t + dt/2) TPlusHalfDt = t + 0.5_DbKi*p%dt @@ -2808,7 +2867,7 @@ SUBROUTINE UA_RK4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, k2%x = p%dt * k2%x - x_tmp%x = x%element(i,j)%x + 0.5 * k2%x + x_tmp%x = x%element(i,j)%x + 0.5_R8Ki * k2%x ! find xdot at t + dt/2 (note x_tmp has changed) CALL UA_CalcContStateDeriv( i, j, TPlusHalfDt, u_interp, p, x_tmp, OtherState, AFInfo, m, k3, ErrStat2, ErrMsg2 ) @@ -2828,7 +2887,7 @@ SUBROUTINE UA_RK4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, k4%x = p%dt * k4%x - x%element(i,j)%x = x%element(i,j)%x + ( k1%x + 2. * k2%x + 2. * k3%x + k4%x ) / 6. + x%element(i,j)%x = x%element(i,j)%x + ( k1%x + 2.0_R8Ki * k2%x + 2.0_R8Ki * k3%x + k4%x ) / 6.0_R8Ki END SUBROUTINE UA_RK4 !---------------------------------------------------------------------------------------------------------------------------------- @@ -2915,9 +2974,8 @@ SUBROUTINE UA_AB4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, IF ( ErrStat >= AbortErrLev ) RETURN else - x%element(i,j)%x = x%element(i,j)%x + p%DT/24. * ( 55.*OtherState%xdot(1)%element(i,j)%x - 59.*OtherState%xdot(2)%element(i,j)%x & - + 37.*OtherState%xdot(3)%element(i,j)%x - 9.*OtherState%xdot(4)%element(i,j)%x ) - + x%element(i,j)%x = x%element(i,j)%x + p%DT/24.0_R8Ki * ( 55.0_R8Ki*OtherState%xdot(1)%element(i,j)%x - 59.0_R8Ki*OtherState%xdot(2)%element(i,j)%x & + + 37.0_R8Ki*OtherState%xdot(3)%element(i,j)%x - 9.0_R8Ki*OtherState%xdot(4)%element(i,j)%x ) endif @@ -2995,16 +3053,208 @@ SUBROUTINE UA_ABM4( i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat, IF ( ErrStat >= AbortErrLev ) RETURN - x%element(i,j)%x = x_in%x + p%DT/24. * ( 9. * xdot_pred%x + 19. * OtherState%xdot(1)%element(i,j)%x & - - 5. * OtherState%xdot(2)%element(i,j)%x & - + 1. * OtherState%xdot(3)%element(i,j)%x ) + x%element(i,j)%x = x_in%x + p%DT/24.0_R8Ki * ( 9.0_R8Ki * xdot_pred%x + 19.0_R8Ki * OtherState%xdot(1)%element(i,j)%x & + - 5.0_R8Ki * OtherState%xdot(2)%element(i,j)%x & + + 1.0_R8Ki * OtherState%xdot(3)%element(i,j)%x ) endif END SUBROUTINE UA_ABM4 !---------------------------------------------------------------------------------------------------------------------------------- !---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine implements a Newton solve of the 2nd-order BDF system for numerically integrating ordinary differential equations: +SUBROUTINE UA_BDF2( i, j, t, n, u_interp, p, x, OtherState, AFInfo, m, ErrStat, ErrMsg ) +!.................................................................................................................................. + + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(UA_InputType), INTENT(IN ) :: u_interp !< Inputs at t + dt + TYPE(UA_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(UA_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(UA_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo ! The airfoil parameter data + TYPE(UA_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + + INTEGER(IntKi) :: k + INTEGER(IntKi), parameter :: KMax = 10 + REAL(R8Ki), parameter :: TolerSquared = (1D-6)**2 + + INTEGER(IntKi) :: ErrStat2 ! local error status + CHARACTER(ErrMsgLen) :: ErrMsg2 ! local error message (ErrMsg) + CHARACTER(*), PARAMETER :: RoutineName = 'UA_BDF2' + REAL(R8Ki) :: JMat(size(x%element(i,j)%x), size(x%element(i,j)%x)) + INTEGER :: iPivot(size(JMat,1)) + REAL(R8Ki) :: x_delta(size(JMat,1)) + REAL(R8Ki) :: x_constant(size(JMat,1)) + REAL(R8Ki) :: err + TYPE(UA_ElementContinuousStateType) :: xdot_pred ! Derivative of continuous states at t + + REAL(R8Ki), parameter :: Beta = 2.0_R8Ki/3.0_R8Ki + REAL(R8Ki), parameter :: Alpha0 = 4.0_R8Ki/3.0_R8Ki + REAL(R8Ki), parameter :: Alpha1 = -1.0_R8Ki/3.0_R8Ki + + !!!! for p=0, we get backward Euler: + !!!REAL(R8Ki), parameter :: Beta = 1.0_R8Ki + !!!REAL(R8Ki), parameter :: Alpha0 = 1.0_R8Ki + !!!REAL(R8Ki), parameter :: Alpha1 = 0.0_R8Ki + + + !NOTE: the error handling here assumes that we do not have any allocatable data in the inputs (u_interp) to be concerned with. + ! Also, We assume that if there is going to be an error in UA_CalcContStateDeriv, it will happen only on the first call + ! to the routine. + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + if (OtherState%n(i,j) < n) then + + OtherState%n(i,j) = n + + OtherState%xHistory(4)%element(i,j) = OtherState%xHistory(3)%element(i,j) + OtherState%xHistory(3)%element(i,j) = OtherState%xHistory(2)%element(i,j) + OtherState%xHistory(2)%element(i,j) = OtherState%xHistory(1)%element(i,j) + if (n <= 1) then + OtherState%xHistory(2)%element(i,j) = x%element(i,j) + end if + + elseif (OtherState%n(i,j) > n) then + + CALL SetErrStat(ErrID_Fatal,'Backing up in time is not supported with a multistep method.',ErrStat,ErrMsg,RoutineName) + RETURN + + endif + + OtherState%xHistory(1)%element(i,j) = x%element(i,j) + + !!if (n<=1) then ! initialize because we don't have values for x + !! CALL UA_RK4(i, j, t, n, u, utimes, p, x, OtherState, AFInfo, m, ErrStat2, ErrMsg2 ) + !! CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + !! RETURN + !!end if + + + x_constant = Alpha0 * x%element(i,j)%x + Alpha1 * OtherState%xHistory(2)%element(i,j)%x + + err = HUGE(err) + k = 0 + DO + + IF (K >= KMax) EXIT + + IF (K==0) THEN + ! This Jacobian will change when x changes, only if the values of x1, x2, or x3 are near boundaries of slope changes in + ! the FullyAttached function of the airfoil. At that point, it should be okay if the derivative is computed + ! on a slightly different region anyway. + CALL UA_Jacobian( i, j, t, n, u_interp, p, x, OtherState, AFInfo, m, Beta, JMat, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! Get the LU decomposition of this matrix using a LAPACK routine: + ! The result is of the form JMat = P * L * U + + CALL LAPACK_getrf( M=size(JMat,1), N=size(JMat,2), A=JMat, IPIV=iPivot, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + END IF + + !------------------------------------------------------------------------------------------------- + ! Solve for delta x: JMat * x_delta = - F = - ( x(t+dt) - x(t) - dt * X(t+dt) + ! using the LAPACK routine + !------------------------------------------------------------------------------------------------- + CALL UA_CalcContStateDeriv( i, j, t, u_interp, p, x%element(i,j), OtherState, AFInfo, m, xdot_pred, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + + x_delta = - x%element(i,j)%x + x_constant + p%dt * Beta * xdot_pred%x + CALL LAPACK_getrs( TRANS="N", N=SIZE(JMat,1), A=JMat, & + IPIV=iPivot, B=x_delta, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + + !------------------------------------------------------------------------------------------------- + ! check for error, update inputs if necessary, and iterate again + !------------------------------------------------------------------------------------------------- + !err_prev = err + err = DOT_PRODUCT(x_delta, x_delta) + IF ( err <= TolerSquared) EXIT + IF (K >= KMax ) EXIT + + !!------------------------------------------------------------------------------------------------- + !! modify states for next iteration + !!------------------------------------------------------------------------------------------------- + !if (err > err_prev ) then + ! u_delta = u_delta * reduction_factor ! don't take a full step if we're getting farther from the solution! + ! err_prev = err_prev * reduction_factor + !end if + + x%element(i,j)%x = x%element(i,j)%x + x_delta + + + K = K + 1 + + END DO ! K + +END SUBROUTINE UA_BDF2 +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE UA_Jacobian( i, j, t, n, u_interp, p, x, OtherState, AFInfo, m, Beta, JMat, ErrStat, ErrMsg ) + integer(IntKi), INTENT(IN ) :: i !< blade node counter + integer(IntKi), INTENT(IN ) :: j !< blade counter + REAL(DbKi), INTENT(IN ) :: t !< Current simulation time in seconds + INTEGER(IntKi), INTENT(IN ) :: n !< time step number + TYPE(UA_InputType), INTENT(IN ) :: u_interp !< Inputs at utimes + TYPE(UA_ParameterType), INTENT(IN ) :: p !< Parameters + TYPE(UA_ContinuousStateType), INTENT(INOUT) :: x !< Continuous states at t on input at t + dt on output + TYPE(UA_OtherStateType), INTENT(INOUT) :: OtherState !< Other states + TYPE(AFI_ParameterType), INTENT(IN ) :: AFInfo ! The airfoil parameter data + TYPE(UA_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables + REAL(R8Ki), INTENT(IN ) :: Beta !< Value of Beta for p-th order BDF method + REAL(R8Ki), INTENT( OUT) :: JMat(:,:) !< Jacobian matrix + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + TYPE(UA_ElementContinuousStateType) :: x_tmp ! Holds temporary modification to x + TYPE(UA_ElementContinuousStateType) :: X_p ! Holds derivative of X + TYPE(UA_ElementContinuousStateType) :: X_m ! Holds derivative of X + + INTEGER :: k + + ! Initialize ErrStat + + ErrStat = ErrID_None + ErrMsg = "" + + + ! compute JMat = I - dt*dXdx + + call eye(JMat, ErrStat, ErrMsg) + + x_tmp%x = x%element(i,j)%x + do k=1,size(p%dx) + x_tmp%x(k) = x%element(i,j)%x(k) + p%dx(k) + CALL UA_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, AFInfo, m, X_p, ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) return + + x_tmp%x(k) = x%element(i,j)%x(k) - p%dx(k) + CALL UA_CalcContStateDeriv( i, j, t, u_interp, p, x_tmp, OtherState, AFInfo, m, X_m, ErrStat, ErrMsg ) + if (ErrStat >= AbortErrLev) return + + ! reset + x_tmp%x(k) = x%element(i,j)%x(k) + + ! compute I(:,k) - dt * dXdx(:,k) + JMat(:,k) = JMat(:,k) - p%dt*Beta*(X_p%x - X_m%x) / (2.0_R8Ki * p%dx(k)) + end do + +END SUBROUTINE UA_Jacobian +!---------------------------------------------------------------------------------------------------------------------------------- !============================================================================== @@ -3050,7 +3300,7 @@ subroutine UA_CalcOutput( i, j, t, u_in, p, x, xd, OtherState, AFInfo, y, misc, ! for UA_HGM real(ReKi) :: alphaE - real(ReKi) :: Tu + real(R8Ki) :: Tu real(ReKi) :: alpha_34 real(ReKi) :: fs_aE real(ReKi) :: cl_fs diff --git a/modules/aerodyn/src/UnsteadyAero_Registry.txt b/modules/aerodyn/src/UnsteadyAero_Registry.txt index b71aef051d..d3eb0ef03a 100644 --- a/modules/aerodyn/src/UnsteadyAero_Registry.txt +++ b/modules/aerodyn/src/UnsteadyAero_Registry.txt @@ -161,6 +161,7 @@ typedef ^ OtherStateType ReKi typedef ^ OtherStateType ReKi sigma3 {:}{:} - - "multiplier for T_V" - typedef ^ OtherStateType IntKi n {:}{:} - - "counter for continuous state integration" - typedef ^ OtherStateType UA_ContinuousStateType xdot 4 - - "history states for continuous state integration" - +typedef ^ OtherStateType UA_ContinuousStateType xHistory 4 - - "history states for continuous state integration" - typedef ^ OtherStateType ReKi t_vortexBegin {:}{:} - - "HGMV model: simulation time when vortex lift term became active" s typedef ^ OtherStateType ReKi SignOfOmega {:}{:} - - "HGMV model: sign of omega when vortex lift term became active " s typedef ^ OtherStateType LOGICAL PositivePressure {:}{:} - - "HGMV model: logical flag indicating if the vortex lift became active because of positive pressure (or negative)" - @@ -202,6 +203,8 @@ typedef ^ ^ INTEGER typedef ^ ^ Logical ShedEffect - - - "Include the effect of shed vorticity. If False, the input alpha is assumed to already contain this effect (e.g. vortex methods)" - typedef ^ ParameterType IntKi lin_nx - 0 - "Number of continuous states for linearization" - typedef ^ ^ LOGICAL UA_off_forGood {:}{:} - - "logical flag indicating if UA is off for good" - +typedef ^ ^ INTEGER lin_xIndx {:}{:} - - "array to indicate which state to perturb for UA" - +typedef ^ ^ R8Ki dx {5} - - "array to indicate size of state perturbations" - # ..... Inputs .................................................................................................................... # Define inputs that are contained on the mesh here: diff --git a/modules/aerodyn/src/UnsteadyAero_Types.f90 b/modules/aerodyn/src/UnsteadyAero_Types.f90 index fa003b201c..23a120ec97 100644 --- a/modules/aerodyn/src/UnsteadyAero_Types.f90 +++ b/modules/aerodyn/src/UnsteadyAero_Types.f90 @@ -181,6 +181,7 @@ MODULE UnsteadyAero_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: sigma3 !< multiplier for T_V [-] INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: n !< counter for continuous state integration [-] TYPE(UA_ContinuousStateType) , DIMENSION(1:4) :: xdot !< history states for continuous state integration [-] + TYPE(UA_ContinuousStateType) , DIMENSION(1:4) :: xHistory !< history states for continuous state integration [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: t_vortexBegin !< HGMV model: simulation time when vortex lift term became active [s] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: SignOfOmega !< HGMV model: sign of omega when vortex lift term became active [s] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: PositivePressure !< HGMV model: logical flag indicating if the vortex lift became active because of positive pressure (or negative) [-] @@ -221,6 +222,8 @@ MODULE UnsteadyAero_Types LOGICAL :: ShedEffect = .false. !< Include the effect of shed vorticity. If False, the input alpha is assumed to already contain this effect (e.g. vortex methods) [-] INTEGER(IntKi) :: lin_nx = 0 !< Number of continuous states for linearization [-] LOGICAL , DIMENSION(:,:), ALLOCATABLE :: UA_off_forGood !< logical flag indicating if UA is off for good [-] + INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: lin_xIndx !< array to indicate which state to perturb for UA [-] + REAL(R8Ki) , DIMENSION(1:5) :: dx = 0.0_R8Ki !< array to indicate size of state perturbations [-] END TYPE UA_ParameterType ! ======================= ! ========= UA_InputType ======= @@ -2252,6 +2255,13 @@ subroutine UA_CopyOtherState(SrcOtherStateData, DstOtherStateData, CtrlCode, Err call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end do + LB(1:1) = lbound(SrcOtherStateData%xHistory) + UB(1:1) = ubound(SrcOtherStateData%xHistory) + do i1 = LB(1), UB(1) + call UA_CopyContState(SrcOtherStateData%xHistory(i1), DstOtherStateData%xHistory(i1), CtrlCode, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) return + end do if (allocated(SrcOtherStateData%t_vortexBegin)) then LB(1:2) = lbound(SrcOtherStateData%t_vortexBegin) UB(1:2) = ubound(SrcOtherStateData%t_vortexBegin) @@ -2373,6 +2383,12 @@ subroutine UA_DestroyOtherState(OtherStateData, ErrStat, ErrMsg) call UA_DestroyContState(OtherStateData%xdot(i1), ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end do + LB(1:1) = lbound(OtherStateData%xHistory) + UB(1:1) = ubound(OtherStateData%xHistory) + do i1 = LB(1), UB(1) + call UA_DestroyContState(OtherStateData%xHistory(i1), ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end do if (allocated(OtherStateData%t_vortexBegin)) then deallocate(OtherStateData%t_vortexBegin) end if @@ -2438,6 +2454,11 @@ subroutine UA_PackOtherState(Buf, Indata) do i1 = LB(1), UB(1) call UA_PackContState(Buf, InData%xdot(i1)) end do + LB(1:1) = lbound(InData%xHistory) + UB(1:1) = ubound(InData%xHistory) + do i1 = LB(1), UB(1) + call UA_PackContState(Buf, InData%xHistory(i1)) + end do call RegPack(Buf, allocated(InData%t_vortexBegin)) if (allocated(InData%t_vortexBegin)) then call RegPackBounds(Buf, 2, lbound(InData%t_vortexBegin), ubound(InData%t_vortexBegin)) @@ -2574,6 +2595,11 @@ subroutine UA_UnPackOtherState(Buf, OutData) do i1 = LB(1), UB(1) call UA_UnpackContState(Buf, OutData%xdot(i1)) ! xdot end do + LB(1:1) = lbound(OutData%xHistory) + UB(1:1) = ubound(OutData%xHistory) + do i1 = LB(1), UB(1) + call UA_UnpackContState(Buf, OutData%xHistory(i1)) ! xHistory + end do if (allocated(OutData%t_vortexBegin)) deallocate(OutData%t_vortexBegin) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -2979,6 +3005,19 @@ subroutine UA_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) end if DstParamData%UA_off_forGood = SrcParamData%UA_off_forGood end if + if (allocated(SrcParamData%lin_xIndx)) then + LB(1:2) = lbound(SrcParamData%lin_xIndx) + UB(1:2) = ubound(SrcParamData%lin_xIndx) + if (.not. allocated(DstParamData%lin_xIndx)) then + allocate(DstParamData%lin_xIndx(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%lin_xIndx.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%lin_xIndx = SrcParamData%lin_xIndx + end if + DstParamData%dx = SrcParamData%dx end subroutine subroutine UA_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -2994,6 +3033,9 @@ subroutine UA_DestroyParam(ParamData, ErrStat, ErrMsg) if (allocated(ParamData%UA_off_forGood)) then deallocate(ParamData%UA_off_forGood) end if + if (allocated(ParamData%lin_xIndx)) then + deallocate(ParamData%lin_xIndx) + end if end subroutine subroutine UA_PackParam(Buf, Indata) @@ -3025,6 +3067,12 @@ subroutine UA_PackParam(Buf, Indata) call RegPackBounds(Buf, 2, lbound(InData%UA_off_forGood), ubound(InData%UA_off_forGood)) call RegPack(Buf, InData%UA_off_forGood) end if + call RegPack(Buf, allocated(InData%lin_xIndx)) + if (allocated(InData%lin_xIndx)) then + call RegPackBounds(Buf, 2, lbound(InData%lin_xIndx), ubound(InData%lin_xIndx)) + call RegPack(Buf, InData%lin_xIndx) + end if + call RegPack(Buf, InData%dx) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -3092,6 +3140,22 @@ subroutine UA_UnPackParam(Buf, OutData) call RegUnpack(Buf, OutData%UA_off_forGood) if (RegCheckErr(Buf, RoutineName)) return end if + if (allocated(OutData%lin_xIndx)) deallocate(OutData%lin_xIndx) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%lin_xIndx(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%lin_xIndx.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%lin_xIndx) + if (RegCheckErr(Buf, RoutineName)) return + end if + call RegUnpack(Buf, OutData%dx) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine UA_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/aerodyn14/CMakeLists.txt b/modules/aerodyn14/CMakeLists.txt index 5c67692e24..cc7cfcfdc4 100644 --- a/modules/aerodyn14/CMakeLists.txt +++ b/modules/aerodyn14/CMakeLists.txt @@ -19,7 +19,7 @@ if (GENERATE_TYPES) generate_f90_types(src/Registry-DWM.txt ${CMAKE_CURRENT_LIST_DIR}/src/DWM_Types.f90) endif() -add_library(aerodyn14lib +add_library(aerodyn14lib STATIC src/AeroDyn14.f90 src/AeroSubs.f90 src/DWM.f90 diff --git a/modules/awae/CMakeLists.txt b/modules/awae/CMakeLists.txt index ee236b36b6..448b4fa1f9 100644 --- a/modules/awae/CMakeLists.txt +++ b/modules/awae/CMakeLists.txt @@ -17,7 +17,7 @@ if (GENERATE_TYPES) generate_f90_types(src/AWAE_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/AWAE_Types.f90 -noextrap) endif() -add_library(awaelib +add_library(awaelib STATIC src/AWAE.f90 src/AWAE_IO.f90 src/AWAE_Types.f90 diff --git a/modules/awae/src/AWAE.f90 b/modules/awae/src/AWAE.f90 index 9c5634d690..602f84cc82 100644 --- a/modules/awae/src/AWAE.f90 +++ b/modules/awae/src/AWAE.f90 @@ -1462,7 +1462,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/beamdyn/CMakeLists.txt b/modules/beamdyn/CMakeLists.txt index bf44a71687..9990c4c768 100644 --- a/modules/beamdyn/CMakeLists.txt +++ b/modules/beamdyn/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/Registry_BeamDyn.txt ${CMAKE_CURRENT_LIST_DIR}/src/BeamDyn_Types.f90) endif() -add_library(beamdynlib +add_library(beamdynlib STATIC src/BeamDyn.f90 src/BeamDyn_IO.f90 src/BeamDyn_BldNdOuts_IO.f90 diff --git a/modules/beamdyn/src/BeamDyn.f90 b/modules/beamdyn/src/BeamDyn.f90 index d2354776ef..9f84c675b2 100644 --- a/modules/beamdyn/src/BeamDyn.f90 +++ b/modules/beamdyn/src/BeamDyn.f90 @@ -177,7 +177,7 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I return end if - ! Set the initial displacements: p%uu0, p%rrN0, p%E10 + ! Set the initial displacements: p%uu0, p%E10 CALL BD_QuadraturePointDataAt0(p) if (ErrStat >= AbortErrLev) then call cleanup() @@ -197,27 +197,9 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I ! Actuator - p%UsePitchAct = InputFileData%UsePitchAct if (p%UsePitchAct) then - p%pitchK = InputFileData%pitchK - p%pitchC = InputFileData%pitchC - p%pitchJ = InputFileData%pitchJ - - ! calculate (I-hA)^-1 - - p%torqM(1,1) = p%pitchJ + p%pitchC*p%dt - p%torqM(2,1) = -p%pitchK * p%dt - p%torqM(1,2) = p%pitchJ * p%dt - p%torqM(2,2) = p%pitchJ - denom = p%pitchJ + p%pitchC*p%dt + p%pitchK*p%dt**2 - if (EqualRealNos(denom,0.0_BDKi)) then - call SetErrStat(ErrID_Fatal,"Cannot invert matrix for pitch actuator: J+c*dt+k*dt^2 is zero.",ErrStat,ErrMsg,RoutineName) - else - p%torqM(:,:) = p%torqM / denom - end if - ! Calculate the pitch angle TmpDCM(:,:) = MATMUL(u%RootMotion%Orientation(:,:,1),TRANSPOSE(u%HubMotion%Orientation(:,:,1))) temp_CRV(:) = EulerExtract(TmpDCM) @@ -261,6 +243,10 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I ! allocate and initialize misc vars (do this after initializing input and output meshes): call Init_MiscVars(p, u, y, MiscVar, ErrStat2, ErrMsg2) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + if (ErrStat >= AbortErrLev) then + call cleanup() + return + end if @@ -330,7 +316,7 @@ SUBROUTINE BD_Init( InitInp, u, p, x, xd, z, OtherState, y, MiscVar, Interval, I !............................................................................................ ! Initialize Jacobian: !............................................................................................ - if (InitInp%Linearize) then + if (InitInp%Linearize .or. p%CompAeroMaps) then call Init_Jacobian( p, u, y, MiscVar, InitOut, ErrStat2, ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) end if @@ -666,8 +652,12 @@ subroutine InitializeNodalLocations(member_total,kp_member,kp_coordinate,p,GLL_n tangent = tangent / TwoNorm(tangent) + ! Calculate the node initial rotation CALL BD_ComputeIniNodalCrv(tangent, twist, temp_CRV, ErrStat, ErrMsg) + + ! Store rotation in node initial position vector and save node twist p%uuN0(4:6,i,elem) = temp_CRV + p%twN0(i,elem) = twist enddo @@ -804,11 +794,11 @@ SUBROUTINE BD_InitShpDerJaco( GLL_Nodes, p ) CALL BD_diffmtc(p%nodes_per_elem,GLL_nodes,p%QPtN,p%nqp,p%Shp,p%ShpDer) + ! Calculate the Jacobian relating element axial length to real coordinates DO nelem = 1,p%elem_total DO idx_qp = 1, p%nqp - Gup0(:) = 0.0_BDKi - DO i=1,p%nodes_per_elem - Gup0(:) = Gup0(:) + p%ShpDer(i,idx_qp)*p%uuN0(1:3,i,nelem) + DO i=1,3 + Gup0(i) = dot_product(p%ShpDer(:,idx_qp), p%uuN0(i,:,nelem)) ENDDO p%Jacobian(idx_qp,nelem) = TwoNorm(Gup0) ENDDO @@ -916,13 +906,15 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) integer(intKi) :: ErrStat2 ! temporary Error status character(ErrMsgLen) :: ErrMsg2 ! temporary Error message character(*), parameter :: RoutineName = 'SetParameters' + real(DbKi) :: denom ErrStat = ErrID_None ErrMsg = "" - + p%CompAeroMaps = InitInp%CompAeroMaps + ! Global position vector p%GlbPos = InitInp%GlbPos @@ -997,7 +989,25 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) p%dof_elem = p%dof_node * p%nodes_per_elem p%rot_elem = (p%dof_node/2) * p%nodes_per_elem + ! Actuator + p%UsePitchAct = InputFileData%UsePitchAct + if (p%UsePitchAct) then + p%pitchK = InputFileData%pitchK + p%pitchC = InputFileData%pitchC + p%pitchJ = InputFileData%pitchJ + ! calculate (I-hA)^-1 + p%torqM(1,1) = p%pitchJ + p%pitchC*p%dt + p%torqM(2,1) = -p%pitchK * p%dt + p%torqM(1,2) = p%pitchJ * p%dt + p%torqM(2,2) = p%pitchJ + denom = p%pitchJ + p%pitchC*p%dt + p%pitchK*p%dt**2 + if (EqualRealNos(denom,0.0_BDKi)) then + call SetErrStat(ErrID_Fatal,"Cannot invert matrix for pitch actuator: J+c*dt+k*dt^2 is zero.",ErrStat,ErrMsg,RoutineName) + else + p%torqM(:,:) = p%torqM / denom + end if + end if !................................ ! allocate some parameter arrays @@ -1019,7 +1029,7 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) CALL AllocAry(p%uuN0, p%dof_node,p%nodes_per_elem, p%elem_total,'uuN0 (initial position) array',ErrStat2,ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - CALL AllocAry(p%rrN0, (p%dof_node/2),p%nodes_per_elem, p%elem_total,'p%rrN0',ErrStat2,ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL AllocAry(p%twN0, p%nodes_per_elem, p%elem_total,'twN0 (initial twist) array',ErrStat2,ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL AllocAry(p%uu0, p%dof_node, p%nqp, p%elem_total,'p%uu0', ErrStat2,ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) CALL AllocAry(p%E10, (p%dof_node/2),p%nqp, p%elem_total,'p%E10', ErrStat2,ErrMsg2); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -1037,6 +1047,14 @@ subroutine SetParameters(InitInp, InputFileData, p, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return + if (p%CompAeroMaps) then + if (p%BldMotionNodeLoc /= BD_MESH_FE) then +! call SetErrStat(ErrID_Warn, "BeamDyn aero maps must have outputs at FEA nodes; this is different than time-series behavior.", ErrStat, ErrMsg, RoutineName ) + p%BldMotionNodeLoc = BD_MESH_FE + call SetErrStat(ErrID_Fatal, "BeamDyn aero maps must have outputs at FEA nodes, which requires Gaussian quadrature. Update the input file.", ErrStat, ErrMsg, RoutineName ) + return + end if + end if !............................................... ! Set start and end node index for each elements @@ -2243,72 +2261,57 @@ SUBROUTINE BD_QuadraturePointDataAt0( p ) TYPE(BD_ParameterType), INTENT(INOUT) :: p !< Parameters - REAL(BDKi) :: rot0_temp(3) - REAL(BDKi) :: rotu_temp(3) - REAL(BDKi) :: rot_temp(3) - REAL(BDKi) :: R0_temp(3,3) - + CHARACTER(*), PARAMETER :: RoutineName = 'BD_QuadraturePointDataAt0' + INTEGER(IntKi) :: ErrStat2 ! The error status code + CHARACTER(ErrMsgLen) :: ErrMsg2 ! The error message, if an error occurred INTEGER(IntKi) :: nelem ! number of current element INTEGER(IntKi) :: idx_qp ! index of current quadrature point - INTEGER(IntKi) :: idx_node ! index of current GLL node - - CHARACTER(*), PARAMETER :: RoutineName = 'BD_QuadraturePointDataAt0' - + INTEGER(IntKi) :: i + REAL(BDKi) :: twist, tan_vect(3), R0(3), u0(3) - ! Initialize to zero for the summation - p%uu0(:,:,:) = 0.0_BDKi - p%rrN0(:,:,:) = 0.0_BDKi - p%E10(:,:,:) = 0.0_BDKi - - - ! calculate rrN0 (Initial relative rotation array) + ! Loop through elements DO nelem = 1,p%elem_total - p%rrN0(1:3,1,nelem) = (/ 0.0_BDKi, 0.0_BDKi, 0.0_BDKi /) ! first node has no rotation relative to itself. - DO idx_node=2,p%nodes_per_elem - ! Find resulting rotation parameters R(Nr) = Ri^T(Nu(1)) R(Nu(:)) - ! where R(Nu(1))^T is the transpose rotation parameters for the root node - CALL BD_CrvCompose(p%rrN0(1:3,idx_node,nelem),p%uuN0(4:6,1,nelem),p%uuN0(4:6,idx_node,nelem),FLAG_R1TR2) ! rrN0 = node composed with root - ENDDO - ENDDO + ! Loop through quadrature points + do idx_qp = 1, p%nqp - DO nelem = 1,p%elem_total - DO idx_qp = 1,p%nqp - !> ### Calculate the the initial displacement fields in an element - !! Initial displacement field \n - !! \f$ \underline{u_0}\left( \xi \right) = - !! \sum_{k=1}^{p+1} h^k\left( \xi \right) \underline{\hat{u}_0}^k - !! \f$ \n - !! and curvature \n - !! \f$ \underline{c_0}\left( \xi \right) = - !! \sum_{k=1}^{p+1} h^k\left( \xi \right) \underline{\hat{c}_0}^k - !! \f$ + ! Loop through displacement DOFs + do i = 1,3 - ! Note that p%uu0 was set to zero prior to this routine call, so the following is the summation. + ! Calculate the quadrature point initial positions by using the + ! shape functions to interpolate from the node initial positions + ! Initial displacement field \n + ! \f$ \underline{u_0}\left( \xi \right) = + ! \sum_{k=1}^{p+1} h^k\left( \xi \right) \underline{\hat{u}_0}^k + ! \f$ + u0(i) = dot_product(p%Shp(:,idx_qp), p%uuN0(i,:,nelem)) - DO idx_node=1,p%nodes_per_elem - p%uu0(1:3,idx_qp,nelem) = p%uu0(1:3,idx_qp,nelem) + p%Shp(idx_node,idx_qp)*p%uuN0(1:3,idx_node,nelem) - p%uu0(4:6,idx_qp,nelem) = p%uu0(4:6,idx_qp,nelem) + p%Shp(idx_node,idx_qp)*p%rrN0(1:3,idx_node,nelem) - ENDDO + ! Calculate \f$ x_0^\prime \f$, the derivative with respect to \f$ \hat{x} \f$-direction + ! (tangent to curve through this GLL point) + ! This uses the shape function derivative to calculate the tangent at the quadrature points + ! with respect to the element axis from the node positions. + ! Note: this is a unit vector after scaling by the Jacobian + tan_vect(i) = dot_product(p%ShpDer(:,idx_qp), p%uuN0(i,:,nelem)) / p%Jacobian(idx_qp,nelem) + end do - !> Add the blade root rotation parameters. That is, - !! compose the rotation parameters calculated with the shape functions with the rotation parameters - !! for the blade root. - rot0_temp(:) = p%uuN0(4:6,1,nelem) ! Rotation at root - rotu_temp(:) = p%uu0( 4:6,idx_qp,nelem) ! Rotation at current GLL point without root rotation + ! Interpolate the twist to QP from the shape function and node values + twist = dot_product(p%Shp(:,idx_qp), p%twN0(:,nelem)) - CALL BD_CrvCompose(rot_temp,rot0_temp,rotu_temp,FLAG_R1R2) ! rot_temp = rot0_temp composed with rotu_temp - p%uu0(4:6,idx_qp,nelem) = rot_temp(:) ! Rotation parameters at current GLL point with the root orientation + ! Calculate quadrature point initial rotation, R0 + ! The nodal rotation function is used to avoid errors that occur when + ! when interpolating the QP rotations from the node rotations. + call BD_ComputeIniNodalCrv(tan_vect, twist, R0, ErrStat2, ErrMsg2) + ! Save initial position and rotation + p%uu0(1:3,idx_qp,nelem) = u0 + p%uu0(4:6,idx_qp,nelem) = R0 - !> Set the initial value of \f$ x_0^\prime \f$, the derivative with respect to \f$ \hat{x} \f$-direction - !! (tangent to curve through this GLL point). This is simply the - CALL BD_CrvMatrixR(p%uu0(4:6,idx_qp,nelem),R0_temp) ! returns R0_temp (the transpose of the DCM orientation matrix) - p%E10(:,idx_qp,nelem) = R0_temp(:,3) ! unit vector tangent to curve through this GLL point (derivative with respect to z in IEC coords). - ENDDO - ENDDO + ! Save initial tangent vector for calculating strain + p%E10(1:3,idx_qp,nelem) = tan_vect + end do + ENDDO END SUBROUTINE BD_QuadraturePointDataAt0 @@ -2357,48 +2360,43 @@ SUBROUTINE BD_DisplacementQP( nelem, p, x, m ) TYPE(BD_ContinuousStateType), INTENT(IN ) :: x !< Continuous states at t TYPE(BD_MiscVarType), INTENT(INOUT) :: m !< misc/optimization variables - INTEGER(IntKi) :: idx_qp !< index to the current quadrature point - INTEGER(IntKi) :: elem_start !< Node point of first node in current element - INTEGER(IntKi) :: idx_node + INTEGER(IntKi) :: node_start !< Node point of first node in current element + INTEGER(IntKi) :: node_end !< Node point of last node in current element + INTEGER(IntKi) :: i, idx_qp CHARACTER(*), PARAMETER :: RoutineName = 'BD_DisplacementQP' + ! Node at start and end of element + node_start = p%node_elem_idx(nelem,1) + node_end = node_start + p%nodes_per_elem - 1 + + !> ### Calculate the the displacement fields in an element + !! Using equations (27) and (28) \n + !! \f$ \underline{u}\left( \xi \right) = + !! \sum_{i=1}^{p+1} h^i\left( \xi \right) \underline{\hat{u}}^i + !! \f$ \n + !! and \n + !! \f$ \underline{u}^\prime \left( \xi \right) = + !! \sum_{k=1}^{p+1} h^{k\prime} \left( \xi \right) \underline{\hat{u}}^i + !! \f$ + !! + !! | Variable | Value | + !! | :---------: | :------------------------------------------------------------------------- | + !! | \f$ \xi \f$ | Element natural coordinate \f$ \in [-1,1] \f$ | + !! | \f$ k \f$ | Node number of a \f$ p^\text{th} \f$ order Langrangian-interpolant | + !! | \f$ h^i \left( \xi \right ) \f$ | Component of the shape function matrix, \f$ \underline{\underline{N}} \f$ | + !! | \f$ h^{k\prime} \left( \xi \right ) \f$ | \f$ \frac{\mathrm{d}}{\mathrm{d}x_1} h^i \left( \xi \right) \f$ | + !! | \f$ \underline{\hat{u}}^i \f$ | \f$ k^\text{th} \f$ nodal value + + ! Loop through all quadrature points and displacement DOFs + ! dot_product appears to be more exact that matmul + forall (idx_qp = 1:p%nqp, i = 1:3) + m%qp%uuu(i,idx_qp,nelem) = dot_product(p%Shp(:,idx_qp), x%q(i,node_start:node_end)) + m%qp%uup(i,idx_qp,nelem) = dot_product(p%ShpDer(:,idx_qp), x%q(i,node_start:node_end)) / p%Jacobian(idx_qp,nelem) + end forall + + !> Calculate \f$ \underline{E}_1 = x_0^\prime + u^\prime \f$ (equation 23). Note E_1 is along the z direction. + m%qp%E1(1:3,:,nelem) = p%E10(1:3,:,nelem) + m%qp%uup(1:3,:,nelem) - DO idx_qp=1,p%nqp - ! Node point before start of this element - elem_start = p%node_elem_idx( nelem,1 ) - - - !> ### Calculate the the displacement fields in an element - !! Using equations (27) and (28) \n - !! \f$ \underline{u}\left( \xi \right) = - !! \sum_{i=1}^{p+1} h^i\left( \xi \right) \underline{\hat{u}}^i - !! \f$ \n - !! and \n - !! \f$ \underline{u}^\prime \left( \xi \right) = - !! \sum_{k=1}^{p+1} h^{k\prime} \left( \xi \right) \underline{\hat{u}}^i - !! \f$ - !! - !! | Variable | Value | - !! | :---------: | :------------------------------------------------------------------------- | - !! | \f$ \xi \f$ | Element natural coordinate \f$ \in [-1,1] \f$ | - !! | \f$ k \f$ | Node number of a \f$ p^\text{th} \f$ order Langrangian-interpolant | - !! | \f$ h^i \left( \xi \right ) \f$ | Component of the shape function matrix, \f$ \underline{\underline{N}} \f$ | - !! | \f$ h^{k\prime} \left( \xi \right ) \f$ | \f$ \frac{\mathrm{d}}{\mathrm{d}x_1} h^i \left( \xi \right) \f$ | - !! | \f$ \underline{\hat{u}}^i \f$ | \f$ k^\text{th} \f$ nodal value | - - ! Initialize values for summation - m%qp%uuu(:,idx_qp,nelem) = 0.0_BDKi ! displacement field \f$ \underline{u} \left( \xi \right) \f$ - m%qp%uup(:,idx_qp,nelem) = 0.0_BDKi ! displacement field \f$ \underline{u}^\prime \left( \xi \right) \f$ - - DO idx_node=1,p%nodes_per_elem - m%qp%uuu(1:3,idx_qp,nelem) = m%qp%uuu(1:3,idx_qp,nelem) + p%Shp(idx_node,idx_qp) *x%q(1:3,elem_start - 1 + idx_node) - m%qp%uup(1:3,idx_qp,nelem) = m%qp%uup(1:3,idx_qp,nelem) + p%ShpDer(idx_node,idx_qp)/p%Jacobian(idx_qp,nelem)*x%q(1:3,elem_start - 1 + idx_node) - ENDDO - - !> Calculate \f$ \underline{E}_1 = x_0^\prime + u^\prime \f$ (equation 23). Note E_1 is along the z direction. - m%qp%E1(1:3,idx_qp,nelem) = p%E10(1:3,idx_qp,nelem) + m%qp%uup(1:3,idx_qp,nelem) - - ENDDO END SUBROUTINE BD_DisplacementQP @@ -2895,21 +2893,21 @@ SUBROUTINE BD_QPDataVelocity( p, x, m ) elem_start = p%node_elem_idx(nelem,1) - DO idx_qp=1,p%nqp + DO idx_qp=1,p%nqp - !> Calculate the values for the + !> Calculate the values for the - ! Initialize to zero for summation - m%qp%vvv(:,idx_qp,nelem) = 0.0_BDKi - m%qp%vvp(:,idx_qp,nelem) = 0.0_BDKi + ! Initialize to zero for summation + m%qp%vvv(:,idx_qp,nelem) = 0.0_BDKi + m%qp%vvp(:,idx_qp,nelem) = 0.0_BDKi - ! Calculate the velocity term, velocity prime (derivative of velocity with respect to X-axis), and acceleration terms - DO idx_node=1,p%nodes_per_elem - m%qp%vvv(:,idx_qp,nelem) = m%qp%vvv(:,idx_qp,nelem) + p%Shp(idx_node,idx_qp) * x%dqdt(:,elem_start-1+idx_node) - m%qp%vvp(:,idx_qp,nelem) = m%qp%vvp(:,idx_qp,nelem) + p%ShpDer(idx_node,idx_qp)/p%Jacobian(idx_qp,nelem) * x%dqdt(:,elem_start-1+idx_node) - ENDDO + ! Calculate the velocity term, velocity prime (derivative of velocity with respect to X-axis), and acceleration terms + DO idx_node=1,p%nodes_per_elem + m%qp%vvv(:,idx_qp,nelem) = m%qp%vvv(:,idx_qp,nelem) + p%Shp(idx_node,idx_qp) * x%dqdt(:,elem_start-1+idx_node) + m%qp%vvp(:,idx_qp,nelem) = m%qp%vvp(:,idx_qp,nelem) + p%ShpDer(idx_node,idx_qp)/p%Jacobian(idx_qp,nelem) * x%dqdt(:,elem_start-1+idx_node) + ENDDO - ENDDO + ENDDO ENDDO @@ -5906,59 +5904,64 @@ SUBROUTINE BD_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM end if end if + if (p%CompAeroMaps) then + dYdu = 0.0_R8Ki + else - ! make a copy of outputs because we will need two for the central difference computations (with orientations) - call BD_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call BD_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if + ! make a copy of outputs because we will need two for the central difference computations (with orientations) + call BD_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call BD_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if - do i=1,size(p%Jac_u_indx,1) + do i=1,size(p%Jac_u_indx,1) - ! get u_op + delta_p u - call BD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, 1, u_perturb, delta_p ) + ! get u_op + delta_p u + call BD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_u( p, i, 1, u_perturb, delta_p ) - ! compute y at u_op + delta_p u - call BD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_p, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! compute y at u_op + delta_p u + call BD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_p, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get u_op - delta_m u - call BD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call Perturb_u( p, i, -1, u_perturb, delta_m ) + ! get u_op - delta_m u + call BD_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call Perturb_u( p, i, -1, u_perturb, delta_m ) - ! compute y at u_op - delta_m u - call BD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_m, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! compute y at u_op - delta_m u + call BD_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_m, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get central difference: - call Compute_dY( p, y_p, y_m, delta_p, dYdu(:,i) ) + ! get central difference: + call Compute_dY( p, y_p, y_m, delta_p, dYdu(:,i) ) - end do + end do - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if - call BD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) ! we don't need this any more - call BD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + call BD_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) ! we don't need this any more + call BD_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more - if (p%RelStates) then - call BD_JacobianPContState_noRotate( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdx=m%lin_C ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if - dYdu = dYdu + matmul(m%lin_C, RelState_x) - end if + if (p%RelStates) then + call BD_JacobianPContState_noRotate( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, dYdx=m%lin_C ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + dYdu = dYdu + matmul(m%lin_C, RelState_x) + end if + + end if ! CompAeroMaps END IF @@ -6572,16 +6575,19 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, index = 1 - FieldMask = .false. - FieldMask(MASKID_TranslationDisp) = .true. - FieldMask(MASKID_Orientation) = .true. - FieldMask(MASKID_TranslationVel) = .true. - FieldMask(MASKID_RotationVel) = .true. - FieldMask(MASKID_TranslationAcc) = .true. - FieldMask(MASKID_RotationAcc) = .true. - call PackMotionMesh(u%RootMotion, u_op, index, FieldMask=FieldMask) + if (.not. p%CompAeroMaps) then + FieldMask = .false. + FieldMask(MASKID_TranslationDisp) = .true. + FieldMask(MASKID_Orientation) = .true. + FieldMask(MASKID_TranslationVel) = .true. + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TranslationAcc) = .true. + FieldMask(MASKID_RotationAcc) = .true. + call PackMotionMesh(u%RootMotion, u_op, index, FieldMask=FieldMask) - call PackLoadMesh(u%PointLoad, u_op, index) + call PackLoadMesh(u%PointLoad, u_op, index) + end if + call PackLoadMesh(u%DistrLoad, u_op, index) END IF @@ -6606,22 +6612,28 @@ SUBROUTINE BD_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, if (ReturnTrimOP) y_op = 0.0_ReKi ! initialize in case we are returning packed orientations and don't fill the entire array index = 1 - call PackLoadMesh(y%ReactionForce, y_op, index) - FieldMask = .false. FieldMask(MASKID_TranslationDisp) = .true. FieldMask(MASKID_Orientation) = .true. FieldMask(MASKID_TranslationVel) = .true. - FieldMask(MASKID_RotationVel) = .true. - FieldMask(MASKID_TranslationAcc) = .true. - FieldMask(MASKID_RotationAcc) = .true. + + if (.not. p%CompAeroMaps) then + + call PackLoadMesh(y%ReactionForce, y_op, index) + + FieldMask(MASKID_RotationVel) = .true. + FieldMask(MASKID_TranslationAcc) = .true. + FieldMask(MASKID_RotationAcc) = .true. + end if call PackMotionMesh(y%BldMotion, y_op, index, FieldMask=FieldMask, TrimOP=ReturnTrimOP) - index = index - 1 - do i=1,p%NumOuts + p%BldNd_TotNumOuts - y_op(i+index) = y%WriteOutput(i) - end do - + if (.not. p%CompAeroMaps) then + index = index - 1 + do i=1,p%NumOuts + p%BldNd_TotNumOuts + y_op(i+index) = y%WriteOutput(i) + end do + end if + END IF diff --git a/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 b/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 index 7cc98b7a03..1c420d1fc7 100644 --- a/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_BldNdOuts_IO.f90 @@ -322,7 +322,7 @@ SUBROUTINE Calc_WriteBldNdOutput( p, m, y, ErrStat, ErrMsg ) ! Set the root rotation DCM relative to the reference. ! NOTE: the orientations used in this routine are DCM's. These are directly from the mesh. - call LAPACK_DGEMM('T', 'N', 1.0_BDKi, m%u2%RootMotion%Orientation(:,:,1), m%u2%RootMotion%RefOrientation(:,:,1), 0.0_BDKi, RootRelOrient, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('T', 'N', 1.0_BDKi, m%u2%RootMotion%Orientation(:,:,1), m%u2%RootMotion%RefOrientation(:,:,1), 0.0_BDKi, RootRelOrient, ErrStat2, ErrMsg2 ) ! Loop over the channel sets @@ -406,8 +406,8 @@ SUBROUTINE Calc_WriteBldNdOutput( p, m, y, ErrStat, ErrMsg ) !------------------------- !FIXME: we are not trapping errors here. Do we need to? ! Sectional angular/rotational deflection Wiener-Milenkovic parameter (relative to the undeflected orientation) expressed in r - call LAPACK_DGEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,idx_node), RootRelOrient, 0.0_BDKi, Tmp33b, ErrStat2, ErrMsg2 ) - call LAPACK_DGEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,idx_node), Tmp33b, 0.0_BDKi, Tmp33a, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,idx_node), RootRelOrient, 0.0_BDKi, Tmp33b, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,idx_node), Tmp33b, 0.0_BDKi, Tmp33a, ErrStat2, ErrMsg2 ) call BD_CrvExtractCrv(Tmp33a,temp_vec2, ErrStat2, ErrMsg2) ! temp_vec2 = the Wiener-Milenkovic parameters of the node's angular/rotational defelctions WM_ParamRD = MATMUL(m%u2%RootMotion%Orientation(:,:,1),temp_vec2) ! Rotate the parameters to the correct coordinate system for output diff --git a/modules/beamdyn/src/BeamDyn_IO.f90 b/modules/beamdyn/src/BeamDyn_IO.f90 index af3548c49e..43c284d8f3 100644 --- a/modules/beamdyn/src/BeamDyn_IO.f90 +++ b/modules/beamdyn/src/BeamDyn_IO.f90 @@ -1006,11 +1006,13 @@ SUBROUTINE BD_ReadPrimaryFile(InputFile,InputFileData,OutFileRoot,UnEc,ErrStat,E ! OutList - List of user-requested output channels at each node(-): CALL ReadOutputList ( UnIn, InputFile, InputFileData%BldNd_OutList, InputFileData%BldNd_NumOuts, 'BldNd_OutList', "List of user-requested output channels", ErrStat2, ErrMsg2, UnEc ) ! Routine in NWTC Subroutine Library - IF ( ErrStat2 >= AbortErrLev ) THEN + IF ( ErrStat2 >= AbortErrLev .and. InputFileData%BldNd_NumOuts < 1) THEN InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoBldNdOuts) ) CALL Cleanup() RETURN + ELSE + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ENDIF !---------------------- END OF FILE ----------------------------------------- @@ -1684,7 +1686,7 @@ SUBROUTINE Calc_WriteOutput( p, AllOuts, y, m, ErrStat, ErrMsg, CalcWriteOutput ! compute the root relative orientation, RootRelOrient, which is used in several calculations below ! RootRelOrient = matmul( transpose(m%u2%RootMotion%Orientation(:,:,1)), m%u2%RootMotion%RefOrientation(:,:,1)) - call LAPACK_DGEMM('T', 'N', 1.0_BDKi, m%u2%RootMotion%Orientation(:,:,1), m%u2%RootMotion%RefOrientation(:,:,1), 0.0_BDKi, RootRelOrient, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('T', 'N', 1.0_BDKi, m%u2%RootMotion%Orientation(:,:,1), m%u2%RootMotion%RefOrientation(:,:,1), 0.0_BDKi, RootRelOrient, ErrStat2, ErrMsg2 ) !------------------------------------ ! Tip translational deflection (relative to the undeflected position) expressed in r @@ -1699,8 +1701,8 @@ SUBROUTINE Calc_WriteOutput( p, AllOuts, y, m, ErrStat, ErrMsg, CalcWriteOutput !------------------------- ! Tip angular/rotational deflection Wiener-Milenkovic parameter (relative to the undeflected orientation) expressed in r - call LAPACK_DGEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,y%BldMotion%NNodes), RootRelOrient, 0.0_BDKi, temp33_2, ErrStat2, ErrMsg2 ) - call LAPACK_DGEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,y%BldMotion%NNodes), temp33_2, 0.0_BDKi, temp33, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,y%BldMotion%NNodes), RootRelOrient, 0.0_BDKi, temp33_2, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,y%BldMotion%NNodes), temp33_2, 0.0_BDKi, temp33, ErrStat2, ErrMsg2 ) call BD_CrvExtractCrv(temp33,temp_vec2, ErrStat2, ErrMsg2) ! temp_vec2 = the Wiener-Milenkovic parameters of the tip angular/rotational defelctions CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -1785,8 +1787,8 @@ SUBROUTINE Calc_WriteOutput( p, AllOuts, y, m, ErrStat, ErrMsg, CalcWriteOutput !------------------------- ! Sectional angular/rotational deflection Wiener-Milenkovic parameter (relative to the undeflected orientation) expressed in r - call LAPACK_DGEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,j_BldMotion), RootRelOrient, 0.0_BDKi, temp33_2, ErrStat2, ErrMsg2 ) - call LAPACK_DGEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,j_BldMotion), temp33_2, 0.0_BDKi, temp33, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('N', 'T', 1.0_BDKi, y%BldMotion%RefOrientation(:,:,j_BldMotion), RootRelOrient, 0.0_BDKi, temp33_2, ErrStat2, ErrMsg2 ) + call LAPACK_GEMM('T', 'N', 1.0_BDKi, y%BldMotion%Orientation( :,:,j_BldMotion), temp33_2, 0.0_BDKi, temp33, ErrStat2, ErrMsg2 ) call BD_CrvExtractCrv(temp33,temp_vec2, ErrStat2, ErrMsg2) ! temp_vec2 = the Wiener-Milenkovic parameters of the node's angular/rotational defelctions CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return @@ -2088,10 +2090,14 @@ SUBROUTINE Init_Jacobian( p, u, y, m, InitOut, ErrStat, ErrMsg) if (ErrStat >= AbortErrLev) return ! determine how many inputs there are in the Jacobians - nu = u%RootMotion%NNodes * 18 & ! 3 Translation Displacements + 3 orientations + 6 velocities (rotation+translation) + 6 accelerations at each node - + u%PointLoad%NNodes * 6 & ! 3 forces + 3 moments at each node - + u%DistrLoad%NNodes * 6 ! 3 forces + 3 moments at each node - + if (p%CompAeroMaps) then + nu = u%DistrLoad%NNodes * 6 ! 3 forces + 3 moments at each node + else + nu = u%RootMotion%NNodes * 18 & ! 3 Translation Displacements + 3 orientations + 6 velocities (rotation+translation) + 6 accelerations at each node + + u%PointLoad%NNodes * 6 & ! 3 forces + 3 moments at each node + + u%DistrLoad%NNodes * 6 ! 3 forces + 3 moments at each node + end if + ! all other inputs (e.g., hub motion) ignored !............................ @@ -2116,29 +2122,31 @@ SUBROUTINE Init_Jacobian( p, u, y, m, InitOut, ErrStat, ErrMsg) !Module/Mesh/Field: u%RootMotion%RotationVel = 4; !Module/Mesh/Field: u%RootMotion%TranslationAcc = 5; !Module/Mesh/Field: u%RootMotion%RotationAcc = 6; - do i_meshField = 1,6 - do i=1,u%RootMotion%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField - p%Jac_u_indx(index,2) = j !component index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + if (.not. p%CompAeroMaps) then + do i_meshField = 1,6 + do i=1,u%RootMotion%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField + p%Jac_u_indx(index,2) = j !component index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do - !Module/Mesh/Field: u%PointLoad%Force = 7; - !Module/Mesh/Field: u%PointLoad%Moment = 8; - do i_meshField = 7,8 - do i=1,u%PointLoad%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField - p%Jac_u_indx(index,2) = j !component index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + !Module/Mesh/Field: u%PointLoad%Force = 7; + !Module/Mesh/Field: u%PointLoad%Moment = 8; + do i_meshField = 7,8 + do i=1,u%PointLoad%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField + p%Jac_u_indx(index,2) = j !component index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do + end if !Module/Mesh/Field: u%DistrLoad%Force = 9; !Module/Mesh/Field: u%DistrLoad%Moment = 10; @@ -2194,10 +2202,12 @@ SUBROUTINE Init_Jacobian( p, u, y, m, InitOut, ErrStat, ErrMsg) InitOut%RotFrame_u = .false. ! every input is on a mesh, which stores values in the global (not rotating) frame index = 1 - call PackMotionMesh_Names(u%RootMotion, 'RootMotion', InitOut%LinNames_u, index) ! all 6 motion fields - InitOut%IsLoad_u(1:index-1) = .false. ! the RootMotion inputs are not loads - InitOut%IsLoad_u(index:) = .true. ! the remaining inputs are loads - call PackLoadMesh_Names( u%PointLoad, 'PointLoad', InitOut%LinNames_u, index) + InitOut%IsLoad_u = .true. ! initialize all inputs as loads, and overwrite for the RootMotion mesh, below: + if (.not. p%CompAeroMaps) then + call PackMotionMesh_Names(u%RootMotion, 'RootMotion', InitOut%LinNames_u, index) ! all 6 motion fields + InitOut%IsLoad_u(1:index-1) = .false. ! the RootMotion inputs are not loads + call PackLoadMesh_Names( u%PointLoad, 'PointLoad', InitOut%LinNames_u, index) + end if call PackLoadMesh_Names( u%DistrLoad, 'DistrLoad', InitOut%LinNames_u, index) @@ -2224,16 +2234,20 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) CHARACTER(ChanLen) :: ChannelName LOGICAL :: isRotating + LOGICAL :: BladeMask(FIELDMASK_SIZE) ! flags to determine if this field is part of the packing ErrStat = ErrID_None ErrMsg = "" + if (p%CompAeroMaps) then + p%Jac_ny = y%BldMotion%NNodes * 12 ! 6 displacements (translation, rotation) + 6 velocities + else - ! determine how many outputs there are in the Jacobians - p%Jac_ny = y%ReactionForce%NNodes * 6 & ! 3 forces + 3 moments at each node - + y%BldMotion%NNodes * 18 & ! 6 displacements (translation, rotation) + 6 velocities + 6 accelerations at each node - + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values - + ! determine how many outputs there are in the Jacobians + p%Jac_ny = y%ReactionForce%NNodes * 6 & ! 3 forces + 3 moments at each node + + y%BldMotion%NNodes * 18 & ! 6 displacements (translation, rotation) + 6 velocities + 6 accelerations at each node + + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values + end if ! get the names of the linearized outputs: call AllocAry(InitOut%LinNames_y, p%Jac_ny,'LinNames_y',ErrStat2,ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -2244,50 +2258,58 @@ SUBROUTINE Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) InitOut%RotFrame_y = .false. ! need to set all the values in the global system to .false index_next = 1 - call PackLoadMesh_Names( y%ReactionForce, 'Reaction force', InitOut%LinNames_y, index_next) - call PackMotionMesh_Names(y%BldMotion, 'Blade motion', InitOut%LinNames_y, index_next) + if (p%CompAeroMaps) then + BladeMask = .true. ! default is all the fields + BladeMask(MASKID_TRANSLATIONACC) = .false. + BladeMask(MASKID_ROTATIONACC) = .false. + + call PackMotionMesh_Names(y%BldMotion, 'Blade motion', InitOut%LinNames_y, index_next, FieldMask=BladeMask) + else + call PackLoadMesh_Names( y%ReactionForce, 'Reaction force', InitOut%LinNames_y, index_next) + call PackMotionMesh_Names(y%BldMotion, 'Blade motion', InitOut%LinNames_y, index_next) - do i=1,p%NumOuts + p%BldNd_TotNumOuts - InitOut%LinNames_y(i+index_next-1) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) - end do + do i=1,p%NumOuts + p%BldNd_TotNumOuts + InitOut%LinNames_y(i+index_next-1) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) + end do - AllOut = .true. ! all output values except those specifically in the global system are in the rotating system - AllOut(TipTVXg) = .false. - AllOut(TipTVYg) = .false. - AllOut(TipTVZg) = .false. - AllOut(TipRVXg) = .false. - AllOut(TipRVYg) = .false. - AllOut(TipRVZg) = .false. + AllOut = .true. ! all output values except those specifically in the global system are in the rotating system + AllOut(TipTVXg) = .false. + AllOut(TipTVYg) = .false. + AllOut(TipTVZg) = .false. + AllOut(TipRVXg) = .false. + AllOut(TipRVYg) = .false. + AllOut(TipRVZg) = .false. - do j=1,9 - do i=1,3 !x,y,z - AllOut(NTVg(j,i)) = .false. - AllOut(NRVg(j,i)) = .false. + do j=1,9 + do i=1,3 !x,y,z + AllOut(NTVg(j,i)) = .false. + AllOut(NRVg(j,i)) = .false. + end do end do - end do - do i=1,p%NumOuts - if (p%OutParam(i)%Indx == 0 ) then - InitOut%RotFrame_y(i+index_next-1) = .false. - else - InitOut%RotFrame_y(i+index_next-1) = AllOut( p%OutParam(i)%Indx ) - end if - end do + do i=1,p%NumOuts + if (p%OutParam(i)%Indx == 0 ) then + InitOut%RotFrame_y(i+index_next-1) = .false. + else + InitOut%RotFrame_y(i+index_next-1) = AllOut( p%OutParam(i)%Indx ) + end if + end do - ! set outputs for all nodes out: - index_next = index_next + p%NumOuts - DO i=1,p%BldNd_NumOuts - ChannelName = p%BldNd_OutParam(i)%Name - call Conv2UC(ChannelName) - if ( ChannelName( LEN_TRIM(ChannelName):LEN_TRIM(ChannelName) ) == 'G') then ! channel is in global coordinate system - isRotating = .false. - else - isRotating = .true. - end if - InitOut%RotFrame_y(index_next : index_next+size(p%BldNd_BlOutNd)-1 ) = isRotating - index_next = index_next + size(p%BldNd_BlOutNd) - ENDDO + ! set outputs for all nodes out: + index_next = index_next + p%NumOuts + DO i=1,p%BldNd_NumOuts + ChannelName = p%BldNd_OutParam(i)%Name + call Conv2UC(ChannelName) + if ( ChannelName( LEN_TRIM(ChannelName):LEN_TRIM(ChannelName) ) == 'G') then ! channel is in global coordinate system + isRotating = .false. + else + isRotating = .true. + end if + InitOut%RotFrame_y(index_next : index_next+size(p%BldNd_BlOutNd)-1 ) = isRotating + index_next = index_next + size(p%BldNd_BlOutNd) + ENDDO + end if END SUBROUTINE Init_Jacobian_y @@ -2438,14 +2460,22 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta, dY) ! local variables: INTEGER(IntKi) :: i ! loop over outputs INTEGER(IntKi) :: indx_first ! index indicating next value of dY to be filled - + LOGICAL :: Mask(FIELDMASK_SIZE) ! flags to determine if this field is part of the packing + indx_first = 1 - call PackLoadMesh_dY( y_p%ReactionForce, y_m%ReactionForce, dY, indx_first) - call PackMotionMesh_dY(y_p%BldMotion, y_m%BldMotion, dY, indx_first) ! all 6 motion fields + if (p%CompAeroMaps) then + Mask = .true. + Mask(MASKID_TRANSLATIONACC) = .false. + Mask(MASKID_ROTATIONACC) = .false. + call PackMotionMesh_dY(y_p%BldMotion, y_m%BldMotion, dY, indx_first, FieldMask=Mask) ! 4 motion fields + else + call PackLoadMesh_dY( y_p%ReactionForce, y_m%ReactionForce, dY, indx_first) + call PackMotionMesh_dY(y_p%BldMotion, y_m%BldMotion, dY, indx_first) ! all 6 motion fields - do i=1,p%NumOuts + p%BldNd_TotNumOuts - dY(i+indx_first-1) = y_p%WriteOutput(i) - y_m%WriteOutput(i) - end do + do i=1,p%NumOuts + p%BldNd_TotNumOuts + dY(i+indx_first-1) = y_p%WriteOutput(i) - y_m%WriteOutput(i) + end do + end if dY = dY / (2.0_R8Ki*delta) diff --git a/modules/beamdyn/src/BeamDyn_Subs.f90 b/modules/beamdyn/src/BeamDyn_Subs.f90 index e60ab59dab..b0006dafd1 100644 --- a/modules/beamdyn/src/BeamDyn_Subs.f90 +++ b/modules/beamdyn/src/BeamDyn_Subs.f90 @@ -1067,7 +1067,7 @@ SUBROUTINE BD_ComputeIniNodalCrv(e3, phi, cc, ErrStat, ErrMsg) Rr(:,2) = Cross_Product(e3,e1) Rr(:,1) = e1(:) - identity = 0. + identity = 0.0_BDKi do i = 1,3 identity(i,i) = 1.0_BDKi enddo diff --git a/modules/beamdyn/src/BeamDyn_Types.f90 b/modules/beamdyn/src/BeamDyn_Types.f90 index 226c4a5137..bb70c195e3 100644 --- a/modules/beamdyn/src/BeamDyn_Types.f90 +++ b/modules/beamdyn/src/BeamDyn_Types.f90 @@ -53,6 +53,7 @@ MODULE BeamDyn_Types REAL(R8Ki) , DIMENSION(1:3,1:3) :: HubRot = 0.0_R8Ki !< Initial Hub direction cosine matrix [-] LOGICAL :: Linearize = .FALSE. !< Flag that tells this module if the glue code wants to linearize. [-] LOGICAL :: DynamicSolve = .TRUE. !< Use dynamic solve option. Set to False for static solving (handled by glue code or driver code). [-] + LOGICAL :: CompAeroMaps = .FALSE. !< flag to determine if BeamDyn is computing aero maps (true) or running a normal simulation (false) [-] END TYPE BD_InitInputType ! ======================= ! ========= BD_InitOutputType ======= @@ -160,7 +161,8 @@ MODULE BeamDyn_Types REAL(DbKi) :: dt = 0.0_R8Ki !< module dt [s] REAL(DbKi) , DIMENSION(1:9) :: coef = 0.0_R8Ki !< GA2 Coefficient [-] REAL(DbKi) :: rhoinf = 0.0_R8Ki !< Numerical Damping Coefficient for GA2 [-] - REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: uuN0 !< Initial Postion Vector of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element) [-] + REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: uuN0 !< Initial Position Vector of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element) [-] + REAL(R8Ki) , DIMENSION(:,:), ALLOCATABLE :: twN0 !< Initial Twist of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element) [-] REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: Stif0_QP !< Sectional Stiffness Properties at quadrature points (6x6xqp) [-] REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: Mass0_QP !< Sectional Mass Properties at quadrature points (6x6xqp) [-] REAL(R8Ki) , DIMENSION(1:3) :: gravity = 0.0_R8Ki !< Gravitational acceleration [m/s^2] @@ -181,7 +183,6 @@ MODULE BeamDyn_Types REAL(R8Ki) , DIMENSION(:,:), ALLOCATABLE :: ShpDer !< Derivative of shape function matrix (index 1 = FE nodes; index 2=quadrature points) [-] REAL(R8Ki) , DIMENSION(:,:), ALLOCATABLE :: Jacobian !< Jacobian value at each quadrature point [-] REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: uu0 !< Initial Disp/Rot value at quadrature point (at T=0) [-] - REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: rrN0 !< Initial relative rotation array, relative to root (at T=0) (index 1=rot DOF; index 2=FE nodes; index 3=element) [-] REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: E10 !< Initial E10 at quadrature point [-] INTEGER(IntKi) :: nodes_per_elem = 0_IntKi !< Finite element (GLL) nodes per element [-] INTEGER(IntKi) , DIMENSION(:,:), ALLOCATABLE :: node_elem_idx !< Index to first and last nodes of element in p%node_total sized arrays [-] @@ -237,6 +238,7 @@ MODULE BeamDyn_Types INTEGER(IntKi) :: Jac_nx = 0_IntKi !< half the number of continuous states in jacobian matrix [-] LOGICAL :: RotStates = .false. !< Orient states in rotating frame during linearization? (flag) [-] LOGICAL :: RelStates = .false. !< Define states relative to root motion during linearization? (flag) [-] + LOGICAL :: CompAeroMaps = .FALSE. !< flag to determine if BeamDyn is computing aero maps (true) or running a normal simulation (false) [-] END TYPE BD_ParameterType ! ======================= ! ========= BD_InputType ======= @@ -356,6 +358,7 @@ subroutine BD_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrSta DstInitInputData%HubRot = SrcInitInputData%HubRot DstInitInputData%Linearize = SrcInitInputData%Linearize DstInitInputData%DynamicSolve = SrcInitInputData%DynamicSolve + DstInitInputData%CompAeroMaps = SrcInitInputData%CompAeroMaps end subroutine subroutine BD_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -384,6 +387,7 @@ subroutine BD_PackInitInput(Buf, Indata) call RegPack(Buf, InData%HubRot) call RegPack(Buf, InData%Linearize) call RegPack(Buf, InData%DynamicSolve) + call RegPack(Buf, InData%CompAeroMaps) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -416,6 +420,8 @@ subroutine BD_UnPackInitInput(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%DynamicSolve) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine BD_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) @@ -1790,6 +1796,18 @@ subroutine BD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) end if DstParamData%uuN0 = SrcParamData%uuN0 end if + if (allocated(SrcParamData%twN0)) then + LB(1:2) = lbound(SrcParamData%twN0) + UB(1:2) = ubound(SrcParamData%twN0) + if (.not. allocated(DstParamData%twN0)) then + allocate(DstParamData%twN0(LB(1):UB(1),LB(2):UB(2)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%twN0.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%twN0 = SrcParamData%twN0 + end if if (allocated(SrcParamData%Stif0_QP)) then LB(1:3) = lbound(SrcParamData%Stif0_QP) UB(1:3) = ubound(SrcParamData%Stif0_QP) @@ -1920,18 +1938,6 @@ subroutine BD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) end if DstParamData%uu0 = SrcParamData%uu0 end if - if (allocated(SrcParamData%rrN0)) then - LB(1:3) = lbound(SrcParamData%rrN0) - UB(1:3) = ubound(SrcParamData%rrN0) - if (.not. allocated(DstParamData%rrN0)) then - allocate(DstParamData%rrN0(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)), stat=ErrStat2) - if (ErrStat2 /= 0) then - call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%rrN0.', ErrStat, ErrMsg, RoutineName) - return - end if - end if - DstParamData%rrN0 = SrcParamData%rrN0 - end if if (allocated(SrcParamData%E10)) then LB(1:3) = lbound(SrcParamData%E10) UB(1:3) = ubound(SrcParamData%E10) @@ -2173,6 +2179,7 @@ subroutine BD_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%Jac_nx = SrcParamData%Jac_nx DstParamData%RotStates = SrcParamData%RotStates DstParamData%RelStates = SrcParamData%RelStates + DstParamData%CompAeroMaps = SrcParamData%CompAeroMaps end subroutine subroutine BD_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -2189,6 +2196,9 @@ subroutine BD_DestroyParam(ParamData, ErrStat, ErrMsg) if (allocated(ParamData%uuN0)) then deallocate(ParamData%uuN0) end if + if (allocated(ParamData%twN0)) then + deallocate(ParamData%twN0) + end if if (allocated(ParamData%Stif0_QP)) then deallocate(ParamData%Stif0_QP) end if @@ -2219,9 +2229,6 @@ subroutine BD_DestroyParam(ParamData, ErrStat, ErrMsg) if (allocated(ParamData%uu0)) then deallocate(ParamData%uu0) end if - if (allocated(ParamData%rrN0)) then - deallocate(ParamData%rrN0) - end if if (allocated(ParamData%E10)) then deallocate(ParamData%E10) end if @@ -2301,6 +2308,11 @@ subroutine BD_PackParam(Buf, Indata) call RegPackBounds(Buf, 3, lbound(InData%uuN0), ubound(InData%uuN0)) call RegPack(Buf, InData%uuN0) end if + call RegPack(Buf, allocated(InData%twN0)) + if (allocated(InData%twN0)) then + call RegPackBounds(Buf, 2, lbound(InData%twN0), ubound(InData%twN0)) + call RegPack(Buf, InData%twN0) + end if call RegPack(Buf, allocated(InData%Stif0_QP)) if (allocated(InData%Stif0_QP)) then call RegPackBounds(Buf, 3, lbound(InData%Stif0_QP), ubound(InData%Stif0_QP)) @@ -2361,11 +2373,6 @@ subroutine BD_PackParam(Buf, Indata) call RegPackBounds(Buf, 3, lbound(InData%uu0), ubound(InData%uu0)) call RegPack(Buf, InData%uu0) end if - call RegPack(Buf, allocated(InData%rrN0)) - if (allocated(InData%rrN0)) then - call RegPackBounds(Buf, 3, lbound(InData%rrN0), ubound(InData%rrN0)) - call RegPack(Buf, InData%rrN0) - end if call RegPack(Buf, allocated(InData%E10)) if (allocated(InData%E10)) then call RegPackBounds(Buf, 3, lbound(InData%E10), ubound(InData%E10)) @@ -2493,6 +2500,7 @@ subroutine BD_PackParam(Buf, Indata) call RegPack(Buf, InData%Jac_nx) call RegPack(Buf, InData%RotStates) call RegPack(Buf, InData%RelStates) + call RegPack(Buf, InData%CompAeroMaps) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -2525,6 +2533,20 @@ subroutine BD_UnPackParam(Buf, OutData) call RegUnpack(Buf, OutData%uuN0) if (RegCheckErr(Buf, RoutineName)) return end if + if (allocated(OutData%twN0)) deallocate(OutData%twN0) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 2, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%twN0(LB(1):UB(1),LB(2):UB(2)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%twN0.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%twN0) + if (RegCheckErr(Buf, RoutineName)) return + end if if (allocated(OutData%Stif0_QP)) deallocate(OutData%Stif0_QP) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -2685,20 +2707,6 @@ subroutine BD_UnPackParam(Buf, OutData) call RegUnpack(Buf, OutData%uu0) if (RegCheckErr(Buf, RoutineName)) return end if - if (allocated(OutData%rrN0)) deallocate(OutData%rrN0) - call RegUnpack(Buf, IsAllocAssoc) - if (RegCheckErr(Buf, RoutineName)) return - if (IsAllocAssoc) then - call RegUnpackBounds(Buf, 3, LB, UB) - if (RegCheckErr(Buf, RoutineName)) return - allocate(OutData%rrN0(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)),stat=stat) - if (stat /= 0) then - call SetErrStat(ErrID_Fatal, 'Error allocating OutData%rrN0.', Buf%ErrStat, Buf%ErrMsg, RoutineName) - return - end if - call RegUnpack(Buf, OutData%rrN0) - if (RegCheckErr(Buf, RoutineName)) return - end if if (allocated(OutData%E10)) deallocate(OutData%E10) call RegUnpack(Buf, IsAllocAssoc) if (RegCheckErr(Buf, RoutineName)) return @@ -3002,6 +3010,8 @@ subroutine BD_UnPackParam(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%RelStates) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine BD_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/beamdyn/src/Driver_Beam.f90 b/modules/beamdyn/src/Driver_Beam.f90 index eed92052de..d437714c9f 100644 --- a/modules/beamdyn/src/Driver_Beam.f90 +++ b/modules/beamdyn/src/Driver_Beam.f90 @@ -102,7 +102,8 @@ PROGRAM BeamDyn_Driver_Program BD_InitInput%RootName = TRIM(RootName)//'.BD' BD_InitInput%RootDisp = MATMUL(BD_InitInput%GlbPos(:),DvrData%RootRelInit) - BD_InitInput%GlbPos(:) BD_InitInput%DynamicSolve = DvrData%DynamicSolve ! QuasiStatic options handled within the BD code. - + BD_InitInput%CompAeroMaps = .false. + t_global = DvrData%t_initial n_t_final = ((DvrData%t_final - DvrData%t_initial) / dt_global ) diff --git a/modules/beamdyn/src/Registry_BeamDyn.txt b/modules/beamdyn/src/Registry_BeamDyn.txt index 419d06517d..2c0ca19fda 100644 --- a/modules/beamdyn/src/Registry_BeamDyn.txt +++ b/modules/beamdyn/src/Registry_BeamDyn.txt @@ -34,6 +34,7 @@ typedef ^ InitInputType ReKi HubPos {3} - - "Initial typedef ^ InitInputType R8Ki HubRot {3}{3} - - "Initial Hub direction cosine matrix" typedef ^ InitInputType Logical Linearize - .FALSE. - "Flag that tells this module if the glue code wants to linearize." - typedef ^ InitInputType Logical DynamicSolve - .TRUE. - "Use dynamic solve option. Set to False for static solving (handled by glue code or driver code)." - +typedef ^ InitInputType LOGICAL CompAeroMaps - .FALSE. - "flag to determine if BeamDyn is computing aero maps (true) or running a normal simulation (false)" - # Define outputs that the initialization routine may need here: @@ -167,7 +168,8 @@ typedef ^ ParameterType DbKi coef {9} - - typedef ^ ParameterType DbKi rhoinf - - - "Numerical Damping Coefficient for GA2" #vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv #the following are BDKi = R8Ki -typedef ^ ParameterType R8Ki uuN0 {:}{:}{:} - - "Initial Postion Vector of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element)" - +typedef ^ ParameterType R8Ki uuN0 {:}{:}{:} - - "Initial Position Vector of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element)" - +typedef ^ ParameterType ^ twN0 {:}{:} - - "Initial Twist of GLL (FE) nodes (index 1=DOF; index 2=FE nodes; index 3=element)" - typedef ^ ParameterType ^ Stif0_QP {:}{:}{:} - - "Sectional Stiffness Properties at quadrature points (6x6xqp)" - typedef ^ ParameterType ^ Mass0_QP {:}{:}{:} - - "Sectional Mass Properties at quadrature points (6x6xqp)" - typedef ^ ParameterType ^ gravity {3} - - "Gravitational acceleration" m/s^2 @@ -188,7 +190,6 @@ typedef ^ ParameterType ^ Shp {:}{:} - - typedef ^ ParameterType ^ ShpDer {:}{:} - - "Derivative of shape function matrix (index 1 = FE nodes; index 2=quadrature points)" - typedef ^ ParameterType ^ Jacobian {:}{:} - - "Jacobian value at each quadrature point" - typedef ^ ParameterType ^ uu0 {:}{:}{:} - - "Initial Disp/Rot value at quadrature point (at T=0)" - -typedef ^ ParameterType ^ rrN0 {:}{:}{:} - - "Initial relative rotation array, relative to root (at T=0) (index 1=rot DOF; index 2=FE nodes; index 3=element)" - typedef ^ ParameterType ^ E10 {:}{:}{:} - - "Initial E10 at quadrature point" - #end of BDKi-type variables #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -249,6 +250,7 @@ typedef ^ ParameterType Integer Jac_ny - typedef ^ ParameterType Integer Jac_nx - - - "half the number of continuous states in jacobian matrix" - typedef ^ ParameterType logical RotStates - - - "Orient states in rotating frame during linearization? (flag)" - typedef ^ ParameterType Logical RelStates - - - "Define states relative to root motion during linearization? (flag)" - +typedef ^ ParameterType LOGICAL CompAeroMaps - .FALSE. - "flag to determine if BeamDyn is computing aero maps (true) or running a normal simulation (false)" - # ..... Inputs diff --git a/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 b/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 index fcf4f75a4f..6101e47b92 100644 --- a/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 +++ b/modules/beamdyn/tests/test_BD_QuadraturePointData.F90 @@ -27,7 +27,6 @@ module test_BD_QuadraturePointData real(BDKi), allocatable :: gll_nodes(:) real(BDKi), allocatable :: baseline_uu0(:,:,:) - real(BDKi), allocatable :: baseline_rrN0(:,:,:) real(BDKi), allocatable :: baseline_E10(:,:,:) real(BDKi), allocatable :: baseline_uuu(:,:,:) @@ -91,7 +90,6 @@ subroutine test_BD_QuadraturePointData_5node() call AllocAry(baseline_uu0 , p%dof_node, p%nqp, p%elem_total, 'baseline_uu0' , ErrStat, ErrMsg) call AllocAry(baseline_E10 , p%dof_node/2, p%nqp, p%elem_total, 'baseline_E10' , ErrStat, ErrMsg) - call AllocAry(baseline_rrN0 , p%dof_node/2, p%nodes_per_elem, p%elem_total, 'baseline_rrN0' , ErrStat, ErrMsg) call AllocAry(baseline_uuu , p%dof_node, p%nqp, p%elem_total, 'baseline_uuu' , ErrStat, ErrMsg) call AllocAry(baseline_uup , p%dof_node/2, p%nqp, p%elem_total, 'baseline_uup' , ErrStat, ErrMsg) @@ -104,6 +102,10 @@ subroutine test_BD_QuadraturePointData_5node() call AllocAry(baseline_Stif , 6, 6, p%nqp, p%elem_total, 'baseline_Stif' , ErrStat, ErrMsg) + ! Allocate memory for GLL node positions in 1D parametric space + call AllocAry(gll_nodes, nodes_per_elem, "GLL points array", ErrStat, ErrMsg) + gll_nodes = (/ -1., -0.6546536707079771, 0., 0.6546536707079771, 1. /) + ! assign baseline results ! uuN0 is of dimension (6 dof, nodes_per_elem, elem_total) @@ -123,27 +125,19 @@ subroutine test_BD_QuadraturePointData_5node() p%uuN0(1:3,5,1) = (/ -1., 1., 5. /) p%uuN0(4:6,5,1) = (/ -1.0730193445455083,-0.42803085368057275,1.292451050059679 /) - - ! the following is uuN0(4:6) with rotation of first node removed - baseline_rrN0(1:3,1,1) = (/ 0., 0., 0. /) - baseline_rrN0(1:3,2,1) = (/ -0.18695562365337798,-0.0032641497706398077,0.048935661676787534 /) - baseline_rrN0(1:3,3,1) = (/ -0.6080640291857297,-0.08595023366039768,0.4027112581652146 /) - baseline_rrN0(1:3,4,1) = (/ -1.1980591841054526,-0.3478409509012645,0.9658032687192992 /) - baseline_rrN0(1:3,5,1) = (/ -1.5856082606694464,-0.3853274394272689,1.3714709059387975 /) - ! We are just looking at one randomly selected point in the domain to test interpolation; can be expanded p%QptN(1) = 0.3 + ! Twist at nodes (nodes_per_elem, elem_total) + p%twN0(:,1) = 90.0*((gll_nodes+1)/2)**2 + ! Input baseline/reference quantities; uu0 and E10 are only for at quadrature points, so just 1 point here ! uu0 is reference line evaluated at quadrature point ! E10 is tangent evaluated at qudrature point baseline_uu0(1:3,1,1) = (/ 0.29298750000000007,-0.03250000000000007,3.2499999999999996 /) - baseline_uu0(4:6,1,1) = (/ -0.419497643454797,-0.1153574679103733,0.610107968645409 /) - baseline_E10(1:3,1,1) = (/ -0.22332806017852783,0.3449485111415417,0.9116661133321399 /) - - ! Allocate memory for GLL node positions in 1D parametric space - call AllocAry(gll_nodes, nodes_per_elem, "GLL points array", ErrStat, ErrMsg) - gll_nodes = (/ -1., -0.6546536707079771, 0., 0.6546536707079771, 1. /) + baseline_uu0(4:6,1,1) = (/ -0.42032456079463276,-0.10798264336200536,0.61929246125947701 /) + baseline_E10(1:3,1,1) = (/ -0.21838554154630824,0.34664371674017153,0.91222030721097547 /) + ! Build the shape functions and derivative of shape functions evaluated at QP points; this is tested elsewhere call BD_InitShpDerJaco(gll_nodes, p) @@ -151,9 +145,6 @@ subroutine test_BD_QuadraturePointData_5node() ! **** primary function being tested ***** call BD_QuadraturePointDataAt0( p ) - testname = "5 node, 1 element, 1 qp, curved: BD_DisplacementQPAt0: rrN0" - @assertEqual(baseline_rrN0(:,:,1), p%rrN0(:,:,1), tolerance, testname) - ! Test uu0; only one quadrature point for now testname = "5 node, 1 element, 1 qp, curved: BD_DisplacementQPAt0: uu0" do idx_qp = 1, p%nqp @@ -192,7 +183,7 @@ subroutine test_BD_QuadraturePointData_5node() baseline_uuu(1:3,idx_qp,nelem) = (/ 0.42250000000000015,-0.14787500000000003,0.4774250000000001 /) baseline_uuu(4:6,idx_qp,nelem) = (/ 0.042250000000000024,0.1300000000000001,0.02746250000000002 /) baseline_uup(1:3,idx_qp,nelem) = (/ 0.23717727987485349,-0.005929431996871376,0.2834268494504499 /) - baseline_E1(1:3, idx_qp,nelem) = (/ 0.01384921969632566, 0.33901907914467033, 1.1950929627825897 /) + baseline_E1(1:3, idx_qp,nelem) = (/ 0.018791738328546054, 0.34071428474330018, 1.1956471566614264 /) call BD_DisplacementQP( nelem, p, x, m ) @@ -214,9 +205,9 @@ subroutine test_BD_QuadraturePointData_5node() baseline_kappa(1:3,1,1) = (/ 0.024664714695954715,0.036297077098213545,0.02229356260962948 /) - baseline_RR0(1,1:3,1,nelem) = (/0.7967507798136657,-0.5939809735620473,-0.11124206898740374/) - baseline_RR0(2,1:3,1,nelem) = (/0.5966254150993577,0.7439195402109748,0.3010346022466711 /) - baseline_RR0(3,1:3,1,nelem) = (/-0.09605367730511442,-0.30621939967705303,0.9471026186942948 /) + baseline_RR0(1,1:3,1,nelem) = (/0.79124185715259476, -0.60219094249350502, -0.1063127098163618/) + baseline_RR0(2,1:3,1,nelem) = (/0.60261503127580685, 0.7383322551011402, 0.30285409879630898/) + baseline_RR0(3,1:3,1,nelem) = (/-0.10388189240754285, -0.30369647652886939, 0.94708869836662024/) CALL BD_RotationalInterpQP( nelem, p, x, m ) @@ -242,12 +233,12 @@ subroutine test_BD_QuadraturePointData_5node() enddo enddo ! the following should be the result from MATMUL(tempR6,MATMUL(p%Stif0_QP(1:6,1:6,temp_id2+idx_qp),TRANSPOSE(tempR6))) - baseline_Stif(1,1:6,idx_qp,nelem) = (/4.5918231909187375, -33.558422946165074, -19.41124878362651, 2.60126686515566, -69.25969416961556, -31.26026770547517 /) - baseline_Stif(2,1:6,idx_qp,nelem) = (/-18.923545538732206, 138.2989541247406, 79.99647091096304, -10.720184539884109, 285.4288856786646, 128.8279349796045 /) - baseline_Stif(3,1:6,idx_qp,nelem) = (/ -13.509458152867301, 98.7311774904666, 57.109222684340786, -7.65310518243836, 203.76676129761876, 91.96984745617996 /) - baseline_Stif(4,1:6,idx_qp,nelem) = (/ 2.852586665816869, -20.847560074045475, -12.058885358769254, 1.6159897420374438, -43.026325677681456, -19.419872917332995 /) - baseline_Stif(5,1:6,idx_qp,nelem) = (/-50.11731488891121, 366.27238899233606, 211.8634858589486, -28.39144827024861, 755.9328304872744, 341.18924335009 /) - baseline_Stif(6,1:6,idx_qp,nelem) = (/-23.86246662028767, 174.39407269994138, 100.87502434184734, -13.518082286573822, 359.9239499295936, 162.45117977068867 /) + baseline_Stif(1,1:6,idx_qp,nelem) = (/4.7536759583339689, -33.907248359179356, -19.542837968671446, 2.9365509821876983, -70.008981029110458, -31.39174980281188/) + baseline_Stif(2,1:6,idx_qp,nelem) = (/-19.401250769011185, 138.38617399872942, 79.760485041818299, -11.984990668437774, 285.72873055166156, 128.11963106880802/) + baseline_Stif(3,1:6,idx_qp,nelem) = (/-13.830884167369799, 98.653595365050748, 56.86015004293688, -8.5439345976052863, 203.69207236173781, 91.33471846615123/) + baseline_Stif(4,1:6,idx_qp,nelem) = (/3.141919298405611, -22.410832986789217, -12.916744914371989, 1.9408992709130821, -46.272099841270119, -20.748226294907653/) + baseline_Stif(5,1:6,idx_qp,nelem) = (/-51.422828167125537, 366.79122036858701, 211.40439684348502, -31.766102251101898, 757.32124637229549, 339.57984728541373/) + baseline_Stif(6,1:6,idx_qp,nelem) = (/-24.340652516975311, 173.61817619702015, 100.06686033300799, -15.036272493606024, 358.4729576086462, 160.73785435679258/) CALL BD_StifAtDeformedQP( nelem, p, m ) @@ -260,9 +251,6 @@ subroutine test_BD_QuadraturePointData_5node() if (allocated(gll_nodes)) deallocate(gll_nodes) if (allocated(baseline_uu0)) deallocate(baseline_uu0) if (allocated(baseline_E10)) deallocate(baseline_E10) - if (allocated(baseline_rrN0)) deallocate(baseline_rrN0) - if (allocated(baseline_rrN0)) deallocate(baseline_rrN0) - if (allocated(baseline_E10)) deallocate(baseline_E10) if (allocated(baseline_uuu)) deallocate(baseline_uuu) if (allocated(baseline_uup)) deallocate(baseline_uup) if (allocated(baseline_E1)) deallocate(baseline_E1) diff --git a/modules/beamdyn/tests/test_tools.F90 b/modules/beamdyn/tests/test_tools.F90 index a2b9fe2f19..9224dfceb9 100644 --- a/modules/beamdyn/tests/test_tools.F90 +++ b/modules/beamdyn/tests/test_tools.F90 @@ -131,10 +131,10 @@ type(BD_ParameterType) function simpleParameterType(elem_total, nodes_per_elem, call AllocAry(p%QPtw_ShpDer, p%nqp, p%nodes_per_elem, 'QPtw_ShpDer', ErrStat, ErrMsg) call AllocAry(p%Jacobian, p%nqp, p%elem_total, 'Jacobian', ErrStat, ErrMsg) call AllocAry(p%uuN0, p%dof_node, p%nodes_per_elem, p%elem_total,'uuN0', ErrStat, ErrMsg) + call AllocAry(p%twN0, p%nodes_per_elem, p%elem_total,'twN0', ErrStat, ErrMsg) call AllocAry(p%uu0, p%dof_node, p%nqp, p%elem_total,'uu0', ErrStat, ErrMsg) call AllocAry(p%E10, p%dof_node/2, p%nqp, p%elem_total,'E10', ErrStat, ErrMsg) - call AllocAry(p%rrN0, p%dof_node/2, p%nodes_per_elem, p%elem_total,'rrN0', ErrStat, ErrMsg) CALL AllocAry(p%node_elem_idx,p%elem_total,2,'start and end node numbers of elements in p%node_total sized arrays',ErrStat,ErrMsg) diff --git a/modules/elastodyn/CMakeLists.txt b/modules/elastodyn/CMakeLists.txt index ce0f1e51bc..0aebedfa67 100644 --- a/modules/elastodyn/CMakeLists.txt +++ b/modules/elastodyn/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/ElastoDyn_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/ElastoDyn_Types.f90) endif() -add_library(elastodynlib +add_library(elastodynlib STATIC src/ElastoDyn.f90 src/ElastoDyn_IO.f90 src/ElastoDyn_AllBldNdOuts_IO.f90 diff --git a/modules/elastodyn/src/ElastoDyn.f90 b/modules/elastodyn/src/ElastoDyn.f90 index 2bcfb11fc4..36d7222ce6 100644 --- a/modules/elastodyn/src/ElastoDyn.f90 +++ b/modules/elastodyn/src/ElastoDyn.f90 @@ -123,7 +123,7 @@ SUBROUTINE ED_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut p%UseAD14 = LEN_TRIM(InitInp%ADInputFile) > 0 ! if we're using AD14, we need to use the AD14 input files p%RootName = InitInp%RootName ! FAST already adds '.ED' to the root name - + p%CompAeroMaps = InitInp%CompAeroMaps p%Gravity = InitInp%Gravity CALL ED_ReadInput( InitInp%InputFile, InitInp%ADInputFile, InputFileData, p%BD4Blades, Interval, p%RootName, ErrStat2, ErrMsg2 ) @@ -148,6 +148,54 @@ SUBROUTINE ED_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut END IF + IF (p%CompAeroMaps) THEN + InputFileData%DT = Interval + p%Gravity = 0.0_ReKi + + ! DEGREES OF FREEDOM + InputFileData%TeetDOF = .false. + InputFileData%DrTrDOF = .false. + InputFileData%GenDOF = .false. + InputFileData%YawDOF = .false. + InputFileData%TwFADOF1 = .false. + InputFileData%TwFADOF2 = .false. + InputFileData%TwSSDOF1 = .false. + InputFileData%TwSSDOF2 = .false. + InputFileData%PtfmSgDOF= .false. + InputFileData%PtfmSwDOF= .false. + InputFileData%PtfmHvDOF= .false. + InputFileData%PtfmRDOF = .false. + InputFileData%PtfmPDOF = .false. + InputFileData%PtfmYDOF = .false. + + ! INITIAL CONDITIONS + InputFileData%RotSpeed = InitInp%RotSpeed + InputFileData%OoPDefl = 0.0_ReKi + InputFileData%IPDefl = 0.0_ReKi + InputFileData%BlPitch(1) = 0.0_ReKi + InputFileData%BlPitch(2) = 0.0_ReKi + InputFileData%BlPitch(3) = 0.0_ReKi + InputFileData%TeetDefl = 0.0_ReKi + InputFileData%Azimuth = 0.0_ReKi + InputFileData%NacYaw = 0.0_ReKi + InputFileData%TTDspFA = 0.0_ReKi + InputFileData%TTDspSS = 0.0_ReKi + InputFileData%PtfmSurge = 0.0_ReKi + InputFileData%PtfmSway = 0.0_ReKi + InputFileData%PtfmHeave = 0.0_ReKi + InputFileData%PtfmRoll = 0.0_ReKi + InputFileData%PtfmPitch = 0.0_ReKi + InputFileData%PtfmYaw = 0.0_ReKi + + ! TURBINE CONFIGURATION + ! CHECK THAT precone is same for all blades??? + InputFileData%ShftTilt = 0.0_ReKi + + ! CHECK THAT BldFile is same for all blades??? + + InputFileData%TeetMod = 0 + + END IF CALL ED_ValidateInput( InputFileData, p%BD4Blades, InitInp%Linearize, InitInp%MHK, ErrStat2, ErrMsg2 ) CALL CheckError( ErrStat2, ErrMsg2 ) @@ -257,6 +305,7 @@ SUBROUTINE ED_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut InitOut%HubRad = p%HubRad InitOut%RotSpeed = p%RotSpeed InitOut%isFixed_GenDOF = .not. InputFileData%GenDOF + InitOut%GearBox_index = DOF_GeAz ! for steady-state solver changing rotor speed if (.not. p%BD4Blades) then @@ -286,7 +335,7 @@ SUBROUTINE ED_Init( InitInp, u, p, x, xd, z, OtherState, y, m, Interval, InitOut ! set up data needed for linearization analysis !............................................................................................ - if (InitInp%Linearize) then + if (InitInp%Linearize .or. p%CompAeroMaps) then call ED_Init_Jacobian(p, u, y, InitOut, ErrStat2, ErrMsg2) call CheckError( ErrStat2, ErrMsg2 ) if (ErrStat >= AbortErrLev) return @@ -760,7 +809,7 @@ SUBROUTINE ED_CalcOutput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg ) m%AllOuts( TipRDxb(K) ) = DOT_PRODUCT( m%RtHS%AngPosHM(:,K,p%TipNode), m%CoordSys%j1(K, :) )*R2D m%AllOuts( TipRDyb(K) ) = DOT_PRODUCT( m%RtHS%AngPosHM(:,K,p%TipNode), m%CoordSys%j2(K, :) )*R2D ! There is no sense computing AllOuts( TipRDzc(K) ) here since it is always zero for FAST simulation results. - IF ( p%MHK == 2 ) THEN + IF ( p%MHK == MHK_Floating ) THEN IF ( rOSTipzn < 0.0 ) THEN ! Tip of blade K is above the yaw bearing. m%AllOuts(TipClrnc(K) ) = SQRT( rOSTipxn*rOSTipxn + rOSTipyn*rOSTipyn + rOSTipzn*rOSTipzn ) ! Absolute distance from the tower top / yaw bearing to the tip of blade 1. ELSE ! Tip of blade K is below the yaw bearing. @@ -3413,7 +3462,7 @@ SUBROUTINE SetPrimaryParameters( InitInp, p, InputFileData, ErrStat, ErrMsg ) p%DT = InputFileData%DT p%OverHang = InputFileData%OverHang p%ShftGagL = InputFileData%ShftGagL - IF ( InitInp%MHK == 1 ) THEN + IF ( InitInp%MHK == MHK_FixedBottom ) THEN p%TowerHt = InputFileData%TowerHt - InitInp%WtrDpth p%TowerBsHt = InputFileData%TowerBsHt - InitInp%WtrDpth p%PtfmRefzt = InputFileData%PtfmRefzt - InitInp%WtrDpth @@ -3502,7 +3551,7 @@ SUBROUTINE SetPrimaryParameters( InitInp, p, InputFileData, ErrStat, ErrMsg ) p%BldFlexL = p%TipRad - p%HubRad ! Length of the flexible portion of the blade. if (p%BD4Blades) p%BldFlexL = 0.0_ReKi - IF ( InitInp%MHK == 1 ) THEN + IF ( InitInp%MHK == MHK_FixedBottom ) THEN p%rZYzt = InputFileData%PtfmCMzt - InitInp%WtrDpth - p%PtfmRefzt ELSE p%rZYzt = InputFileData%PtfmCMzt - p%PtfmRefzt @@ -3869,7 +3918,7 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) INTEGER :: I ! Generic loop-counting index INTEGER :: J ! Generic loop-counting index INTEGER :: INDX ! Index for valid arrays - INTEGER :: startIndx ! Index for BeamDyn + INTEGER :: startIndx ! Index for using BeamDyn for Blades LOGICAL :: CheckOutListAgain ! Flag used to determine if output parameter starting with "M" is valid (or the negative of another parameter) LOGICAL :: InvalidOutput(0:MaxOutPts) ! This array determines if the output channel is valid for this configuration @@ -4490,50 +4539,20 @@ SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg ) DO I = 1,p%NumOuts p%OutParam(I)%Name = OutList(I) - OutListTmp = OutList(I) - - ! Reverse the sign (+/-) of the output channel if the user prefixed the - ! channel name with a "-", "_", "m", or "M" character indicating "minus". - - - CheckOutListAgain = .FALSE. - - IF ( INDEX( "-_", OutListTmp(1:1) ) > 0 ) THEN - p%OutParam(I)%SignM = -1 ! ex, "-TipDxc1" causes the sign of TipDxc1 to be switched. - OutListTmp = OutListTmp(2:) - ELSE IF ( INDEX( "mM", OutListTmp(1:1) ) > 0 ) THEN ! We'll assume this is a variable name for now, (if not, we will check later if OutListTmp(2:) is also a variable name) - CheckOutListAgain = .TRUE. - p%OutParam(I)%SignM = 1 - ELSE - p%OutParam(I)%SignM = 1 - END IF - - CALL Conv2UC( OutListTmp ) ! Convert OutListTmp to upper case - - - Indx = IndexCharAry( OutListTmp(1:OutStrLenM1), ValidParamAry ) - - - ! If it started with an "M" (CheckOutListAgain) we didn't find the value in our list (Indx < 1) - - IF ( CheckOutListAgain .AND. Indx < 1 ) THEN ! Let's assume that "M" really meant "minus" and then test again - p%OutParam(I)%SignM = -1 ! ex, "MTipDxc1" causes the sign of TipDxc1 to be switched. - OutListTmp = OutListTmp(2:) - - Indx = IndexCharAry( OutListTmp(1:OutStrLenM1), ValidParamAry ) - END IF + Indx = FindValidChannelIndx(OutList(I), ValidParamAry, p%OutParam(I)%SignM) IF ( Indx > 0 ) THEN ! we found the channel name - p%OutParam(I)%Indx = ParamIndxAry(Indx) IF ( InvalidOutput( ParamIndxAry(Indx) ) ) THEN ! but, it isn't valid for these settings + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) p%OutParam(I)%Units = "INVALID" p%OutParam(I)%SignM = 0 ELSE + p%OutParam(I)%Indx = ParamIndxAry(Indx) p%OutParam(I)%Units = ParamUnitsAry(Indx) ! it's a valid output END IF ELSE ! this channel isn't valid - p%OutParam(I)%Indx = Time ! pick any valid channel (I just picked "Time" here because it's universal) + p%OutParam(I)%Indx = 0 ! pick any valid channel (I just picked "Time=0" here because it's universal) p%OutParam(I)%Units = "INVALID" p%OutParam(I)%SignM = 0 ! multiply all results by zero @@ -10233,7 +10252,7 @@ SUBROUTINE ED_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM ! allocate dYdu if necessary if (.not. allocated(dYdu)) then - call AllocAry(dYdu, p%Jac_ny, size(p%Jac_u_indx,1)+1, 'dYdu', ErrStat2, ErrMsg2) + call AllocAry(dYdu, p%Jac_ny, size(p%Jac_u_indx,1)+p%NumExtendedInputs, 'dYdu', ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() @@ -10241,57 +10260,62 @@ SUBROUTINE ED_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM end if end if - ! make a copy of outputs because we will need two for the central difference computations (with orientations) - call ED_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - call ED_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if + if (p%CompAeroMaps) then + dYdu = 0.0_R8Ki + else + ! make a copy of outputs because we will need two for the central difference computations (with orientations) + call ED_CopyOutput( y, y_p, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + call ED_CopyOutput( y, y_m, MESH_NEWCOPY, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if - do i=1,size(p%Jac_u_indx,1) + do i=1,size(p%Jac_u_indx,1) - ! get u_op + delta u - call ED_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call ED_Perturb_u( p, i, 1, u_perturb, delta ) - - ! compute y at u_op + delta u - call ED_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_p, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! get u_op + delta u + call ED_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call ED_Perturb_u( p, i, 1, u_perturb, delta ) + + ! compute y at u_op + delta u + call ED_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_p, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get u_op - delta u - call ED_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - call ED_Perturb_u( p, i, -1, u_perturb, delta ) + ! get u_op - delta u + call ED_CopyInput( u, u_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + call ED_Perturb_u( p, i, -1, u_perturb, delta ) - ! compute y at u_op - delta u - call ED_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_m, m, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later + ! compute y at u_op - delta u + call ED_CalcOutput( t, u_perturb, p, x, xd, z, OtherState, y_m, m, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ! we shouldn't have any errors about allocating memory here so I'm not going to return-on-error until later - ! get central difference: - call Compute_dY( p, y_p, y_m, delta, dYdu(:,i) ) + ! get central difference: + call Compute_dY( p, y_p, y_m, delta, dYdu(:,i) ) - end do - - ! now do the extended input: sum the p%NumBl blade pitch columns - dYdu(:,size(p%Jac_u_indx,1)+1) = dYdu(:,size(p%Jac_u_indx,1)-p%NumBl-1) ! last NumBl+2 columns are: GenTrq, YawMom, and BlPitchCom - do i=2,p%NumBl - dYdu(:,size(p%Jac_u_indx,1)+1) = dYdu(:,size(p%Jac_u_indx,1)+1) + dYdu(:,size(p%Jac_u_indx,1)-p%NumBl-2+i) - end do + end do + ! now do the extended input: sum the p%NumBl blade pitch columns + if (p%NumExtendedInputs > 0) then + dYdu(:,size(p%Jac_u_indx,1)+1) = dYdu(:,size(p%Jac_u_indx,1)-p%NumBl-1) ! last NumBl+2 columns are: GenTrq, YawMom, and BlPitchCom + do i=2,p%NumBl + dYdu(:,size(p%Jac_u_indx,1)+1) = dYdu(:,size(p%Jac_u_indx,1)+1) + dYdu(:,size(p%Jac_u_indx,1)-p%NumBl-2+i) + end do + end if - if (ErrStat>=AbortErrLev) then - call cleanup() - return - end if - call ED_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) ! we don't need this any more - call ED_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more + if (ErrStat>=AbortErrLev) then + call cleanup() + return + end if + call ED_DestroyOutput( y_p, ErrStat2, ErrMsg2 ) ! we don't need this any more + call ED_DestroyOutput( y_m, ErrStat2, ErrMsg2 ) ! we don't need this any more + end if !CompAeroMaps END IF @@ -10302,7 +10326,7 @@ SUBROUTINE ED_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM ! allocate dXdu if necessary if (.not. allocated(dXdu)) then - call AllocAry(dXdu, p%DOFs%NActvDOF * 2, size(p%Jac_u_indx,1)+1, 'dXdu', ErrStat2, ErrMsg2) + call AllocAry(dXdu, p%NActvDOF_Lin + p%NActvVelDOF_Lin, size(p%Jac_u_indx,1)+p%NumExtendedInputs, 'dXdu', ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() @@ -10334,31 +10358,25 @@ SUBROUTINE ED_JacobianPInput( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrM call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get central difference: - ! we may have had an error allocating memory, so we'll check if (ErrStat>=AbortErrLev) then call cleanup() return - end if - - do j=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dXdu(j, i) = x_p%QT( p%DOFs%PS(j) ) - x_m%QT( p%DOFs%PS(j) ) - end do - do j=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dXdu(j+p%DOFs%NActvDOF, i) = x_p%QDT( p%DOFs%PS(j) ) - x_m%QDT( p%DOFs%PS(j) ) - end do - dXdu(:,i) = dXdu(:,i) / (2*delta) + end if + ! get central difference: + call Compute_dX( p, x_p, x_m, delta, dXdu(:,i) ) + end do ! now do the extended input: sum the p%NumBl blade pitch columns - dXdu(:,size(p%Jac_u_indx,1)+1) = dXdu(:,size(p%Jac_u_indx,1)-p%NumBl-1) ! last NumBl+2 columns are: GenTrq, YawMom, and BlPitchCom - do i=2,p%NumBl - dXdu(:,size(p%Jac_u_indx,1)+1) = dXdu(:,size(p%Jac_u_indx,1)+1) + dXdu(:,size(p%Jac_u_indx,1)-p%NumBl-2+i) - end do - + if (p%NumExtendedInputs > 0) then + dXdu(:,size(p%Jac_u_indx,1)+1) = dXdu(:,size(p%Jac_u_indx,1)-p%NumBl-1) ! last NumBl+2 columns are: GenTrq, YawMom, and BlPitchCom + do i=2,p%NumBl + dXdu(:,size(p%Jac_u_indx,1)+1) = dXdu(:,size(p%Jac_u_indx,1)+1) + dXdu(:,size(p%Jac_u_indx,1)-p%NumBl-2+i) + end do + end if call ED_DestroyContState( x_p, ErrStat2, ErrMsg2 ) ! we don't need this any more call ED_DestroyContState( x_m, ErrStat2, ErrMsg2 ) ! we don't need this any more @@ -10453,7 +10471,7 @@ SUBROUTINE ED_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ! allocate dYdx if necessary if (.not. allocated(dYdx)) then - call AllocAry(dYdx, p%Jac_ny, p%DOFs%NActvDOF*2, 'dYdx', ErrStat2, ErrMsg2) + call AllocAry(dYdx, p%Jac_ny, p%NActvDOF_Lin + p%NActvVelDOF_Lin, 'dYdx', ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() @@ -10472,7 +10490,7 @@ SUBROUTINE ED_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, end if - do i=1,p%DOFs%NActvDOF*2 + do i=1,p%NActvDOF_Lin + p%NActvVelDOF_Lin ! get x_op + delta x call ED_CopyContState( x, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) @@ -10514,7 +10532,7 @@ SUBROUTINE ED_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ! allocate dXdx if necessary if (.not. allocated(dXdx)) then - call AllocAry(dXdx, p%DOFs%NActvDOF * 2, p%DOFs%NActvDOF * 2, 'dXdx', ErrStat2, ErrMsg2) + call AllocAry(dXdx, p%NActvDOF_Lin + p%NActvVelDOF_Lin, p%NActvDOF_Lin + p%NActvVelDOF_Lin, 'dXdx', ErrStat2, ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) then call cleanup() @@ -10522,7 +10540,7 @@ SUBROUTINE ED_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, end if end if - do i=1,p%DOFs%NActvDOF * 2 + do i=1,p%NActvDOF_Lin + p%NActvVelDOF_Lin ! get x_op + delta x call ED_CopyContState( x, x_perturb, MESH_UPDATECOPY, ErrStat2, ErrMsg2 ) @@ -10544,22 +10562,17 @@ SUBROUTINE ED_JacobianPContState( t, u, p, x, xd, z, OtherState, y, m, ErrStat, call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! get central difference: - ! we may have had an error allocating memory, so we'll check if (ErrStat>=AbortErrLev) then call cleanup() return - end if + end if - do j=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dXdx(j, i) = x_p%QT( p%DOFs%PS(j) ) - x_m%QT( p%DOFs%PS(j) ) - end do - do j=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dXdx(j+p%DOFs%NActvDOF, i) = x_p%QDT( p%DOFs%PS(j) ) - x_m%QDT( p%DOFs%PS(j) ) - end do - dXdx(:,i) = dXdx(:,i) / (2*delta) + ! get central difference: + + call Compute_dX( p, x_p, x_m, delta, dXdx(:,i) ) + end do call ED_DestroyContState( x_p, ErrStat2, ErrMsg2 ) ! we don't need this any more @@ -10749,6 +10762,7 @@ SUBROUTINE ED_Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) CHARACTER(ErrMsgLen) :: ErrMsg2 CHARACTER(*), PARAMETER :: RoutineName = 'ED_Init_Jacobian_y' LOGICAL :: Mask(FIELDMASK_SIZE) ! flags to determine if this field is part of the packing + LOGICAL :: BladeMask(FIELDMASK_SIZE) ! flags to determine if this field is part of the packing logical, allocatable :: AllOut(:) @@ -10758,25 +10772,37 @@ SUBROUTINE ED_Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) ! determine how many outputs there are in the Jacobians - p%Jac_ny = 0 - if (allocated(y%BladeLn2Mesh)) then - do i=1,p%NumBl - p%Jac_ny = p%Jac_ny + y%BladeLn2Mesh(i)%NNodes * 18 ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node on each blade - end do - end if + p%Jac_ny = 0 + BladeMask = .true. ! default is all the fields + if (p%CompAeroMaps) then + if (allocated(y%BladeLn2Mesh)) then + do i=1,p%NumBl_Lin + p%Jac_ny = p%Jac_ny + y%BladeLn2Mesh(i)%NNodes * 12 ! 3 TranslationDisp, Orientation, TranslationVel, and RotationVel at each node on each blade (skip accelerations) + end do + end if + BladeMask(MASKID_TRANSLATIONACC) = .false. + BladeMask(MASKID_ROTATIONACC) = .false. + else - p%Jac_ny = p%Jac_ny & - + y%PlatformPtMesh%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node - + y%TowerLn2Mesh%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node - + y%HubPtMotion%NNodes * 9 & ! 3 TranslationDisp, Orientation, and RotationVel at each node - + y%NacelleMotion%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node - + 3 & ! Yaw, YawRate, and HSS_Spd - + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values + if (allocated(y%BladeLn2Mesh)) then + do i=1,p%NumBl_Lin + p%Jac_ny = p%Jac_ny + y%BladeLn2Mesh(i)%NNodes * 18 ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node on each blade + end do + end if + + p%Jac_ny = p%Jac_ny & + + y%PlatformPtMesh%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node + + y%TowerLn2Mesh%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node + + y%HubPtMotion%NNodes * 9 & ! 3 TranslationDisp, Orientation, and RotationVel at each node + + y%NacelleMotion%NNodes * 18 & ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each node + + 3 & ! Yaw, YawRate, and HSS_Spd + + p%NumOuts + p%BldNd_TotNumOuts ! WriteOutput values - do i=1,p%NumBl - p%Jac_ny = p%Jac_ny + y%BladeRootMotion(i)%NNodes * 18 ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each (1) node on each blade - end do + do i=1,p%NumBl_Lin + p%Jac_ny = p%Jac_ny + y%BladeRootMotion(i)%NNodes * 18 ! 3 TranslationDisp, Orientation, TranslationVel, RotationVel, TranslationAcc, and RotationAcc at each (1) node on each blade + end do + end if !................. ! set linearization output names: @@ -10787,101 +10813,103 @@ SUBROUTINE ED_Init_Jacobian_y( p, y, InitOut, ErrStat, ErrMsg) InitOut%RotFrame_y = .false. ! note that meshes are in the global, not rotating frame - ! note that this Mask is for the y%HubPtMotion mesh ONLY. The others pack *all* of the motion fields - Mask = .false. - Mask(MASKID_TRANSLATIONDISP) = .true. - Mask(MASKID_ORIENTATION) = .true. - Mask(MASKID_ROTATIONVEL) = .true. index_next = 1 if (allocated(y%BladeLn2Mesh)) then index_last = index_next - do i=1,p%NumBl - call PackMotionMesh_Names(y%BladeLn2Mesh(i), 'Blade '//trim(num2lstr(i)), InitOut%LinNames_y, index_next) + do i=1,p%NumBl_Lin + call PackMotionMesh_Names(y%BladeLn2Mesh(i), 'Blade '//trim(num2lstr(i)), InitOut%LinNames_y, index_next, FieldMask=BladeMask) end do - !InitOut%RotFrame_y(index_last:index_next-1) = .true. ! values on the mesh are in global, not rotating frame end if - call PackMotionMesh_Names(y%PlatformPtMesh, 'Platform', InitOut%LinNames_y, index_next) - call PackMotionMesh_Names(y%TowerLn2Mesh, 'Tower', InitOut%LinNames_y, index_next) - call PackMotionMesh_Names(y%HubPtMotion, 'Hub', InitOut%LinNames_y, index_next, FieldMask=Mask) - index_last = index_next - do i=1,p%NumBl - call PackMotionMesh_Names(y%BladeRootMotion(i), 'Blade root '//trim(num2lstr(i)), InitOut%LinNames_y, index_next) - end do - !InitOut%RotFrame_y(index_last:index_next-1) = .true. ! values on the mesh are in global, not rotating frame - - call PackMotionMesh_Names(y%NacelleMotion, 'Nacelle', InitOut%LinNames_y, index_next) - InitOut%LinNames_y(index_next) = 'Yaw, rad'; index_next = index_next+1 - InitOut%LinNames_y(index_next) = 'YawRate, rad/s'; index_next = index_next+1 - InitOut%LinNames_y(index_next) = 'HSS_Spd, rad/s' + + if (.not. p%CompAeroMaps) then + call PackMotionMesh_Names(y%PlatformPtMesh, 'Platform', InitOut%LinNames_y, index_next) + call PackMotionMesh_Names(y%TowerLn2Mesh, 'Tower', InitOut%LinNames_y, index_next) + + ! note that this Mask is for the y%HubPtMotion mesh ONLY. The others pack *all* of the motion fields + Mask = .false. + Mask(MASKID_TRANSLATIONDISP) = .true. + Mask(MASKID_ORIENTATION) = .true. + Mask(MASKID_ROTATIONVEL) = .true. + + call PackMotionMesh_Names(y%HubPtMotion, 'Hub', InitOut%LinNames_y, index_next, FieldMask=Mask) + index_last = index_next + do i=1,p%NumBl_Lin + call PackMotionMesh_Names(y%BladeRootMotion(i), 'Blade root '//trim(num2lstr(i)), InitOut%LinNames_y, index_next) + end do + + call PackMotionMesh_Names(y%NacelleMotion, 'Nacelle', InitOut%LinNames_y, index_next) + InitOut%LinNames_y(index_next) = 'Yaw, rad'; index_next = index_next+1 + InitOut%LinNames_y(index_next) = 'YawRate, rad/s'; index_next = index_next+1 + InitOut%LinNames_y(index_next) = 'HSS_Spd, rad/s' - do i=1,p%NumOuts + p%BldNd_TotNumOuts - InitOut%LinNames_y(i+index_next) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) !trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units - end do + do i=1,p%NumOuts + p%BldNd_TotNumOuts + InitOut%LinNames_y(i+index_next) = trim(InitOut%WriteOutputHdr(i))//', '//trim(InitOut%WriteOutputUnt(i)) !trim(p%OutParam(i)%Name)//', '//p%OutParam(i)%Units + end do - !! check for AllOuts in rotating frame - allocate( AllOut(0:MaxOutPts), STAT=ErrStat2 ) ! allocate starting at zero to account for invalid output channels - if (ErrStat2 /=0 ) then - call SetErrStat(ErrID_Info, 'error allocating temporary space for AllOut',ErrStat,ErrMsg,RoutineName) - return; - end if + !! check for AllOuts in rotating frame + allocate( AllOut(0:MaxOutPts), STAT=ErrStat2 ) ! allocate starting at zero to account for invalid output channels + if (ErrStat2 /=0 ) then + call SetErrStat(ErrID_Info, 'error allocating temporary space for AllOut',ErrStat,ErrMsg,RoutineName) + return; + end if - AllOut = .false. - do k=1,3 - AllOut(TipDxc( k)) = .true. - AllOut(TipDyc( k)) = .true. - AllOut(TipDzc( k)) = .true. - AllOut(TipDxb( k)) = .true. - AllOut(TipDyb( k)) = .true. - AllOut(TipALxb( k)) = .true. - AllOut(TipALyb( k)) = .true. - AllOut(TipALzb( k)) = .true. - AllOut(TipRDxb( k)) = .true. - AllOut(TipRDyb( k)) = .true. - AllOut(TipRDzc( k)) = .true. - AllOut(TipClrnc(k)) = .true. - AllOut(PtchPMzc(k)) = .true. - AllOut(RootFxc( k)) = .true. - AllOut(RootFyc( k)) = .true. - AllOut(RootFzc( k)) = .true. - AllOut(RootFxb( k)) = .true. - AllOut(RootFyb( k)) = .true. - AllOut(RootMxc( k)) = .true. - AllOut(RootMyc( k)) = .true. - AllOut(RootMzc( k)) = .true. - AllOut(RootMxb( k)) = .true. - AllOut(RootMyb( k)) = .true. - - do j=1,9 - AllOut(SpnALxb( j,k)) = .true. - AllOut(SpnALyb( j,k)) = .true. - AllOut(SpnALzb( j,k)) = .true. - AllOut(SpnFLxb( j,k)) = .true. - AllOut(SpnFLyb( j,k)) = .true. - AllOut(SpnFLzb( j,k)) = .true. - AllOut(SpnMLxb( j,k)) = .true. - AllOut(SpnMLyb( j,k)) = .true. - AllOut(SpnMLzb( j,k)) = .true. - AllOut(SpnTDxb( j,k)) = .true. - AllOut(SpnTDyb( j,k)) = .true. - AllOut(SpnTDzb( j,k)) = .true. - AllOut(SpnRDxb( j,k)) = .true. - AllOut(SpnRDyb( j,k)) = .true. - AllOut(SpnRDzb( j,k)) = .true. + AllOut = .false. + do k=1,3 + AllOut(TipDxc( k)) = .true. + AllOut(TipDyc( k)) = .true. + AllOut(TipDzc( k)) = .true. + AllOut(TipDxb( k)) = .true. + AllOut(TipDyb( k)) = .true. + AllOut(TipALxb( k)) = .true. + AllOut(TipALyb( k)) = .true. + AllOut(TipALzb( k)) = .true. + AllOut(TipRDxb( k)) = .true. + AllOut(TipRDyb( k)) = .true. + AllOut(TipRDzc( k)) = .true. + AllOut(TipClrnc(k)) = .true. + AllOut(PtchPMzc(k)) = .true. + AllOut(RootFxc( k)) = .true. + AllOut(RootFyc( k)) = .true. + AllOut(RootFzc( k)) = .true. + AllOut(RootFxb( k)) = .true. + AllOut(RootFyb( k)) = .true. + AllOut(RootMxc( k)) = .true. + AllOut(RootMyc( k)) = .true. + AllOut(RootMzc( k)) = .true. + AllOut(RootMxb( k)) = .true. + AllOut(RootMyb( k)) = .true. + + do j=1,9 + AllOut(SpnALxb( j,k)) = .true. + AllOut(SpnALyb( j,k)) = .true. + AllOut(SpnALzb( j,k)) = .true. + AllOut(SpnFLxb( j,k)) = .true. + AllOut(SpnFLyb( j,k)) = .true. + AllOut(SpnFLzb( j,k)) = .true. + AllOut(SpnMLxb( j,k)) = .true. + AllOut(SpnMLyb( j,k)) = .true. + AllOut(SpnMLzb( j,k)) = .true. + AllOut(SpnTDxb( j,k)) = .true. + AllOut(SpnTDyb( j,k)) = .true. + AllOut(SpnTDzb( j,k)) = .true. + AllOut(SpnRDxb( j,k)) = .true. + AllOut(SpnRDyb( j,k)) = .true. + AllOut(SpnRDzb( j,k)) = .true. + end do end do - end do - do i=1,p%NumOuts - InitOut%RotFrame_y(i+index_next) = AllOut( p%OutParam(i)%Indx ) - end do + do i=1,p%NumOuts + InitOut%RotFrame_y(i+index_next) = AllOut( p%OutParam(i)%Indx ) + end do - do i=1, p%BldNd_TotNumOuts - InitOut%RotFrame_y(i+p%NumOuts+index_next) = .true. - end do - - deallocate(AllOut) + do i=1, p%BldNd_TotNumOuts + InitOut%RotFrame_y(i+p%NumOuts+index_next) = .true. + end do + deallocate(AllOut) + end if !.not. p%CompAeroMaps END SUBROUTINE ED_Init_Jacobian_y !---------------------------------------------------------------------------------------------------------------------------------- @@ -10899,17 +10927,26 @@ SUBROUTINE ED_Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) CHARACTER(*), PARAMETER :: RoutineName = 'ED_Init_Jacobian_x' ! local variables: - INTEGER(IntKi) :: i + INTEGER(IntKi) :: i, indx ErrStat = ErrID_None ErrMsg = "" + if (p%CompAeroMaps) then + p%NActvDOF_Lin = p%DOFs%NActvDOF / p%NumBl ! we have only blade DOFs, and we are going to use only 1 of the blades + p%NActvDOF_Stride = p%NumBl + p%NActvVelDOF_Lin = 0 ! we do NOT have velocity states + else + p%NActvDOF_Lin = p%DOFs%NActvDOF + p%NActvDOF_Stride = 1 + p%NActvVelDOF_Lin = p%NActvDOF_Lin ! we have velocity states + end if ! allocate space for the row/column names and for perturbation sizes - call allocAry(p%dx, p%NDof, 'p%dx', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - CALL AllocAry(InitOut%LinNames_x, p%DOFs%NActvDOF*2, 'LinNames_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - CALL AllocAry(InitOut%RotFrame_x, p%DOFs%NActvDOF*2, 'RotFrame_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - CALL AllocAry(InitOut%DerivOrder_x, p%DOFs%NActvDOF*2, 'DerivOrder_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call allocAry(p%dx, p%NDof, 'p%dx', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%LinNames_x, p%NActvDOF_Lin + p%NActvVelDOF_Lin,'LinNames_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%RotFrame_x, p%NActvDOF_Lin + p%NActvVelDOF_Lin,'RotFrame_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + CALL AllocAry(InitOut%DerivOrder_x, p%NActvDOF_Lin + p%NActvVelDOF_Lin,'DerivOrder_x', ErrStat2, ErrMsg2); CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return ! All Elastodyn continuous states are max order = 2 @@ -10939,26 +10976,33 @@ SUBROUTINE ED_Init_Jacobian_x( p, InitOut, ErrStat, ErrMsg) p%dx(i) = max(p%dx(i), MinPerturb) end do - InitOut%RotFrame_x = .false. - do i=1,p%DOFs%NActvDOF - if ( p%DOFs%PS(i) >= DOF_BF(1,1) ) then - if ( p%NumBl == 2 ) then - InitOut%RotFrame_x(i) = p%DOFs%PS(i) < DOF_Teet - else - InitOut%RotFrame_x(i) = .true. ! = p%DOFs%PS(i) <= DOF_BF (MaxBl,NumBF) + if (p%CompAeroMaps) then + InitOut%RotFrame_x = .true. + else + InitOut%RotFrame_x = .false. + do i=1,p%DOFs%NActvDOF + if ( p%DOFs%PS(i) >= DOF_BF(1,1) ) then + if ( p%NumBl == 2 ) then + InitOut%RotFrame_x(i) = p%DOFs%PS(i) < DOF_Teet + else + InitOut%RotFrame_x(i) = .true. ! = p%DOFs%PS(i) <= DOF_BF (MaxBl,NumBF) + end if end if - end if - end do + end do + end if ! set linearization output names: - do i=1,p%DOFs%NActvDOF - InitOut%LinNames_x(i) = p%DOF_Desc( p%DOFs%PS(i) ) + indx = 0 + do i=1,p%DOFs%NActvDOF,p%NActvDOF_Stride + indx = indx + 1 + InitOut%LinNames_x(indx) = p%DOF_Desc( p%DOFs%PS(i) ) end do - do i=1,p%DOFs%NActvDOF - InitOut%LinNames_x(i+p%DOFs%NActvDOF) = 'First time derivative of '//trim(InitOut%LinNames_x(i))//'/s' - InitOut%RotFrame_x(i+p%DOFs%NActvDOF) = InitOut%RotFrame_x(i) - end do + + do i=1,p%NActvVelDOF_Lin + InitOut%LinNames_x(i+p%NActvDOF_Lin) = 'First time derivative of '//trim(InitOut%LinNames_x(i))//'/s' + InitOut%RotFrame_x(i+p%NActvDOF_Lin) = InitOut%RotFrame_x(i) + end do END SUBROUTINE ED_Init_Jacobian_x !---------------------------------------------------------------------------------------------------------------------------------- @@ -10983,10 +11027,15 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) REAL(R8Ki) :: ScaleLength - ErrStat = ErrID_None ErrMsg = "" - + + if (p%CompAeroMaps) then + p%NumBl_Lin = 1 + else + p%NumBl_Lin = p%NumBl + end if + call ED_Init_Jacobian_y( p, y, InitOut, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -10999,18 +11048,23 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) ! determine how many inputs there are in the Jacobians nu = 0; if (allocated(u%BladePtLoads)) then - do i=1,p%NumBl + do i=1,p%NumBl_Lin nu = nu + u%BladePtLoads(i)%NNodes * 6 ! 3 forces + 3 moments at each node on each blade end do end if - nu = nu & - + u%PlatformPtMesh%NNodes * 6 & ! 3 forces + 3 moments at each node - + u%TowerPtLoads%NNodes * 6 & ! 3 forces + 3 moments at each node - + u%HubPtLoad%NNodes * 6 & ! 3 forces + 3 moments at each node - + u%NacelleLoads%NNodes * 6 & ! 3 forces + 3 moments at each node - + p%NumBl & ! blade pitch command (BlPitchCom) - + 2 ! YawMom and GenTrq - + + if (p%CompAeroMaps) then + p%NumExtendedInputs = 0 + else + nu = nu & + + u%PlatformPtMesh%NNodes * 6 & ! 3 forces + 3 moments at each node + + u%TowerPtLoads%NNodes * 6 & ! 3 forces + 3 moments at each node + + u%HubPtLoad%NNodes * 6 & ! 3 forces + 3 moments at each node + + u%NacelleLoads%NNodes * 6 & ! 3 forces + 3 moments at each node + + p%NumBl & ! blade pitch command (BlPitchCom) + + 2 ! YawMom and GenTrq + p%NumExtendedInputs = 1 + end if ! note: all other inputs are ignored !.................... @@ -11037,7 +11091,7 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) !Module/Mesh/Field: u%BladePtLoads(2)%Moment = 4; !Module/Mesh/Field: u%BladePtLoads(3)%Force = 5; !Module/Mesh/Field: u%BladePtLoads(3)%Moment = 6; - do k=1,p%NumBl + do k=1,p%NumBl_Lin do i_meshField = 1,2 do i=1,u%BladePtLoads(k)%NNodes @@ -11054,64 +11108,66 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) end if - !if MaxBl ever changes (i.e., MaxBl /=3), we need to modify this accordingly: - do i_meshField = 7,8 - do i=1,u%PlatformPtMesh%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%PlatformPtMesh%Force = 7; u%PlatformPtMesh%Moment = 8; - p%Jac_u_indx(index,2) = j !index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + if (.not. p%CompAeroMaps) then + !if MaxBl ever changes (i.e., MaxBl /=3), we need to modify this accordingly: + do i_meshField = 7,8 + do i=1,u%PlatformPtMesh%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%PlatformPtMesh%Force = 7; u%PlatformPtMesh%Moment = 8; + p%Jac_u_indx(index,2) = j !index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do - do i_meshField = 9,10 - do i=1,u%TowerPtLoads%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%TowerPtLoads%Force = 9; u%TowerPtLoads%Moment = 10; - p%Jac_u_indx(index,2) = j !index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + do i_meshField = 9,10 + do i=1,u%TowerPtLoads%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%TowerPtLoads%Force = 9; u%TowerPtLoads%Moment = 10; + p%Jac_u_indx(index,2) = j !index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do - do i_meshField = 11,12 - do i=1,u%HubPtLoad%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%HubPtLoad%Force = 11; u%HubPtLoad%Moment = 12; - p%Jac_u_indx(index,2) = j !index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do - - do i_meshField = 13,14 - do i=1,u%NacelleLoads%NNodes - do j=1,3 - p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%NacelleLoads%Force = 13; u%NacelleLoads%Moment = 14; - p%Jac_u_indx(index,2) = j !index: j - p%Jac_u_indx(index,3) = i !Node: i - index = index + 1 - end do !j - end do !i - end do + do i_meshField = 11,12 + do i=1,u%HubPtLoad%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%HubPtLoad%Force = 11; u%HubPtLoad%Moment = 12; + p%Jac_u_indx(index,2) = j !index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do + + do i_meshField = 13,14 + do i=1,u%NacelleLoads%NNodes + do j=1,3 + p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%NacelleLoads%Force = 13; u%NacelleLoads%Moment = 14; + p%Jac_u_indx(index,2) = j !index: j + p%Jac_u_indx(index,3) = i !Node: i + index = index + 1 + end do !j + end do !i + end do - do i_meshField = 1,p%NumBl ! scalars - p%Jac_u_indx(index,1) = 15 !Module/Mesh/Field: u%BlPitchCom = 15; - p%Jac_u_indx(index,2) = 1 !index: n/a - p%Jac_u_indx(index,3) = i_meshField !Node: blade - index = index + 1 - end do + do i_meshField = 1,p%NumBl ! scalars + p%Jac_u_indx(index,1) = 15 !Module/Mesh/Field: u%BlPitchCom = 15; + p%Jac_u_indx(index,2) = 1 !index: n/a + p%Jac_u_indx(index,3) = i_meshField !Node: blade + index = index + 1 + end do - do i_meshField = 16,17 ! scalars - p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%YawMom = 16; u%GenTrq = 17; - p%Jac_u_indx(index,2) = 1 !index: j - p%Jac_u_indx(index,3) = 1 !Node: i - index = index + 1 - end do + do i_meshField = 16,17 ! scalars + p%Jac_u_indx(index,1) = i_meshField !Module/Mesh/Field: u%YawMom = 16; u%GenTrq = 17; + p%Jac_u_indx(index,2) = 1 !index: j + p%Jac_u_indx(index,3) = 1 !Node: i + index = index + 1 + end do + end if ! .not. p%CompAeroMaps !................ ! input perturbations, du: @@ -11154,9 +11210,9 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) !................ ! names of the columns, InitOut%LinNames_u: !................ - call AllocAry(InitOut%LinNames_u, nu+1, 'LinNames_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call AllocAry(InitOut%RotFrame_u, nu+1, 'RotFrame_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call AllocAry(InitOut%IsLoad_u, nu+1, 'IsLoad_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call AllocAry(InitOut%LinNames_u, nu+p%NumExtendedInputs, 'LinNames_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call AllocAry(InitOut%RotFrame_u, nu+p%NumExtendedInputs, 'RotFrame_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call AllocAry(InitOut%IsLoad_u, nu+p%NumExtendedInputs, 'IsLoad_u', ErrStat2, ErrMsg2); call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return InitOut%IsLoad_u = .true. ! most of ED's inputs are loads; we will override the non-load inputs below. @@ -11164,27 +11220,29 @@ SUBROUTINE ED_Init_Jacobian( p, u, y, InitOut, ErrStat, ErrMsg) index = 1 if (allocated(u%BladePtLoads)) then index_last = index - do k=1,p%NumBl + do k=1,p%NumBl_Lin call PackLoadMesh_Names(u%BladePtLoads(k), 'Blade '//trim(num2lstr(k)), InitOut%LinNames_u, index) end do !InitOut%RotFrame_u(index_last:index-1) = .true. ! values on the mesh are in global, not rotating frame end if - call PackLoadMesh_Names(u%PlatformPtMesh, 'Platform', InitOut%LinNames_u, index) - call PackLoadMesh_Names(u%TowerPtLoads, 'Tower', InitOut%LinNames_u, index) - call PackLoadMesh_Names(u%HubPtLoad, 'Hub', InitOut%LinNames_u, index) - call PackLoadMesh_Names(u%NacelleLoads, 'Nacelle', InitOut%LinNames_u, index) + if (.not. p%CompAeroMaps) then + call PackLoadMesh_Names(u%PlatformPtMesh, 'Platform', InitOut%LinNames_u, index) + call PackLoadMesh_Names(u%TowerPtLoads, 'Tower', InitOut%LinNames_u, index) + call PackLoadMesh_Names(u%HubPtLoad, 'Hub', InitOut%LinNames_u, index) + call PackLoadMesh_Names(u%NacelleLoads, 'Nacelle', InitOut%LinNames_u, index) - do k = 1,p%NumBl ! scalars - InitOut%LinNames_u(index) = 'Blade '//trim(num2lstr(k))//' pitch command, rad' - InitOut%IsLoad_u( index) = .false. - InitOut%RotFrame_u(index) = .true. - index = index + 1 - end do + do k = 1,p%NumBl ! scalars + InitOut%LinNames_u(index) = 'Blade '//trim(num2lstr(k))//' pitch command, rad' + InitOut%IsLoad_u( index) = .false. + InitOut%RotFrame_u(index) = .true. + index = index + 1 + end do - InitOut%LinNames_u(index) = 'Yaw moment, Nm' ; index = index + 1 - InitOut%LinNames_u(index) = 'Generator torque, Nm' ; index = index + 1 - InitOut%LinNames_u(index) = 'Extended input: collective blade-pitch command, rad' - InitOut%IsLoad_u( index) = .false. + InitOut%LinNames_u(index) = 'Yaw moment, Nm' ; index = index + 1 + InitOut%LinNames_u(index) = 'Generator torque, Nm' ; index = index + 1 + InitOut%LinNames_u(index) = 'Extended input: collective blade-pitch command, rad' + InitOut%IsLoad_u( index) = .false. + end if END SUBROUTINE ED_Init_Jacobian !---------------------------------------------------------------------------------------------------------------------------------- @@ -11258,10 +11316,10 @@ END SUBROUTINE ED_Perturb_u !---------------------------------------------------------------------------------------------------------------------------------- !> This routine perturbs the nth element of the continuous state array. !! Do not change this without making sure subroutine elastodyn::ed_init_jacobian is consistant with this routine! -SUBROUTINE ED_Perturb_x( p, n, perturb_sign, x, dx ) +SUBROUTINE ED_Perturb_x( p, n_in, perturb_sign, x, dx ) TYPE(ED_ParameterType) , INTENT(IN ) :: p !< parameters - INTEGER( IntKi ) , INTENT(IN ) :: n !< number of array element to use + INTEGER( IntKi ) , INTENT(IN ) :: n_in !< number of array element to use INTEGER( IntKi ) , INTENT(IN ) :: perturb_sign !< +1 or -1 (value to multiply perturbation by; positive or negative difference) TYPE(ED_ContinuousStateType) , INTENT(INOUT) :: x !< perturbed ED states REAL( R8Ki ) , INTENT( OUT) :: dx !< amount that specific state was perturbed @@ -11269,14 +11327,19 @@ SUBROUTINE ED_Perturb_x( p, n, perturb_sign, x, dx ) ! local variables integer(intKi) :: indx + integer(intKi) :: n + n = (n_in - 1) * p%NActvDOF_Stride + 1 if (n > p%DOFs%NActvDOF) then + indx = p%DOFs%PS(n-p%DOFs%NActvDOF) dx = p%dx( indx ) - x%QDT( indx ) = x%QDT( indx ) + dx * perturb_sign + x%QDT( indx ) = x%QDT( indx ) + dx * perturb_sign + else + indx = p%DOFs%PS(n) dx = p%dx( indx ) @@ -11301,40 +11364,81 @@ SUBROUTINE Compute_dY(p, y_p, y_m, delta, dY) LOGICAL :: Mask(FIELDMASK_SIZE) ! flags to determine if this field is part of the packing - Mask = .false. - Mask(MASKID_TRANSLATIONDISP) = .true. - Mask(MASKID_ORIENTATION) = .true. - Mask(MASKID_ROTATIONVEL) = .true. - - - indx_first = 1 + indx_first = 1 if (allocated(y_p%BladeLn2Mesh)) then - do k=1,p%NumBl - call PackMotionMesh_dY(y_p%BladeLn2Mesh(k), y_m%BladeLn2Mesh(k), dY, indx_first) - end do + Mask = .true. + if (p%CompAeroMaps) then + Mask(MASKID_TRANSLATIONACC) = .false. + Mask(MASKID_ROTATIONACC) = .false. + end if + + do k=1,p%NumBl_Lin + call PackMotionMesh_dY(y_p%BladeLn2Mesh(k), y_m%BladeLn2Mesh(k), dY, indx_first, FieldMask=Mask) + end do end if - call PackMotionMesh_dY(y_p%PlatformPtMesh, y_m%PlatformPtMesh, dY, indx_first, UseSmlAngle=.true.) - call PackMotionMesh_dY(y_p%TowerLn2Mesh, y_m%TowerLn2Mesh, dY, indx_first, UseSmlAngle=.true.) - call PackMotionMesh_dY(y_p%HubPtMotion, y_m%HubPtMotion, dY, indx_first, FieldMask=Mask) - do k=1,p%NumBl - call PackMotionMesh_dY(y_p%BladeRootMotion(k), y_m%BladeRootMotion(k), dY, indx_first) - end do - call PackMotionMesh_dY(y_p%NacelleMotion, y_m%NacelleMotion, dY, indx_first) + if (.not. p%CompAeroMaps) then + call PackMotionMesh_dY(y_p%PlatformPtMesh, y_m%PlatformPtMesh, dY, indx_first, UseSmlAngle=.true.) + call PackMotionMesh_dY(y_p%TowerLn2Mesh, y_m%TowerLn2Mesh, dY, indx_first, UseSmlAngle=.true.) + + Mask = .false. + Mask(MASKID_TRANSLATIONDISP) = .true. + Mask(MASKID_ORIENTATION) = .true. + Mask(MASKID_ROTATIONVEL) = .true. + call PackMotionMesh_dY(y_p%HubPtMotion, y_m%HubPtMotion, dY, indx_first, FieldMask=Mask) + + do k=1,p%NumBl_Lin + call PackMotionMesh_dY(y_p%BladeRootMotion(k), y_m%BladeRootMotion(k), dY, indx_first) + end do + call PackMotionMesh_dY(y_p%NacelleMotion, y_m%NacelleMotion, dY, indx_first) - dY(indx_first) = y_p%Yaw - y_m%Yaw; indx_first = indx_first + 1 - dY(indx_first) = y_p%YawRate - y_m%YawRate; indx_first = indx_first + 1 - dY(indx_first) = y_p%HSS_Spd - y_m%HSS_Spd; indx_first = indx_first + 1 + dY(indx_first) = y_p%Yaw - y_m%Yaw; indx_first = indx_first + 1 + dY(indx_first) = y_p%YawRate - y_m%YawRate; indx_first = indx_first + 1 + dY(indx_first) = y_p%HSS_Spd - y_m%HSS_Spd; indx_first = indx_first + 1 - !indx_last = indx_first + p%NumOuts - 1 - do k=1,p%NumOuts + p%BldNd_TotNumOuts - dY(k+indx_first-1) = y_p%WriteOutput(k) - y_m%WriteOutput(k) - end do + !indx_last = indx_first + p%NumOuts - 1 + do k=1,p%NumOuts + p%BldNd_TotNumOuts + dY(k+indx_first-1) = y_p%WriteOutput(k) - y_m%WriteOutput(k) + end do + end if dY = dY / (2.0_R8Ki*delta) END SUBROUTINE Compute_dY !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine uses values of two continuous state types to compute an array of differences. +!! Do not change this packing without making sure subroutine elastodyn::init_jacobian is consistant with this routine! +SUBROUTINE Compute_dX(p, x_p, x_m, delta, dX) + + TYPE(ED_ParameterType) , INTENT(IN ) :: p !< parameters + TYPE(ED_ContinuousStateType) , INTENT(IN ) :: x_p !< ED continuous states at \f$ u + \Delta_p u \f$ or \f$ x + \Delta_p x \f$ (p=plus) + TYPE(ED_ContinuousStateType) , INTENT(IN ) :: x_m !< ED continuous states at \f$ u - \Delta_m u \f$ or \f$ x - \Delta_m x \f$ (m=minus) + REAL(R8Ki) , INTENT(IN ) :: delta !< difference in inputs or states \f$ delta = \Delta u \f$ or \f$ delta = \Delta_p x \f$ + REAL(R8Ki) , INTENT(INOUT) :: dX(:) !< column of dXdu or dXdx: \f$ \frac{\partial Y}{\partial u_i} = \frac{y_p - y_m}{2 \, \Delta u}\f$ or \f$ \frac{\partial Y}{\partial x_i} = \frac{y_p - y_m}{2 \, \Delta x}\f$ + + ! local variables: + INTEGER(IntKi) :: i ! loop over blade nodes + INTEGER(IntKi) :: j ! loop over blades + INTEGER(IntKi) :: indx_first ! index indicating next value of dY to be filled + + indx_first = 0 + + if (p%NActvVelDOF_Lin > 0) then + do j=1,p%DOFs%NActvDOF, p%NActvDOF_Stride ! Loop through all active (enabled) DOFs for linearization + indx_first = indx_first + 1 + dX(indx_first) = x_p%QT( p%DOFs%PS(j) ) - x_m%QT( p%DOFs%PS(j) ) + end do + end if + + do j=1,p%DOFs%NActvDOF, p%NActvDOF_Stride ! Loop through all active (enabled) DOFs for linearization + indx_first = indx_first + 1 + dX(indx_first) = x_p%QDT( p%DOFs%PS(j) ) - x_m%QDT( p%DOFs%PS(j) ) + end do + + dX = dX / (2*delta) ! whole array operation + +END SUBROUTINE Compute_dX +!---------------------------------------------------------------------------------------------------------------------------------- !> Routine to pack the data structures representing the operating points into arrays for linearization. SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, y_op, x_op, dx_op, xd_op, z_op, NeedTrimOP ) @@ -11373,43 +11477,45 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, ErrStat = ErrID_None ErrMsg = '' - + !.................................. IF ( PRESENT( u_op ) ) THEN if (.not. allocated(u_op)) then - call AllocAry(u_op, size(p%Jac_u_indx,1)+1,'u_op',ErrStat2,ErrMsg2) ! +1 for extended input here + call AllocAry(u_op, size(p%Jac_u_indx,1)+p%NumExtendedInputs,'u_op',ErrStat2,ErrMsg2) ! +1 for extended input here call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return end if index = 1 if (allocated(u%BladePtLoads)) then - do k=1,p%NumBl + do k=1,p%NumBl_Lin call PackLoadMesh(u%BladePtLoads(k), u_op, index) end do end if - call PackLoadMesh(u%PlatformPtMesh, u_op, index) - call PackLoadMesh(u%TowerPtLoads, u_op, index) - call PackLoadMesh(u%HubPtLoad, u_op, index) - call PackLoadMesh(u%NacelleLoads, u_op, index) - - do k = 1,p%NumBl ! scalars - u_op(index) = u%BlPitchCom(k) - index = index + 1 - end do - u_op(index) = u%YawMom ; index = index + 1 - u_op(index) = u%GenTrq ; index = index + 1 - - ! extended input: - u_op(index) = u%BlPitchCom(1) - - do k = 2,p%NumBl - if (.not. EqualRealNos( u%BlPitchCom(1), u%BlPitchCom(k) ) ) then - call SetErrStat(ErrID_Info,"Operating point of collective pitch extended input is invalid because "// & - "the commanded blade pitch angles are not the same for each blade.", ErrStat, ErrMsg, RoutineName) - exit - end if - end do + if (.not. p%CompAeroMaps) then + call PackLoadMesh(u%PlatformPtMesh, u_op, index) + call PackLoadMesh(u%TowerPtLoads, u_op, index) + call PackLoadMesh(u%HubPtLoad, u_op, index) + call PackLoadMesh(u%NacelleLoads, u_op, index) + + do k = 1,p%NumBl_Lin ! scalars + u_op(index) = u%BlPitchCom(k) + index = index + 1 + end do + u_op(index) = u%YawMom ; index = index + 1 + u_op(index) = u%GenTrq ; index = index + 1 + + ! extended input: ! note this happens only if .not. p%CompAeroMaps, so p%NumExtendedInputs > 0 + u_op(index) = u%BlPitchCom(1) + + do k = 2,p%NumBl_Lin + if (.not. EqualRealNos( u%BlPitchCom(1), u%BlPitchCom(k) ) ) then + call SetErrStat(ErrID_Info,"Operating point of collective pitch extended input is invalid because "// & + "the commanded blade pitch angles are not the same for each blade.", ErrStat, ErrMsg, RoutineName) + exit + end if + end do + end if END IF @@ -11423,20 +11529,26 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, if (.not. allocated(y_op)) then ! our operating point includes DCM (orientation) matrices, not just small angles like the perturbation matrices do - ny = p%Jac_ny + y%PlatformPtMesh%NNodes * 6 & ! Jac_ny has 3 for Orientation, but we need 9 at each node + if (p%CompAeroMaps) then + ny = p%Jac_ny + else + ny = p%Jac_ny + y%PlatformPtMesh%NNodes * 6 & ! Jac_ny has 3 for Orientation, but we need 9 at each node + y%TowerLn2Mesh%NNodes * 6 & ! Jac_ny has 3 for Orientation, but we need 9 at each node + y%HubPtMotion%NNodes * 6 & ! Jac_ny has 3 for Orientation, but we need 9 at each node + y%NacelleMotion%NNodes * 6 ! Jac_ny has 3 for Orientation, but we need 9 at each node - + + do k=1,p%NumBl_Lin + ny = ny + y%BladeRootMotion(k)%NNodes * 6 ! Jac_ny has 3 for Orientation, but we need 9 at each node on each blade + end do + + end if + if (allocated(y%BladeLn2Mesh)) then - do k=1,p%NumBl + do k=1,p%NumBl_Lin ny = ny + y%BladeLn2Mesh(k)%NNodes * 6 ! Jac_ny has 3 for Orientation, but we need 9 (at each node on each blade) end do end if - do k=1,p%NumBl - ny = ny + y%BladeRootMotion(k)%NNodes * 6 ! Jac_ny has 3 for Orientation, but we need 9 at each node on each blade - end do - + call AllocAry(y_op, ny,'y_op',ErrStat2,ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return @@ -11445,33 +11557,44 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, if (ReturnTrimOP) y_op = 0.0_ReKi ! initialize in case we are returning packed orientations and don't fill the entire array - Mask = .false. - Mask(MASKID_TRANSLATIONDISP) = .true. - Mask(MASKID_ORIENTATION) = .true. - Mask(MASKID_ROTATIONVEL) = .true. - + if ( p%CompAeroMaps ) then + Mask = .false. + Mask(MASKID_TRANSLATIONDISP) = .true. + Mask(MASKID_ORIENTATION) = .true. + Mask(MASKID_TRANSLATIONVEL) = .true. + Mask(MASKID_ROTATIONVEL) = .true. + else + Mask = .true. + end if + index = 1 if (allocated(y%BladeLn2Mesh)) then - do k=1,p%NumBl - call PackMotionMesh(y%BladeLn2Mesh(k), y_op, index, TrimOP=ReturnTrimOP) + do k=1,p%NumBl_Lin + call PackMotionMesh(y%BladeLn2Mesh(k), y_op, index, FieldMask=Mask, TrimOP=ReturnTrimOP) end do end if - call PackMotionMesh(y%PlatformPtMesh, y_op, index, TrimOP=ReturnTrimOP) - call PackMotionMesh(y%TowerLn2Mesh, y_op, index, TrimOP=ReturnTrimOP) - call PackMotionMesh(y%HubPtMotion, y_op, index, FieldMask=Mask, TrimOP=ReturnTrimOP) - - do k=1,p%NumBl - call PackMotionMesh(y%BladeRootMotion(k), y_op, index, TrimOP=ReturnTrimOP) - end do - call PackMotionMesh(y%NacelleMotion, y_op, index, TrimOP=ReturnTrimOP) - - y_op(index) = y%Yaw ; index = index + 1 - y_op(index) = y%YawRate ; index = index + 1 - y_op(index) = y%HSS_Spd - - do i=1,p%NumOuts + p%BldNd_TotNumOuts - y_op(i+index) = y%WriteOutput(i) - end do + if (.not. p%CompAeroMaps) then + Mask = .false. + Mask(MASKID_TRANSLATIONDISP) = .true. + Mask(MASKID_ORIENTATION) = .true. + Mask(MASKID_ROTATIONVEL) = .true. + + call PackMotionMesh(y%PlatformPtMesh, y_op, index, TrimOP=ReturnTrimOP) + call PackMotionMesh(y%TowerLn2Mesh, y_op, index, TrimOP=ReturnTrimOP) + call PackMotionMesh(y%HubPtMotion, y_op, index, FieldMask=Mask, TrimOP=ReturnTrimOP) + do k=1,p%NumBl_Lin + call PackMotionMesh(y%BladeRootMotion(k), y_op, index, TrimOP=ReturnTrimOP) + end do + call PackMotionMesh(y%NacelleMotion, y_op, index, TrimOP=ReturnTrimOP) + + y_op(index) = y%Yaw ; index = index + 1 + y_op(index) = y%YawRate ; index = index + 1 + y_op(index) = y%HSS_Spd + + do i=1,p%NumOuts + p%BldNd_TotNumOuts + y_op(i+index) = y%WriteOutput(i) + end do + end if END IF @@ -11479,17 +11602,23 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, IF ( PRESENT( x_op ) ) THEN if (.not. allocated(x_op)) then - call AllocAry(x_op, p%DOFs%NActvDOF * 2,'x_op',ErrStat2,ErrMsg2) + call AllocAry(x_op, p%NActvDOF_Lin + p%NActvVelDOF_Lin,'x_op',ErrStat2,ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return end if - do i=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - x_op(i) = x%QT( p%DOFs%PS(i) ) + index = 0 + do i=1,p%DOFs%NActvDOF,p%NActvDOF_Stride ! Loop through all active (enabled) DOFs in the Jacobian + index = index + 1 + x_op(index) = x%QT( p%DOFs%PS(i) ) end do - do i=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - x_op(i+p%DOFs%NActvDOF) = x%QDT( p%DOFs%PS(i) ) - end do + + if (p%NActvVelDOF_Lin > 0) then ! .not. p%CompAeroMaps + do i=1,p%DOFs%NActvDOF,p%NActvDOF_Stride ! Loop through all active (enabled) DOFs in the Jacobian + index = index + 1 + x_op(index) = x%QDT( p%DOFs%PS(i) ) + end do + end if END IF @@ -11497,7 +11626,7 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, IF ( PRESENT( dx_op ) ) THEN if (.not. allocated(dx_op)) then - call AllocAry(dx_op, p%DOFs%NActvDOF * 2,'dx_op',ErrStat2,ErrMsg2) + call AllocAry(dx_op, p%NActvDOF_Lin + p%NActvVelDOF_Lin,'dx_op',ErrStat2,ErrMsg2) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat>=AbortErrLev) return end if @@ -11509,12 +11638,18 @@ SUBROUTINE ED_GetOP( t, u, p, x, xd, z, OtherState, y, m, ErrStat, ErrMsg, u_op, return end if - do i=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dx_op(i) = dx%QT( p%DOFs%PS(i) ) + index = 0 + if (p%NActvVelDOF_Lin > 0) then ! p%CompAeroMaps + do i=1,p%DOFs%NActvDOF,p%NActvDOF_Stride ! Loop through all active (enabled) DOFs in the Jacobian + index = index + 1 + dx_op(index) = dx%QT( p%DOFs%PS(i) ) + end do + end if + + do i=1,p%DOFs%NActvDOF,p%NActvDOF_Stride ! Loop through all active (enabled) DOFs in the Jacobian + index = index + 1 + dx_op(index) = dx%QDT( p%DOFs%PS(i) ) end do - do i=1,p%DOFs%NActvDOF ! Loop through all active (enabled) DOFs - dx_op(i+p%DOFs%NActvDOF) = dx%QDT( p%DOFs%PS(i) ) - end do call ED_DestroyContState( dx, ErrStat2, ErrMsg2) diff --git a/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 b/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 index adbbd13201..2bc7764364 100644 --- a/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_AllBldNdOuts_IO.f90 @@ -482,9 +482,11 @@ SUBROUTINE AllBldNdOuts_SetParameters( p, InputFileData, ErrStat, ErrMsg ) ErrMsg = "" ! Check if the requested blades exist - IF ( (InputFileData%BldNd_BladesOut < 0_IntKi) .OR. (InputFileData%BldNd_BladesOut > p%NumBl) ) THEN - CALL SetErrStat( ErrID_Warn, " Number of blades to output data at all bladed nodes (BldNd_BladesOut) must be between 0 and "//TRIM(Num2LStr(p%NumBl))//".", ErrStat, ErrMsg, RoutineName) + IF ( (InputFileData%BldNd_BladesOut < 0_IntKi) ) THEN p%BldNd_BladesOut = 0_IntKi + ELSE IF ((InputFileData%BldNd_BladesOut > p%NumBl) ) THEN + CALL SetErrStat( ErrID_Warn, " Number of blades to output data at all blade nodes (BldNd_BladesOut) must be less than "//TRIM(Num2LStr(p%NumBl))//".", ErrStat, ErrMsg, RoutineName) + p%BldNd_BladesOut = p%NumBl ! NOTE: we are forgiving and plateau to numBlades ELSE p%BldNd_BladesOut = InputFileData%BldNd_BladesOut ENDIF @@ -503,6 +505,7 @@ SUBROUTINE AllBldNdOuts_SetParameters( p, InputFileData, ErrStat, ErrMsg ) ELSE p%BldNd_NumOuts = InputFileData%BldNd_NumOuts ENDIF + if (p%BldNd_BladesOut==0) p%BldNd_NumOuts = 0 ! Set the total number of outputs ( requested channel groups * number requested nodes * number requested blades ) p%BldNd_TotNumOuts = p%BldNodes*p%BldNd_BladesOut*p%BldNd_NumOuts !p%BldNd_NumOuts * size(p%BldNd_BlOutNd) * size(p%BldNd_BladesOut) diff --git a/modules/elastodyn/src/ElastoDyn_IO.f90 b/modules/elastodyn/src/ElastoDyn_IO.f90 index c4e40d272b..286ab30aac 100644 --- a/modules/elastodyn/src/ElastoDyn_IO.f90 +++ b/modules/elastodyn/src/ElastoDyn_IO.f90 @@ -3574,12 +3574,12 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile !----------- OUTLIST ----------------------------------------------------------- ! In case there is something ill-formed in the additional nodal outputs section, we will simply ignore it and assume that this section does not exist. ErrMsg_NoAllBldNdOuts='Nodal outputs section of ElastoDyn input file not found or improperly formatted.' + InputFileData%BldNd_NumOuts = 0 ! initialize in case of error + InputFileData%BldNd_BladesOut = 0 ! initialize in case of error !----------- OUTLIST for BldNd ----------------------------------------------------------- CALL ReadCom( UnIn, InputFile, 'Section Header: OutList for Blade node channels', ErrStat2, ErrMsg2, UnEc ) IF ( ErrStat2 >= AbortErrLev ) THEN - InputFileData%BldNd_BladesOut = 0 - InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoAllBldNdOuts) ) CALL Cleanup() RETURN @@ -3592,7 +3592,6 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile CALL ReadVar( UnIn, InputFile, InputFileData%BldNd_BladesOut, 'BldNd_BladesOut', 'Which blades to output node data on.'//TRIM(Num2Lstr(I)), ErrStat2, ErrMsg2, UnEc ) IF ( ErrStat2 >= AbortErrLev ) THEN InputFileData%BldNd_BladesOut = 0 - InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoAllBldNdOuts) ) CALL Cleanup() RETURN @@ -3603,8 +3602,6 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile ! TODO: Parse this string into an array of nodes to output at (one idea is to set an array of boolean to T/F for which nodes to output). At present, we ignore it entirely. CALL ReadVar( UnIn, InputFile, InputFileData%BldNd_BlOutNd_Str, 'BldNd_BlOutNd_Str', 'Which nodes to output node data on.'//TRIM(Num2Lstr(I)), ErrStat2, ErrMsg2, UnEc ) IF ( ErrStat2 >= AbortErrLev ) THEN - InputFileData%BldNd_BladesOut = 0 - InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoAllBldNdOuts) ) CALL Cleanup() RETURN @@ -3614,8 +3611,6 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile ! Section header for outlist CALL ReadCom( UnIn, InputFile, 'Section Header: OutList', ErrStat2, ErrMsg2, UnEc ) IF ( ErrStat2 >= AbortErrLev ) THEN - InputFileData%BldNd_BladesOut = 0 - InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoAllBldNdOuts) ) CALL Cleanup() RETURN @@ -3624,13 +3619,18 @@ SUBROUTINE ReadPrimaryFile( InputFile, InputFileData, BldFile, FurlFile, TwrFile ! OutList - List of user-requested output channels at each node(-): CALL ReadOutputList ( UnIn, InputFile, InputFileData%BldNd_OutList, InputFileData%BldNd_NumOuts, 'BldNd_OutList', "List of user-requested output channels", ErrStat2, ErrMsg2, UnEc ) ! Routine in NWTC Subroutine Library - IF ( ErrStat2 >= AbortErrLev ) THEN - InputFileData%BldNd_BladesOut = 0 + IF ( ErrStat2 >= AbortErrLev .and. InputFileData%BldNd_NumOuts < 1) THEN InputFileData%BldNd_NumOuts = 0 call wrscr( trim(ErrMsg_NoAllBldNdOuts) ) CALL Cleanup() RETURN + ELSE + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ENDIF + +!FIXME: this is a hack to fix a segfault. Better logic is really needed for the nodal outputs. + ! Node outputs. If no blades specified set BldNd_Outs to 0 (all checks are currently done on NumOuts, not BladesOut). + if (InputFileData%BldNd_BladesOut <= 0) InputFileData%BldNd_NumOuts = 0 !---------------------- END OF FILE ----------------------------------------- call cleanup() @@ -4131,9 +4131,7 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta REAL(ReKi) :: SmallAngleLimit_Rad ! Largest input angle considered "small" (check in input file), radians INTEGER(IntKi) :: I ! loop counter INTEGER(IntKi) :: K ! blade number - INTEGER(IntKi) :: FmtWidth ! width of the field returned by the specified OutFmt - INTEGER(IntKi) :: ErrStat2 ! Temporary error status - CHARACTER(ErrMsgLen) :: ErrMsg2 ! Temporary rror message + !!INTEGER(IntKi) :: FmtWidth ! width of the field returned by the specified OutFmt CHARACTER(*), PARAMETER :: RoutineName = 'ValidatePrimaryData' ! Initialize error status and angle limit defined locally (in correct units) @@ -4183,9 +4181,9 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta IF ( InputFileData%YawBrMass < 0.0_ReKi) call SetErrStat(ErrID_Fatal,'YawBrMass must not be negative.',ErrStat,ErrMsg,RoutineName) IF ( InputFileData%NacMass < 0.0_ReKi) call SetErrStat(ErrID_Fatal,'NacMass must not be negative.',ErrStat,ErrMsg,RoutineName) IF ( InputFileData%HubMass < 0.0_ReKi) call SetErrStat(ErrID_Fatal,'HubMass must not be negative.',ErrStat,ErrMsg,RoutineName) - IF ( MHK /= 2 ) THEN + IF ( MHK /= MHK_Floating ) THEN IF ( InputFileData%Twr2Shft < 0.0_ReKi) call SetErrStat(ErrID_Fatal,'Twr2Shft must not be negative.',ErrStat,ErrMsg,RoutineName) - ELSEIF ( MHK == 2 ) THEN + ELSE IF ( InputFileData%Twr2Shft > 0.0_ReKi) call SetErrStat(ErrID_Fatal,'Twr2Shft must not be positive for a floating MHK turbine.',ErrStat,ErrMsg,RoutineName) ENDIF @@ -4198,9 +4196,9 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta IF ( InputFileData%HubIner < 0.0_ReKi) call SetErrStat(ErrID_Fatal,'HubIner must not be negative.',ErrStat,ErrMsg,RoutineName) ! Check that TowerHt is in the range [0,inf): - IF ( MHK /= 2 ) THEN + IF ( MHK /= MHK_Floating ) THEN IF ( InputFileData%TowerHt <= 0.0_ReKi ) CALL SetErrStat( ErrID_Fatal, 'TowerHt must be greater than zero.',ErrStat,ErrMsg,RoutineName ) - ELSEIF ( MHK == 2 ) THEN + ELSE IF ( InputFileData%TowerHt >= 0.0_ReKi ) CALL SetErrStat( ErrID_Fatal, 'TowerHt must be less than zero for a floating MHK turbine.',ErrStat,ErrMsg,RoutineName ) ENDIF @@ -4212,7 +4210,7 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta ! Check that the gearbox efficiency is valid: IF ( ( InputFileData%GBoxEff <= 0.0_ReKi ) .OR. ( InputFileData%GBoxEff > 1.0_ReKi ) ) THEN CALL SetErrStat( ErrID_Fatal, 'GBoxEff must be in the range (0,1] (i.e., (0,100] percent).',ErrStat,ErrMsg,RoutineName ) - ENDIF + ENDIF ! warn if 2nd modes are enabled without their corresponding 1st modes @@ -4241,7 +4239,7 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta END IF ENDIF - IF ( MHK /= 2 ) THEN + IF ( MHK /= MHK_Floating ) THEN IF ( InputFileData%TowerBsHt >= InputFileData%TowerHt ) CALL SetErrStat( ErrID_Fatal, 'TowerBsHt must be less than TowerHt.',ErrStat,ErrMsg,RoutineName) @@ -4251,7 +4249,7 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta IF ( InputFileData%PtfmRefzt > InputFileData%TowerBsHt ) & CALL SetErrStat( ErrID_Fatal, 'PtfmRefzt must not be greater than TowerBsHt.',ErrStat,ErrMsg,RoutineName) - ELSEIF ( MHK == 2 ) THEN + ELSE IF ( InputFileData%TowerBsHt <= InputFileData%TowerHt ) CALL SetErrStat( ErrID_Fatal, 'TowerBsHt must be greater than TowerHt for a floating MHK turbine.',ErrStat,ErrMsg,RoutineName) @@ -4261,15 +4259,15 @@ SUBROUTINE ValidatePrimaryData( InputFileData, BD4Blades, Linearize, MHK, ErrSta IF (InputFileData%HubRad >= InputFileData%TipRad ) & CALL SetErrStat( ErrID_Fatal, 'HubRad must be less than TipRad.',ErrStat,ErrMsg,RoutineName) - IF ( MHK /= 2 ) THEN + IF ( MHK /= MHK_Floating ) THEN IF ( InputFileData%TowerHt + InputFileData%Twr2Shft + InputFileData%OverHang*SIN(InputFileData%ShftTilt) & <= InputFileData%TipRad ) THEN CALL SetErrStat( ErrID_Fatal, 'TowerHt + Twr2Shft + OverHang*SIN(ShftTilt) must be greater than TipRad.',ErrStat,ErrMsg,RoutineName) END IF - ELSEIF ( MHK == 2 ) THEN + ELSE IF ( -InputFileData%TowerHt - InputFileData%Twr2Shft - InputFileData%OverHang*SIN(InputFileData%ShftTilt) & <= InputFileData%TipRad ) THEN - CALL SetErrStat( ErrID_Fatal, 'TowerHt + Twr2Shft + OverHang*SIN(ShftTilt) must be greater than TipRad.',ErrStat,ErrMsg,RoutineName) + CALL SetErrStat( ErrID_Fatal, '-TowerHt - Twr2Shft - OverHang*SIN(ShftTilt) must be greater than TipRad.',ErrStat,ErrMsg,RoutineName) END IF ENDIF END IF diff --git a/modules/elastodyn/src/ElastoDyn_Registry.txt b/modules/elastodyn/src/ElastoDyn_Registry.txt index d18ab670cd..4d1038aebf 100644 --- a/modules/elastodyn/src/ElastoDyn_Registry.txt +++ b/modules/elastodyn/src/ElastoDyn_Registry.txt @@ -26,6 +26,8 @@ typedef ^ InitInputType CHARACTER(1024) RootName - - - "RootName for writing out typedef ^ InitInputType ReKi Gravity - - - "Gravitational acceleration" m/s^2 typedef ^ InitInputType IntKi MHK - - - "MHK turbine type switch" - typedef ^ InitInputType ReKi WtrDpth - - - "Water depth" m +typedef ^ InitInputType LOGICAL CompAeroMaps - .FALSE. - "flag to determine if ElastoDyn is computing aero maps (true) or running a normal simulation (false)" - +typedef ^ InitInputType ReKi RotSpeed - - - "Rotor speed used when ElastoDyn is computing aero maps" "rad/s" # Define outputs from the initialization routine here: typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - @@ -55,6 +57,7 @@ typedef ^ InitOutputType LOGICAL RotFrame_x {:} - - "Flag that tells FAST/MBC3 i typedef ^ InitOutputType IntKi DerivOrder_x {:} - - "Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization" - typedef ^ InitOutputType LOGICAL RotFrame_u {:} - - "Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame" - typedef ^ InitOutputType LOGICAL IsLoad_u {:} - - "Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix)" - +typedef ^ InitOutputType IntKi GearBox_index - - - "Index to gearbox rotation in state array (for steady-state calculations)" - # ..... Blade Input file data ........................................................................................................... typedef ElastoDyn/ED BladeInputData IntKi NBlInpSt - - - "Number of blade input stations" - @@ -748,6 +751,12 @@ typedef ^ ParameterType Integer Jac_u_indx {:}{:} - - "matrix to help fill/pack typedef ^ ParameterType R8Ki du {:} - - "vector that determines size of perturbation for u (inputs)" typedef ^ ParameterType R8Ki dx {:} - - "vector that determines size of perturbation for x (continuous states)" typedef ^ ParameterType Integer Jac_ny - - - "number of outputs in jacobian matrix" - +typedef ^ ParameterType Logical CompAeroMaps - - - "number of outputs in jacobian matrix" - +typedef ^ ParameterType Integer NumExtendedInputs - - - "number of extended inputs for linearization" - +typedef ^ ParameterType Integer NumBl_Lin - - - "number of blades in the jacobian" - +typedef ^ ParameterType Integer NActvVelDOF_Lin - - - "number of velocity states in the jacobian" - +typedef ^ ParameterType Integer NActvDOF_Lin - - - "number of active DOFs to use in the jacobian" - +typedef ^ ParameterType Integer NActvDOF_Stride - - - "stride for active DOFs to use in the jacobian" - # ..... Inputs .................................................................................................................... # Define inputs that are contained on the mesh here: diff --git a/modules/elastodyn/src/ElastoDyn_Types.f90 b/modules/elastodyn/src/ElastoDyn_Types.f90 index 45e632f0a6..4e52b6773b 100644 --- a/modules/elastodyn/src/ElastoDyn_Types.f90 +++ b/modules/elastodyn/src/ElastoDyn_Types.f90 @@ -44,6 +44,8 @@ MODULE ElastoDyn_Types REAL(ReKi) :: Gravity = 0.0_ReKi !< Gravitational acceleration [m/s^2] INTEGER(IntKi) :: MHK = 0_IntKi !< MHK turbine type switch [-] REAL(ReKi) :: WtrDpth = 0.0_ReKi !< Water depth [m] + LOGICAL :: CompAeroMaps = .FALSE. !< flag to determine if ElastoDyn is computing aero maps (true) or running a normal simulation (false) [-] + REAL(ReKi) :: RotSpeed = 0.0_ReKi !< Rotor speed used when ElastoDyn is computing aero maps [rad/s] END TYPE ED_InitInputType ! ======================= ! ========= ED_InitOutputType ======= @@ -75,6 +77,7 @@ MODULE ElastoDyn_Types INTEGER(IntKi) , DIMENSION(:), ALLOCATABLE :: DerivOrder_x !< Integer that tells FAST/MBC3 the maximum derivative order of continuous states used in linearization [-] LOGICAL , DIMENSION(:), ALLOCATABLE :: RotFrame_u !< Flag that tells FAST/MBC3 if the inputs used in linearization are in the rotating frame [-] LOGICAL , DIMENSION(:), ALLOCATABLE :: IsLoad_u !< Flag that tells FAST if the inputs used in linearization are loads (for preconditioning matrix) [-] + INTEGER(IntKi) :: GearBox_index = 0_IntKi !< Index to gearbox rotation in state array (for steady-state calculations) [-] END TYPE ED_InitOutputType ! ======================= ! ========= BladeInputData ======= @@ -752,6 +755,12 @@ MODULE ElastoDyn_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 = 0_IntKi !< number of outputs in jacobian matrix [-] + LOGICAL :: CompAeroMaps = .false. !< number of outputs in jacobian matrix [-] + INTEGER(IntKi) :: NumExtendedInputs = 0_IntKi !< number of extended inputs for linearization [-] + INTEGER(IntKi) :: NumBl_Lin = 0_IntKi !< number of blades in the jacobian [-] + INTEGER(IntKi) :: NActvVelDOF_Lin = 0_IntKi !< number of velocity states in the jacobian [-] + INTEGER(IntKi) :: NActvDOF_Lin = 0_IntKi !< number of active DOFs to use in the jacobian [-] + INTEGER(IntKi) :: NActvDOF_Stride = 0_IntKi !< stride for active DOFs to use in the jacobian [-] END TYPE ED_ParameterType ! ======================= ! ========= ED_InputType ======= @@ -832,6 +841,8 @@ subroutine ED_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrSta DstInitInputData%Gravity = SrcInitInputData%Gravity DstInitInputData%MHK = SrcInitInputData%MHK DstInitInputData%WtrDpth = SrcInitInputData%WtrDpth + DstInitInputData%CompAeroMaps = SrcInitInputData%CompAeroMaps + DstInitInputData%RotSpeed = SrcInitInputData%RotSpeed end subroutine subroutine ED_DestroyInitInput(InitInputData, ErrStat, ErrMsg) @@ -856,6 +867,8 @@ subroutine ED_PackInitInput(Buf, Indata) call RegPack(Buf, InData%Gravity) call RegPack(Buf, InData%MHK) call RegPack(Buf, InData%WtrDpth) + call RegPack(Buf, InData%CompAeroMaps) + call RegPack(Buf, InData%RotSpeed) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -880,6 +893,10 @@ subroutine ED_UnPackInitInput(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%WtrDpth) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%RotSpeed) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine ED_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) @@ -1066,6 +1083,7 @@ subroutine ED_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, Err end if DstInitOutputData%IsLoad_u = SrcInitOutputData%IsLoad_u end if + DstInitOutputData%GearBox_index = SrcInitOutputData%GearBox_index end subroutine subroutine ED_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) @@ -1204,6 +1222,7 @@ subroutine ED_PackInitOutput(Buf, Indata) call RegPackBounds(Buf, 1, lbound(InData%IsLoad_u), ubound(InData%IsLoad_u)) call RegPack(Buf, InData%IsLoad_u) end if + call RegPack(Buf, InData%GearBox_index) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -1424,6 +1443,8 @@ subroutine ED_UnPackInitOutput(Buf, OutData) call RegUnpack(Buf, OutData%IsLoad_u) if (RegCheckErr(Buf, RoutineName)) return end if + call RegUnpack(Buf, OutData%GearBox_index) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine ED_CopyBladeInputData(SrcBladeInputDataData, DstBladeInputDataData, CtrlCode, ErrStat, ErrMsg) @@ -8625,6 +8646,12 @@ subroutine ED_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%dx = SrcParamData%dx end if DstParamData%Jac_ny = SrcParamData%Jac_ny + DstParamData%CompAeroMaps = SrcParamData%CompAeroMaps + DstParamData%NumExtendedInputs = SrcParamData%NumExtendedInputs + DstParamData%NumBl_Lin = SrcParamData%NumBl_Lin + DstParamData%NActvVelDOF_Lin = SrcParamData%NActvVelDOF_Lin + DstParamData%NActvDOF_Lin = SrcParamData%NActvDOF_Lin + DstParamData%NActvDOF_Stride = SrcParamData%NActvDOF_Stride end subroutine subroutine ED_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -9293,6 +9320,12 @@ subroutine ED_PackParam(Buf, Indata) call RegPack(Buf, InData%dx) end if call RegPack(Buf, InData%Jac_ny) + call RegPack(Buf, InData%CompAeroMaps) + call RegPack(Buf, InData%NumExtendedInputs) + call RegPack(Buf, InData%NumBl_Lin) + call RegPack(Buf, InData%NActvVelDOF_Lin) + call RegPack(Buf, InData%NActvDOF_Lin) + call RegPack(Buf, InData%NActvDOF_Stride) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -10438,6 +10471,18 @@ subroutine ED_UnPackParam(Buf, OutData) end if call RegUnpack(Buf, OutData%Jac_ny) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NumExtendedInputs) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NumBl_Lin) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NActvVelDOF_Lin) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NActvDOF_Lin) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NActvDOF_Stride) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine ED_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) diff --git a/modules/openfoam/CMakeLists.txt b/modules/externalinflow/CMakeLists.txt similarity index 61% rename from modules/openfoam/CMakeLists.txt rename to modules/externalinflow/CMakeLists.txt index ec8f56c83e..a5ca83a18e 100644 --- a/modules/openfoam/CMakeLists.txt +++ b/modules/externalinflow/CMakeLists.txt @@ -15,20 +15,24 @@ # if (GENERATE_TYPES) - generate_f90_types(src/OpenFOAM_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/OpenFOAM_Types.f90 -ccode) + generate_f90_types(src/ExternalInflow_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/ExternalInflow_Types.f90 -ccode) endif() -add_library(foamtypeslib src/OpenFOAM_Types.f90) -target_link_libraries(foamtypeslib nwtclibs ifwlib) +add_library(extinflowtypeslib STATIC + src/ExternalInflow_Types.f90 +) +target_link_libraries(extinflowtypeslib nwtclibs ifwlib) -add_library(foamfastlib src/OpenFOAM.f90) -target_link_libraries(foamfastlib openfast_prelib) -target_include_directories(foamfastlib PUBLIC +add_library(extinflowlib STATIC + src/ExternalInflow.f90 +) +target_link_libraries(extinflowlib openfast_prelib) +target_include_directories(extinflowlib PUBLIC $ ) -set_target_properties(foamfastlib PROPERTIES PUBLIC_HEADER src/OpenFOAM_Types.h) +set_target_properties(extinflowlib PROPERTIES PUBLIC_HEADER src/ExternalInflow_Types.h) -install(TARGETS foamtypeslib foamfastlib +install(TARGETS extinflowtypeslib extinflowlib EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin ARCHIVE DESTINATION lib diff --git a/modules/externalinflow/README.md b/modules/externalinflow/README.md new file mode 100644 index 0000000000..0c79d6c7b7 --- /dev/null +++ b/modules/externalinflow/README.md @@ -0,0 +1,5 @@ +# ExternalInflow Module + +## Overview +This is a pseudo module used to couple OpenFAST with CFD codes (NALU-Wind, AMR-Wind, SOWFA); +it is considered part of the OpenFAST glue code. diff --git a/modules/openfoam/src/OpenFOAM.f90 b/modules/externalinflow/src/ExternalInflow.f90 similarity index 54% rename from modules/openfoam/src/OpenFOAM.f90 rename to modules/externalinflow/src/ExternalInflow.f90 index 114f440971..8aa7086020 100644 --- a/modules/openfoam/src/OpenFOAM.f90 +++ b/modules/externalinflow/src/ExternalInflow.f90 @@ -2,7 +2,7 @@ ! LICENSING ! Copyright (C) 2015 National Renewable Energy Laboratory ! -! OpenFOAM module +! ExternalInflow module ! ! Licensed under the Apache License, Version 2.0 (the "License"); ! you may not use this file except in compliance with the License. @@ -17,33 +17,33 @@ ! limitations under the License. ! !********************************************************************************************************************************** -!> This is a pseudo module used to couple OpenFAST with OpenFOAM; it is used to interface to CFD codes including SOWFA, OpenFOAM, and AMR-Wind -MODULE OpenFOAM +!> This is a pseudo module used to couple OpenFAST with ExternalInflow; it is used to interface to CFD codes including SOWFA, ExternalInflow, and AMR-Wind +MODULE ExternalInflow USE FAST_Types USE IfW_FlowField USE InflowWind_IO IMPLICIT NONE PRIVATE - TYPE(ProgDesc), PARAMETER :: OpFM_Ver = ProgDesc( 'OpenFOAM Integration', '', '' ) + TYPE(ProgDesc), PARAMETER :: ExtInfw_Ver = ProgDesc( 'ExternalInflow Integration', '', '' ) ! ..... Public Subroutines ................................................................................................... - PUBLIC :: Init_OpFM ! Initialization routine - PUBLIC :: OpFM_SetInputs ! Glue-code routine to update inputs for OpenFOAM - PUBLIC :: OpFM_SetWriteOutput - PUBLIC :: OpFM_UpdateFlowField + PUBLIC :: Init_ExtInfw ! Initialization routine + PUBLIC :: ExtInfw_SetInputs ! Glue-code routine to update inputs for ExternalInflow + PUBLIC :: ExtInfw_SetWriteOutput + PUBLIC :: ExtInfw_UpdateFlowField CONTAINS !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, InitOut, ErrStat, ErrMsg ) - TYPE(OpFM_InitInputType), INTENT(IN ) :: InitInp ! Input data for initialization routine +SUBROUTINE Init_ExtInfw( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, ExtInfw, InitOut, ErrStat, ErrMsg ) + TYPE(ExtInfw_InitInputType), INTENT(IN ) :: InitInp ! Input data for initialization routine TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code REAL(ReKi), INTENT(IN ) :: AirDens ! Air Density kg/m^3 TYPE(AD_InputType), INTENT(IN ) :: u_AD ! AeroDyn input data TYPE(AD_OutputType), INTENT(IN ) :: y_AD ! AeroDyn output data (for mesh mapping) TYPE(AD_InitOutputType), INTENT(IN ) :: initOut_AD ! AeroDyn InitOutput data (for BladeProps) - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module - TYPE(OpFM_InitOutputType), INTENT(INOUT) :: InitOut ! Output for initialization routine + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module + TYPE(ExtInfw_InitOutputType), INTENT(INOUT) :: InitOut ! Output for initialization routine INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -53,7 +53,7 @@ SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, In INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'Init_OpFM' + CHARACTER(*), PARAMETER :: RoutineName = 'Init_ExtInfw' ! Initialize variables @@ -61,12 +61,12 @@ SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, In ErrMsg = "" ! number of blades - OpFM%p%NumBl = SIZE( u_AD%rotors(1)%BladeMotion, 1 ) + ExtInfw%p%NumBl = SIZE( u_AD%rotors(1)%BladeMotion, 1 ) - ! air density, required for normalizing values sent to OpenFOAM: - OpFM%p%AirDens = AirDens + ! air density, required for normalizing values sent to ExternalInflow: + ExtInfw%p%AirDens = AirDens if ( EqualRealNos( AirDens, 0.0_ReKi ) ) & - CALL SetErrStat( ErrID_Fatal, 'Air density cannot be zero for OpenFOAM integration. Check that AeroDyn is used and that air density is set properly', ErrStat,ErrMsg,RoutineName) + CALL SetErrStat( ErrID_Fatal, 'Air density cannot be zero for ExternalInflow integration. Check that AeroDyn is used and that air density is set properly', ErrStat,ErrMsg,RoutineName) IF (ErrStat >= AbortErrLev) RETURN @@ -75,18 +75,18 @@ SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, In ! quick sanity checks. ! If the number of nodes requested from CFD (nNodesForceBlade) is more than 4x the number of AD15 blade nodes ! we expect a lot of innacuracies. The user should increase the number of nodes in AD15 - if (Opfm%p%nNodesForceBlade > 4 * u_AD%rotors(1)%BladeMotion(1)%NNodes) then - ErrMsg2=trim(Num2LStr(Opfm%p%nNodesForceBlade))//' blade points requested from CFD. AD15 only uses ' & + if (ExtInfw%p%nNodesForceBlade > 4 * u_AD%rotors(1)%BladeMotion(1)%NNodes) then + ErrMsg2=trim(Num2LStr(ExtInfw%p%nNodesForceBlade))//' blade points requested from CFD. AD15 only uses ' & //trim(Num2LStr(u_AD%rotors(1)%BladeMotion(k)%NNodes))//' mesh points. ' & //'Increase number of AD15 mesh points to at least 50% as many points as the CFD requested.' - call WrScr('OpFM Error: '//trim(ErrMsg2)) + call WrScr('ExtInfw Error: '//trim(ErrMsg2)) call SetErrStat(ErrID_Fatal, ErrMsg2, ErrStat, ErrMsg, RoutineName) return ! if the number of nodes requested from CFD (nNodesForceBlade) is more than double the number of nodes in AD15, issue a warning. - elseif (Opfm%p%nNodesForceBlade > 2 * u_AD%rotors(1)%BladeMotion(1)%NNodes) then - ErrMsg2=trim(Num2LStr(Opfm%p%nNodesForceBlade))//' blade points requested from CFD. AD15 only uses ' & + elseif (ExtInfw%p%nNodesForceBlade > 2 * u_AD%rotors(1)%BladeMotion(1)%NNodes) then + ErrMsg2=trim(Num2LStr(ExtInfw%p%nNodesForceBlade))//' blade points requested from CFD. AD15 only uses ' & //trim(Num2LStr(u_AD%rotors(1)%BladeMotion(k)%NNodes))//' mesh points. This may result in inacurate loads.' - call WrScr('OpFM WARNING: '//trim(ErrMsg2)) + call WrScr('ExtInfw WARNING: '//trim(ErrMsg2)) call SetErrStat(ErrID_Warn, ErrMsg2, ErrStat, ErrMsg, RoutineName) endif @@ -95,114 +95,114 @@ SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, In !--------------------------- ! Hub node (always set) - OpFM%p%nNodesVel = 1 ! Hub is first point always + ExtInfw%p%nNodesVel = 1 ! Hub is first point always ! Blade nodes (always set) - DO k=1,OpFM%p%NumBl - OpFM%p%nNodesVel = OpFM%p%nNodesVel + u_AD%rotors(1)%BladeMotion(k)%NNodes + DO k=1,ExtInfw%p%NumBl + ExtInfw%p%nNodesVel = ExtInfw%p%nNodesVel + u_AD%rotors(1)%BladeMotion(k)%NNodes END DO ! Tower motion - OpFM%p%nNodesVel = OpFM%p%nNodesVel + u_AD%rotors(1)%TowerMotion%NNodes + ExtInfw%p%nNodesVel = ExtInfw%p%nNodesVel + u_AD%rotors(1)%TowerMotion%NNodes ! Nacelle motion if (u_AD%rotors(1)%HubMotion%NNodes > 0) then - OpFM%p%nNodesVel = OpFM%p%nNodesVel + u_AD%rotors(1)%HubMotion%NNodes + ExtInfw%p%nNodesVel = ExtInfw%p%nNodesVel + u_AD%rotors(1)%HubMotion%NNodes endif ! Tail fin nodes if (u_AD%rotors(1)%TFinMotion%NNodes > 0) then - OpFM%p%nNodesVel = OpFM%p%nNodesVel + u_AD%rotors(1)%TFinMotion%NNodes + ExtInfw%p%nNodesVel = ExtInfw%p%nNodesVel + u_AD%rotors(1)%TFinMotion%NNodes endif !--------------------------- ! number of force actuator points from CFD. !--------------------------- - Opfm%p%nNodesForceBlade = InitInp%NumActForcePtsBlade ! from extern CFD - OpFM%p%nNodesForceTower = InitInp%NumActForcePtsTower ! from extern CFD + ExtInfw%p%nNodesForceBlade = InitInp%NumActForcePtsBlade ! from extern CFD + ExtInfw%p%nNodesForceTower = InitInp%NumActForcePtsTower ! from extern CFD ! Hub + blades - OpFM%p%nNodesForce = 1 + OpFM%p%NumBl * Opfm%p%nNodesForceBlade ! +1 for hub - OpFM%p%BladeLength = InitInp%BladeLength + ExtInfw%p%nNodesForce = 1 + ExtInfw%p%NumBl * ExtInfw%p%nNodesForceBlade ! +1 for hub + ExtInfw%p%BladeLength = InitInp%BladeLength ! Tower motion - if ( (u_AD%rotors(1)%TowerMotion%NNodes > 0) .and. (OpFM%p%nNodesForceTower > 0) ) then - OpFM%p%NMappings = OpFM%p%NumBl + 1 - OpFM%p%TowerHeight = InitInp%TowerHeight - OpFM%p%TowerBaseHeight = InitInp%TowerBaseHeight - OpFM%p%nNodesForce = OpFM%p%nNodesForce + OpFM%p%nNodesForceTower + if ( (u_AD%rotors(1)%TowerMotion%NNodes > 0) .and. (ExtInfw%p%nNodesForceTower > 0) ) then + ExtInfw%p%NMappings = ExtInfw%p%NumBl + 1 + ExtInfw%p%TowerHeight = InitInp%TowerHeight + ExtInfw%p%TowerBaseHeight = InitInp%TowerBaseHeight + ExtInfw%p%nNodesForce = ExtInfw%p%nNodesForce + ExtInfw%p%nNodesForceTower else - OpFM%p%NMappings = OpFM%p%NumBl + ExtInfw%p%NMappings = ExtInfw%p%NumBl end if ! FIXME: we are missing the nacelle and tail fin nodes. Add these sometime (may require changes in CFD) !............................................................................................ - ! Allocate arrays and define initial guesses for the OpenFOAM inputs here: + ! Allocate arrays and define initial guesses for the ExternalInflow inputs here: !............................................................................................ ! Motion points (from AD15) - CALL AllocPAry( OpFM%u%pxVel, OpFM%p%nNodesVel, 'pxVel', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%pyVel, OpFM%p%nNodesVel, 'pyVel', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%pzVel, OpFM%p%nNodesVel, 'pzVel', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pxVel, ExtInfw%p%nNodesVel, 'pxVel', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pyVel, ExtInfw%p%nNodesVel, 'pyVel', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pzVel, ExtInfw%p%nNodesVel, 'pzVel', ErrStat2, ErrMsg2 ); if (Failed()) return; ! Force actuator points (large number set by CFD) - CALL AllocPAry( OpFM%u%pxForce, OpFM%p%nNodesForce, 'pxForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%pyForce, OpFM%p%nNodesForce, 'pyForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%pzForce, OpFM%p%nNodesForce, 'pzForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%xdotForce, OpFM%p%nNodesForce, 'xdotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%ydotForce, OpFM%p%nNodesForce, 'ydotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%zdotForce, OpFM%p%nNodesForce, 'zdotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%pOrientation,3*3*OpFM%p%nNodesForce, 'pOrientation', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%fx, OpFM%p%nNodesForce, 'fx', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%fy, OpFM%p%nNodesForce, 'fy', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%fz, OpFM%p%nNodesForce, 'fz', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%momentx, OpFM%p%nNodesForce, 'momentx', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%momenty, OpFM%p%nNodesForce, 'momenty', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%momentz, OpFM%p%nNodesForce, 'momentz', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%u%forceNodesChord, OpFM%p%nNodesForce, 'forceNodesChord', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pxForce, ExtInfw%p%nNodesForce, 'pxForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pyForce, ExtInfw%p%nNodesForce, 'pyForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pzForce, ExtInfw%p%nNodesForce, 'pzForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%xdotForce, ExtInfw%p%nNodesForce, 'xdotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%ydotForce, ExtInfw%p%nNodesForce, 'ydotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%zdotForce, ExtInfw%p%nNodesForce, 'zdotForce', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%pOrientation,3*3*ExtInfw%p%nNodesForce, 'pOrientation', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%fx, ExtInfw%p%nNodesForce, 'fx', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%fy, ExtInfw%p%nNodesForce, 'fy', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%fz, ExtInfw%p%nNodesForce, 'fz', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%momentx, ExtInfw%p%nNodesForce, 'momentx', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%momenty, ExtInfw%p%nNodesForce, 'momenty', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%momentz, ExtInfw%p%nNodesForce, 'momentz', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%u%forceNodesChord, ExtInfw%p%nNodesForce, 'forceNodesChord', ErrStat2, ErrMsg2 ); if (Failed()) return; ! make sure the C versions are synced with these arrays: ! Motion points (from AD15) - OpFM%u%c_obj%pxVel_Len = OpFM%p%nNodesVel; OpFM%u%c_obj%pxVel = C_LOC( OpFM%u%pxVel(1) ) - OpFM%u%c_obj%pyVel_Len = OpFM%p%nNodesVel; OpFM%u%c_obj%pyVel = C_LOC( OpFM%u%pyVel(1) ) - OpFM%u%c_obj%pzVel_Len = OpFM%p%nNodesVel; OpFM%u%c_obj%pzVel = C_LOC( OpFM%u%pzVel(1) ) + ExtInfw%u%c_obj%pxVel_Len = ExtInfw%p%nNodesVel; ExtInfw%u%c_obj%pxVel = C_LOC( ExtInfw%u%pxVel(1) ) + ExtInfw%u%c_obj%pyVel_Len = ExtInfw%p%nNodesVel; ExtInfw%u%c_obj%pyVel = C_LOC( ExtInfw%u%pyVel(1) ) + ExtInfw%u%c_obj%pzVel_Len = ExtInfw%p%nNodesVel; ExtInfw%u%c_obj%pzVel = C_LOC( ExtInfw%u%pzVel(1) ) ! Force actuator points (large number set by CFD) - OpFM%u%c_obj%pxForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%pxForce = C_LOC( OpFM%u%pxForce(1) ) - OpFM%u%c_obj%pyForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%pyForce = C_LOC( OpFM%u%pyForce(1) ) - OpFM%u%c_obj%pzForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%pzForce = C_LOC( OpFM%u%pzForce(1) ) - OpFM%u%c_obj%xdotForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%xdotForce = C_LOC( OpFM%u%xdotForce(1) ) - OpFM%u%c_obj%ydotForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%ydotForce = C_LOC( OpFM%u%ydotForce(1) ) - OpFM%u%c_obj%zdotForce_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%zdotForce = C_LOC( OpFM%u%zdotForce(1) ) - OpFM%u%c_obj%pOrientation_Len = OpFM%p%nNodesForce*3*3; OpFM%u%c_obj%pOrientation = C_LOC( OpFM%u%pOrientation(1) ) - OpFM%u%c_obj%fx_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%fx = C_LOC( OpFM%u%fx(1) ) - OpFM%u%c_obj%fy_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%fy = C_LOC( OpFM%u%fy(1) ) - OpFM%u%c_obj%fz_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%fz = C_LOC( OpFM%u%fz(1) ) - OpFM%u%c_obj%momentx_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%momentx = C_LOC( OpFM%u%momentx(1) ) - OpFM%u%c_obj%momenty_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%momenty = C_LOC( OpFM%u%momenty(1) ) - OpFM%u%c_obj%momentz_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%momentz = C_LOC( OpFM%u%momentz(1) ) - OpFM%u%c_obj%forceNodesChord_Len = OpFM%p%nNodesForce; OpFM%u%c_obj%forceNodesChord = C_LOC( OpFM%u%forceNodesChord(1) ) + ExtInfw%u%c_obj%pxForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%pxForce = C_LOC( ExtInfw%u%pxForce(1) ) + ExtInfw%u%c_obj%pyForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%pyForce = C_LOC( ExtInfw%u%pyForce(1) ) + ExtInfw%u%c_obj%pzForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%pzForce = C_LOC( ExtInfw%u%pzForce(1) ) + ExtInfw%u%c_obj%xdotForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%xdotForce = C_LOC( ExtInfw%u%xdotForce(1) ) + ExtInfw%u%c_obj%ydotForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%ydotForce = C_LOC( ExtInfw%u%ydotForce(1) ) + ExtInfw%u%c_obj%zdotForce_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%zdotForce = C_LOC( ExtInfw%u%zdotForce(1) ) + ExtInfw%u%c_obj%pOrientation_Len = ExtInfw%p%nNodesForce*3*3; ExtInfw%u%c_obj%pOrientation = C_LOC( ExtInfw%u%pOrientation(1) ) + ExtInfw%u%c_obj%fx_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%fx = C_LOC( ExtInfw%u%fx(1) ) + ExtInfw%u%c_obj%fy_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%fy = C_LOC( ExtInfw%u%fy(1) ) + ExtInfw%u%c_obj%fz_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%fz = C_LOC( ExtInfw%u%fz(1) ) + ExtInfw%u%c_obj%momentx_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%momentx = C_LOC( ExtInfw%u%momentx(1) ) + ExtInfw%u%c_obj%momenty_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%momenty = C_LOC( ExtInfw%u%momenty(1) ) + ExtInfw%u%c_obj%momentz_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%momentz = C_LOC( ExtInfw%u%momentz(1) ) + ExtInfw%u%c_obj%forceNodesChord_Len = ExtInfw%p%nNodesForce; ExtInfw%u%c_obj%forceNodesChord = C_LOC( ExtInfw%u%forceNodesChord(1) ) ! initialize the arrays: !----------------------- - OpFM%p%NodeClusterType = InitInp%NodeClusterType + ExtInfw%p%NodeClusterType = InitInp%NodeClusterType ! Create the blade and tower nodes in radial and tower height co-ordinates - call OpFM_CreateActForceBladeTowerNodes(initOut_AD, OpFM%p, OpFM%u, ErrStat2, ErrMsg2); if (Failed()) return; + call ExtInfw_CreateActForceBladeTowerNodes(initOut_AD, ExtInfw%p, ExtInfw%u, ErrStat2, ErrMsg2); if (Failed()) return; ! Interpolates the chord distribution to the force nodes - call OpFM_InterpolateForceNodesChord(initOut_AD, OpFM%p, OpFM%u, ErrStat2, ErrMsg2); if (Failed()) return; + call ExtInfw_InterpolateForceNodesChord(initOut_AD, ExtInfw%p, ExtInfw%u, ErrStat2, ErrMsg2); if (Failed()) return; ! create actuator point motion mesh - call OpFM_CreateActForceMotionsMesh( p_FAST, u_AD, InitInp, OpFM, ErrStat2, ErrMsg2); if (Failed()) return; + call ExtInfw_CreateActForceMotionsMesh( p_FAST, u_AD, InitInp, ExtInfw, ErrStat2, ErrMsg2); if (Failed()) return; !............................................................................................ ! Allocate arrays and set up mappings to point loads (for AD15 only): ! (bjj: note that normally I'd put these things in the FAST_ModuleMapType, but I don't want - ! to add OpenFOAM integrations in the rest fo the code). + ! to add ExternalInflow integrations in the rest fo the code). !............................................................................................ ! Allocate space for mapping data structures - ALLOCATE( OpFM%m%ActForceLoadsPoints(OpFM%p%NMappings), OpFM%m%Line2_to_Point_Loads(OpFM%p%NMappings), OpFM%m%Line2_to_Point_Motions(OpFM%p%NMappings),STAT=ErrStat2); if (Failed2()) return; + ALLOCATE( ExtInfw%m%ActForceLoadsPoints(ExtInfw%p%NMappings), ExtInfw%m%Line2_to_Point_Loads(ExtInfw%p%NMappings), ExtInfw%m%Line2_to_Point_Motions(ExtInfw%p%NMappings),STAT=ErrStat2); if (Failed2()) return; - do k=1,OpFM%p%NMappings - call MeshCopy ( SrcMesh = OpFM%m%ActForceMotionsPoints(k) & - , DestMesh = OpFM%m%ActForceLoadsPoints(k) & + do k=1,ExtInfw%p%NMappings + call MeshCopy ( SrcMesh = ExtInfw%m%ActForceMotionsPoints(k) & + , DestMesh = ExtInfw%m%ActForceLoadsPoints(k) & , CtrlCode = MESH_SIBLING & , IOS = COMPONENT_OUTPUT & , Force = .true. & @@ -210,72 +210,72 @@ SUBROUTINE Init_OpFM( InitInp, p_FAST, AirDens, u_AD, initOut_AD, y_AD, OpFM, In , ErrStat = ErrStat2 & , ErrMess = ErrMsg2 ) if (Failed()) return; - OpFM%m%ActForceLoadsPoints(k)%RemapFlag = .true. + ExtInfw%m%ActForceLoadsPoints(k)%RemapFlag = .true. end do ! Mapping of meshes for blades - DO k=1,OpFM%p%NumBl - call MeshMapCreate( u_AD%rotors(1)%BladeMotion(k), OpFM%m%ActForceMotionsPoints(k), OpFM%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; - call MeshMapCreate( y_AD%rotors(1)%BladeLoad(k), OpFM%m%ActForceLoadsPoints(k), OpFM%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + DO k=1,ExtInfw%p%NumBl + call MeshMapCreate( u_AD%rotors(1)%BladeMotion(k), ExtInfw%m%ActForceMotionsPoints(k), ExtInfw%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + call MeshMapCreate( y_AD%rotors(1)%BladeLoad(k), ExtInfw%m%ActForceLoadsPoints(k), ExtInfw%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2 ); if (Failed()) return; END DO ! Mapping tower - do k=OpFM%p%NumBl+1,OpFM%p%NMappings - call MeshMapCreate( u_AD%rotors(1)%TowerMotion, OpFM%m%ActForceMotionsPoints(k), OpFM%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + do k=ExtInfw%p%NumBl+1,ExtInfw%p%NMappings + call MeshMapCreate( u_AD%rotors(1)%TowerMotion, ExtInfw%m%ActForceMotionsPoints(k), ExtInfw%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; if ( y_AD%rotors(1)%TowerLoad%nnodes > 0 ) then ! we can have an input mesh on the tower without having an output mesh. - call MeshMapCreate( y_AD%rotors(1)%TowerLoad, OpFM%m%ActForceLoadsPoints(k), OpFM%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + call MeshMapCreate( y_AD%rotors(1)%TowerLoad, ExtInfw%m%ActForceLoadsPoints(k), ExtInfw%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2 ); if (Failed()) return; end if end do - call SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat2, ErrMsg2); if (Failed()) return; - OpFM%u%fx = 0.0_ReKi - OpFM%u%fy = 0.0_ReKi - OpFM%u%fz = 0.0_ReKi + call SetExtInfwPositions(p_FAST, u_AD, ExtInfw, ErrStat2, ErrMsg2); if (Failed()) return; + ExtInfw%u%fx = 0.0_ReKi + ExtInfw%u%fy = 0.0_ReKi + ExtInfw%u%fz = 0.0_ReKi !............................................................................................ ! Define system output initializations (set up mesh) here: !............................................................................................ - CALL AllocPAry( OpFM%y%u, OpFM%p%nNodesVel, 'u', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%y%v, OpFM%p%nNodesVel, 'v', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocPAry( OpFM%y%w, OpFM%p%nNodesVel, 'w', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%y%u, ExtInfw%p%nNodesVel, 'u', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%y%v, ExtInfw%p%nNodesVel, 'v', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocPAry( ExtInfw%y%w, ExtInfw%p%nNodesVel, 'w', ErrStat2, ErrMsg2 ); if (Failed()) return; ! make sure the C versions are synced with these arrays - OpFM%y%c_obj%u_Len = OpFM%p%nNodesVel; OpFM%y%c_obj%u = C_LOC( OpFM%y%u(1) ) - OpFM%y%c_obj%v_Len = OpFM%p%nNodesVel; OpFM%y%c_obj%v = C_LOC( OpFM%y%v(1) ) - OpFM%y%c_obj%w_Len = OpFM%p%nNodesVel; OpFM%y%c_obj%w = C_LOC( OpFM%y%w(1) ) + ExtInfw%y%c_obj%u_Len = ExtInfw%p%nNodesVel; ExtInfw%y%c_obj%u = C_LOC( ExtInfw%y%u(1) ) + ExtInfw%y%c_obj%v_Len = ExtInfw%p%nNodesVel; ExtInfw%y%c_obj%v = C_LOC( ExtInfw%y%v(1) ) + ExtInfw%y%c_obj%w_Len = ExtInfw%p%nNodesVel; ExtInfw%y%c_obj%w = C_LOC( ExtInfw%y%w(1) ) !............................................................................................ ! Initialize InflowWind FlowField !............................................................................................ - if (associated(OpFm%m%FlowField)) deallocate(OpFm%m%FlowField) - allocate(OpFm%m%FlowField, stat=ErrStat2) + if (associated(ExtInfw%m%FlowField)) deallocate(ExtInfw%m%FlowField) + allocate(ExtInfw%m%FlowField, stat=ErrStat2) if (ErrStat2 /= 0) then call SetErrStat( ErrID_Fatal, 'Error allocating m%FlowField', ErrStat, ErrMsg, RoutineName ) return end if - + ! Initialize flowfield points type - OpFm%m%FlowField%FieldType = Point_FieldType - Points_InitInput%NumWindPoints = OpFM%p%nNodesVel - call IfW_Points_Init(Points_InitInput, OpFm%m%FlowField%Points, ErrStat2, ErrMsg2); if (Failed()) return + ExtInfw%m%FlowField%FieldType = Point_FieldType + Points_InitInput%NumWindPoints = ExtInfw%p%nNodesVel + call IfW_Points_Init(Points_InitInput, ExtInfw%m%FlowField%Points, ErrStat2, ErrMsg2); if (Failed()) return ! Set pointer to flow field in InitOut - InitOut%FlowField => OpFm%m%FlowField + InitOut%FlowField => ExtInfw%m%FlowField !............................................................................................ ! Define initialization-routine output (including writeOutput array) here: !............................................................................................ CALL AllocAry( InitOut%WriteOutputHdr, 3, 'WriteOutputHdr', ErrStat2, ErrMsg2 ); if (Failed()) return; CALL AllocAry( InitOut%WriteOutputUnt, 3, 'WriteOutputUnt', ErrStat2, ErrMsg2 ); if (Failed()) return; - CALL AllocAry( OpFM%y%WriteOutput, 3, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL AllocAry( ExtInfw%y%WriteOutput, 3, 'WriteOutput', ErrStat2, ErrMsg2 ); if (Failed()) return; InitOut%WriteOutputHdr(1) = 'Wind1VelX'; InitOut%WriteOutputUnt(1) = '(m/s)' InitOut%WriteOutputHdr(2) = 'Wind1VelY'; InitOut%WriteOutputUnt(2) = '(m/s)' InitOut%WriteOutputHdr(3) = 'Wind1VelZ'; InitOut%WriteOutputUnt(3) = '(m/s)' - OpFM%y%WriteOutput = 0.0_ReKi + ExtInfw%y%WriteOutput = 0.0_ReKi - InitOut%Ver = OpFM_Ver + InitOut%Ver = ExtInfw_Ver RETURN contains @@ -291,55 +291,55 @@ logical function Failed2() Failed2 = .false. endif end function Failed2 -END SUBROUTINE Init_OpFM - -SUBROUTINE OpFM_UpdateFlowField(p_FAST, OpFM, ErrStat, ErrMsg) - TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module +END SUBROUTINE Init_ExtInfw +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE ExtInfw_UpdateFlowField(p_FAST, ExtInfw, ErrStat, ErrMsg) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None ErrStat = ErrID_None ErrMsg = "" - OpFM%m%FlowField%Points%Vel(1:size(OpFM%y%u),1) = OpFM%y%u - OpFM%m%FlowField%Points%Vel(1:size(OpFM%y%v),2) = OpFM%y%v - OpFM%m%FlowField%Points%Vel(1:size(OpFM%y%w),3) = OpFM%y%w -END SUBROUTINE OpFM_UpdateFlowField + ExtInfw%m%FlowField%Points%Vel(1:size(ExtInfw%y%u),1) = ExtInfw%y%u + ExtInfw%m%FlowField%Points%Vel(1:size(ExtInfw%y%v),2) = ExtInfw%y%v + ExtInfw%m%FlowField%Points%Vel(1:size(ExtInfw%y%w),3) = ExtInfw%y%w +END SUBROUTINE ExtInfw_UpdateFlowField !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE OpFM_SetInputs( p_FAST, u_AD, y_AD, y_SrvD, OpFM, ErrStat, ErrMsg ) - TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code - TYPE(AD_InputType), INTENT(IN) :: u_AD ! The input meshes (already calculated) from AeroDyn - TYPE(AD_OutputType), INTENT(IN) :: y_AD ! The output meshes (already calculated) from AeroDyn - TYPE(SrvD_OutputType), INTENT(IN) :: y_SrvD ! The outputs of the ServoDyn module (control) - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module +SUBROUTINE ExtInfw_SetInputs( p_FAST, u_AD, y_AD, y_SrvD, ExtInfw, ErrStat, ErrMsg ) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code + TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The input meshes (already calculated) from AeroDyn + TYPE(AD_OutputType), INTENT(IN ) :: y_AD ! The output meshes (already calculated) from AeroDyn + TYPE(SrvD_OutputType), INTENT(IN ) :: y_SrvD ! The outputs of the ServoDyn module (control) + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None ! local variables INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_SetInputs' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_SetInputs' ErrStat = ErrID_None ErrMsg = "" ! set the positions - call SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat2, ErrMsg2) + call SetExtInfwPositions(p_FAST, u_AD, ExtInfw, ErrStat2, ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! set the forces - call SetOpFMForces(p_FAST, u_AD, y_AD, OpFM, ErrStat2, ErrMsg2) + call SetExtInfwForces(p_FAST, u_AD, y_AD, ExtInfw, ErrStat2, ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) -END SUBROUTINE OpFM_SetInputs +END SUBROUTINE ExtInfw_SetInputs !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat, ErrMsg) - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module - TYPE(AD_InputType), INTENT(IN) :: u_AD ! The input meshes (already calculated) from AeroDyn +SUBROUTINE SetExtInfwPositions(p_FAST, u_AD, ExtInfw, ErrStat, ErrMsg) + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module + TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The input meshes (already calculated) from AeroDyn TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! FAST parameter data INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -350,7 +350,7 @@ SUBROUTINE SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat, ErrMsg) INTEGER(IntKi) :: J ! Loops through nodes / elements. INTEGER(IntKi) :: K ! Loops through blades. INTEGER(IntKi) :: Node ! Node number for blade/node on mesh - CHARACTER(*), PARAMETER :: RoutineName = 'SetOpFMPositions' + CHARACTER(*), PARAMETER :: RoutineName = 'SetExtInfwPositions' ErrStat = ErrID_None ErrMsg = "" @@ -361,32 +361,34 @@ SUBROUTINE SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat, ErrMsg) ! Hub Node = 1 if (u_AD%rotors(1)%HubMotion%Committed) then - OpFM%u%pxVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(1,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(1,1), c_float) - OpFM%u%pyVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(2,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(2,1), c_float) - OpFM%u%pzVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(3,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(3,1), c_float) + ExtInfw%u%pxVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(1,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(1,1), c_float) + ExtInfw%u%pyVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(2,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(2,1), c_float) + ExtInfw%u%pzVel(Node) = real(u_AD%rotors(1)%HubMotion%Position(3,1) + u_AD%rotors(1)%HubMotion%TranslationDisp(3,1), c_float) else - OpFM%u%pxVel(Node) = 0.0_c_float - OpFM%u%pyVel(Node) = 0.0_c_float - OpFM%u%pzVel(Node) = 0.0_c_float + ExtInfw%u%pxVel(Node) = 0.0_c_float + ExtInfw%u%pyVel(Node) = 0.0_c_float + ExtInfw%u%pzVel(Node) = 0.0_c_float end if + ! blade nodes DO K = 1,SIZE(u_AD%rotors(1)%BladeMotion) DO J = 1,u_AD%rotors(1)%BladeMotion(k)%nNodes + Node = Node + 1 - OpFM%u%pxVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(1,j) + u_AD%rotors(1)%BladeMotion(k)%Position(1,j), c_float) - OpFM%u%pyVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(2,j) + u_AD%rotors(1)%BladeMotion(k)%Position(2,j), c_float) - OpFM%u%pzVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + u_AD%rotors(1)%BladeMotion(k)%Position(3,j), c_float) + ExtInfw%u%pxVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(1,j) + u_AD%rotors(1)%BladeMotion(k)%Position(1,j), c_float) + ExtInfw%u%pyVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(2,j) + u_AD%rotors(1)%BladeMotion(k)%Position(2,j), c_float) + ExtInfw%u%pzVel(Node) = real(u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + u_AD%rotors(1)%BladeMotion(k)%Position(3,j), c_float) END DO !J = 1,p%BldNodes ! Loop through the blade nodes / elements END DO !K = 1,p%NumBl - if (OpFM%p%NMappings .gt. OpFM%p%NumBl) then + if (ExtInfw%p%NMappings .gt. ExtInfw%p%NumBl) then ! tower nodes DO J=1,u_AD%rotors(1)%TowerMotion%nnodes Node = Node + 1 - OpFM%u%pxVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(1,J) + u_AD%rotors(1)%TowerMotion%Position(1,J), c_float) - OpFM%u%pyVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(2,J) + u_AD%rotors(1)%TowerMotion%Position(2,J), c_float) - OpFM%u%pzVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(3,J) + u_AD%rotors(1)%TowerMotion%Position(3,J), c_float) + ExtInfw%u%pxVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(1,J) + u_AD%rotors(1)%TowerMotion%Position(1,J), c_float) + ExtInfw%u%pyVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(2,J) + u_AD%rotors(1)%TowerMotion%Position(2,J), c_float) + ExtInfw%u%pzVel(Node) = real(u_AD%rotors(1)%TowerMotion%TranslationDisp(3,J) + u_AD%rotors(1)%TowerMotion%Position(3,J), c_float) END DO end if @@ -396,44 +398,46 @@ SUBROUTINE SetOpFMPositions(p_FAST, u_AD, OpFM, ErrStat, ErrMsg) ! Hub Node = 1 if (u_AD%rotors(1)%HubMotion%Committed) then - OpFM%u%pxForce(Node) = OpFM%u%pxVel(Node) - OpFM%u%pyForce(Node) = OpFM%u%pyVel(Node) - OpFM%u%pzForce(Node) = OpFM%u%pzVel(Node) - OpFM%u%pOrientation((Node-1)*9+1:Node*9) = real(pack(u_AD%rotors(1)%HubMotion%Orientation(:,:,1),.true.),c_float) + ExtInfw%u%pxForce(Node) = ExtInfw%u%pxVel(Node) + ExtInfw%u%pyForce(Node) = ExtInfw%u%pyVel(Node) + ExtInfw%u%pzForce(Node) = ExtInfw%u%pzVel(Node) + ExtInfw%u%pOrientation((Node-1)*9+1:Node*9) = real(pack(u_AD%rotors(1)%HubMotion%Orientation(:,:,1),.true.),c_float) else - OpFM%u%pxForce(Node) = 0.0_c_float - OpFM%u%pyForce(Node) = 0.0_c_float - OpFM%u%pzForce(Node) = 0.0_c_float - OpFM%u%pOrientation((Node-1)*9+1:Node*9) = real([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], c_float) + ExtInfw%u%pxForce(Node) = 0.0_c_float + ExtInfw%u%pyForce(Node) = 0.0_c_float + ExtInfw%u%pzForce(Node) = 0.0_c_float + ExtInfw%u%pOrientation((Node-1)*9+1:Node*9) = real([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0], c_float) end if - DO K = 1,OpFM%p%NumBl + + DO K = 1,ExtInfw%p%NumBl ! mesh mapping from line2 mesh to point mesh - call Transfer_Line2_to_Point( u_AD%rotors(1)%BladeMotion(k), OpFM%m%ActForceMotionsPoints(k), OpFM%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + call Transfer_Line2_to_Point( u_AD%rotors(1)%BladeMotion(k), ExtInfw%m%ActForceMotionsPoints(k), ExtInfw%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + - DO J = 1, OpFM%p%nNodesForceBlade + DO J = 1, ExtInfw%p%nNodesForceBlade Node = Node + 1 - OpFM%u%pxForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(1,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(1,J),c_float) - OpFM%u%pyForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(2,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(2,J),c_float) - OpFM%u%pzForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(3,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(3,J),c_float) - OpFM%u%xdotForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%TranslationVel(1,J),c_float) - OpFM%u%ydotForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%TranslationVel(2,J),c_float) - OpFM%u%zdotForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%TranslationVel(3,J),c_float) - OpFM%u%pOrientation((Node-1)*9_1:Node*9) = real(pack(OpFM%m%ActForceMotionsPoints(k)%Orientation(:,:,J),.true.),c_float) + ExtInfw%u%pxForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(1,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(1,J),c_float) + ExtInfw%u%pyForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(2,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(2,J),c_float) + ExtInfw%u%pzForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(3,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(3,J),c_float) + ExtInfw%u%xdotForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%TranslationVel(1,J),c_float) + ExtInfw%u%ydotForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%TranslationVel(2,J),c_float) + ExtInfw%u%zdotForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%TranslationVel(3,J),c_float) + ExtInfw%u%pOrientation((Node-1)*9_1:Node*9) = real(pack(ExtInfw%m%ActForceMotionsPoints(k)%Orientation(:,:,J),.true.),c_float) END DO END DO - if (OpFM%p%NMappings .gt. OpFM%p%NumBl) then - DO K = OpFM%p%NumBl+1,OpFM%p%NMappings - call Transfer_Line2_to_Point( u_AD%rotors(1)%TowerMotion, OpFM%m%ActForceMotionsPoints(k), OpFM%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; + if (ExtInfw%p%NMappings .gt. ExtInfw%p%NumBl) then + DO K = ExtInfw%p%NumBl+1,ExtInfw%p%NMappings + call Transfer_Line2_to_Point( u_AD%rotors(1)%TowerMotion, ExtInfw%m%ActForceMotionsPoints(k), ExtInfw%m%Line2_to_Point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; - DO J=1,OpFM%p%nNodesForceTower + DO J=1,ExtInfw%p%nNodesForceTower Node = Node + 1 - OpFM%u%pxForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(1,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(1,J),c_float) - OpFM%u%pyForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(2,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(2,J),c_float) - OpFM%u%pzForce(Node) = real(OpFM%m%ActForceMotionsPoints(k)%Position(3,J) + OpFM%m%ActForceMotionsPoints(k)%TranslationDisp(3,J),c_float) - OpFM%u%pOrientation((Node-1)*9+1:Node*9) = real(pack(OpFM%m%ActForceMotionsPoints(k)%Orientation(:,:,J),.true.),c_float) + ExtInfw%u%pxForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(1,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(1,J),c_float) + ExtInfw%u%pyForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(2,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(2,J),c_float) + ExtInfw%u%pzForce(Node) = real(ExtInfw%m%ActForceMotionsPoints(k)%Position(3,J) + ExtInfw%m%ActForceMotionsPoints(k)%TranslationDisp(3,J),c_float) + ExtInfw%u%pOrientation((Node-1)*9+1:Node*9) = real(pack(ExtInfw%m%ActForceMotionsPoints(k)%Orientation(:,:,J),.true.),c_float) END DO END DO endif @@ -443,13 +447,13 @@ logical function Failed() CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) Failed = ErrStat >= AbortErrLev end function Failed -END SUBROUTINE SetOpFMPositions +END SUBROUTINE SetExtInfwPositions !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE SetOpFMForces(p_FAST, u_AD, y_AD, OpFM, ErrStat, ErrMsg) - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module - TYPE(AD_InputType), INTENT(IN) :: u_AD ! The input meshes (already calculated) from AeroDyn - TYPE(AD_OutputType), INTENT(IN) :: y_AD ! The output meshes (already calculated) from AeroDyn +SUBROUTINE SetExtInfwForces(p_FAST, u_AD, y_AD, ExtInfw, ErrStat, ErrMsg) + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module + TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The input meshes (already calculated) from AeroDyn + TYPE(AD_OutputType), INTENT(IN ) :: y_AD ! The output meshes (already calculated) from AeroDyn TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! FAST parameter data INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -463,16 +467,16 @@ SUBROUTINE SetOpFMForces(p_FAST, u_AD, y_AD, OpFM, ErrStat, ErrMsg) INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'SetOpFMForces' + CHARACTER(*), PARAMETER :: RoutineName = 'SetExtInfwForces' ErrStat = ErrID_None ErrMsg = '' !------------------------------------------------------------------------------------------------- Node = 1 ! undisplaced hub position (no aerodynamics computed here) - OpFM%u%fx(Node) = 0.0_ReKi - OpFM%u%fy(Node) = 0.0_ReKi - OpFM%u%fz(Node) = 0.0_ReKi + ExtInfw%u%fx(Node) = 0.0_ReKi + ExtInfw%u%fy(Node) = 0.0_ReKi + ExtInfw%u%fz(Node) = 0.0_ReKi !....................... ! blade nodes @@ -488,59 +492,59 @@ SUBROUTINE SetOpFMForces(p_FAST, u_AD, y_AD, OpFM, ErrStat, ErrMsg) write(actForcesFile,*) '#x, y, z, fx, fy, fz' #endif - DO K = 1,OpFM%p%NumBl + DO K = 1,ExtInfw%p%NumBl #ifdef DEBUG_OPENFOAM DO J = 1,u_AD%rotors(1)%BladeMotion(k)%NNodes - write(aerodynForcesFile,*) u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(1,j) + u_AD%rotors(1)%BladeMotion(k)%Position(1,j), ', ', u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(2,j) + u_AD%rotors(1)%BladeMotion(k)%Position(2,j), ', ', u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + u_AD%rotors(1)%BladeMotion(k)%Position(3,j), ', ', OpFM%y%u(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', OpFM%y%v(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', OpFM%y%w(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(1,j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(2,j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(2,j) + write(aerodynForcesFile,*) u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(1,j) + u_AD%rotors(1)%BladeMotion(k)%Position(1,j), ', ', u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(2,j) + u_AD%rotors(1)%BladeMotion(k)%Position(2,j), ', ', u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(3,j) + u_AD%rotors(1)%BladeMotion(k)%Position(3,j), ', ', ExtInfw%y%u(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', ExtInfw%y%v(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', ExtInfw%y%w(1 + (k-1)*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(1,j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(2,j), ', ', y_AD%rotors(1)%BladeLoad(k)%Force(2,j) END DO #endif - call Transfer_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), OpFM%m%ActForceLoadsPoints(k), OpFM%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), OpFM%m%ActForceMotionsPoints(k) ); if (Failed()) return; + call Transfer_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), ExtInfw%m%ActForceLoadsPoints(k), ExtInfw%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), ExtInfw%m%ActForceMotionsPoints(k) ); if (Failed()) return; - DO J = 1, OpFM%p%nNodesForceBlade + DO J = 1, ExtInfw%p%nNodesForceBlade Node = Node + 1 - OpFM%u%fx(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(1,j) - OpFM%u%fy(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(2,j) - OpFM%u%fz(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(3,j) - OpFM%u%momentx(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(1,j) - OpFM%u%momenty(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(2,j) - OpFM%u%momentz(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(3,j) + ExtInfw%u%fx(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(1,j) + ExtInfw%u%fy(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(2,j) + ExtInfw%u%fz(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(3,j) + ExtInfw%u%momentx(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(1,j) + ExtInfw%u%momenty(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(2,j) + ExtInfw%u%momentz(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(3,j) #ifdef DEBUG_OPENFOAM - write(actForcesFile,*) OpFM%u%pxForce(Node), ', ', OpFM%u%pyForce(Node), ', ', OpFM%u%pzForce(Node), ', ', OpFM%u%fx(Node), ', ', OpFM%u%fy(Node), ', ', OpFM%u%fz(Node), ', ' + write(actForcesFile,*) ExtInfw%u%pxForce(Node), ', ', ExtInfw%u%pyForce(Node), ', ', ExtInfw%u%pzForce(Node), ', ', ExtInfw%u%fx(Node), ', ', ExtInfw%u%fy(Node), ', ', ExtInfw%u%fz(Node), ', ' #endif END DO - END DO !K = 1,OpFM%p%NumBl + END DO !K = 1,ExtInfw%p%NumBl !....................... ! tower nodes !....................... - if (OpFM%p%NMappings .gt. OpFM%p%NumBl) then + if (ExtInfw%p%NMappings .gt. ExtInfw%p%NumBl) then ! mesh mapping from line2 mesh to point mesh - DO K = OpFM%p%NumBl+1,OpFM%p%NMappings + DO K = ExtInfw%p%NumBl+1,ExtInfw%p%NMappings #ifdef DEBUG_OPENFOAM DO J = 1,u_AD%rotors(1)%TowerMotion%NNodes - write(aerodynForcesFile,*) u_AD%rotors(1)%TowerMotion%TranslationDisp(1,j) + u_AD%rotors(1)%TowerMotion%Position(1,j), ', ', u_AD%rotors(1)%TowerMotion%TranslationDisp(2,j) + u_AD%rotors(1)%TowerMotion%Position(2,j), ', ', u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) + u_AD%rotors(1)%TowerMotion%Position(3,j), ', ', OpFM%y%u(1 + OpFM%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', OpFM%y%v(1 + OpFM%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', OpFM%y%w(1 + OpFM%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', y_AD%rotors(1)%TowerLoad%Force(1,j), ', ', y_AD%rotors(1)%TowerLoad%Force(2,j), ', ', y_AD%rotors(1)%TowerLoad%Force(2,j) + write(aerodynForcesFile,*) u_AD%rotors(1)%TowerMotion%TranslationDisp(1,j) + u_AD%rotors(1)%TowerMotion%Position(1,j), ', ', u_AD%rotors(1)%TowerMotion%TranslationDisp(2,j) + u_AD%rotors(1)%TowerMotion%Position(2,j), ', ', u_AD%rotors(1)%TowerMotion%TranslationDisp(3,j) + u_AD%rotors(1)%TowerMotion%Position(3,j), ', ', ExtInfw%y%u(1 + ExtInfw%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', ExtInfw%y%v(1 + ExtInfw%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', ExtInfw%y%w(1 + ExtInfw%p%NumBl*u_AD%rotors(1)%BladeMotion(k)%NNodes + j), ', ', y_AD%rotors(1)%TowerLoad%Force(1,j), ', ', y_AD%rotors(1)%TowerLoad%Force(2,j), ', ', y_AD%rotors(1)%TowerLoad%Force(2,j) END DO #endif - call Transfer_Line2_to_Point( y_AD%rotors(1)%TowerLoad, OpFM%m%ActForceLoadsPoints(k), OpFM%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%TowerMotion, OpFM%m%ActForceMotionsPoints(k) ); if (Failed()) return; + call Transfer_Line2_to_Point( y_AD%rotors(1)%TowerLoad, ExtInfw%m%ActForceLoadsPoints(k), ExtInfw%m%Line2_to_Point_Loads(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%TowerMotion, ExtInfw%m%ActForceMotionsPoints(k) ); if (Failed()) return; - DO J=1,OpFM%p%nNodesForceTower + DO J=1,ExtInfw%p%nNodesForceTower Node = Node + 1 - OpFM%u%fx(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(1,j) - OpFM%u%fy(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(2,j) - OpFM%u%fz(Node) = OpFM%m%ActForceLoadsPoints(k)%Force(3,j) - OpFM%u%momentx(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(1,j) - OpFM%u%momenty(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(2,j) - OpFM%u%momentz(Node) = OpFM%m%ActForceLoadsPoints(k)%Moment(3,j) + ExtInfw%u%fx(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(1,j) + ExtInfw%u%fy(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(2,j) + ExtInfw%u%fz(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Force(3,j) + ExtInfw%u%momentx(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(1,j) + ExtInfw%u%momenty(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(2,j) + ExtInfw%u%momentz(Node) = ExtInfw%m%ActForceLoadsPoints(k)%Moment(3,j) #ifdef DEBUG_OPENFOAM - write(actForcesFile,*) OpFM%u%pxForce(Node), ', ', OpFM%u%pyForce(Node), ', ', OpFM%u%pzForce(Node), ', ', OpFM%u%fx(Node), ', ', OpFM%u%fy(Node), ', ', OpFM%u%fz(Node), ', ' + write(actForcesFile,*) ExtInfw%u%pxForce(Node), ', ', ExtInfw%u%pyForce(Node), ', ', ExtInfw%u%pzForce(Node), ', ', ExtInfw%u%fx(Node), ', ', ExtInfw%u%fy(Node), ', ', ExtInfw%u%fz(Node), ', ' #endif END DO @@ -557,32 +561,32 @@ logical function Failed() CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) Failed = ErrStat >= AbortErrLev end function Failed -END SUBROUTINE SetOpFMForces +END SUBROUTINE SetExtInfwForces !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE OpFM_SetWriteOutput( OpFM ) - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module +SUBROUTINE ExtInfw_SetWriteOutput( ExtInfw ) + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module ! set the hub-height wind speeds - IF ( ALLOCATED( OpFM%y%WriteOutput ) ) THEN - IF ( ASSOCIATED( OpFM%y%u ) ) then - OpFM%y%WriteOutput(1) = OpFM%y%u(1) - OpFM%y%WriteOutput(2) = OpFM%y%v(1) - OpFM%y%WriteOutput(3) = OpFM%y%w(1) + IF ( ALLOCATED( ExtInfw%y%WriteOutput ) ) THEN + IF ( ASSOCIATED( ExtInfw%y%u ) ) then + ExtInfw%y%WriteOutput(1) = ExtInfw%y%u(1) + ExtInfw%y%WriteOutput(2) = ExtInfw%y%v(1) + ExtInfw%y%WriteOutput(3) = ExtInfw%y%w(1) END IF END IF -END SUBROUTINE OpFM_SetWriteOutput +END SUBROUTINE ExtInfw_SetWriteOutput !---------------------------------------------------------------------------------------------------------------------------------- !> Create the actuator line force point mesh -SUBROUTINE OpFM_CreateActForceMotionsMesh( p_FAST, u_AD, InitIn_OpFM, OpFM, ErrStat, ErrMsg ) - TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code - TYPE(AD_InputType), INTENT(IN) :: u_AD ! The input meshes (already calculated) from AeroDyn - TYPE(OpFM_InitInputType), INTENT(IN ) :: InitIn_OpFM ! InitInp data for the OpenFOAM integration module - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM ! data for the OpenFOAM integration module - INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None +SUBROUTINE ExtInfw_CreateActForceMotionsMesh( p_FAST, u_AD, InitIn_ExtInfw, ExtInfw, ErrStat, ErrMsg ) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code + TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The input meshes (already calculated) from AeroDyn + TYPE(ExtInfw_InitInputType), INTENT(IN ) :: InitIn_ExtInfw ! InitInp data for the ExternalInflow integration module + TYPE(ExternalInflow_Data), INTENT(INOUT) :: ExtInfw ! data for the ExternalInflow integration module + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None ! local variables TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: tmpActForceMotionsMesh !< temporary mesh for interpolating orientation to actuator force points [-] @@ -590,25 +594,25 @@ SUBROUTINE OpFM_CreateActForceMotionsMesh( p_FAST, u_AD, InitIn_OpFM, OpFM, ErrS INTEGER(IntKi) :: j ! node counter INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_CreateActForceMotionsMesh' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_CreateActForceMotionsMesh' ! Initialize variables ErrStat = ErrID_None ErrMsg = "" ! Allocate space for mapping data structures - ALLOCATE(tmpActForceMotionsMesh(OpFM%p%NMappings) , STAT=ErrStat2); if (Failed2()) return; - ALLOCATE(OpFM%m%ActForceMotionsPoints(OpFM%p%NMappings), STAT=ErrStat2); if (Failed2()) return; + ALLOCATE(tmpActForceMotionsMesh(ExtInfw%p%NMappings) , STAT=ErrStat2); if (Failed2()) return; + ALLOCATE(ExtInfw%m%ActForceMotionsPoints(ExtInfw%p%NMappings), STAT=ErrStat2); if (Failed2()) return; ! create a temporary mesh with the correct orientation info (stored in Orientation). This is then stored as the RefOrientation on the real mesh. ! ADP: this is a clever method @gantech came up with to interpolate orientations from one mesh to a finer mesh. - CALL OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, OpFM%p, InitIn_OpFM, tmpActForceMotionsMesh, ErrStat2, ErrMsg2 ); if (Failed()) return; + CALL ExtInfw_CreateTmpActForceMotionsMesh( p_FAST, u_AD, ExtInfw%p, InitIn_ExtInfw, tmpActForceMotionsMesh, ErrStat2, ErrMsg2 ); if (Failed()) return; !------- ! Blades - DO k=1,OpFM%p%NumBl - call MeshCreate ( BlankMesh = OpFM%m%ActForceMotionsPoints(k) & + DO k=1,ExtInfw%p%NumBl + call MeshCreate ( BlankMesh = ExtInfw%m%ActForceMotionsPoints(k) & ,IOS = COMPONENT_INPUT & - ,nNodes = OpFM%p%nNodesForceBlade & + ,nNodes = ExtInfw%p%nNodesForceBlade & ,Orientation = .true. & ,TranslationDisp = .true. & ,TranslationVel = .true. & @@ -617,24 +621,24 @@ SUBROUTINE OpFM_CreateActForceMotionsMesh( p_FAST, u_AD, InitIn_OpFM, OpFM, ErrS ,ErrMess = ErrMsg2 & ) if (Failed()) return; - OpFM%m%ActForceMotionsPoints(k)%RemapFlag = .false. + ExtInfw%m%ActForceMotionsPoints(k)%RemapFlag = .false. - do j=1,OpFM%p%nNodesForceBlade + do j=1,ExtInfw%p%nNodesForceBlade ! Use the temp mesh Orientation info as the RefOrientation for this mesh. - call MeshPositionNode(OpFM%m%ActForceMotionsPoints(k), j, tmpActForceMotionsMesh(k)%position(:,j), errStat2, errMsg2, orient=tmpActForceMotionsMesh(k)%Orientation(:,:,j)); if (Failed()) return; - call MeshConstructElement(OpFM%m%ActForceMotionsPoints(k), ELEMENT_POINT, errStat2, errMsg2, p1=j ); if (Failed()) return; + call MeshPositionNode(ExtInfw%m%ActForceMotionsPoints(k), j, tmpActForceMotionsMesh(k)%position(:,j), errStat2, errMsg2, orient=tmpActForceMotionsMesh(k)%Orientation(:,:,j)); if (Failed()) return; + call MeshConstructElement(ExtInfw%m%ActForceMotionsPoints(k), ELEMENT_POINT, errStat2, errMsg2, p1=j ); if (Failed()) return; end do !j - call MeshCommit(OpFM%m%ActForceMotionsPoints(k), errStat2, errMsg2 ); if (Failed()) return; + call MeshCommit(ExtInfw%m%ActForceMotionsPoints(k), errStat2, errMsg2 ); if (Failed()) return; END DO !------ ! Tower - if (OpFM%p%NMappings .gt. OpFM%p%NumBl) then - DO k=OpFM%p%NumBl+1,OpFM%p%NMappings - call MeshCreate ( BlankMesh = OpFM%m%ActForceMotionsPoints(k) & + if (ExtInfw%p%NMappings .gt. ExtInfw%p%NumBl) then + DO k=ExtInfw%p%NumBl+1,ExtInfw%p%NMappings + call MeshCreate ( BlankMesh = ExtInfw%m%ActForceMotionsPoints(k) & ,IOS = COMPONENT_INPUT & - ,nNodes = OpFM%p%nNodesForceTower & + ,nNodes = ExtInfw%p%nNodesForceTower & ,Orientation = .true. & ,TranslationDisp = .true. & ,TranslationVel = .true. & @@ -643,13 +647,13 @@ SUBROUTINE OpFM_CreateActForceMotionsMesh( p_FAST, u_AD, InitIn_OpFM, OpFM, ErrS ,ErrMess = ErrMsg2 & ) if (Failed()) return; - OpFM%m%ActForceMotionsPoints(k)%RemapFlag = .false. + ExtInfw%m%ActForceMotionsPoints(k)%RemapFlag = .false. - do j=1,OpFM%p%nNodesForceTower - call MeshPositionNode(OpFM%m%ActForceMotionsPoints(k), j, tmpActForceMotionsMesh(k)%position(:,j), errStat2, errMsg2, orient=tmpActForceMotionsMesh(k)%Orientation(:,:,j)); if (Failed()) return; - call MeshConstructElement(OpFM%m%ActForceMotionsPoints(k), ELEMENT_POINT, errStat2, errMsg2, p1=j); if (Failed()) return; + do j=1,ExtInfw%p%nNodesForceTower + call MeshPositionNode(ExtInfw%m%ActForceMotionsPoints(k), j, tmpActForceMotionsMesh(k)%position(:,j), errStat2, errMsg2, orient=tmpActForceMotionsMesh(k)%Orientation(:,:,j)); if (Failed()) return; + call MeshConstructElement(ExtInfw%m%ActForceMotionsPoints(k), ELEMENT_POINT, errStat2, errMsg2, p1=j); if (Failed()) return; end do !j - call MeshCommit(OpFM%m%ActForceMotionsPoints(k), errStat2, errMsg2 ); if (Failed()) return; + call MeshCommit(ExtInfw%m%ActForceMotionsPoints(k), errStat2, errMsg2 ); if (Failed()) return; END DO endif @@ -665,7 +669,7 @@ end function Failed subroutine Cleanup() ! NOTE: don't trap errors here if (allocated(tmpActForceMotionsMesh)) then - do k=1,OpFM%p%NMappings + do k=1,ExtInfw%p%NMappings call MeshDestroy ( tmpActForceMotionsMesh(k), ErrStat2, ErrMsg2 ) end do deallocate(tmpActForceMotionsMesh) @@ -680,17 +684,17 @@ logical function Failed2() Failed2 = .false. endif end function Failed2 -END SUBROUTINE OpFM_CreateActForceMotionsMesh +END SUBROUTINE ExtInfw_CreateActForceMotionsMesh !---------------------------------------------------------------------------------------------------------------------------------- !> this routine is used to create a temporary mesh with the number of points requested by CFD using the AD15 blade definition. This !! mesh is then used as an intermediate to interpolate the AD15 orientations over using mesh mapping. This routine only exists to !! facilitate the orientation calculations. -SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, tmpActForceMotions, ErrStat, ErrMsg ) +SUBROUTINE ExtInfw_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_ExtInfw, InitIn_ExtInfw, tmpActForceMotions, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code - TYPE(AD_InputType), INTENT(IN) :: u_AD ! The input meshes (already calculated) from AeroDyn - TYPE(OpFM_ParameterType), INTENT(IN ) :: p_OpFM ! data for the OpenFOAM integration module - TYPE(OpFM_InitInputType), INTENT(IN ) :: InitIn_OpFM ! InitInp data for the OpenFOAM integration module + TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The input meshes (already calculated) from AeroDyn + TYPE(ExtInfw_ParameterType), INTENT(IN ) :: p_ExtInfw ! data for the ExternalInflow integration module + TYPE(ExtInfw_InitInputType), INTENT(IN ) :: InitIn_ExtInfw ! InitInp data for the ExternalInflow integration module TYPE(MeshType), INTENT(INOUT) :: tmpActForceMotions(:) ! temporary mesh to create the actuator force nodes INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -704,25 +708,25 @@ SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, INTEGER(IntKi) :: j ! node counter INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_CreateTmpActForceMotionsMesh' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_CreateTmpActForceMotionsMesh' ! Initialize variables ErrStat = ErrID_None ErrMsg = "" ! Make a copy of the Structural model mesh with the reference orientation set to zero - ALLOCATE(tmp_StructModelMesh(p_OpFM%NMappings) , STAT=ErrStat2); if (Failed2()) return; - CALL CreateTmpStructModelMesh(p_FAST, u_AD, p_OpFM, tmp_StructModelMesh, ErrStat2, ErrMsg2 ); if (Failed()) return; + ALLOCATE(tmp_StructModelMesh(p_ExtInfw%NMappings) , STAT=ErrStat2); if (Failed2()) return; + CALL CreateTmpStructModelMesh(p_FAST, u_AD, p_ExtInfw, tmp_StructModelMesh, ErrStat2, ErrMsg2 ); if (Failed()) return; ! Allocate space for mapping data structures - ALLOCATE( tmp_line2_to_point_Motions(p_OpFM%NMappings),STAT=ErrStat2); if (Failed2()) return; + ALLOCATE( tmp_line2_to_point_Motions(p_ExtInfw%NMappings),STAT=ErrStat2); if (Failed2()) return; ! Blade nodes - call AllocAry(forceNodePositions, 3, p_OpFM%nNodesForceBlade, "forceNodePositions", ErrStat2, ErrMsg2); if (Failed()) return; - DO k=1,p_OpFM%NumBl + call AllocAry(forceNodePositions, 3, p_ExtInfw%nNodesForceBlade, "forceNodePositions", ErrStat2, ErrMsg2); if (Failed()) return; + DO k=1,p_ExtInfw%NumBl call MeshCreate ( BlankMesh = tmpActForceMotions(k) & , IOS = COMPONENT_INPUT & - , nNodes = p_OpFM%nNodesForceBlade & + , nNodes = p_ExtInfw%nNodesForceBlade & , ErrStat = ErrStat2 & , ErrMess = ErrMsg2 & , force = .false. & @@ -732,8 +736,8 @@ SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, if (Failed()) return; tmpActForceMotions(k)%RemapFlag = .false. - call CalcForceActuatorPositionsBlade(InitIn_OpFM, p_OpFM, tmp_StructModelMesh(k)%position, forceNodePositions, errStat2, errMsg2); if (Failed()) return; - do j=1,p_OpFM%nNodesForceBlade + call CalcForceActuatorPositionsBlade(InitIn_ExtInfw, p_ExtInfw, tmp_StructModelMesh(k)%position, forceNodePositions, errStat2, errMsg2); if (Failed()) return; + do j=1,p_ExtInfw%nNodesForceBlade call MeshPositionNode(tmpActForceMotions(k), j, forceNodePositions(:,j), errStat2, errMsg2); if (Failed()) return; call MeshConstructElement( tmpActForceMotions(k), ELEMENT_POINT, errStat2, errMsg2, p1=j ); if (Failed()) return; end do !j @@ -744,14 +748,14 @@ SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, if (allocated(forceNodePositions)) deallocate(forceNodePositions) ! Free space ! Tower nodes - if (p_OpFM%NMappings .gt. p_OpFM%NumBl) then - call AllocAry(forceNodePositions, 3, p_OpFM%nNodesForceTower, "forceNodePositions", ErrStat2, ErrMsg2); if (Failed()) return; - DO k=p_OpFM%NumBl+1,p_OpFM%NMappings - call CalcForceActuatorPositionsTower(InitIn_OpFM, p_OpFM, tmp_StructModelMesh(k)%position, forceNodePositions, errStat2, errMsg2); if (Failed()) return; + if (p_ExtInfw%NMappings .gt. p_ExtInfw%NumBl) then + call AllocAry(forceNodePositions, 3, p_ExtInfw%nNodesForceTower, "forceNodePositions", ErrStat2, ErrMsg2); if (Failed()) return; + DO k=p_ExtInfw%NumBl+1,p_ExtInfw%NMappings + call CalcForceActuatorPositionsTower(InitIn_ExtInfw, p_ExtInfw, tmp_StructModelMesh(k)%position, forceNodePositions, errStat2, errMsg2); if (Failed()) return; call MeshCreate ( BlankMesh = tmpActForceMotions(k) & ,IOS = COMPONENT_INPUT & - ,nNodes = p_OpFM%nNodesForceTower & + ,nNodes = p_ExtInfw%nNodesForceTower & ,ErrStat = ErrStat2 & ,ErrMess = ErrMsg2 & ,force = .false. & @@ -761,7 +765,7 @@ SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, if (Failed()) return; tmpActForceMotions(k)%RemapFlag = .false. - do j=1,p_OpFM%nNodesForceTower + do j=1,p_ExtInfw%nNodesForceTower call MeshPositionNode(tmpActForceMotions(k), j, forceNodePositions(:,j), errStat2, errMsg2); if (Failed()) return; call MeshConstructElement( tmpActForceMotions(k), ELEMENT_POINT, errStat2, errMsg2, p1=j ); if (Failed()) return; end do !j @@ -772,18 +776,18 @@ SUBROUTINE OpFM_CreateTmpActForceMotionsMesh( p_FAST, u_AD, p_OpFM, InitIn_OpFM, endif ! create the mapping data structures: - DO k=1,p_OpFM%NumBl + DO k=1,p_ExtInfw%NumBl call MeshMapCreate( tmp_StructModelMesh(k), tmpActForceMotions(k), tmp_line2_to_point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; END DO - if (p_OpFM%NMappings .gt. p_OpFM%NumBl) then - DO k=p_OpFM%NumBl+1,p_OpFM%NMappings + if (p_ExtInfw%NMappings .gt. p_ExtInfw%NumBl) then + DO k=p_ExtInfw%NumBl+1,p_ExtInfw%NMappings call MeshMapCreate( tmp_StructModelMesh(k), tmpActForceMotions(k), tmp_line2_to_point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; END DO endif ! Map the orientation - DO K = 1,p_OpFM%NMappings + DO K = 1,p_ExtInfw%NMappings ! mesh mapping from line2 mesh to point mesh call Transfer_Line2_to_Point( tmp_StructModelMesh(k), tmpActForceMotions(k), tmp_line2_to_point_Motions(k), ErrStat2, ErrMsg2 ); if (Failed()) return; END DO @@ -801,7 +805,7 @@ end function Failed subroutine Cleanup() ! NOTE: don't trap errors here if (allocated(forceNodePositions)) deallocate(forceNodePositions) - DO k=1,p_OpFM%NMappings + DO k=1,p_ExtInfw%NMappings call MeshDestroy ( tmp_StructModelMesh(k), ErrStat2, ErrMsg2 ) call MeshMapDestroy ( tmp_line2_to_point_Motions(k), ErrStat2, ErrMsg2 ) end do @@ -817,15 +821,15 @@ logical function Failed2() Failed2 = .false. endif end function Failed2 -END SUBROUTINE OpFM_CreateTmpActForceMotionsMesh +END SUBROUTINE ExtInfw_CreateTmpActForceMotionsMesh !---------------------------------------------------------------------------------------------------------------------------------- !> A temporary mesh is a copy of the AD15 mesh with the RefOrientation set to identity, and Orientation set to the AD15 RefOrientation. !! This is used to map orientations over to a more refined mesh. -SUBROUTINE CreateTmpStructModelMesh(p_FAST, u_AD, p_OpFM, tmpBladeMesh, ErrStat, ErrMsg ) +SUBROUTINE CreateTmpStructModelMesh(p_FAST, u_AD, p_ExtInfw, tmpBladeMesh, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST ! Parameters for the glue code TYPE(AD_InputType), INTENT(IN ) :: u_AD ! The inputs for AD15 - TYPE(OpFM_ParameterType), INTENT(IN ) :: p_OpFM ! Parameters of the OpenFOAM integration module + TYPE(ExtInfw_ParameterType), INTENT(IN ) :: p_ExtInfw ! Parameters of the ExternalInflow integration module TYPE(MeshType), INTENT(INOUT) :: tmpBladeMesh(:) ! temporary copy of structural model mesh INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -838,7 +842,7 @@ SUBROUTINE CreateTmpStructModelMesh(p_FAST, u_AD, p_OpFM, tmpBladeMesh, ErrStat, CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None CHARACTER(*), PARAMETER :: RoutineName = 'CreateTmpStructModelMesh' - DO K = 1,p_OpFM%NumBl + DO K = 1,p_ExtInfw%NumBl nNodes = u_AD%rotors(1)%BladeMotion(K)%nNodes CALL MeshCreate( BlankMesh = tmpBladeMesh(K) & , NNodes = nNodes & @@ -874,8 +878,8 @@ SUBROUTINE CreateTmpStructModelMesh(p_FAST, u_AD, p_OpFM, tmpBladeMesh, ErrStat, END DO END DO - if (p_OpFM%NMappings .gt. p_OpFM%NumBl) then - DO K = p_OpFM%NumBl+1, p_OpFM%NMappings + if (p_ExtInfw%NMappings .gt. p_ExtInfw%NumBl) then + DO K = p_ExtInfw%NumBl+1, p_ExtInfw%NMappings nNodes = u_AD%rotors(1)%TowerMotion%nNodes CALL MeshCreate( BlankMesh = tmpBladeMesh(K) & , NNodes = nNodes & @@ -920,13 +924,13 @@ end function Failed END SUBROUTINE CreateTmpStructModelMesh !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE CalcForceActuatorPositionsBlade(InitIn_OpFM, p_OpFM, structPositions, forceNodePositions, ErrStat, ErrMsg) - TYPE(OpFM_InitInputType), INTENT(IN ) :: InitIn_OpFM ! data for the OpenFOAM integration module - TYPE(OpFM_ParameterType), INTENT(IN ) :: p_OpFM ! data for the OpenFOAM integration module - REAL(ReKi), POINTER :: structPositions(:,:) ! structural model positions - REAL(ReKi), INTENT(INOUT) :: forceNodePositions(:,:) ! Array to store the newly created positions - INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation - CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None +SUBROUTINE CalcForceActuatorPositionsBlade(InitIn_ExtInfw, p_ExtInfw, structPositions, forceNodePositions, ErrStat, ErrMsg) + TYPE(ExtInfw_InitInputType), INTENT(IN ) :: InitIn_ExtInfw ! data for the ExternalInflow integration module + TYPE(ExtInfw_ParameterType), INTENT(IN ) :: p_ExtInfw ! data for the ExternalInflow integration module + REAL(ReKi), POINTER, INTENT(IN ) :: structPositions(:,:) ! structural model positions + REAL(ReKi), INTENT(INOUT) :: forceNodePositions(:,:) ! Array to store the newly created positions + INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None !Local variables INTEGER(IntKi) :: nStructNodes ! Number of velocity nodes @@ -945,21 +949,21 @@ SUBROUTINE CalcForceActuatorPositionsBlade(InitIn_OpFM, p_OpFM, structPositions, call AllocAry(rStructNodes, nStructNodes, "rStructNodes", ErrStat2, ErrMsg2); if (Failed()) return; ! Store the distance of the structural model nodes from the root into an array (from AD15 blade defenition) - rStructNodes(:) = InitIn_OpFM%StructBldRnodes(:) + rStructNodes(:) = InitIn_ExtInfw%StructBldRnodes(:) ! Now calculate the positions of the force nodes based on interpolation ! NOTE: the InterpArray function from the NWTC Library could be used here instead. This interpolation will eventually be removed, so we won't update it here. forceNodePositions(:,1) = structPositions(:,1) - DO I=2,p_OpFM%nNodesForceBlade-1 ! Calculate the position of the force nodes + DO I=2,p_ExtInfw%nNodesForceBlade-1 ! Calculate the position of the force nodes do jLower = 1, (nStructNodes - 1) - if ((rStructNodes(jLower) - p_OpFM%forceBldRnodes(I))*(rStructNodes(jLower+1) - p_OpFM%forceBldRnodes(I)) .le. 0) then + if ((rStructNodes(jLower) - p_ExtInfw%forceBldRnodes(I))*(rStructNodes(jLower+1) - p_ExtInfw%forceBldRnodes(I)) .le. 0) then exit endif end do - rInterp = (p_OpFM%forceBldRnodes(I) - rStructNodes(jLower))/(rStructNodes(jLower+1)-rStructNodes(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes + rInterp = (p_ExtInfw%forceBldRnodes(I) - rStructNodes(jLower))/(rStructNodes(jLower+1)-rStructNodes(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes forceNodePositions(:,I) = structPositions(:,jLower) + rInterp * (structPositions(:,jLower+1) - structPositions(:,jLower)) END DO - forceNodePositions(:,p_OpFM%nNodesForceBlade) = structPositions(:,nStructNodes) + forceNodePositions(:,p_ExtInfw%nNodesForceBlade) = structPositions(:,nStructNodes) if (allocated(rStructNodes)) deallocate(rStructNodes) @@ -973,13 +977,13 @@ end function Failed END SUBROUTINE CalcForceActuatorPositionsBlade !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE CalcForceActuatorPositionsTower(InitIn_OpFM, p_OpFM, structPositions, forceNodePositions, ErrStat, ErrMsg) - TYPE(OpFM_InitInputType), INTENT(IN ) :: InitIn_OpFM ! data for the OpenFOAM integration module - TYPE(OpFM_ParameterType), INTENT(IN ) :: p_OpFM ! data for the OpenFOAM integration module - REAL(ReKi), POINTER :: structPositions(:,:) ! structural model positions - REAL(ReKi), INTENT(INOUT) :: forceNodePositions(:,:) ! Array to store the newly created positions - INTEGER(IntKi) , intent(out) :: ErrStat ! temporary Error status of the operation - CHARACTER(ErrMsgLen) , intent(out) :: ErrMsg ! temporary Error message if ErrStat /= ErrID_None +SUBROUTINE CalcForceActuatorPositionsTower(InitIn_ExtInfw, p_ExtInfw, structPositions, forceNodePositions, ErrStat, ErrMsg) + TYPE(ExtInfw_InitInputType), INTENT(IN ) :: InitIn_ExtInfw ! data for the ExternalInflow integration module + TYPE(ExtInfw_ParameterType), INTENT(IN ) :: p_ExtInfw ! data for the ExternalInflow integration module + REAL(ReKi), POINTER, INTENT(IN ) :: structPositions(:,:) ! structural model positions + REAL(ReKi), INTENT(INOUT) :: forceNodePositions(:,:) ! Array to store the newly created positions + INTEGER(IntKi) , intent( out) :: ErrStat ! temporary Error status of the operation + CHARACTER(ErrMsgLen) , intent( out) :: ErrMsg ! temporary Error message if ErrStat /= ErrID_None !Local variables INTEGER(IntKi) :: nStructNodes ! Number of velocity nodes @@ -998,22 +1002,22 @@ SUBROUTINE CalcForceActuatorPositionsTower(InitIn_OpFM, p_OpFM, structPositions, call AllocAry(hStructNodes, nStructNodes, "hStructNodes", ErrStat2, ErrMsg2); if (Failed()) return; ! Store the distance of the structural model nodes from the root into an array - hStructNodes(:) = InitIn_OpFM%StructTwrHnodes(:) - hStructNodes(nStructNodes) = p_OpFM%TowerHeight+p_OpFM%TowerBaseHeight + hStructNodes(:) = InitIn_ExtInfw%StructTwrHnodes(:) + hStructNodes(nStructNodes) = p_ExtInfw%TowerHeight+p_ExtInfw%TowerBaseHeight ! Now calculate the positions of the force nodes based on interpolation ! NOTE: the InterpArray function from the NWTC Library could be used here instead. This interpolation will eventually be removed, so we won't update it here. forceNodePositions(:,1) = structPositions(:,1) - DO I=2,p_OpFM%nNodesForceTower-1 ! Calculate the position of the force nodes + DO I=2,p_ExtInfw%nNodesForceTower-1 ! Calculate the position of the force nodes do jLower = 1, (nStructNodes - 1) - if ((hStructNodes(jLower) - (p_OpFM%forceTwrHnodes(I)+p_OpFM%TowerBaseHeight))*(hStructNodes(jLower+1) - (p_OpFM%forceTwrHnodes(I)+p_OpFM%TowerBaseHeight)) .le. 0) then + if ((hStructNodes(jLower) - (p_ExtInfw%forceTwrHnodes(I)+p_ExtInfw%TowerBaseHeight))*(hStructNodes(jLower+1) - (p_ExtInfw%forceTwrHnodes(I)+p_ExtInfw%TowerBaseHeight)) .le. 0) then exit endif enddo - hInterp = (p_OpFM%forceTwrHnodes(I)+p_OpFM%TowerBaseHeight - hStructNodes(jLower))/(hStructNodes(jLower+1)-hStructNodes(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes + hInterp = (p_ExtInfw%forceTwrHnodes(I)+p_ExtInfw%TowerBaseHeight - hStructNodes(jLower))/(hStructNodes(jLower+1)-hStructNodes(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes forceNodePositions(:,I) = structPositions(:,jLower) + hInterp * (structPositions(:,jLower+1) - structPositions(:,jLower)) END DO - forceNodePositions(:,p_OpFM%nNodesForceTower) = structPositions(:,nStructNodes) + forceNodePositions(:,p_ExtInfw%nNodesForceTower) = structPositions(:,nStructNodes) if (allocated(hStructNodes)) deallocate(hStructNodes) RETURN @@ -1027,12 +1031,12 @@ END SUBROUTINE CalcForceActuatorPositionsTower !-------------------------------------------------------------------------- !> Creates the blade and tower nodes in radial and tower height co-ordinates -SUBROUTINE OpFM_CreateActForceBladeTowerNodes(InitOut_AD, p_OpFM, u_OpFM, ErrStat, ErrMsg) - TYPE(AD_InitOutputType), INTENT(IN ) :: InitOut_AD ! InitOut data for the OpenFOAM integration module - TYPE(OpFM_ParameterType),INTENT(INOUT) :: p_OpFM ! Parameter data for the OpenFOAM integration module - TYPE(OpFM_InputType), INTENT(INOUT) :: u_OpFM ! Input data for the OpenFOAM integration module - INTEGER(IntKi) :: ErrStat ! Error status of the operation - CHARACTER(ErrMsgLen) :: ErrMsg ! Error message if ErrStat /= ErrID_None +SUBROUTINE ExtInfw_CreateActForceBladeTowerNodes(InitOut_AD, p_ExtInfw, u_ExtInfw, ErrStat, ErrMsg) + TYPE(AD_InitOutputType), INTENT(IN ) :: InitOut_AD ! InitOut data for the ExternalInflow integration module + TYPE(ExtInfw_ParameterType), INTENT(INOUT) :: p_ExtInfw ! Parameter data for the ExternalInflow integration module + TYPE(ExtInfw_InputType), INTENT(INOUT) :: u_ExtInfw ! Input data for the ExternalInflow integration module + INTEGER(IntKi) :: ErrStat ! Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg ! Error message if ErrStat /= ErrID_None !Local variables REAL(ReKi), ALLOCATABLE :: cNonUniform(:) @@ -1048,7 +1052,7 @@ SUBROUTINE OpFM_CreateActForceBladeTowerNodes(InitOut_AD, p_OpFM, u_OpFM, ErrSta INTEGER(IntKI) :: i ! Loop variables INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_CreateActForceBladeTowerNodes' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_CreateActForceBladeTowerNodes' ErrStat = ErrID_None ErrMsg = "" @@ -1056,38 +1060,38 @@ SUBROUTINE OpFM_CreateActForceBladeTowerNodes(InitOut_AD, p_OpFM, u_OpFM, ErrSta ! Tower - if (p_OpFM%NMappings .gt. p_OpFM%NumBl) then - allocate(p_OpFM%forceTwrHnodes(p_OpFM%nNodesForceTower), stat=errStat2); if (Failed2()) return; + if (p_ExtInfw%NMappings .gt. p_ExtInfw%NumBl) then + allocate(p_ExtInfw%forceTwrHnodes(p_ExtInfw%nNodesForceTower), stat=errStat2); if (Failed2()) return; ! Compute uniform spacing. - dRforceNodes = p_OpFM%TowerHeight/(p_OpFM%nNodesForceTower-1) - do i=1,p_OpFM%nNodesForceTower-1 - p_OpFM%forceTwrHnodes(i) = (i-1)*dRforceNodes + dRforceNodes = p_ExtInfw%TowerHeight/(p_ExtInfw%nNodesForceTower-1) + do i=1,p_ExtInfw%nNodesForceTower-1 + p_ExtInfw%forceTwrHnodes(i) = (i-1)*dRforceNodes end do - p_OpFM%forceTwrHnodes(p_OpFM%nNodesForceTower) = p_OpFM%TowerHeight + p_ExtInfw%forceTwrHnodes(p_ExtInfw%nNodesForceTower) = p_ExtInfw%TowerHeight end if ! Blades - allocate(cNonUniform(p_OpFM%nNodesForceBlade),stat=errStat2) - allocate(sNonUniform(p_OpFM%nNodesForceBlade),stat=errStat2) - allocate(pNonUniform(p_OpFM%nNodesForceBlade),stat=errStat2) - allocate(pUniform(p_OpFM%nNodesForceBlade),stat=errStat2) - allocate(cByS(p_OpFM%nNodesForceBlade),stat=errStat2) - allocate(e(p_OpFM%nNodesForceBlade-1),stat=errStat2) - allocate(p_OpFM%forceBldRnodes(p_OpFM%nNodesForceBlade), stat=errStat2); if (Failed2()) return; + allocate(cNonUniform(p_ExtInfw%nNodesForceBlade),stat=errStat2) + allocate(sNonUniform(p_ExtInfw%nNodesForceBlade),stat=errStat2) + allocate(pNonUniform(p_ExtInfw%nNodesForceBlade),stat=errStat2) + allocate(pUniform(p_ExtInfw%nNodesForceBlade),stat=errStat2) + allocate(cByS(p_ExtInfw%nNodesForceBlade),stat=errStat2) + allocate(e(p_ExtInfw%nNodesForceBlade-1),stat=errStat2) + allocate(p_ExtInfw%forceBldRnodes(p_ExtInfw%nNodesForceBlade), stat=errStat2); if (Failed2()) return; ! Compute uniform spacing. - dRforceNodes = p_OpFM%BladeLength/(p_OpFM%nNodesForceBlade-1) - do i=1,p_OpFM%nNodesForceBlade-1 + dRforceNodes = p_ExtInfw%BladeLength/(p_ExtInfw%nNodesForceBlade-1) + do i=1,p_ExtInfw%nNodesForceBlade-1 pUniform(i) = (i-1)*dRforceNodes end do - pUniform(p_OpFM%nNodesForceBlade) = p_OpFM%BladeLength - p_OpFM%forceBldRnodes = pUniform + pUniform(p_ExtInfw%nNodesForceBlade) = p_ExtInfw%BladeLength + p_ExtInfw%forceBldRnodes = pUniform - if (p_OpFM%NodeClusterType .eq. 0) then + if (p_ExtInfw%NodeClusterType .eq. 0) then print*, "Using uniform blade force node clustering." - !do i = 1, p_OpFM%nNodesForceBlade + !do i = 1, p_ExtInfw%nNodesForceBlade ! print*, "r(",i,") = ", pUniform(i) !end do end if @@ -1103,15 +1107,15 @@ SUBROUTINE OpFM_CreateActForceBladeTowerNodes(InitOut_AD, p_OpFM, u_OpFM, ErrSta ! convergence check. We take the difference between a = c/ds between ! all neighboring points to see how different they are, and take the ! rms of that error as the convergence measure (eSum). - if (p_OpFM%NodeClusterType .eq. 1) then + if (p_ExtInfw%NodeClusterType .eq. 1) then ! For chord-based clustering (increase resolution in regions of decreased chord), an iterative solution to the grid spacing is used. ! The initial guess to the spacing is uniform spacing, so start with that. pNonUniform = pUniform ! Get the chord at the initial force points. - call OpFM_InterpolateForceNodesChord(initOut_AD, p_OpFM, u_OpFM, ErrStat2, ErrMsg2) - cNonUniform(1:p_OpFM%nNodesForceBlade) = u_OpFM%forceNodesChord(2:p_OpFM%nNodesForceBlade+1) + call ExtInfw_InterpolateForceNodesChord(initOut_AD, p_ExtInfw, u_ExtInfw, ErrStat2, ErrMsg2) + cNonUniform(1:p_ExtInfw%nNodesForceBlade) = u_ExtInfw%forceNodesChord(2:p_ExtInfw%nNodesForceBlade+1) ! Iterate on a chord-based non-uniform spacing. counter = 0 @@ -1123,25 +1127,25 @@ SUBROUTINE OpFM_CreateActForceBladeTowerNodes(InitOut_AD, p_OpFM, u_OpFM, ErrSta !set the non-uniform spacing to ds = (sum(ds^) / sum(c^)) * c^, where !the ^ denotes from the last iteration. To begin the iteration, we !use ds = uniform. - sNonUniform = (p_OpFM%BladeLength)*cNonUniform/(sum(cNonUniform(2:p_OpFM%nNodesForceBlade-1)) + 0.5*(cNonUniform(1)+cNonUniform(p_OpFM%nNodesForceBlade))) + sNonUniform = (p_ExtInfw%BladeLength)*cNonUniform/(sum(cNonUniform(2:p_ExtInfw%nNodesForceBlade-1)) + 0.5*(cNonUniform(1)+cNonUniform(p_ExtInfw%nNodesForceBlade))) ! set the new blade points based on the new ds. - do i = 2, p_OpFM%nNodesForceBlade + do i = 2, p_ExtInfw%nNodesForceBlade pNonUniform(i) = pNonUniform(i-1) + 0.5*(sNonUniform(i-1) + sNonUniform(i)) end do - pNonUniform(p_OpFM%nNodesForceBlade) = p_OpFM%BladeLength - p_OpFM%forceBldRnodes = pNonUniform + pNonUniform(p_ExtInfw%nNodesForceBlade) = p_ExtInfw%BladeLength + p_ExtInfw%forceBldRnodes = pNonUniform ! interpolate chord to the new points to get the updated chord values - call OpFM_InterpolateForceNodesChord(initOut_AD, p_OpFM, u_OpFM,ErrStat2, ErrMsg2) - cNonUniform(1:p_OpFM%nNodesForceBlade) = u_OpFM%forceNodesChord(2:p_OpFM%nNodesForceBlade+1) + call ExtInfw_InterpolateForceNodesChord(initOut_AD, p_ExtInfw, u_ExtInfw,ErrStat2, ErrMsg2) + cNonUniform(1:p_ExtInfw%nNodesForceBlade) = u_ExtInfw%forceNodesChord(2:p_ExtInfw%nNodesForceBlade+1) ! compute a = c/ds cByS = cNonUniform/sNonUniform ! check how a = c/s varies along the span and take its rms to check ! convergence. - e = cByS(2:p_OpFM%nNodesForceBlade) - cByS(1:p_OpFM%nNodesForceBlade-1) + e = cByS(2:p_ExtInfw%nNodesForceBlade) - cByS(1:p_ExtInfw%nNodesForceBlade-1) eSum = sqrt(sum(e*e)) ! increment the iteration counter @@ -1165,16 +1169,16 @@ logical function Failed2() Failed2 = .false. endif end function Failed2 -END SUBROUTINE OpFM_CreateActForceBladeTowerNodes +END SUBROUTINE ExtInfw_CreateActForceBladeTowerNodes !-------------------------------------------------------------------------- !> Interpolates the chord distribution to the force nodes -SUBROUTINE OpFM_InterpolateForceNodesChord(InitOut_AD, p_OpFM, u_OpFM, ErrStat, ErrMsg) - TYPE(AD_InitOutputType), INTENT(IN ) :: InitOut_AD ! InitOut data for the OpenFOAM integration module - TYPE(OpFM_ParameterType), INTENT(IN ) :: p_OpFM ! Parameter data for the OpenFOAM integration module - TYPE(OpFM_InputType), INTENT(INOUT) :: u_OpFM ! Input data for the OpenFOAM integration module - INTEGER(IntKi) :: ErrStat ! temporary Error status of the operation - CHARACTER(ErrMsgLen) :: ErrMsg ! temporary Error message if ErrStat /= ErrID_None +SUBROUTINE ExtInfw_InterpolateForceNodesChord(InitOut_AD, p_ExtInfw, u_ExtInfw, ErrStat, ErrMsg) + TYPE(AD_InitOutputType), INTENT(IN ) :: InitOut_AD ! InitOut data for the ExternalInflow integration module + TYPE(ExtInfw_ParameterType), INTENT(IN ) :: p_ExtInfw ! Parameter data for the ExternalInflow integration module + TYPE(ExtInfw_InputType), INTENT(INOUT) :: u_ExtInfw ! Input data for the ExternalInflow integration module + INTEGER(IntKi) :: ErrStat ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg ! temporary Error message if ErrStat /= ErrID_None !Local variables INTEGER(IntKI) :: i,k,node ! Loop variables @@ -1188,57 +1192,57 @@ SUBROUTINE OpFM_InterpolateForceNodesChord(InitOut_AD, p_OpFM, u_OpFM, ErrStat, ! Set the chord for the hub node to be zero. Ideally, I'd like this to be the hub radius. Will figure this out later. Node = 1 - u_OpFM%forceNodesChord(Node) = 0.0_ReKi + u_ExtInfw%forceNodesChord(Node) = 0.0_ReKi ! The blades first - do k = 1, p_OpFM%NumBl + do k = 1, p_ExtInfw%NumBl ! Calculate the chord at the force nodes based on interpolation ! NOTE: the InterpArray function from the NWTC Library could be used here instead. This interpolation will eventually be removed, so we won't update it here. nNodesBladeProps = SIZE(InitOut_AD%rotors(1)%BladeProps(k)%BlChord) - DO I=1,p_OpFM%nNodesForceBlade + DO I=1,p_ExtInfw%nNodesForceBlade Node = Node + 1 do jLower = 1, (nNodesBladeProps - 1) - if ( (InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower) - p_OpFM%forceBldRnodes(I))*(InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower+1) - p_OpFM%forceBldRnodes(I)) .le. 0 ) then + if ( (InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower) - p_ExtInfw%forceBldRnodes(I))*(InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower+1) - p_ExtInfw%forceBldRnodes(I)) .le. 0 ) then exit endif enddo if (jLower .lt. nNodesBladeProps) then - rInterp = (p_OpFM%forceBldRnodes(I) - InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower))/(InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower+1)-InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes - u_OpFM%forceNodesChord(Node) = InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower) + rInterp * (InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower+1) - InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower)) + rInterp = (p_ExtInfw%forceBldRnodes(I) - InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower))/(InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower+1)-InitOut_AD%rotors(1)%BladeProps(k)%BlSpn(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes + u_ExtInfw%forceNodesChord(Node) = InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower) + rInterp * (InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower+1) - InitOut_AD%rotors(1)%BladeProps(k)%BlChord(jLower)) else - u_OpFM%forceNodesChord(Node) = InitOut_AD%rotors(1)%BladeProps(k)%BlChord(nNodesBladeProps) !Work around for when the last node of the actuator mesh is slightly outside of the Aerodyn blade properties. Surprisingly this is not an issue with the tower. + u_ExtInfw%forceNodesChord(Node) = InitOut_AD%rotors(1)%BladeProps(k)%BlChord(nNodesBladeProps) !Work around for when the last node of the actuator mesh is slightly outside of the Aerodyn blade properties. Surprisingly this is not an issue with the tower. end if END DO end do ! The tower now - if (p_OpFM%NMappings .gt. p_OpFM%NumBl) then - do k = p_OpFM%NumBl+1,p_OpFM%NMappings + if (p_ExtInfw%NMappings .gt. p_ExtInfw%NumBl) then + do k = p_ExtInfw%NumBl+1,p_ExtInfw%NMappings nNodesTowerProps = SIZE(InitOut_AD%rotors(1)%TwrElev) ! Calculate the chord at the force nodes based on interpolation - do I=1,p_OpFM%nNodesForceTower + do I=1,p_ExtInfw%nNodesForceTower Node = Node + 1 do jLower = 1, (nNodesTowerProps - 1) - if ( (InitOut_AD%rotors(1)%TwrElev(jLower) - p_OpFM%forceTwrHnodes(I)-p_OpFM%TowerBaseHeight)*(InitOut_AD%rotors(1)%TwrElev(jLower+1) - p_OpFM%forceTwrHnodes(I)-p_OpFM%TowerBaseHeight) .le. 0) then + if ( (InitOut_AD%rotors(1)%TwrElev(jLower) - p_ExtInfw%forceTwrHnodes(I)-p_ExtInfw%TowerBaseHeight)*(InitOut_AD%rotors(1)%TwrElev(jLower+1) - p_ExtInfw%forceTwrHnodes(I)-p_ExtInfw%TowerBaseHeight) .le. 0) then exit endif enddo if (jLower .lt. nNodesTowerProps) then - rInterp = (p_OpFM%forceTwrHnodes(I)+p_OpFM%TowerBaseHeight - InitOut_AD%rotors(1)%TwrElev(jLower))/(InitOut_AD%rotors(1)%TwrElev(jLower+1)-InitOut_AD%rotors(1)%TwrElev(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes - u_OpFM%forceNodesChord(Node) = InitOut_AD%rotors(1)%TwrDiam(jLower) + rInterp * (InitOut_AD%rotors(1)%TwrDiam(jLower+1) - InitOut_AD%rotors(1)%TwrDiam(jLower)) + rInterp = (p_ExtInfw%forceTwrHnodes(I)+p_ExtInfw%TowerBaseHeight - InitOut_AD%rotors(1)%TwrElev(jLower))/(InitOut_AD%rotors(1)%TwrElev(jLower+1)-InitOut_AD%rotors(1)%TwrElev(jLower)) ! The location of this force node in (0,1) co-ordinates between the jLower and jLower+1 nodes + u_ExtInfw%forceNodesChord(Node) = InitOut_AD%rotors(1)%TwrDiam(jLower) + rInterp * (InitOut_AD%rotors(1)%TwrDiam(jLower+1) - InitOut_AD%rotors(1)%TwrDiam(jLower)) else - u_OpFM%forceNodesChord(Node) = InitOut_AD%rotors(1)%TwrDiam(nNodesTowerProps) !Work around for when the last node of the actuator mesh is slightly outside of the Aerodyn tower properties. + u_ExtInfw%forceNodesChord(Node) = InitOut_AD%rotors(1)%TwrDiam(nNodesTowerProps) !Work around for when the last node of the actuator mesh is slightly outside of the Aerodyn tower properties. end if end do end do endif -END SUBROUTINE OpFM_InterpolateForceNodesChord +END SUBROUTINE ExtInfw_InterpolateForceNodesChord -END MODULE OpenFOAM +END MODULE ExternalInflow !********************************************************************************************************************************** diff --git a/modules/externalinflow/src/ExternalInflow_Registry.txt b/modules/externalinflow/src/ExternalInflow_Registry.txt new file mode 100644 index 0000000000..346b559395 --- /dev/null +++ b/modules/externalinflow/src/ExternalInflow_Registry.txt @@ -0,0 +1,79 @@ +################################################################################################################################### +# Registry for ExternalInflow - CFD interface types in the FAST Modularization Framework +# Entries are of the form +# +# +# Use ^ as a shortcut for the value in the same column from the previous line. +################################################################################################################################### +# ...... Include files (definitions from NWTC Library) ............................................................................ +include Registry_NWTC_Library.txt +include IfW_FlowField.txt + + + +# ..... ExternalInflow_InitInputType data ....................................................................................................... +typedef ExternalInflow/ExtInfw InitInputType IntKi NumActForcePtsBlade - - - "number of actuator line force points in blade -- from extern (used to linearly interpolate along AD15 blades)" - +typedef ^ ^ IntKi NumActForcePtsTower - - - "number of actuator line force points in tower -- from extern (used to linearly interpolate along AD15 tower)" - +typedef ^ ^ ReKi StructBldRNodes {:} - - "Radius to structural model analysis nodes relative to hub" +typedef ^ ^ ReKi StructTwrHNodes {:} - - "Location of tower nodes from AD15 (relative to the tower rigid base height)" +typedef ^ ^ ReKi BladeLength - - - "Blade length" meters +typedef ^ ^ ReKi TowerHeight - - - "Tower Height" meters +typedef ^ ^ ReKi TowerBaseHeight - - - "Tower Base Height" meters +typedef ^ ^ IntKi NodeClusterType - - - "Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip)" - + + + +# ..... ExternalInflow_InitOutputType data ....................................................................................................... +# Define outputs from the initialization routine here: +typedef ExternalInflow/ExtInfw InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - +typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputUnt {:} - - "Units of the output-to-file channels" - +typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - +typedef ^ InitOutputType FlowFieldType *FlowField - - - "Pointer of flow field data type" - + +# ..... MiscVars ................................................................................................................ +typedef ExternalInflow/ExtInfw ExtInfw_MiscVarType MeshType ActForceMotionsPoints {:} - - "point mesh for transferring AeroDyn motions to ExternalInflow (includes hub+blades+nacelle+tower+tailfin)" - +typedef ExternalInflow/ExtInfw ExtInfw_MiscVarType MeshType ActForceLoadsPoints {:} - - "point mesh for transferring AeroDyn distributed loads to ExternalInflow (includes hub+blades+nacelle+tower+tailfin)" - +typedef ExternalInflow/ExtInfw ExtInfw_MiscVarType MeshMapType Line2_to_Point_Loads {:} - - "mapping data structure to convert line2 loads to point loads" - +typedef ExternalInflow/ExtInfw ExtInfw_MiscVarType MeshMapType Line2_to_Point_Motions {:} - - "mapping data structure to convert line2 loads to point motions" - +typedef ExternalInflow/ExtInfw ExtInfw_MiscVarType FlowFieldType &FlowField - - - "Flow field data type" - + + +# ..... Parameters ................................................................................................................ +typedef ExternalInflow/ExtInfw ParameterType ReKi AirDens - - - "Air density for normalization of loads sent to ExternalInflow" kg/m^3 +typedef ExternalInflow/ExtInfw ParameterType IntKi NumBl - - - "Number of blades" - +typedef ExternalInflow/ExtInfw ParameterType IntKi NMappings - - - "Number of mappings" - +typedef ExternalInflow/ExtInfw ParameterType IntKi NnodesVel - - - "number of velocity nodes on FAST v8-ExternalInflow interface" - +typedef ExternalInflow/ExtInfw ParameterType IntKi NnodesForce - - - "number of force nodes on FAST v8-ExternalInflow interface" - +typedef ExternalInflow/ExtInfw ParameterType IntKi NnodesForceBlade - - - "number of force nodes on FAST v8-ExternalInflow interface" - +typedef ExternalInflow/ExtInfw ParameterType IntKi NnodesForceTower - - - "number of force nodes on FAST v8-ExternalInflow interface" - +typedef ExternalInflow/ExtInfw ParameterType ReKi forceBldRnodes {:} - - "Radial location of force nodes" - +typedef ExternalInflow/ExtInfw ParameterType ReKi forceTwrHnodes {:} - - "Vertical location of force nodes" - +typedef ExternalInflow/ExtInfw ParameterType ReKi BladeLength - - - "Blade length (same for all blades)" "m" +typedef ExternalInflow/ExtInfw ParameterType ReKi TowerHeight - - - "Tower height" "m" +typedef ExternalInflow/ExtInfw ParameterType ReKi TowerBaseHeight - - - "Tower base height" "m" +typedef ExternalInflow/ExtInfw ParameterType IntKi NodeClusterType - - - "Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip)" - + +# ..... ExternalInflow_InputType data ....................................................................................................... +typedef ^ InputType ReKi pxVel {:} - - "x position of velocity interface (Aerodyn) nodes" "m" +typedef ^ InputType ReKi pyVel {:} - - "y position of velocity interface (Aerodyn) nodes" "m" +typedef ^ InputType ReKi pzVel {:} - - "z position of velocity interface (Aerodyn) nodes" "m" +typedef ^ InputType ReKi pxForce {:} - - "x position of actuator force nodes" "m" +typedef ^ InputType ReKi pyForce {:} - - "y position of actuator force nodes" "m" +typedef ^ InputType ReKi pzForce {:} - - "z position of actuator force nodes" "m" +typedef ^ InputType ReKi xdotForce {:} - - "x velocity of actuator force nodes" "m/s" +typedef ^ InputType ReKi ydotForce {:} - - "y velocity of actuator force nodes" "m/s" +typedef ^ InputType ReKi zdotForce {:} - - "z velocity of actuator force nodes" "m/s" +typedef ^ InputType ReKi pOrientation {:} - - "Direction cosine matrix to transform vectors from global frame of reference to actuator force node frame of reference" - +typedef ^ InputType ReKi fx {:} - - "normalized x force at actuator force nodes" "N/kg/m^3" +typedef ^ InputType ReKi fy {:} - - "normalized y force at actuator force nodes" "N/kg/m^3" +typedef ^ InputType ReKi fz {:} - - "normalized z force at actuator force nodes" "N/kg/m^3" +typedef ^ InputType ReKi momentx {:} - - "normalized x moment at actuator force nodes" "Nm/kg/m^3" +typedef ^ InputType ReKi momenty {:} - - "normalized y moment at actuator force nodes" "Nm/kg/m^3" +typedef ^ InputType ReKi momentz {:} - - "normalized z moment at actuator force nodes" "Nm/kg/m^3" +typedef ^ InputType ReKi forceNodesChord {:} - - "chord distribution at the actuator force nodes" "m" + +# ..... ExternalInflow_OutputType data ....................................................................................................... +typedef ^ OutputType ReKi u {:} - - "U-component wind speed (in the X-direction) at interface nodes" m/s +typedef ^ OutputType ReKi v {:} - - "V-component wind speed (in the Y-direction) at interface nodes" m/s +typedef ^ OutputType ReKi w {:} - - "W-component wind speed (in the Z-direction) at interface nodes" m/s +typedef ^ OutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" diff --git a/modules/openfoam/src/OpenFOAM_Types.f90 b/modules/externalinflow/src/ExternalInflow_Types.f90 similarity index 92% rename from modules/openfoam/src/OpenFOAM_Types.f90 rename to modules/externalinflow/src/ExternalInflow_Types.f90 index 69330280b8..f7714f8fa7 100644 --- a/modules/openfoam/src/OpenFOAM_Types.f90 +++ b/modules/externalinflow/src/ExternalInflow_Types.f90 @@ -1,13 +1,13 @@ -!STARTOFREGISTRYGENERATEDFILE 'OpenFOAM_Types.f90' +!STARTOFREGISTRYGENERATEDFILE 'ExternalInflow_Types.f90' ! ! WARNING This file is generated automatically by the FAST registry. ! Do not edit. Your changes to this file will be lost. ! ! FAST Registry !********************************************************************************************************************************* -! OpenFOAM_Types +! ExternalInflow_Types !................................................................................................................................. -! This file is part of OpenFOAM. +! This file is part of ExternalInflow. ! ! Copyright (C) 2012-2016 National Renewable Energy Laboratory ! @@ -27,15 +27,15 @@ ! W A R N I N G : This file was automatically generated from the FAST registry. Changes made to this file may be lost. ! !********************************************************************************************************************************* -!> This module contains the user-defined types needed in OpenFOAM. It also contains copy, destroy, pack, and +!> This module contains the user-defined types needed in ExternalInflow. It also contains copy, destroy, pack, and !! unpack routines associated with each defined data type. This code is automatically generated by the FAST Registry. -MODULE OpenFOAM_Types +MODULE ExternalInflow_Types !--------------------------------------------------------------------------------------------------------------------------------- USE IfW_FlowField_Types USE NWTC_Library IMPLICIT NONE -! ========= OpFM_InitInputType_C ======= - TYPE, BIND(C) :: OpFM_InitInputType_C +! ========= ExtInfw_InitInputType_C ======= + TYPE, BIND(C) :: ExtInfw_InitInputType_C TYPE(C_PTR) :: object = C_NULL_PTR INTEGER(KIND=C_INT) :: NumActForcePtsBlade INTEGER(KIND=C_INT) :: NumActForcePtsTower @@ -47,9 +47,9 @@ MODULE OpenFOAM_Types REAL(KIND=C_FLOAT) :: TowerHeight REAL(KIND=C_FLOAT) :: TowerBaseHeight INTEGER(KIND=C_INT) :: NodeClusterType - END TYPE OpFM_InitInputType_C - TYPE, PUBLIC :: OpFM_InitInputType - TYPE( OpFM_InitInputType_C ) :: C_obj + END TYPE ExtInfw_InitInputType_C + TYPE, PUBLIC :: ExtInfw_InitInputType + TYPE( ExtInfw_InitInputType_C ) :: C_obj INTEGER(IntKi) :: NumActForcePtsBlade = 0_IntKi !< number of actuator line force points in blade -- from extern (used to linearly interpolate along AD15 blades) [-] INTEGER(IntKi) :: NumActForcePtsTower = 0_IntKi !< number of actuator line force points in tower -- from extern (used to linearly interpolate along AD15 tower) [-] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: StructBldRNodes => NULL() !< Radius to structural model analysis nodes relative to hub [-] @@ -58,39 +58,39 @@ MODULE OpenFOAM_Types REAL(ReKi) :: TowerHeight = 0.0_ReKi !< Tower Height [meters] REAL(ReKi) :: TowerBaseHeight = 0.0_ReKi !< Tower Base Height [meters] INTEGER(IntKi) :: NodeClusterType = 0_IntKi !< Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip) [-] - END TYPE OpFM_InitInputType + END TYPE ExtInfw_InitInputType ! ======================= -! ========= OpFM_InitOutputType_C ======= - TYPE, BIND(C) :: OpFM_InitOutputType_C +! ========= ExtInfw_InitOutputType_C ======= + TYPE, BIND(C) :: ExtInfw_InitOutputType_C TYPE(C_PTR) :: object = C_NULL_PTR TYPE(C_ptr) :: WriteOutputHdr = C_NULL_PTR INTEGER(C_int) :: WriteOutputHdr_Len = 0 TYPE(C_ptr) :: WriteOutputUnt = C_NULL_PTR INTEGER(C_int) :: WriteOutputUnt_Len = 0 - END TYPE OpFM_InitOutputType_C - TYPE, PUBLIC :: OpFM_InitOutputType - TYPE( OpFM_InitOutputType_C ) :: C_obj + END TYPE ExtInfw_InitOutputType_C + TYPE, PUBLIC :: ExtInfw_InitOutputType + TYPE( ExtInfw_InitOutputType_C ) :: C_obj CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputHdr !< Names of the output-to-file channels [-] CHARACTER(ChanLen) , DIMENSION(:), ALLOCATABLE :: WriteOutputUnt !< Units of the output-to-file channels [-] TYPE(ProgDesc) :: Ver !< This module's name, version, and date [-] TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Pointer of flow field data type [-] - END TYPE OpFM_InitOutputType + END TYPE ExtInfw_InitOutputType ! ======================= -! ========= OpFM_MiscVarType_C ======= - TYPE, BIND(C) :: OpFM_MiscVarType_C +! ========= ExtInfw_MiscVarType_C ======= + TYPE, BIND(C) :: ExtInfw_MiscVarType_C TYPE(C_PTR) :: object = C_NULL_PTR - END TYPE OpFM_MiscVarType_C - TYPE, PUBLIC :: OpFM_MiscVarType - TYPE( OpFM_MiscVarType_C ) :: C_obj - TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: ActForceMotionsPoints !< point mesh for transferring AeroDyn motions to OpenFOAM (includes hub+blades+nacelle+tower+tailfin) [-] - TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: ActForceLoadsPoints !< point mesh for transferring AeroDyn distributed loads to OpenFOAM (includes hub+blades+nacelle+tower+tailfin) [-] + END TYPE ExtInfw_MiscVarType_C + TYPE, PUBLIC :: ExtInfw_MiscVarType + TYPE( ExtInfw_MiscVarType_C ) :: C_obj + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: ActForceMotionsPoints !< point mesh for transferring AeroDyn motions to ExternalInflow (includes hub+blades+nacelle+tower+tailfin) [-] + TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: ActForceLoadsPoints !< point mesh for transferring AeroDyn distributed loads to ExternalInflow (includes hub+blades+nacelle+tower+tailfin) [-] TYPE(MeshMapType) , DIMENSION(:), ALLOCATABLE :: Line2_to_Point_Loads !< mapping data structure to convert line2 loads to point loads [-] TYPE(MeshMapType) , DIMENSION(:), ALLOCATABLE :: Line2_to_Point_Motions !< mapping data structure to convert line2 loads to point motions [-] TYPE(FlowFieldType) , POINTER :: FlowField => NULL() !< Flow field data type [-] - END TYPE OpFM_MiscVarType + END TYPE ExtInfw_MiscVarType ! ======================= -! ========= OpFM_ParameterType_C ======= - TYPE, BIND(C) :: OpFM_ParameterType_C +! ========= ExtInfw_ParameterType_C ======= + TYPE, BIND(C) :: ExtInfw_ParameterType_C TYPE(C_PTR) :: object = C_NULL_PTR REAL(KIND=C_FLOAT) :: AirDens INTEGER(KIND=C_INT) :: NumBl @@ -107,26 +107,26 @@ MODULE OpenFOAM_Types REAL(KIND=C_FLOAT) :: TowerHeight REAL(KIND=C_FLOAT) :: TowerBaseHeight INTEGER(KIND=C_INT) :: NodeClusterType - END TYPE OpFM_ParameterType_C - TYPE, PUBLIC :: OpFM_ParameterType - TYPE( OpFM_ParameterType_C ) :: C_obj - REAL(ReKi) :: AirDens = 0.0_ReKi !< Air density for normalization of loads sent to OpenFOAM [kg/m^3] + END TYPE ExtInfw_ParameterType_C + TYPE, PUBLIC :: ExtInfw_ParameterType + TYPE( ExtInfw_ParameterType_C ) :: C_obj + REAL(ReKi) :: AirDens = 0.0_ReKi !< Air density for normalization of loads sent to ExternalInflow [kg/m^3] INTEGER(IntKi) :: NumBl = 0_IntKi !< Number of blades [-] INTEGER(IntKi) :: NMappings = 0_IntKi !< Number of mappings [-] - INTEGER(IntKi) :: NnodesVel = 0_IntKi !< number of velocity nodes on FAST v8-OpenFOAM interface [-] - INTEGER(IntKi) :: NnodesForce = 0_IntKi !< number of force nodes on FAST v8-OpenFOAM interface [-] - INTEGER(IntKi) :: NnodesForceBlade = 0_IntKi !< number of force nodes on FAST v8-OpenFOAM interface [-] - INTEGER(IntKi) :: NnodesForceTower = 0_IntKi !< number of force nodes on FAST v8-OpenFOAM interface [-] + INTEGER(IntKi) :: NnodesVel = 0_IntKi !< number of velocity nodes on FAST v8-ExternalInflow interface [-] + INTEGER(IntKi) :: NnodesForce = 0_IntKi !< number of force nodes on FAST v8-ExternalInflow interface [-] + INTEGER(IntKi) :: NnodesForceBlade = 0_IntKi !< number of force nodes on FAST v8-ExternalInflow interface [-] + INTEGER(IntKi) :: NnodesForceTower = 0_IntKi !< number of force nodes on FAST v8-ExternalInflow interface [-] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: forceBldRnodes => NULL() !< Radial location of force nodes [-] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: forceTwrHnodes => NULL() !< Vertical location of force nodes [-] REAL(ReKi) :: BladeLength = 0.0_ReKi !< Blade length (same for all blades) [m] REAL(ReKi) :: TowerHeight = 0.0_ReKi !< Tower height [m] REAL(ReKi) :: TowerBaseHeight = 0.0_ReKi !< Tower base height [m] INTEGER(IntKi) :: NodeClusterType = 0_IntKi !< Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip) [-] - END TYPE OpFM_ParameterType + END TYPE ExtInfw_ParameterType ! ======================= -! ========= OpFM_InputType_C ======= - TYPE, BIND(C) :: OpFM_InputType_C +! ========= ExtInfw_InputType_C ======= + TYPE, BIND(C) :: ExtInfw_InputType_C TYPE(C_PTR) :: object = C_NULL_PTR TYPE(C_ptr) :: pxVel = C_NULL_PTR INTEGER(C_int) :: pxVel_Len = 0 @@ -162,9 +162,9 @@ MODULE OpenFOAM_Types INTEGER(C_int) :: momentz_Len = 0 TYPE(C_ptr) :: forceNodesChord = C_NULL_PTR INTEGER(C_int) :: forceNodesChord_Len = 0 - END TYPE OpFM_InputType_C - TYPE, PUBLIC :: OpFM_InputType - TYPE( OpFM_InputType_C ) :: C_obj + END TYPE ExtInfw_InputType_C + TYPE, PUBLIC :: ExtInfw_InputType + TYPE( ExtInfw_InputType_C ) :: C_obj REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: pxVel => NULL() !< x position of velocity interface (Aerodyn) nodes [m] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: pyVel => NULL() !< y position of velocity interface (Aerodyn) nodes [m] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: pzVel => NULL() !< z position of velocity interface (Aerodyn) nodes [m] @@ -182,10 +182,10 @@ MODULE OpenFOAM_Types REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: momenty => NULL() !< normalized y moment at actuator force nodes [Nm/kg/m^3] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: momentz => NULL() !< normalized z moment at actuator force nodes [Nm/kg/m^3] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: forceNodesChord => NULL() !< chord distribution at the actuator force nodes [m] - END TYPE OpFM_InputType + END TYPE ExtInfw_InputType ! ======================= -! ========= OpFM_OutputType_C ======= - TYPE, BIND(C) :: OpFM_OutputType_C +! ========= ExtInfw_OutputType_C ======= + TYPE, BIND(C) :: ExtInfw_OutputType_C TYPE(C_PTR) :: object = C_NULL_PTR TYPE(C_ptr) :: u = C_NULL_PTR INTEGER(C_int) :: u_Len = 0 @@ -195,26 +195,26 @@ MODULE OpenFOAM_Types INTEGER(C_int) :: w_Len = 0 TYPE(C_ptr) :: WriteOutput = C_NULL_PTR INTEGER(C_int) :: WriteOutput_Len = 0 - END TYPE OpFM_OutputType_C - TYPE, PUBLIC :: OpFM_OutputType - TYPE( OpFM_OutputType_C ) :: C_obj + END TYPE ExtInfw_OutputType_C + TYPE, PUBLIC :: ExtInfw_OutputType + TYPE( ExtInfw_OutputType_C ) :: C_obj REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: u => NULL() !< U-component wind speed (in the X-direction) at interface nodes [m/s] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: v => NULL() !< V-component wind speed (in the Y-direction) at interface nodes [m/s] REAL(KIND=C_FLOAT) , DIMENSION(:), POINTER :: w => NULL() !< W-component wind speed (in the Z-direction) at interface nodes [m/s] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WriteOutput !< Data to be written to an output file: see WriteOutputHdr for names of each variable [see WriteOutputUnt] - END TYPE OpFM_OutputType + END TYPE ExtInfw_OutputType ! ======================= CONTAINS -subroutine OpFM_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_InitInputType), intent(in) :: SrcInitInputData - type(OpFM_InitInputType), intent(inout) :: DstInitInputData +subroutine ExtInfw_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_InitInputType), intent(in) :: SrcInitInputData + type(ExtInfw_InitInputType), intent(inout) :: DstInitInputData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 - character(*), parameter :: RoutineName = 'OpFM_CopyInitInput' + character(*), parameter :: RoutineName = 'ExtInfw_CopyInitInput' ErrStat = ErrID_None ErrMsg = '' DstInitInputData%NumActForcePtsBlade = SrcInitInputData%NumActForcePtsBlade @@ -261,11 +261,11 @@ subroutine OpFM_CopyInitInput(SrcInitInputData, DstInitInputData, CtrlCode, ErrS DstInitInputData%C_obj%NodeClusterType = SrcInitInputData%C_obj%NodeClusterType end subroutine -subroutine OpFM_DestroyInitInput(InitInputData, ErrStat, ErrMsg) - type(OpFM_InitInputType), intent(inout) :: InitInputData +subroutine ExtInfw_DestroyInitInput(InitInputData, ErrStat, ErrMsg) + type(ExtInfw_InitInputType), intent(inout) :: InitInputData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'OpFM_DestroyInitInput' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyInitInput' ErrStat = ErrID_None ErrMsg = '' if (associated(InitInputData%StructBldRNodes)) then @@ -282,10 +282,10 @@ subroutine OpFM_DestroyInitInput(InitInputData, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_PackInitInput(Buf, Indata) +subroutine ExtInfw_PackInitInput(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InitInputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackInitInput' + type(ExtInfw_InitInputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackInitInput' logical :: PtrInIndex if (Buf%ErrStat >= AbortErrLev) return if (c_associated(InData%C_obj%object)) then @@ -317,10 +317,10 @@ subroutine OpFM_PackInitInput(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackInitInput(Buf, OutData) +subroutine ExtInfw_UnPackInitInput(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InitInputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackInitInput' + type(ExtInfw_InitInputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackInitInput' integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc @@ -399,8 +399,8 @@ subroutine OpFM_UnPackInitInput(Buf, OutData) OutData%C_obj%NodeClusterType = OutData%NodeClusterType end subroutine -SUBROUTINE OpFM_C2Fary_CopyInitInput(InitInputData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_InitInputType), INTENT(INOUT) :: InitInputData +SUBROUTINE ExtInfw_C2Fary_CopyInitInput(InitInputData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_InitInputType), INTENT(INOUT) :: InitInputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -440,8 +440,8 @@ SUBROUTINE OpFM_C2Fary_CopyInitInput(InitInputData, ErrStat, ErrMsg, SkipPointer InitInputData%NodeClusterType = InitInputData%C_obj%NodeClusterType END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyInitInput( InitInputData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_InitInputType), INTENT(INOUT) :: InitInputData +SUBROUTINE ExtInfw_F2C_CopyInitInput( InitInputData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_InitInputType), INTENT(INOUT) :: InitInputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -487,16 +487,16 @@ SUBROUTINE OpFM_F2C_CopyInitInput( InitInputData, ErrStat, ErrMsg, SkipPointers InitInputData%C_obj%NodeClusterType = InitInputData%NodeClusterType END SUBROUTINE -subroutine OpFM_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_InitOutputType), intent(in) :: SrcInitOutputData - type(OpFM_InitOutputType), intent(inout) :: DstInitOutputData +subroutine ExtInfw_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_InitOutputType), intent(in) :: SrcInitOutputData + type(ExtInfw_InitOutputType), intent(inout) :: DstInitOutputData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'OpFM_CopyInitOutput' + character(*), parameter :: RoutineName = 'ExtInfw_CopyInitOutput' ErrStat = ErrID_None ErrMsg = '' if (allocated(SrcInitOutputData%WriteOutputHdr)) then @@ -529,13 +529,13 @@ subroutine OpFM_CopyInitOutput(SrcInitOutputData, DstInitOutputData, CtrlCode, E DstInitOutputData%FlowField => SrcInitOutputData%FlowField end subroutine -subroutine OpFM_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) - type(OpFM_InitOutputType), intent(inout) :: InitOutputData +subroutine ExtInfw_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) + type(ExtInfw_InitOutputType), intent(inout) :: InitOutputData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'OpFM_DestroyInitOutput' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyInitOutput' ErrStat = ErrID_None ErrMsg = '' if (allocated(InitOutputData%WriteOutputHdr)) then @@ -549,10 +549,10 @@ subroutine OpFM_DestroyInitOutput(InitOutputData, ErrStat, ErrMsg) nullify(InitOutputData%FlowField) end subroutine -subroutine OpFM_PackInitOutput(Buf, Indata) +subroutine ExtInfw_PackInitOutput(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InitOutputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackInitOutput' + type(ExtInfw_InitOutputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackInitOutput' logical :: PtrInIndex if (Buf%ErrStat >= AbortErrLev) return if (c_associated(InData%C_obj%object)) then @@ -580,10 +580,10 @@ subroutine OpFM_PackInitOutput(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackInitOutput(Buf, OutData) +subroutine ExtInfw_UnPackInitOutput(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InitOutputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackInitOutput' + type(ExtInfw_InitOutputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackInitOutput' integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc @@ -641,8 +641,8 @@ subroutine OpFM_UnPackInitOutput(Buf, OutData) end if end subroutine -SUBROUTINE OpFM_C2Fary_CopyInitOutput(InitOutputData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_InitOutputType), INTENT(INOUT) :: InitOutputData +SUBROUTINE ExtInfw_C2Fary_CopyInitOutput(InitOutputData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_InitOutputType), INTENT(INOUT) :: InitOutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -658,8 +658,8 @@ SUBROUTINE OpFM_C2Fary_CopyInitOutput(InitOutputData, ErrStat, ErrMsg, SkipPoint END IF END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyInitOutput( InitOutputData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_InitOutputType), INTENT(INOUT) :: InitOutputData +SUBROUTINE ExtInfw_F2C_CopyInitOutput( InitOutputData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_InitOutputType), INTENT(INOUT) :: InitOutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -675,9 +675,9 @@ SUBROUTINE OpFM_F2C_CopyInitOutput( InitOutputData, ErrStat, ErrMsg, SkipPointer END IF END SUBROUTINE -subroutine OpFM_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_MiscVarType), intent(inout) :: SrcMiscData - type(OpFM_MiscVarType), intent(inout) :: DstMiscData +subroutine ExtInfw_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_MiscVarType), intent(inout) :: SrcMiscData + type(ExtInfw_MiscVarType), intent(inout) :: DstMiscData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg @@ -685,7 +685,7 @@ subroutine OpFM_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'OpFM_CopyMisc' + character(*), parameter :: RoutineName = 'ExtInfw_CopyMisc' ErrStat = ErrID_None ErrMsg = '' if (allocated(SrcMiscData%ActForceMotionsPoints)) then @@ -766,15 +766,15 @@ subroutine OpFM_CopyMisc(SrcMiscData, DstMiscData, CtrlCode, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_DestroyMisc(MiscData, ErrStat, ErrMsg) - type(OpFM_MiscVarType), intent(inout) :: MiscData +subroutine ExtInfw_DestroyMisc(MiscData, ErrStat, ErrMsg) + type(ExtInfw_MiscVarType), intent(inout) :: MiscData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: i1 integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'OpFM_DestroyMisc' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyMisc' ErrStat = ErrID_None ErrMsg = '' if (allocated(MiscData%ActForceMotionsPoints)) then @@ -821,10 +821,10 @@ subroutine OpFM_DestroyMisc(MiscData, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_PackMisc(Buf, Indata) +subroutine ExtInfw_PackMisc(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_MiscVarType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackMisc' + type(ExtInfw_MiscVarType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackMisc' integer(IntKi) :: i1 integer(IntKi) :: LB(1), UB(1) logical :: PtrInIndex @@ -879,10 +879,10 @@ subroutine OpFM_PackMisc(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackMisc(Buf, OutData) +subroutine ExtInfw_UnPackMisc(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_MiscVarType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackMisc' + type(ExtInfw_MiscVarType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackMisc' integer(IntKi) :: i1 integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat @@ -972,8 +972,8 @@ subroutine OpFM_UnPackMisc(Buf, OutData) end if end subroutine -SUBROUTINE OpFM_C2Fary_CopyMisc(MiscData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_MiscVarType), INTENT(INOUT) :: MiscData +SUBROUTINE ExtInfw_C2Fary_CopyMisc(MiscData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_MiscVarType), INTENT(INOUT) :: MiscData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -989,8 +989,8 @@ SUBROUTINE OpFM_C2Fary_CopyMisc(MiscData, ErrStat, ErrMsg, SkipPointers) END IF END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyMisc( MiscData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_MiscVarType), INTENT(INOUT) :: MiscData +SUBROUTINE ExtInfw_F2C_CopyMisc( MiscData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_MiscVarType), INTENT(INOUT) :: MiscData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -1006,15 +1006,15 @@ SUBROUTINE OpFM_F2C_CopyMisc( MiscData, ErrStat, ErrMsg, SkipPointers ) END IF END SUBROUTINE -subroutine OpFM_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_ParameterType), intent(in) :: SrcParamData - type(OpFM_ParameterType), intent(inout) :: DstParamData +subroutine ExtInfw_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_ParameterType), intent(in) :: SrcParamData + type(ExtInfw_ParameterType), intent(inout) :: DstParamData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 - character(*), parameter :: RoutineName = 'OpFM_CopyParam' + character(*), parameter :: RoutineName = 'ExtInfw_CopyParam' ErrStat = ErrID_None ErrMsg = '' DstParamData%AirDens = SrcParamData%AirDens @@ -1071,11 +1071,11 @@ subroutine OpFM_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%C_obj%NodeClusterType = SrcParamData%C_obj%NodeClusterType end subroutine -subroutine OpFM_DestroyParam(ParamData, ErrStat, ErrMsg) - type(OpFM_ParameterType), intent(inout) :: ParamData +subroutine ExtInfw_DestroyParam(ParamData, ErrStat, ErrMsg) + type(ExtInfw_ParameterType), intent(inout) :: ParamData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'OpFM_DestroyParam' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyParam' ErrStat = ErrID_None ErrMsg = '' if (associated(ParamData%forceBldRnodes)) then @@ -1092,10 +1092,10 @@ subroutine OpFM_DestroyParam(ParamData, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_PackParam(Buf, Indata) +subroutine ExtInfw_PackParam(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_ParameterType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackParam' + type(ExtInfw_ParameterType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackParam' logical :: PtrInIndex if (Buf%ErrStat >= AbortErrLev) return if (c_associated(InData%C_obj%object)) then @@ -1132,10 +1132,10 @@ subroutine OpFM_PackParam(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackParam(Buf, OutData) +subroutine ExtInfw_UnPackParam(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_ParameterType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackParam' + type(ExtInfw_ParameterType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackParam' integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc @@ -1229,8 +1229,8 @@ subroutine OpFM_UnPackParam(Buf, OutData) OutData%C_obj%NodeClusterType = OutData%NodeClusterType end subroutine -SUBROUTINE OpFM_C2Fary_CopyParam(ParamData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_ParameterType), INTENT(INOUT) :: ParamData +SUBROUTINE ExtInfw_C2Fary_CopyParam(ParamData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_ParameterType), INTENT(INOUT) :: ParamData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -1275,8 +1275,8 @@ SUBROUTINE OpFM_C2Fary_CopyParam(ParamData, ErrStat, ErrMsg, SkipPointers) ParamData%NodeClusterType = ParamData%C_obj%NodeClusterType END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyParam( ParamData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_ParameterType), INTENT(INOUT) :: ParamData +SUBROUTINE ExtInfw_F2C_CopyParam( ParamData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_ParameterType), INTENT(INOUT) :: ParamData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -1327,15 +1327,15 @@ SUBROUTINE OpFM_F2C_CopyParam( ParamData, ErrStat, ErrMsg, SkipPointers ) ParamData%C_obj%NodeClusterType = ParamData%NodeClusterType END SUBROUTINE -subroutine OpFM_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_InputType), intent(in) :: SrcInputData - type(OpFM_InputType), intent(inout) :: DstInputData +subroutine ExtInfw_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_InputType), intent(in) :: SrcInputData + type(ExtInfw_InputType), intent(inout) :: DstInputData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 - character(*), parameter :: RoutineName = 'OpFM_CopyInput' + character(*), parameter :: RoutineName = 'ExtInfw_CopyInput' ErrStat = ErrID_None ErrMsg = '' if (associated(SrcInputData%pxVel)) then @@ -1595,11 +1595,11 @@ subroutine OpFM_CopyInput(SrcInputData, DstInputData, CtrlCode, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_DestroyInput(InputData, ErrStat, ErrMsg) - type(OpFM_InputType), intent(inout) :: InputData +subroutine ExtInfw_DestroyInput(InputData, ErrStat, ErrMsg) + type(ExtInfw_InputType), intent(inout) :: InputData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'OpFM_DestroyInput' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyInput' ErrStat = ErrID_None ErrMsg = '' if (associated(InputData%pxVel)) then @@ -1706,10 +1706,10 @@ subroutine OpFM_DestroyInput(InputData, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_PackInput(Buf, Indata) +subroutine ExtInfw_PackInput(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackInput' + type(ExtInfw_InputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackInput' logical :: PtrInIndex if (Buf%ErrStat >= AbortErrLev) return if (c_associated(InData%C_obj%object)) then @@ -1855,10 +1855,10 @@ subroutine OpFM_PackInput(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackInput(Buf, OutData) +subroutine ExtInfw_UnPackInput(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_InputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackInput' + type(ExtInfw_InputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackInput' integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc @@ -2309,8 +2309,8 @@ subroutine OpFM_UnPackInput(Buf, OutData) end if end subroutine -SUBROUTINE OpFM_C2Fary_CopyInput(InputData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_InputType), INTENT(INOUT) :: InputData +SUBROUTINE ExtInfw_C2Fary_CopyInput(InputData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_InputType), INTENT(INOUT) :: InputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -2479,8 +2479,8 @@ SUBROUTINE OpFM_C2Fary_CopyInput(InputData, ErrStat, ErrMsg, SkipPointers) END IF END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyInput( InputData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_InputType), INTENT(INOUT) :: InputData +SUBROUTINE ExtInfw_F2C_CopyInput( InputData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_InputType), INTENT(INOUT) :: InputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -2700,15 +2700,15 @@ SUBROUTINE OpFM_F2C_CopyInput( InputData, ErrStat, ErrMsg, SkipPointers ) END IF END SUBROUTINE -subroutine OpFM_CopyOutput(SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg) - type(OpFM_OutputType), intent(in) :: SrcOutputData - type(OpFM_OutputType), intent(inout) :: DstOutputData +subroutine ExtInfw_CopyOutput(SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrMsg) + type(ExtInfw_OutputType), intent(in) :: SrcOutputData + type(ExtInfw_OutputType), intent(inout) :: DstOutputData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 - character(*), parameter :: RoutineName = 'OpFM_CopyOutput' + character(*), parameter :: RoutineName = 'ExtInfw_CopyOutput' ErrStat = ErrID_None ErrMsg = '' if (associated(SrcOutputData%u)) then @@ -2770,11 +2770,11 @@ subroutine OpFM_CopyOutput(SrcOutputData, DstOutputData, CtrlCode, ErrStat, ErrM end if end subroutine -subroutine OpFM_DestroyOutput(OutputData, ErrStat, ErrMsg) - type(OpFM_OutputType), intent(inout) :: OutputData +subroutine ExtInfw_DestroyOutput(OutputData, ErrStat, ErrMsg) + type(ExtInfw_OutputType), intent(inout) :: OutputData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - character(*), parameter :: RoutineName = 'OpFM_DestroyOutput' + character(*), parameter :: RoutineName = 'ExtInfw_DestroyOutput' ErrStat = ErrID_None ErrMsg = '' if (associated(OutputData%u)) then @@ -2800,10 +2800,10 @@ subroutine OpFM_DestroyOutput(OutputData, ErrStat, ErrMsg) end if end subroutine -subroutine OpFM_PackOutput(Buf, Indata) +subroutine ExtInfw_PackOutput(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpFM_OutputType), intent(in) :: InData - character(*), parameter :: RoutineName = 'OpFM_PackOutput' + type(ExtInfw_OutputType), intent(in) :: InData + character(*), parameter :: RoutineName = 'ExtInfw_PackOutput' logical :: PtrInIndex if (Buf%ErrStat >= AbortErrLev) return if (c_associated(InData%C_obj%object)) then @@ -2842,10 +2842,10 @@ subroutine OpFM_PackOutput(Buf, Indata) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine OpFM_UnPackOutput(Buf, OutData) +subroutine ExtInfw_UnPackOutput(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpFM_OutputType), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'OpFM_UnPackOutput' + type(ExtInfw_OutputType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'ExtInfw_UnPackOutput' integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: stat logical :: IsAllocAssoc @@ -2946,8 +2946,8 @@ subroutine OpFM_UnPackOutput(Buf, OutData) end if end subroutine -SUBROUTINE OpFM_C2Fary_CopyOutput(OutputData, ErrStat, ErrMsg, SkipPointers) - TYPE(OpFM_OutputType), INTENT(INOUT) :: OutputData +SUBROUTINE ExtInfw_C2Fary_CopyOutput(OutputData, ErrStat, ErrMsg, SkipPointers) + TYPE(ExtInfw_OutputType), INTENT(INOUT) :: OutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -2990,8 +2990,8 @@ SUBROUTINE OpFM_C2Fary_CopyOutput(OutputData, ErrStat, ErrMsg, SkipPointers) END IF END SUBROUTINE -SUBROUTINE OpFM_F2C_CopyOutput( OutputData, ErrStat, ErrMsg, SkipPointers ) - TYPE(OpFM_OutputType), INTENT(INOUT) :: OutputData +SUBROUTINE ExtInfw_F2C_CopyOutput( OutputData, ErrStat, ErrMsg, SkipPointers ) + TYPE(ExtInfw_OutputType), INTENT(INOUT) :: OutputData INTEGER(IntKi), INTENT( OUT) :: ErrStat CHARACTER(*), INTENT( OUT) :: ErrMsg LOGICAL,OPTIONAL,INTENT(IN ) :: SkipPointers @@ -3043,7 +3043,7 @@ SUBROUTINE OpFM_F2C_CopyOutput( OutputData, ErrStat, ErrMsg, SkipPointers ) END IF END SUBROUTINE -subroutine OpFM_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) +subroutine ExtInfw_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) ! ! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time ! values of u (which has values associated with times in t). Order of the interpolation is given by the size of u @@ -3059,9 +3059,9 @@ subroutine OpFM_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) ! !---------------------------------------------------------------------------------------------------------------------------------- - type(OpFM_InputType), intent(in) :: u(:) ! Input at t1 > t2 > t3 + type(ExtInfw_InputType), intent(in) :: u(:) ! Input at t1 > t2 > t3 real(DbKi), intent(in ) :: t(:) ! Times associated with the Inputs - type(OpFM_InputType), intent(inout) :: u_out ! Input at tin_out + type(ExtInfw_InputType), intent(inout) :: u_out ! Input at tin_out real(DbKi), intent(in ) :: t_out ! time to be extrap/interp'd to integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -3069,7 +3069,7 @@ subroutine OpFM_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) integer(IntKi) :: order ! order of polynomial fit (max 2) integer(IntKi) :: ErrStat2 ! local errors character(ErrMsgLen) :: ErrMsg2 ! local errors - character(*), PARAMETER :: RoutineName = 'OpFM_Input_ExtrapInterp' + character(*), PARAMETER :: RoutineName = 'ExtInfw_Input_ExtrapInterp' ! Initialize ErrStat ErrStat = ErrID_None @@ -3081,13 +3081,13 @@ subroutine OpFM_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) order = size(u) - 1 select case (order) case (0) - call OpFM_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) + call ExtInfw_CopyInput(u(1), u_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case (1) - call OpFM_Input_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2) + call ExtInfw_Input_ExtrapInterp1(u(1), u(2), t, u_out, t_out, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case (2) - call OpFM_Input_ExtrapInterp2(u(1), u(2), u(3), t, u_out, t_out, ErrStat2, ErrMsg2) + call ExtInfw_Input_ExtrapInterp2(u(1), u(2), u(3), t, u_out, t_out, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case default call SetErrStat(ErrID_Fatal, 'size(u) must be less than 4 (order must be less than 3).', ErrStat, ErrMsg, RoutineName) @@ -3095,7 +3095,7 @@ subroutine OpFM_Input_ExtrapInterp(u, t, u_out, t_out, ErrStat, ErrMsg) end select end subroutine -SUBROUTINE OpFM_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) +SUBROUTINE ExtInfw_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ) ! ! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time ! values of u (which has values associated with times in t). Order of the interpolation is 1. @@ -3107,17 +3107,17 @@ SUBROUTINE OpFM_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg ! !.................................................................................................................................. - TYPE(OpFM_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 - TYPE(OpFM_InputType), INTENT(IN) :: u2 ! Input at t2 + TYPE(ExtInfw_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 + TYPE(ExtInfw_InputType), INTENT(IN) :: u2 ! Input at t2 REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Inputs - TYPE(OpFM_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + TYPE(ExtInfw_InputType), INTENT(INOUT) :: u_out ! Input at tin_out REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None ! local variables REAL(DbKi) :: t(2) ! Times associated with the Inputs REAL(DbKi) :: t_out ! Time to which to be extrap/interpd - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_Input_ExtrapInterp1' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_Input_ExtrapInterp1' REAL(DbKi) :: a1, a2 ! temporary for extrapolation/interpolation INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors @@ -3193,7 +3193,7 @@ SUBROUTINE OpFM_Input_ExtrapInterp1(u1, u2, tin, u_out, tin_out, ErrStat, ErrMsg END IF ! check if allocated END SUBROUTINE -SUBROUTINE OpFM_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) +SUBROUTINE ExtInfw_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, ErrMsg ) ! ! This subroutine calculates a extrapolated (or interpolated) Input u_out at time t_out, from previous/future time ! values of u (which has values associated with times in t). Order of the interpolation is 2. @@ -3207,11 +3207,11 @@ SUBROUTINE OpFM_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er ! !.................................................................................................................................. - TYPE(OpFM_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 > t3 - TYPE(OpFM_InputType), INTENT(IN) :: u2 ! Input at t2 > t3 - TYPE(OpFM_InputType), INTENT(IN) :: u3 ! Input at t3 + TYPE(ExtInfw_InputType), INTENT(IN) :: u1 ! Input at t1 > t2 > t3 + TYPE(ExtInfw_InputType), INTENT(IN) :: u2 ! Input at t2 > t3 + TYPE(ExtInfw_InputType), INTENT(IN) :: u3 ! Input at t3 REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Inputs - TYPE(OpFM_InputType), INTENT(INOUT) :: u_out ! Input at tin_out + TYPE(ExtInfw_InputType), INTENT(INOUT) :: u_out ! Input at tin_out REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -3222,7 +3222,7 @@ SUBROUTINE OpFM_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er REAL(DbKi) :: a1,a2,a3 ! temporary for extrapolation/interpolation INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_Input_ExtrapInterp2' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_Input_ExtrapInterp2' INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts INTEGER :: i1 ! dim1 counter variable for arrays ! Initialize ErrStat @@ -3301,7 +3301,7 @@ SUBROUTINE OpFM_Input_ExtrapInterp2(u1, u2, u3, tin, u_out, tin_out, ErrStat, Er END IF ! check if allocated END SUBROUTINE -subroutine OpFM_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) +subroutine ExtInfw_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) ! ! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time ! values of y (which has values associated with times in t). Order of the interpolation is given by the size of y @@ -3317,9 +3317,9 @@ subroutine OpFM_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) ! !---------------------------------------------------------------------------------------------------------------------------------- - type(OpFM_OutputType), intent(in) :: y(:) ! Output at t1 > t2 > t3 + type(ExtInfw_OutputType), intent(in) :: y(:) ! Output at t1 > t2 > t3 real(DbKi), intent(in ) :: t(:) ! Times associated with the Outputs - type(OpFM_OutputType), intent(inout) :: y_out ! Output at tin_out + type(ExtInfw_OutputType), intent(inout) :: y_out ! Output at tin_out real(DbKi), intent(in ) :: t_out ! time to be extrap/interp'd to integer(IntKi), intent( out) :: ErrStat ! Error status of the operation character(*), intent( out) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -3327,7 +3327,7 @@ subroutine OpFM_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) integer(IntKi) :: order ! order of polynomial fit (max 2) integer(IntKi) :: ErrStat2 ! local errors character(ErrMsgLen) :: ErrMsg2 ! local errors - character(*), PARAMETER :: RoutineName = 'OpFM_Output_ExtrapInterp' + character(*), PARAMETER :: RoutineName = 'ExtInfw_Output_ExtrapInterp' ! Initialize ErrStat ErrStat = ErrID_None @@ -3339,13 +3339,13 @@ subroutine OpFM_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) order = size(y) - 1 select case (order) case (0) - call OpFM_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) + call ExtInfw_CopyOutput(y(1), y_out, MESH_UPDATECOPY, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case (1) - call OpFM_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2) + call ExtInfw_Output_ExtrapInterp1(y(1), y(2), t, y_out, t_out, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case (2) - call OpFM_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2) + call ExtInfw_Output_ExtrapInterp2(y(1), y(2), y(3), t, y_out, t_out, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) case default call SetErrStat(ErrID_Fatal, 'size(y) must be less than 4 (order must be less than 3).', ErrStat, ErrMsg, RoutineName) @@ -3353,7 +3353,7 @@ subroutine OpFM_Output_ExtrapInterp(y, t, y_out, t_out, ErrStat, ErrMsg) end select end subroutine -SUBROUTINE OpFM_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) +SUBROUTINE ExtInfw_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMsg ) ! ! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time ! values of y (which has values associated with times in t). Order of the interpolation is 1. @@ -3365,17 +3365,17 @@ SUBROUTINE OpFM_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMs ! !.................................................................................................................................. - TYPE(OpFM_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 - TYPE(OpFM_OutputType), INTENT(IN) :: y2 ! Output at t2 + TYPE(ExtInfw_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 + TYPE(ExtInfw_OutputType), INTENT(IN) :: y2 ! Output at t2 REAL(DbKi), INTENT(IN ) :: tin(2) ! Times associated with the Outputs - TYPE(OpFM_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + TYPE(ExtInfw_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None ! local variables REAL(DbKi) :: t(2) ! Times associated with the Outputs REAL(DbKi) :: t_out ! Time to which to be extrap/interpd - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_Output_ExtrapInterp1' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_Output_ExtrapInterp1' REAL(DbKi) :: a1, a2 ! temporary for extrapolation/interpolation INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors @@ -3412,7 +3412,7 @@ SUBROUTINE OpFM_Output_ExtrapInterp1(y1, y2, tin, y_out, tin_out, ErrStat, ErrMs END IF ! check if allocated END SUBROUTINE -SUBROUTINE OpFM_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) +SUBROUTINE ExtInfw_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, ErrMsg ) ! ! This subroutine calculates a extrapolated (or interpolated) Output y_out at time t_out, from previous/future time ! values of y (which has values associated with times in t). Order of the interpolation is 2. @@ -3426,11 +3426,11 @@ SUBROUTINE OpFM_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, E ! !.................................................................................................................................. - TYPE(OpFM_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 > t3 - TYPE(OpFM_OutputType), INTENT(IN) :: y2 ! Output at t2 > t3 - TYPE(OpFM_OutputType), INTENT(IN) :: y3 ! Output at t3 + TYPE(ExtInfw_OutputType), INTENT(IN) :: y1 ! Output at t1 > t2 > t3 + TYPE(ExtInfw_OutputType), INTENT(IN) :: y2 ! Output at t2 > t3 + TYPE(ExtInfw_OutputType), INTENT(IN) :: y3 ! Output at t3 REAL(DbKi), INTENT(IN ) :: tin(3) ! Times associated with the Outputs - TYPE(OpFM_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out + TYPE(ExtInfw_OutputType), INTENT(INOUT) :: y_out ! Output at tin_out REAL(DbKi), INTENT(IN ) :: tin_out ! time to be extrap/interp'd to INTEGER(IntKi), INTENT( OUT) :: ErrStat ! Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg ! Error message if ErrStat /= ErrID_None @@ -3441,7 +3441,7 @@ SUBROUTINE OpFM_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, E REAL(DbKi) :: a1,a2,a3 ! temporary for extrapolation/interpolation INTEGER(IntKi) :: ErrStat2 ! local errors CHARACTER(ErrMsgLen) :: ErrMsg2 ! local errors - CHARACTER(*), PARAMETER :: RoutineName = 'OpFM_Output_ExtrapInterp2' + CHARACTER(*), PARAMETER :: RoutineName = 'ExtInfw_Output_ExtrapInterp2' INTEGER :: i01 ! dim1 level 0 counter variable for arrays of ddts INTEGER :: i1 ! dim1 counter variable for arrays ! Initialize ErrStat @@ -3480,5 +3480,5 @@ SUBROUTINE OpFM_Output_ExtrapInterp2(y1, y2, y3, tin, y_out, tin_out, ErrStat, E y_out%WriteOutput = a1*y1%WriteOutput + a2*y2%WriteOutput + a3*y3%WriteOutput END IF ! check if allocated END SUBROUTINE -END MODULE OpenFOAM_Types +END MODULE ExternalInflow_Types !ENDOFREGISTRYGENERATEDFILE diff --git a/modules/openfoam/src/OpenFOAM_Types.h b/modules/externalinflow/src/ExternalInflow_Types.h similarity index 71% rename from modules/openfoam/src/OpenFOAM_Types.h rename to modules/externalinflow/src/ExternalInflow_Types.h index 8d60af91d0..90bbbb5f09 100644 --- a/modules/openfoam/src/OpenFOAM_Types.h +++ b/modules/externalinflow/src/ExternalInflow_Types.h @@ -1,11 +1,11 @@ -//!STARTOFREGISTRYGENERATEDFILE 'OpenFOAM_Types.h' +//!STARTOFREGISTRYGENERATEDFILE 'ExternalInflow_Types.h' //! //! WARNING This file is generated automatically by the FAST registry. //! Do not edit. Your changes to this file will be lost. //! -#ifndef _OpenFOAM_TYPES_H -#define _OpenFOAM_TYPES_H +#ifndef _ExternalInflow_TYPES_H +#define _ExternalInflow_TYPES_H #ifdef _WIN32 //define something for Windows (32-bit) #include "stdbool.h" @@ -18,7 +18,7 @@ #define CALL #endif -typedef struct OpFM_InitInputType { +typedef struct ExtInfw_InitInputType { void *object; int NumActForcePtsBlade; int NumActForcePtsTower; @@ -28,19 +28,19 @@ typedef struct OpFM_InitInputType { float TowerHeight; float TowerBaseHeight; int NodeClusterType; -} OpFM_InitInputType_t; +} ExtInfw_InitInputType_t; -typedef struct OpFM_InitOutputType { +typedef struct ExtInfw_InitOutputType { void *object; char *WriteOutputHdr; int WriteOutputHdr_Len; char *WriteOutputUnt; int WriteOutputUnt_Len; -} OpFM_InitOutputType_t; +} ExtInfw_InitOutputType_t; -typedef struct OpFM_MiscVarType { +typedef struct ExtInfw_MiscVarType { void *object; -} OpFM_MiscVarType_t; +} ExtInfw_MiscVarType_t; -typedef struct OpFM_ParameterType { +typedef struct ExtInfw_ParameterType { void *object; float AirDens; int NumBl; @@ -55,9 +55,9 @@ typedef struct OpFM_ParameterType { float TowerHeight; float TowerBaseHeight; int NodeClusterType; -} OpFM_ParameterType_t; +} ExtInfw_ParameterType_t; -typedef struct OpFM_InputType { +typedef struct ExtInfw_InputType { void *object; float *pxVel; int pxVel_Len; float *pyVel; int pyVel_Len; @@ -76,25 +76,25 @@ typedef struct OpFM_InputType { float *momenty; int momenty_Len; float *momentz; int momentz_Len; float *forceNodesChord; int forceNodesChord_Len; -} OpFM_InputType_t; +} ExtInfw_InputType_t; -typedef struct OpFM_OutputType { +typedef struct ExtInfw_OutputType { void *object; float *u; int u_Len; float *v; int v_Len; float *w; int w_Len; float *WriteOutput; int WriteOutput_Len; -} OpFM_OutputType_t; +} ExtInfw_OutputType_t; -typedef struct OpFM_UserData { - OpFM_InitInputType_t OpFM_InitInput; - OpFM_InitOutputType_t OpFM_InitOutput; - OpFM_MiscVarType_t OpFM_Misc; - OpFM_ParameterType_t OpFM_Param; - OpFM_InputType_t OpFM_Input; - OpFM_OutputType_t OpFM_Output; -} OpFM_t; +typedef struct ExtInfw_UserData { + ExtInfw_InitInputType_t ExtInfw_InitInput; + ExtInfw_InitOutputType_t ExtInfw_InitOutput; + ExtInfw_MiscVarType_t ExtInfw_Misc; + ExtInfw_ParameterType_t ExtInfw_Param; + ExtInfw_InputType_t ExtInfw_Input; + ExtInfw_OutputType_t ExtInfw_Output; +} ExtInfw_t; -#endif // _OpenFOAM_TYPES_H +#endif // _ExternalInflow_TYPES_H //!ENDOFREGISTRYGENERATEDFILE diff --git a/modules/extptfm/CMakeLists.txt b/modules/extptfm/CMakeLists.txt index 4eb338ffbc..a9f7fd0c3a 100644 --- a/modules/extptfm/CMakeLists.txt +++ b/modules/extptfm/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/ExtPtfm_MCKF_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/ExtPtfm_MCKF_Types.f90) endif() -add_library(extptfm_mckflib +add_library(extptfm_mckflib STATIC src/ExtPtfm_MCKF.f90 src/ExtPtfm_MCKF_IO.f90 src/ExtPtfm_MCKF_Types.f90 diff --git a/modules/feamooring/CMakeLists.txt b/modules/feamooring/CMakeLists.txt index 20a01aca85..9ff91c38c9 100644 --- a/modules/feamooring/CMakeLists.txt +++ b/modules/feamooring/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/FEAM_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/FEAMooring_Types.f90) endif() -add_library(feamlib +add_library(feamlib STATIC src/FEAM.f90 src/FEAMooring_Types.f90 ) diff --git a/modules/hydrodyn/CMakeLists.txt b/modules/hydrodyn/CMakeLists.txt index feee1f8f7c..7b9a59f9f9 100644 --- a/modules/hydrodyn/CMakeLists.txt +++ b/modules/hydrodyn/CMakeLists.txt @@ -24,7 +24,7 @@ if (GENERATE_TYPES) generate_f90_types(src/WAMIT2.txt ${CMAKE_CURRENT_LIST_DIR}/src/WAMIT2_Types.f90) endif() -add_library(hydrodynlib +add_library(hydrodynlib STATIC src/Conv_Radiation.f90 src/HydroDyn.f90 src/HydroDyn_Input.f90 @@ -47,7 +47,7 @@ add_library(hydrodynlib target_link_libraries(hydrodynlib seastlib nwtclibs) # HydroDyn Driver Subs Library -add_library(hydrodyn_driver_subs +add_library(hydrodyn_driver_subs STATIC src/HydroDyn_DriverSubs.f90 ) target_link_libraries(hydrodyn_driver_subs hydrodynlib) diff --git a/modules/hydrodyn/src/HydroDyn.f90 b/modules/hydrodyn/src/HydroDyn.f90 index 1fe48f7e65..ba95f2d4ee 100644 --- a/modules/hydrodyn/src/HydroDyn.f90 +++ b/modules/hydrodyn/src/HydroDyn.f90 @@ -1276,7 +1276,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/icedyn/CMakeLists.txt b/modules/icedyn/CMakeLists.txt index 77f4d42949..cfbd2e9d72 100644 --- a/modules/icedyn/CMakeLists.txt +++ b/modules/icedyn/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/Registry_IceDyn.txt ${CMAKE_CURRENT_LIST_DIR}/src/IceDyn_Types.f90) endif() -add_library(icedynlib +add_library(icedynlib STATIC src/IceDyn.f90 src/IceDyn_Types.f90 ) diff --git a/modules/icefloe/CMakeLists.txt b/modules/icefloe/CMakeLists.txt index 8bba15450a..0cd33d9af1 100644 --- a/modules/icefloe/CMakeLists.txt +++ b/modules/icefloe/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/interfaces/FAST/IceFloe_FASTRegistry.inp ${CMAKE_CURRENT_LIST_DIR}/src/icefloe/IceFloe_Types.f90) endif() -add_library(icefloelib +add_library(icefloelib STATIC src/icefloe/IceFlexBase.F90 src/icefloe/IceFlexIEC.f90 src/icefloe/IceFlexISO.f90 diff --git a/modules/inflowwind/CMakeLists.txt b/modules/inflowwind/CMakeLists.txt index 7e7005d9b3..8e5b3c2e34 100644 --- a/modules/inflowwind/CMakeLists.txt +++ b/modules/inflowwind/CMakeLists.txt @@ -22,7 +22,7 @@ if (GENERATE_TYPES) endif() # InflowWind object library -add_library(ifwlib +add_library(ifwlib STATIC src/IfW_FlowField_Types.f90 src/IfW_FlowField.f90 src/InflowWind_IO_Types.f90 diff --git a/modules/inflowwind/src/IfW_FlowField.f90 b/modules/inflowwind/src/IfW_FlowField.f90 index 80cd44fd69..4232dca0c2 100644 --- a/modules/inflowwind/src/IfW_FlowField.f90 +++ b/modules/inflowwind/src/IfW_FlowField.f90 @@ -1256,34 +1256,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 @@ -1292,13 +1290,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 @@ -1553,6 +1551,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 = "" @@ -1567,7 +1566,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 @@ -1580,9 +1585,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 @@ -1613,7 +1624,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 00b63f285e..28d1fc208d 100644 --- a/modules/inflowwind/src/IfW_FlowField.txt +++ b/modules/inflowwind/src/IfW_FlowField.txt @@ -93,7 +93,7 @@ typedef ^ ^ LOGICAL BoxExceedAllo #---------------------------------------------------------------------------------------------------------------------------------- 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 diff --git a/modules/inflowwind/src/IfW_FlowField_Types.f90 b/modules/inflowwind/src/IfW_FlowField_Types.f90 index 700e246352..bb8a9b991f 100644 --- a/modules/inflowwind/src/IfW_FlowField_Types.f90 +++ b/modules/inflowwind/src/IfW_FlowField_Types.f90 @@ -129,7 +129,7 @@ MODULE IfW_FlowField_Types ! ========= Grid4DFieldType ======= TYPE, PUBLIC :: Grid4DFieldType INTEGER(IntKi) , DIMENSION(1:4) :: n = 0_IntKi !< number of evenly-spaced grid points in the x, y, z, and t directions [-] - REAL(ReKi) , DIMENSION(1:4) :: delta = 0.0_ReKi !< size between 2 consecutive grid points in each grid direction [m,m,m,s] + REAL(DbKi) , DIMENSION(1:4) :: delta = 0.0_R8Ki !< size between 2 consecutive grid points in each grid direction [m,m,m,s] REAL(ReKi) , DIMENSION(1:3) :: pZero = 0.0_ReKi !< fixed position of the XYZ grid (i.e., XYZ coordinates of m%V(:,1,1,1,:)) [m] REAL(SiKi) , DIMENSION(:,:,:,:,:), POINTER :: Vel => NULL() !< this is the 4-d velocity field for each wind component [{uvw},nx,ny,nz,nt] [-] REAL(ReKi) :: TimeStart = 0.0_ReKi !< this is the time where the first time grid in m%V starts (i.e, the time associated with m%V(:,:,:,:,1)) [s] diff --git a/modules/inflowwind/src/InflowWind.f90 b/modules/inflowwind/src/InflowWind.f90 index 8030e7c7d2..d22e13cd9d 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 @@ -304,7 +302,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() @@ -324,7 +322,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() @@ -339,7 +337,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() @@ -365,7 +363,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() @@ -374,7 +372,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 @@ -384,7 +382,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() @@ -420,7 +418,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() @@ -433,7 +431,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() @@ -519,7 +517,7 @@ SUBROUTINE InflowWind_Init( InitInp, InputGuess, p, ContStates, DiscStates, Cons InitInp%BoxExceedAllow .or. (p%lidar%SensorType /= SensorType_None) ! Calculate field average if box is allowed to be exceeded - if (p%FlowField%Grid3D%BoxExceedAllow) then + if (p%FlowField%Grid3D%BoxExceedAllow) 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 0de132b70c..98ca14aef2 100644 --- a/modules/inflowwind/src/InflowWind_Driver.f90 +++ b/modules/inflowwind/src/InflowWind_Driver.f90 @@ -736,8 +736,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 3405d90af4..ac4a9b5d9e 100644 --- a/modules/inflowwind/src/InflowWind_IO.f90 +++ b/modules/inflowwind/src/InflowWind_IO.f90 @@ -1029,7 +1029,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) @@ -2530,8 +2530,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 517aa1096f..14531600f7 100644 --- a/modules/inflowwind/src/InflowWind_Subs.f90 +++ b/modules/inflowwind/src/InflowWind_Subs.f90 @@ -679,7 +679,7 @@ SUBROUTINE InflowWind_ValidateInput( InitInp, InputFileData, ErrStat, ErrMsg ) ! make sure that all values for WindVzi are above ground. Set to 0 otherwise. - IF ( InitInp%MHK == 1 .or. InitInp%MHK == 2 ) THEN + IF ( InitInp%MHK /= MHK_None ) THEN DO I = 1, InputFileData%NWindVel IF ( InputFileData%WindVziList(I) >= InitInp%WtrDpth + InitInp%MSL2SWL ) THEN CALL SetErrStat( ErrID_Warn, ' Requested wind velocity at point ( '// & diff --git a/modules/inflowwind/src/Lidar.f90 b/modules/inflowwind/src/Lidar.f90 index 2f80c37938..6250b75ae7 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 diff --git a/modules/map/CMakeLists.txt b/modules/map/CMakeLists.txt index ef52239d12..43da778252 100644 --- a/modules/map/CMakeLists.txt +++ b/modules/map/CMakeLists.txt @@ -33,32 +33,23 @@ endif() file(GLOB MAP_CLIB_SOURCES src/*.c src/*.cc src/*/*.c src/*/*.cc) file(GLOB MAP_C_HEADERS src/*.h src/*/*.h) -add_library(maplib_fortran - src/MAP_Fortran_Types.f90 +add_library(maplib STATIC + src/map.f90 src/MAP_Types.f90 -) -target_link_libraries(maplib_fortran nwtclibs) - -add_library(maplib_c + src/MAP_Fortran_Types.f90 ${MAP_CLIB_SOURCES} - ${MAP_C_HEADERS} ) -target_link_libraries(maplib_c nwtclibs) -target_include_directories(maplib_c PUBLIC +target_link_libraries(maplib nwtclibs) +target_include_directories(maplib PUBLIC $ $ $ $ $ ) -set_target_properties(maplib_c PROPERTIES PUBLIC_HEADER src/MAP_Types.h) - -add_library(maplib - src/map.f90 -) -target_link_libraries(maplib maplib_fortran maplib_c) +set_target_properties(maplib PROPERTIES PUBLIC_HEADER src/MAP_Types.h) -install(TARGETS maplib maplib_fortran maplib_c +install(TARGETS maplib EXPORT "${CMAKE_PROJECT_NAME}Libraries" RUNTIME DESTINATION bin ARCHIVE DESTINATION lib 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/CMakeLists.txt b/modules/moordyn/CMakeLists.txt index ec15a3f329..7cb0cf82e5 100644 --- a/modules/moordyn/CMakeLists.txt +++ b/modules/moordyn/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/MoorDyn_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/MoorDyn_Types.f90) endif() -add_library(moordynlib +add_library(moordynlib STATIC src/MoorDyn.f90 src/MoorDyn_Body.f90 src/MoorDyn_IO.f90 diff --git a/modules/nwtc-library/CMakeLists.txt b/modules/nwtc-library/CMakeLists.txt index 81a39fc2a0..fab4131327 100644 --- a/modules/nwtc-library/CMakeLists.txt +++ b/modules/nwtc-library/CMakeLists.txt @@ -141,7 +141,10 @@ if (CMAKE_BUILD_TYPE MATCHES Debug) endif() # Create NWTC Library -add_library(nwtclibs ${NWTC_SYS_FILE} ${NWTCLIBS_SOURCES}) +add_library(nwtclibs STATIC + ${NWTC_SYS_FILE} + ${NWTCLIBS_SOURCES} +) target_link_libraries(nwtclibs PUBLIC ${LAPACK_LIBRARIES} ${CMAKE_DL_LIBS} diff --git a/modules/nwtc-library/src/ModReg.f90 b/modules/nwtc-library/src/ModReg.f90 index 2dd0fd829d..8ba353b4b7 100644 --- a/modules/nwtc-library/src/ModReg.f90 +++ b/modules/nwtc-library/src/ModReg.f90 @@ -5,7 +5,7 @@ module ModReg private public :: PackBuffer - public :: WritePackBuffer, ReadPackBuffer, InitPackBuffer, RegCheckErr + public :: WritePackBuffer, ReadPackBuffer, InitPackBuffer, DestroyPackBuffer, RegCheckErr public :: RegPack, RegPackBounds, RegPackPointer public :: RegUnpack, RegUnpackBounds, RegUnpackPointer @@ -85,6 +85,25 @@ subroutine InitPackBuffer(Buf, ErrStat, ErrMsg) end subroutine + subroutine DestroyPackBuffer(Buf, ErrStat, ErrMsg) + type(PackBuffer), intent(inout) :: Buf + integer(IntKi), intent(out) :: ErrStat + character(ErrMsgLen), intent(out) :: ErrMsg + + character(*), parameter :: RoutineName = "DestroyPackBuffer" + + ErrStat = ErrID_None + ErrMsg = "" + + Buf%ErrStat = ErrID_None + Buf%ErrMsg = "" + Buf%NP = 0 + Buf%NB = 0 + + if (allocated(Buf%Pointers)) deallocate (Buf%Pointers) + if (allocated(Buf%Bytes )) deallocate (Buf%Bytes) + end subroutine + subroutine WritePackBuffer(Buf, Unit, ErrStat, ErrMsg) type(PackBuffer), intent(inout) :: Buf integer(IntKi), intent(in) :: Unit diff --git a/modules/nwtc-library/src/NWTC_IO.f90 b/modules/nwtc-library/src/NWTC_IO.f90 index b7e5707fea..25d317c68d 100644 --- a/modules/nwtc-library/src/NWTC_IO.f90 +++ b/modules/nwtc-library/src/NWTC_IO.f90 @@ -58,7 +58,7 @@ MODULE NWTC_IO LOGICAL :: Beep = .TRUE. !< Flag that specifies whether or not to beep for error messages and program terminations. - CHARACTER(20) :: ProgName = ' ' !< The name of the calling program. DO NOT USE THIS IN NEW PROGRAMS (Modules) + CHARACTER(25) :: ProgName = ' ' !< The name of the calling program. DO NOT USE THIS IN NEW PROGRAMS (Modules) CHARACTER(99) :: ProgVer = ' ' !< The version (including date) of the calling program. DO NOT USE THIS IN NEW PROGRAMS CHARACTER(1), PARAMETER :: Tab = CHAR( 9 ) !< The tab character. CHARACTER(*), PARAMETER :: CommChars = '!#%' !< Comment characters that mark the end of useful input @@ -6379,7 +6379,6 @@ SUBROUTINE ReadIAryWDefault ( UnIn, Fil, Var, AryLen, VarName, VarDescr, VarDefa CHARACTER( *), INTENT(IN) :: VarDescr !< Text string describing the variable. CHARACTER( *), INTENT(IN) :: VarName !< Text string containing the variable name. ! Local declarations: - INTEGER :: IOS ! I/O status returned from the read statement. CHARACTER(1024) :: sVar ! String to hold the value of the variable ! Read full content of variable as one string, should it be "default", or an array CALL ReadVar (UnIn, Fil, sVar, VarName, VarDescr, ErrStat, ErrMsg, UnEc) diff --git a/modules/nwtc-library/src/NWTC_Library.f90 b/modules/nwtc-library/src/NWTC_Library.f90 index 9772468d1b..c27ede5c1c 100644 --- a/modules/nwtc-library/src/NWTC_Library.f90 +++ b/modules/nwtc-library/src/NWTC_Library.f90 @@ -82,6 +82,11 @@ MODULE NWTC_Library #endif IMPLICIT NONE + + INTEGER, PARAMETER ::MHK_None = 0 + INTEGER, PARAMETER ::MHK_FixedBottom = 1 + INTEGER, PARAMETER ::MHK_Floating = 2 + CONTAINS diff --git a/modules/nwtc-library/src/NWTC_Num.f90 b/modules/nwtc-library/src/NWTC_Num.f90 index 3168adb776..012a6f280a 100644 --- a/modules/nwtc-library/src/NWTC_Num.f90 +++ b/modules/nwtc-library/src/NWTC_Num.f90 @@ -6383,7 +6383,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) @@ -6427,7 +6433,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) @@ -6470,7 +6482,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) @@ -6514,7 +6532,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) @@ -6560,7 +6584,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) @@ -6623,7 +6653,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) @@ -6686,7 +6722,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) @@ -6749,7 +6791,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/CMakeLists.txt b/modules/openfast-library/CMakeLists.txt index d6d973f5e1..bec742da71 100644 --- a/modules/openfast-library/CMakeLists.txt +++ b/modules/openfast-library/CMakeLists.txt @@ -37,7 +37,9 @@ elseif (${_compiler_id} MATCHES "^INTEL" AND ${_build_type} STREQUAL "RELEASE" A set_source_files_properties(src/FAST_Types.f90 PROPERTIES COMPILE_FLAGS "-O2") endif() -add_library(openfast_prelib src/FAST_Types.f90) +add_library(openfast_prelib STATIC + src/FAST_Types.f90 +) target_link_libraries(openfast_prelib nwtclibs versioninfolib @@ -47,7 +49,7 @@ target_link_libraries(openfast_prelib elastodynlib extptfm_mckflib feamlib - foamtypeslib + extinflowtypeslib hydrodynlib icedynlib icefloelib @@ -61,13 +63,15 @@ target_link_libraries(openfast_prelib subdynlib ) -add_library(openfast_postlib +add_library(openfast_postlib STATIC src/FAST_Lin.f90 src/FAST_Mods.f90 src/FAST_Subs.f90 src/FAST_Solver.f90 + src/FAST_SS_Subs.f90 + src/FAST_SS_Solver.f90 ) -target_link_libraries(openfast_postlib openfast_prelib foamfastlib scfastlib) +target_link_libraries(openfast_postlib openfast_prelib extinflowlib scfastlib) target_include_directories(openfast_postlib PUBLIC $ ) @@ -78,7 +82,9 @@ add_library(openfastlib_static INTERFACE) target_link_libraries(openfastlib_static INTERFACE openfast_postlib) # OpenFAST Library shared (Python, openfast_cpp, openfastcpplib) -add_library(openfastlib SHARED src/FAST_Library.f90) +add_library(openfastlib SHARED + src/FAST_Library.f90 +) target_link_libraries(openfastlib openfast_postlib) if(APPLE OR UNIX) target_compile_definitions(openfastlib PRIVATE IMPLICIT_DLLEXPORT) diff --git a/modules/openfast-library/src/FAST_Library.f90 b/modules/openfast-library/src/FAST_Library.f90 index 1a02f350ff..e253a1a44d 100644 --- a/modules/openfast-library/src/FAST_Library.f90 +++ b/modules/openfast-library/src/FAST_Library.f90 @@ -99,8 +99,8 @@ subroutine FAST_Sizes(iTurb, InputFileName_c, AbortErrLev_c, NumOuts_c, dt_c, dt INTEGER(C_INT), INTENT( OUT) :: ErrStat_c CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ChannelNames_c(ChanLen*MAXOUTPUTS+1) - REAL(C_DOUBLE), OPTIONAL, INTENT(IN ) :: TMax - REAL(C_DOUBLE), OPTIONAL, INTENT(IN ) :: InitInpAry(MAXInitINPUTS) + REAL(C_DOUBLE),OPTIONAL,INTENT(IN ) :: TMax + REAL(C_DOUBLE),OPTIONAL,INTENT(IN ) :: InitInpAry(MAXInitINPUTS) ! local CHARACTER(IntfStrLen) :: InputFileName @@ -507,36 +507,36 @@ subroutine FAST_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, NumOuts_c, d end subroutine FAST_Restart !================================================================================================================================== -subroutine FAST_OpFM_Init(iTurb, TMax, InputFileName_c, TurbID, NumSC2CtrlGlob, NumSC2Ctrl, NumCtrl2SC, InitSCOutputsGlob, InitSCOutputsTurbine, NumActForcePtsBlade, NumActForcePtsTower, TurbPosn, AbortErrLev_c, dt_c, NumBl_c, NumBlElem_c, NodeClusterType_c, & - OpFM_Input_from_FAST, OpFM_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_OpFM_Init') +subroutine FAST_ExtInfw_Init(iTurb, TMax, InputFileName_c, TurbID, NumSC2CtrlGlob, NumSC2Ctrl, NumCtrl2SC, InitSCOutputsGlob, InitSCOutputsTurbine, NumActForcePtsBlade, NumActForcePtsTower, TurbPosn, AbortErrLev_c, dt_c, NumBl_c, NumBlElem_c, NodeClusterType_c, & + ExtInfw_Input_from_FAST, ExtInfw_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtInfw_Init') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Init -!GCC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Init +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Init +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Init #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number - REAL(C_DOUBLE), INTENT(IN ) :: TMax - CHARACTER(KIND=C_CHAR), INTENT(IN ) :: InputFileName_c(IntfStrLen) - INTEGER(C_INT), INTENT(IN ) :: TurbID ! Need not be same as iTurb - INTEGER(C_INT), INTENT(IN ) :: NumSC2CtrlGlob ! Supercontroller global outputs = controller global inputs - INTEGER(C_INT), INTENT(IN ) :: NumSC2Ctrl ! Supercontroller outputs = controller inputs - INTEGER(C_INT), INTENT(IN ) :: NumCtrl2SC ! controller outputs = Supercontroller inputs - REAL(C_FLOAT), INTENT(IN ) :: InitScOutputsGlob (*) ! Initial Supercontroller global outputs = controller inputs - REAL(C_FLOAT), INTENT(IN ) :: InitScOutputsTurbine (*) ! Initial Supercontroller turbine specific outputs = controller inputs - INTEGER(C_INT), INTENT(IN ) :: NumActForcePtsBlade ! number of actuator line force points in blade - INTEGER(C_INT), INTENT(IN ) :: NumActForcePtsTower ! number of actuator line force points in tower - INTEGER(C_INT), INTENT(IN ):: NodeClusterType_c - REAL(C_FLOAT), INTENT(IN ) :: TurbPosn(3) - INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c - REAL(C_DOUBLE), INTENT( OUT) :: dt_c - INTEGER(C_INT), INTENT( OUT) :: NumBl_c - INTEGER(C_INT), INTENT( OUT) :: NumBlElem_c - TYPE(OpFM_InputType_C), INTENT(INOUT) :: OpFM_Input_from_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes - TYPE(OpFM_OutputType_C),INTENT(INOUT) :: OpFM_Output_to_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes + INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + REAL(C_DOUBLE), INTENT(IN ) :: TMax + CHARACTER(KIND=C_CHAR), INTENT(IN ) :: InputFileName_c(IntfStrLen) + INTEGER(C_INT), INTENT(IN ) :: TurbID ! Need not be same as iTurb + INTEGER(C_INT), INTENT(IN ) :: NumSC2CtrlGlob ! Supercontroller global outputs = controller global inputs + INTEGER(C_INT), INTENT(IN ) :: NumSC2Ctrl ! Supercontroller outputs = controller inputs + INTEGER(C_INT), INTENT(IN ) :: NumCtrl2SC ! controller outputs = Supercontroller inputs + REAL(C_FLOAT), INTENT(IN ) :: InitScOutputsGlob (*) ! Initial Supercontroller global outputs = controller inputs + REAL(C_FLOAT), INTENT(IN ) :: InitScOutputsTurbine (*) ! Initial Supercontroller turbine specific outputs = controller inputs + INTEGER(C_INT), INTENT(IN ) :: NumActForcePtsBlade ! number of actuator line force points in blade + INTEGER(C_INT), INTENT(IN ) :: NumActForcePtsTower ! number of actuator line force points in tower + INTEGER(C_INT), INTENT(IN ):: NodeClusterType_c + REAL(C_FLOAT), INTENT(IN ) :: TurbPosn(3) + INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c + REAL(C_DOUBLE), INTENT( OUT) :: dt_c + INTEGER(C_INT), INTENT( OUT) :: NumBl_c + INTEGER(C_INT), INTENT( OUT) :: NumBlElem_c + TYPE(ExtInfw_InputType_C), INTENT(INOUT) :: ExtInfw_Input_from_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes + TYPE(ExtInfw_OutputType_C),INTENT(INOUT) :: ExtInfw_Output_to_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes TYPE(SC_DX_InputType_C), INTENT(INOUT) :: SC_DX_Input_from_FAST TYPE(SC_DX_OutputType_C), INTENT(INOUT) :: SC_DX_Output_to_FAST - INTEGER(C_INT), INTENT( OUT) :: ErrStat_c - CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + INTEGER(C_INT), INTENT( OUT) :: ErrStat_c + CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) ! local CHARACTER(IntfStrLen) :: InputFileName @@ -589,7 +589,7 @@ subroutine FAST_OpFM_Init(iTurb, TMax, InputFileName_c, TurbID, NumSC2CtrlGlob, CALL FAST_InitializeAll_T( t_initial, iTurb, Turbine(iTurb), ErrStat, ErrMsg, InputFileName, ExternInitData ) - ! set values for return to OpenFOAM + ! set values for return to ExternalInflow AbortErrLev_c = AbortErrLev dt_c = Turbine(iTurb)%p_FAST%dt ErrStat_c = ErrStat @@ -597,14 +597,14 @@ subroutine FAST_OpFM_Init(iTurb, TMax, InputFileName_c, TurbID, NumSC2CtrlGlob, ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) IF ( ErrStat >= AbortErrLev ) THEN - CALL WrScr( "Error in FAST_OpFM_Init:FAST_InitializeAll_T" // TRIM(ErrMsg) ) + CALL WrScr( "Error in FAST_ExtInfw_Init:FAST_InitializeAll_T" // TRIM(ErrMsg) ) RETURN END IF - call SetOpenFOAM_pointers(iTurb, OpFM_Input_from_FAST, OpFM_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) + call SetExternalInflow_pointers(iTurb, ExtInfw_Input_from_FAST, ExtInfw_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) - ! 7-Sep-2015: Sang wants these integers for the OpenFOAM mapping, which is tied to the AeroDyn nodes. FAST doesn't restrict the number of nodes on each - ! blade mesh to be the same, so if this DOES ever change, we'll need to make OpenFOAM less tied to the AeroDyn mapping. + ! 7-Sep-2015: Sang wants these integers for the ExternalInflow mapping, which is tied to the AeroDyn nodes. FAST doesn't restrict the number of nodes on each + ! blade mesh to be the same, so if this DOES ever change, we'll need to make ExternalInflow less tied to the AeroDyn mapping. IF (Turbine(iTurb)%p_FAST%CompAero == MODULE_AD14) THEN NumBl_c = SIZE(Turbine(iTurb)%AD14%Input(1)%InputMarkers) NumBlElem_c = Turbine(iTurb)%AD14%Input(1)%InputMarkers(1)%Nnodes @@ -625,7 +625,7 @@ LOGICAL FUNCTION FAILED() FAILED = ErrStat >= AbortErrLev IF (ErrStat > 0) THEN - CALL WrScr( "Error in FAST_OpFM_Init:FAST_InitializeAll_T" // TRIM(ErrMsg) ) + CALL WrScr( "Error in FAST_ExtInfw_Init:FAST_InitializeAll_T" // TRIM(ErrMsg) ) IF ( FAILED ) THEN @@ -643,11 +643,11 @@ LOGICAL FUNCTION FAILED() END FUNCTION FAILED end subroutine !================================================================================================================================== -subroutine FAST_OpFM_Solution0(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_OpFM_Solution0') +subroutine FAST_ExtInfw_Solution0(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtInfw_Solution0') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Solution0 -!GCC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Solution0 +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Solution0 +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Solution0 #endif INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number INTEGER(C_INT), INTENT( OUT) :: ErrStat_c @@ -659,34 +659,34 @@ subroutine FAST_OpFM_Solution0(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_O ! CALL SC_SetInputs(Turbine(iTurb)%p_FAST, Turbine(iTurb)%SrvD%y, Turbine(iTurb)%SC_DX, ErrStat, ErrMsg) ! end if - ! set values for return to OpenFOAM + ! set values for return to ExternalInflow ErrStat_c = ErrStat ErrMsg = TRIM(ErrMsg)//C_NULL_CHAR ErrMsg_c = TRANSFER( ErrMsg//C_NULL_CHAR, ErrMsg_c ) -end subroutine FAST_OpFM_Solution0 +end subroutine FAST_ExtInfw_Solution0 !================================================================================================================================== -subroutine FAST_OpFM_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c, numblades_c, numElementsPerBlade_c, n_t_global_c, & - OpFM_Input_from_FAST, OpFM_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_OpFM_Restart') +subroutine FAST_ExtInfw_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c, numblades_c, numElementsPerBlade_c, n_t_global_c, & + ExtInfw_Input_from_FAST, ExtInfw_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtInfw_Restart') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Restart -!GCC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Restart +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Restart +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Restart #endif - INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number - CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CheckpointRootName_c(IntfStrLen) - INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c - INTEGER(C_INT), INTENT( OUT) :: numblades_c - INTEGER(C_INT), INTENT( OUT) :: numElementsPerBlade_c - REAL(C_DOUBLE), INTENT( OUT) :: dt_c - INTEGER(C_INT), INTENT( OUT) :: n_t_global_c - TYPE(OpFM_InputType_C), INTENT(INOUT) :: OpFM_Input_from_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes - TYPE(OpFM_OutputType_C),INTENT(INOUT) :: OpFM_Output_to_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes + INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number + CHARACTER(KIND=C_CHAR), INTENT(IN ) :: CheckpointRootName_c(IntfStrLen) + INTEGER(C_INT), INTENT( OUT) :: AbortErrLev_c + INTEGER(C_INT), INTENT( OUT) :: numblades_c + INTEGER(C_INT), INTENT( OUT) :: numElementsPerBlade_c + REAL(C_DOUBLE), INTENT( OUT) :: dt_c + INTEGER(C_INT), INTENT( OUT) :: n_t_global_c + TYPE(ExtInfw_InputType_C), INTENT(INOUT) :: ExtInfw_Input_from_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes + TYPE(ExtInfw_OutputType_C),INTENT(INOUT) :: ExtInfw_Output_to_FAST !INTENT(INOUT) instead of INTENT(OUT) to avoid gcc compiler warnings about variable tracking sizes TYPE(SC_DX_InputType_C), INTENT(INOUT) :: SC_DX_Input_from_FAST TYPE(SC_DX_OutputType_C), INTENT(INOUT) :: SC_DX_Output_to_FAST - INTEGER(C_INT), INTENT( OUT) :: ErrStat_c - CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) + INTEGER(C_INT), INTENT( OUT) :: ErrStat_c + CHARACTER(KIND=C_CHAR), INTENT( OUT) :: ErrMsg_c(IntfStrLen) ! local variables INTEGER(C_INT) :: NumOuts_c @@ -734,58 +734,58 @@ subroutine FAST_OpFM_Restart(iTurb, CheckpointRootName_c, AbortErrLev_c, dt_c, n if (ErrStat >= AbortErrLev) return - call SetOpenFOAM_pointers(iTurb, OpFM_Input_from_FAST, OpFM_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) + call SetExternalInflow_pointers(iTurb, ExtInfw_Input_from_FAST, ExtInfw_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) -end subroutine FAST_OpFM_Restart +end subroutine FAST_ExtInfw_Restart !================================================================================================================================== -subroutine SetOpenFOAM_pointers(iTurb, OpFM_Input_from_FAST, OpFM_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) +subroutine SetExternalInflow_pointers(iTurb, ExtInfw_Input_from_FAST, ExtInfw_Output_to_FAST, SC_DX_Input_from_FAST, SC_DX_Output_to_FAST) IMPLICIT NONE INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number - TYPE(OpFM_InputType_C), INTENT(INOUT) :: OpFM_Input_from_FAST - TYPE(OpFM_OutputType_C), INTENT(INOUT) :: OpFM_Output_to_FAST + TYPE(ExtInfw_InputType_C), INTENT(INOUT) :: ExtInfw_Input_from_FAST + TYPE(ExtInfw_OutputType_C),INTENT(INOUT) :: ExtInfw_Output_to_FAST TYPE(SC_DX_InputType_C), INTENT(INOUT) :: SC_DX_Input_from_FAST TYPE(SC_DX_OutputType_C), INTENT(INOUT) :: SC_DX_Output_to_FAST - OpFM_Input_from_FAST%pxVel_Len = Turbine(iTurb)%OpFM%u%c_obj%pxVel_Len; OpFM_Input_from_FAST%pxVel = Turbine(iTurb)%OpFM%u%c_obj%pxVel - OpFM_Input_from_FAST%pyVel_Len = Turbine(iTurb)%OpFM%u%c_obj%pyVel_Len; OpFM_Input_from_FAST%pyVel = Turbine(iTurb)%OpFM%u%c_obj%pyVel - OpFM_Input_from_FAST%pzVel_Len = Turbine(iTurb)%OpFM%u%c_obj%pzVel_Len; OpFM_Input_from_FAST%pzVel = Turbine(iTurb)%OpFM%u%c_obj%pzVel - OpFM_Input_from_FAST%pxForce_Len = Turbine(iTurb)%OpFM%u%c_obj%pxForce_Len; OpFM_Input_from_FAST%pxForce = Turbine(iTurb)%OpFM%u%c_obj%pxForce - OpFM_Input_from_FAST%pyForce_Len = Turbine(iTurb)%OpFM%u%c_obj%pyForce_Len; OpFM_Input_from_FAST%pyForce = Turbine(iTurb)%OpFM%u%c_obj%pyForce - OpFM_Input_from_FAST%pzForce_Len = Turbine(iTurb)%OpFM%u%c_obj%pzForce_Len; OpFM_Input_from_FAST%pzForce = Turbine(iTurb)%OpFM%u%c_obj%pzForce - OpFM_Input_from_FAST%xdotForce_Len = Turbine(iTurb)%OpFM%u%c_obj%xdotForce_Len; OpFM_Input_from_FAST%xdotForce = Turbine(iTurb)%OpFM%u%c_obj%xdotForce - OpFM_Input_from_FAST%ydotForce_Len = Turbine(iTurb)%OpFM%u%c_obj%ydotForce_Len; OpFM_Input_from_FAST%ydotForce = Turbine(iTurb)%OpFM%u%c_obj%ydotForce - OpFM_Input_from_FAST%zdotForce_Len = Turbine(iTurb)%OpFM%u%c_obj%zdotForce_Len; OpFM_Input_from_FAST%zdotForce = Turbine(iTurb)%OpFM%u%c_obj%zdotForce - OpFM_Input_from_FAST%pOrientation_Len = Turbine(iTurb)%OpFM%u%c_obj%pOrientation_Len; OpFM_Input_from_FAST%pOrientation = Turbine(iTurb)%OpFM%u%c_obj%pOrientation - OpFM_Input_from_FAST%fx_Len = Turbine(iTurb)%OpFM%u%c_obj%fx_Len; OpFM_Input_from_FAST%fx = Turbine(iTurb)%OpFM%u%c_obj%fx - OpFM_Input_from_FAST%fy_Len = Turbine(iTurb)%OpFM%u%c_obj%fy_Len; OpFM_Input_from_FAST%fy = Turbine(iTurb)%OpFM%u%c_obj%fy - OpFM_Input_from_FAST%fz_Len = Turbine(iTurb)%OpFM%u%c_obj%fz_Len; OpFM_Input_from_FAST%fz = Turbine(iTurb)%OpFM%u%c_obj%fz - OpFM_Input_from_FAST%momentx_Len = Turbine(iTurb)%OpFM%u%c_obj%momentx_Len; OpFM_Input_from_FAST%momentx = Turbine(iTurb)%OpFM%u%c_obj%momentx - OpFM_Input_from_FAST%momenty_Len = Turbine(iTurb)%OpFM%u%c_obj%momenty_Len; OpFM_Input_from_FAST%momenty = Turbine(iTurb)%OpFM%u%c_obj%momenty - OpFM_Input_from_FAST%momentz_Len = Turbine(iTurb)%OpFM%u%c_obj%momentz_Len; OpFM_Input_from_FAST%momentz = Turbine(iTurb)%OpFM%u%c_obj%momentz - OpFM_Input_from_FAST%forceNodesChord_Len = Turbine(iTurb)%OpFM%u%c_obj%forceNodesChord_Len; OpFM_Input_from_FAST%forceNodesChord = Turbine(iTurb)%OpFM%u%c_obj%forceNodesChord + ExtInfw_Input_from_FAST%pxVel_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pxVel_Len; ExtInfw_Input_from_FAST%pxVel = Turbine(iTurb)%ExtInfw%u%c_obj%pxVel + ExtInfw_Input_from_FAST%pyVel_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pyVel_Len; ExtInfw_Input_from_FAST%pyVel = Turbine(iTurb)%ExtInfw%u%c_obj%pyVel + ExtInfw_Input_from_FAST%pzVel_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pzVel_Len; ExtInfw_Input_from_FAST%pzVel = Turbine(iTurb)%ExtInfw%u%c_obj%pzVel + ExtInfw_Input_from_FAST%pxForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pxForce_Len; ExtInfw_Input_from_FAST%pxForce = Turbine(iTurb)%ExtInfw%u%c_obj%pxForce + ExtInfw_Input_from_FAST%pyForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pyForce_Len; ExtInfw_Input_from_FAST%pyForce = Turbine(iTurb)%ExtInfw%u%c_obj%pyForce + ExtInfw_Input_from_FAST%pzForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pzForce_Len; ExtInfw_Input_from_FAST%pzForce = Turbine(iTurb)%ExtInfw%u%c_obj%pzForce + ExtInfw_Input_from_FAST%xdotForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%xdotForce_Len; ExtInfw_Input_from_FAST%xdotForce = Turbine(iTurb)%ExtInfw%u%c_obj%xdotForce + ExtInfw_Input_from_FAST%ydotForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%ydotForce_Len; ExtInfw_Input_from_FAST%ydotForce = Turbine(iTurb)%ExtInfw%u%c_obj%ydotForce + ExtInfw_Input_from_FAST%zdotForce_Len = Turbine(iTurb)%ExtInfw%u%c_obj%zdotForce_Len; ExtInfw_Input_from_FAST%zdotForce = Turbine(iTurb)%ExtInfw%u%c_obj%zdotForce + ExtInfw_Input_from_FAST%pOrientation_Len = Turbine(iTurb)%ExtInfw%u%c_obj%pOrientation_Len; ExtInfw_Input_from_FAST%pOrientation = Turbine(iTurb)%ExtInfw%u%c_obj%pOrientation + ExtInfw_Input_from_FAST%fx_Len = Turbine(iTurb)%ExtInfw%u%c_obj%fx_Len; ExtInfw_Input_from_FAST%fx = Turbine(iTurb)%ExtInfw%u%c_obj%fx + ExtInfw_Input_from_FAST%fy_Len = Turbine(iTurb)%ExtInfw%u%c_obj%fy_Len; ExtInfw_Input_from_FAST%fy = Turbine(iTurb)%ExtInfw%u%c_obj%fy + ExtInfw_Input_from_FAST%fz_Len = Turbine(iTurb)%ExtInfw%u%c_obj%fz_Len; ExtInfw_Input_from_FAST%fz = Turbine(iTurb)%ExtInfw%u%c_obj%fz + ExtInfw_Input_from_FAST%momentx_Len = Turbine(iTurb)%ExtInfw%u%c_obj%momentx_Len; ExtInfw_Input_from_FAST%momentx = Turbine(iTurb)%ExtInfw%u%c_obj%momentx + ExtInfw_Input_from_FAST%momenty_Len = Turbine(iTurb)%ExtInfw%u%c_obj%momenty_Len; ExtInfw_Input_from_FAST%momenty = Turbine(iTurb)%ExtInfw%u%c_obj%momenty + ExtInfw_Input_from_FAST%momentz_Len = Turbine(iTurb)%ExtInfw%u%c_obj%momentz_Len; ExtInfw_Input_from_FAST%momentz = Turbine(iTurb)%ExtInfw%u%c_obj%momentz + ExtInfw_Input_from_FAST%forceNodesChord_Len = Turbine(iTurb)%ExtInfw%u%c_obj%forceNodesChord_Len; ExtInfw_Input_from_FAST%forceNodesChord = Turbine(iTurb)%ExtInfw%u%c_obj%forceNodesChord if (Turbine(iTurb)%p_FAST%UseSC) then SC_DX_Input_from_FAST%toSC_Len = Turbine(iTurb)%SC_DX%u%c_obj%toSC_Len SC_DX_Input_from_FAST%toSC = Turbine(iTurb)%SC_DX%u%c_obj%toSC end if - OpFM_Output_to_FAST%u_Len = Turbine(iTurb)%OpFM%y%c_obj%u_Len; OpFM_Output_to_FAST%u = Turbine(iTurb)%OpFM%y%c_obj%u - OpFM_Output_to_FAST%v_Len = Turbine(iTurb)%OpFM%y%c_obj%v_Len; OpFM_Output_to_FAST%v = Turbine(iTurb)%OpFM%y%c_obj%v - OpFM_Output_to_FAST%w_Len = Turbine(iTurb)%OpFM%y%c_obj%w_Len; OpFM_Output_to_FAST%w = Turbine(iTurb)%OpFM%y%c_obj%w + ExtInfw_Output_to_FAST%u_Len = Turbine(iTurb)%ExtInfw%y%c_obj%u_Len; ExtInfw_Output_to_FAST%u = Turbine(iTurb)%ExtInfw%y%c_obj%u + ExtInfw_Output_to_FAST%v_Len = Turbine(iTurb)%ExtInfw%y%c_obj%v_Len; ExtInfw_Output_to_FAST%v = Turbine(iTurb)%ExtInfw%y%c_obj%v + ExtInfw_Output_to_FAST%w_Len = Turbine(iTurb)%ExtInfw%y%c_obj%w_Len; ExtInfw_Output_to_FAST%w = Turbine(iTurb)%ExtInfw%y%c_obj%w if (Turbine(iTurb)%p_FAST%UseSC) then SC_DX_Output_to_FAST%fromSC_Len = Turbine(iTurb)%SC_DX%y%c_obj%fromSC_Len SC_DX_Output_to_FAST%fromSC = Turbine(iTurb)%SC_DX%y%c_obj%fromSC end if -end subroutine SetOpenFOAM_pointers +end subroutine SetExternalInflow_pointers !================================================================================================================================== -subroutine FAST_OpFM_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_OpFM_Step') +subroutine FAST_ExtInfw_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_ExtInfw_Step') IMPLICIT NONE #ifndef IMPLICIT_DLLEXPORT -!DEC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Step -!GCC$ ATTRIBUTES DLLEXPORT :: FAST_OpFM_Step +!DEC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Step +!GCC$ ATTRIBUTES DLLEXPORT :: FAST_ExtInfw_Step #endif INTEGER(C_INT), INTENT(IN ) :: iTurb ! Turbine number INTEGER(C_INT), INTENT( OUT) :: ErrStat_c @@ -822,6 +822,6 @@ subroutine FAST_OpFM_Step(iTurb, ErrStat_c, ErrMsg_c) BIND (C, NAME='FAST_OpFM_S END IF -end subroutine FAST_OpFM_Step +end subroutine FAST_ExtInfw_Step !================================================================================================================================== END MODULE FAST_Data diff --git a/modules/openfast-library/src/FAST_Library.h b/modules/openfast-library/src/FAST_Library.h index 0fcb764f67..779aba9456 100644 --- a/modules/openfast-library/src/FAST_Library.h +++ b/modules/openfast-library/src/FAST_Library.h @@ -2,7 +2,7 @@ #define FAST_LIBRARY_H // routines in FAST_Library_$(PlatformName).dll -#include "OpenFOAM_Types.h" +#include "ExternalInflow_Types.h" #include "SCDataEx_Types.h" #include "stdio.h" @@ -15,13 +15,13 @@ EXTERNAL_ROUTINE void FAST_AllocateTurbines(int * iTurb, int *ErrStat, char *ErrMsg); EXTERNAL_ROUTINE void FAST_DeallocateTurbines(int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_OpFM_Restart(int * iTurb, const char *CheckpointRootName, int *AbortErrLev, double * dt, int * NumBl, int * NumBlElem, int * n_t_global, - OpFM_InputType_t* OpFM_Input, OpFM_OutputType_t* OpFM_Output, SC_DX_InputType_t* SC_DX_Input, SC_DX_OutputType_t* SC_DX_Output, int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_OpFM_Init(int * iTurb, double *TMax, const char *InputFileName, int * TurbineID, int * NumSC2CtrlGlob, int * NumSC2Ctrl, int * NumCtrl2SC, float * initSCInputsGlob, float * initSCInputsTurbine, int * NumActForcePtsBlade, int * NumActForcePtsTower, float * TurbinePosition, - int *AbortErrLev, double * dt, int * NumBl, int * NumBlElem, int * NodeClusterType, OpFM_InputType_t* OpFM_Input, OpFM_OutputType_t* OpFM_Output, SC_DX_InputType_t* SC_DX_Input, SC_DX_OutputType_t* SC_DX_Output, +EXTERNAL_ROUTINE void FAST_ExtInfw_Restart(int * iTurb, const char *CheckpointRootName, int *AbortErrLev, double * dt, int * NumBl, int * NumBlElem, int * n_t_global, + ExtInfw_InputType_t* ExtInfw_Input, ExtInfw_OutputType_t* ExtInfw_Output, SC_DX_InputType_t* SC_DX_Input, SC_DX_OutputType_t* SC_DX_Output, int *ErrStat, char *ErrMsg); +EXTERNAL_ROUTINE void FAST_ExtInfw_Init(int * iTurb, double *TMax, const char *InputFileName, int * TurbineID, int * NumSC2CtrlGlob, int * NumSC2Ctrl, int * NumCtrl2SC, float * initSCInputsGlob, float * initSCInputsTurbine, int * NumActForcePtsBlade, int * NumActForcePtsTower, float * TurbinePosition, + int *AbortErrLev, double * dt, int * NumBl, int * NumBlElem, int * NodeClusterType, ExtInfw_InputType_t* ExtInfw_Input, ExtInfw_OutputType_t* ExtInfw_Output, SC_DX_InputType_t* SC_DX_Input, SC_DX_OutputType_t* SC_DX_Output, int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_OpFM_Solution0(int * iTurb, int *ErrStat, char *ErrMsg); -EXTERNAL_ROUTINE void FAST_OpFM_Step(int * iTurb, int *ErrStat, char *ErrMsg); +EXTERNAL_ROUTINE void FAST_ExtInfw_Solution0(int * iTurb, int *ErrStat, char *ErrMsg); +EXTERNAL_ROUTINE void FAST_ExtInfw_Step(int * iTurb, int *ErrStat, char *ErrMsg); EXTERNAL_ROUTINE void FAST_HubPosition(int * iTurb, float * absolute_position, float * rotation_veocity, double * orientation_dcm, int *ErrStat, char *ErrMsg); diff --git a/modules/openfast-library/src/FAST_Lin.f90 b/modules/openfast-library/src/FAST_Lin.f90 index d68dbec8ec..dae24ac693 100644 --- a/modules/openfast-library/src/FAST_Lin.f90 +++ b/modules/openfast-library/src/FAST_Lin.f90 @@ -332,10 +332,14 @@ SUBROUTINE Init_Lin(p_FAST, y_FAST, m_FAST, AD, ED, NumBl, NumBlNodes, ErrStat, call AllocAry( m_FAST%Lin%y_ref, y_FAST%Lin%Glue%SizeLin(LIN_OUTPUT_COL), 'y_ref', ErrStat2, ErrMsg2) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + !call AllocAry( m_FAST%Lin%eps_squared, y_FAST%Lin%Glue%SizeLin(LIN_OUTPUT_COL), 'eps_squared', ErrStat2, ErrMsg2) ! for debugging + ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat < AbortErrLev) then m_FAST%Lin%y_interp = 0.0_R8Ki m_FAST%Lin%Y_prevRot = 0.0_R8Ki m_FAST%Lin%y_ref = 1.0_R8Ki + !m_FAST%Lin%eps_squared = 0.0_ReKi end if end if @@ -380,51 +384,51 @@ SUBROUTINE Init_Lin_IfW( p_FAST, y_FAST, u_AD ) end do end if - IF (p_FAST%CompAero == MODULE_AD) THEN - - DO K = 1,SIZE(u_AD%rotors(1)%BladeMotion) - DO J = 1,u_AD%rotors(1)%BladeMotion(k)%Nnodes - Node = Node + 1 ! InflowWind node - NodeDesc = ' (blade '//trim(num2lstr(k))//', node '//trim(num2lstr(j))//')' - - do i=1,3 !XYZ components of this node - i2 = (Node-1)*3 + i - - position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2), ',') - 1 - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(1:position)//trim(NodeDesc)//& - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(position+1:) - - position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2), ',') - 1 - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(1:position)//trim(NodeDesc)//& - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(position+1:) - - ! IfW has inputs and outputs in the global frame - !y_FAST%Lin%Modules(Module_IfW)%Instance(1)%RotFrame_u(i2) = .true. - !y_FAST%Lin%Modules(Module_IfW)%Instance(1)%RotFrame_y(i2) = .true. - - end do - END DO !J = 1,p%BldNodes ! Loop through the blade nodes / elements - END DO !K = 1,p%NumBl - - ! tower: - DO J=1,u_AD%rotors(1)%TowerMotion%nnodes - Node = Node + 1 - NodeDesc = ' (Tower node '//trim(num2lstr(j))//')' - - do i=1,3 !XYZ components of this node - i2 = (Node-1)*3 + i - - position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2), ',') - 1 - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(1:position)//trim(NodeDesc)//& - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(position+1:) - - position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2), ',') - 1 - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(1:position)//trim(NodeDesc)//& - y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(position+1:) - end do - END DO - - END IF + ! BJJ: SINCE INFLOWWIND NOW DOES NOT GET INITIALIZED WITH THE NUMBER OF POINTS, THIS CODE DOES NOT APPLY: + !IF (p_FAST%CompAero == MODULE_AD) THEN + ! + ! DO K = 1,SIZE(u_AD%rotors(1)%BladeMotion) + ! DO J = 1,u_AD%rotors(1)%BladeMotion(k)%Nnodes + ! Node = Node + 1 ! InflowWind node + ! NodeDesc = ' (blade '//trim(num2lstr(k))//', node '//trim(num2lstr(j))//')' + ! + ! do i=1,3 !XYZ components of this node + ! i2 = (Node-1)*3 + i + ! position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2), ',') - 1 + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(1:position)//trim(NodeDesc)//& + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(position+1:) + ! + ! position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2), ',') - 1 + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(1:position)//trim(NodeDesc)//& + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(position+1:) + ! + ! ! IfW has inputs and outputs in the global frame + ! !y_FAST%Lin%Modules(Module_IfW)%Instance(1)%RotFrame_u(i2) = .true. + ! !y_FAST%Lin%Modules(Module_IfW)%Instance(1)%RotFrame_y(i2) = .true. + ! + ! end do + ! END DO !J = 1,p%BldNodes ! Loop through the blade nodes / elements + ! END DO !K = 1,p%NumBl + ! + ! ! tower: + ! DO J=1,u_AD%rotors(1)%TowerMotion%nnodes + ! Node = Node + 1 + ! NodeDesc = ' (Tower node '//trim(num2lstr(j))//')' + ! + ! do i=1,3 !XYZ components of this node + ! i2 = (Node-1)*3 + i + ! + ! position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2), ',') - 1 + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(1:position)//trim(NodeDesc)//& + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_u(i2)(position+1:) + ! + ! position = index(y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2), ',') - 1 + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2) = y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(1:position)//trim(NodeDesc)//& + ! y_FAST%Lin%Modules(Module_IfW)%Instance(1)%Names_y(i2)(position+1:) + ! end do + ! END DO + ! + !END IF END SUBROUTINE Init_Lin_IfW !---------------------------------------------------------------------------------------------------------------------------------- @@ -564,7 +568,7 @@ SUBROUTINE Init_Lin_InputOutput(p_FAST, y_FAST, NumBl, NumBlNodes, ErrStat, ErrM END SUBROUTINE Init_Lin_InputOutput !---------------------------------------------------------------------------------------------------------------------------------- !> Routine that performs lineaization at current operating point for a turbine. -SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & +SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, MeshMapData, ErrStat, ErrMsg ) REAL(DbKi), INTENT(IN ) :: t_global !< current (global) simulation time @@ -578,7 +582,7 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm_MCKF data @@ -628,7 +632,7 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, LinRootName = TRIM(p_FAST%OutFileRoot)//'.'//trim(num2lstr(m_FAST%Lin%NextLinTimeIndx)) if (p_FAST%WrVTK == VTK_ModeShapes .and. .not. p_FAST%CalcSteady) then ! we already saved these for the CalcSteady case - call SaveOP(m_FAST%Lin%NextLinTimeIndx, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & + call SaveOP(m_FAST%Lin%NextLinTimeIndx, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat, ErrMsg, m_FAST%Lin%CopyOP_CtrlCode ) !m_FAST%Lin%CopyOP_CtrlCode = MESH_UPDATECOPY ! we need a new copy for each LinTime end if @@ -663,37 +667,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_ED)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - !dXdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) - - !dXdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) - - ! dYdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y ) - - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_ED)%Instance(1)%use_u ) - - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_ED)%Instance(1) ) - - end if + call WriteModuleLinearMatrices(Module_ED, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; !..................... ! BeamDyn @@ -726,35 +701,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_BD))//TRIM(num2lstr(k)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - !dXdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, Un, p_FAST%OutFmt, 'dXdx' ) - - !dXdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) - - !dYdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y ) - - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_BD)%Instance(k)%use_u ) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_BD)%Instance(k) ) - end if + call WriteModuleLinearMatrices(Module_BD, k, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end do end if !BeamDyn @@ -782,27 +730,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_IfW)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_IfW)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_IfW)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', & - UseRow=y_FAST%Lin%Modules(Module_IfW)%Instance(1)%use_y, UseCol=y_FAST%Lin%Modules(Module_IfW)%Instance(1)%use_u ) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_IfW)%Instance(1) ) - - end if + call WriteModuleLinearMatrices(Module_IfW, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if @@ -836,31 +765,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, return end if - ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_SrvD)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_SrvD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - ! Jacobians - if (p_FAST%LinOutJac) then - ! Jacobians - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx') - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_u) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_y) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_SrvD)%Instance(1)%use_u) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_SrvD)%Instance(1) ) - - end if + call WriteModuleLinearMatrices(Module_SrvD, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if !..................... @@ -894,38 +800,11 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, end if ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_AD)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_AD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) - - call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', & - UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) - - call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', & - UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y ) - - call WrPartialMatrix( y_FAST%Lin%Modules(Module_AD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', & - UseRow=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_AD)%Instance(1)%use_u ) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_AD)%Instance(1) ) - end if + call WriteModuleLinearMatrices(Module_AD, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if - !..................... ! HydroDyn !..................... @@ -952,39 +831,9 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_HD)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_HD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - !dXdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) - - !dXdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_u ) - - !dYdx: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_y ) - - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_HD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_HD)%Instance(1)%use_u ) - - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_HD)%Instance(1) ) - - end if + call WriteModuleLinearMatrices(Module_HD, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if - !..................... ! SubDyn / ExtPtfm !..................... @@ -1009,22 +858,9 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, if(Failed()) return; ! write the module matrices: - if (p_FAST%LinOutMod) then - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_SD)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_SD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2) - if(Failed()) return; - - if (p_FAST%LinOutJac) then - ! Jacobians - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx') - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_SD)%Instance(1)%use_u) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_SD)%Instance(1)%use_y) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_SD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_SD)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_SD)%Instance(1)%use_u) - end if - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_SD)%Instance(1) ) - end if + call WriteModuleLinearMatrices(Module_SD, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; + elseif ( p_FAST%CompSub == Module_ExtPtfm ) then ! get the jacobians call ExtPtfm_JacobianPInput( t_global, ExtPtfm%Input(1), ExtPtfm%p, ExtPtfm%x(STATE_CURR), ExtPtfm%xd(STATE_CURR), & @@ -1045,22 +881,9 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, if(Failed()) return; ! write the module matrices: - if (p_FAST%LinOutMod) then - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_ExtPtfm)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2) - if(Failed()) return; - - if (p_FAST%LinOutJac) then - ! Jacobians - call WrPartialMatrix(y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx') - call WrPartialMatrix(y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%use_u) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%use_y) - call WrPartialMatrix(y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1)%use_u) - end if - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_ExtPtfm)%Instance(1) ) - end if + call WriteModuleLinearMatrices(Module_ExtPtfm, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; + end if ! SubDyn/ExtPtfm @@ -1086,28 +909,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, end if ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_MAP)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_MAP)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - !dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_MAP)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', & - UseRow=y_FAST%Lin%Modules(Module_MAP)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_MAP)%Instance(1)%use_u ) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_MAP)%Instance(1) ) - - end if ! if ( p_FAST%LinOutMod ) + call WriteModuleLinearMatrices(Module_MAP, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if ! if ( p_FAST%CompMooring == Module_MAP ) @@ -1141,31 +944,8 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, end if ! write the module matrices: - if (p_FAST%LinOutMod) then - - OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(Module_MD)) - call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(Module_MD)%Instance(1), OutFileName, Un, ErrStat2, ErrMsg2 ) - call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >=AbortErrLev) then - call cleanup() - return - end if - - if (p_FAST%LinOutJac) then - ! Jacobians - ! dXdx, dXdu, dYdx, dYdu: - call WrPartialMatrix( y_FAST%Lin%Modules(Module_MD)%Instance(1)%A, Un, p_FAST%OutFmt, 'dXdx' ) - call WrPartialMatrix( y_FAST%Lin%Modules(Module_MD)%Instance(1)%B, Un, p_FAST%OutFmt, 'dXdu', UseCol=y_FAST%Lin%Modules(Module_MD)%Instance(1)%use_u ) - call WrPartialMatrix( y_FAST%Lin%Modules(Module_MD)%Instance(1)%C, Un, p_FAST%OutFmt, 'dYdx', UseRow=y_FAST%Lin%Modules(Module_MD)%Instance(1)%use_y ) - call WrPartialMatrix( y_FAST%Lin%Modules(Module_MD)%Instance(1)%D, Un, p_FAST%OutFmt, 'dYdu', UseRow=y_FAST%Lin%Modules(Module_MD)%Instance(1)%use_y, & - UseCol=y_FAST%Lin%Modules(Module_MD)%Instance(1)%use_u ) - end if - - ! finish writing the file - call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(Module_MD)%Instance(1) ) - - end if ! if ( p_FAST%LinOutMod ) - end if ! if ( p_FAST%CompMooring == Module_MD ) + call WriteModuleLinearMatrices(Module_MD, 1, t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + if(Failed()) return; end if ! if ( p_FAST%CompMooring == Module_MD ) !..................... ! Linearization of glue code Input/Output solve: @@ -1184,7 +964,7 @@ SUBROUTINE FAST_Linearize_OP(t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, end if ! get the dUdu and dUdy matrices, which linearize SolveOption2 for the modules we've included in linearization - call Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, MAPp, FEAM, MD, Orca, & + call Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, MAPp, FEAM, MD, Orca, & IceF, IceD, MeshMapData, dUdu, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) if (ErrStat >=AbortErrLev) then @@ -1322,6 +1102,8 @@ SUBROUTINE WrLinFile_txt_Head(t_global, p_FAST, y_FAST, LinData, FileName, Un, E WRITE(Un, '(A)') 'Simulation information:' fmt = '(3x,A,1x,'//trim(p_FAST%OutFmt_t)//',1x,A)' + !fmt = '(3x,A,1x,F10.4,1x,A)' + Desc = 'Simulation time:'; WRITE (Un, fmt) Desc, t_global, 's' Desc = 'Rotor Speed:'; WRITE (Un, fmt) Desc, y_FAST%Lin%RotSpeed, 'rad/s' Desc = 'Azimuth:'; WRITE (Un, fmt) Desc, y_FAST%Lin%Azimuth, 'rad' @@ -1349,10 +1131,10 @@ SUBROUTINE WrLinFile_txt_Head(t_global, p_FAST, y_FAST, LinData, FileName, Un, E !...................................................... if (n(Indx_x) > 0) then WRITE(Un, '(A)') 'Order of continuous states:' - call WrLinFile_txt_Table(p_FAST, Un, "Row/Column", LinData%op_x, LinData%names_x, rotFrame=LinData%RotFrame_x, derivOrder=LinData%DerivOrder_x ) + call WrLinFile_txt_Table(p_FAST, Un, "Row/Column", LinData%op_x, LinData%names_x, rotFrame=LinData%RotFrame_x, derivOrder=LinData%DerivOrder_x ) WRITE(Un, '(A)') 'Order of continuous state derivatives:' - call WrLinFile_txt_Table(p_FAST, Un, "Row/Column", LinData%op_dx, LinData%names_x, rotFrame=LinData%RotFrame_x, deriv=.true., derivOrder=LinData%DerivOrder_x ) + call WrLinFile_txt_Table(p_FAST, Un, "Row/Column", LinData%op_dx, LinData%names_x, rotFrame=LinData%RotFrame_x, deriv=.true., derivOrder=LinData%DerivOrder_x ) end if if (n(Indx_xd) > 0) then @@ -1443,6 +1225,8 @@ SUBROUTINE WrLinFile_txt_Table(p_FAST, Un, RowCol, op, names, rotFrame, deriv, d CHARACTER(100) :: Fmt CHARACTER(100) :: Fmt_Str CHARACTER(100) :: FmtOrient + CHARACTER(25) :: DerivStr + CHARACTER(25) :: DerivUnitStr @@ -1469,12 +1253,25 @@ SUBROUTINE WrLinFile_txt_Table(p_FAST, Un, RowCol, op, names, rotFrame, deriv, d i_print = 1 end if + if (UseDerivNames) then + if (p_FAST%CompAeroMaps .and. p_FAST%CompElast /= MODULE_BD) then ! this might not work if we are using some other (not BD, ED) module with states + DerivStr = 'Second time derivative of' + DerivUnitStr = '/s^2' + else + DerivStr = 'First time derivative of' + DerivUnitStr = '/s' + end if + else + DerivStr = '' + DerivUnitStr = '' + end if + do i=1,size(names) UseThisCol = .true. if (present(UseCol)) then UseThisCol = useCol(i) - end if + end if DerivOrdCol = 0 if (present(derivOrder)) DerivOrdCol = derivOrder(i) @@ -1492,12 +1289,12 @@ SUBROUTINE WrLinFile_txt_Table(p_FAST, Un, RowCol, op, names, rotFrame, deriv, d else if (UseThisCol) then if (UseDerivNames) then - WRITE(Un, Fmt) i_print, op(i_op), RotatingCol, DerivOrdCol, 'First time derivative of '//trim(names(i))//'/s' + WRITE(Un, Fmt) i_print, op(i_op), RotatingCol, DerivOrdCol, trim(DerivStr)//' '//trim(names(i))//trim(DerivUnitStr) else WRITE(Un, Fmt) i_print, op(i_op), RotatingCol, DerivOrdCol, trim(names(i)) - end if + end if i_print = i_print + 1 - end if + end if i_op = i_op + 1 end if @@ -1509,7 +1306,68 @@ SUBROUTINE WrLinFile_txt_Table(p_FAST, Un, RowCol, op, names, rotFrame, deriv, d END SUBROUTINE WrLinFile_txt_Table !---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE WriteModuleLinearMatrices(ThisModule, ThisInstance, t_global, p_FAST, y_FAST, LinRootName, ErrStat, ErrMsg) + INTEGER(IntKi), INTENT(IN ) :: ThisModule !< Module index + INTEGER(IntKi), INTENT(IN ) :: ThisInstance !< Module instance index + + REAL(DbKi), INTENT(IN ) :: t_global !< current time step (written in file) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code +! TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + CHARACTER(*), INTENT(IN ) :: LinRootName !< root name for linearization output files + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + CHARACTER(1024) :: OutFileName + INTEGER(IntKi) :: Un ! unit number for linearization file + + ErrStat = ErrID_None + ErrMsg = "" + + ! write the module matrices: + if (p_FAST%LinOutMod) then + + OutFileName = trim(LinRootName)//'.'//TRIM(y_FAST%Module_Abrev(ThisModule)) + if (size(y_FAST%Lin%Modules(ThisModule)%Instance) > 1 .or. ThisModule==Module_BD) OutFileName = trim(OutFileName)//TRIM(num2lstr(ThisInstance)) + + call WrLinFile_txt_Head(t_global, p_FAST, y_FAST, y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance), OutFileName, Un, ErrStat, ErrMsg ) + if (ErrStat >=AbortErrLev) then + if (Un > 0) close(Un) + return + end if + + if (p_FAST%LinOutJac) then + ! Jacobians + !dXdx: + if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%A)) & + call WrPartialMatrix( y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%A, Un, p_FAST%OutFmt, 'dXdx' ) + + !dXdu: + if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%B)) & + call WrPartialMatrix( y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%B, Un, p_FAST%OutFmt, 'dXdu', & + UseCol=y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%use_u ) + + ! dYdx: + if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%C)) & + call WrPartialMatrix( y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%C, Un, p_FAST%OutFmt, 'dYdx', & + UseRow=y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%use_y ) + + !dYdu: + if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%D)) & + call WrPartialMatrix( y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%D, Un, p_FAST%OutFmt, 'dYdu', & + UseRow=y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%use_y, & + UseCol=y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance)%use_u ) + + end if + + ! finish writing the file + call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Modules(ThisModule)%Instance(ThisInstance) ) + + end if +END SUBROUTINE WriteModuleLinearMatrices +!---------------------------------------------------------------------------------------------------------------------------------- !> This routine returns the operating points for the entire glue code. SUBROUTINE Glue_GetOP(p_FAST, y_FAST, ErrStat, ErrMsg) @@ -1602,7 +1460,7 @@ END SUBROUTINE Glue_GetOP !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the Jacobian for the glue-code input-output solves. -SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, MAPp, FEAM, MD, Orca, & +SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, MAPp, FEAM, MD, Orca, & IceF, IceD, MeshMapData, dUdu, dUdy, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code @@ -1614,7 +1472,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(MAP_Data), INTENT(INOUT) :: MAPp !< MAP data @@ -1725,7 +1583,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{SD}} \end{bmatrix} = \f$ and ! \f$ \frac{\partial U_\Lambda^{ED}}{\partial u^{MAP}} \end{bmatrix} = \f$ (dUdu block row 3=ED) !............ - ! we need to do this for CompElast=ED and CompElast=BD + ! we need to do this for CompElast=ED and CompElast=BD call Linear_ED_InputSolve_du( p_FAST, y_FAST, SrvD, ED%Input(1), ED%y, AD%y, AD%Input(1), BD, HD, SD, MAPp, MD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) @@ -1745,7 +1603,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, IF (p_FAST%CompAero == MODULE_AD) THEN call Linear_AD_InputSolve_du( p_FAST, y_FAST, AD%Input(1), ED%y, BD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - end if + END IF @@ -1755,7 +1613,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, IF (p_FAST%CompHydro == MODULE_HD) THEN call Linear_HD_InputSolve_du( p_FAST, y_FAST, HD%Input(1), ED%y, SD%y, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - end if + END IF !............ ! \f$ \frac{\partial U_\Lambda^{SD}}{\partial u^{HD}} \end{bmatrix} = \f$ and @@ -1872,7 +1730,7 @@ SUBROUTINE Glue_Jacobians( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, call Linear_SD_InputSolve_dy( p_FAST, y_FAST, SrvD, SD%Input(1), SD%y, ED%y, HD, MAPp, MD, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) ELSE IF (p_FAST%CompSub == Module_ExtPtfm) THEN - write(*,*)'>>> FAST_LIN: Linear_ExtPtfm_InputSolve_dy, TODO' + CALL WrScr('>>> FAST_LIN: Linear_ExtPtfm_InputSolve_dy, TODO') ENDIF !............ @@ -1926,7 +1784,7 @@ SUBROUTINE Linear_IfW_InputSolve_du_AD( p_FAST, y_FAST, u_AD, dUdu ) do k = 1,size(u_AD%rotors(1)%BladeRootMotion) AD_Start_Bl = AD_Start_Bl + u_AD%rotors(1)%BladeRootMotion(k)%NNodes * 3 ! 1 field (MASKID_Orientation) with 3 components end do - ! next is u_AD%BladeMotion(k): + ! next is u_AD%rotors(1)%BladeMotion(k): DO K = 1,SIZE(u_AD%rotors(1)%BladeMotion) DO J = 1,u_AD%rotors(1)%BladeMotion(k)%Nnodes @@ -2690,7 +2548,7 @@ SUBROUTINE Linear_BD_InputSolve_du( p_FAST, y_FAST, SrvD, y_ED, y_AD, u_AD, BD, ! AD is source in the mapping, so we want M_{uSm} if (allocated(MeshMapData%AD_L_2_BDED_B(k)%dM%m_us )) then - AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! index for the start of u_AD%BladeMotion(k)%translationDisp field + AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! index for the start of u_AD%rotors(1)%BladeMotion(k)%translationDisp field BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) & + BD%Input(1,k)%RootMotion%NNodes *18 & ! displacement, rotation, & acceleration fields for each node @@ -2812,11 +2670,11 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, DO k=1,size(u_AD%rotors(1)%BladeMotion) - AD_Start_td = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! index for u_AD%BladeMotion(k)%translationDisp field + AD_Start_td = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! index for u_AD%rotors(1)%BladeMotion(k)%translationDisp field !AD is the destination here, so we need tv_ud if (allocated( MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud)) then - ! index for u_AD%BladeMotion(k+1)%translationVel field + ! index for u_AD%rotors(1)%BladeMotion(k+1)%translationVel field AD_Start_tv = AD_Start_td + u_AD%rotors(1)%BladeMotion(k)%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field call SetBlockMatrix( dUdu, MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud, AD_Start_tv, AD_Start_td ) @@ -2829,10 +2687,8 @@ SUBROUTINE Linear_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, end if END DO -END SUBROUTINE Linear_AD_InputSolve_du - - +END SUBROUTINE Linear_AD_InputSolve_du !---------------------------------------------------------------------------------------------------------------------------------- !> This routine forms the dU^{SrvD}/du^{SrvD} block (SrvD row) of dUdu. !! (i.e., how do changes in the SrvD inputs affect the SrvD inputs?) @@ -3275,12 +3131,12 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD IF ( p_FAST%CompAero == Module_AD ) THEN IF (p_FAST%CompElast == Module_ED) THEN - AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) + y_AD%rotors(1)%TowerLoad%NNodes * 6 ! start of y_AD%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] + AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) + y_AD%rotors(1)%TowerLoad%NNodes * 6 ! start of y_AD%rotors(1)%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] DO K = 1,SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) !!! ! This linearization was done in forming dUdu (see Linear_ED_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. - !CALL Linearize_Line2_to_Point( y_AD%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%BladeMotion(k), y_ED%BladeLn2Mesh(k) ) + !CALL Linearize_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), y_ED%BladeLn2Mesh(k) ) ! AD loads-to-ED loads transfer (dU^{ED}/dy^{AD}): ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) ! start of u_ED%BladePtLoads(k)%Force field @@ -3291,7 +3147,7 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of y_ED%BladeLn2Mesh(1)%TranslationDisp field call SumBlockMatrix( dUdy, MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD, ED_Start, ED_Out_Start ) - AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%BladeLoad(k+1)%Force field [skip 2 fields to forces on next blade] + AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%rotors(1)%BladeLoad(k+1)%Force field [skip 2 fields to forces on next blade] END DO END IF ! ED @@ -3299,11 +3155,11 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD IF ( y_AD%rotors(1)%TowerLoad%Committed ) THEN !!! ! This linearization was done in forming dUdu (see Linear_ED_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. - !CALL Linearize_Line2_to_Point( y_AD%TowerLoad, u_ED%TowerPtLoads, MeshMapData%AD_L_2_ED_P_T, ErrStat2, ErrMsg2, u_AD%TowerMotion, y_ED%TowerLn2Mesh ) + !CALL Linearize_Line2_to_Point( y_AD%rotors(1)%TowerLoad, u_ED%TowerPtLoads, MeshMapData%AD_L_2_ED_P_T, ErrStat2, ErrMsg2, u_AD%rotors(1)%TowerMotion, y_ED%TowerLn2Mesh ) ! AD loads-to-ED loads transfer (dU^{ED}/dy^{AD}): ED_Start = Indx_u_ED_Tower_Start(u_ED, y_FAST) ! u_ED%TowerPtLoads%Force field - AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) ! start of y_AD%Tower%Force + AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) ! start of y_AD%rotors(1)%Tower%Force call Assemble_dUdy_Loads(y_AD%rotors(1)%TowerLoad, u_ED%TowerPtLoads, MeshMapData%AD_L_2_ED_P_T, ED_Start, AD_Out_Start, dUdy) ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): @@ -3399,7 +3255,7 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD !!! ! This linearization was done in forming dUdu (see Linear_ED_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. MD_Out_Start = y_FAST%Lin%Modules(Module_MD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) - ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) ! start of u_ED%PlatformPtMesh%TranslationDisp field + ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) ! start of u_ED%PlatformPtMesh%Force field call Assemble_dUdy_Loads(MD%y%CoupledLoads(1), u_ED%PlatformPtMesh, MeshMapData%Mooring_2_Structure, ED_Start, MD_Out_Start, dUdy) ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): @@ -3415,7 +3271,7 @@ SUBROUTINE Linear_ED_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD !!! ! while forming dUdy, too. ! CALL Linearize_Point_to_Point( SD%y%Y1Mesh, u_ED%PlatformPtMesh, MeshMapData%SD_TP_2_ED_P, ErrStat2, ErrMsg2, SD%Input(1)%TPMesh, y_ED%PlatformPtMesh) !SD%Input(1)%TPMesh and y_ED%PlatformPtMesh contain the displaced positions for load calculations SD_Out_Start = y_FAST%Lin%Modules(MODULE_SD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) - ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) ! start of u_ED%PlatformPtMesh%TranslationDisp field + ED_Start = Indx_u_ED_Platform_Start(u_ED, y_FAST) ! start of u_ED%PlatformPtMesh%Force field call Assemble_dUdy_Loads(SD%y%Y1Mesh, u_ED%PlatformPtMesh, MeshMapData%SD_TP_2_ED_P, ED_Start, SD_Out_Start, dUdy) ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): @@ -3495,13 +3351,13 @@ SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD !!! ! This linearization was done in forming dUdu (see Linear_BD_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. !!!if (p_FAST%BD_OutputSibling) then - !!! CALL Linearize_Line2_to_Line2( y_AD%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%BladeMotion(k), BD%y(k)%BldMotion ) + !!! CALL Linearize_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), BD%y(k)%BldMotion ) !!!else !!! CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, MeshMapData%y_BD_BldMotion_4Loads(k), MeshMapData%BD_L_2_BD_L(k), ErrStat2, ErrMsg2 ) - !!! CALL Linearize_Line2_to_Line2( y_AD%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%BladeMotion(k), MeshMapData%y_BD_BldMotion_4Loads(k) ) + !!! CALL Linearize_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), MeshMapData%y_BD_BldMotion_4Loads(k) ) !!!end if - AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) + y_AD%rotors(1)%TowerLoad%NNodes * 6 ! start of y_AD%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] + AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) + y_AD%rotors(1)%TowerLoad%NNodes * 6 ! start of y_AD%rotors(1)%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] DO K = 1,p_FAST%nBeams ! Loop through all blades BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) & ! start of BD%Input(1,k)%DistrLoad%Force field @@ -3510,7 +3366,7 @@ SUBROUTINE Linear_BD_InputSolve_dy( p_FAST, y_FAST, SrvD, u_ED, y_ED, y_AD, u_AD ! AD loads-to-BD loads transfer (dU^{BD}/dy^{AD}): call Assemble_dUdy_Loads(y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), BD_Start, AD_Out_Start, dUdy) - AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%BladeLoad(k+1)%Force field [skip the moments to get to forces on next blade] + AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%rotors(1)%BladeLoad(k+1)%Force field [skip the moments to get to forces on next blade] ! BD translation displacement-to-BD moment transfer (dU^{BD}/dy^{BD}): @@ -3587,7 +3443,7 @@ SUBROUTINE Linear_AD_InputSolve_IfW_dy( p_FAST, y_FAST, u_AD, dUdy ) end if - AD_Start = Indx_u_AD_BladeInflow_Start(u_AD, y_FAST) ! start of u_AD%InflowOnBlade array + AD_Start = Indx_u_AD_BladeInflow_Start(u_AD, y_FAST) ! start of u_AD%rotors(1)%InflowOnBlade array do k=1,size(u_AD%rotors(1)%Bld) ! blades do j=1,size(u_AD%rotors(1)%Bld(k)%InflowOnBlade,2) ! nodes @@ -3660,9 +3516,9 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. - !!!CALL Linearize_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%TowerMotion, MeshMapData%ED_L_2_AD_L_T, ErrStat2, ErrMsg2 ) + !!!CALL Linearize_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%rotors(1)%TowerMotion, MeshMapData%ED_L_2_AD_L_T, ErrStat2, ErrMsg2 ) - AD_Start = Indx_u_AD_Tower_Start(u_AD, y_FAST) ! start of u_AD%TowerMotion%TranslationDisp field + AD_Start = Indx_u_AD_Tower_Start(u_AD, y_FAST) ! start of u_AD%rotors(1)%TowerMotion%TranslationDisp field ED_Out_Start = Indx_y_ED_Tower_Start(y_ED, y_FAST) ! start of y_ED%TowerLn2Mesh%TranslationDisp field call Assemble_dUdy_Motions(y_ED%TowerLn2Mesh, u_AD%rotors(1)%TowerMotion, MeshMapData%ED_L_2_AD_L_T, AD_Start, ED_Out_Start, dUdy, skipRotVel=.true.) @@ -3677,7 +3533,7 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa if (errStat>=AbortErrLev) return ! *** AD translational displacement: from ED translational displacement (MeshMapData%ED_P_2_AD_P_H%dM%mi) and orientation (MeshMapData%ED_P_2_AD_P_H%dM%fx_p) - AD_Start = Indx_u_AD_Hub_Start(u_AD, y_FAST) ! start of u_AD%HubMotion%TranslationDisp field + AD_Start = Indx_u_AD_Hub_Start(u_AD, y_FAST) ! start of u_AD%rotors(1)%HubMotion%TranslationDisp field ED_Out_Start = Indx_y_ED_Hub_Start(y_ED, y_FAST) ! start of y_ED%HubPtMotion%TranslationDisp field call SetBlockMatrix( dUdy, MeshMapData%ED_P_2_AD_P_H%dM%mi, AD_Start, ED_Out_Start ) @@ -3704,7 +3560,7 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa if (errStat>=AbortErrLev) return ! *** AD orientation: from ED orientation - AD_Start = Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, k) ! start of u_AD%BladeRootMotion(k)%Orientation field + AD_Start = Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, k) ! start of u_AD%rotors(1)%BladeRootMotion(k)%Orientation field ED_Out_Start = Indx_y_ED_BladeRoot_Start(y_ED, y_FAST, k) & ! start of y_ED%BladeRootMotion(k)%TranslationDisp field + y_ED%BladeRootMotion(k)%NNodes * 3 ! start of y_ED%BladeRootMotion(k)%Orientation field @@ -3722,9 +3578,9 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa DO k=1,size(y_ED%BladeLn2Mesh) !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. - !!!CALL Linearize_Line2_to_Line2( y_ED%BladeLn2Mesh(k), u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + !!!CALL Linearize_Line2_to_Line2( y_ED%BladeLn2Mesh(k), u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) - AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field + AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%rotors(1)%BladeMotion(k)%TranslationDisp field ED_Out_Start = Indx_y_ED_Blade_Start(y_ED, y_FAST, k) ! start of y_ED%BladeLn2Mesh(k)%TranslationDisp field CALL Assemble_dUdy_Motions(y_ED%BladeLn2Mesh(k), u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, ED_Out_Start, dUdy, skipRotAcc=.true.) @@ -3733,10 +3589,10 @@ SUBROUTINE Linear_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMa ELSEIF (p_FAST%CompElast == Module_BD ) THEN !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices !!! ! while forming dUdy, too. - !!!CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + !!!CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) DO k=1,p_FAST%nBeams - AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field + AD_Start = Indx_u_AD_Blade_Start(u_AD, y_FAST, k) ! start of u_AD%rotors(1)%BladeMotion(k)%TranslationDisp field BD_Out_Start = y_FAST%Lin%Modules(Module_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) CALL Assemble_dUdy_Motions(BD%y(k)%BldMotion, u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, BD_Out_Start, dUdy, skipRotAcc=.true.) @@ -3756,8 +3612,8 @@ SUBROUTINE Linear_HD_InputSolve_du( p_FAST, y_FAST, u_HD, y_ED, y_SD, MeshMapDat TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(HydroDyn_InputType), INTENT(INOUT) :: u_HD !< The inputs to HydroDyn - TYPE(ED_OutputType),TARGET, INTENT(IN) :: y_ED !< The outputs from the ElastoDyn structural dynamics module - TYPE(SD_OutputType),TARGET, INTENT(IN) :: y_SD !< The outputs from the SubDyn structural dynamics module + TYPE(ED_OutputType), TARGET, INTENT(IN) :: y_ED !< The outputs from the ElastoDyn structural dynamics module + TYPE(SD_OutputType), TARGET, INTENT(IN) :: y_SD !< The outputs from the SubDyn structural dynamics module TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules REAL(R8Ki), INTENT(INOUT) :: dUdu(:,:) !< Jacobian matrix of which we are computing the dU^{HD}/du^{HD} block @@ -3778,7 +3634,7 @@ SUBROUTINE Linear_HD_InputSolve_du( p_FAST, y_FAST, u_HD, y_ED, y_SD, MeshMapDat ErrStat = ErrID_None ErrMsg = "" - + ! note that we assume this block matrix has been initialized to the identity matrix before calling this routine PlatformMotion => y_ED%PlatformPtMesh @@ -4951,7 +4807,7 @@ END FUNCTION Indx_y_Yaw_Start !---------------------------------------------------------------------------------------------------------------------------------- !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine returns the starting index for the u_AD%TowerMotion mesh in the FAST linearization inputs. +!> This routine returns the starting index for the u_AD%rotors(1)%TowerMotion mesh in the FAST linearization inputs. FUNCTION Indx_u_AD_Tower_Start(u_AD, y_FAST) RESULT(AD_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t @@ -4962,7 +4818,7 @@ FUNCTION Indx_u_AD_Tower_Start(u_AD, y_FAST) RESULT(AD_Start) END FUNCTION Indx_u_AD_Tower_Start !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine returns the starting index for the u_AD%HubMotion mesh in the FAST linearization inputs. +!> This routine returns the starting index for the u_AD%rotors(1)%HubMotion mesh in the FAST linearization inputs. FUNCTION Indx_u_AD_Hub_Start(u_AD, y_FAST) RESULT(AD_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t @@ -4973,7 +4829,7 @@ FUNCTION Indx_u_AD_Hub_Start(u_AD, y_FAST) RESULT(AD_Start) END FUNCTION Indx_u_AD_Hub_Start !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine returns the starting index for the u_AD%BladeRootMotion(k) mesh in the FAST linearization inputs. +!> This routine returns the starting index for the u_AD%rotors(1)%BladeRootMotion(k) mesh in the FAST linearization inputs. FUNCTION Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, BladeNum) RESULT(AD_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t @@ -4989,7 +4845,7 @@ FUNCTION Indx_u_AD_BladeRoot_Start(u_AD, y_FAST, BladeNum) RESULT(AD_Start) end do END FUNCTION Indx_u_AD_BladeRoot_Start !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine returns the starting index for the u_AD%BladeMotion(k) mesh in the FAST linearization inputs. +!> This routine returns the starting index for the u_AD%rotors(1)%BladeMotion(k) mesh in the FAST linearization inputs. FUNCTION Indx_u_AD_Blade_Start(u_AD, y_FAST, BladeNum) RESULT(AD_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t @@ -5005,7 +4861,7 @@ FUNCTION Indx_u_AD_Blade_Start(u_AD, y_FAST, BladeNum) RESULT(AD_Start) end do END FUNCTION Indx_u_AD_Blade_Start !---------------------------------------------------------------------------------------------------------------------------------- -!> This routine returns the starting index for the u_AD%InflowOnBlade array in the FAST linearization inputs. +!> This routine returns the starting index for the u_AD%rotors(1)%InflowOnBlade array in the FAST linearization inputs. FUNCTION Indx_u_AD_BladeInflow_Start(u_AD, y_FAST) RESULT(AD_Start) TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t @@ -5332,7 +5188,7 @@ END SUBROUTINE AllocateOP !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine is the inverse of SetOperatingPoint(). It saves the current operating points so they can be retrieved !> when visualizing mode shapes. -SUBROUTINE SaveOP(i, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & +SUBROUTINE SaveOP(i, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat, ErrMsg, CtrlCode ) INTEGER(IntKi) , INTENT(IN ) :: i !< current index into LinTimes @@ -5344,7 +5200,7 @@ SUBROUTINE SaveOP(i, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtf TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm_MCKF data @@ -5579,7 +5435,7 @@ END SUBROUTINE SaveOP !---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine takes arrays representing the eigenvector of the states and uses it to modify the operating points for !! continuous states. It is highly tied to the module organizaton. -SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & +SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat, ErrMsg ) REAL(DbKi), INTENT(IN ) :: t @@ -5594,7 +5450,7 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm_MCKF data @@ -5614,6 +5470,7 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, INTEGER(IntKi) :: i, iStart ! generic loop counters INTEGER(IntKi) :: iBody ! WAMIT body loop counter INTEGER(IntKi) :: j ! generic loop counters + INTEGER(IntKi) :: n ! generic loop counters INTEGER(IntKi) :: indx ! generic loop counters INTEGER(IntKi) :: indx_last ! generic loop counters INTEGER(IntKi) :: i_x ! index into packed array @@ -5689,8 +5546,6 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, !!! ! AeroDyn: copy final predictions to actual states; copy current outputs to next - !!!!IF ( p_FAST%CompAero == Module_AD14 ) THEN - !!!!ELSE IF ( p_FAST%CompAero == Module_AD ) THEN ThisModule = Module_AD if (allocated(y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag)) then @@ -5711,7 +5566,7 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, do i=1,size(AD%x(STATE_CURR)%rotors(1)%BEMT%DBEMT%element,1) indx_last = indx + size(AD%x(STATE_CURR)%rotors(1)%BEMT%DBEMT%element(i,j)%vind_1) - 1 call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%rotors(1)%BEMT%DBEMT%element(i,j)%vind_1, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & - y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) + y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) indx = indx_last + 1 end do end do @@ -5719,16 +5574,26 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, end if if (AD%p%rotors(1)%BEMT%UA%lin_nx>0) then - do j=1,size(AD%x(STATE_CURR)%rotors(1)%BEMT%UA%element,2) - do i=1,size(AD%x(STATE_CURR)%rotors(1)%BEMT%UA%element,1) - indx_last = indx + size(AD%x(STATE_CURR)%rotors(1)%BEMT%UA%element(i,j)%x) - 1 - call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%rotors(1)%BEMT%UA%element(i,j)%x, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & - y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) - indx = indx_last + 1 - end do + do n=1,AD%p%rotors(1)%BEMT%UA%lin_nx + i = AD%p%rotors(1)%BEMT%UA%lin_xIndx(n,1) + j = AD%p%rotors(1)%BEMT%UA%lin_xIndx(n,2) + k = AD%p%rotors(1)%BEMT%UA%lin_xIndx(n,3) + + indx_last = indx + call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%rotors(1)%BEMT%UA%element(i,j)%x(k:k), y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & + y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) + indx = indx_last + 1 end do + end if +! if (AD%p%rotors(1)%BEMT%lin_nx>0) then +! indx_last = indx + size(AD%x(STATE_CURR)%rotors(1)%BEMT%v_w) - 1 +! call GetStateAry(p_FAST, iMode, t, AD%x(STATE_CURR)%rotors(1)%BEMT%v_w, y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_mag( indx : indx_last), & +! y_FAST%Lin%Modules(ThisModule)%Instance(1)%op_x_eig_phase(indx : indx_last) ) +! indx = indx_last + 1 +! end if +! end if END IF !!! @@ -5780,7 +5645,7 @@ SUBROUTINE PerturbOP(t, iLinTime, iMode, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, END SUBROUTINE PerturbOP !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE SetOperatingPoint(i, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, & +SUBROUTINE SetOperatingPoint(i, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat, ErrMsg ) INTEGER(IntKi), INTENT(IN ) :: i !< Index into LinTimes (to determine which operating point to copy) @@ -5793,7 +5658,7 @@ SUBROUTINE SetOperatingPoint(i, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, O TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm_MCKF data @@ -6037,7 +5902,7 @@ end subroutine GetStateAry !---------------------------------------------------------------------------------------------------------------------------------- !---------------------------------------------------------------------------------------------------------------------------------- !> This routine performs the algorithm for computing a periodic steady-state solution. -SUBROUTINE FAST_CalcSteady( n_t_global, t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & +SUBROUTINE FAST_CalcSteady( n_t_global, t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat, ErrMsg ) INTEGER(IntKi), INTENT(IN ) :: n_t_global !< integer time step @@ -6051,7 +5916,7 @@ SUBROUTINE FAST_CalcSteady( n_t_global, t_global, p_FAST, y_FAST, m_FAST, ED, BD TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm data @@ -6135,7 +6000,7 @@ SUBROUTINE FAST_CalcSteady( n_t_global, t_global, p_FAST, y_FAST, m_FAST, ED, BD if (m_FAST%Lin%IsConverged .or. m_FAST%Lin%n_rot == 0) then ! save this operating point for linearization later m_FAST%Lin%LinTimes(m_FAST%Lin%AzimIndx) = t_global - call SaveOP(m_FAST%Lin%AzimIndx, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & + call SaveOP(m_FAST%Lin%AzimIndx, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat, ErrMsg, m_FAST%Lin%CopyOP_CtrlCode ) end if @@ -6786,8 +6651,8 @@ SUBROUTINE FAST_DiffInterpOutputs( psi_target, p_FAST, y_FAST, m_FAST, ED, BD, S call pack_in_array(p_FAST, y_FAST, m_FAST) - if (m_FAST%Lin%IsConverged) then - ! check that error equation is less than TrimTol !!!call + if (m_FAST%Lin%IsConverged) then ! if Forced Linearization, the error may be large due to a different azimuth, so printing it here isn't very helpful + ! check that error equation is less than TrimTol call calc_error(p_FAST, y_FAST, m_FAST, SrvD%y, eps_squared) m_FAST%Lin%IsConverged = eps_squared < p_FAST%TrimTol end if @@ -6863,6 +6728,7 @@ SUBROUTINE calc_error(p_FAST, y_FAST, m_FAST, y_SrvD, eps_squared) ! compute the error: eps_squared = 0.0_ReKi + !m_FAST%Lin%eps_squared = 0.0_ReKi do i = 1,p_FAST%Lin_NumMods ThisModule = p_FAST%Lin_ModOrder( i ) @@ -6879,6 +6745,7 @@ SUBROUTINE calc_error(p_FAST, y_FAST, m_FAST, y_SrvD, eps_squared) else diff = m_FAST%Lin%y_interp( indx ) - m_FAST%Lin%Y_prevRot( indx, m_FAST%Lin%AzimIndx ) end if + !m_FAST%Lin%eps_squared(indx) = ( diff / m_FAST%Lin%y_ref( indx ) ) ** 2 eps_squared = eps_squared + ( diff / m_FAST%Lin%y_ref( indx ) ) ** 2 end do @@ -6910,7 +6777,6 @@ SUBROUTINE ComputeOutputRanges(p_FAST, y_FAST, m_FAST, y_SrvD) do indx = 1,y_FAST%Lin%Glue%SizeLin(LIN_OUTPUT_COL) m_FAST%Lin%y_ref(indx) = maxval( m_FAST%Lin%Y_prevRot( indx, : ) ) - minval( m_FAST%Lin%Y_prevRot( indx, : ) ) m_FAST%Lin%y_ref(indx) = max( m_FAST%Lin%y_ref(indx), 0.01_ReKi ) -! if (m_FAST%Lin%y_ref(indx) < 1.0e-4) m_FAST%Lin%y_ref(indx) = 1.0_ReKi ! not sure why we wouldn't just do m_FAST%Lin%y_ref(indx) = max(1.0_ReKi, m_FAST%Lin%y_ref(indx)) or max(1e-4, y_ref(indx)) end do ! special case for angles: diff --git a/modules/openfast-library/src/FAST_Mods.f90 b/modules/openfast-library/src/FAST_Mods.f90 index e223e39268..d62bb0b616 100644 --- a/modules/openfast-library/src/FAST_Mods.f90 +++ b/modules/openfast-library/src/FAST_Mods.f90 @@ -24,8 +24,7 @@ MODULE FAST_ModTypes USE NWTC_Library USE FAST_Types - TYPE(ProgDesc), PARAMETER :: FAST_Ver = & - ProgDesc( 'OpenFAST', '', '' ) !< The version number of this module + TYPE(ProgDesc) :: FAST_Ver = ProgDesc( 'OpenFAST', '', '' ) !< The version number of this module !.................................................................. diff --git a/modules/openfast-library/src/FAST_Registry.txt b/modules/openfast-library/src/FAST_Registry.txt index 649b1528e5..c599fd0745 100644 --- a/modules/openfast-library/src/FAST_Registry.txt +++ b/modules/openfast-library/src/FAST_Registry.txt @@ -17,11 +17,11 @@ usefrom ServoDyn_Registry.txt usefrom Registry-AD14.txt usefrom AeroDyn_Registry.txt usefrom SubDyn_Registry.txt -usefrom SeaState.txt +usefrom SeaState.txt usefrom HydroDyn.txt usefrom IceFloe_FASTRegistry.inp usefrom InflowWind.txt -usefrom OpenFOAM_Registry.txt +usefrom ExternalInflow_Registry.txt usefrom SC_DataEx_Registry.txt usefrom Registry_IceDyn.txt usefrom FEAM_Registry.txt @@ -39,7 +39,7 @@ param FAST - INTEGER Module_Unknown - -1 - "Unknown" - param ^ - INTEGER Module_None - 0 - "No module selected" - param ^ - INTEGER Module_Glue - 1 - "Glue code" - param ^ - INTEGER Module_IfW - 2 - "InflowWind" - -param ^ - INTEGER Module_OpFM - 3 - "OpenFOAM" - +param ^ - INTEGER Module_ExtInfw - 3 - "ExternalInflow" - param ^ - INTEGER Module_ED - 4 - "ElastoDyn" - param ^ - INTEGER Module_BD - 5 - "BeamDyn" - param ^ - INTEGER Module_AD14 - 6 - "AeroDyn14" - @@ -59,6 +59,14 @@ param ^ - INTEGER NumModules - 18 - "The number of modules available in FAST" - # Other Constants param ^ - INTEGER MaxNBlades - 3 - "Maximum number of blades allowed on a turbine" - param ^ - INTEGER IceD_MaxLegs - 4 - "because I don't know how many legs there are before calling IceD_Init and I don't want to copy the data because of sibling mesh issues, I'm going to allocate IceD based on this number" - +# Constants for steady-state solve (indices for output channels) +param ^ - INTEGER SS_Indx_Pitch - 1 - "pitch" - +param ^ - INTEGER SS_Indx_TSR - 2 - "TSR" - +param ^ - INTEGER SS_Indx_WS - 3 - "wind speed" - +param ^ - INTEGER SS_Indx_RotSpeed - 4 - "rotor speed" - +param ^ - INTEGER SS_Indx_Err - 5 - "err in the ss solve" - +param ^ - INTEGER SS_Indx_Iter - 6 - "number of iterations" - + # ...... Data for VTK surface visualization ............................................................................ typedef ^ FAST_VTK_BLSurfaceType SiKi AirfoilCoords {:}{:}{:} - - "x,y coordinates for airfoil around each blade node on a blade (relative to reference)" - # ...... Data for VTK surface visualization ............................................................................ @@ -89,6 +97,11 @@ typedef ^ FAST_VTK_ModeShapeType R8Ki x_eig_magnitude {:}{:}{:} - - typedef ^ FAST_VTK_ModeShapeType R8Ki x_eig_phase {:}{:}{:} - - "phase of eigenvector (dimension 1=state, dim 2= azimuth, dim 3 = mode)" - +typedef ^ FAST_SS_CaseType ReKi RotSpeed - - - "Rotor speed for this case of the steady-state solve [>0]" "(rad/s)" +typedef ^ FAST_SS_CaseType ReKi TSR - - - "TSR for this case of the steady-state solve [>0]" "(-)" +typedef ^ FAST_SS_CaseType ReKi WindSpeed - - - "Windspeed for this case of the steady-state solve [>0]" "(m/s)" +typedef ^ FAST_SS_CaseType ReKi Pitch - - - "Pitch angle for this case of the steady-state solve" "(rad)" + # ..... FAST_ParameterType data ....................................................................................................... # Misc data for coupling: typedef FAST FAST_ParameterType DbKi DT - - - "Integration time step [global time]" s @@ -98,7 +111,7 @@ typedef ^ FAST_ParameterType INTEGER n_TMax_m1 - - - "The time step of TMax - dt typedef ^ FAST_ParameterType DbKi TMax - - - "Total run time" s typedef ^ FAST_ParameterType IntKi InterpOrder - - - "Interpolation order {0,1,2}" - typedef ^ FAST_ParameterType IntKi NumCrctn - - - "Number of correction iterations" - -typedef ^ FAST_ParameterType IntKi KMax - - - "Maximum number of input-output-solve iterations (KMax >= 1)" - +typedef ^ FAST_ParameterType IntKi KMax - - - "Maximum number of input-output-solve or nonlinear solve residual equation iterations (KMax >= 1) [>0]" - typedef ^ FAST_ParameterType IntKi numIceLegs - - - "number of suport-structure legs in contact with ice (IceDyn coupling)" - typedef ^ FAST_ParameterType IntKi nBeams - - - "number of BeamDyn instances" - typedef ^ FAST_ParameterType LOGICAL BD_OutputSibling - - - "flag to determine if BD input is sibling of output mesh" - @@ -110,7 +123,7 @@ typedef ^ FAST_ParameterType IntKi SizeJac_Opt1 {9} - - "(1)=size of matrix; (2) typedef ^ FAST_ParameterType IntKi SolveOption - - - "Switch to determine which solve option we are going to use (see Solve_FullOpt1, etc)" - # Feature switches and flags: typedef ^ FAST_ParameterType IntKi CompElast - - - "Compute blade loads (switch) {Module_ED; Module_BD}" - -typedef ^ FAST_ParameterType IntKi CompInflow - - - "Compute inflow wind conditions (switch) {Module_None; Module_IfW; Module_OpFM}" - +typedef ^ FAST_ParameterType IntKi CompInflow - - - "Compute inflow wind conditions (switch) {Module_None; Module_IfW; Module_ExtInfw}" - typedef ^ FAST_ParameterType IntKi CompAero - - - "Compute aerodynamic loads (switch) {Module_None; Module_AD14; Module_AD}" - typedef ^ FAST_ParameterType IntKi CompServo - - - "Compute control and electrical-drive dynamics (switch) {Module_None; Module_SrvD}" - typedef ^ FAST_ParameterType IntKi CompSeaSt - - - "Compute sea states; wave kinematics (switch) {Module_None; Module_SeaSt}" - @@ -154,7 +167,6 @@ typedef ^ FAST_ParameterType INTEGER n_SttsTime - - - "Number of time steps betw typedef ^ FAST_ParameterType INTEGER n_ChkptTime - - - "Number of time steps between writing checkpoint files" - typedef ^ FAST_ParameterType INTEGER n_DT_Out - - - "Number of time steps between writing a line in the time-marching output files" - typedef ^ FAST_ParameterType INTEGER n_VTKTime - - - "Number of time steps between writing VTK files" - -typedef ^ FAST_ParameterType IntKi TurbineType - - - "Type_LandBased, Type_Offshore_Fixed, Type_Offshore_Floating, Type_MHK_Fixed, or Type_MHK_Floating" - typedef ^ FAST_ParameterType LOGICAL WrBinOutFile - - - "Write a binary output file? (.outb)" - typedef ^ FAST_ParameterType LOGICAL WrTxtOutFile - - - "Write a text (formatted) output file? (.out)" - typedef ^ FAST_ParameterType IntKi WrBinMod - - - "If writing binary, which file format is to be written [1, 2, or 3]" - @@ -197,6 +209,19 @@ typedef ^ FAST_ParameterType IntKi Lin_ModOrder {NumModules} - - "indices that d typedef ^ FAST_ParameterType IntKi LinInterpOrder - - - "Interpolation order for CalcSteady solution" - #typedef ^ FAST_ParameterType LOGICAL CheckHSSBrTrqC - - - "Flag to determine if we should check HSSBrTrqC extrapolation to ElastoDyn" - +# Parameters for steady-state calculations: +typedef ^ FAST_ParameterType LOGICAL CompAeroMaps - - - "Flag to determine if we are calculating aero maps" - +typedef ^ FAST_ParameterType IntKi N_UJac - - - "Number of iterations between re-calculating Jacobian" "(-)" +typedef ^ FAST_ParameterType IntKi NumBl_Lin - - - "number of blades in the jacobian" - +typedef ^ FAST_ParameterType R8Ki tolerSquared - - - "Convergence tolerance for nonlinear solve residual equation [>0] squared" "(-)" +typedef ^ FAST_ParameterType IntKi NumSSCases - - - "Number of cases for steady-state solver generation [>0]" "(-)" +typedef ^ FAST_ParameterType IntKi WindSpeedOrTSR - - - "Choice of swept parameter (switch) { 1:wind speed; 2: TSR }" "(-)" +typedef ^ FAST_ParameterType ReKi RotSpeedInit - - - "Initial rotor speed for steady-state solve [>0]" "(rad/s)" +typedef ^ FAST_ParameterType ReKi RotSpeed {:} - - "List of rotor speeds for steady-state solve [>0]" "(rad/s)" +typedef ^ FAST_ParameterType ReKi WS_TSR {:} - - "List of WindSpeed or TSRs (depending on WindSpeedOrTSR setting) for aeromap generation" "(m/s or -)" +typedef ^ FAST_ParameterType ReKi Pitch {:} - - "List of pitch angles for aeromap generation" "(rad)" +typedef ^ FAST_ParameterType IntKi GearBox_index - - - "Index to gearbox rotation in state array (for steady-state calculations)" - + # SAVED OPERATING POINT DATA FOR VTKLIN (visualization of mode shapes from linearization analysis) # ..... IceDyn OP data ....................................................................................................... @@ -236,7 +261,7 @@ typedef ^ ^ InflowWind_DiscreteStateType xd_If typedef ^ ^ InflowWind_ConstraintStateType z_IfW {:} - - "Constraint states" typedef ^ ^ InflowWind_OtherStateType OtherSt_IfW {:} - - "Other states" typedef ^ ^ InflowWind_InputType u_IfW {:} - - "System inputs" -# ..... No OpenFOAM integration data ....................................................................................................... +# ..... No ExternalInflow integration data ....................................................................................................... # ..... SubDyn OP data ....................................................................................................... typedef FAST FAST_LinStateSave SD_ContinuousStateType x_SD {:} - - "Continuous states" typedef ^ ^ SD_DiscreteStateType xd_SD {:} - - "Discrete states" @@ -339,6 +364,7 @@ typedef ^ FAST_MiscLinType DbKi Psi {:} - - "Azimuth angle a typedef ^ FAST_MiscLinType ReKi y_interp {:} - - "Interpolated outputs packed into an array" - typedef ^ FAST_MiscLinType ReKi y_ref {:} - - "Reference output range for CalcSteady error calculation" - typedef ^ FAST_MiscLinType ReKi Y_prevRot {:}{:} - - "Linearization outputs from previous rotor revolution at each target azimuth " - +#typedef ^ FAST_MiscLinType ReKi eps_squared {:} - - "For debugging, quantity of each component that contributes to eps_squared" - # ..... FAST_OutputFileType data ....................................................................................................... @@ -361,7 +387,7 @@ typedef ^ FAST_OutputFileType IntKi VTK_LastWaveIndx - - - "last index into wave typedef ^ FAST_OutputFileType FAST_LinFileType Lin - - - "linearization data for output" typedef ^ FAST_OutputFileType IntKi ActualChanLen - - - "width of the column headers output in the text and/or binary file" - typedef ^ FAST_OutputFileType FAST_LinStateSave op - - - "operating points of states and inputs for VTK output of mode shapes" -typedef ^ FAST_OutputFileType ReKi DriverWriteOutput {5} - - "pitch and tsr for current aero map case, plus error, number of iterations, wind speed" +typedef ^ FAST_OutputFileType ReKi DriverWriteOutput {6} - - "pitch and tsr for current aero map case, plus error, number of iterations, wind speed, rotor speed" #typedef ^ FAST_OutputFileType CHARACTER(ChanLen) DriverWriteOutputHdr {:} - - "headers of data output from the driver" #typedef ^ FAST_OutputFileType CHARACTER(ChanLen) DriverWriteOutputUnit {:} - - "units of data output from the driver" @@ -465,11 +491,11 @@ typedef ^ ^ InflowWind_OutputType y_interp - - - "interpolated system outputs fo typedef ^ ^ InflowWind_InputType Input {:} - - "Array of inputs associated with InputTimes" typedef ^ ^ DbKi InputTimes {:} - - "Array of times associated with Input Array" -# ..... OpenFOAM integration data ....................................................................................................... -typedef FAST OpenFOAM_Data OpFM_InputType u - - - "System inputs" -typedef ^ ^ OpFM_OutputType y - - - "System outputs" -typedef ^ ^ OpFM_ParameterType p - - - "Parameters" -typedef ^ ^ OpFM_MiscVarType m - - - "Parameters" +# ..... ExternalInflow integration data ....................................................................................................... +typedef FAST ExternalInflow_Data ExtInfw_InputType u - - - "System inputs" +typedef ^ ^ ExtInfw_OutputType y - - - "System outputs" +typedef ^ ^ ExtInfw_ParameterType p - - - "Parameters" +typedef ^ ^ ExtInfw_MiscVarType m - - - "Parameters" # ..... SuperController integration data ....................................................................................................... typedef FAST SCDataEx_Data SC_DX_InputType u - - - "System inputs" @@ -672,6 +698,9 @@ typedef ^ FAST_ModuleMapType MeshType u_BD_Distrload {:} - - "copy of BD DistrLo typedef ^ FAST_ModuleMapType MeshType u_Orca_PtfmMesh - - - "copy of Orca PtfmMesh input mesh" typedef ^ FAST_ModuleMapType MeshType u_ExtPtfm_PtfmMesh - - - "copy of ExtPtfm_MCKF PtfmMesh input mesh" #typedef ^ FAST_ModuleMapType MeshType u_FarmMD_CoupledLoads - - - "FAST-internal copy of MoorDyn's CoupledLoads output mesh for use with shared moorings in FAST.Farm" +# for steady-state solve (convert 1 blade to all blades) +typedef ^ FAST_ModuleMapType R8Ki HubOrient {:}{:}{:} - - "Orientation matrix to translate results from blade 1 to remaining blades in aeromaps" "(-)" + # ..... FAST_ExternalInput data ....................................................................................................... typedef FAST FAST_ExternInputType ReKi GenTrq - - - "generator torque input from Simulink/Labview" typedef ^ FAST_ExternInputType ReKi ElecPwr - - - "electric power input from Simulink/Labview" @@ -712,8 +741,8 @@ typedef ^ FAST_InitData AD_InitInputType InData_AD - - typedef ^ FAST_InitData AD_InitOutputType OutData_AD - - - "AD Initialization output data" typedef ^ FAST_InitData InflowWind_InitInputType InData_IfW - - - "IfW Initialization input data" typedef ^ FAST_InitData InflowWind_InitOutputType OutData_IfW - - - "IfW Initialization output data" -typedef ^ FAST_InitData OpFM_InitInputType InData_OpFM - - - "OpFM Initialization input data" -typedef ^ FAST_InitData OpFM_InitOutputType OutData_OpFM - - - "OpFM Initialization output data" +typedef ^ FAST_InitData ExtInfw_InitInputType InData_ExtInfw - - - "ExtInfw Initialization input data" +typedef ^ FAST_InitData ExtInfw_InitOutputType OutData_ExtInfw - - - "ExtInfw Initialization output data" typedef ^ FAST_InitData SeaSt_InitInputType InData_SeaSt - - - "SeaSt Initialization input data" typedef ^ FAST_InitData SeaSt_InitOutputType OutData_SeaSt - - - "SeaSt Initialization output data" typedef ^ FAST_InitData HydroDyn_InitInputType InData_HD - - - "HD Initialization input data" @@ -756,7 +785,7 @@ typedef ^ FAST_ExternInitType SiKi *windGrid_data ::::: - - "Pointers to Wind ve typedef ^ FAST_ExternInitType CHARACTER(1024) RootName - - - "Root name of FAST output files (overrides normal operation)" - typedef ^ FAST_ExternInitType IntKi NumActForcePtsBlade - - - "number of actuator line force points in blade" - typedef ^ FAST_ExternInitType IntKi NumActForcePtsTower - - - "number of actuator line force points in tower" - -typedef ^ FAST_ExternInitType IntKi NodeClusterType - - - "Node clustering for actuator line (0 - Uniform, 1 - Non-uniform clustered towards tip)" - +typedef ^ FAST_ExternInitType IntKi NodeClusterType - - - "Node clustering for actuator line (0 - Uniform, 1 - Non-uniform clustered towards tip)" - # ..... FAST Turbine Data (one realization) ....................................................................................................... typedef ^ FAST_TurbineType IntKi TurbID - 1 - "Turbine ID Number" - @@ -770,7 +799,7 @@ typedef ^ FAST_TurbineType ServoDyn_Data SrvD - - - "Data for the ServoDyn modul typedef ^ FAST_TurbineType AeroDyn_Data AD - - - "Data for the AeroDyn module" - typedef ^ FAST_TurbineType AeroDyn14_Data AD14 - - - "Data for the AeroDyn14 module" - typedef ^ FAST_TurbineType InflowWind_Data IfW - - - "Data for InflowWind module" - -typedef ^ FAST_TurbineType OpenFOAM_Data OpFM - - - "Data for OpenFOAM integration module" - +typedef ^ FAST_TurbineType ExternalInflow_Data ExtInfw - - - "Data for ExternalInflow integration module" - typedef ^ FAST_TurbineType SCDataEx_Data SC_DX - - - "Data for SuperController integration module" - typedef ^ FAST_TurbineType SeaState_Data SeaSt - - - "Data for the SeaState module" - typedef ^ FAST_TurbineType HydroDyn_Data HD - - - "Data for the HydroDyn module" - diff --git a/modules/openfast-library/src/FAST_SS_Solver.f90 b/modules/openfast-library/src/FAST_SS_Solver.f90 new file mode 100644 index 0000000000..d91c741254 --- /dev/null +++ b/modules/openfast-library/src/FAST_SS_Solver.f90 @@ -0,0 +1,2174 @@ +!********************************************************************************************************************************** +! LICENSING +! Copyright (C) 2020 Envision Energy USA, National Renewable Energy Laboratory +! +! This file is part of FAST. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +!********************************************************************************************************************************** +!> This module contains the routines used by FAST to solve input-output equations and to advance states. +MODULE FAST_SS_Solver + + USE FAST_SOLVER + USE FAST_Linear + USE FAST_Subs + USE BeamDyn_Subs, ONLY: BD_CrvMatrixR, BD_CrvExtractCrv + + IMPLICIT NONE + + REAL(DbKi), PARAMETER :: SS_t_global = 0.0_DbKi + REAL(DbKi), PARAMETER :: UJacSclFact_x = 1.0d3 + + LOGICAL, PARAMETER :: output_debugging = .false. + +CONTAINS +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE SteadyStateCCSD( caseData, p_FAST, y_FAST, m_FAST, ED, BD, InputIndex, ErrStat, ErrMsg ) + + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType), INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + INTEGER(IntKi), INTENT(IN ) :: InputIndex !< Index into input array + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + INTEGER(IntKi) :: i + INTEGER(IntKi) :: k + INTEGER(IntKi) :: BldMeshNode + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + CHARACTER(*), PARAMETER :: RoutineName = 'SteadyStateCCSD' + REAL(R8Ki) :: Omega_Hub(3) + REAL(R8Ki) :: position(3) + REAL(R8Ki) :: omega_cross_position(3) + + ErrStat = ErrID_None + ErrMsg = "" + + IF (p_FAST%CompElast == Module_ED) THEN + CALL ED_CalcContStateDeriv( SS_t_global, ED%Input(InputIndex), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), & + ED%OtherSt(STATE_CURR), ED%m, ED%x(STATE_PRED), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ELSEIF (p_FAST%CompElast == Module_BD) THEN + Omega_Hub(1) = caseData%RotSpeed + Omega_Hub(2:3) = 0.0_R8Ki + + DO K = 1,p_FAST%nBeams + CALL BD_CalcContStateDeriv( SS_t_global, BD%Input(InputIndex,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), & + BD%OtherSt(k,STATE_CURR), BD%m(k), BD%x(k,STATE_PRED), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! subtract xdot(y) here: + ! note that this only works when the BldMotion mesh is on the FE nodes + do i=2,BD%p(k)%node_total ! the first node isn't technically a state + BldMeshNode = BD%p(k)%NdIndx(i) + position = BD%y(k)%BldMotion%Position(:,BldMeshNode) + BD%y(k)%BldMotion%TranslationDisp(:,BldMeshNode) + omega_cross_position = cross_product( Omega_Hub, position ) + + BD%x(k, STATE_PRED)%q( 1:3,i) = BD%x(k, STATE_PRED)%q( 1:3,i) - omega_cross_position + BD%x(k, STATE_PRED)%q( 4:6,i) = BD%x(k, STATE_PRED)%q( 4:6,i) - Omega_Hub + BD%x(k, STATE_PRED)%dqdt( 1:3,i) = BD%x(k, STATE_PRED)%dqdt( 1:3,i) - cross_product( Omega_Hub, omega_cross_position ) + end do + + END DO + END IF + +END SUBROUTINE SteadyStateCCSD +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE SteadyStateCalculatedInputs( p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, InputIndex, ErrStat, ErrMsg ) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType), INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + INTEGER(IntKi), INTENT(IN ) :: InputIndex !< Index into input array + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + CHARACTER(*), PARAMETER :: RoutineName = 'SteadyStateCalculatedInputs' + + ErrStat = ErrID_None + ErrMsg = "" + + ! transfer the motions first: + CALL SS_AD_InputSolve( p_FAST, AD%Input(InputIndex), ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! transfer the loads next: + IF (p_FAST%CompElast == Module_ED) THEN + CALL SS_ED_InputSolve( p_FAST, ED%Input(InputIndex), ED%y, AD%y, AD%Input(InputIndex), MeshMapData, ErrStat2, ErrMsg2 ) + + ELSEIF (p_FAST%CompElast == Module_BD) THEN + CALL SS_BD_InputSolve( p_FAST, BD, AD%y, AD%Input(InputIndex), MeshMapData, InputIndex, ErrStat2, ErrMsg2 ) + END IF + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + +END SUBROUTINE SteadyStateCalculatedInputs +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade load inputs required for BD. +SUBROUTINE SS_BD_InputSolve( p_FAST, BD, y_AD, u_AD, MeshMapData, InputIndex, ErrStat, ErrMsg ) +!.................................................................................................................................. + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BD Inputs at t + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD inputs (for AD-BD load transfer) + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + INTEGER(IntKi), INTENT(IN ) :: InputIndex !< Index into input array + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + CHARACTER(*), PARAMETER :: RoutineName = 'SS_BD_InputSolve' + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + + ! BD inputs on blade from AeroDyn + + if (p_FAST%BD_OutputSibling) then + + DO K = 1, p_FAST%NumBl_Lin ! we don't need all blades here: p_FAST%nBeams ! Loop through all blades + + CALL Transfer_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(InputIndex,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), BD%y(k)%BldMotion ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + END DO + + else + DO K = 1, p_FAST%NumBl_Lin ! we don't need all blades here: p_FAST%nBeams ! Loop through all blades + + ! need to transfer the BD output blade motions to nodes on a sibling of the BD blade motion mesh: + CALL Transfer_Line2_to_Line2( BD%y(k)%BldMotion, MeshMapData%y_BD_BldMotion_4Loads(k), MeshMapData%BD_L_2_BD_L(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + CALL Transfer_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(InputIndex,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), MeshMapData%y_BD_BldMotion_4Loads(k) ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + END DO + end if + + + +END SUBROUTINE SS_BD_InputSolve +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade-load ElastoDyn inputs from blade 1 to the other blades. +SUBROUTINE SS_BD_InputSolve_OtherBlades( p_FAST, BD, MeshMapData, InputIndex ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BD Inputs at t + + TYPE(FAST_ModuleMapType), INTENT(IN ) :: MeshMapData !< Data for mapping between modules + INTEGER(IntKi), INTENT(IN ) :: InputIndex !< Index into input array + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: J ! Loops through nodes + + + DO k = p_FAST%NumBl_Lin+1,p_FAST%nBeams + DO j=1,BD%Input(InputIndex,k)%DistrLoad%NNodes + BD%Input(InputIndex,k)%DistrLoad%Force( :,j) = MATMUL(BD%Input(InputIndex,1)%DistrLoad%Force( :,j), MeshMapData%HubOrient(:,:,k) ) + BD%Input(InputIndex,k)%DistrLoad%Moment(:,j) = MATMUL(BD%Input(InputIndex,1)%DistrLoad%Moment(:,j), MeshMapData%HubOrient(:,:,k) ) + END DO + END DO + +END SUBROUTINE SS_BD_InputSolve_OtherBlades + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade load inputs required for ED. +SUBROUTINE SS_ED_InputSolve( p_FAST, u_ED, y_ED, y_AD, u_AD, MeshMapData, ErrStat, ErrMsg ) +!.................................................................................................................................. + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t + TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD inputs (for AD-ED load transfer) + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + CHARACTER(*), PARAMETER :: RoutineName = 'SS_ED_InputSolve' + + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + ! ED inputs on blade from AeroDyn + + DO K = 1, p_FAST%NumBl_Lin !we don't need all blades here: SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) + CALL Transfer_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), y_ED%BladeLn2Mesh(k) ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END DO + +END SUBROUTINE SS_ED_InputSolve +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade-load ElastoDyn inputs from blade 1 to the other blades. +SUBROUTINE SS_ED_InputSolve_OtherBlades( p_FAST, u_ED, MeshMapData ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t + TYPE(FAST_ModuleMapType), INTENT(IN ) :: MeshMapData !< Data for mapping between modules + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: J ! Loops through nodes + + + DO k = p_FAST%NumBl_Lin+1,size(u_ED%BladePtLoads,1) + DO j=1,u_ED%BladePtLoads(k)%NNodes + u_ED%BladePtLoads(k)%Force( :,j) = MATMUL(u_ED%BladePtLoads(1)%Force( :,j), MeshMapData%HubOrient(:,:,k) ) + u_ED%BladePtLoads(k)%Moment(:,j) = MATMUL(u_ED%BladePtLoads(1)%Moment(:,j), MeshMapData%HubOrient(:,:,k) ) + END DO + END DO + +END SUBROUTINE SS_ED_InputSolve_OtherBlades + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade-motion AeroDyn inputs. +SUBROUTINE SS_AD_InputSolve( p_FAST, u_AD, y_ED, BD, MeshMapData, ErrStat, ErrMsg ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< The inputs to AeroDyn14 + TYPE(ED_OutputType), INTENT(IN) :: y_ED !< The outputs from the structural dynamics module + TYPE(BeamDyn_Data), INTENT(IN) :: BD !< The data from BeamDyn (want the outputs only, but it's in an array) + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + + INTEGER(IntKi) :: ErrStat !< Error status of the operation + CHARACTER(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SS_AD_InputSolve' + + + ErrStat = ErrID_None + ErrMsg = "" + + !------------------------------------------------------------------------------------------------- + ! Set the inputs from structure: + !------------------------------------------------------------------------------------------------- + IF (p_FAST%CompElast == Module_ED ) THEN + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades here: size(y_ED%BladeLn2Mesh) + CALL Transfer_Line2_to_Line2( y_ED%BladeLn2Mesh(k), u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeMotion('//trim(num2lstr(k))//')' ) + END DO + + ELSEIF (p_FAST%CompElast == Module_BD ) THEN + + ! get them from BeamDyn + DO k=1,p_FAST%NumBl_Lin !we don't need all blades here: size(u_AD%BladeMotion) + CALL Transfer_Line2_to_Line2( BD%y(k)%BldMotion, u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeMotion('//trim(num2lstr(k))//')' ) + END DO + + END IF + + ! make sure these are the prescribed values: + DO k = 1,p_FAST%NumBl_Lin !we don't need all blades here: size(u_AD%BladeMotion,1) + u_AD%rotors(1)%BladeMotion(k)%RotationVel = 0.0_ReKi + u_AD%rotors(1)%BladeMotion(k)%TranslationAcc = 0.0_ReKi + END DO + + +END SUBROUTINE SS_AD_InputSolve +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine sets the blade-motion AeroDyn inputs. +SUBROUTINE SS_AD_InputSolve_OtherBlades( p_FAST, u_AD, MeshMapData ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< The inputs to AeroDyn14 + TYPE(FAST_ModuleMapType), INTENT(IN ) :: MeshMapData !< Data for mapping between modules + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: J ! Loops through nodes + + + DO k = p_FAST%NumBl_Lin+1,size(u_AD%rotors(1)%BladeMotion,1) + DO j=1,u_AD%rotors(1)%BladeMotion(k)%NNodes + u_AD%rotors(1)%BladeMotion(k)%TranslationDisp(:,j) = MATMUL( u_AD%rotors(1)%BladeMotion(1)%TranslationDisp(:,j), MeshMapData%HubOrient(:,:,k) ) + u_AD%rotors(1)%BladeMotion(k)%Orientation( :,:,j) = MATMUL( u_AD%rotors(1)%BladeMotion(1)%Orientation( :,:,j), MeshMapData%HubOrient(:,:,k) ) + u_AD%rotors(1)%BladeMotion(k)%TranslationVel( :,j) = MATMUL( u_AD%rotors(1)%BladeMotion(1)%TranslationVel( :,j), MeshMapData%HubOrient(:,:,k) ) + END DO + END DO + +END SUBROUTINE SS_AD_InputSolve_OtherBlades + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine performs the Input-Output solve for the steady-state solver. +!! Note that this has been customized for the physics in the problems and is not a general solution. +SUBROUTINE SolveSteadyState( caseData, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData , ErrStat, ErrMsg ) +!.................................................................................................................................. + + ! Passed variables + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< temporary storage space for jacobian matrix + + TYPE(FAST_ParameterType) , INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType) , INTENT(INOUT) :: y_FAST !< Glue-code output file values + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType) , INTENT(INOUT) :: MeshMapData !< data for mapping meshes between modules + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables: + CHARACTER(*), PARAMETER :: RoutineName = 'SolveSteadyState' + +!bjj: store these so that we don't reallocate every time? + REAL(R8Ki) :: u( p_FAST%SizeJac_Opt1(1)) ! size of loads/accelerations passed between the 6 modules + REAL(R8Ki) :: u_delta( p_FAST%SizeJac_Opt1(1)) ! size of loads/accelerations passed between the 6 modules + REAL(R8Ki) :: Fn_U_Resid( p_FAST%SizeJac_Opt1(1)) ! Residual of U + REAL(R8Ki) :: err + REAL(R8Ki) :: err_prev + REAL(R8Ki), PARAMETER :: reduction_factor = 0.1_R8Ki + + INTEGER(IntKi) :: nb ! loop counter (blade number) + INTEGER(IntKi) :: MaxIter ! maximum number of iterations + INTEGER(IntKi) :: K ! Input-output-solve iteration counter + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + LOGICAL :: GetWriteOutput ! flag to determine if we need WriteOutputs from this call to CalcOutput + + ! Note: p_FAST%UJacSclFact is a scaling factor that gets us similar magnitudes between loads and accelerations... + +!bjj: note, that this routine may have a problem if there is remapping done + + ErrStat = ErrID_None + ErrMsg = "" + !---------------------------------------------------------------------------------------------------- + ! Some record keeping stuff: + !---------------------------------------------------------------------------------------------------- + + CALL SteadyStateUpdateStates( caseData, p_FAST, ED, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + CALL SteadyStatePrescribedInputs( caseData, p_FAST, y_FAST, m_FAST, ED, BD, AD ) + CALL CopyStatesInputs( p_FAST, ED, BD, AD, ErrStat2, ErrMsg2, MESH_UPDATECOPY ) ! COPY the inputs to the temp copy (so we get updated input values) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + K = 0 + err = 1.0E3 + err_prev = err + + y_FAST%DriverWriteOutput(SS_Indx_Err) = -1 + y_FAST%DriverWriteOutput(SS_Indx_Iter) = 0 + y_FAST%DriverWriteOutput(SS_Indx_TSR) = caseData%tsr + y_FAST%DriverWriteOutput(SS_Indx_WS) = caseData%windSpeed + y_FAST%DriverWriteOutput(SS_Indx_Pitch) = caseData%Pitch*R2D + y_FAST%DriverWriteOutput(SS_Indx_RotSpeed) = caseData%RotSpeed*RPS2RPM + + MaxIter = p_FAST%KMax + 1 ! adding 1 here so that we get the error calculated correctly when we hit the max iteration + DO + + !------------------------------------------------------------------------------------------------- + ! Calculate outputs, based on inputs at this time + !------------------------------------------------------------------------------------------------- + GetWriteOutput = K > 0 ! we can skip this on the first call (because we always calculate outputs twice) + + IF ( p_FAST%CompElast == Module_ED ) THEN + CALL ED_CalcOutput( SS_t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), ED%y, ED%m, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ELSEIF ( p_FAST%CompElast == Module_BD) THEN + do nb=1,p_FAST%nBeams + CALL BD_CalcOutput( SS_t_global, BD%Input(1,nb), BD%p(nb), BD%x(nb, STATE_CURR), BD%xd(nb, STATE_CURR), BD%z(nb, STATE_CURR), BD%OtherSt(nb, STATE_CURR), & + BD%y(nb), BD%m(nb), ErrStat2, ErrMsg2, GetWriteOutput ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + end do + END IF + + IF (K==0) THEN + + ! set the AD input guess based on the structural output (this will ensure that the pitch is accounted for in the fixed aero-map solve:): + CALL SS_AD_InputSolve( p_FAST, AD%Input(1), ED%y, BD, MeshMapData, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + CALL SS_AD_InputSolve_OtherBlades( p_FAST, AD%Input(1), MeshMapData ) ! transfer results from blade 1 to other blades + + !---------------------------------------------------------------------------------------------------- + ! set up x-u vector, using local initial guesses: + !---------------------------------------------------------------------------------------------------- + CALL Create_SS_Vector( p_FAST, y_FAST, u, AD, ED, BD, 1, STATE_CURR ) + + END IF + + CALL AD_CalcOutput(SS_t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, GetWriteOutput ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + call resetInputsAndStates() + RETURN + END IF + + IF (K >= MaxIter) EXIT + + + !------------------------------------------------------------------------------------------------- + ! Calculate residual and the Jacobian: + ! (note that we don't want to change module%Input(1), here) + ! Also, the residual uses values from y_FAST, so do this before calculating the jacobian + !------------------------------------------------------------------------------------------------- + CALL SteadyStateSolve_Residual(caseData, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, u, Fn_U_Resid, ErrStat2, ErrMsg2) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + call resetInputsAndStates() + RETURN + END IF + + IF ( mod( K, p_FAST%N_UJac ) == 0 ) THEN + CALL FormSteadyStateJacobian( caseData, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + call Precondition_Jmat(p_FAST, y_FAST, Jmat) + + ! Get the LU decomposition of this matrix using a LAPACK routine: + ! The result is of the form Jmat = P * L * U + + CALL LAPACK_getrf( M=size(Jmat,1), N=size(Jmat,2), & + A=Jmat, IPIV=MeshMapData%Jacobian_pivot, & + ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) THEN + call resetInputsAndStates() + RETURN + END IF + + END IF + + !------------------------------------------------------------------------------------------------- + ! Solve for delta u: Jac*u_delta = - Fn_U_Resid + ! using the LAPACK routine + !------------------------------------------------------------------------------------------------- + + u_delta = -Fn_U_Resid + CALL LAPACK_getrs( TRANS="N", N=SIZE(Jmat,1), A=Jmat, & + IPIV=MeshMapData%Jacobian_pivot, B=u_delta, ErrStat=ErrStat2, ErrMsg=ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF ( ErrStat >= AbortErrLev ) RETURN + + !------------------------------------------------------------------------------------------------- + ! check for error, update inputs if necessary, and iterate again + !------------------------------------------------------------------------------------------------- + err_prev = err + err = DOT_PRODUCT(u_delta, u_delta) + y_FAST%DriverWriteOutput(SS_Indx_Err) = sqrt(err) / p_FAST%SizeJac_Opt1(1) + + IF ( err <= p_FAST%TolerSquared) THEN + IF (K==0) THEN ! the error will be incorrect in this instance, but the outputs will be better + MaxIter = K + ELSE + EXIT + END IF + END IF + + IF (K >= p_FAST%KMax ) EXIT + IF (K > 5 .and. err > 1.0E35) EXIT ! this is obviously not converging. Let's try something else. + + !------------------------------------------------------------------------------------------------- + ! modify inputs and states for next iteration + !------------------------------------------------------------------------------------------------- + if (err > err_prev ) then + u_delta = u_delta * reduction_factor ! don't take a full step if we're getting farther from the solution! + err_prev = err_prev * reduction_factor + end if + + CALL Add_SteadyState_delta( p_FAST, y_FAST, u_delta, AD, ED, BD, MeshMapData ) + + !u = u + u_delta + CALL Create_SS_Vector( p_FAST, y_FAST, u, AD, ED, BD, 1, STATE_CURR ) + + K = K + 1 + y_FAST%DriverWriteOutput(SS_Indx_Iter) = k + + END DO ! K + + IF ( p_FAST%CompElast == Module_BD ) THEN + ! this doesn't actually get the correct hub point load from BD, but we'll get some outputs: + CALL ED_CalcOutput( SS_t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), ED%y, ED%m, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END IF + + call resetInputsAndStates() + +contains + subroutine resetInputsAndStates() + + IF ( err > p_FAST%TolerSquared ) THEN + CALL SetErrStat(ErrID_Severe, 'Steady-state solver did not converge.', ErrStat, ErrMsg, RoutineName) + + IF ( err > 100.0 ) THEN + ! if we didn't get close on the solution, we should reset the states and inputs because they very well could + ! lead to numerical issues on the next iteration. Here, set the initial values to 0: + + ! because loads occasionally get very large when it fails, manually set these to zero (otherwise + ! roundoff can lead to non-zero values with the method below, which is most useful for states) + IF( p_FAST%CompElast == Module_BD ) THEN + DO K = 1,p_FAST%nBeams + BD%Input(1,k)%DistrLoad%Force = 0.0_ReKi + BD%Input(1,k)%DistrLoad%Moment = 0.0_ReKi + END DO + + END IF + + CALL Create_SS_Vector( p_FAST, y_FAST, u, AD, ED, BD, 1, STATE_CURR ) ! find the values we have been modifying (in u... continuous states and inputs) + CALL Add_SteadyState_delta( p_FAST, y_FAST, -u, AD, ED, BD, MeshMapData ) ! and reset them to 0 (by adding -u) + + END IF + END IF + end subroutine resetInputsAndStates + +END SUBROUTINE SolveSteadyState +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE SteadyStateSolve_Residual(caseData, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, u_in, u_resid, ErrStat, ErrMsg) + ! Passed variables + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + TYPE(FAST_ParameterType) , INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType) , INTENT(INOUT) :: y_FAST !< Glue-code output file values + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType) , INTENT(INOUT) :: MeshMapData !< data for mapping meshes between modules + REAL( R8Ki ) , INTENT(IN ) :: u_in(:) !< The residual of the array of states and inputs we are trying to solve for + REAL( R8Ki ) , INTENT( OUT) :: u_resid(:) !< The residual of the array of states and inputs we are trying to solve for + INTEGER(IntKi) , INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*) , INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: ErrStat2 + INTEGER(IntKi) :: Indx_u_start + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SteadyStateSolve_Residual' + + integer, parameter :: InputIndex = 2 + + ErrStat = ErrID_None + ErrMsg = "" + + !note: prescribed inputs are already set in both InputIndex=1 and InputIndex=2 so we can ignore them here + + call SteadyStateCCSD( caseData, p_FAST, y_FAST, m_FAST, ED, BD, 1, ErrStat2, ErrMsg2 ) ! use current inputs and calculate CCSD in STATE_PRED + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! note that we don't need to calculate the inputs on more than p_FAST%NumBl_Lin blades because we are only using them to compute the Create_SS_Vector + call SteadyStateCalculatedInputs( p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, InputIndex, ErrStat2, ErrMsg2 ) ! calculate new inputs and store in InputIndex=2 + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + !.................. + ! Pack the output "residual vector" with these state derivatives and new inputs: + !.................. + CALL Create_SS_Vector( p_FAST, y_FAST, U_Resid, AD, ED, BD, InputIndex, STATE_PRED ) + + ! Make the inputs a residual (subtract from previous inputs) + Indx_u_start = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + 1 + U_Resid(Indx_u_start : ) = u_in(Indx_u_start : ) - U_Resid(Indx_u_start : ) + +END SUBROUTINE SteadyStateSolve_Residual +!---------------------------------------------------------------------------------------------------------------------------------- +!> This subroutine saves the current states so they can be used to compute the residual. +SUBROUTINE CopyStatesInputs( p_FAST, ED, BD, AD, ErrStat, ErrMsg, CtrlCode ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + INTEGER(IntKi), INTENT(IN ) :: CtrlCode !< mesh copy control code (new, vs update) + + ! local variables + INTEGER(IntKi) :: k ! generic loop counters + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'CopyStatesInputs' + + + ErrStat = ErrID_None + ErrMsg = "" + + + !---------------------------------------------------------------------------------------- + !! copy the operating point of the states and inputs + !---------------------------------------------------------------------------------------- + + ! ElastoDyn: copy states and inputs + IF ( CtrlCode == MESH_NEWCOPY ) THEN + CALL ED_CopyContState (ED%x( STATE_CURR), ED%x( STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL ED_CopyDiscState (ED%xd(STATE_CURR), ED%xd(STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL ED_CopyConstrState (ED%z( STATE_CURR), ED%z( STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL ED_CopyOtherState (ED%OtherSt( STATE_CURR), ED%OtherSt( STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END IF + + CALL ED_CopyInput (ED%Input(1), ED%Input(2), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + ! BeamDyn: copy states and inputs to OP array + IF ( p_FAST%CompElast == Module_BD ) THEN + + IF ( CtrlCode == MESH_NEWCOPY ) THEN + DO k=1,p_FAST%nBeams + CALL BD_CopyContState (BD%x( k,STATE_CURR),BD%x( k,STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL BD_CopyDiscState (BD%xd(k,STATE_CURR),BD%xd(k,STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL BD_CopyConstrState (BD%z( k,STATE_CURR),BD%z( k,STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL BD_CopyOtherState (BD%OtherSt( k,STATE_CURR),BD%OtherSt( k,STATE_PRED), MESH_UPDATECOPY, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END DO + END IF + + DO k=1,p_FAST%nBeams + CALL BD_CopyInput (BD%Input(1,k), BD%Input(2,k), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END DO + END IF + + + + ! AeroDyn: copy states and inputs to OP array + IF ( CtrlCode == MESH_NEWCOPY ) THEN + CALL AD_CopyContState (AD%x( STATE_CURR), AD%x( STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL AD_CopyDiscState (AD%xd(STATE_CURR), AD%xd(STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL AD_CopyConstrState (AD%z( STATE_CURR), AD%z( STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + CALL AD_CopyOtherState( AD%OtherSt(STATE_CURR), AD%OtherSt(STATE_PRED), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat( Errstat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + END IF + + CALL AD_CopyInput (AD%Input(1), AD%Input(2), CtrlCode, Errstat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + +END SUBROUTINE CopyStatesInputs +!---------------------------------------------------------------------------------------------------------------------------------- +! This routine sets the rotor speed for the steady state cases. Rotor speed is a continuous state. +SUBROUTINE SteadyStateUpdateStates(CaseData, p_FAST, ED, ErrStat, ErrMsg ) +!.................................................................................................................................. + + ! Passed variables + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! local variables + INTEGER(IntKi) :: k ! generic loop counters + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'SteadyStateUpdateStates' + + + ErrStat = ErrID_None + ErrMsg = "" + + + ED%x(STATE_CURR)%QDT(p_FAST%GearBox_Index) = caseData%RotSpeed + +END SUBROUTINE SteadyStateUpdateStates +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine returns the preconditioned matrix, \f$ \hat{J} \f$, such that \f$ \hat{J} = S^(-1) J S \f$ with \f$S^(-1)\f$ defined +!! such that loads are scaled by p_FAST\%UJacSclFact. +SUBROUTINE Precondition_Jmat(p_FAST, y_FAST, Jmat) + + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + REAL(R8Ki), INTENT(INOUT) :: JMat(:,:) !< variable for steady-state solve (in is Jmat; out is Jmat_hat) + + + integer :: r, c, nx + + nx = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + + !! Change J to J_hat: + do c=1,nx ! states are not loads: + + do r = 1,size(y_FAST%Lin%Glue%IsLoad_u) + if ( y_FAST%Lin%Glue%IsLoad_u(r) ) then + ! column is motion, but row is a load: + JMat(nx+r,c) = JMat(nx+r,c) / p_FAST%UJacSclFact + end if + end do + + end do + + + do c = 1,size(y_FAST%Lin%Glue%IsLoad_u) + + if ( y_FAST%Lin%Glue%IsLoad_u(c) ) then + + do r=1,nx ! states are not loads: + ! column is load, but row is a motion: + JMat(r,nx+c) = JMat(r,nx+c) * p_FAST%UJacSclFact + end do + + do r = 1,size(y_FAST%Lin%Glue%IsLoad_u) + if ( .not. y_FAST%Lin%Glue%IsLoad_u(r) ) then + ! column is load, but row is a motion: + JMat(nx+r,nx+c) = JMat(nx+r,nx+c) * p_FAST%UJacSclFact + end if + end do + + else + + do r = 1,size(y_FAST%Lin%Glue%IsLoad_u) + if ( y_FAST%Lin%Glue%IsLoad_u(r) ) then + ! column is motion, but row is a load: + JMat(nx+r,nx+c) = JMat(nx+r,nx+c) / p_FAST%UJacSclFact + end if + end do + + end if + + end do + + + +END SUBROUTINE Precondition_Jmat + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine basically packs the relevant parts of the modules' inputs and states for use in the steady-state solver. +SUBROUTINE Create_SS_Vector( p_FAST, y_FAST, u, AD, ED, BD, InputIndex, StateIndex ) +!.................................................................................................................................. + TYPE(FAST_ParameterType) , INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Output variables for the glue code + REAL( R8Ki ) , INTENT(INOUT) :: u(:) !< The array of states and inputs we are trying to solve for + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + INTEGER(IntKi), INTENT(IN ) :: InputIndex + INTEGER(IntKi), INTENT(IN ) :: StateIndex + + ! local variables: + INTEGER :: n + INTEGER :: fieldIndx + INTEGER :: node + INTEGER :: indx, indx_last + INTEGER :: i, j, k + INTEGER :: nx, nStates + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + + + nx = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) ! make sure this is only STRUCTURAL states!!! + + ! structural code states: + IF ( p_FAST%CompElast == Module_ED ) THEN !bjj: QUESTION/FIXME: does this work when BD is used? Don't we have a combination of ED and BD states then??? Or are these only states on the blades? + nStates = nx + + if (StateIndex == STATE_PRED) then !this is actually the derivative of the current states instead of the value of the current states + do j = 1, nStates + indx = ED%p%DOFs%PS((j-1)*ED%p%NActvDOF_Stride + 1) + u(j) = ED%x( StateIndex )%QDT(indx) + end do + else + do j = 1, nStates + indx = ED%p%DOFs%PS((j-1)*ED%p%NActvDOF_Stride + 1) + u(j) = ED%x( StateIndex )%QT(indx) + end do + end if + + ELSEIF ( p_FAST%CompElast == Module_BD ) THEN + nStates = nx / 2 + + DO k=1,p_FAST%nBeams + indx = 1 + do i=2,BD%p(k)%node_total ! the first node isn't technically a state + indx_last = indx + BD%p(k)%dof_node - 1 + u( indx:indx_last ) = BD%x(k, StateIndex)%q( :,i) + u(nStates+indx:indx_last+nStates) = BD%x(k, StateIndex)%dqdt( :,i) + indx = indx_last+1 + end do + END DO + END IF !CompElast + + + + ! inputs: + ! we are at u_delta(nx+1 : end) + n = nx+1 + IF ( p_FAST%CompElast == Module_ED ) THEN + + do K = 1,p_FAST%NumBl_Lin !we don't need all blades here: SIZE(ED%Input(InputIndex)%BladePtLoads,1) ! Loop through all blades + + do node = 1, ED%Input(InputIndex)%BladePtLoads(k)%NNodes + do fieldIndx = 1,3 + u(n) = ED%Input(InputIndex)%BladePtLoads(k)%Force( fieldIndx,node) / p_FAST%UJacSclFact + n = n+1 + end do + end do + + do node = 1, ED%Input(InputIndex)%BladePtLoads(k)%NNodes + do fieldIndx = 1,3 + u(n) = ED%Input(InputIndex)%BladePtLoads(k)%Moment( fieldIndx,node) / p_FAST%UJacSclFact + n = n+1 + end do + end do + + end do + + ELSEIF ( p_FAST%CompElast == Module_BD ) THEN + + do K = 1,p_FAST%NumBl_Lin !we don't need all blades here: p_FAST%nBeams ! Loop through all blades + + do node = 1, BD%Input(InputIndex,k)%DistrLoad%NNodes + do fieldIndx = 1,3 + u(n) = BD%Input(InputIndex,k)%DistrLoad%Force( fieldIndx,node) / p_FAST%UJacSclFact + n = n+1 + end do + end do + + do node = 1, BD%Input(InputIndex,k)%DistrLoad%NNodes + do fieldIndx = 1,3 + u(n) = BD%Input(InputIndex,k)%DistrLoad%Moment( fieldIndx,node) / p_FAST%UJacSclFact + n = n+1 + end do + end do + + end do + END IF !CompElast + + + ! AeroDyn + DO k=1,p_FAST%NumBl_Lin !we don't need all blades here: SIZE(AD%Input(InputIndex)%BladeMotion) + do node = 1, AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%NNodes + do fieldIndx = 1,3 + u(n) = AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%TranslationDisp( fieldIndx,node) + n = n+1 + end do + end do + + do node = 1, AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%NNodes + CALL DCM_LogMap( AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%Orientation(:,:,node), u(n:n+2), ErrStat2, ErrMsg2 ) + n = n+3 + end do + + do node = 1, AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%NNodes + do fieldIndx = 1,3 + u(n) = AD%Input(InputIndex)%rotors(1)%BladeMotion(k)%TranslationVel( fieldIndx,node) + n = n+1 + end do + end do + + END DO + + +END SUBROUTINE Create_SS_Vector + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine adds u_delta to the corresponding mesh field and scales it as appropriate +SUBROUTINE Add_SteadyState_delta( p_FAST, y_FAST, u_delta, AD, ED, BD, MeshMapData ) +!.................................................................................................................................. + TYPE(FAST_ParameterType) , INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Output variables for the glue code + REAL( R8Ki ) , INTENT(IN ) :: u_delta(:) !< The delta amount to add to the appropriate mesh fields + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + TYPE(FAST_ModuleMapType) , INTENT(IN ) :: MeshMapData !< data for mapping meshes between modules + + ! local variables + INTEGER :: n + INTEGER :: fieldIndx + INTEGER :: node + INTEGER :: indx, indx_last + INTEGER :: i, j, k + INTEGER :: nx, nStates + + REAL(R8Ki) :: orientation(3,3) + REAL(R8Ki) :: rotation(3,3) + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + + + nx = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + + ! structural code states: + IF ( p_FAST%CompElast == Module_ED ) THEN + nStates = nx + + do j = 1, nStates + + do k=1,ED%p%NActvDOF_Stride ! transfer these states to the other blades (this means that the original states MUST be set the same for all blades!!!) + indx = ED%p%DOFs%PS((j-1)*ED%p%NActvDOF_Stride + k) + + ED%x( STATE_CURR)%QT(indx) = ED%x( STATE_CURR)%QT( indx) + u_delta(j) + ED%x( STATE_CURR)%QDT(indx) = 0.0_R8Ki !ED%x( STATE_CURR)%QDT(indx) + u_delta(j+nStates) + end do + + end do + + + ELSEIF ( p_FAST%CompElast == Module_BD ) THEN + nStates = nx / 2 + + ! see BD's Perturb_x function: + + DO k=1,p_FAST%nBeams + indx = 1 + do i=2,BD%p(k)%node_total + indx_last = indx + BD%p(k)%dof_node - 1 + BD%x(k, STATE_CURR)%dqdt( :,i) = BD%x(k, STATE_CURR)%dqdt(:,i) + u_delta(nStates+indx:indx_last+nStates) + BD%x(k, STATE_CURR)%q( 1:3,i) = BD%x(k, STATE_CURR)%q( 1:3,i) + u_delta( indx:indx+2 ) + + ! w-m parameters + call BD_CrvMatrixR( BD%x(k, STATE_CURR)%q( 4:6,i), rotation ) ! returns the rotation matrix (transpose of DCM) that was stored in the state as a w-m parameter + orientation = transpose(rotation) + + call PerturbOrientationMatrix( Orientation, Perturbations = u_delta( indx+3:indx_last) ) + + rotation = transpose(orientation) + call BD_CrvExtractCrv( rotation, BD%x(k, STATE_CURR)%q( 4:6,i), ErrStat2, ErrMsg2 ) ! return the w-m parameters of the new orientation + + indx = indx_last+1 + end do + END DO + END IF !CompElast + + + + ! inputs: + ! we are at u_delta(nx+1 : end) + n = nx+1 + IF ( p_FAST%CompElast == Module_ED ) THEN + + do K = 1,p_FAST%NumBl_Lin !we don't need all blades here: SIZE(ED%Input(1)%BladePtLoads,1) ! Loop through all blades + + do node = 1, ED%Input(1)%BladePtLoads(k)%NNodes + do fieldIndx = 1,3 + ED%Input(1)%BladePtLoads(k)%Force( fieldIndx,node) = ED%Input(1)%BladePtLoads(k)%Force( fieldIndx,node) + u_delta(n) * p_FAST%UJacSclFact + n = n+1 + end do + end do + + do node = 1, ED%Input(1)%BladePtLoads(k)%NNodes + do fieldIndx = 1,3 + ED%Input(1)%BladePtLoads(k)%Moment( fieldIndx,node) = ED%Input(1)%BladePtLoads(k)%Moment( fieldIndx,node) + u_delta(n) * p_FAST%UJacSclFact + n = n+1 + end do + end do + + end do + + call SS_ED_InputSolve_OtherBlades( p_FAST, ED%Input(1), MeshMapData ) + + ELSEIF ( p_FAST%CompElast == Module_BD ) THEN + + do K = 1,p_FAST%NumBl_Lin !we don't need all blades here: p_FAST%nBeams ! Loop through all blades + + do node = 1, BD%Input(1,k)%DistrLoad%NNodes + do fieldIndx = 1,3 + BD%Input(1,k)%DistrLoad%Force( fieldIndx,node) = BD%Input(1,k)%DistrLoad%Force( fieldIndx,node) + u_delta(n) * p_FAST%UJacSclFact + n = n+1 + end do + end do + + do node = 1, BD%Input(1,k)%DistrLoad%NNodes + do fieldIndx = 1,3 + BD%Input(1,k)%DistrLoad%Moment( fieldIndx,node) = BD%Input(1,k)%DistrLoad%Moment( fieldIndx,node) + u_delta(n) * p_FAST%UJacSclFact + n = n+1 + end do + end do + + end do + + call SS_BD_InputSolve_OtherBlades( p_FAST, BD, MeshMapData, 1 ) ! 1 is for the input index (i.e., Input(1,Blades2-end) + + END IF !CompElast + + + ! AeroDyn + DO k=1,p_FAST%NumBl_Lin !we don't need all blades here: SIZE(AD%Input(1)%BladeMotion) + do node = 1, AD%Input(1)%rotors(1)%BladeMotion(k)%NNodes + do fieldIndx = 1,3 + AD%Input(1)%rotors(1)%BladeMotion(k)%TranslationDisp( fieldIndx,node) = AD%Input(1)%rotors(1)%BladeMotion(k)%TranslationDisp( fieldIndx,node) + u_delta(n) + n = n+1 + end do + end do + + do node = 1, AD%Input(1)%rotors(1)%BladeMotion(k)%NNodes + CALL PerturbOrientationMatrix( AD%Input(1)%rotors(1)%BladeMotion(k)%Orientation(:,:,node), Perturbations = u_delta(n:n+2) ) + n = n+3 + end do + + do node = 1, AD%Input(1)%rotors(1)%BladeMotion(k)%NNodes + AD%Input(1)%rotors(1)%BladeMotion(k)%TranslationVel( :,node) = AD%Input(1)%rotors(1)%BladeMotion(k)%TranslationVel( :,node) + u_delta(n:n+2) + + n = n+3 + end do + + END DO + + + ! now update the inputs on other blades: + CALL SS_AD_InputSolve_OtherBlades( p_FAST, AD%Input(1), MeshMapData ) ! transfer results from blade 1 to other blades + + +END SUBROUTINE Add_SteadyState_delta + +!---------------------------------------------------------------------------------------------------------------------------------- + + + + + +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE SteadyStatePrescribedInputs( caseData, p_FAST, y_FAST, m_FAST, ED, BD, AD ) + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType), INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + INTEGER(IntKi) :: k + REAL(R8Ki) :: theta(3) + + ! Set prescribed inputs for all of the modules in the steady-state solve + + + ED%Input(1)%TwrAddedMass = 0.0_ReKi + ED%Input(1)%PtfmAddedMass = 0.0_ReKi + + ED%Input(1)%TowerPtLoads%Force = 0.0 + ED%Input(1)%TowerPtLoads%Moment = 0.0 + ED%Input(1)%NacelleLoads%Force = 0.0 + ED%Input(1)%NacelleLoads%Moment = 0.0 + ED%Input(1)%HubPtLoad%Force = 0.0 ! these are from BD, but they don't affect the ED calculations for aeromaps, so set them to 0 + ED%Input(1)%HubPtLoad%Moment = 0.0 ! these are from BD, but they don't affect the ED calculations for aeromaps, so set them to 0 + + ED%Input(1)%BlPitchCom = caseData%Pitch + ED%Input(1)%YawMom = 0.0 + ED%Input(1)%HSSBrTrqC = 0.0 + ED%Input(1)%GenTrq = 0.0 + + ! BeamDyn + IF (p_FAST%CompElast == Module_BD) THEN + + !CALL ED_CalcOutput( 0.0_DbKi, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), ED%y, ED%m, ErrStat2, ErrMsg2 ) + ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + DO k = 1,p_FAST%nBeams + BD%Input(1,k)%RootMotion%TranslationDisp = 0.0_ReKi + + theta = EulerExtract(BD%Input(1,k)%RootMotion%RefOrientation(:,:,1)) + theta(3) = -caseData%Pitch + BD%Input(1,k)%RootMotion%Orientation(:,:,1) = EulerConstruct(theta) + + BD%Input(1,k)%RootMotion%RotationVel(1,1) = caseData%RotSpeed !BD%Input(1,k)%RootMotion%RotationVel = ED%y_interp%BladeRootMotion(k)%RotationVel + BD%Input(1,k)%RootMotion%RotationVel(2:3,1) = 0.0_ReKi + + BD%Input(1,k)%RootMotion%TranslationVel(:,1) = cross_product( BD%Input(1,k)%RootMotion%RotationVel(:,1), BD%Input(1,k)%RootMotion%Position(:,1) - AD%Input(1)%rotors(1)%HubMotion%Position(:,1) ) ! ED%y_interp%BladeRootMotion(k)%TranslationVel + BD%Input(1,k)%RootMotion%TranslationAcc(:,1) = cross_product( BD%Input(1,k)%RootMotion%RotationVel(:,1), BD%Input(1,k)%RootMotion%TranslationVel(:,1) ) ! ED%y_interp%BladeRootMotion(k)%TranslationAcc + + BD%Input(1,k)%RootMotion%RotationAcc = 0.0_ReKi + END DO ! k=p_FAST%nBeams + + END IF ! BeamDyn + !BeamDyn's first "state" is not actually the state. So, do we need to do something with that????? + + + !AeroDyn + !note: i'm skipping the (unused) TowerMotion mesh + AD%Input(1)%rotors(1)%HubMotion%TranslationDisp = 0.0 + AD%Input(1)%rotors(1)%HubMotion%Orientation = AD%Input(1)%rotors(1)%HubMotion%RefOrientation + AD%Input(1)%rotors(1)%HubMotion%RotationVel(1, :) = caseData%RotSpeed + AD%Input(1)%rotors(1)%HubMotion%RotationVel(2:3,:) = 0.0_ReKi + + DO k = 1,size(AD%Input(1)%rotors(1)%BladeRootMotion,1) + theta = EulerExtract(AD%Input(1)%rotors(1)%BladeRootMotion(k)%RefOrientation(:,:,1)) + theta(3) = -caseData%Pitch + AD%Input(1)%rotors(1)%BladeRootMotion(k)%Orientation(:,:,1) = EulerConstruct(theta) !AD%Input(1)%BladeRootMotion(k)%RefOrientation + + AD%Input(1)%rotors(1)%BladeMotion(k)%RotationVel = 0.0_ReKi + !AD%Input(1)%rotors(1)%BladeMotion(k)%RotationAcc = 0.0_ReKi + AD%Input(1)%rotors(1)%BladeMotion(k)%TranslationAcc = 0.0_ReKi + END DO + + !> begin @todo + do k = 1,size(AD%Input(1)%rotors(1)%Bld) + AD%Input(1)%rotors(1)%Bld(k)%InflowOnBlade( 1, :) = caseData%WindSpeed + AD%Input(1)%rotors(1)%Bld(k)%InflowOnBlade( 2:3,:) = 0.0_ReKi + end do + AD%Input(1)%rotors(1)%InflowOnHub( 1 ,1) = caseData%WindSpeed + AD%Input(1)%rotors(1)%InflowOnHub( 2:3,1) = 0.0_ReKi + AD%Input(1)%rotors(1)%InflowOnNacelle(1 ,1) = caseData%WindSpeed + AD%Input(1)%rotors(1)%InflowOnNacelle(2:3,1) = 0.0_ReKi + AD%Input(1)%rotors(1)%InflowOnTailFin(1 ,1) = caseData%WindSpeed + AD%Input(1)%rotors(1)%InflowOnTailFin(2:3,1) = 0.0_ReKi + AD%Input(1)%rotors(1)%InflowOnTower = 0.0_ReKi + !> end @todo + + AD%Input(1)%rotors(1)%UserProp = 0.0_ReKi + + AD%Input(1)%rotors(1)%AvgDiskVel = AD%Input(1)%rotors(1)%Bld(1)%InflowOnBlade(:,1) + + +END SUBROUTINE SteadyStatePrescribedInputs +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE FormSteadyStateJacobian( caseData, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat, ErrMsg ) + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< temporary storage space for jacobian matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + + CHARACTER(1024) :: LinRootName + REAL(R8Ki), ALLOCATABLE :: dUdu(:,:) !< temporary storage space for jacobian matrix + REAL(R8Ki), ALLOCATABLE :: dUdy(:,:) !< temporary storage space for jacobian matrix + REAL(R8Ki), ALLOCATABLE :: dxdotdy(:,:) !< temporary storage space for jacobian matrix + + + INTEGER(IntKi) :: Un + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + CHARACTER(*), PARAMETER :: RoutineName = 'FormSteadyStateJacobian' + + ErrStat = ErrID_None + ErrMsg = "" + + Jmat = 0.0_R8Ki ! initialize everything we are not spec + Un = -1 + + ! these values may get printed in the linearization output files, so we'll set them here: + y_FAST%Lin%WindSpeed = caseData%WindSpeed + y_FAST%Lin%RotSpeed = caseData%RotSpeed + y_FAST%Lin%Azimuth = 0.0 + + LinRootName = TRIM(p_FAST%OutFileRoot)//'.'//trim(num2lstr(m_FAST%Lin%NextLinTimeIndx)) + + call GetModuleJacobians( caseData, dxdotdy, p_FAST, y_FAST, m_FAST, ED, BD, AD, LinRootName, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if + + call GetGlueJacobians( dUdu, dUdy, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if + + + if (output_debugging) then + call WrLinFile_txt_Head(SS_t_global, p_FAST, y_FAST, y_FAST%Lin%Glue, LinRootName, Un, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if + + if (p_FAST%LinOutJac) then ! write these before they possibly get modified with LAPACK routines (in particular, dUdu) + call WrPartialMatrix( dUdu, Un, p_FAST%OutFmt, 'dUdu', UseRow=y_FAST%Lin%Glue%use_u, UseCol=y_FAST%Lin%Glue%use_u ) + call WrPartialMatrix( dUdy, Un, p_FAST%OutFmt, 'dUdy', UseRow=y_FAST%Lin%Glue%use_u, UseCol=y_FAST%Lin%Glue%use_y ) + call WrPartialMatrix( dxdotdy, Un, p_FAST%OutFmt, 'dxdotdy', UseRow=y_FAST%Lin%Glue%use_u, UseCol=y_FAST%Lin%Glue%use_y ) + end if + end if + + !----------------------------------------- + ! form J matrix + !----------------------------------------- + CALL GetBlock11(Jmat, dxdotdy, p_FAST, y_FAST, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL GetBlock12(Jmat, dxdotdy, p_FAST, y_FAST, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL GetBlock21(Jmat, dUdy, p_FAST, y_FAST, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL GetBlock22(Jmat, dUdy, dUdu, p_FAST, y_FAST, ErrStat2, ErrMsg2); call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + if (ErrStat >=AbortErrLev) then + call cleanup() + return + end if + + + + if (output_debugging) then + if (p_FAST%LinOutJac) then + ! Jacobians + call WrPartialMatrix( Jmat, Un, p_FAST%OutFmt, 'J' ) + end if + + ! finish writing the file + call WrLinFile_txt_End(Un, p_FAST, y_FAST%Lin%Glue ) + end if + + m_FAST%Lin%NextLinTimeIndx = m_FAST%Lin%NextLinTimeIndx + 1 +CONTAINS + SUBROUTINE Cleanup() + + IF (ALLOCATED(dUdu)) DEALLOCATE(dUdu) + IF (ALLOCATED(dUdy)) DEALLOCATE(dUdy) + IF (ALLOCATED(dxdotdy)) DEALLOCATE(dxdotdy) + + if (Un > 0) close(Un) + + END SUBROUTINE Cleanup + +END SUBROUTINE FormSteadyStateJacobian +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetModuleJacobians( caseData, dxdotdy, p_FAST, y_FAST, m_FAST, ED, BD, AD, LinRootName, ErrStat, ErrMsg ) + TYPE(FAST_SS_CaseType) , INTENT(IN ) :: caseData !< tsr, windSpeed, pitch, and rotor speed for this case + REAL(R8Ki), ALLOCATABLE ,INTENT(INOUT) :: dxdotdy(:,:) !< temporary storage space for jacobian matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + CHARACTER(*), INTENT(IN ) :: LinRootName + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + REAL(R8Ki) :: OmegaSquared + INTEGER(IntKi) :: k + INTEGER(IntKi) :: i, r, c, nx + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + CHARACTER(*), PARAMETER :: RoutineName = 'GetModuleJacobians' + + ErrStat = ErrID_None + ErrMsg = "" + + !------------------------ + ! dx_dot/dy: + !------------------------ + if (.not. allocated(dxdotdy)) then + call AllocAry(dxdotdy, y_FAST%Lin%Glue%SizeLin(LIN_ContState_COL), y_FAST%Lin%Glue%SizeLin(LIN_OUTPUT_COL), 'dxdotdy', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + end if + + dxdotdy = 0.0_R8Ki + + !..................... + ! Structure + !..................... + + y_FAST%Lin%RotSpeed = ED%y%RotSpeed + y_FAST%Lin%Azimuth = ED%y%LSSTipPxa + + !..................... + ! ElastoDyn + !..................... + if ( p_FAST%CompElast == Module_ED ) then + ! get the jacobians + call ED_JacobianPInput( SS_t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + ED%y, ED%m, ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%D, dXdu=y_FAST%Lin%Modules(Module_ED)%Instance(1)%B ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call ED_JacobianPContState( SS_t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + ED%y, ED%m, ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%C, dXdx=y_FAST%Lin%Modules(Module_ED)%Instance(1)%A ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + ! get the operating point + if (output_debugging) then + call ED_GetOP( SS_t_global, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + ED%y, ED%m, ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_u, & + y_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_y, & + x_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_x, & + dx_op=y_FAST%Lin%Modules(Module_ED)%Instance(1)%op_dx ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) return + + ! write the module matrices: + call WriteModuleLinearMatrices(Module_ED, 1, SS_t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + !..................... + ! BeamDyn + !..................... + elseif ( p_FAST%CompElast == Module_BD ) then + + OmegaSquared = caseData%RotSpeed**2 + nx = size(dxdotdy,1)/2 + + do k=1,p_FAST%nBeams + + ! get the jacobians + call BD_JacobianPInput( SS_t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & + BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%D, & + dXdu=y_FAST%Lin%Modules(Module_BD)%Instance(k)%B, & + StateRel_x =y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_x, & + StateRel_xdot=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRel_xdot ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + call BD_JacobianPContState( SS_t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & + BD%y(k), BD%m(k), ErrStat2, ErrMsg2, dYdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%C, dXdx=y_FAST%Lin%Modules(Module_BD)%Instance(k)%A, & + StateRotation=y_FAST%Lin%Modules(Module_BD)%Instance(k)%StateRotation) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + if (output_debugging) then + ! get the operating point (for writing to file only) + call BD_GetOP( SS_t_global, BD%Input(1,k), BD%p(k), BD%x(k,STATE_CURR), BD%xd(k,STATE_CURR), BD%z(k,STATE_CURR), BD%OtherSt(k,STATE_CURR), & + BD%y(k), BD%m(k), ErrStat2, ErrMsg2, u_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_u, y_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_y, & + x_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_x, dx_op=y_FAST%Lin%Modules(Module_BD)%Instance(k)%op_dx ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) return + + ! write the module matrices: + call WriteModuleLinearMatrices(Module_BD, k, SS_t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + ! calculate dxdotdy here: + ! NOTE that this implies that the FEA nodes (states) are the same as the output nodes!!!! (note that we have overlapping nodes at the element end points) + r = 1 + do i=2,BD%p(k)%node_total ! the first node isn't technically a state + c = (BD%p(k)%NdIndx(i)-1)*3 + 1 ! BldMeshNode = BD%p(k)%NdIndx(i) + + !dxdotdy(r:r+2,c:c+2) = SkewSymMat( [p_FAST%RotSpeed, 0.0_ReKi, 0.0_ReKi] ) + dxdotdy(r+2,c+1) = caseData%RotSpeed + dxdotdy(r+1,c+2) = -caseData%RotSpeed + + ! derivative + dxdotdy(r+nx+1,c+1) = -OmegaSquared + dxdotdy(r+nx+2,c+2) = -OmegaSquared + + r = r + BD%p(k)%dof_node + end do + + end do ! k + + end if !BeamDyn + + + !..................... + ! AeroDyn + !..................... + if ( p_FAST%CompAero == Module_AD ) then + ! get the jacobians + call AD_JacobianPInput( SS_t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & + AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, & + dYdu=y_FAST%Lin%Modules(Module_AD)%Instance(1)%D ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + if (output_debugging) then + ! get the operating point + call AD_GetOP( SS_t_global, AD%Input(1), AD%p, AD%x(STATE_CURR), AD%xd(STATE_CURR), AD%z(STATE_CURR), & + AD%OtherSt(STATE_CURR), AD%y, AD%m, ErrStat2, ErrMsg2, & + u_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_u, & + y_op=y_FAST%Lin%Modules(Module_AD)%Instance(1)%op_y ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) return + + + ! write the module matrices: + call WriteModuleLinearMatrices(Module_AD, 1, SS_t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) RETURN + end if + + end if + + ! move all module-level matrices into system-wide glue matrices: + call Glue_FormDiag( p_FAST, y_FAST, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + +END SUBROUTINE GetModuleJacobians +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetGlueJacobians( dUdu, dUdy, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat, ErrMsg ) + REAL(R8Ki), ALLOCATABLE, INTENT(INOUT) :: dUdu(:,:) !< temporary storage space for jacobian matrix + REAL(R8Ki), ALLOCATABLE, INTENT(INOUT) :: dUdy(:,:) !< temporary storage space for jacobian matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: ThisModule + INTEGER(IntKi) :: i, j + INTEGER(IntKi) :: k + INTEGER(IntKi) :: r_start, r_end + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + CHARACTER(*), PARAMETER :: RoutineName = 'GetGlueJacobians' + + + ErrStat = ErrID_None + ErrMsg = "" + + !------------------------ + ! dU/du: + !------------------------ + if (.not. allocated(dUdu)) then + call AllocAry(dUdu, y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), 'dUdu', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + end if + + dUdu = 0.0_R8Ki ! most of this matrix is zero, so we'll just initialize everything and set only the non-zero parts below + do j = 1,p_FAST%Lin_NumMods + ThisModule = p_FAST%Lin_ModOrder(j) + do k=1,size(y_FAST%Lin%Modules(ThisModule)%Instance) + r_start = y_FAST%Lin%Modules(ThisModule)%Instance(k)%LinStartIndx(LIN_INPUT_COL) + r_end = r_start + y_FAST%Lin%Modules(ThisModule)%Instance(k)%SizeLin( LIN_INPUT_COL) - 1 + do i = r_start,r_end + dUdu(i,i) = 1.0_R8Ki + end do + end do + end do + + + call LinearSS_AD_InputSolve_du( p_FAST, y_FAST, AD%Input(1), ED%y, BD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + IF (p_FAST%CompElast == Module_ED) THEN + call LinearSS_ED_InputSolve_du( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + ELSEIF (p_FAST%CompElast == Module_BD) THEN + call LinearSS_BD_InputSolve_du( p_FAST, y_FAST, AD%y, AD%Input(1), BD, MeshMapData, dUdu, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + END IF + +!!! write the module matrices: +!!!call WriteModuleLinearMatrices(Module_AD, 1, SS_t_global, p_FAST, y_FAST, LinRootName, ErrStat2, ErrMsg2) +!!! call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) +!!! if (ErrStat >=AbortErrLev) RETURN + + !------------------------ + ! dU/dy: + !------------------------ + if (.not. allocated(dUdy)) then + call AllocAry(dUdy, y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), y_FAST%Lin%Glue%SizeLin(LIN_OUTPUT_COL), 'dUdy', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat>=AbortErrLev) return + end if + + dUdy = 0.0_R8Ki ! most of this matrix is zero, so we'll just initialize everything and set only the non-zero parts below + + + if (p_FAST%CompElast == Module_ED) then + call LinearSS_ED_InputSolve_dy( p_FAST, y_FAST, ED%Input(1), ED%y, AD%y, AD%Input(1), MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + elseif (p_FAST%CompElast == MODULE_BD) then + call LinearSS_BD_InputSolve_dy( p_FAST, y_FAST, AD%y, AD%Input(1), BD, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + end if + + call LinearSS_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, AD%Input(1), ED%y, BD, MeshMapData, dUdy, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + if (output_debugging) then + ! for debugging: + call Glue_GetOP(p_FAST, y_FAST, ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >=AbortErrLev) return + end if + +END SUBROUTINE GetGlueJacobians +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetBlock11(Jmat, dxdotdy, p_FAST, y_FAST, ErrStat, ErrMsg) + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< Jacobian matrix of which we are calculating the upper left block: (1,1) + REAL(R8Ki), INTENT(IN ) :: dxdotdy(:,:) !< temporary storage space for jacobian matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + REAL(R8Ki), ALLOCATABLE :: blockMat(:,:) + INTEGER(IntKi) :: r_start, c_start, r, c + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'GetBlock11' + + ErrStat = ErrID_None + ErrMsg = "" + + !--------------- + ! upper left corner of J matrix: size of A (uses only blade DOFs from the structural module) + !--------------- + call AllocAry(blockMat, y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL), y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL), 'block matrix 1,1', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + blockMat = y_FAST%Lin%Glue%A ! copy this so we don't overwrite y_FAST%Lin%Glue%A here + call LAPACK_GEMM( 'N', 'N', -1.0_R8Ki, dxdotdy, y_FAST%Lin%Glue%C, 1.0_R8Ki, blockMat, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + + r_start = 1 + c_start = 1 + + ! dX/dx - dx_dot/dy * dY/dx = A - dx_dot/dy * C: + do c=1,size( blockMat, 2) + do r=1,size( blockMat, 1) + Jmat(r_start + r - 1, c_start + c - 1) = blockMat(r,c) + end do + end do + + + if (allocated (blockMat)) deallocate(blockMat) + + +END SUBROUTINE GetBlock11 +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetBlock12(Jmat, dxdotdy, p_FAST, y_FAST, ErrStat, ErrMsg) + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< Jacobian matrix of which we are calculating the upper right block: (1,2) + REAL(R8Ki), INTENT(IN ) :: dxdotdy(:,:) !< temporary storage space for jacobian matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + REAL(R8Ki), ALLOCATABLE :: blockMat(:,:) + INTEGER(IntKi) :: r_start, c_start, r, c + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'GetBlock11' + + ErrStat = ErrID_None + ErrMsg = "" + + !--------------- + ! upper right corner of J matrix: size of B (uses only blade DOFs from the structural module) + !--------------- + call AllocAry(blockMat, y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL), y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), 'block matrix 1,2', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + blockMat = y_FAST%Lin%Glue%B ! copy this so we don't overwrite y_FAST%Lin%Glue%B here + call LAPACK_GEMM( 'N', 'N', -1.0_R8Ki, dxdotdy, y_FAST%Lin%Glue%D, 1.0_R8Ki, blockMat, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + r_start = 1 + c_start = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + 1 + + ! dX/du - dx_dot/dy * dY/du = B - dx_dot/dy * D: + do c=1,size( blockMat, 2) + do r=1,size( blockMat, 1) + Jmat(r_start + r - 1, c_start + c - 1) = blockMat(r,c) + end do + end do + + + if (allocated (blockMat)) deallocate(blockMat) + + +END SUBROUTINE GetBlock12 +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetBlock21(Jmat, dUdy, p_FAST, y_FAST, ErrStat, ErrMsg) + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< Jacobian matrix of which we are calculating the lower left block: (2,1) + REAL(R8Ki), INTENT(IN ) :: dUdy(:,:) !< dUdy matrix + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + REAL(R8Ki), ALLOCATABLE :: dUdx(:,:) + INTEGER(IntKi) :: r_start, c_start, r, c + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'GetBlock21' + + ErrStat = ErrID_None + ErrMsg = "" + + !--------------- + ! lower left corner of J matrix: + !--------------- + call AllocAry(dUdx, y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL), y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL), 'block matrix 2,1', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + if (ErrStat >= AbortErrLev) return + + call LAPACK_GEMM( 'N', 'N', 1.0_R8Ki, dUdy, y_FAST%Lin%Glue%C, 0.0_R8Ki, dUdx, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + r_start = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + 1 + c_start = 1 + + ! dU/dy * dY/dx: + do c=1,size( dUdx, 2) + do r=1,size( dUdx, 1) + Jmat(r_start + r - 1, c_start + c - 1) = dUdx(r,c) + end do + end do + + if (allocated (dUdx)) deallocate(dUdx) + +END SUBROUTINE GetBlock21 +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE GetBlock22(Jmat, dUdy, dUdu, p_FAST, y_FAST, ErrStat, ErrMsg) + REAL(R8Ki), INTENT(INOUT) :: Jmat(:,:) !< Jacobian matrix of which we are calculating the lower left block: (2,1) + REAL(R8Ki), INTENT(IN ) :: dUdy(:,:) !< dUdy matrix + REAL(R8Ki), INTENT(INOUT) :: dUdu(:,:) !< dUdu matrix (note that it is modified on exit of this routine!) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: r_start, c_start, r, c + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'GetBlock22' + + ErrStat = ErrID_None + ErrMsg = "" + + !--------------- + ! lower right corner of J matrix: + !--------------- + call LAPACK_GEMM( 'N', 'N', 1.0_R8Ki, dUdy, y_FAST%Lin%Glue%D, 1.0_R8Ki, dUdu, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + + r_start = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + 1 + c_start = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + 1 + + ! dU/du + dU/dy * dY/du: + do c=1,size( dUdu, 2) + do r=1,size( dUdu, 1) + Jmat(r_start + r - 1, c_start + c - 1) = dUdu(r,c) + end do + end do + + +END SUBROUTINE GetBlock22 +!---------------------------------------------------------------------------------------------------------------------------------- + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{ED}/du^{BD} and dU^{ED}/du^{AD} blocks (ED row) of dUdu. (i.e., how do changes in the AD and BD inputs affect the ED inputs?) +SUBROUTINE LinearSS_ED_InputSolve_du( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, MeshMapData, dUdu, ErrStat, ErrMsg ) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t + TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load linerization) + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdu(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Start_Bl ! starting index of dUdu (column) where AD blade motion inputs are located + INTEGER(IntKi) :: ED_Start_mt ! starting index of dUdu (row) where ED blade/tower or hub moment inputs are located + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'LinearSS_ED_InputSolve_du' + + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + !.......... + ! dU^{ED}/du^{AD} + !.......... + IF ( p_FAST%CompAero == Module_AD ) THEN + + ! ED inputs on blade from AeroDyn + IF (p_FAST%CompElast == Module_ED) THEN + + ED_Start_mt = y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%LinStartIndx(LIN_INPUT_COL) + + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) + ED_Start_mt = ED_Start_mt + u_ED%BladePtLoads(k)%NNodes*3 ! skip the forces on this blade + AD_Start_Bl = SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, k) + + CALL Linearize_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), y_ED%BladeLn2Mesh(k) ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + ! AD is source in the mapping, so we want M_{uSm} + if (allocated(MeshMapData%AD_L_2_BDED_B(k)%dM%m_us )) then + call SetBlockMatrix( dUdu, MeshMapData%AD_L_2_BDED_B(k)%dM%m_us, ED_Start_mt, AD_Start_Bl ) + end if + + ! get starting index of next blade + ED_Start_mt = ED_Start_mt + u_ED%BladePtLoads(k)%NNodes* 3 ! skip the moments on this blade + + END DO + + END IF + + END IF + + +END SUBROUTINE LinearSS_ED_InputSolve_du +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{BD}/du^{BD} and dU^{BD}/du^{AD} blocks (BD row) of dUdu. (i.e., how do changes in the AD and BD inputs +!! affect the BD inputs?) This should be called only when p_FAST%CompElast == Module_BD. +SUBROUTINE LinearSS_BD_InputSolve_du( p_FAST, y_FAST, y_AD, u_AD, BD, MeshMapData, dUdu, ErrStat, ErrMsg ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< Glue-code output parameters (for linearization) + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load linerization) + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BD data at t + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdu(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + INTEGER(IntKi) :: k ! Loops through blades + INTEGER(IntKi) :: BD_Start ! starting index of dUdu (row) where BD inputs are located + INTEGER(IntKi) :: AD_Start ! starting index of dUdu (column) where AD inputs are located + INTEGER(IntKi) :: ErrStat2 ! temporary Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg2 ! temporary Error message if ErrStat /= ErrID_None + + CHARACTER(*), PARAMETER :: RoutineName = 'LinearSS_BD_InputSolve_du' + + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + !.......... + ! dU^{BD}/du^{AD} + !.......... + IF ( p_FAST%CompAero == Module_AD ) THEN + + ! BD inputs on blade from AeroDyn + + + if (p_FAST%BD_OutputSibling) then + + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: p_FAST%nBeams ! Loop through all blades + CALL Linearize_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), BD%y(k)%BldMotion ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END DO + + else + + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: p_FAST%nBeams ! Loop through all blades + !linearization for dUdy will need some matrix multiplies because of the transfer (chain rule!), but we will perform individual linearization calculations here + !!! need to transfer the BD output blade motions to nodes on a sibling of the BD blade motion mesh: + CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, MeshMapData%y_BD_BldMotion_4Loads(k), MeshMapData%BD_L_2_BD_L(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + CALL Linearize_Line2_to_Line2( y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%rotors(1)%BladeMotion(k), MeshMapData%y_BD_BldMotion_4Loads(k) ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END DO + + end if + + + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: p_FAST%nBeams ! Loop through all blades + + ! AD is source in the mapping, so we want M_{uSm} + if (allocated(MeshMapData%AD_L_2_BDED_B(k)%dM%m_us )) then + AD_Start = SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, k) ! index for the start of u_AD%BladeMotion(k)%translationDisp field + + BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) & + + BD%Input(1,k)%DistrLoad%NNodes * 3 ! force field for each node (start with moment field) + + call SetBlockMatrix( dUdu, MeshMapData%AD_L_2_BDED_B(k)%dM%m_us, BD_Start, AD_Start ) + end if + + END DO + + END IF + +END SUBROUTINE LinearSS_BD_InputSolve_du +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{AD}/du^{AD} block of dUdu. (i.e., how do changes in the AD inputs affect the AD inputs?) +SUBROUTINE LinearSS_AD_InputSolve_du( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, dUdu, ErrStat, ErrMsg ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< The inputs to AeroDyn14 + TYPE(ED_OutputType), INTENT(IN) :: y_ED !< The outputs from the structural dynamics module + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BD data at t + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdu(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + + INTEGER(IntKi) :: ErrStat !< Error status of the operation + CHARACTER(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Start_td ! starting index of dUdu (column) where AD translation displacements are located + INTEGER(IntKi) :: AD_Start_tv ! starting index of dUdu (column) where AD translation velocities are located + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'LinearSS_ED_InputSolve_dy' + + + ErrStat = ErrID_None + ErrMsg = "" + + ! note that we assume this block matrix has been initialized to the identity matrix before calling this routine + + ! look at how the translational displacement gets transfered to the translational velocity: + !------------------------------------------------------------------------------------------------- + ! Set the inputs from ElastoDyn and/or BeamDyn: + !------------------------------------------------------------------------------------------------- + + ! blades + IF (p_FAST%CompElast == Module_ED ) THEN + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades: size(u_AD%BladeMotion) + CALL Linearize_Line2_to_Line2( y_ED%BladeLn2Mesh(k), u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeMotion('//trim(num2lstr(k))//')' ) + END DO + + ELSEIF (p_FAST%CompElast == Module_BD ) THEN + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades: size(u_AD%BladeMotion) + CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName//':u_AD%BladeMotion('//trim(num2lstr(k))//')' ) + END DO + + END IF + + + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades: size(u_AD%BladeMotion) + + AD_Start_td = SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, k) ! index for u_AD%BladeMotion(k)%translationDisp field + + !AD is the destination here, so we need tv_ud + if (allocated( MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud)) then + ! index for u_AD%BladeMotion(k+1)%translationVel field + AD_Start_tv = AD_Start_td + u_AD%rotors(1)%BladeMotion(k)%NNodes * 6 ! 2 fields (TranslationDisp and Orientation) with 3 components before translational velocity field + + call SetBlockMatrix( dUdu, MeshMapData%BDED_L_2_AD_L_B(k)%dM%tv_ud, AD_Start_tv, AD_Start_td ) + end if + + + END DO + + + +END SUBROUTINE LinearSS_AD_InputSolve_du + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{ED}/dy^{SrvD}, dU^{ED}/dy^{ED}, dU^{ED}/dy^{BD}, dU^{ED}/dy^{AD}, dU^{ED}/dy^{HD}, and dU^{ED}/dy^{MAP} +!! blocks of dUdy. (i.e., how do changes in the SrvD, ED, BD, AD, HD, and MAP outputs effect the ED inputs?) +SUBROUTINE LinearSS_ED_InputSolve_dy( p_FAST, y_FAST, u_ED, y_ED, y_AD, u_AD, MeshMapData, dUdy, ErrStat, ErrMsg ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(ED_InputType), INTENT(INOUT) :: u_ED !< ED Inputs at t + TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ElastoDyn outputs (need translation displacement on meshes for loads mapping) + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load linerization) + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Out_Start ! starting index of dUdy (column) where particular AD fields are located + INTEGER(IntKi) :: ED_Start ! starting index of dUdy (row) where ED input fields are located + INTEGER(IntKi) :: ED_Out_Start ! starting index of dUdy (column) where ED output fields are located + CHARACTER(*), PARAMETER :: RoutineName = 'Linear_ED_InputSolve_dy' + + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + ! parts of dU^{ED}/dy^{AD} and dU^{ED}/dy^{ED}: + + ! ElastoDyn inputs on blade from AeroDyn and ElastoDyn + + AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) ! start of y_AD%rotors(1)%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] + + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: SIZE(u_ED%BladePtLoads,1) ! Loop through all blades (p_ED%NumBl) + !!! ! This linearization was done in forming dUdu (see Linear_ED_InputSolve_du()), so we don't need to re-calculate these matrices + !!! ! while forming dUdy, too. + !CALL Linearize_Line2_to_Point( y_AD%rotors(1)%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ErrStat2, ErrMsg2, u_AD%BladeMotion(k), y_ED%BladeLn2Mesh(k) ) + + ! AD loads-to-ED loads transfer (dU^{ED}/dy^{AD}): + ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) ! start of u_ED%BladePtLoads(k)%Force field + call Assemble_dUdy_Loads(y_AD%rotors(1)%BladeLoad(k), u_ED%BladePtLoads(k), MeshMapData%AD_L_2_BDED_B(k), ED_Start, AD_Out_Start, dUdy) + + ! ED translation displacement-to-ED moment transfer (dU^{ED}/dy^{ED}): + ED_Start = Indx_u_ED_Blade_Start(u_ED, y_FAST, k) + u_ED%BladePtLoads(k)%NNodes*3 ! start of u_ED%BladePtLoads(k)%Moment field (skip the ED forces) + ED_Out_Start = SS_Indx_y_ED_Blade_Start(y_ED, p_FAST, y_FAST, k) ! start of y_ED%BladeLn2Mesh(1)%TranslationDisp field + call SetBlockMatrix( dUdy, MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD, ED_Start, ED_Out_Start ) + + AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%rotors(1)%BladeLoad(k+1)%Force field [skip 2 fields to forces on next blade] + END DO + + +END SUBROUTINE LinearSS_ED_InputSolve_dy +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{BD}/dy^{ED}, dU^{BD}/dy^{BD}, and dU^{BD}/dy^{AD} blocks of dUdy. (i.e., how do +!! changes in the ED, BD, and AD outputs effect the BD inputs?) +SUBROUTINE LinearSS_BD_InputSolve_dy( p_FAST, y_FAST, y_AD, u_AD, BD, MeshMapData, dUdy, ErrStat, ErrMsg ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Glue-code simulation parameters + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(AD_OutputType), INTENT(IN ) :: y_AD !< AeroDyn outputs + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< AD inputs (for AD-ED load linearization) + TYPE(BeamDyn_Data), INTENT(IN ) :: BD !< BD data at t + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< Jacobian matrix of which we are computing the dU^(ED)/du^(AD) block + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message + + ! local variables + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Out_Start ! starting index of dUdy (column) where particular AD fields are located + INTEGER(IntKi) :: BD_Start ! starting index of dUdy (column) where particular BD fields are located + INTEGER(IntKi) :: BD_Out_Start ! starting index of dUdy (column) where BD output fields are located + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMsg2 + REAL(R8Ki), ALLOCATABLE :: TempMat(:,:) ! temporary matrix for getting linearization matrices when BD input and output meshes are not siblings + CHARACTER(*), PARAMETER :: RoutineName = 'LinearSS_BD_InputSolve_dy' + + + ! Initialize error status + + ErrStat = ErrID_None + ErrMsg = "" + + ! parts of dU^{BD}/dy^{AD} and dU^{BD}/dy^{BD}: + + ! BeamDyn inputs on blade from AeroDyn and BeamDyn + + AD_Out_Start = y_FAST%Lin%Modules(MODULE_AD)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) ! start of y_AD%rotors(1)%BladeLoad(1)%Force field [2 fields (force, moment) with 3 components] + DO K = 1,p_FAST%NumBl_Lin !we don't need all blades: p_FAST%nBeams ! Loop through all blades + + BD_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_INPUT_COL) ! start of BD%Input(1,k)%DistrLoad%Force field + + ! AD loads-to-BD loads transfer (dU^{BD}/dy^{AD}): + call Assemble_dUdy_Loads(y_AD%rotors(1)%BladeLoad(k), BD%Input(1,k)%DistrLoad, MeshMapData%AD_L_2_BDED_B(k), BD_Start, AD_Out_Start, dUdy) + AD_Out_Start = AD_Out_Start + y_AD%rotors(1)%BladeLoad(k)%NNodes*6 ! start of y_AD%rotors(1)%BladeLoad(k+1)%Force field [skip the moments to get to forces on next blade] + + + ! BD translation displacement-to-BD moment transfer (dU^{BD}/dy^{BD}): + BD_Start = BD_Start + BD%Input(1,k)%DistrLoad%NNodes * 3 ! start of BD%Input(1,k)%DistrLoad%Moment field (start with moment field) + BD_Out_Start = y_FAST%Lin%Modules(MODULE_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) ! start of BD%y(k)%BldMotion%TranslationDisp field + + + if (p_FAST%BD_OutputSibling) then + call SetBlockMatrix( dUdy, MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD, BD_Start, BD_Out_Start ) + else + call AllocAry(TempMat, size(MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD,1), size(MeshMapData%BD_L_2_BD_L(k)%dM%mi,2), 'TempMat', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat>=AbortErrLev) return + + ! these blocks should be small enough that we can use matmul instead of calling a LAPACK routine to do it. + TempMat = matmul(MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD,MeshMapData%BD_L_2_BD_L(k)%dM%mi) + call SetBlockMatrix( dUdy, TempMat, BD_Start, BD_Out_Start ) + + BD_Out_Start = BD_Out_Start + BD%y(k)%BldMotion%NNodes*3 ! start of BD%y(k)%BldMotion%Orientation field + TempMat = matmul(MeshMapData%AD_L_2_BDED_B(k)%dM%m_uD,MeshMapData%BD_L_2_BD_L(k)%dM%fx_p) + call SetBlockMatrix( dUdy, TempMat, BD_Start, BD_Out_Start ) + + deallocate(TempMat) ! the next blade may have a different number of nodes + end if + + END DO + + +END SUBROUTINE LinearSS_BD_InputSolve_dy +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine forms the dU^{AD}/dy^{ED} and dU^{AD}/dy^{BD} blocks of dUdy. (i.e., how do changes in the ED and BD outputs affect +!! the AD inputs?) +SUBROUTINE LinearSS_AD_InputSolve_NoIfW_dy( p_FAST, y_FAST, u_AD, y_ED, BD, MeshMapData, dUdy, ErrStat, ErrMsg ) + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(AD_InputType), INTENT(INOUT) :: u_AD !< The inputs to AeroDyn14 + TYPE(ED_OutputType), INTENT(IN) :: y_ED !< The outputs from the structural dynamics module + TYPE(BeamDyn_Data), INTENT(IN ) :: BD !< BD data at t + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), INTENT(INOUT) :: dUdy(:,:) !< Jacobian matrix of which we are computing the dU^{AD}/dy^{ED} block + + INTEGER(IntKi) :: ErrStat !< Error status of the operation + CHARACTER(*) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ! Local variables: + + INTEGER(IntKi) :: K ! Loops through blades + INTEGER(IntKi) :: AD_Start ! starting index of dUdy (column) where particular AD fields are located + INTEGER(IntKi) :: ED_Out_Start! starting index of dUdy (row) where particular ED fields are located + INTEGER(IntKi) :: BD_Out_Start! starting index of dUdy (row) where particular BD fields are located +! INTEGER(IntKi) :: ErrStat2 +! CHARACTER(ErrMsgLen) :: ErrMsg2 + CHARACTER(*), PARAMETER :: RoutineName = 'LinearSS_AD_InputSolve_NoIfW_dy' + + + ErrStat = ErrID_None + ErrMsg = "" + + !------------------------------------------------------------------------------------------------- + ! Set the inputs from ElastoDyn and/or BeamDyn: + !------------------------------------------------------------------------------------------------- + !................................... + ! blades + !................................... + IF (p_FAST%CompElast == Module_ED ) THEN + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades: size(y_ED%BladeLn2Mesh) + !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices + !!! ! while forming dUdy, too. + !!!CALL Linearize_Line2_to_Line2( y_ED%BladeLn2Mesh(k), u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + + AD_Start = SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field + ED_Out_Start = SS_Indx_y_ED_Blade_Start(y_ED, p_FAST, y_FAST, k) ! start of y_ED%BladeLn2Mesh(k)%TranslationDisp field + CALL Assemble_dUdy_Motions(y_ED%BladeLn2Mesh(k), u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, ED_Out_Start, dUdy, skipRotVel=.true.) + + END DO + + ELSEIF (p_FAST%CompElast == Module_BD ) THEN + !!! ! This linearization was done in forming dUdu (see Linear_AD_InputSolve_du()), so we don't need to re-calculate these matrices + !!! ! while forming dUdy, too. + !!!CALL Linearize_Line2_to_Line2( BD%y(k)%BldMotion, u_AD%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), ErrStat2, ErrMsg2 ) + + DO k=1,p_FAST%NumBl_Lin !we don't need all blades: p_FAST%nBeams + AD_Start = SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, k) ! start of u_AD%BladeMotion(k)%TranslationDisp field + BD_Out_Start = y_FAST%Lin%Modules(Module_BD)%Instance(k)%LinStartIndx(LIN_OUTPUT_COL) + + CALL Assemble_dUdy_Motions(BD%y(k)%BldMotion, u_AD%rotors(1)%BladeMotion(k), MeshMapData%BDED_L_2_AD_L_B(k), AD_Start, BD_Out_Start, dUdy, skipRotVel=.true.) + END DO + + END IF + + +END SUBROUTINE LinearSS_AD_InputSolve_NoIfW_dy +!---------------------------------------------------------------------------------------------------------------------------------- + +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine returns the starting index for the u_AD%BladeMotion(k) mesh in the FAST linearization inputs. +FUNCTION SS_Indx_u_AD_Blade_Start(u_AD, p_FAST, y_FAST, BladeNum) RESULT(AD_Start) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(AD_InputType), INTENT(IN ) :: u_AD !< AD Inputs at t + INTEGER(IntKi), INTENT(IN ) :: BladeNum !< blade number to find index for + INTEGER :: k !< blade number loop + + INTEGER(IntKi) :: AD_Start !< starting index of this mesh in AeroDyn inputs + + AD_Start = y_FAST%Lin%Modules(Module_AD)%Instance(1)%LinStartIndx(LIN_INPUT_COL) + + do k = 1,min(BladeNum-1,p_FAST%NumBl_Lin) !size(u_AD%BladeMotion)) + AD_Start = AD_Start + u_AD%rotors(1)%BladeMotion(k)%NNodes * 9 ! 3 fields (TranslationDisp, MASKID_Orientation, TranslationVel) with 3 components + end do +END FUNCTION SS_Indx_u_AD_Blade_Start +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine returns the starting index for the y_ED%BladeLn2Mesh(BladeNum) mesh in the FAST linearization outputs. +FUNCTION SS_Indx_y_ED_Blade_Start(y_ED, p_FAST, y_FAST, BladeNum) RESULT(ED_Out_Start) + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< FAST parameter data + TYPE(FAST_OutputFileType), INTENT(IN ) :: y_FAST !< FAST output file data (for linearization) + TYPE(ED_OutputType), INTENT(IN ) :: y_ED !< ED outputs at t + INTEGER(IntKi), INTENT(IN ) :: BladeNum !< blade number to find index for + INTEGER :: k !< blade number loop + + INTEGER(IntKi) :: ED_Out_Start !< starting index of this blade mesh in ElastoDyn outputs + + ED_Out_Start = y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%LinStartIndx(LIN_OUTPUT_COL) ! start of y_ED%BladeLn2Mesh(1)%TranslationDisp field (blade motions in y_ED) + if (allocated(y_ED%BladeLn2Mesh)) then + do k = 1,min(BladeNum-1,p_FAST%NumBl_Lin) ! we don't need all blades: SIZE(y_ED%BladeLn2Mesh,1)) ! Loop through all blades (p_ED%NumBl) + ED_Out_Start = ED_Out_Start + y_ED%BladeLn2Mesh(k)%NNodes*12 ! 4 fields with 3 components on each blade + end do + end if + +END FUNCTION SS_Indx_y_ED_Blade_Start +!---------------------------------------------------------------------------------------------------------------------------------- + + + +END MODULE FAST_SS_Solver diff --git a/modules/openfast-library/src/FAST_SS_Subs.f90 b/modules/openfast-library/src/FAST_SS_Subs.f90 new file mode 100644 index 0000000000..ca1fb0dd18 --- /dev/null +++ b/modules/openfast-library/src/FAST_SS_Subs.f90 @@ -0,0 +1,297 @@ +!********************************************************************************************************************************** +! FAST_Solver.f90, FAST_Subs.f90, FAST_Lin.f90, and FAST_Mods.f90 make up the FAST glue code in the FAST Modularization Framework. +! FAST_Prog.f90, FAST_Library.f90, FAST_Prog.c are different drivers for this code. +!.................................................................................................................................. +! LICENSING +! Copyright (C) 2013-2016 National Renewable Energy Laboratory +! +! This file is part of FAST. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. +!********************************************************************************************************************************** +MODULE FAST_SS_Subs + + USE FAST_SS_Solver + + IMPLICIT NONE + + +CONTAINS +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +! DRIVER ROUTINE (runs + ends simulation) +! Put here so that we can call from either stand-alone code or from the ENFAST executable. +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +SUBROUTINE FAST_RunSteadyStateDriver( Turbine ) + TYPE(FAST_TurbineType), INTENT(INOUT) :: Turbine !< all data for one instance of a turbine + + INTEGER(IntKi) :: ErrStat !< Error status of the operation + CHARACTER(ErrMsgLen) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + ProgName = TRIM(FAST_Ver%Name)//' Steady State' + FAST_Ver%Name = ProgName + + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ! initialization + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + CALL FAST_InitializeSteadyState_T( Turbine, ErrStat, ErrMsg ) + CALL CheckError( ErrStat, ErrMsg, 'during module initialization' ) + + + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ! Calculate steady-state solutions: + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + CALL FAST_SteadyState_T( Turbine, ErrStat, ErrMsg ) + CALL CheckError( ErrStat, ErrMsg, 'during steady-state solve' ) + + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ! Clean up and stop + !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + CALL ExitThisProgram_T( Turbine, ErrID_None, .true. ) + + CONTAINS + !............................................................................................................................... + SUBROUTINE CheckError(ErrID,Msg,SimMsg) + ! This subroutine sets the error message and level and cleans up if the error is >= AbortErrLev + !............................................................................................................................... + + ! Passed arguments + INTEGER(IntKi), INTENT(IN) :: ErrID ! The error identifier (ErrStat) + CHARACTER(*), INTENT(IN) :: Msg ! The error message (ErrMsg) + CHARACTER(*), INTENT(IN) :: SimMsg ! a message describing the location of the error + + IF ( ErrID /= ErrID_None ) THEN + CALL WrScr( NewLine//TRIM(Msg)//NewLine ) + + IF ( ErrID >= AbortErrLev ) THEN + CALL ExitThisProgram_T( Turbine, ErrID, .true., SimMsg ) + END IF + + END IF + + END SUBROUTINE CheckError +END SUBROUTINE FAST_RunSteadyStateDriver +!---------------------------------------------------------------------------------------------------------------------------------- + +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +! INITIALIZATION ROUTINES +!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +SUBROUTINE FAST_InitializeSteadyState_T( Turbine, ErrStat, ErrMsg ) + TYPE(FAST_TurbineType), INTENT(INOUT) :: Turbine !< all data for one instance of a turbine + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + LOGICAL, PARAMETER :: CompAeroMaps = .true. + REAL(DbKi), PARAMETER :: t_initial = 0.0_DbKi + + Turbine%TurbID = 1 + + CALL FAST_InitializeAll( t_initial, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX, & + Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & + Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, CompAeroMaps, ErrStat, ErrMsg ) + +END SUBROUTINE FAST_InitializeSteadyState_T +!---------------------------------------------------------------------------------------------------------------------------------- +!> Routine that calls FAST_Solution for one instance of a Turbine data structure. This is a separate subroutine so that the FAST +!! driver programs do not need to change or operate on the individual module level. +SUBROUTINE FAST_SteadyState_T( Turbine, ErrStat, ErrMsg ) + + TYPE(FAST_TurbineType), INTENT(INOUT) :: Turbine !< all data for one instance of a turbine + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + CALL FAST_SteadyState( Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & + Turbine%ED, Turbine%BD, Turbine%AD, Turbine%MeshMapData, ErrStat, ErrMsg ) + +END SUBROUTINE FAST_SteadyState_T +!---------------------------------------------------------------------------------------------------------------------------------- +!> This routine takes data from n_t_global and gets values at n_t_global + 1 +SUBROUTINE FAST_SteadyState(p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat, ErrMsg ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: n_case !< loop counter + REAL(DbKi) :: n_global + REAL(ReKi), ALLOCATABLE :: UnusedAry(:) + REAL(R8Ki), ALLOCATABLE :: Jmat(:,:) + TYPE(FAST_SS_CaseType) :: caseData ! tsr, windSpeed, pitch, and rotor speed for this case + TYPE(FAST_SS_CaseType) :: caseData_try2 ! tsr, windSpeed, pitch, and rotor speed for this case (to try a different operating point first) + + INTEGER(IntKi) :: NStatus + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + TYPE(IceD_OutputType), ALLOCATABLE :: y_IceD (:) !< IceDyn outputs (WriteOutput values are subset) + CHARACTER(MaxWrScrLen), PARAMETER :: BlankLine = " " + + CHARACTER(*), PARAMETER :: RoutineName = 'FAST_SteadyState' + + ErrStat = ErrID_None + ErrMsg = "" + + CALL InitSSVariables(p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, JMat, ErrStat2, ErrMsg2 ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName ) + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if + + ! how often do we inform the user which case we are on? + NStatus = min( 100, p_FAST%NumSSCases/100 + 1) ! at least 100 every 100 cases or 100 times per simulation + call WrScr(NewLine) + + DO n_case = 1, p_FAST%NumSSCases + + if (mod(n_case,NStatus) == 0 .or. n_case==p_FAST%NumSSCases .or. n_case==1) then + call WrOver( ' Case '//trim(num2lstr(n_case))//' of '//trim(num2lstr(p_FAST%NumSSCases)) ) + end if + + + if (p_FAST%WindSpeedOrTSR==1) then + caseData%windSpeed = p_FAST%WS_TSR(n_case) + caseData%tsr = p_FAST%RotSpeed(n_case) * AD%p%rotors(1)%BEMT%rTipFixMax / caseData%windSpeed + else + caseData%tsr = p_FAST%WS_TSR(n_case) + caseData%windSpeed = p_FAST%RotSpeed(n_case) * AD%p%rotors(1)%BEMT%rTipFixMax / caseData%tsr + end if + caseData%pitch = p_FAST%Pitch(n_case) + caseData%RotSpeed = p_FAST%RotSpeed(n_case) + + ! Call steady-state solve for this pitch and rotor speed + call SolveSteadyState(caseData, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat2, ErrMsg2) + + if (ErrStat2 >= ErrID_Severe) then + ! we didn't converge; let's try a different operating point and see if that helps: + caseData_try2%RotSpeed = caseData%RotSpeed + caseData_try2%Pitch = caseData%Pitch * 0.5_ReKi + caseData_try2%TSR = caseData%TSR * 0.5_ReKi + caseData_try2%WindSpeed = caseData%WindSpeed * 0.5_ReKi + + call WrScr('Retrying case '//trim(num2lstr(n_case))//', first trying to get a better initial guess. Average error is '// & + trim(num2lstr(y_FAST%DriverWriteOutput(SS_Indx_Err)))//'.') + call SolveSteadyState(caseData_try2, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat2, ErrMsg2) + + ! if that worked, try the real case again: + if (ErrStat2 < AbortErrLev) then + call SolveSteadyState(caseData, Jmat, p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, ErrStat2, ErrMsg2) + call WrOver(BlankLine) + end if + + end if + + if (ErrStat2 > ErrID_None) then + ErrMsg2 = trim(ErrMsg2)//" case "//trim(num2lstr(n_case))//& + ' (tsr='//trim(num2lstr(caseData%tsr))//& + ', wind speed='//trim(num2lstr(caseData%windSpeed))//' m/s'//& + ', pitch='//trim(num2lstr(caseData%pitch*R2D))//' deg'//& + ', rotor speed='//trim(num2lstr(caseData%RotSpeed*RPS2RPM))//' rpm)' + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + end if + + !---------------------------------------------------------------------------------------- + ! Write results to file + !---------------------------------------------------------------------------------------- + n_global = real(n_case, DbKi) ! n_global is double-precision so that we can reuse existing code. + + CALL WrOutputLine( n_global, p_FAST, y_FAST, UnusedAry, UnusedAry, ED%y%WriteOutput, & + AD%y, UnusedAry, UnusedAry, UnusedAry, UnusedAry, UnusedAry, UnusedAry, & + UnusedAry, UnusedAry, UnusedAry, UnusedAry, y_IceD, BD%y, ErrStat2, ErrMsg2 ) + + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (ErrStat >= AbortErrLev) then + call Cleanup() + return + end if + + + ! in case we have a lot of error messages, let's print the non fatal ones here: + if (ErrStat > ErrID_None) then + call WrScr(trim(ErrMsg)) + call WrScr("") + ErrStat = ErrID_None + ErrMsg = "" + end if + + END DO + +CONTAINS + SUBROUTINE Cleanup() + if (allocated(Jmat)) deallocate(Jmat) + END SUBROUTINE Cleanup + + +END SUBROUTINE FAST_SteadyState +!---------------------------------------------------------------------------------------------------------------------------------- +SUBROUTINE InitSSVariables(p_FAST, y_FAST, m_FAST, ED, BD, AD, MeshMapData, JMat, ErrStat, ErrMsg ) + + TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code + TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + + TYPE(ElastoDyn_Data), INTENT(INOUT) :: ED !< ElastoDyn data + TYPE(BeamDyn_Data), INTENT(INOUT) :: BD !< BeamDyn data + TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data + + TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules + REAL(R8Ki), ALLOCATABLE , INTENT(INOUT) :: Jmat(:,:) !< Matrix for storing Jacobian + + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation + CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None + + INTEGER(IntKi) :: NumBlades !< number of blades + + + INTEGER(IntKi) :: ErrStat2 + CHARACTER(ErrMsgLen) :: ErrMSg2 + + CHARACTER(*), PARAMETER :: RoutineName = 'SS_InitVariables' + + ErrStat = ErrID_None + ErrMsg = "" + + NumBlades = size(AD%y%rotors(1)%BladeLoad) + + + call AllocAry(Jmat, p_FAST%SizeJac_Opt1(1), p_FAST%SizeJac_Opt1(1), 'Jmat', ErrStat2, ErrMsg2) + call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + CALL AllocAry( MeshMapData%Jacobian_pivot, p_FAST%SizeJac_Opt1(1), 'Pivot array for Jacobian LU decomposition', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + !CALL AllocAry( MeshMapData%HubOrient, 3, 3, NumBlades, 'Hub orientation matrix', ErrStat2, ErrMsg2 ) + ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + + if (ErrStat >= AbortErrLev) return + + + CALL CopyStatesInputs( p_FAST, ED, BD, AD, ErrStat2, ErrMsg2, MESH_NEWCOPY ) + call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName ) + + +END SUBROUTINE InitSSVariables +!---------------------------------------------------------------------------------------------------------------------------------- +END MODULE FAST_SS_Subs +!---------------------------------------------------------------------------------------------------------------------------------- diff --git a/modules/openfast-library/src/FAST_Solver.f90 b/modules/openfast-library/src/FAST_Solver.f90 index 1e28b5f285..31635cb07d 100644 --- a/modules/openfast-library/src/FAST_Solver.f90 +++ b/modules/openfast-library/src/FAST_Solver.f90 @@ -42,7 +42,7 @@ MODULE FAST_Solver USE IceFloe USE ServoDyn USE SubDyn - USE OpenFOAM + USE ExternalInflow Use ExtPtfm_MCKF @@ -375,7 +375,7 @@ SUBROUTINE ED_InputSolve( p_FAST, u_ED, y_ED, p_AD14, y_AD14, y_AD, y_SrvD, u_AD END IF END IF - IF ( p_FAST%CompAero == Module_AD .and. p_FAST%MHK > 0 .and. .not. (p_FAST%CompElast == Module_BD .and. BD_Solve_Option1)) THEN + IF ( p_FAST%CompAero == Module_AD .and. p_FAST%MHK /= MHK_None .and. .not. (p_FAST%CompElast == Module_BD .and. BD_Solve_Option1)) THEN u_ED%HubPtLoad%Force = 0.0_ReKi u_ED%HubPtLoad%Moment = 0.0_ReKi IF ( u_AD%rotors(1)%HubMotion%Committed ) THEN @@ -469,7 +469,10 @@ SUBROUTINE IfW_InputSolve( p_FAST, m_FAST, u_IfW, p_IfW, u_AD14, u_AD, OtherSt_A u_IfW%HubPosition = y_ED%HubPtMotion%Position(:,1) + y_ED%HubPtMotion%TranslationDisp(:,1) u_IfW%HubOrientation = y_ED%HubPtMotion%Orientation(:,:,1) - IF ( p_FAST%MHK==1 .or. p_FAST%MHK==2 ) THEN + + + + IF ( p_FAST%MHK /= MHK_None ) THEN u_IfW%PositionXYZ(3,:) = u_IfW%PositionXYZ(3,:) + p_FAST%WtrDpth ENDIF @@ -659,7 +662,7 @@ SUBROUTINE AD14_InputSolve_NoIfW( p_FAST, u_AD14, y_ED, MeshMapData, ErrStat, Er IF (p_FAST%CompElast == Module_ED) THEN DO K = 1,NumBl !p%NumBl ! Loop through all blades - !CALL Transfer_Line2_to_Line2( y_ED%BladeLn2Mesh(K), u_AD%InputMarkers(K), MeshMapData%BDED_L_2_AD_L_B(K), ErrStat, ErrMsg ) + !CALL Transfer_Line2_to_Line2( y_ED%BladeLn2Mesh(K), u_AD%rotors(1)%InputMarkers(K), MeshMapData%BDED_L_2_AD_L_B(K), ErrStat, ErrMsg ) ! IF (ErrStat >= AbortErrLev ) RETURN u_AD14%InputMarkers(K)%RotationVel = 0.0_ReKi ! bjj: we don't need this field @@ -744,7 +747,7 @@ SUBROUTINE AD14_InputSolve_NoIfW( p_FAST, u_AD14, y_ED, MeshMapData, ErrStat, Er IF ( u_AD14%Twr_InputMarkers%Committed ) THEN - !CALL Transfer_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%Twr_InputMarkers, MeshMapData%ED_L_2_AD_L_T, ErrStat, ErrMsg ) + !CALL Transfer_Line2_to_Line2( y_ED%TowerLn2Mesh, u_AD%rotors(1)%Twr_InputMarkers, MeshMapData%ED_L_2_AD_L_T, ErrStat, ErrMsg ) ! IF (ErrStat >= AbortErrLev ) RETURN J = u_AD14%Twr_InputMarkers%NNodes @@ -763,7 +766,7 @@ END SUBROUTINE AD14_InputSolve_NoIfW !---------------------------------------------------------------------------------------------------------------------------------- !> This routine sets the inputs required for ServoDyn -SUBROUTINE SrvD_InputSolve( p_FAST, m_FAST, u_SrvD, y_ED, y_IfW, y_OpFM, y_BD, y_SD, MeshMapData, ErrStat, ErrMsg ) +SUBROUTINE SrvD_InputSolve( p_FAST, m_FAST, u_SrvD, y_ED, y_IfW, y_ExtInfw, y_BD, y_SD, MeshMapData, ErrStat, ErrMsg ) !.................................................................................................................................. TYPE(FAST_ParameterType), INTENT(IN) :: p_FAST !< Glue-code simulation parameters @@ -771,7 +774,7 @@ SUBROUTINE SrvD_InputSolve( p_FAST, m_FAST, u_SrvD, y_ED, y_IfW, y_OpFM, y_BD, y TYPE(SrvD_InputType), INTENT(INOUT) :: u_SrvD !< ServoDyn Inputs at t TYPE(ED_OutputType),TARGET, INTENT(IN) :: y_ED !< ElastoDyn outputs TYPE(InflowWind_OutputType), INTENT(IN) :: y_IfW !< InflowWind outputs - TYPE(OpFM_OutputType), INTENT(IN) :: y_OpFM !< OpenFOAM outputs + TYPE(ExtInfw_OutputType), INTENT(IN) :: y_ExtInfw !< ExternalInflow outputs TYPE(BD_OutputType), INTENT(IN) :: y_BD(:) !< BD Outputs TYPE(SD_OutputType),TARGET, INTENT(IN) :: y_SD !< SD Outputs TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -808,10 +811,10 @@ SUBROUTINE SrvD_InputSolve( p_FAST, m_FAST, u_SrvD, y_ED, y_IfW, y_OpFM, y_BD, y if (allocated(y_IfW%lidar%MsrPositionsY)) u_SrvD%MsrPositionsY = y_IfW%lidar%MsrPositionsY if (allocated(y_IfW%lidar%MsrPositionsZ)) u_SrvD%MsrPositionsZ = y_IfW%lidar%MsrPositionsZ - ELSEIF ( p_FAST%CompInflow == Module_OpFM ) THEN + ELSEIF ( p_FAST%CompInflow == Module_ExtInfw ) THEN - u_SrvD%WindDir = ATAN2( y_OpFM%v(1), y_OpFM%u(1) ) - u_SrvD%HorWindV = SQRT( y_OpFM%u(1)**2 + y_OpFM%v(1)**2 ) + u_SrvD%WindDir = ATAN2( y_ExtInfw%v(1), y_ExtInfw%u(1) ) + u_SrvD%HorWindV = SQRT( y_ExtInfw%u(1)**2 + y_ExtInfw%v(1)**2 ) if (allocated(u_SrvD%LidSpeed )) u_SrvD%LidSpeed = 0.0 if (allocated(u_SrvD%MsrPositionsX)) u_SrvD%MsrPositionsX = 0.0 if (allocated(u_SrvD%MsrPositionsY)) u_SrvD%MsrPositionsY = 0.0 @@ -1002,7 +1005,7 @@ SUBROUTINE SrvD_SetExternalInputs( p_FAST, m_FAST, u_SrvD ) u_SrvD%ExternalYawRateCom = m_FAST%ExternInput%YawRateCom u_SrvD%ExternalHSSBrFrac = m_FAST%ExternInput%HSSBrFrac - if (ALLOCATED(u_SrvD%ExternalBlPitchCom)) then !there should be no reason this isn't allocated, but OpenFOAM is acting strange... + if (ALLOCATED(u_SrvD%ExternalBlPitchCom)) then !there should be no reason this isn't allocated, but ExternalInflow is acting strange... do i=1,SIZE(u_SrvD%ExternalBlPitchCom) u_SrvD%ExternalBlPitchCom(i) = m_FAST%ExternInput%BlPitchCom(i) end do @@ -1379,7 +1382,7 @@ END FUNCTION GetPerturb !---------------------------------------------------------------------------------------------------------------------------------- !> This routine performs the Input-Output solve for ED and HD. !! Note that this has been customized for the physics in the problems and is not a general solution. -!! This is only called is there is no substructure model (RIGID substructure) +!! This is only called if there is no substructure model (RIGID substructure) SUBROUTINE ED_HD_InputOutputSolve( this_time, p_FAST, calcJacobian & , u_ED, p_ED, x_ED, xd_ED, z_ED, OtherSt_ED, y_ED, m_ED & , u_HD, p_HD, x_HD, xd_HD, z_HD, OtherSt_HD, y_HD, m_HD & @@ -2796,7 +2799,7 @@ SUBROUTINE U_FullOpt1_Residual( y_ED2, y_SD2, y_HD2, y_BD2, y_Orca2, y_ExtPtfm2, MeshMapData%u_ED_HubPtLoad%Force = MeshMapData%u_ED_HubPtLoad%Force + MeshMapData%u_ED_HubPtLoad_2%Force MeshMapData%u_ED_HubPtLoad%Moment = MeshMapData%u_ED_HubPtLoad%Moment + MeshMapData%u_ED_HubPtLoad_2%Moment end do - IF ( p_FAST%CompAero == Module_AD .and. p_FAST%MHK > 0) THEN + IF ( p_FAST%CompAero == Module_AD .and. p_FAST%MHK /= MHK_None) THEN IF ( u_AD%rotors(1)%HubMotion%Committed ) THEN CALL Transfer_Point_to_Point( y_AD%rotors(1)%HubLoad, MeshMapData%u_ED_HubPtLoad_2, MeshMapData%AD_P_2_ED_P_H, ErrStat2, ErrMsg2, u_AD%rotors(1)%HubMotion, y_ED2%HubPtMotion ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -4533,14 +4536,16 @@ SUBROUTINE InitModuleMappings(p_FAST, ED, BD, AD14, AD, HD, SD, ExtPtfm, SrvD, M !............................................................................................................................ ! Initialize the Jacobian structures: !............................................................................................................................ - IF ( p_FAST%SolveOption == Solve_FullOpt1 ) THEN - CALL Init_FullOpt1_Jacobian( p_FAST, MeshMapData, ED%Input(1)%PlatformPtMesh, SD%Input(1)%TPMesh, SD%Input(1)%LMesh, & - HD%Input(1)%Morison%Mesh, HD%Input(1)%WAMITMesh, & - ED%Input(1)%HubPtLoad, BD%Input(1,:), Orca%Input(1)%PtfmMesh, ExtPtfm%Input(1)%PtfmMesh, ErrStat2, ErrMsg2) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ELSEIF ( p_FAST%SolveOption == Solve_SimplifiedOpt1 ) THEN - CALL AllocAry( MeshMapData%Jacobian_Opt1, SizeJac_ED_HD, SizeJac_ED_HD, 'Jacobian for Ptfm-HD coupling', ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (.not. p_FAST%CompAeroMaps) THEN + IF ( p_FAST%SolveOption == Solve_FullOpt1 ) THEN + CALL Init_FullOpt1_Jacobian( p_FAST, MeshMapData, ED%Input(1)%PlatformPtMesh, SD%Input(1)%TPMesh, SD%Input(1)%LMesh, & + HD%Input(1)%Morison%Mesh, HD%Input(1)%WAMITMesh, & + ED%Input(1)%HubPtLoad, BD%Input(1,:), Orca%Input(1)%PtfmMesh, ExtPtfm%Input(1)%PtfmMesh, ErrStat2, ErrMsg2) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ELSEIF ( p_FAST%SolveOption == Solve_SimplifiedOpt1 ) THEN + CALL AllocAry( MeshMapData%Jacobian_Opt1, SizeJac_ED_HD, SizeJac_ED_HD, 'Jacobian for Ptfm-HD coupling', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + ENDIF END IF IF ( ALLOCATED( MeshMapData%Jacobian_Opt1 ) ) THEN @@ -4559,7 +4564,7 @@ SUBROUTINE InitModuleMappings(p_FAST, ED, BD, AD14, AD, HD, SD, ExtPtfm, SrvD, M ! initialize the temporary input meshes (for input-output solves in Solve Option 1): ! (note that we do this after ResetRemapFlags() so that the copies have remap=false) !............................................................................................................................ - IF ( p_FAST%SolveOption /= Solve_FullOpt2 ) THEN + IF ( p_FAST%SolveOption /= Solve_FullOpt2 .and. .not. p_FAST%CompAeroMaps) THEN ! Temporary meshes for transfering inputs to ED, HD, BD, Orca, and SD CALL MeshCopy ( ED%Input(1)%HubPtLoad, MeshMapData%u_ED_HubPtLoad, MESH_NEWCOPY, ErrStat2, ErrMsg2 ) @@ -4662,7 +4667,7 @@ END SUBROUTINE InitModuleMappings !! *** Note that modules that do not have direct feedthrough should be called first. *** SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, calcJacobian, NextJacCalcTime, & p_FAST, m_FAST, WriteThisStep, ED, BD, & - SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg ) + SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg ) REAL(DbKi) , intent(in ) :: this_time !< The current simulation time (actual or time of prediction) INTEGER(IntKi) , intent(in ) :: this_state !< Index into the state array (current or predicted states) INTEGER(IntKi) , intent(in ) :: n_t_global !< current time step (used only for SrvD hack) @@ -4679,7 +4684,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm data @@ -4739,7 +4744,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca !> Solve option 2 (modules without direct feedthrough): - CALL SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, n_t_global < 0, WriteThisStep) + CALL SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, n_t_global < 0, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) #ifdef OUTPUT_MASS_MATRIX @@ -4778,7 +4783,7 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca CALL AD14_InputSolve_NoIfW( p_FAST, AD14%Input(1), ED%y, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! because we're not calling InflowWind_CalcOutput or getting new values from OpenFOAM, + ! because we're not calling InflowWind_CalcOutput or getting new values from ExternalInflow, ! this probably can be skipped CALL AD14_InputSolve_IfW( p_FAST, AD14%Input(1), IfW%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -4793,17 +4798,17 @@ SUBROUTINE CalcOutputs_And_SolveForInputs( n_t_global, this_time, this_state, ca IF ( p_FAST%CompInflow == Module_IfW ) THEN CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(1), IfW%p, AD14%Input(1), AD%Input(1), AD%OtherSt(this_state), ED%y, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ELSE IF ( p_FAST%CompInflow == Module_OpFM ) THEN - ! OpenFOAM is the driver and it sets these inputs outside of this solve; the OpenFOAM inputs and outputs thus don't change - ! in this scenario until OpenFOAM takes another step **this is a source of error, but it is the way the OpenFOAM-FAST7 coupling + ELSE IF ( p_FAST%CompInflow == Module_ExtInfw ) THEN + ! ExternalInflow is the driver and it sets these inputs outside of this solve; the ExternalInflow inputs and outputs thus don't change + ! in this scenario until ExternalInflow takes another step **this is a source of error, but it is the way the ExternalInflow-FAST7 coupling ! works, so I'm not going to spend time that I don't have now to fix it** - CALL OpFM_SetInputs( p_FAST, AD%Input(1), AD%y, SrvD%y, OpFM, ErrStat2, ErrMsg2 ) + CALL ExtInfw_SetInputs( p_FAST, AD%Input(1), AD%y, SrvD%y, ExtInfw, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF IF ( p_FAST%CompServo == Module_SrvD ) THEN - CALL SrvD_InputSolve( p_FAST, m_FAST, SrvD%Input(1), ED%y, IfW%y, OpFM%y, BD%y, SD%y, MeshmapData, ErrStat2, ErrMsg2 ) + CALL SrvD_InputSolve( p_FAST, m_FAST, SrvD%Input(1), ED%y, IfW%y, ExtInfw%y, BD%y, SD%y, MeshmapData, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF @@ -5019,7 +5024,7 @@ SUBROUTINE SolveOption1(this_time, this_state, calcJacobian, p_FAST, ED, BD, HD, END SUBROUTINE SolveOption1 !---------------------------------------------------------------------------------------------------------------------------------- !> This routine implements the first part of the "option 2" solve for inputs that apply to BeamDyn and AeroDyn -SUBROUTINE SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat, ErrMsg, WriteThisStep) +SUBROUTINE SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat, ErrMsg, WriteThisStep) REAL(DbKi) , intent(in ) :: this_time !< The current simulation time (actual or time of prediction) INTEGER(IntKi) , intent(in ) :: this_state !< Index into the state array (current or predicted states) @@ -5031,7 +5036,7 @@ SUBROUTINE SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, A TYPE(ServoDyn_Data), INTENT(INOUT) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5065,7 +5070,7 @@ SUBROUTINE SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, A END SUBROUTINE SolveOption2a_Inp2BD !---------------------------------------------------------------------------------------------------------------------------------- !> This routine implements the first part of the "option 2" solve for inputs that apply to AeroDyn & InflowWind -SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat, ErrMsg, WriteThisStep) +SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat, ErrMsg, WriteThisStep) REAL(DbKi) , intent(in ) :: this_time !< The current simulation time (actual or time of prediction) INTEGER(IntKi) , intent(in ) :: this_state !< Index into the state array (current or predicted states) @@ -5078,7 +5083,7 @@ SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5129,11 +5134,11 @@ SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, ! must be done after ED_CalcOutput and before AD_CalcOutput and SrvD CALL IfW_InputSolve( p_FAST, m_FAST, IfW%Input(1), IfW%p, AD14%Input(1), AD%Input(1), AD%OtherSt(this_state), ED%y, ErrStat2, ErrMsg2 ) ! do we want this to be curr states CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - !ELSE IF ( p_FAST%CompInflow == Module_OpFM ) THEN - ! ! OpenFOAM is the driver and it computes outputs outside of this solve; the OpenFOAM inputs and outputs thus don't change - ! ! in this scenario until OpenFOAM takes another step **this is a source of error, but it is the way the OpenFOAM-FAST7 coupling + !ELSE IF ( p_FAST%CompInflow == Module_ExtInfw ) THEN + ! ! ExternalInflow is the driver and it computes outputs outside of this solve; the ExternalInflow inputs and outputs thus don't change + ! ! in this scenario until ExternalInflow takes another step **this is a source of error, but it is the way the ExternalInflow-FAST7 coupling ! ! works, so I'm not going to spend time that I don't have now to fix it** - ! CALL OpFM_SetInputs( p_FAST, AD14%p, AD14%Input(1), AD14%y, AD%Input(1), AD%y, ED%y, SrvD%y, OpFM, ErrStat2, ErrMsg2 ) + ! CALL ExtInfw_SetInputs( p_FAST, AD14%p, AD14%Input(1), AD14%y, AD%Input(1), AD%y, ED%y, SrvD%y, ExtInfw, ErrStat2, ErrMsg2 ) ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF @@ -5141,7 +5146,7 @@ SUBROUTINE SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, END SUBROUTINE SolveOption2b_Inp2IfW !---------------------------------------------------------------------------------------------------------------------------------- !> This routine implements the first part of the "option 2" solve for inputs that apply to AeroDyn and ServoDyn. -SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, OpFM, MeshMapData, ErrStat, ErrMsg, WriteThisStep) +SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat, ErrMsg, WriteThisStep) REAL(DbKi) , intent(in ) :: this_time !< The current simulation time (actual or time of prediction) INTEGER(IntKi) , intent(in ) :: this_state !< Index into the state array (current or predicted states) @@ -5155,7 +5160,7 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5187,17 +5192,16 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, IfW%OtherSt(this_state), IfW%y, IfW%m, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ELSE IF ( p_FAST%CompInflow == Module_OpFM ) THEN - ! OpenFOAM is the driver and it computes outputs outside of this solve; the OpenFOAM inputs and outputs thus don't change - ! in this scenario until OpenFOAM takes another step **this is a source of error, but it is the way the OpenFOAM-FAST7 coupling + ELSE IF ( p_FAST%CompInflow == Module_ExtInfw ) THEN + ! ExternalInflow is the driver and it computes outputs outside of this solve; the ExternalInflow inputs and outputs thus don't change + ! in this scenario until ExternalInflow takes another step **this is a source of error, but it is the way the OpenFOAM-FAST7 coupling ! works, so I'm not going to spend time that I don't have now to fix it** - ! The outputs from OpenFOAM need to be transfered to the FlowField for use by AeroDyn, this seems like the right place - call OpFM_UpdateFlowField(p_FAST, OpFM, ErrStat2, ErrMsg2) + ! The outputs from ExternalInflow need to be transfered to the FlowField for use by AeroDyn, this seems like the right place + call ExtInfw_UpdateFlowField(p_FAST, ExtInfw, ErrStat2, ErrMsg2) call SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! CALL OpFM_SetInputs( p_FAST, AD%Input(1), AD%y, ED%y, SrvD%y, OpFM, ErrStat2, ErrMsg2 ) + ! CALL ExtInfw_SetInputs( p_FAST, AD%Input(1), AD%y, ED%y, SrvD%y, ExtInfw, ErrStat2, ErrMsg2 ) ! CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - ! CALL OpFM_SetWriteOutput(OpFM) - + ! CALL ExtInfw_SetWriteOutput(OpFM) END IF IF ( p_FAST%CompAero == Module_AD14 ) THEN @@ -5210,7 +5214,7 @@ SUBROUTINE SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, IF ( p_FAST%CompServo == Module_SrvD ) THEN - CALL SrvD_InputSolve( p_FAST, m_FAST, SrvD%Input(1), ED%y, IfW%y, OpFM%y, BD%y, SD%y, MeshMapData, ErrStat2, ErrMsg2 ) + CALL SrvD_InputSolve( p_FAST, m_FAST, SrvD%Input(1), ED%y, IfW%y, ExtInfw%y, BD%y, SD%y, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) END IF @@ -5219,7 +5223,7 @@ END SUBROUTINE SolveOption2c_Inp2AD_SrvD !---------------------------------------------------------------------------------------------------------------------------------- !> This routine implements the "option 2" solve for all inputs without direct links to HD, SD, MAP, or the ED platform reference !! point. -SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, OpFM, MeshMapData, ErrStat, ErrMsg, firstCall, WriteThisStep) +SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat, ErrMsg, firstCall, WriteThisStep) !............................................................................................................................... LOGICAL , intent(in ) :: firstCall !< flag to determine how to call ServoDyn (a hack) REAL(DbKi) , intent(in ) :: this_time !< The current simulation time (actual or time of prediction) @@ -5235,7 +5239,7 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules @@ -5261,13 +5265,13 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, ! SolveOption2* routines are being called in FAST_AdvanceStates, but the first time we call CalcOutputs_And_SolveForInputs, we haven't called the AdvanceStates routine IF (firstCall) THEN ! call ElastoDyn's CalcOutput & compute BD inputs from ED: - CALL SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2a_Inp2BD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! compute AD position inputs; compute all of IfW inputs from ED/BD outputs: - CALL SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2b_Inp2IfW(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! call IfW's CalcOutput; transfer wind-inflow inputs to AD; compute all of SrvD inputs: - CALL SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2c_Inp2AD_SrvD(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! ELSE ! these subroutines are called in the AdvanceStates routine before BD, IfW, AD, and SrvD states are updated. This gives a more accurate solution that would otherwise require a correction step. END IF @@ -5295,14 +5299,14 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, END IF - IF ( p_FAST%CompInflow == Module_OpFM ) THEN - ! OpenFOAM is the driver and it computes outputs outside of this solve; the OpenFOAM inputs and outputs thus don't change - ! in this scenario until OpenFOAM takes another step **this is a source of error, but it is the way the OpenFOAM-FAST7 coupling + IF ( p_FAST%CompInflow == Module_ExtInfw ) THEN + ! ExternalInflow is the driver and it computes outputs outside of this solve; the ExternalInflow inputs and outputs thus don't change + ! in this scenario until ExternalInflow takes another step **this is a source of error, but it is the way the ExternalInflow-FAST7 coupling ! works, so I'm not going to spend time that I don't have now to fix it** - ! note that I'm setting these inputs AFTER the call to ServoDyn so OpenFOAM gets all the inputs updated at the same step - CALL OpFM_SetInputs( p_FAST, AD%Input(1), AD%y, SrvD%y, OpFM, ErrStat2, ErrMsg2 ) + ! note that I'm setting these inputs AFTER the call to ServoDyn so ExternalInflow gets all the inputs updated at the same step + CALL ExtInfw_SetInputs( p_FAST, AD%Input(1), AD%y, SrvD%y, ExtInfw, ErrStat2, ErrMsg2 ) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) - CALL OpFM_SetWriteOutput(OpFM) + CALL ExtInfw_SetWriteOutput(ExtInfw) END IF @@ -5317,7 +5321,7 @@ SUBROUTINE SolveOption2(this_time, this_state, p_FAST, m_FAST, ED, BD, AD14, AD, END SUBROUTINE SolveOption2 !---------------------------------------------------------------------------------------------------------------------------------- !> This routines advances the states of each module -SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, & +SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg, WriteThisStep ) REAL(DbKi), INTENT(IN ) :: t_initial !< initial simulation time (almost always 0) @@ -5331,7 +5335,7 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn v14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm data @@ -5394,7 +5398,7 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr ! BeamDyn doesn't like extrapolated rotations, so we will calculate them from ED and transfer instead of doing a correction step. ! (Also calls ED_CalcOutput here so that we can use it for AeroDyn optimization, too): - CALL SolveOption2a_Inp2BD(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2a_Inp2BD(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF ( p_FAST%CompElast == Module_BD ) THEN @@ -5426,7 +5430,7 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr ! because AeroDyn DBEMT states depend heavily on getting inputs correct, we are overwriting its inputs with updated structural outputs here - CALL SolveOption2b_Inp2IfW(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2b_Inp2IfW(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD14, AD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -5453,7 +5457,7 @@ SUBROUTINE FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, Sr ! because AeroDyn DBEMT states depend heavily on getting inputs correct, we are overwriting its inputs with updated inflow outputs here - CALL SolveOption2c_Inp2AD_SrvD(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, OpFM, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) + CALL SolveOption2c_Inp2AD_SrvD(t_global_next, STATE_PRED, p_FAST, m_FAST, ED, BD, AD14, AD, SD, SrvD, IfW, ExtInfw, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! AeroDyn: get predicted states diff --git a/modules/openfast-library/src/FAST_Subs.f90 b/modules/openfast-library/src/FAST_Subs.f90 index 837d3e0ab7..76b383989a 100644 --- a/modules/openfast-library/src/FAST_Subs.f90 +++ b/modules/openfast-library/src/FAST_Subs.f90 @@ -27,7 +27,7 @@ MODULE FAST_Subs USE VersionInfo IMPLICIT NONE - + CONTAINS !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! INITIALIZATION ROUTINES @@ -42,35 +42,36 @@ SUBROUTINE FAST_InitializeAll_T( t_initial, TurbID, Turbine, ErrStat, ErrMsg, In CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None CHARACTER(*), OPTIONAL,INTENT(IN ) :: InFile !< A CHARACTER string containing the name of the primary FAST input file (if not present, we'll get it from the command line) TYPE(FAST_ExternInitType),OPTIONAL,INTENT(IN ) :: ExternInitData !< Initialization input data from an external source (Simulink) - + + LOGICAL, PARAMETER :: CompAeroMaps = .false. Turbine%TurbID = TurbID - - + + IF (PRESENT(InFile)) THEN IF (PRESENT(ExternInitData)) THEN CALL FAST_InitializeAll( t_initial, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%SC_DX,& + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX,& Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & - Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg, InFile, ExternInitData ) + Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, CompAeroMaps, ErrStat, ErrMsg, InFile, ExternInitData ) ELSE CALL FAST_InitializeAll( t_initial, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%SC_DX, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX, & Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & - Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg, InFile ) + Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, CompAeroMaps, ErrStat, ErrMsg, InFile ) END IF ELSE CALL FAST_InitializeAll( t_initial, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%SC_DX, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX, & Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & - Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg ) + Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, CompAeroMaps, ErrStat, ErrMsg ) END IF END SUBROUTINE FAST_InitializeAll_T !---------------------------------------------------------------------------------------------------------------------------------- !> Routine to call Init routine for each module. This routine sets all of the init input data for each module. -SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SC_DX, SeaSt, HD, SD, ExtPtfm, & - MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg, InFile, ExternInitData ) +SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SC_DX, SeaSt, HD, SD, ExtPtfm, & + MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, CompAeroMaps, ErrStat, ErrMsg, InFile, ExternInitData ) use ElastoDyn_Parameters, only: Method_RK4 @@ -85,7 +86,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SCDataEx_Data), INTENT(INOUT) :: SC_DX !< SuperController exchange data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data @@ -100,7 +101,8 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, TYPE(IceDyn_Data), INTENT(INOUT) :: IceD !< All the IceDyn data used in time-step loop TYPE(FAST_ModuleMapType), INTENT(INOUT) :: MeshMapData !< Data for mapping between modules - + LOGICAL, INTENT(IN ) :: CompAeroMaps !< Determines if simplifications are made to produce aero maps (not time-marching) + INTEGER(IntKi), INTENT( OUT) :: ErrStat !< Error status of the operation CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None CHARACTER(*), OPTIONAL, INTENT(IN ) :: InFile !< A CHARACTER string containing the name of the primary FAST input file (if not present, we'll get it from the command line) @@ -112,16 +114,17 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, TYPE(FAST_InitData) :: Init !< Initialization data for all modules - REAL(ReKi) :: AirDens ! air density for initialization/normalization of OpenFOAM data + REAL(ReKi) :: AirDens ! air density for initialization/normalization of ExternalInflow data REAL(DbKi) :: dt_IceD ! tmp dt variable to ensure IceDyn doesn't specify different dt values for different legs (IceDyn instances) REAL(DbKi) :: dt_BD ! tmp dt variable to ensure BeamDyn doesn't specify different dt values for different instances INTEGER(IntKi) :: ErrStat2 INTEGER(IntKi) :: IceDim ! dimension we're pre-allocating for number of IceDyn legs/instances INTEGER(IntKi) :: I ! generic loop counter INTEGER(IntKi) :: k ! blade loop counter - INTEGER(IntKi) :: nNodes ! temp var for OpFM coupling + INTEGER(IntKi) :: nNodes ! temp var for ExtInfw coupling logical :: CallStart + REAL(R8Ki) :: theta(3) ! angles for hub orientation matrix for aeromaps INTEGER(IntKi) :: NumBl @@ -133,6 +136,8 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, !.......... ErrStat = ErrID_None ErrMsg = "" + + p_FAST%CompAeroMaps = CompAeroMaps y_FAST%UnSum = -1 ! set the summary file unit to -1 to indicate it's not open y_FAST%UnOu = -1 ! set the text output file unit to -1 to indicate it's not open @@ -172,7 +177,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, if (CallStart) then AbortErrLev = ErrID_Fatal ! Until we read otherwise from the FAST input file, we abort only on FATAL errors CALL FAST_ProgStart( FAST_Ver ) - p_FAST%WrSttsTime = .TRUE. + p_FAST%WrSttsTime = .not. p_FAST%CompAeroMaps !.TRUE. else ! if we don't call the start data (e.g., from FAST.Farm), we won't override AbortErrLev either CALL DispNVD( FAST_Ver ) @@ -236,60 +241,56 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, RETURN END IF - Init%InData_ED%Linearize = p_FAST%Linearize - Init%InData_ED%InputFile = p_FAST%EDFile - IF ( p_FAST%CompAero == Module_AD14 ) THEN - Init%InData_ED%ADInputFile = p_FAST%AeroFile - ELSE - Init%InData_ED%ADInputFile = "" - END IF + Init%InData_ED%Linearize = p_FAST%Linearize + Init%InData_ED%CompAeroMaps = p_FAST%CompAeroMaps + Init%InData_ED%RotSpeed = p_FAST%RotSpeedInit + Init%InData_ED%InputFile = p_FAST%EDFile + IF ( p_FAST%CompAero == Module_AD14 ) THEN + Init%InData_ED%ADInputFile = p_FAST%AeroFile + ELSE + Init%InData_ED%ADInputFile = "" + END IF - Init%InData_ED%RootName = TRIM(p_FAST%OutFileRoot)//'.'//TRIM(y_FAST%Module_Abrev(Module_ED)) - Init%InData_ED%CompElast = p_FAST%CompElast == Module_ED + Init%InData_ED%RootName = TRIM(p_FAST%OutFileRoot)//'.'//TRIM(y_FAST%Module_Abrev(Module_ED)) + Init%InData_ED%CompElast = p_FAST%CompElast == Module_ED Init%InData_ED%Gravity = p_FAST%Gravity Init%InData_ED%MHK = p_FAST%MHK Init%InData_ED%WtrDpth = p_FAST%WtrDpth - CALL ED_Init( Init%InData_ED, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & + CALL ED_Init( Init%InData_ED, ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & ED%y, ED%m, p_FAST%dt_module( MODULE_ED ), Init%OutData_ED, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - - p_FAST%ModuleInitialized(Module_ED) = .TRUE. - CALL SetModuleSubstepTime(Module_ED, p_FAST, y_FAST, ErrStat2, ErrMsg2) - CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! bjj: added this check per jmj; perhaps it would be better in ElastoDyn, but I'll leave it here for now: - IF ( p_FAST%TurbineType == Type_Offshore_Floating ) THEN - IF ( ED%p%TowerBsHt < 0.0_ReKi .AND. .NOT. EqualRealNos( ED%p%TowerBsHt, 0.0_ReKi ) ) THEN - CALL SetErrStat(ErrID_Fatal,"ElastoDyn TowerBsHt must not be negative for floating offshore systems.",ErrStat,ErrMsg,RoutineName) - END IF - END IF + p_FAST%ModuleInitialized(Module_ED) = .TRUE. + CALL SetModuleSubstepTime(Module_ED, p_FAST, y_FAST, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - allocate( y_FAST%Lin%Modules(MODULE_ED)%Instance(1), stat=ErrStat2) - if (ErrStat2 /= 0 ) then - call SetErrStat(ErrID_Fatal, "Error allocating Lin%Modules(ED).", ErrStat, ErrMsg, RoutineName ) - else + allocate( y_FAST%Lin%Modules(MODULE_ED)%Instance(1), stat=ErrStat2) + if (ErrStat2 /= 0 ) then + call SetErrStat(ErrID_Fatal, "Error allocating Lin%Modules(ED).", ErrStat, ErrMsg, RoutineName ) + else - if (allocated(Init%OutData_ED%LinNames_y)) call move_alloc(Init%OutData_ED%LinNames_y,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_y) - if (allocated(Init%OutData_ED%LinNames_x)) call move_alloc(Init%OutData_ED%LinNames_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_x) - if (allocated(Init%OutData_ED%LinNames_u)) call move_alloc(Init%OutData_ED%LinNames_u,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_u) - if (allocated(Init%OutData_ED%RotFrame_y)) call move_alloc(Init%OutData_ED%RotFrame_y,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_y) - if (allocated(Init%OutData_ED%RotFrame_x)) call move_alloc(Init%OutData_ED%RotFrame_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_x) - if (allocated(Init%OutData_ED%DerivOrder_x)) call move_alloc(Init%OutData_ED%DerivOrder_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%DerivOrder_x) - if (allocated(Init%OutData_ED%RotFrame_u)) call move_alloc(Init%OutData_ED%RotFrame_u,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_u) - if (allocated(Init%OutData_ED%IsLoad_u )) call move_alloc(Init%OutData_ED%IsLoad_u ,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%IsLoad_u ) + if (allocated(Init%OutData_ED%LinNames_y)) call move_alloc(Init%OutData_ED%LinNames_y,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_y) + if (allocated(Init%OutData_ED%LinNames_x)) call move_alloc(Init%OutData_ED%LinNames_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_x) + if (allocated(Init%OutData_ED%LinNames_u)) call move_alloc(Init%OutData_ED%LinNames_u,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%Names_u) + if (allocated(Init%OutData_ED%RotFrame_y)) call move_alloc(Init%OutData_ED%RotFrame_y,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_y) + if (allocated(Init%OutData_ED%RotFrame_x)) call move_alloc(Init%OutData_ED%RotFrame_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_x) + if (allocated(Init%OutData_ED%DerivOrder_x)) call move_alloc(Init%OutData_ED%DerivOrder_x,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%DerivOrder_x) + if (allocated(Init%OutData_ED%RotFrame_u)) call move_alloc(Init%OutData_ED%RotFrame_u,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%RotFrame_u) + if (allocated(Init%OutData_ED%IsLoad_u )) call move_alloc(Init%OutData_ED%IsLoad_u ,y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%IsLoad_u ) - if (allocated(Init%OutData_ED%WriteOutputHdr)) y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%NumOutputs = size(Init%OutData_ED%WriteOutputHdr) - end if + if (allocated(Init%OutData_ED%WriteOutputHdr)) y_FAST%Lin%Modules(MODULE_ED)%Instance(1)%NumOutputs = size(Init%OutData_ED%WriteOutputHdr) + end if - IF (ErrStat >= AbortErrLev) THEN - CALL Cleanup() - RETURN - END IF + IF (ErrStat >= AbortErrLev) THEN + CALL Cleanup() + RETURN + END IF - NumBl = Init%OutData_ED%NumBl + NumBl = Init%OutData_ED%NumBl + p_FAST%GearBox_index = Init%OutData_ED%GearBox_index if (p_FAST%CalcSteady) then @@ -307,7 +308,11 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! initialize BeamDyn ! ........................ IF ( p_FAST%CompElast == Module_BD ) THEN - p_FAST%nBeams = Init%OutData_ED%NumBl ! initialize number of BeamDyn instances = number of blades + IF (p_FAST%CompAeroMaps) then + p_FAST%nBeams = 1 ! initialize number of BeamDyn instances = 1 blade for aero maps + ELSE + p_FAST%nBeams = Init%OutData_ED%NumBl ! initialize number of BeamDyn instances = number of blades + END IF ELSE p_FAST%nBeams = 0 END IF @@ -340,6 +345,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_BD%DynamicSolve = .TRUE. ! FAST can only couple to BeamDyn when dynamic solve is used. Init%InData_BD%Linearize = p_FAST%Linearize + Init%InData_BD%CompAeroMaps = p_FAST%CompAeroMaps Init%InData_BD%gravity = (/ 0.0_ReKi, 0.0_ReKi, -p_FAST%Gravity /) ! "Gravitational acceleration" m/s^2 ! now initialize BeamDyn for all beams @@ -366,6 +372,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_BD%GlbPos = ED%y%BladeRootMotion(k)%Position(:,1) ! {:} - - "Initial Position Vector of the local blade coordinate system" Init%InData_BD%GlbRot = ED%y%BladeRootMotion(k)%RefOrientation(:,:,1) ! {:}{:} - - "Initial direction cosine matrix of the local blade coordinate system" + ! These outputs are set in ElastoDyn only when BeamDyn is used: Init%InData_BD%RootDisp = ED%y%BladeRootMotion(k)%TranslationDisp(:,1) ! {:} - - "Initial root displacement" Init%InData_BD%RootOri = ED%y%BladeRootMotion(k)%Orientation(:,:,1) ! {:}{:} - - "Initial root orientation" Init%InData_BD%RootVel(1:3) = ED%y%BladeRootMotion(k)%TranslationVel(:,1) ! {:} - - "Initial root velocities and angular veolcities" @@ -386,8 +393,9 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, CALL SetErrStat(ErrID_Fatal,"All instances of BeamDyn (one per blade) must have the same time step.",ErrStat,ErrMsg,RoutineName) END IF - ! We're going to do fewer computations if the BD input and output meshes that couple to AD are siblings: + ! We're going to do fewer computations if the BD input and output meshes that couple to AD are siblings (but it needs to be true for all instances): if (BD%p(k)%BldMotionNodeLoc /= BD_MESH_QP) p_FAST%BD_OutputSibling = .false. + if (p_FAST%CompAeroMaps .and. BD%p(k)%BldMotionNodeLoc /= BD_MESH_FE) call SetErrStat(ErrID_Fatal, "BeamDyn aero maps must have outputs at FE nodes.", ErrStat, ErrMsg, RoutineName ) if (ErrStat>=AbortErrLev) exit !exit this loop so we don't get p_FAST%nBeams of the same errors @@ -446,12 +454,6 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, CALL SetModuleSubstepTime(Module_AD14, p_FAST, y_FAST, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - ! bjj: this really shouldn't be in the FAST glue code, but I'm going to put this check here so people don't use an invalid model - ! and send me emails to debug numerical issues in their results. - IF ( AD14%p%TwrProps%PJM_Version .AND. p_FAST%TurbineType == Type_Offshore_Floating ) THEN - CALL SetErrStat(ErrID_Fatal,'AeroDyn v14 tower influence model "NEWTOWER" is invalid for models of floating offshore turbines.',ErrStat,ErrMsg,RoutineName) - END IF - AirDens = Init%OutData_AD14%AirDens IF (ErrStat >= AbortErrLev) THEN @@ -469,24 +471,43 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, end if Init%InData_AD%rotors(1)%NumBlades = NumBl - + + if (p_FAST%CompAeroMaps) then + CALL AllocAry( MeshMapData%HubOrient, 3, 3, Init%InData_AD%rotors(1)%NumBlades, 'Hub orientation matrix', ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (ErrStat >= AbortErrLev) THEN + CALL Cleanup() + RETURN + END IF + + theta = 0.0_R8Ki + do k=1,Init%InData_AD%rotors(1)%NumBlades + theta(1) = TwoPi_R8 * (k-1) / Init%InData_AD%rotors(1)%NumBlades + MeshMapData%HubOrient(:,:,k) = EulerConstruct( theta ) + end do + end if + + ! set initialization data for AD - CALL AllocAry( Init%InData_AD%rotors(1)%BladeRootPosition, 3, Init%InData_AD%rotors(1)%NumBlades, 'Init%InData_AD%BladeRootPosition', errStat2, ErrMsg2) + CALL AllocAry( Init%InData_AD%rotors(1)%BladeRootPosition, 3, Init%InData_AD%rotors(1)%NumBlades, 'Init%InData_AD%rotors(1)%BladeRootPosition', errStat2, ErrMsg2) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - CALL AllocAry( Init%InData_AD%rotors(1)%BladeRootOrientation,3, 3, Init%InData_AD%rotors(1)%NumBlades, 'Init%InData_AD%BladeRootOrientation', errStat2, ErrMsg2) + CALL AllocAry( Init%InData_AD%rotors(1)%BladeRootOrientation,3, 3, Init%InData_AD%rotors(1)%NumBlades, 'Init%InData_AD%rotors(1)%BladeRootOrientation', errStat2, ErrMsg2) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) IF (ErrStat >= AbortErrLev) THEN CALL Cleanup() RETURN END IF + Init%InData_AD%Gravity = p_FAST%Gravity Init%InData_AD%Linearize = p_FAST%Linearize + Init%InData_AD%CompAeroMaps = p_FAST%CompAeroMaps + Init%InData_AD%rotors(1)%RotSpeed = p_FAST%RotSpeedInit ! used only for aeromaps Init%InData_AD%InputFile = p_FAST%AeroFile Init%InData_AD%RootName = p_FAST%OutFileRoot Init%InData_AD%MHK = p_FAST%MHK - if ( p_FAST%MHK == 0 ) then + if ( p_FAST%MHK == MHK_None ) then Init%InData_AD%defFldDens = p_FAST%AirDens - elseif ( p_FAST%MHK == 1 .or. p_FAST%MHK == 2 ) then + else Init%InData_AD%defFldDens = p_FAST%WtrDens end if Init%InData_AD%defKinVisc = p_FAST%KinVisc @@ -562,7 +583,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%InData_IfW%RootName = TRIM(p_FAST%OutFileRoot)//'.'//TRIM(y_FAST%Module_Abrev(Module_IfW)) Init%InData_IfW%UseInputFile = .TRUE. Init%InData_IfW%FixedWindFileRootName = .FALSE. - Init%InData_IfW%OutputAccel = p_FAST%MHK > 0 + Init%InData_IfW%OutputAccel = p_FAST%MHK /= MHK_None Init%InData_IfW%MHK = p_FAST%MHK Init%InData_IfW%WtrDpth = p_FAST%WtrDpth @@ -666,39 +687,39 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, END IF - ELSEIF ( p_FAST%CompInflow == Module_OpFM ) THEN + ELSEIF ( p_FAST%CompInflow == Module_ExtInfw ) THEN IF ( PRESENT(ExternInitData) ) THEN - Init%InData_OpFM%NumActForcePtsBlade = ExternInitData%NumActForcePtsBlade - Init%InData_OpFM%NumActForcePtsTower = ExternInitData%NumActForcePtsTower + Init%InData_ExtInfw%NumActForcePtsBlade = ExternInitData%NumActForcePtsBlade + Init%InData_ExtInfw%NumActForcePtsTower = ExternInitData%NumActForcePtsTower ELSE - CALL SetErrStat( ErrID_Fatal, 'OpenFOAM integration can be used only with external input data (not the stand-alone executable).', ErrStat, ErrMsg, RoutineName ) + CALL SetErrStat( ErrID_Fatal, 'ExternalInflow integration can be used only with external input data (not the stand-alone executable).', ErrStat, ErrMsg, RoutineName ) CALL Cleanup() RETURN END IF ! get blade and tower info from AD. Assumption made that all blades have same spanwise characteristics - Init%InData_OpFM%BladeLength = Init%OutData_AD%rotors(1)%BladeProps(1)%BlSpn(Init%OutData_AD%rotors(1)%BladeProps(1)%NumBlNds) + Init%InData_ExtInfw%BladeLength = Init%OutData_AD%rotors(1)%BladeProps(1)%BlSpn(Init%OutData_AD%rotors(1)%BladeProps(1)%NumBlNds) if (allocated(Init%OutData_AD%rotors(1)%TwrElev)) then - Init%InData_OpFM%TowerHeight = Init%OutData_AD%rotors(1)%TwrElev(SIZE(Init%OutData_AD%rotors(1)%TwrElev)) - Init%OutData_AD%rotors(1)%TwrElev(1) ! TwrElev is based on ground or MSL. Need flexible tower length and first node - Init%InData_OpFM%TowerBaseHeight = Init%OutData_AD%rotors(1)%TwrElev(1) - ALLOCATE(Init%InData_OpFM%StructTwrHNodes( SIZE(Init%OutData_AD%rotors(1)%TwrElev)), STAT=ErrStat2) - Init%InData_OpFM%StructTwrHNodes(:) = Init%OutData_AD%rotors(1)%TwrElev(:) + Init%InData_ExtInfw%TowerHeight = Init%OutData_AD%rotors(1)%TwrElev(SIZE(Init%OutData_AD%rotors(1)%TwrElev)) - Init%OutData_AD%rotors(1)%TwrElev(1) ! TwrElev is based on ground or MSL. Need flexible tower length and first node + Init%InData_ExtInfw%TowerBaseHeight = Init%OutData_AD%rotors(1)%TwrElev(1) + ALLOCATE(Init%InData_ExtInfw%StructTwrHNodes( SIZE(Init%OutData_AD%rotors(1)%TwrElev)), STAT=ErrStat2) + Init%InData_ExtInfw%StructTwrHNodes(:) = Init%OutData_AD%rotors(1)%TwrElev(:) else - Init%InData_OpFM%TowerHeight = 0.0_ReKi - Init%InData_OpFM%TowerBaseHeight = 0.0_ReKi + Init%InData_ExtInfw%TowerHeight = 0.0_ReKi + Init%InData_ExtInfw%TowerBaseHeight = 0.0_ReKi endif - ALLOCATE(Init%InData_OpFM%StructBldRNodes(Init%OutData_AD%rotors(1)%BladeProps(1)%NumBlNds), STAT=ErrStat2) - Init%InData_OpFM%StructBldRNodes(:) = Init%OutData_AD%rotors(1)%BladeProps(1)%BlSpn(:) + ALLOCATE(Init%InData_ExtInfw%StructBldRNodes(Init%OutData_AD%rotors(1)%BladeProps(1)%NumBlNds), STAT=ErrStat2) + Init%InData_ExtInfw%StructBldRNodes(:) = Init%OutData_AD%rotors(1)%BladeProps(1)%BlSpn(:) IF (ErrStat2 /= 0) THEN - CALL SetErrStat(ErrID_Fatal,"Error allocating OpFM%InitInput.",ErrStat,ErrMsg,RoutineName) + CALL SetErrStat(ErrID_Fatal,"Error allocating ExtInfw%InitInput.",ErrStat,ErrMsg,RoutineName) CALL Cleanup() RETURN END IF !Set node clustering type - Init%InData_OpFM%NodeClusterType = ExternInitData%NodeClusterType - ! set up the data structures for integration with OpenFOAM - CALL Init_OpFM( Init%InData_OpFM, p_FAST, AirDens, AD%Input(1), Init%OutData_AD, AD%y, OpFM, Init%OutData_OpFM, ErrStat2, ErrMsg2 ) + Init%InData_ExtInfw%NodeClusterType = ExternInitData%NodeClusterType + ! set up the data structures for integration with ExternalInflow + CALL Init_ExtInfw( Init%InData_ExtInfw, p_FAST, AirDens, AD%Input(1), Init%OutData_AD, AD%y, ExtInfw, Init%OutData_ExtInfw, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) IF (ErrStat >= AbortErrLev) THEN @@ -710,7 +731,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, Init%OutData_IfW%WindFileInfo%MWS = 0.0_ReKi ! Set pointer to flowfield - IF (p_FAST%CompAero == Module_AD) AD%p%FlowField => Init%OutData_OpFM%FlowField + IF (p_FAST%CompAero == Module_AD) AD%p%FlowField => Init%OutData_ExtInfw%FlowField ELSE Init%OutData_IfW%WindFileInfo%MWS = 0.0_ReKi @@ -756,7 +777,7 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, ! ........................ - ! set some VTK parameters required before HydroDyn init (so we can get wave elevations for visualization) + ! set some VTK parameters required before SeaState init (so we can get wave elevations for visualization) ! ........................ ! get wave elevation data for visualization @@ -1474,9 +1495,9 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, END IF ! ------------------------------------------------------------------------- - ! Initialize for linearization: + ! Initialize for linearization or computing aero maps: ! ------------------------------------------------------------------------- - if ( p_FAST%Linearize ) then + if ( p_FAST%Linearize .or. p_FAST%CompAeroMaps) then ! NOTE: In the following call, we use Init%OutData_AD%BladeProps(1)%NumBlNds as the number of aero nodes on EACH blade, which ! is consistent with the current AD implementation, but if AD changes this, then it must be handled here, too! if (p_FAST%CompAero == MODULE_AD) then @@ -1485,11 +1506,19 @@ SUBROUTINE FAST_InitializeAll( t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, call Init_Lin(p_FAST, y_FAST, m_FAST, AD, ED, NumBl, -1, ErrStat2, ErrMsg2) endif call SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName) - if (ErrStat >= AbortErrLev) then call Cleanup() return end if + + if (p_FAST%CompAeroMaps) then + p_FAST%SizeJac_Opt1(1) = y_FAST%Lin%Glue%SizeLin(LIN_ContSTATE_COL) + y_FAST%Lin%Glue%SizeLin(LIN_INPUT_COL) + p_FAST%TolerSquared = p_FAST%TolerSquared * (p_FAST%SizeJac_Opt1(1)**2) ! do this calculation here so we don't have to keep dividing by the size of the array later + p_FAST%NumBl_Lin = 1 + else + p_FAST%NumBl_Lin = NumBl + end if + end if @@ -1672,9 +1701,18 @@ END SUBROUTINE FAST_InitializeAll SUBROUTINE FAST_ProgStart(ThisProgVer) TYPE(ProgDesc), INTENT(IN) :: ThisProgVer !< program name/date/version description + + TYPE(ProgDesc) :: NewProgVer !< program name/date/version description + + NewProgVer = ThisProgVer + if (LEN_TRIM(ProgName)>0) then ! add this for steady-state solver + NewProgVer%Name = ProgName + end if + + ! ... Initialize NWTC Library ! sets the pi constants, open console for output, etc... - CALL NWTC_Init( ProgNameIN=ThisProgVer%Name, EchoLibVer=.FALSE. ) + CALL NWTC_Init( ProgNameIN=NewProgVer%Name, EchoLibVer=.FALSE. ) ! Display the copyright notice and compile info: CALL DispCopyrightLicense( ThisProgVer%Name ) @@ -1692,13 +1730,14 @@ SUBROUTINE GetInputFileName(InputFile,UseDWM,ErrStat,ErrMsg) INTEGER(IntKi) :: ErrStat2 ! local error stat CHARACTER(1024) :: LastArg ! A second command-line argument that will allow DWM module to be used in AeroDyn + CHARACTER(1024) :: Flag ! Put this here in case we are calling steady-state solver (so it doesn't error out about the flag) ErrStat = ErrID_None ErrMsg = '' UseDWM = .FALSE. ! by default, we're not going to use the DWM module InputFile = "" ! initialize to empty string to make sure it's input from the command line - CALL CheckArgs( InputFile, ErrStat2, LastArg ) ! if ErrStat2 /= ErrID_None, we'll ignore and deal with the problem when we try to read the input file + CALL CheckArgs( InputFile, ErrStat2, LastArg, Flag ) ! if ErrStat2 /= ErrID_None, we'll ignore and deal with the problem when we try to read the input file IF (LEN_TRIM(InputFile) == 0) THEN ! no input file was specified ErrStat = ErrID_Fatal @@ -1789,7 +1828,7 @@ SUBROUTINE FAST_Init( p, m_FAST, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, y_FAST%Module_Ver(i)%Ver = 'unknown version' END DO y_FAST%Module_Ver( Module_IfW )%Name = 'InflowWind' - y_FAST%Module_Ver( Module_OpFM )%Name = 'OpenFOAM integration' + y_FAST%Module_Ver( Module_ExtInfw)%Name = 'ExternalInflow integration' y_FAST%Module_Ver( Module_ED )%Name = 'ElastoDyn' y_FAST%Module_Ver( Module_BD )%Name = 'BeamDyn' y_FAST%Module_Ver( Module_AD14 )%Name = 'AeroDyn14' @@ -1808,7 +1847,7 @@ SUBROUTINE FAST_Init( p, m_FAST, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, y_FAST%Module_Abrev( Module_Glue ) = 'FAST' y_FAST%Module_Abrev( Module_IfW ) = 'IfW' - y_FAST%Module_Abrev( Module_OpFM ) = 'OpFM' + y_FAST%Module_Abrev( Module_ExtInfw) = 'ExtInfw' y_FAST%Module_Abrev( Module_ED ) = 'ED' y_FAST%Module_Abrev( Module_BD ) = 'BD' y_FAST%Module_Abrev( Module_AD14 ) = 'AD' @@ -1831,8 +1870,14 @@ SUBROUTINE FAST_Init( p, m_FAST, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, !............................................................................................................................... ! Read the primary file for the glue code: !............................................................................................................................... - CALL FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrStat2, ErrMsg2 ) - CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) + IF (p%CompAeroMaps) THEN + CALL FAST_ReadSteadyStateFile( InputFile, p, m_FAST, ErrStat2, ErrMsg2 ) + ELSE + p%KMax = 1 ! after more checking, we may put this in the input file... + p%tolerSquared = 1 ! not used for time-marching simulation + CALL FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrStat2, ErrMsg2 ) + END IF + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! make sure some linearization variables are consistant if (.not. p%Linearize) p%CalcSteady = .false. @@ -1849,7 +1894,6 @@ SUBROUTINE FAST_Init( p, m_FAST, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, IF ( ErrStat >= AbortErrLev ) RETURN - p%KMax = 1 ! after more checking, we may put this in the input file... !IF (p%CompIce == Module_IceF) p%KMax = 2 p%SizeJac_Opt1 = 0 ! initialize this vector to zero; after we figure out what size the ED/SD/HD/BD meshes are, we'll fill this @@ -1857,39 +1901,22 @@ SUBROUTINE FAST_Init( p, m_FAST, y_FAST, t_initial, InputFile, ErrStat, ErrMsg, p%nBeams = 0 ! initialize number of BeamDyn instances (will be set later) - ! determine what kind of turbine we're modeling: - IF ( p%MHK == 1 ) THEN - p%TurbineType = Type_MHK_Fixed - ELSEIF ( p%MHK == 2 ) THEN - p%TurbineType = Type_MHK_Floating - ELSEIF ( p%CompHydro == Module_HD ) THEN - IF ( p%CompSub == Module_SD ) THEN - p%TurbineType = Type_Offshore_Fixed - ELSE - p%TurbineType = Type_Offshore_Floating - END IF - ELSEIF ( p%CompMooring == Module_Orca ) THEN - p%TurbineType = Type_Offshore_Floating - ELSEIF ( p%CompSub == Module_ExtPtfm ) THEN - p%TurbineType = Type_Offshore_Fixed - ELSEIF ( p%MHK == 1 ) THEN - p%TurbineType = Type_MHK_Fixed - ELSEIF ( p%MHK == 2 ) THEN - p%TurbineType = Type_MHK_Floating - ELSE - p%TurbineType = Type_LandBased - END IF - - p%n_TMax_m1 = CEILING( ( (p%TMax - t_initial) / p%DT ) ) - 1 ! We're going to go from step 0 to n_TMax (thus the -1 here) - if (p%TMax < 1.0_DbKi) then ! log10(0) gives floating point divide-by-zero error + + if (p%CompAeroMaps) then p%TChanLen = MinChanLen + p%OutFmt_t = 'F'//trim(num2lstr( p%TChanLen ))//'.0' ! 'F10.0' else - p%TChanLen = max( MinChanLen, int(log10(p%TMax))+7 ) + if (p%TMax < 1.0_DbKi) then !log10(0) is undefined (gives floating point divide-by-zero error) + p%TChanLen = MinChanLen + else + p%TChanLen = max( MinChanLen, int(log10(p%TMax))+7 ) + end if + p%OutFmt_t = 'F'//trim(num2lstr( p%TChanLen ))//'.4' ! 'F10.4' end if - p%OutFmt_t = 'F'//trim(num2lstr( p%TChanLen ))//'.4' ! 'F10.4' - + + !............................................................................................................................... ! Do some error checking on the inputs (validation): !............................................................................................................................... @@ -1943,6 +1970,14 @@ SUBROUTINE ValidateInputData(p, m_FAST, ErrStat, ErrMsg) END IF END IF + IF (p%tolerSquared < EPSILON(p%tolerSquared)) THEN + CALL SetErrStat( ErrID_Fatal, 'Toler must be larger than sqrt(epsilon).', ErrStat, ErrMsg, RoutineName ) + END IF + + IF (p%KMax < 1) THEN + CALL SetErrStat( ErrID_Fatal, 'MaxIter must be at least 1.', ErrStat, ErrMsg, RoutineName ) + END IF + ! Check that InputFileData%OutFmt is a valid format specifier and will fit over the column headings CALL ChkRealFmtStr( p%OutFmt, 'OutFmt', p%FmtWidth, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -2000,13 +2035,13 @@ SUBROUTINE ValidateInputData(p, m_FAST, ErrStat, ErrMsg) END IF IF (p%CompElast == Module_BD .and. p%CompAero == Module_AD14 ) CALL SetErrStat( ErrID_Fatal, 'AeroDyn14 cannot be used when BeamDyn is used. Change CompAero or CompElast in the FAST input file.', ErrStat, ErrMsg, RoutineName ) - if (p%CompInflow == MODULE_OpFM .and. p%CompAero == Module_AD14 ) CALL SetErrStat( ErrID_Fatal, 'AeroDyn14 cannot be used when OpenFOAM is used. Change CompAero or CompInflow in the FAST input file.', ErrStat, ErrMsg, RoutineName ) + if (p%CompInflow == MODULE_ExtInfw .and. p%CompAero == Module_AD14 ) CALL SetErrStat( ErrID_Fatal, 'AeroDyn14 cannot be used when ExternalInflow is used. Change CompAero or CompInflow in the FAST input file.', ErrStat, ErrMsg, RoutineName ) - IF (p%MHK /= 0 .and. p%MHK /= 1 .and. p%MHK /= 2) CALL SetErrStat( ErrID_Fatal, 'MHK switch is invalid. Set MHK to 0, 1, or 2 in the FAST input file.', ErrStat, ErrMsg, RoutineName ) + IF (p%MHK /= MHK_None .and. p%MHK /= MHK_FixedBottom .and. p%MHK /= MHK_Floating) CALL SetErrStat( ErrID_Fatal, 'MHK switch is invalid. Set MHK to 0, 1, or 2 in the FAST input file.', ErrStat, ErrMsg, RoutineName ) - IF (p%MHK == 1 .and. p%CompAero == Module_AD14 .or. p%MHK == 2 .and. p%CompAero == Module_AD14) CALL SetErrStat( ErrID_Fatal, 'AeroDyn14 cannot be used with an MHK turbine. Change CompAero or MHK in the FAST input file.', ErrStat, ErrMsg, RoutineName ) + IF (p%MHK /= MHK_None .and. p%CompAero == Module_AD14) CALL SetErrStat( ErrID_Fatal, 'AeroDyn14 cannot be used with an MHK turbine. Change CompAero or MHK in the FAST input file.', ErrStat, ErrMsg, RoutineName ) - IF (p%MHK == 1 .and. p%Linearize .or. p%MHK == 2 .and. p%Linearize) CALL SetErrStat( ErrID_Fatal, 'Linearization has not yet been implemented for an MHK turbine. Change MHK or Linearize in the FAST input file.', ErrStat, ErrMsg, RoutineName ) + IF (p%MHK /= MHK_None .and. p%Linearize) CALL SetErrStat( ErrID_Fatal, 'Linearization has not yet been implemented for an MHK turbine. Change MHK or Linearize in the FAST input file.', ErrStat, ErrMsg, RoutineName ) IF (p%Gravity < 0.0_ReKi) CALL SetErrStat( ErrID_Fatal, 'Gravity must not be negative.', ErrStat, ErrMsg, RoutineName ) @@ -2014,7 +2049,7 @@ SUBROUTINE ValidateInputData(p, m_FAST, ErrStat, ErrMsg) ! IF ( p%InterpOrder < 0 .OR. p%InterpOrder > 2 ) THEN IF ( p%InterpOrder < 1 .OR. p%InterpOrder > 2 ) THEN - CALL SetErrStat( ErrID_Fatal, 'InterpOrder must be 1 or 2.', ErrStat, ErrMsg, RoutineName ) ! 5/13/14 bjj: MAS and JMJ compromise for certain integrators is that InterpOrder cannot be 0 + if (.not. p%CompAeroMaps) CALL SetErrStat( ErrID_Fatal, 'InterpOrder must be 1 or 2.', ErrStat, ErrMsg, RoutineName ) ! 5/13/14 bjj: MAS and JMJ compromise for certain integrators is that InterpOrder cannot be 0 p%InterpOrder = 1 ! Avoid problems in error handling by setting this to 0 END IF @@ -2075,19 +2110,13 @@ SUBROUTINE ValidateInputData(p, m_FAST, ErrStat, ErrMsg) end if ! now, make sure we haven't asked for any modules that we can't yet linearize: - if (p%CompInflow == MODULE_OpFM) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the OpenFOAM coupling.',ErrStat, ErrMsg, RoutineName) + if (p%CompInflow == MODULE_ExtInfw) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the ExternalInflow coupling.',ErrStat, ErrMsg, RoutineName) if (p%CompAero == MODULE_AD14) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the AeroDyn v14 module.',ErrStat, ErrMsg, RoutineName) - !if (p%CompSub == MODULE_SD) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the SubDyn module.',ErrStat, ErrMsg, RoutineName) if (p%CompSub /= MODULE_None .and. p%CompSub /= MODULE_SD ) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the ExtPtfm_MCKF substructure module.',ErrStat, ErrMsg, RoutineName) if (p%CompMooring /= MODULE_None .and. p%CompMooring == MODULE_FEAM) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for the FEAMooring mooring module.',ErrStat, ErrMsg, RoutineName) if (p%CompIce /= MODULE_None) call SetErrStat(ErrID_Fatal,'Linearization is not implemented for any of the ice loading modules.',ErrStat, ErrMsg, RoutineName) end if - - - if ( (p%TurbineType == Type_Offshore_Fixed .or. p%TurbineType == Type_Offshore_Floating) .and. .not. EqualRealNos(p%TurbinePos(3), 0.0_SiKi) ) then - call SetErrStat(ErrID_Fatal, 'Height of turbine location, TurbinePos(3), must be 0 for offshore turbines.', ErrStat, ErrMsg, RoutineName) - end if !............................................................................................................................... @@ -2101,7 +2130,26 @@ SUBROUTINE ValidateInputData(p, m_FAST, ErrStat, ErrMsg) END IF END IF + if (p%CompAeroMaps) then + if (p%NumSSCases < 0) then + CALL SetErrStat( ErrID_Fatal, 'NumSSCases must be at least 1 to compute steady-state solve.', ErrStat, ErrMsg, RoutineName ) + else + do i=1,p%NumSSCases + if (p%RotSpeed(i) < 0.0_ReKi) then + CALL SetErrStat( ErrID_Fatal, 'RotSpeed must be positive for the steady-state solver.', ErrStat, ErrMsg, RoutineName ) + end if + end do + + do i=1,p%NumSSCases + if (p%WS_TSR(i) < EPSILON(p%WS_TSR(1))) then + CALL SetErrStat( ErrID_Fatal, 'WindSpeed and TSR must be positive numbers for the steady-state solver.', ErrStat, ErrMsg, RoutineName ) ! at least, they can't be zero! + end if + end do + + end if + + end if END SUBROUTINE ValidateInputData !---------------------------------------------------------------------------------------------------------------------------------- @@ -2151,9 +2199,9 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) IF ( p_FAST%CompInflow == Module_IfW ) THEN y_FAST%Module_Ver( Module_IfW ) = Init%OutData_IfW%Ver ! call copy routine for this type if it every uses dynamic memory y_FAST%FileDescLines(2) = TRIM(y_FAST%FileDescLines(2) ) //'; '//TRIM(GetNVD(y_FAST%Module_Ver( Module_IfW ))) - ELSEIF ( p_FAST%CompInflow == Module_OpFM ) THEN - y_FAST%Module_Ver( Module_OpFM ) = Init%OutData_OpFM%Ver ! call copy routine for this type if it every uses dynamic memory - y_FAST%FileDescLines(2) = TRIM(y_FAST%FileDescLines(2) ) //'; '//TRIM(GetNVD(y_FAST%Module_Ver( Module_OpFM ))) + ELSEIF ( p_FAST%CompInflow == Module_ExtInfw ) THEN + y_FAST%Module_Ver( Module_ExtInfw ) = Init%OutData_ExtInfw%Ver ! call copy routine for this type if it every uses dynamic memory + y_FAST%FileDescLines(2) = TRIM(y_FAST%FileDescLines(2) ) //'; '//TRIM(GetNVD(y_FAST%Module_Ver( Module_ExtInfw ))) END IF IF ( p_FAST%CompAero == Module_AD14 ) THEN @@ -2215,7 +2263,7 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) y_FAST%numOuts = 0 ! Inintialize entire array IF ( ALLOCATED( Init%OutData_IfW%WriteOutputHdr ) ) y_FAST%numOuts(Module_IfW) = SIZE(Init%OutData_IfW%WriteOutputHdr) - IF ( ALLOCATED( Init%OutData_OpFM%WriteOutputHdr ) ) y_FAST%numOuts(Module_OpFM) = SIZE(Init%OutData_OpFM%WriteOutputHdr) + IF ( ALLOCATED( Init%OutData_ExtInfw%WriteOutputHdr ) ) y_FAST%numOuts(Module_ExtInfw) = SIZE(Init%OutData_ExtInfw%WriteOutputHdr) IF ( ALLOCATED( Init%OutData_ED%WriteOutputHdr ) ) y_FAST%numOuts(Module_ED) = SIZE(Init%OutData_ED%WriteOutputHdr) do i=1,p_FAST%nBeams IF ( ALLOCATED( Init%OutData_BD(i)%WriteOutputHdr) ) y_FAST%numOuts(Module_BD) = y_FAST%numOuts(Module_BD) + SIZE(Init%OutData_BD(i)%WriteOutputHdr) @@ -2241,7 +2289,11 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) !...................................................... ! Initialize the output channel names and units !...................................................... + if (p_FAST%CompAeroMaps) then + y_FAST%numOuts(Module_Glue) = 1 + size(y_FAST%DriverWriteOutput) + else y_FAST%numOuts(Module_Glue) = 1 ! time + end if NumOuts = SUM( y_FAST%numOuts ) @@ -2252,9 +2304,33 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) IF ( ErrStat /= ErrID_None ) RETURN ! Glue outputs: - y_FAST%ChannelNames(1) = 'Time' - y_FAST%ChannelUnits(1) = '(s)' + if (p_FAST%CompAeroMaps) then + y_FAST%ChannelNames(1) = 'Case' + y_FAST%ChannelUnits(1) = '(-)' + + y_FAST%ChannelNames(SS_Indx_Pitch+1) = 'Pitch' + y_FAST%ChannelUnits(SS_Indx_Pitch+1) = '(deg)' + + y_FAST%ChannelNames(SS_Indx_TSR+1) = 'TSR' + y_FAST%ChannelUnits(SS_Indx_TSR+1) = '(-)' + + y_FAST%ChannelNames(SS_Indx_RotSpeed+1) = 'RotorSpeed' + y_FAST%ChannelUnits(SS_Indx_RotSpeed+1) = '(RPM)' + + y_FAST%ChannelNames(SS_Indx_Err+1) = 'AvgError' + y_FAST%ChannelUnits(SS_Indx_Err+1) = '(-)' + + y_FAST%ChannelNames(SS_Indx_Iter+1) = 'Iterations' + y_FAST%ChannelUnits(SS_Indx_Iter+1) = '(-)' + + y_FAST%ChannelNames(SS_Indx_WS+1) = 'WindSpeed' + y_FAST%ChannelUnits(SS_Indx_WS+1) = '(m/s)' + + else + y_FAST%ChannelNames(1) = 'Time' + y_FAST%ChannelUnits(1) = '(s)' + end if indxNext = y_FAST%numOuts(Module_Glue) + 1 @@ -2264,9 +2340,9 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) indxNext = indxNext + 1 END DO - DO i=1,y_FAST%numOuts(Module_OpFM) !OpenFOAM - y_FAST%ChannelNames(indxNext) = Init%OutData_OpFM%WriteOutputHdr(i) - y_FAST%ChannelUnits(indxNext) = Init%OutData_OpFM%WriteOutputUnt(i) + DO i=1,y_FAST%numOuts(Module_ExtInfw) !ExternalInflow + y_FAST%ChannelNames(indxNext) = Init%OutData_ExtInfw%WriteOutputHdr(i) + y_FAST%ChannelUnits(indxNext) = Init%OutData_ExtInfw%WriteOutputUnt(i) indxNext = indxNext + 1 END DO @@ -2446,9 +2522,10 @@ SUBROUTINE FAST_InitOutput( p_FAST, y_FAST, Init, ErrStat, ErrMsg ) IF (p_FAST%WrBinOutFile) THEN ! calculate the size of the array of outputs we need to store + !IF (p_FAST%CompAeroMaps) y_FAST%NOutSteps = p_FAST%NumTSR * p_FAST%NumPitch y_FAST%NOutSteps = CEILING ( (p_FAST%TMax - p_FAST%TStart) / p_FAST%DT_OUT ) + 1 - CALL AllocAry( y_FAST%AllOutData, NumOuts-1, y_FAST%NOutSteps, 'AllOutData', ErrStat, ErrMsg ) ! this does not include the time channel + CALL AllocAry( y_FAST%AllOutData, NumOuts-1, y_FAST%NOutSteps, 'AllOutData', ErrStat, ErrMsg ) ! this does not include the time channel (or case number for steady-state solve) IF ( ErrStat >= AbortErrLev ) RETURN y_FAST%AllOutData = 0.0_ReKi @@ -2528,6 +2605,8 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrS RETURN end if + p%NumSSCases = 0 + p%RotSpeedInit = 0.0_ReKi ! Read the lines up/including to the "Echo" simulation control variable ! If echo is FALSE, don't write these lines to the echo file. @@ -2594,9 +2673,11 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrS END DO - CALL WrScr( TRIM(FAST_Ver%Name)//' input file heading:' ) - CALL WrScr( ' '//TRIM( p%FTitle ) ) - CALL WrScr('') + if (.not. p%CompAeroMaps) then + CALL WrScr( TRIM(FAST_Ver%Name)//' input file heading:' ) + CALL WrScr( ' '//TRIM( p%FTitle ) ) + CALL WrScr('') + end if ! AbortLevel - Error level when simulation should abort: @@ -2724,13 +2805,13 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrS ELSEIF ( p%CompInflow == 1 ) THEN p%CompInflow = Module_IfW ELSEIF ( p%CompInflow == 2 ) THEN - p%CompInflow = Module_OpFM + p%CompInflow = Module_ExtInfw ELSE p%CompInflow = Module_Unknown END IF ! CompAero - Compute aerodynamic loads (switch) {0=None; 1=AeroDyn}: - CALL ReadVar( UnIn, InputFile, p%CompAero, "CompAero", "Compute aerodynamic loads (switch) {0=None; 1=AeroDyn}", ErrStat2, ErrMsg2, UnEc) + CALL ReadVar( UnIn, InputFile, p%CompAero, "CompAero", "Compute aerodynamic loads (switch) {0=None; 1=AeroDyn14; 2=AeroDyn}", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if ( ErrStat >= AbortErrLev ) then call cleanup() @@ -3284,6 +3365,12 @@ SUBROUTINE FAST_ReadPrimaryFile( InputFile, p, m_FAST, OverrideAbortErrLev, ErrS RETURN end if + ! temporary work-around for error with CalcSteady + if (p%CalcSteady .and. p%NLinTimes == 1 ) then + call SetErrStat(ErrID_Info, "Setting NLinTimes to 2 to avoid problem with CalcSteady with only one time.", ErrStat,ErrMsg,RoutineName) + p%NLinTimes = 2 + end if + ! LinInputs - Include inputs in linearization (switch) {0=none; 1=standard; 2=all module inputs (debug)} CALL ReadVar( UnIn, InputFile, p%LinInputs, "LinInputs", "Include inputs in linearization (switch) {0=none; 1=standard; 2=all module inputs (debug)}", ErrStat2, ErrMsg2, UnEc) CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -3418,6 +3505,320 @@ end subroutine cleanup !............................................................................................................................... END SUBROUTINE FAST_ReadPrimaryFile !---------------------------------------------------------------------------------------------------------------------------------- +!> This routine reads in the primary FAST input file for steady-state calculations, does some validation, and places the values it reads in the +!! parameter structure (p). It prints to an echo file if requested. +SUBROUTINE FAST_ReadSteadyStateFile( InputFile, p, m_FAST, ErrStat, ErrMsg ) + + IMPLICIT NONE + + ! Passed variables + TYPE(FAST_ParameterType), INTENT(INOUT) :: p !< The parameter data for the FAST (glue-code) simulation + TYPE(FAST_MiscVarType), INTENT(INOUT) :: m_FAST !< Miscellaneous variables + CHARACTER(*), INTENT(IN) :: InputFile !< Name of the file containing the primary input data + INTEGER(IntKi), INTENT(OUT) :: ErrStat !< Error status + CHARACTER(*), INTENT(OUT) :: ErrMsg !< Error message + + ! Local variables: + INTEGER(IntKi) :: I ! loop counter + INTEGER(IntKi) :: UnIn ! Unit number for reading file + INTEGER(IntKi) :: UnEc ! I/O unit for echo file. If > 0, file is open for writing. + + REAL(ReKi) :: TmpAry(3) ! temporary array to read in columns of case table + + INTEGER(IntKi) :: ErrStat2 ! Temporary Error status + LOGICAL :: Echo ! Determines if an echo file should be written + CHARACTER(ErrMsgLen) :: ErrMsg2 ! Temporary Error message + CHARACTER(1024) :: PriPath ! Path name of the primary file + CHARACTER(1024) :: FstFile ! Name of the primary ENFAST model file + + CHARACTER(*), PARAMETER :: RoutineName = 'FAST_ReadSteadyStateFile' + + + ! Initialize some variables: + UnEc = -1 + Echo = .FALSE. ! Don't echo until we've read the "Echo" flag + CALL GetPath( InputFile, PriPath ) ! Input files will be relative to the path where the primary input file is located. + + + ! Get an available unit number for the file. + + CALL GetNewUnit( UnIn, ErrStat, ErrMsg ) + IF ( ErrStat >= AbortErrLev ) RETURN + + + ! Open the Primary input file. + + CALL OpenFInpFile ( UnIn, InputFile, ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + ! Read the lines up/including to the "Echo" simulation control variable + ! If echo is FALSE, don't write these lines to the echo file. + ! If Echo is TRUE, rewind and write on the second try. + + I = 1 !set the number of times we've read the file + DO + !-------------------------- HEADER --------------------------------------------- + + CALL ReadCom( UnIn, InputFile, 'File header: Version (line 1)', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + CALL ReadStr( UnIn, InputFile, p%FTitle, 'FTitle', 'File Header: File Description (line 2)', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + !---------------------- ENFAST MODEL FILE -------------------------------------- + CALL ReadCom( UnIn, InputFile, 'Section Header: ENFAST Model', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + CALL ReadVar( UnIn, InputFile, FstFile, "FstFile", "Name of the primary ENFAST model file (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + !---------------------- STEADY-STATE SIMULATION CONTROL -------------------------------------- + CALL ReadCom( UnIn, InputFile, 'Section Header: Simulation Control', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + ! Echo - Echo input data to .ech (flag): + CALL ReadVar( UnIn, InputFile, Echo, "Echo", "Echo input data to .ech (flag)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + IF (.NOT. Echo .OR. I > 1) EXIT !exit this loop + + ! Otherwise, open the echo file, then rewind the input file and echo everything we've read + + I = I + 1 ! make sure we do this only once (increment counter that says how many times we've read this file) + + CALL OpenEcho ( UnEc, TRIM(p%OutFileRoot)//'.ech', ErrStat2, ErrMsg2, FAST_Ver ) + CALL SetErrStat( ErrStat2, ErrMsg2,ErrStat,ErrMsg,RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + IF ( UnEc > 0 ) WRITE (UnEc,'(/,A,/)') 'Data from '//TRIM(FAST_Ver%Name)//' primary steady-state input file "'//TRIM( InputFile )//'":' + + REWIND( UnIn, IOSTAT=ErrStat2 ) + IF (ErrStat2 /= 0_IntKi ) THEN + CALL SetErrStat( ErrID_Fatal, 'Error rewinding file "'//TRIM(InputFile)//'".',ErrStat,ErrMsg,RoutineName) + call cleanup() + RETURN + END IF + + END DO + + CALL WrScr( TRIM(FAST_Ver%Name)//' input file heading:' ) + CALL WrScr( ' '//TRIM( p%FTitle ) ) + CALL WrScr('') + + ! ------------------------------------------------------------- + ! READ FROM THE PRIMARY OPENFAST (TIME-DOMAIN) INPUT FILE + ! do this before reading the rest of the variables in this + ! steady-state input file so that we don't accidentally + ! overwrite them. + ! ------------------------------------------------------------- + IF ( PathIsRelative( FstFile ) ) FstFile = TRIM(PriPath)//TRIM(FstFile) + CALL FAST_ReadPrimaryFile( FstFile, p, m_FAST, .true., ErrStat2, ErrMsg2 ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + !-------------------------------------------- + ! Overwrite values for parameters that we do not + ! want to read from the input file: + !-------------------------------------------- + p%DT = 1.0_DbKi ! we'll make this unity to represent case numbers instead of time in the case of AeroMap generation + p%TMax = p%DT ! overwrite this later when we have the number of cases to run + p%InterpOrder = 1 ! set this to 1 so we have two copies of inputs in the solver + p%NumCrctn = 0 + p%DT_UJac = 9999.0_ReKi ! any non-zero number will do ! maybe we will want to use this???? + p%n_SttsTime = 1 + p%n_ChkptTime = HUGE(p%n_ChkptTime) + + p%CompInflow = Module_NONE + p%CompServo = Module_NONE + p%CompHydro = Module_NONE + p%CompSeaSt = Module_NONE + p%CompSub = Module_NONE + p%CompMooring = Module_NONE + p%CompIce = Module_NONE + if ( p%CompAero /= Module_AD) then + p%CompAero = Module_AD + call WrScr('Warning: AeroDyn must be used for generating AeroMaps. Check that variable "AeroFile" is set properly in the OpenFAST input file.') + end if + if (p%CompElast == Module_BD) then + CALL SetErrStat( ErrID_Warn, "AeroMaps with BeamDyn have not been verified.", ErrStat, ErrMsg, RoutineName) + end if + + p%DT_Out = p%DT + p%n_DT_Out = 1 ! output every step (i.e., every case) + p%TStart = 0.0_DbKi + + p%Linearize = .false. ! we use p%CompAeroMaps to do a subset of the linearization routines + p%CalcSteady = .false. + p%TrimCase = TrimCase_none + p%NLinTimes = 1 + p%LinInputs = LIN_ALL + p%LinOutputs = LIN_ALL + + p%LinOutMod = .TRUE. ! if debugging, this will allow us to output linearization files (see parameter "output_debugging" in FAST_SS_Solver.f90); otherwise this doesn't do anything + p%LinOutJac = .TRUE. ! if debugging, this will allow us to output linearization files (see parameter "output_debugging" in FAST_SS_Solver.f90); otherwise this doesn't do anything + p%WrVTK = VTK_None + p%VTK_Type = VTK_None + p%n_VTKTime = 1 + m_FAST%Lin%FoundSteady = .false. + p%LinInterpOrder = p%InterpOrder ! 1 ! always use linear (or constant) interpolation on rotor + !-------------------------------------------- + + + ! Toler - Convergence tolerance for nonlinear solve residual equation [>0] (-) + CALL ReadVar( UnIn, InputFile, p%tolerSquared, "Toler", "Convergence tolerance for nonlinear solve residual equation (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + p%tolerSquared = p%tolerSquared ** 2 + + + ! MaxIter - Maximum number of iteration steps for nonlinear solve [>0] (-) + CALL ReadVar( UnIn, InputFile, p%KMax, "MaxIter", "Maximum number of iteration steps for nonlinear solve (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + ! N_UJac - Number of iteration steps to recalculate Jacobian (-) [1=every iteration step, 2=every other step] + CALL ReadVar( UnIn, InputFile, p%N_UJac, "N_SSJac", "Number of iteration steps to recalculate steady-state Jacobian (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + ! UJacSclFact - Scaling factor used in Jacobians (-) + CALL ReadVar( UnIn, InputFile, p%UJacSclFact, "SSJacSclFact", "Scaling factor used in steady-state Jacobians (-)", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + !---------------------- CASES ----------------------------------------------- + CALL ReadCom( UnIn, InputFile, 'Section Header: Steady-State Cases', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + ! WindSpeedOrTSR - Choice of swept parameter (switch) { 1:wind speed; 2: TSR }: + CALL ReadVar( UnIn, InputFile, p%WindSpeedOrTSR, "WindSpeedOrTSR", "Choice of swept parameter (switch) { 1:wind speed; 2: TSR }", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + ! NumSSCases - Number of steady-state cases (-) [>=1] + CALL ReadVar( UnIn, InputFile, p%NumSSCases, "NumSSCases", "Number of steady-state cases (-) [>=1]", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + if (p%NumSSCases < 1) then + CALL SetErrStat( ErrID_Fatal, "Number of cases must be at least 1.", ErrStat, ErrMsg, RoutineName) + call cleanup() + RETURN + end if + + ! TSR - List of TSRs (-) [>0] + call AllocAry( p%RotSpeed, p%NumSSCases, 'RotSpeed', ErrStat2, ErrMsg2 ); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call AllocAry( p%WS_TSR, p%NumSSCases, 'WS_TSR', ErrStat2, ErrMsg2 ); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + call AllocAry( p%Pitch, p%NumSSCases, 'Pitch', ErrStat2, ErrMsg2 ); CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + ! Case table header: + CALL ReadCom( UnIn, InputFile, 'Section Header: Steady-State Case Column Names', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + CALL ReadCom( UnIn, InputFile, 'Section Header: Steady-State Case Column Units', ErrStat2, ErrMsg2, UnEc ) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + + ! Case table: + do i=1,p%NumSSCases + CALL ReadAry( UnIn, InputFile, TmpAry, size(TmpAry), "TmpAry", "List of cases (-) [>0]", ErrStat2, ErrMsg2, UnEc) + CALL SetErrStat( ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if ( ErrStat >= AbortErrLev ) then + call cleanup() + RETURN + end if + + p%RotSpeed(i) = TmpAry(1) * RPM2RPS + p%WS_TSR( i) = TmpAry(2) + p%Pitch( i) = TmpAry(3) * D2R + end do + + !---------------------- END OF FILE ----------------------------------------- + p%TMax = p%NumSSCases + p%RotSpeedInit = p%RotSpeed(1) + + call cleanup() + RETURN + +CONTAINS + !............................................................................................................................... + subroutine cleanup() + CLOSE( UnIn ) + IF ( UnEc > 0 ) CLOSE ( UnEc ) + end subroutine cleanup + !............................................................................................................................... +END SUBROUTINE FAST_ReadSteadyStateFile +!---------------------------------------------------------------------------------------------------------------------------------- !> This subroutine sets up some of the information needed for plotting VTK surfaces. It initializes only the data needed before !! SeaState initialization. (SeaSt needs some of this data so it can return the wave elevation data we want.) SUBROUTINE SetVTKParameters_B4SeaSt(p_FAST, InitOutData_ED, InitInData_SeaSt, BD, ErrStat, ErrMsg) @@ -3430,7 +3831,7 @@ SUBROUTINE SetVTKParameters_B4SeaSt(p_FAST, InitOutData_ED, InitInData_SeaSt, BD CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None - REAL(SiKi) :: BladeLength, Width, WidthBy2 + REAL(SiKi) :: BladeLength, HubRad, Width, WidthBy2 REAL(SiKi) :: dx, dy INTEGER(IntKi) :: i, j, n INTEGER(IntKi) :: ErrStat2 @@ -3444,11 +3845,13 @@ SUBROUTINE SetVTKParameters_B4SeaSt(p_FAST, InitOutData_ED, InitInData_SeaSt, BD ! Get radius for ground (blade length + hub radius): if ( p_FAST%CompElast == Module_BD ) then BladeLength = TwoNorm(BD%y(1)%BldMotion%Position(:,1) - BD%y(1)%BldMotion%Position(:,BD%y(1)%BldMotion%Nnodes)) + HubRad = InitOutData_ED%HubRad else BladeLength = InitOutData_ED%BladeLength + HubRad = InitOutData_ED%HubRad end if - p_FAST%VTK_Surface%HubRad = InitOutData_ED%HubRad - p_FAST%VTK_Surface%GroundRad = BladeLength + p_FAST%VTK_Surface%HubRad + p_FAST%VTK_Surface%HubRad = HubRad + p_FAST%VTK_Surface%GroundRad = BladeLength + HubRad !........................................................................................................ ! We don't use the rest of this routine for stick-figure output @@ -4083,22 +4486,6 @@ SUBROUTINE FAST_WrSum( p_FAST, y_FAST, MeshMapData, ErrStat, ErrMsg ) ! output file format (text/binary) ! coupling method - SELECT CASE ( p_FAST%TurbineType ) - CASE ( Type_LandBased ) - DescStr = 'Modeling a land-based turbine' - CASE ( Type_Offshore_Fixed ) - DescStr = 'Modeling a fixed-bottom offshore turbine' - CASE ( Type_Offshore_Floating ) - DescStr = 'Modeling a floating offshore turbine' - CASE ( Type_MHK_Fixed ) - DescStr = 'Modeling a fixed-bottom MHK turbine' - CASE ( Type_MHK_Floating ) - DescStr = 'Modeling a floating MHK turbine' - CASE DEFAULT ! This should never happen - DescStr="" - END SELECT - WRITE(y_FAST%UnSum,'(//A)') TRIM(DescStr) - WRITE (y_FAST%UnSum,'(A)' ) 'Description from the FAST input file: ' WRITE (y_FAST%UnSum,'(2X,A)') TRIM(p_FAST%FTitle) @@ -4222,14 +4609,14 @@ SUBROUTINE FAST_Solution0_T(Turbine, ErrStat, ErrMsg) CALL FAST_Solution0(Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%SC_DX,& + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX,& Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg ) END SUBROUTINE FAST_Solution0_T !---------------------------------------------------------------------------------------------------------------------------------- !> Routine that calls CalcOutput for the first time of the simulation (at t=0). After the initial solve, data arrays are initialized. -SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SC_DX, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SC_DX, SeaSt, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code @@ -4242,7 +4629,7 @@ SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, O TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SCDataEx_Data), INTENT(INOUT) :: SC_DX !< Supercontroller exchange data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data @@ -4296,7 +4683,7 @@ SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, O end if CALL CalcOutputs_And_SolveForInputs( n_t_global, t_initial, STATE_CURR, m_FAST%calcJacobian, m_FAST%NextJacCalcTime, & - p_FAST, m_FAST, y_FAST%WriteThisStep, ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, & + p_FAST, m_FAST, y_FAST%WriteThisStep, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -4309,14 +4696,14 @@ SUBROUTINE FAST_Solution0(p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, O ! Check to see if we should output data this time step: !---------------------------------------------------------------------------------------- - CALL WriteOutputToFile(n_t_global_next, t_initial, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2) + CALL WriteOutputToFile(n_t_global_next, t_initial, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! turn off VTK output when if (p_FAST%WrVTK == VTK_InitOnly) then ! Write visualization data for initialization (and also note that we're ignoring any errors that occur doing so) - call WriteVTK(t_initial, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + call WriteVTK(t_initial, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) end if @@ -4802,14 +5189,14 @@ SUBROUTINE FAST_Solution_T(t_initial, n_t_global, Turbine, ErrStat, ErrMsg ) CHARACTER(*), INTENT( OUT) :: ErrMsg !< Error message if ErrStat /= ErrID_None CALL FAST_Solution(t_initial, n_t_global, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%SC_DX, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%SC_DX, & Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg ) END SUBROUTINE FAST_Solution_T !---------------------------------------------------------------------------------------------------------------------------------- !> This routine takes data from n_t_global and gets values at n_t_global + 1 -SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SC_DX, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SC_DX, SeaSt, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg ) REAL(DbKi), INTENT(IN ) :: t_initial !< initial time @@ -4825,7 +5212,7 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SCDataEx_Data), INTENT(INOUT) :: SC_DX !< Supercontroller Exchange data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data @@ -4861,11 +5248,9 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, CHARACTER(*), PARAMETER :: RoutineName = 'FAST_Solution' - ErrStat = ErrID_None - ErrMsg = "" - ErrStat2 = ErrID_None - ErrMsg2 = "" - + ErrStat = ErrID_None + ErrMsg = "" + n_t_global_next = n_t_global+1 t_global_next = t_initial + n_t_global_next*p_FAST%DT ! = m_FAST%t_global + p_FAST%dt @@ -4926,7 +5311,7 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, !! STATE_PRED values contain values at t_global_next. !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - CALL FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, & + CALL FAST_AdvanceStates( t_initial, n_t_global, p_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2, WriteThisStep ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN @@ -4940,7 +5325,7 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, !END IF CALL CalcOutputs_And_SolveForInputs( n_t_global, t_global_next, STATE_PRED, m_FAST%calcJacobian, m_FAST%NextJacCalcTime, & - p_FAST, m_FAST, WriteThisStep, ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) + p_FAST, m_FAST, WriteThisStep, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN @@ -5170,7 +5555,7 @@ SUBROUTINE FAST_Solution(t_initial, n_t_global, p_FAST, y_FAST, m_FAST, ED, BD, !---------------------------------------------------------------------------------------- !! Check to see if we should output data this time step: !---------------------------------------------------------------------------------------- - CALL WriteOutputToFile(n_t_global_next, t_global_next, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, & + CALL WriteOutputToFile(n_t_global_next, t_global_next, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, & SrvD, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -5207,7 +5592,7 @@ END FUNCTION NeedWriteOutput !> This routine determines if it's time to write to the output files--based on a previous call to fast_subs::needwriteoutput--, and !! calls the routine to write to the files with the output data. It should be called after all the output solves for a given time !! have been completed, and assumes y_FAST\%WriteThisStep has been set. -SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, & SrvD, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg) !............................................................................................................................... INTEGER(IntKi), INTENT(IN ) :: n_t_global !< Current global time step @@ -5221,7 +5606,7 @@ SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, TYPE(AeroDyn14_Data), INTENT(IN ) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(IN ) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(IN ) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(IN ) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(IN ) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(IN ) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(IN ) :: SD !< SubDyn data @@ -5249,7 +5634,7 @@ SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, IF ( y_FAST%WriteThisStep ) THEN ! Generate glue-code output file - CALL WrOutputLine( t_global, p_FAST, y_FAST, IfW%y%WriteOutput, OpFM%y%WriteOutput, ED%y%WriteOutput, & + CALL WrOutputLine( t_global, p_FAST, y_FAST, IfW%y%WriteOutput, ExtInfw%y%WriteOutput, ED%y%WriteOutput, & AD%y, SrvD%y%WriteOutput, SeaSt%y%WriteOutput, HD%y%WriteOutput, SD%y%WriteOutput, ExtPtfm%y%WriteOutput, MAPp%y%WriteOutput, & FEAM%y%WriteOutput, MD%y%WriteOutput, Orca%y%WriteOutput, IceF%y%WriteOutput, IceD%y, BD%y, ErrStat, ErrMsg ) @@ -5258,7 +5643,7 @@ SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, ! Write visualization data (and also note that we're ignoring any errors that occur doing so) IF ( p_FAST%WrVTK == VTK_Animate ) THEN IF ( MOD( n_t_global, p_FAST%n_VTKTime ) == 0 ) THEN - call WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + call WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) END IF END IF @@ -5266,7 +5651,7 @@ SUBROUTINE WriteOutputToFile(n_t_global, t_global, p_FAST, y_FAST, ED, BD, AD14, END SUBROUTINE WriteOutputToFile !---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes the module output to the primary output file(s). -SUBROUTINE WrOutputLine( t, p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput,& +SUBROUTINE WrOutputLine( t, p_FAST, y_FAST, IfWOutput, ExtInfwOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput,& MAPOutput, FEAMOutput, MDOutput, OrcaOutput, IceFOutput, y_IceD, y_BD, ErrStat, ErrMsg) IMPLICIT NONE @@ -5278,7 +5663,7 @@ SUBROUTINE WrOutputLine( t, p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_A REAL(ReKi), ALLOCATABLE, INTENT(IN) :: IfWOutput (:) !< InflowWind WriteOutput values - REAL(ReKi), ALLOCATABLE, INTENT(IN) :: OpFMOutput (:) !< OpenFOAM WriteOutput values + REAL(ReKi), ALLOCATABLE, INTENT(IN) :: ExtInfwOutput (:) !< ExternalInflow WriteOutput values REAL(ReKi), ALLOCATABLE, INTENT(IN) :: EDOutput (:) !< ElastoDyn WriteOutput values TYPE(AD_OutputType), INTENT(IN) :: y_AD !< AeroDyn outputs (WriteOutput values are subset of allocated Rotors) REAL(ReKi), ALLOCATABLE, INTENT(IN) :: SrvDOutput (:) !< ServoDyn WriteOutput values @@ -5307,7 +5692,7 @@ SUBROUTINE WrOutputLine( t, p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_A ErrStat = ErrID_None ErrMsg = '' - CALL FillOutputAry(p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput, & + CALL FillOutputAry(p_FAST, y_FAST, IfWOutput, ExtInfwOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput, & MAPOutput, FEAMOutput, MDOutput, OrcaOutput, IceFOutput, y_IceD, y_BD, OutputAry) IF (p_FAST%WrTxtOutFile) THEN @@ -5366,7 +5751,7 @@ SUBROUTINE FillOutputAry_T(Turbine, Outputs) REAL(ReKi), INTENT( OUT) :: Outputs(:) !< single array of output - CALL FillOutputAry(Turbine%p_FAST, Turbine%y_FAST, Turbine%IfW%y%WriteOutput, Turbine%OpFM%y%WriteOutput, & + CALL FillOutputAry(Turbine%p_FAST, Turbine%y_FAST, Turbine%IfW%y%WriteOutput, Turbine%ExtInfw%y%WriteOutput, & Turbine%ED%y%WriteOutput, Turbine%AD%y, Turbine%SrvD%y%WriteOutput, & Turbine%SeaSt%y%WriteOutput, Turbine%HD%y%WriteOutput, Turbine%SD%y%WriteOutput, Turbine%ExtPtfm%y%WriteOutput, Turbine%MAP%y%WriteOutput, & Turbine%FEAM%y%WriteOutput, Turbine%MD%y%WriteOutput, Turbine%Orca%y%WriteOutput, & @@ -5376,14 +5761,14 @@ END SUBROUTINE FillOutputAry_T !---------------------------------------------------------------------------------------------------------------------------------- !> This routine concatenates all of the WriteOutput values from the module Output into one array to be written to the FAST !! output file. -SUBROUTINE FillOutputAry(p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput, & +SUBROUTINE FillOutputAry(p_FAST, y_FAST, IfWOutput, ExtInfwOutput, EDOutput, y_AD, SrvDOutput, SeaStOutput, HDOutput, SDOutput, ExtPtfmOutput, & MAPOutput, FEAMOutput, MDOutput, OrcaOutput, IceFOutput, y_IceD, y_BD, OutputAry) TYPE(FAST_ParameterType), INTENT(IN) :: p_FAST !< Glue-code simulation parameters TYPE(FAST_OutputFileType),INTENT(IN) :: y_FAST !< Glue-code simulation outputs REAL(ReKi), ALLOCATABLE, INTENT(IN) :: IfWOutput (:) !< InflowWind WriteOutput values - REAL(ReKi), ALLOCATABLE, INTENT(IN) :: OpFMOutput (:) !< OpenFOAM WriteOutput values + REAL(ReKi), ALLOCATABLE, INTENT(IN) :: ExtInfwOutput (:) !< ExternalInflow WriteOutput values REAL(ReKi), ALLOCATABLE, INTENT(IN) :: EDOutput (:) !< ElastoDyn WriteOutput values TYPE(AD_OutputType), INTENT(IN) :: y_AD !< AeroDyn outputs (WriteOutput values are subset of allocated Rotors) REAL(ReKi), ALLOCATABLE, INTENT(IN) :: SrvDOutput (:) !< ServoDyn WriteOutput values @@ -5421,9 +5806,9 @@ SUBROUTINE FillOutputAry(p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_AD, indxLast = indxNext + SIZE(IfWOutput) - 1 OutputAry(indxNext:indxLast) = IfWOutput indxNext = IndxLast + 1 - ELSEIF ( y_FAST%numOuts(Module_OpFM) > 0 ) THEN - indxLast = indxNext + SIZE(OpFMOutput) - 1 - OutputAry(indxNext:indxLast) = OpFMOutput + ELSEIF ( y_FAST%numOuts(Module_ExtInfw) > 0 ) THEN + indxLast = indxNext + SIZE(ExtInfwOutput) - 1 + OutputAry(indxNext:indxLast) = ExtInfwOutput indxNext = IndxLast + 1 END IF @@ -5511,7 +5896,7 @@ SUBROUTINE FillOutputAry(p_FAST, y_FAST, IfWOutput, OpFMOutput, EDOutput, y_AD, END SUBROUTINE FillOutputAry !---------------------------------------------------------------------------------------------------------------------------------- -SUBROUTINE WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) +SUBROUTINE WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) REAL(DbKi), INTENT(IN ) :: t_global !< Current global time TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code (only because we're updating VTK_LastWaveIndx) @@ -5522,7 +5907,7 @@ SUBROUTINE WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM TYPE(ServoDyn_Data), INTENT(IN ) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(IN ) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(IN ) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(IN ) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(IN ) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(IN ) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(IN ) :: SD !< SubDyn data @@ -5541,11 +5926,11 @@ SUBROUTINE WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM IF ( p_FAST%VTK_Type == VTK_Surf ) THEN - CALL WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + CALL WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) ELSE IF ( p_FAST%VTK_Type == VTK_Basic ) THEN - CALL WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + CALL WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) ELSE IF ( p_FAST%VTK_Type == VTK_All ) THEN - CALL WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + CALL WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) ELSE IF (p_FAST%VTK_Type==VTK_Old) THEN CALL WriteInputMeshesToFile( ED%Input(1), AD%Input(1), SD%Input(1), HD%Input(1), MAPp%Input(1), BD%Input(1,:), TRIM(p_FAST%OutFileRoot)//'.InputMeshes.bin', ErrStat2, ErrMsg2) CALL WriteMotionMeshesToFile(t_global, ED%y, SD%Input(1), SD%y, HD%Input(1), MAPp%Input(1), BD%y, BD%Input(1,:), y_FAST%UnGra, ErrStat2, ErrMsg2, TRIM(p_FAST%OutFileRoot)//'.gra') @@ -5561,7 +5946,7 @@ SUBROUTINE WriteVTK(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM END SUBROUTINE WriteVTK !---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes all the committed meshes to VTK-formatted files. It doesn't bother with returning an error code. -SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) +SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) use FVW_IO, only: WrVTK_FVW TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code @@ -5573,7 +5958,7 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H TYPE(ServoDyn_Data), INTENT(IN ) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(IN ) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(IN ) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(IN ) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(IN ) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(IN ) :: SD !< SubDyn data TYPE(ExtPtfm_Data), INTENT(IN ) :: ExtPtfm !< ExtPtfm data @@ -5711,15 +6096,17 @@ SUBROUTINE WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, H DO K=1,NumBl call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%rotors(1)%BladeRootMotion(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_BladeRootMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) - !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%BladeMotion(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_BladeMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%rotors(1)%BladeMotion(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_BladeMotion'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) END DO call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%rotors(1)%HubMotion, trim(p_FAST%VTK_OutFileRoot)//'.AD_HubMotion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) - !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%TowerMotion, trim(p_FAST%VTK_OutFileRoot)//'.AD_TowerMotion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) + !call MeshWrVTK(p_FAST%TurbinePos, AD%Input(1)%rotors(1)%TowerMotion, trim(p_FAST%VTK_OutFileRoot)//'.AD_TowerMotion', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth ) - DO K=1,NumBl - call MeshWrVTK(p_FAST%TurbinePos, AD%y%rotors(1)%BladeLoad(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_Blade'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, AD%Input(1)%rotors(1)%BladeMotion(k) ) - END DO + IF (allocated(AD%y%rotors(1)%BladeLoad)) then + DO K=1,NumBl + call MeshWrVTK(p_FAST%TurbinePos, AD%y%rotors(1)%BladeLoad(K), trim(p_FAST%VTK_OutFileRoot)//'.AD_Blade'//trim(num2lstr(k)), y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, AD%Input(1)%rotors(1)%BladeMotion(k) ) + END DO + END IF call MeshWrVTK(p_FAST%TurbinePos, AD%y%rotors(1)%TowerLoad, trim(p_FAST%VTK_OutFileRoot)//'.AD_Tower', y_FAST%VTK_count, p_FAST%VTK_fields, ErrStat2, ErrMsg2, p_FAST%VTK_tWidth, AD%Input(1)%rotors(1)%TowerMotion ) end if @@ -5811,7 +6198,7 @@ END SUBROUTINE WrVTK_AllMeshes !---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes a minimal subset of meshes (enough to visualize the turbine) to VTK-formatted files. It doesn't bother with !! returning an error code. -SUBROUTINE WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) +SUBROUTINE WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) TYPE(FAST_ParameterType), INTENT(IN ) :: p_FAST !< Parameters for the glue code TYPE(FAST_OutputFileType),INTENT(IN ) :: y_FAST !< Output variables for the glue code @@ -5822,7 +6209,7 @@ SUBROUTINE WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, TYPE(ServoDyn_Data), INTENT(IN ) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(IN ) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(IN ) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(IN ) :: ExtInfw !< ExternalInflow data TYPE(HydroDyn_Data), INTENT(IN ) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(IN ) :: SD !< SubDyn data TYPE(MAP_Data), INTENT(IN ) :: MAPp !< MAP data @@ -5911,7 +6298,7 @@ END SUBROUTINE WrVTK_BasicMeshes !---------------------------------------------------------------------------------------------------------------------------------- !> This routine writes a minimal subset of meshes with surfaces to VTK-formatted files. It doesn't bother with !! returning an error code. -SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) +SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) use FVW_IO, only: WrVTK_FVW REAL(DbKi), INTENT(IN ) :: t_global !< Current global time @@ -5924,7 +6311,7 @@ SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW TYPE(ServoDyn_Data), INTENT(IN ) :: SrvD !< ServoDyn data TYPE(AeroDyn_Data), INTENT(IN ) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(IN ) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(IN ) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(IN ) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(IN ) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(IN ) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(IN ) :: SD !< SubDyn data @@ -6036,7 +6423,7 @@ SUBROUTINE WrVTK_Surfaces(t_global, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW if (p_FAST%VTK_fields) then - call WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + call WrVTK_BasicMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) end if @@ -6319,8 +6706,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 ) @@ -6403,7 +6790,7 @@ SUBROUTINE FAST_Linearize_T(t_initial, n_t_global, Turbine, ErrStat, ErrMsg) if ( EqualRealNos( t_global, next_lin_time ) .or. t_global > next_lin_time ) then CALL FAST_Linearize_OP(t_global, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD, Turbine%IfW, Turbine%OpFM, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, & Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -6422,7 +6809,7 @@ SUBROUTINE FAST_Linearize_T(t_initial, n_t_global, Turbine, ErrStat, ErrMsg) t_global = t_initial + n_t_global*Turbine%p_FAST%dt call FAST_CalcSteady( n_t_global, t_global, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, Turbine%ED, Turbine%BD, Turbine%SrvD, & - Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, & + Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, & Turbine%Orca, Turbine%IceF, Turbine%IceD, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -6435,7 +6822,7 @@ SUBROUTINE FAST_Linearize_T(t_initial, n_t_global, Turbine, ErrStat, ErrMsg) t_global = Turbine%m_FAST%Lin%LinTimes(iLinTime) call SetOperatingPoint(iLinTime, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, Turbine%ED, Turbine%BD, Turbine%SrvD, & - Turbine%AD, Turbine%IfW, Turbine%OpFM, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, & + Turbine%AD, Turbine%IfW, Turbine%ExtInfw, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, & Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, Turbine%IceF, Turbine%IceD, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -6445,13 +6832,13 @@ SUBROUTINE FAST_Linearize_T(t_initial, n_t_global, Turbine, ErrStat, ErrMsg) end if CALL CalcOutputs_And_SolveForInputs( -1, t_global, STATE_CURR, Turbine%m_FAST%calcJacobian, Turbine%m_FAST%NextJacCalcTime, & - Turbine%p_FAST, Turbine%m_FAST, .false., Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, & + Turbine%p_FAST, Turbine%m_FAST, .false., Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, & Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN CALL FAST_Linearize_OP(t_global, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD, Turbine%IfW, Turbine%OpFM, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, & Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -6509,14 +6896,14 @@ SUBROUTINE ExitThisProgram_T( Turbine, ErrLevel_in, StopTheProgram, ErrLocMsg, S IF (PRESENT(ErrLocMsg)) THEN CALL ExitThisProgram( Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, & Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrLevel_in, StopTheProgram, ErrLocMsg, SkipRunTimes ) ELSE CALL ExitThisProgram( Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%OpFM, & + Turbine%ED, Turbine%BD, Turbine%SrvD, Turbine%AD14, Turbine%AD, Turbine%IfW, Turbine%ExtInfw, & Turbine%SeaSt, Turbine%HD, Turbine%SD, Turbine%ExtPtfm, Turbine%MAP, Turbine%FEAM, Turbine%MD, Turbine%Orca, & Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrLevel_in, StopTheProgram, SkipRunTimeMsg=SkipRunTimes ) @@ -6532,7 +6919,7 @@ END SUBROUTINE ExitThisProgram_T !! main program. If there was an error, it also aborts. Otherwise, it prints the run times and performs a normal exit. !! This routine should not be called from glue code (e.g., FAST_Prog.f90) or ExitThisProgram_T only. It should not be called in any !! of these driver routines. -SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrLevel_in, StopTheProgram, ErrLocMsg, SkipRunTimeMsg ) !............................................................................................................................... @@ -6547,7 +6934,7 @@ SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn v14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data @@ -6584,13 +6971,13 @@ SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, IF ( ErrorLevel >= AbortErrLev .AND. p_FAST%WrVTK > VTK_None .and. .not. m_FAST%Lin%FoundSteady) THEN p_FAST%VTK_OutFileRoot = trim(p_FAST%VTK_OutFileRoot)//'.DebugError' p_FAST%VTK_fields = .true. - CALL WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + CALL WrVTK_AllMeshes(p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) end if ! End all modules - CALL FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat2, ErrMsg2 ) + CALL FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, SeaSt, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat2, ErrMsg2 ) IF (ErrStat2 /= ErrID_None) THEN CALL WrScr( NewLine//RoutineName//':'//TRIM(ErrMsg2)//NewLine ) ErrorLevel = MAX(ErrorLevel,ErrStat2) @@ -6598,7 +6985,7 @@ SUBROUTINE ExitThisProgram( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ! Destroy all data associated with FAST variables: - CALL FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) + CALL FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) IF (ErrStat2 /= ErrID_None) THEN CALL WrScr( NewLine//RoutineName//':'//TRIM(ErrMsg2)//NewLine ) ErrorLevel = MAX(ErrorLevel,ErrStat2) @@ -6728,7 +7115,7 @@ SUBROUTINE FAST_EndOutput( p_FAST, y_FAST, m_FAST, ErrStat, ErrMsg ) END SUBROUTINE FAST_EndOutput !---------------------------------------------------------------------------------------------------------------------------------- !> This routine calls the end routines for each module that was previously initialized. -SUBROUTINE FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat, ErrMsg ) +SUBROUTINE FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, SeaSt, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(INOUT) :: p_FAST !< Parameters for the glue code TYPE(FAST_OutputFileType),INTENT(INOUT) :: y_FAST !< Output variables for the glue code @@ -6742,6 +7129,7 @@ SUBROUTINE FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, HD TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data + TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(ExtPtfm_Data), INTENT(INOUT) :: ExtPtfm !< ExtPtfm data TYPE(MAP_Data), INTENT(INOUT) :: MAPp !< MAP data TYPE(FEAMooring_Data), INTENT(INOUT) :: FEAM !< FEAMooring data @@ -6766,11 +7154,8 @@ SUBROUTINE FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, HD ErrStat = ErrID_None ErrMsg = "" - - - CALL FAST_EndOutput( p_FAST, y_FAST, m_FAST, ErrStat2, ErrMsg2 ) - CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - + + IF ( p_FAST%ModuleInitialized(Module_ED) ) THEN CALL ED_End( ED%Input(1), ED%p, ED%x(STATE_CURR), ED%xd(STATE_CURR), ED%z(STATE_CURR), ED%OtherSt(STATE_CURR), & ED%y, ED%m, ErrStat2, ErrMsg2 ) @@ -6858,10 +7243,25 @@ SUBROUTINE FAST_EndMods( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, HD END IF + IF ( p_FAST%ModuleInitialized(Module_SeaSt) ) THEN + ! make sure this is done AFTER any module that may be pointing to SeaSt data -- we deallocate the pointer targets here + CALL SeaSt_End( SeaSt%Input(1), SeaSt%p, SeaSt%x(STATE_CURR), SeaSt%xd(STATE_CURR), SeaSt%z(STATE_CURR), SeaSt%OtherSt(STATE_CURR), & + SeaSt%y, SeaSt%m, ErrStat2, ErrMsg2) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + END IF + + + + ! Write output to file (do this after ending modules so that we have more memory to use if needed) + CALL FAST_EndOutput( p_FAST, y_FAST, m_FAST, ErrStat2, ErrMsg2 ) + CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + + + END SUBROUTINE FAST_EndMods !---------------------------------------------------------------------------------------------------------------------------------- !> This routine calls the destroy routines for each module. (It is basically a duplicate of FAST_DestroyTurbineType().) -SUBROUTINE FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat, ErrMsg ) TYPE(FAST_ParameterType), INTENT(INOUT) :: p_FAST !< Parameters for the glue code @@ -6874,7 +7274,7 @@ SUBROUTINE FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn v14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data @@ -6940,8 +7340,8 @@ SUBROUTINE FAST_DestroyAll( p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, CALL FAST_DestroyInflowWind_Data( IfW, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - ! OpenFOAM - CALL FAST_DestroyOpenFOAM_Data( OpFM, ErrStat2, ErrMsg2 ) + ! ExternalInflow + CALL FAST_DestroyExternalInflow_Data( ExtInfw, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) ! SeaState @@ -7078,8 +7478,11 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, ! Get the arrays of data to be stored in the output file call FAST_PackTurbineType(Buf, Turbine) call SetErrStat(Buf%ErrStat, Buf%ErrMsg, ErrStat, ErrMsg, RoutineName ) - if (ErrStat >= AbortErrLev) return - + if (ErrStat >= AbortErrLev ) then + call cleanup() + return + end if + FileName = TRIM(CheckpointRoot)//'.chkp' DLLFileName = TRIM(CheckpointRoot)//'.dll.chkp' @@ -7097,6 +7500,7 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, CLOSE(unOut) unOut = -1 end if + call cleanup() return end if @@ -7111,12 +7515,6 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, ! data from current turbine at time step: call WritePackBuffer(Buf, unOut, ErrStat2, ErrMsg2) - !CALL FAST_CreateCheckpoint(t_initial, n_t_global, Turbine%p_FAST, Turbine%y_FAST, Turbine%m_FAST, & - ! Turbine%ED, Turbine%SrvD, Turbine%AD, Turbine%IfW, & - ! Turbine%HD, Turbine%SD, Turbine%MAP, Turbine%FEAM, Turbine%MD, & - ! Turbine%IceF, Turbine%IceD, Turbine%MeshMapData, ErrStat, ErrMsg ) - - ! If last turbine or no unit, close output unit IF (Turbine%TurbID == NumTurbines .OR. .NOT. PRESENT(Unit)) THEN CLOSE(unOut) @@ -7146,6 +7544,13 @@ SUBROUTINE FAST_CreateCheckpoint_T(t_initial, n_t_global, NumTurbines, Turbine, Turbine%SrvD%m%dll_data%SimStatus = Turbine%SrvD%m%dll_data%avrSWAP( 1) end if END IF + + call cleanup() + +contains + subroutine cleanup() + call DestroyPackBuffer(Buf, ErrStat2, ErrMsg2) + end subroutine cleanup END SUBROUTINE FAST_CreateCheckpoint_T !---------------------------------------------------------------------------------------------------------------------------------- @@ -7362,7 +7767,7 @@ SUBROUTINE FAST_RestoreForVTKModeShape_Tary(t_initial, Turbine, InputFileName, E end if CALL FAST_RestoreForVTKModeShape_T(t_initial, Turbine(i_turb)%p_FAST, Turbine(i_turb)%y_FAST, Turbine(i_turb)%m_FAST, & - Turbine(i_turb)%ED, Turbine(i_turb)%BD, Turbine(i_turb)%SrvD, Turbine(i_turb)%AD14, Turbine(i_turb)%AD, Turbine(i_turb)%IfW, Turbine(i_turb)%OpFM, & + Turbine(i_turb)%ED, Turbine(i_turb)%BD, Turbine(i_turb)%SrvD, Turbine(i_turb)%AD14, Turbine(i_turb)%AD, Turbine(i_turb)%IfW, Turbine(i_turb)%ExtInfw, & Turbine(i_turb)%SeaSt, Turbine(i_turb)%HD, Turbine(i_turb)%SD, Turbine(i_turb)%ExtPtfm, Turbine(i_turb)%MAP, Turbine(i_turb)%FEAM, Turbine(i_turb)%MD, Turbine(i_turb)%Orca, & Turbine(i_turb)%IceF, Turbine(i_turb)%IceD, Turbine(i_turb)%MeshMapData, trim(InputFileName), ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) @@ -7373,7 +7778,7 @@ END SUBROUTINE FAST_RestoreForVTKModeShape_Tary !---------------------------------------------------------------------------------------------------------------------------------- !> This routine calculates the motions generated by mode shapes and outputs VTK data for it -SUBROUTINE FAST_RestoreForVTKModeShape_T(t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, & +SUBROUTINE FAST_RestoreForVTKModeShape_T(t_initial, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD14, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, InputFileName, ErrStat, ErrMsg ) REAL(DbKi), INTENT(IN ) :: t_initial !< initial time @@ -7388,7 +7793,7 @@ SUBROUTINE FAST_RestoreForVTKModeShape_T(t_initial, p_FAST, y_FAST, m_FAST, ED, TYPE(AeroDyn14_Data), INTENT(INOUT) :: AD14 !< AeroDyn14 data TYPE(AeroDyn_Data), INTENT(INOUT) :: AD !< AeroDyn data TYPE(InflowWind_Data), INTENT(INOUT) :: IfW !< InflowWind data - TYPE(OpenFOAM_Data), INTENT(INOUT) :: OpFM !< OpenFOAM data + TYPE(ExternalInflow_Data),INTENT(INOUT) :: ExtInfw !< ExternalInflow data TYPE(SeaState_Data), INTENT(INOUT) :: SeaSt !< SeaState data TYPE(HydroDyn_Data), INTENT(INOUT) :: HD !< HydroDyn data TYPE(SubDyn_Data), INTENT(INOUT) :: SD !< SubDyn data @@ -7480,22 +7885,22 @@ SUBROUTINE FAST_RestoreForVTKModeShape_T(t_initial, p_FAST, y_FAST, m_FAST, ED, m_FAST%NextJacCalcTime = m_FAST%Lin%LinTimes(iLinTime) end if - call SetOperatingPoint(iLinTime, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, & + call SetOperatingPoint(iLinTime, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! set perturbation of states based on x_eig magnitude and phase - call PerturbOP(tprime, iLinTime, ModeNo, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & + call PerturbOP(tprime, iLinTime, ModeNo, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN CALL CalcOutputs_And_SolveForInputs( -1, m_FAST%Lin%LinTimes(iLinTime), STATE_CURR, m_FAST%calcJacobian, m_FAST%NextJacCalcTime, & - p_FAST, m_FAST, .true., ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) + p_FAST, m_FAST, .true., ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN - call WriteVTK(m_FAST%Lin%LinTimes(iLinTime), p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + call WriteVTK(m_FAST%Lin%LinTimes(iLinTime), p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) end do ! iLinTime case (2) @@ -7512,22 +7917,22 @@ SUBROUTINE FAST_RestoreForVTKModeShape_T(t_initial, p_FAST, y_FAST, m_FAST, ED, do it = 1,nt tprime = (it-1)*dt - call SetOperatingPoint(iLinTime, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, & + call SetOperatingPoint(iLinTime, p_FAST, y_FAST, m_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, & MAPp, FEAM, MD, Orca, IceF, IceD, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) ! set perturbation of states based on x_eig magnitude and phase - call PerturbOP(tprime, iLinTime, ModeNo, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & + call PerturbOP(tprime, iLinTime, ModeNo, p_FAST, y_FAST, ED, BD, SrvD, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, & IceF, IceD, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN CALL CalcOutputs_And_SolveForInputs( -1, m_FAST%Lin%LinTimes(iLinTime), STATE_CURR, m_FAST%calcJacobian, m_FAST%NextJacCalcTime, & - p_FAST, m_FAST, .true., ED, BD, SrvD, AD14, AD, IfW, OpFM, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) + p_FAST, m_FAST, .true., ED, BD, SrvD, AD14, AD, IfW, ExtInfw, HD, SD, ExtPtfm, MAPp, FEAM, MD, Orca, IceF, IceD, MeshMapData, ErrStat2, ErrMsg2 ) CALL SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName ) IF (ErrStat >= AbortErrLev) RETURN - call WriteVTK(m_FAST%Lin%LinTimes(iLinTime)+tprime, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, OpFM, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) + call WriteVTK(m_FAST%Lin%LinTimes(iLinTime)+tprime, p_FAST, y_FAST, MeshMapData, ED, BD, AD, IfW, ExtInfw, SeaSt, HD, SD, ExtPtfm, SrvD, MAPp, FEAM, MD, Orca, IceF, IceD) end do ! it end do ! iLinTime diff --git a/modules/openfast-library/src/FAST_Types.f90 b/modules/openfast-library/src/FAST_Types.f90 index aa9ff1b0c6..55e16b222f 100644 --- a/modules/openfast-library/src/FAST_Types.f90 +++ b/modules/openfast-library/src/FAST_Types.f90 @@ -40,7 +40,7 @@ MODULE FAST_Types USE SeaState_Types USE HydroDyn_Types USE IceFloe_Types -USE OpenFOAM_Types +USE ExternalInflow_Types USE SCDataEx_Types USE IceDyn_Types USE FEAMooring_Types @@ -54,7 +54,7 @@ MODULE FAST_Types INTEGER(IntKi), PUBLIC, PARAMETER :: Module_None = 0 ! No module selected [-] INTEGER(IntKi), PUBLIC, PARAMETER :: Module_Glue = 1 ! Glue code [-] INTEGER(IntKi), PUBLIC, PARAMETER :: Module_IfW = 2 ! InflowWind [-] - INTEGER(IntKi), PUBLIC, PARAMETER :: Module_OpFM = 3 ! OpenFOAM [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: Module_ExtInfw = 3 ! ExternalInflow [-] INTEGER(IntKi), PUBLIC, PARAMETER :: Module_ED = 4 ! ElastoDyn [-] INTEGER(IntKi), PUBLIC, PARAMETER :: Module_BD = 5 ! BeamDyn [-] INTEGER(IntKi), PUBLIC, PARAMETER :: Module_AD14 = 6 ! AeroDyn14 [-] @@ -73,6 +73,12 @@ MODULE FAST_Types INTEGER(IntKi), PUBLIC, PARAMETER :: NumModules = 18 ! The number of modules available in FAST [-] INTEGER(IntKi), PUBLIC, PARAMETER :: MaxNBlades = 3 ! Maximum number of blades allowed on a turbine [-] INTEGER(IntKi), PUBLIC, PARAMETER :: IceD_MaxLegs = 4 ! because I don't know how many legs there are before calling IceD_Init and I don't want to copy the data because of sibling mesh issues, I'm going to allocate IceD based on this number [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_Pitch = 1 ! pitch [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_TSR = 2 ! TSR [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_WS = 3 ! wind speed [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_RotSpeed = 4 ! rotor speed [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_Err = 5 ! err in the ss solve [-] + INTEGER(IntKi), PUBLIC, PARAMETER :: SS_Indx_Iter = 6 ! number of iterations [-] ! ========= FAST_VTK_BLSurfaceType ======= TYPE, PUBLIC :: FAST_VTK_BLSurfaceType REAL(SiKi) , DIMENSION(:,:,:), ALLOCATABLE :: AirfoilCoords !< x,y coordinates for airfoil around each blade node on a blade (relative to reference) [-] @@ -109,6 +115,14 @@ MODULE FAST_Types REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: x_eig_phase !< phase of eigenvector (dimension 1=state, dim 2= azimuth, dim 3 = mode) [-] END TYPE FAST_VTK_ModeShapeType ! ======================= +! ========= FAST_SS_CaseType ======= + TYPE, PUBLIC :: FAST_SS_CaseType + REAL(ReKi) :: RotSpeed = 0.0_ReKi !< Rotor speed for this case of the steady-state solve [>0] [(rad/s)] + REAL(ReKi) :: TSR = 0.0_ReKi !< TSR for this case of the steady-state solve [>0] [(-)] + REAL(ReKi) :: WindSpeed = 0.0_ReKi !< Windspeed for this case of the steady-state solve [>0] [(m/s)] + REAL(ReKi) :: Pitch = 0.0_ReKi !< Pitch angle for this case of the steady-state solve [(rad)] + END TYPE FAST_SS_CaseType +! ======================= ! ========= FAST_ParameterType ======= TYPE, PUBLIC :: FAST_ParameterType REAL(DbKi) :: DT = 0.0_R8Ki !< Integration time step [global time] [s] @@ -118,7 +132,7 @@ MODULE FAST_Types REAL(DbKi) :: TMax = 0.0_R8Ki !< Total run time [s] INTEGER(IntKi) :: InterpOrder = 0_IntKi !< Interpolation order {0,1,2} [-] INTEGER(IntKi) :: NumCrctn = 0_IntKi !< Number of correction iterations [-] - INTEGER(IntKi) :: KMax = 0_IntKi !< Maximum number of input-output-solve iterations (KMax >= 1) [-] + INTEGER(IntKi) :: KMax = 0_IntKi !< Maximum number of input-output-solve or nonlinear solve residual equation iterations (KMax >= 1) [>0] [-] INTEGER(IntKi) :: numIceLegs = 0_IntKi !< number of suport-structure legs in contact with ice (IceDyn coupling) [-] INTEGER(IntKi) :: nBeams = 0_IntKi !< number of BeamDyn instances [-] LOGICAL :: BD_OutputSibling = .false. !< flag to determine if BD input is sibling of output mesh [-] @@ -128,7 +142,7 @@ MODULE FAST_Types INTEGER(IntKi) , DIMENSION(1:9) :: SizeJac_Opt1 = 0_IntKi !< (1)=size of matrix; (2)=size of ED portion; (3)=size of SD portion [2 meshes]; (4)=size of HD portion; (5)=size of BD portion blade 1; (6)=size of BD portion blade 2; (7)=size of BD portion blade 3; (8)=size of Orca portion; (9)=size of ExtPtfm portion; [-] INTEGER(IntKi) :: SolveOption = 0_IntKi !< Switch to determine which solve option we are going to use (see Solve_FullOpt1, etc) [-] INTEGER(IntKi) :: CompElast = 0_IntKi !< Compute blade loads (switch) {Module_ED; Module_BD} [-] - INTEGER(IntKi) :: CompInflow = 0_IntKi !< Compute inflow wind conditions (switch) {Module_None; Module_IfW; Module_OpFM} [-] + INTEGER(IntKi) :: CompInflow = 0_IntKi !< Compute inflow wind conditions (switch) {Module_None; Module_IfW; Module_ExtInfw} [-] INTEGER(IntKi) :: CompAero = 0_IntKi !< Compute aerodynamic loads (switch) {Module_None; Module_AD14; Module_AD} [-] INTEGER(IntKi) :: CompServo = 0_IntKi !< Compute control and electrical-drive dynamics (switch) {Module_None; Module_SrvD} [-] INTEGER(IntKi) :: CompSeaSt = 0_IntKi !< Compute sea states; wave kinematics (switch) {Module_None; Module_SeaSt} [-] @@ -168,7 +182,6 @@ MODULE FAST_Types INTEGER(IntKi) :: n_ChkptTime = 0_IntKi !< Number of time steps between writing checkpoint files [-] INTEGER(IntKi) :: n_DT_Out = 0_IntKi !< Number of time steps between writing a line in the time-marching output files [-] INTEGER(IntKi) :: n_VTKTime = 0_IntKi !< Number of time steps between writing VTK files [-] - INTEGER(IntKi) :: TurbineType = 0_IntKi !< Type_LandBased, Type_Offshore_Fixed, Type_Offshore_Floating, Type_MHK_Fixed, or Type_MHK_Floating [-] LOGICAL :: WrBinOutFile = .false. !< Write a binary output file? (.outb) [-] LOGICAL :: WrTxtOutFile = .false. !< Write a text (formatted) output file? (.out) [-] INTEGER(IntKi) :: WrBinMod = 0_IntKi !< If writing binary, which file format is to be written [1, 2, or 3] [-] @@ -205,6 +218,17 @@ MODULE FAST_Types INTEGER(IntKi) :: Lin_NumMods = 0_IntKi !< number of modules in the linearization [-] INTEGER(IntKi) , DIMENSION(1:NumModules) :: Lin_ModOrder = 0_IntKi !< indices that determine which order the modules are in the glue-code linearization matrix [-] INTEGER(IntKi) :: LinInterpOrder = 0_IntKi !< Interpolation order for CalcSteady solution [-] + LOGICAL :: CompAeroMaps = .false. !< Flag to determine if we are calculating aero maps [-] + INTEGER(IntKi) :: N_UJac = 0_IntKi !< Number of iterations between re-calculating Jacobian [(-)] + INTEGER(IntKi) :: NumBl_Lin = 0_IntKi !< number of blades in the jacobian [-] + REAL(R8Ki) :: tolerSquared = 0.0_R8Ki !< Convergence tolerance for nonlinear solve residual equation [>0] squared [(-)] + INTEGER(IntKi) :: NumSSCases = 0_IntKi !< Number of cases for steady-state solver generation [>0] [(-)] + INTEGER(IntKi) :: WindSpeedOrTSR = 0_IntKi !< Choice of swept parameter (switch) { 1:wind speed; 2: TSR } [(-)] + REAL(ReKi) :: RotSpeedInit = 0.0_ReKi !< Initial rotor speed for steady-state solve [>0] [(rad/s)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: RotSpeed !< List of rotor speeds for steady-state solve [>0] [(rad/s)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: WS_TSR !< List of WindSpeed or TSRs (depending on WindSpeedOrTSR setting) for aeromap generation [(m/s or -)] + REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: Pitch !< List of pitch angles for aeromap generation [(rad)] + INTEGER(IntKi) :: GearBox_index = 0_IntKi !< Index to gearbox rotation in state array (for steady-state calculations) [-] END TYPE FAST_ParameterType ! ======================= ! ========= FAST_LinStateSave ======= @@ -362,7 +386,7 @@ MODULE FAST_Types TYPE(FAST_LinFileType) :: Lin !< linearization data for output [-] INTEGER(IntKi) :: ActualChanLen = 0_IntKi !< width of the column headers output in the text and/or binary file [-] TYPE(FAST_LinStateSave) :: op !< operating points of states and inputs for VTK output of mode shapes [-] - REAL(ReKi) , DIMENSION(1:5) :: DriverWriteOutput = 0.0_ReKi !< pitch and tsr for current aero map case, plus error, number of iterations, wind speed [-] + REAL(ReKi) , DIMENSION(1:6) :: DriverWriteOutput = 0.0_ReKi !< pitch and tsr for current aero map case, plus error, number of iterations, wind speed, rotor speed [-] END TYPE FAST_OutputFileType ! ======================= ! ========= IceDyn_Data ======= @@ -473,13 +497,13 @@ MODULE FAST_Types REAL(DbKi) , DIMENSION(:), ALLOCATABLE :: InputTimes !< Array of times associated with Input Array [-] END TYPE InflowWind_Data ! ======================= -! ========= OpenFOAM_Data ======= - TYPE, PUBLIC :: OpenFOAM_Data - TYPE(OpFM_InputType) :: u !< System inputs [-] - TYPE(OpFM_OutputType) :: y !< System outputs [-] - TYPE(OpFM_ParameterType) :: p !< Parameters [-] - TYPE(OpFM_MiscVarType) :: m !< Parameters [-] - END TYPE OpenFOAM_Data +! ========= ExternalInflow_Data ======= + TYPE, PUBLIC :: ExternalInflow_Data + TYPE(ExtInfw_InputType) :: u !< System inputs [-] + TYPE(ExtInfw_OutputType) :: y !< System outputs [-] + TYPE(ExtInfw_ParameterType) :: p !< Parameters [-] + TYPE(ExtInfw_MiscVarType) :: m !< Parameters [-] + END TYPE ExternalInflow_Data ! ======================= ! ========= SCDataEx_Data ======= TYPE, PUBLIC :: SCDataEx_Data @@ -686,6 +710,7 @@ MODULE FAST_Types TYPE(MeshType) , DIMENSION(:), ALLOCATABLE :: u_BD_Distrload !< copy of BD DistrLoad input meshes [-] TYPE(MeshType) :: u_Orca_PtfmMesh !< copy of Orca PtfmMesh input mesh [-] TYPE(MeshType) :: u_ExtPtfm_PtfmMesh !< copy of ExtPtfm_MCKF PtfmMesh input mesh [-] + REAL(R8Ki) , DIMENSION(:,:,:), ALLOCATABLE :: HubOrient !< Orientation matrix to translate results from blade 1 to remaining blades in aeromaps [(-)] END TYPE FAST_ModuleMapType ! ======================= ! ========= FAST_ExternInputType ======= @@ -731,8 +756,8 @@ MODULE FAST_Types TYPE(AD_InitOutputType) :: OutData_AD !< AD Initialization output data [-] TYPE(InflowWind_InitInputType) :: InData_IfW !< IfW Initialization input data [-] TYPE(InflowWind_InitOutputType) :: OutData_IfW !< IfW Initialization output data [-] - TYPE(OpFM_InitInputType) :: InData_OpFM !< OpFM Initialization input data [-] - TYPE(OpFM_InitOutputType) :: OutData_OpFM !< OpFM Initialization output data [-] + TYPE(ExtInfw_InitInputType) :: InData_ExtInfw !< ExtInfw Initialization input data [-] + TYPE(ExtInfw_InitOutputType) :: OutData_ExtInfw !< ExtInfw Initialization output data [-] TYPE(SeaSt_InitInputType) :: InData_SeaSt !< SeaSt Initialization input data [-] TYPE(SeaSt_InitOutputType) :: OutData_SeaSt !< SeaSt Initialization output data [-] TYPE(HydroDyn_InitInputType) :: InData_HD !< HD Initialization input data [-] @@ -792,7 +817,7 @@ MODULE FAST_Types TYPE(AeroDyn_Data) :: AD !< Data for the AeroDyn module [-] TYPE(AeroDyn14_Data) :: AD14 !< Data for the AeroDyn14 module [-] TYPE(InflowWind_Data) :: IfW !< Data for InflowWind module [-] - TYPE(OpenFOAM_Data) :: OpFM !< Data for OpenFOAM integration module [-] + TYPE(ExternalInflow_Data) :: ExtInfw !< Data for ExternalInflow integration module [-] TYPE(SCDataEx_Data) :: SC_DX !< Data for SuperController integration module [-] TYPE(SeaState_Data) :: SeaSt !< Data for the SeaState module [-] TYPE(HydroDyn_Data) :: HD !< Data for the HydroDyn module [-] @@ -1408,12 +1433,64 @@ subroutine FAST_UnPackVTK_ModeShapeType(Buf, OutData) end if end subroutine +subroutine FAST_CopySS_CaseType(SrcSS_CaseTypeData, DstSS_CaseTypeData, CtrlCode, ErrStat, ErrMsg) + type(FAST_SS_CaseType), intent(in) :: SrcSS_CaseTypeData + type(FAST_SS_CaseType), intent(inout) :: DstSS_CaseTypeData + integer(IntKi), intent(in ) :: CtrlCode + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'FAST_CopySS_CaseType' + ErrStat = ErrID_None + ErrMsg = '' + DstSS_CaseTypeData%RotSpeed = SrcSS_CaseTypeData%RotSpeed + DstSS_CaseTypeData%TSR = SrcSS_CaseTypeData%TSR + DstSS_CaseTypeData%WindSpeed = SrcSS_CaseTypeData%WindSpeed + DstSS_CaseTypeData%Pitch = SrcSS_CaseTypeData%Pitch +end subroutine + +subroutine FAST_DestroySS_CaseType(SS_CaseTypeData, ErrStat, ErrMsg) + type(FAST_SS_CaseType), intent(inout) :: SS_CaseTypeData + integer(IntKi), intent( out) :: ErrStat + character(*), intent( out) :: ErrMsg + character(*), parameter :: RoutineName = 'FAST_DestroySS_CaseType' + ErrStat = ErrID_None + ErrMsg = '' +end subroutine + +subroutine FAST_PackSS_CaseType(Buf, Indata) + type(PackBuffer), intent(inout) :: Buf + type(FAST_SS_CaseType), intent(in) :: InData + character(*), parameter :: RoutineName = 'FAST_PackSS_CaseType' + if (Buf%ErrStat >= AbortErrLev) return + call RegPack(Buf, InData%RotSpeed) + call RegPack(Buf, InData%TSR) + call RegPack(Buf, InData%WindSpeed) + call RegPack(Buf, InData%Pitch) + if (RegCheckErr(Buf, RoutineName)) return +end subroutine + +subroutine FAST_UnPackSS_CaseType(Buf, OutData) + type(PackBuffer), intent(inout) :: Buf + type(FAST_SS_CaseType), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'FAST_UnPackSS_CaseType' + if (Buf%ErrStat /= ErrID_None) return + call RegUnpack(Buf, OutData%RotSpeed) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%TSR) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%WindSpeed) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%Pitch) + if (RegCheckErr(Buf, RoutineName)) return +end subroutine + subroutine FAST_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) type(FAST_ParameterType), intent(in) :: SrcParamData type(FAST_ParameterType), intent(inout) :: DstParamData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg + integer(IntKi) :: LB(1), UB(1) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'FAST_CopyParam' @@ -1476,7 +1553,6 @@ subroutine FAST_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%n_ChkptTime = SrcParamData%n_ChkptTime DstParamData%n_DT_Out = SrcParamData%n_DT_Out DstParamData%n_VTKTime = SrcParamData%n_VTKTime - DstParamData%TurbineType = SrcParamData%TurbineType DstParamData%WrBinOutFile = SrcParamData%WrBinOutFile DstParamData%WrTxtOutFile = SrcParamData%WrTxtOutFile DstParamData%WrBinMod = SrcParamData%WrBinMod @@ -1517,6 +1593,50 @@ subroutine FAST_CopyParam(SrcParamData, DstParamData, CtrlCode, ErrStat, ErrMsg) DstParamData%Lin_NumMods = SrcParamData%Lin_NumMods DstParamData%Lin_ModOrder = SrcParamData%Lin_ModOrder DstParamData%LinInterpOrder = SrcParamData%LinInterpOrder + DstParamData%CompAeroMaps = SrcParamData%CompAeroMaps + DstParamData%N_UJac = SrcParamData%N_UJac + DstParamData%NumBl_Lin = SrcParamData%NumBl_Lin + DstParamData%tolerSquared = SrcParamData%tolerSquared + DstParamData%NumSSCases = SrcParamData%NumSSCases + DstParamData%WindSpeedOrTSR = SrcParamData%WindSpeedOrTSR + DstParamData%RotSpeedInit = SrcParamData%RotSpeedInit + if (allocated(SrcParamData%RotSpeed)) then + LB(1:1) = lbound(SrcParamData%RotSpeed) + UB(1:1) = ubound(SrcParamData%RotSpeed) + if (.not. allocated(DstParamData%RotSpeed)) then + allocate(DstParamData%RotSpeed(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%RotSpeed.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%RotSpeed = SrcParamData%RotSpeed + end if + if (allocated(SrcParamData%WS_TSR)) then + LB(1:1) = lbound(SrcParamData%WS_TSR) + UB(1:1) = ubound(SrcParamData%WS_TSR) + if (.not. allocated(DstParamData%WS_TSR)) then + allocate(DstParamData%WS_TSR(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%WS_TSR.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%WS_TSR = SrcParamData%WS_TSR + end if + if (allocated(SrcParamData%Pitch)) then + LB(1:1) = lbound(SrcParamData%Pitch) + UB(1:1) = ubound(SrcParamData%Pitch) + if (.not. allocated(DstParamData%Pitch)) then + allocate(DstParamData%Pitch(LB(1):UB(1)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstParamData%Pitch.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstParamData%Pitch = SrcParamData%Pitch + end if + DstParamData%GearBox_index = SrcParamData%GearBox_index end subroutine subroutine FAST_DestroyParam(ParamData, ErrStat, ErrMsg) @@ -1532,6 +1652,15 @@ subroutine FAST_DestroyParam(ParamData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call FAST_DestroyVTK_ModeShapeType(ParamData%VTK_modes, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (allocated(ParamData%RotSpeed)) then + deallocate(ParamData%RotSpeed) + end if + if (allocated(ParamData%WS_TSR)) then + deallocate(ParamData%WS_TSR) + end if + if (allocated(ParamData%Pitch)) then + deallocate(ParamData%Pitch) + end if end subroutine subroutine FAST_PackParam(Buf, Indata) @@ -1596,7 +1725,6 @@ subroutine FAST_PackParam(Buf, Indata) call RegPack(Buf, InData%n_ChkptTime) call RegPack(Buf, InData%n_DT_Out) call RegPack(Buf, InData%n_VTKTime) - call RegPack(Buf, InData%TurbineType) call RegPack(Buf, InData%WrBinOutFile) call RegPack(Buf, InData%WrTxtOutFile) call RegPack(Buf, InData%WrBinMod) @@ -1633,6 +1761,29 @@ subroutine FAST_PackParam(Buf, Indata) call RegPack(Buf, InData%Lin_NumMods) call RegPack(Buf, InData%Lin_ModOrder) call RegPack(Buf, InData%LinInterpOrder) + call RegPack(Buf, InData%CompAeroMaps) + call RegPack(Buf, InData%N_UJac) + call RegPack(Buf, InData%NumBl_Lin) + call RegPack(Buf, InData%tolerSquared) + call RegPack(Buf, InData%NumSSCases) + call RegPack(Buf, InData%WindSpeedOrTSR) + call RegPack(Buf, InData%RotSpeedInit) + call RegPack(Buf, allocated(InData%RotSpeed)) + if (allocated(InData%RotSpeed)) then + call RegPackBounds(Buf, 1, lbound(InData%RotSpeed), ubound(InData%RotSpeed)) + call RegPack(Buf, InData%RotSpeed) + end if + call RegPack(Buf, allocated(InData%WS_TSR)) + if (allocated(InData%WS_TSR)) then + call RegPackBounds(Buf, 1, lbound(InData%WS_TSR), ubound(InData%WS_TSR)) + call RegPack(Buf, InData%WS_TSR) + end if + call RegPack(Buf, allocated(InData%Pitch)) + if (allocated(InData%Pitch)) then + call RegPackBounds(Buf, 1, lbound(InData%Pitch), ubound(InData%Pitch)) + call RegPack(Buf, InData%Pitch) + end if + call RegPack(Buf, InData%GearBox_index) if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -1640,6 +1791,9 @@ subroutine FAST_UnPackParam(Buf, OutData) type(PackBuffer), intent(inout) :: Buf type(FAST_ParameterType), intent(inout) :: OutData character(*), parameter :: RoutineName = 'FAST_UnPackParam' + integer(IntKi) :: LB(1), UB(1) + integer(IntKi) :: stat + logical :: IsAllocAssoc if (Buf%ErrStat /= ErrID_None) return call RegUnpack(Buf, OutData%DT) if (RegCheckErr(Buf, RoutineName)) return @@ -1755,8 +1909,6 @@ subroutine FAST_UnPackParam(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%n_VTKTime) if (RegCheckErr(Buf, RoutineName)) return - call RegUnpack(Buf, OutData%TurbineType) - if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%WrBinOutFile) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%WrTxtOutFile) @@ -1827,6 +1979,64 @@ subroutine FAST_UnPackParam(Buf, OutData) if (RegCheckErr(Buf, RoutineName)) return call RegUnpack(Buf, OutData%LinInterpOrder) if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%CompAeroMaps) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%N_UJac) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NumBl_Lin) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%tolerSquared) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%NumSSCases) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%WindSpeedOrTSR) + if (RegCheckErr(Buf, RoutineName)) return + call RegUnpack(Buf, OutData%RotSpeedInit) + if (RegCheckErr(Buf, RoutineName)) return + if (allocated(OutData%RotSpeed)) deallocate(OutData%RotSpeed) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 1, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%RotSpeed(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%RotSpeed.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%RotSpeed) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%WS_TSR)) deallocate(OutData%WS_TSR) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 1, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%WS_TSR(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%WS_TSR.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%WS_TSR) + if (RegCheckErr(Buf, RoutineName)) return + end if + if (allocated(OutData%Pitch)) deallocate(OutData%Pitch) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 1, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%Pitch(LB(1):UB(1)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%Pitch.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%Pitch) + if (RegCheckErr(Buf, RoutineName)) return + end if + call RegUnpack(Buf, OutData%GearBox_index) + if (RegCheckErr(Buf, RoutineName)) return end subroutine subroutine FAST_CopyLinStateSave(SrcLinStateSaveData, DstLinStateSaveData, CtrlCode, ErrStat, ErrMsg) @@ -9549,71 +9759,71 @@ subroutine FAST_UnPackInflowWind_Data(Buf, OutData) end if end subroutine -subroutine FAST_CopyOpenFOAM_Data(SrcOpenFOAM_DataData, DstOpenFOAM_DataData, CtrlCode, ErrStat, ErrMsg) - type(OpenFOAM_Data), intent(inout) :: SrcOpenFOAM_DataData - type(OpenFOAM_Data), intent(inout) :: DstOpenFOAM_DataData +subroutine FAST_CopyExternalInflow_Data(SrcExternalInflow_DataData, DstExternalInflow_DataData, CtrlCode, ErrStat, ErrMsg) + type(ExternalInflow_Data), intent(inout) :: SrcExternalInflow_DataData + type(ExternalInflow_Data), intent(inout) :: DstExternalInflow_DataData integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'FAST_CopyOpenFOAM_Data' + character(*), parameter :: RoutineName = 'FAST_CopyExternalInflow_Data' ErrStat = ErrID_None ErrMsg = '' - call OpFM_CopyInput(SrcOpenFOAM_DataData%u, DstOpenFOAM_DataData%u, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyInput(SrcExternalInflow_DataData%u, DstExternalInflow_DataData%u, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call OpFM_CopyOutput(SrcOpenFOAM_DataData%y, DstOpenFOAM_DataData%y, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyOutput(SrcExternalInflow_DataData%y, DstExternalInflow_DataData%y, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call OpFM_CopyParam(SrcOpenFOAM_DataData%p, DstOpenFOAM_DataData%p, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyParam(SrcExternalInflow_DataData%p, DstExternalInflow_DataData%p, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call OpFM_CopyMisc(SrcOpenFOAM_DataData%m, DstOpenFOAM_DataData%m, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyMisc(SrcExternalInflow_DataData%m, DstExternalInflow_DataData%m, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return end subroutine -subroutine FAST_DestroyOpenFOAM_Data(OpenFOAM_DataData, ErrStat, ErrMsg) - type(OpenFOAM_Data), intent(inout) :: OpenFOAM_DataData +subroutine FAST_DestroyExternalInflow_Data(ExternalInflow_DataData, ErrStat, ErrMsg) + type(ExternalInflow_Data), intent(inout) :: ExternalInflow_DataData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 - character(*), parameter :: RoutineName = 'FAST_DestroyOpenFOAM_Data' + character(*), parameter :: RoutineName = 'FAST_DestroyExternalInflow_Data' ErrStat = ErrID_None ErrMsg = '' - call OpFM_DestroyInput(OpenFOAM_DataData%u, ErrStat2, ErrMsg2) + call ExtInfw_DestroyInput(ExternalInflow_DataData%u, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call OpFM_DestroyOutput(OpenFOAM_DataData%y, ErrStat2, ErrMsg2) + call ExtInfw_DestroyOutput(ExternalInflow_DataData%y, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call OpFM_DestroyParam(OpenFOAM_DataData%p, ErrStat2, ErrMsg2) + call ExtInfw_DestroyParam(ExternalInflow_DataData%p, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call OpFM_DestroyMisc(OpenFOAM_DataData%m, ErrStat2, ErrMsg2) + call ExtInfw_DestroyMisc(ExternalInflow_DataData%m, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) end subroutine -subroutine FAST_PackOpenFOAM_Data(Buf, Indata) +subroutine FAST_PackExternalInflow_Data(Buf, Indata) type(PackBuffer), intent(inout) :: Buf - type(OpenFOAM_Data), intent(in) :: InData - character(*), parameter :: RoutineName = 'FAST_PackOpenFOAM_Data' + type(ExternalInflow_Data), intent(in) :: InData + character(*), parameter :: RoutineName = 'FAST_PackExternalInflow_Data' if (Buf%ErrStat >= AbortErrLev) return - call OpFM_PackInput(Buf, InData%u) - call OpFM_PackOutput(Buf, InData%y) - call OpFM_PackParam(Buf, InData%p) - call OpFM_PackMisc(Buf, InData%m) + call ExtInfw_PackInput(Buf, InData%u) + call ExtInfw_PackOutput(Buf, InData%y) + call ExtInfw_PackParam(Buf, InData%p) + call ExtInfw_PackMisc(Buf, InData%m) if (RegCheckErr(Buf, RoutineName)) return end subroutine -subroutine FAST_UnPackOpenFOAM_Data(Buf, OutData) +subroutine FAST_UnPackExternalInflow_Data(Buf, OutData) type(PackBuffer), intent(inout) :: Buf - type(OpenFOAM_Data), intent(inout) :: OutData - character(*), parameter :: RoutineName = 'FAST_UnPackOpenFOAM_Data' + type(ExternalInflow_Data), intent(inout) :: OutData + character(*), parameter :: RoutineName = 'FAST_UnPackExternalInflow_Data' if (Buf%ErrStat /= ErrID_None) return - call OpFM_UnpackInput(Buf, OutData%u) ! u - call OpFM_UnpackOutput(Buf, OutData%y) ! y - call OpFM_UnpackParam(Buf, OutData%p) ! p - call OpFM_UnpackMisc(Buf, OutData%m) ! m + call ExtInfw_UnpackInput(Buf, OutData%u) ! u + call ExtInfw_UnpackOutput(Buf, OutData%y) ! y + call ExtInfw_UnpackParam(Buf, OutData%p) ! p + call ExtInfw_UnpackMisc(Buf, OutData%m) ! m end subroutine subroutine FAST_CopySCDataEx_Data(SrcSCDataEx_DataData, DstSCDataEx_DataData, CtrlCode, ErrStat, ErrMsg) @@ -12214,8 +12424,8 @@ subroutine FAST_CopyModuleMapType(SrcModuleMapTypeData, DstModuleMapTypeData, Ct integer(IntKi), intent(in ) :: CtrlCode integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - integer(IntKi) :: i1, i2 - integer(IntKi) :: LB(2), UB(2) + integer(IntKi) :: i1, i2, i3 + integer(IntKi) :: LB(3), UB(3) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'FAST_CopyModuleMapType' @@ -12735,14 +12945,26 @@ subroutine FAST_CopyModuleMapType(SrcModuleMapTypeData, DstModuleMapTypeData, Ct call MeshCopy(SrcModuleMapTypeData%u_ExtPtfm_PtfmMesh, DstModuleMapTypeData%u_ExtPtfm_PtfmMesh, CtrlCode, ErrStat2, ErrMsg2 ) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return + if (allocated(SrcModuleMapTypeData%HubOrient)) then + LB(1:3) = lbound(SrcModuleMapTypeData%HubOrient) + UB(1:3) = ubound(SrcModuleMapTypeData%HubOrient) + if (.not. allocated(DstModuleMapTypeData%HubOrient)) then + allocate(DstModuleMapTypeData%HubOrient(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)), stat=ErrStat2) + if (ErrStat2 /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating DstModuleMapTypeData%HubOrient.', ErrStat, ErrMsg, RoutineName) + return + end if + end if + DstModuleMapTypeData%HubOrient = SrcModuleMapTypeData%HubOrient + end if end subroutine subroutine FAST_DestroyModuleMapType(ModuleMapTypeData, ErrStat, ErrMsg) type(FAST_ModuleMapType), intent(inout) :: ModuleMapTypeData integer(IntKi), intent( out) :: ErrStat character(*), intent( out) :: ErrMsg - integer(IntKi) :: i1, i2 - integer(IntKi) :: LB(2), UB(2) + integer(IntKi) :: i1, i2, i3 + integer(IntKi) :: LB(3), UB(3) integer(IntKi) :: ErrStat2 character(ErrMsgLen) :: ErrMsg2 character(*), parameter :: RoutineName = 'FAST_DestroyModuleMapType' @@ -13040,14 +13262,17 @@ subroutine FAST_DestroyModuleMapType(ModuleMapTypeData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call MeshDestroy( ModuleMapTypeData%u_ExtPtfm_PtfmMesh, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) + if (allocated(ModuleMapTypeData%HubOrient)) then + deallocate(ModuleMapTypeData%HubOrient) + end if end subroutine subroutine FAST_PackModuleMapType(Buf, Indata) type(PackBuffer), intent(inout) :: Buf type(FAST_ModuleMapType), intent(in) :: InData character(*), parameter :: RoutineName = 'FAST_PackModuleMapType' - integer(IntKi) :: i1, i2 - integer(IntKi) :: LB(2), UB(2) + integer(IntKi) :: i1, i2, i3 + integer(IntKi) :: LB(3), UB(3) if (Buf%ErrStat >= AbortErrLev) return call RegPack(Buf, allocated(InData%ED_P_2_BD_P)) if (allocated(InData%ED_P_2_BD_P)) then @@ -13313,6 +13538,11 @@ subroutine FAST_PackModuleMapType(Buf, Indata) end if call MeshPack(Buf, InData%u_Orca_PtfmMesh) call MeshPack(Buf, InData%u_ExtPtfm_PtfmMesh) + call RegPack(Buf, allocated(InData%HubOrient)) + if (allocated(InData%HubOrient)) then + call RegPackBounds(Buf, 3, lbound(InData%HubOrient), ubound(InData%HubOrient)) + call RegPack(Buf, InData%HubOrient) + end if if (RegCheckErr(Buf, RoutineName)) return end subroutine @@ -13320,8 +13550,8 @@ subroutine FAST_UnPackModuleMapType(Buf, OutData) type(PackBuffer), intent(inout) :: Buf type(FAST_ModuleMapType), intent(inout) :: OutData character(*), parameter :: RoutineName = 'FAST_UnPackModuleMapType' - integer(IntKi) :: i1, i2 - integer(IntKi) :: LB(2), UB(2) + integer(IntKi) :: i1, i2, i3 + integer(IntKi) :: LB(3), UB(3) integer(IntKi) :: stat logical :: IsAllocAssoc if (Buf%ErrStat /= ErrID_None) return @@ -13754,6 +13984,20 @@ subroutine FAST_UnPackModuleMapType(Buf, OutData) end if call MeshUnpack(Buf, OutData%u_Orca_PtfmMesh) ! u_Orca_PtfmMesh call MeshUnpack(Buf, OutData%u_ExtPtfm_PtfmMesh) ! u_ExtPtfm_PtfmMesh + if (allocated(OutData%HubOrient)) deallocate(OutData%HubOrient) + call RegUnpack(Buf, IsAllocAssoc) + if (RegCheckErr(Buf, RoutineName)) return + if (IsAllocAssoc) then + call RegUnpackBounds(Buf, 3, LB, UB) + if (RegCheckErr(Buf, RoutineName)) return + allocate(OutData%HubOrient(LB(1):UB(1),LB(2):UB(2),LB(3):UB(3)),stat=stat) + if (stat /= 0) then + call SetErrStat(ErrID_Fatal, 'Error allocating OutData%HubOrient.', Buf%ErrStat, Buf%ErrMsg, RoutineName) + return + end if + call RegUnpack(Buf, OutData%HubOrient) + if (RegCheckErr(Buf, RoutineName)) return + end if end subroutine subroutine FAST_CopyExternInputType(SrcExternInputTypeData, DstExternInputTypeData, CtrlCode, ErrStat, ErrMsg) @@ -13982,10 +14226,10 @@ subroutine FAST_CopyInitData(SrcInitDataData, DstInitDataData, CtrlCode, ErrStat call InflowWind_CopyInitOutput(SrcInitDataData%OutData_IfW, DstInitDataData%OutData_IfW, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call OpFM_CopyInitInput(SrcInitDataData%InData_OpFM, DstInitDataData%InData_OpFM, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyInitInput(SrcInitDataData%InData_ExtInfw, DstInitDataData%InData_ExtInfw, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call OpFM_CopyInitOutput(SrcInitDataData%OutData_OpFM, DstInitDataData%OutData_OpFM, CtrlCode, ErrStat2, ErrMsg2) + call ExtInfw_CopyInitOutput(SrcInitDataData%OutData_ExtInfw, DstInitDataData%OutData_ExtInfw, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return call SeaSt_CopyInitInput(SrcInitDataData%InData_SeaSt, DstInitDataData%InData_SeaSt, CtrlCode, ErrStat2, ErrMsg2) @@ -14092,9 +14336,9 @@ subroutine FAST_DestroyInitData(InitDataData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call InflowWind_DestroyInitOutput(InitDataData%OutData_IfW, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call OpFM_DestroyInitInput(InitDataData%InData_OpFM, ErrStat2, ErrMsg2) + call ExtInfw_DestroyInitInput(InitDataData%InData_ExtInfw, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call OpFM_DestroyInitOutput(InitDataData%OutData_OpFM, ErrStat2, ErrMsg2) + call ExtInfw_DestroyInitOutput(InitDataData%OutData_ExtInfw, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call SeaSt_DestroyInitInput(InitDataData%InData_SeaSt, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -14165,8 +14409,8 @@ subroutine FAST_PackInitData(Buf, Indata) call AD_PackInitOutput(Buf, InData%OutData_AD) call InflowWind_PackInitInput(Buf, InData%InData_IfW) call InflowWind_PackInitOutput(Buf, InData%OutData_IfW) - call OpFM_PackInitInput(Buf, InData%InData_OpFM) - call OpFM_PackInitOutput(Buf, InData%OutData_OpFM) + call ExtInfw_PackInitInput(Buf, InData%InData_ExtInfw) + call ExtInfw_PackInitOutput(Buf, InData%OutData_ExtInfw) call SeaSt_PackInitInput(Buf, InData%InData_SeaSt) call SeaSt_PackInitOutput(Buf, InData%OutData_SeaSt) call HydroDyn_PackInitInput(Buf, InData%InData_HD) @@ -14225,8 +14469,8 @@ subroutine FAST_UnPackInitData(Buf, OutData) call AD_UnpackInitOutput(Buf, OutData%OutData_AD) ! OutData_AD call InflowWind_UnpackInitInput(Buf, OutData%InData_IfW) ! InData_IfW call InflowWind_UnpackInitOutput(Buf, OutData%OutData_IfW) ! OutData_IfW - call OpFM_UnpackInitInput(Buf, OutData%InData_OpFM) ! InData_OpFM - call OpFM_UnpackInitOutput(Buf, OutData%OutData_OpFM) ! OutData_OpFM + call ExtInfw_UnpackInitInput(Buf, OutData%InData_ExtInfw) ! InData_ExtInfw + call ExtInfw_UnpackInitOutput(Buf, OutData%OutData_ExtInfw) ! OutData_ExtInfw call SeaSt_UnpackInitInput(Buf, OutData%InData_SeaSt) ! InData_SeaSt call SeaSt_UnpackInitOutput(Buf, OutData%OutData_SeaSt) ! OutData_SeaSt call HydroDyn_UnpackInitInput(Buf, OutData%InData_HD) ! InData_HD @@ -14504,7 +14748,7 @@ subroutine FAST_CopyTurbineType(SrcTurbineTypeData, DstTurbineTypeData, CtrlCode call FAST_CopyInflowWind_Data(SrcTurbineTypeData%IfW, DstTurbineTypeData%IfW, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return - call FAST_CopyOpenFOAM_Data(SrcTurbineTypeData%OpFM, DstTurbineTypeData%OpFM, CtrlCode, ErrStat2, ErrMsg2) + call FAST_CopyExternalInflow_Data(SrcTurbineTypeData%ExtInfw, DstTurbineTypeData%ExtInfw, CtrlCode, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) if (ErrStat >= AbortErrLev) return call FAST_CopySCDataEx_Data(SrcTurbineTypeData%SC_DX, DstTurbineTypeData%SC_DX, CtrlCode, ErrStat2, ErrMsg2) @@ -14571,7 +14815,7 @@ subroutine FAST_DestroyTurbineType(TurbineTypeData, ErrStat, ErrMsg) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call FAST_DestroyInflowWind_Data(TurbineTypeData%IfW, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) - call FAST_DestroyOpenFOAM_Data(TurbineTypeData%OpFM, ErrStat2, ErrMsg2) + call FAST_DestroyExternalInflow_Data(TurbineTypeData%ExtInfw, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) call FAST_DestroySCDataEx_Data(TurbineTypeData%SC_DX, ErrStat2, ErrMsg2) call SetErrStat(ErrStat2, ErrMsg2, ErrStat, ErrMsg, RoutineName) @@ -14613,7 +14857,7 @@ subroutine FAST_PackTurbineType(Buf, Indata) call FAST_PackAeroDyn_Data(Buf, InData%AD) call FAST_PackAeroDyn14_Data(Buf, InData%AD14) call FAST_PackInflowWind_Data(Buf, InData%IfW) - call FAST_PackOpenFOAM_Data(Buf, InData%OpFM) + call FAST_PackExternalInflow_Data(Buf, InData%ExtInfw) call FAST_PackSCDataEx_Data(Buf, InData%SC_DX) call FAST_PackSeaState_Data(Buf, InData%SeaSt) call FAST_PackHydroDyn_Data(Buf, InData%HD) @@ -14645,7 +14889,7 @@ subroutine FAST_UnPackTurbineType(Buf, OutData) call FAST_UnpackAeroDyn_Data(Buf, OutData%AD) ! AD call FAST_UnpackAeroDyn14_Data(Buf, OutData%AD14) ! AD14 call FAST_UnpackInflowWind_Data(Buf, OutData%IfW) ! IfW - call FAST_UnpackOpenFOAM_Data(Buf, OutData%OpFM) ! OpFM + call FAST_UnpackExternalInflow_Data(Buf, OutData%ExtInfw) ! ExtInfw call FAST_UnpackSCDataEx_Data(Buf, OutData%SC_DX) ! SC_DX call FAST_UnpackSeaState_Data(Buf, OutData%SeaSt) ! SeaSt call FAST_UnpackHydroDyn_Data(Buf, OutData%HD) ! HD diff --git a/modules/openfast-registry/src/registry.hpp b/modules/openfast-registry/src/registry.hpp index 8229622d75..5d760e949a 100644 --- a/modules/openfast-registry/src/registry.hpp +++ b/modules/openfast-registry/src/registry.hpp @@ -277,7 +277,7 @@ struct DataType switch (field.data_type->tag) { - // Field is a derived type, so check it's fields and + // Field is a derived type, so check its fields and // return false if it doesn't only contain reals case Tag::Derived: if (!field.data_type->derived.only_contains_reals()) diff --git a/modules/openfoam/README.md b/modules/openfoam/README.md deleted file mode 100644 index 0d57400745..0000000000 --- a/modules/openfoam/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# OpenFOAM Module - -## Overview -This is a pseudo module used to couple OpenFAST with OpenFOAM; -it is considered part of the OpenFAST glue code. diff --git a/modules/openfoam/src/OpenFOAM_Registry.txt b/modules/openfoam/src/OpenFOAM_Registry.txt deleted file mode 100644 index f3f27d11e7..0000000000 --- a/modules/openfoam/src/OpenFOAM_Registry.txt +++ /dev/null @@ -1,79 +0,0 @@ -################################################################################################################################### -# Registry for OpenFOAM - CFD interface types in the FAST Modularization Framework -# Entries are of the form -# -# -# Use ^ as a shortcut for the value in the same column from the previous line. -################################################################################################################################### -# ...... Include files (definitions from NWTC Library) ............................................................................ -include Registry_NWTC_Library.txt -include IfW_FlowField.txt - - - -# ..... OpenFOAM_InitInputType data ....................................................................................................... -typedef OpenFOAM/OpFM InitInputType IntKi NumActForcePtsBlade - - - "number of actuator line force points in blade -- from extern (used to linearly interpolate along AD15 blades)" - -typedef ^ ^ IntKi NumActForcePtsTower - - - "number of actuator line force points in tower -- from extern (used to linearly interpolate along AD15 tower)" - -typedef ^ ^ ReKi StructBldRNodes {:} - - "Radius to structural model analysis nodes relative to hub" -typedef ^ ^ ReKi StructTwrHNodes {:} - - "Location of tower nodes from AD15 (relative to the tower rigid base height)" -typedef ^ ^ ReKi BladeLength - - - "Blade length" meters -typedef ^ ^ ReKi TowerHeight - - - "Tower Height" meters -typedef ^ ^ ReKi TowerBaseHeight - - - "Tower Base Height" meters -typedef ^ ^ IntKi NodeClusterType - - - "Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip)" - - - - -# ..... OpenFOAM_InitOutputType data ....................................................................................................... -# Define outputs from the initialization routine here: -typedef OpenFOAM/OpFM InitOutputType CHARACTER(ChanLen) WriteOutputHdr {:} - - "Names of the output-to-file channels" - -typedef ^ InitOutputType CHARACTER(ChanLen) WriteOutputUnt {:} - - "Units of the output-to-file channels" - -typedef ^ InitOutputType ProgDesc Ver - - - "This module's name, version, and date" - -typedef ^ InitOutputType FlowFieldType *FlowField - - - "Pointer of flow field data type" - - -# ..... MiscVars ................................................................................................................ -typedef OpenFOAM/OpFM OpFM_MiscVarType MeshType ActForceMotionsPoints {:} - - "point mesh for transferring AeroDyn motions to OpenFOAM (includes hub+blades+nacelle+tower+tailfin)" - -typedef OpenFOAM/OpFM OpFM_MiscVarType MeshType ActForceLoadsPoints {:} - - "point mesh for transferring AeroDyn distributed loads to OpenFOAM (includes hub+blades+nacelle+tower+tailfin)" - -typedef OpenFOAM/OpFM OpFM_MiscVarType MeshMapType Line2_to_Point_Loads {:} - - "mapping data structure to convert line2 loads to point loads" - -typedef OpenFOAM/OpFM OpFM_MiscVarType MeshMapType Line2_to_Point_Motions {:} - - "mapping data structure to convert line2 loads to point motions" - -typedef OpenFOAM/OpFM OpFM_MiscVarType FlowFieldType &FlowField - - - "Flow field data type" - - - -# ..... Parameters ................................................................................................................ -typedef OpenFOAM/OpFM ParameterType ReKi AirDens - - - "Air density for normalization of loads sent to OpenFOAM" kg/m^3 -typedef OpenFOAM/OpFM ParameterType IntKi NumBl - - - "Number of blades" - -typedef OpenFOAM/OpFM ParameterType IntKi NMappings - - - "Number of mappings" - -typedef OpenFOAM/OpFM ParameterType IntKi NnodesVel - - - "number of velocity nodes on FAST v8-OpenFOAM interface" - -typedef OpenFOAM/OpFM ParameterType IntKi NnodesForce - - - "number of force nodes on FAST v8-OpenFOAM interface" - -typedef OpenFOAM/OpFM ParameterType IntKi NnodesForceBlade - - - "number of force nodes on FAST v8-OpenFOAM interface" - -typedef OpenFOAM/OpFM ParameterType IntKi NnodesForceTower - - - "number of force nodes on FAST v8-OpenFOAM interface" - -typedef OpenFOAM/OpFM ParameterType ReKi forceBldRnodes {:} - - "Radial location of force nodes" - -typedef OpenFOAM/OpFM ParameterType ReKi forceTwrHnodes {:} - - "Vertical location of force nodes" - -typedef OpenFOAM/OpFM ParameterType ReKi BladeLength - - - "Blade length (same for all blades)" "m" -typedef OpenFOAM/OpFM ParameterType ReKi TowerHeight - - - "Tower height" "m" -typedef OpenFOAM/OpFM ParameterType ReKi TowerBaseHeight - - - "Tower base height" "m" -typedef OpenFOAM/OpFM ParameterType IntKi NodeClusterType - - - "Node clustering (0 - Uniform, 1 - Non-uniform clustered towards tip)" - - -# ..... OpenFOAM_InputType data ....................................................................................................... -typedef ^ InputType ReKi pxVel {:} - - "x position of velocity interface (Aerodyn) nodes" "m" -typedef ^ InputType ReKi pyVel {:} - - "y position of velocity interface (Aerodyn) nodes" "m" -typedef ^ InputType ReKi pzVel {:} - - "z position of velocity interface (Aerodyn) nodes" "m" -typedef ^ InputType ReKi pxForce {:} - - "x position of actuator force nodes" "m" -typedef ^ InputType ReKi pyForce {:} - - "y position of actuator force nodes" "m" -typedef ^ InputType ReKi pzForce {:} - - "z position of actuator force nodes" "m" -typedef ^ InputType ReKi xdotForce {:} - - "x velocity of actuator force nodes" "m/s" -typedef ^ InputType ReKi ydotForce {:} - - "y velocity of actuator force nodes" "m/s" -typedef ^ InputType ReKi zdotForce {:} - - "z velocity of actuator force nodes" "m/s" -typedef ^ InputType ReKi pOrientation {:} - - "Direction cosine matrix to transform vectors from global frame of reference to actuator force node frame of reference" - -typedef ^ InputType ReKi fx {:} - - "normalized x force at actuator force nodes" "N/kg/m^3" -typedef ^ InputType ReKi fy {:} - - "normalized y force at actuator force nodes" "N/kg/m^3" -typedef ^ InputType ReKi fz {:} - - "normalized z force at actuator force nodes" "N/kg/m^3" -typedef ^ InputType ReKi momentx {:} - - "normalized x moment at actuator force nodes" "Nm/kg/m^3" -typedef ^ InputType ReKi momenty {:} - - "normalized y moment at actuator force nodes" "Nm/kg/m^3" -typedef ^ InputType ReKi momentz {:} - - "normalized z moment at actuator force nodes" "Nm/kg/m^3" -typedef ^ InputType ReKi forceNodesChord {:} - - "chord distribution at the actuator force nodes" "m" - -# ..... OpenFOAM_OutputType data ....................................................................................................... -typedef OpenFOAM/OpFM OutputType ReKi u {:} - - "U-component wind speed (in the X-direction) at interface nodes" m/s -typedef ^ OutputType ReKi v {:} - - "V-component wind speed (in the Y-direction) at interface nodes" m/s -typedef ^ OutputType ReKi w {:} - - "W-component wind speed (in the Z-direction) at interface nodes" m/s -typedef ^ OutputType ReKi WriteOutput {:} - - "Data to be written to an output file: see WriteOutputHdr for names of each variable" "see WriteOutputUnt" diff --git a/modules/orcaflex-interface/CMakeLists.txt b/modules/orcaflex-interface/CMakeLists.txt index 3b744c4ce8..737f57be9a 100644 --- a/modules/orcaflex-interface/CMakeLists.txt +++ b/modules/orcaflex-interface/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/OrcaFlexInterface.txt ${CMAKE_CURRENT_LIST_DIR}/src/OrcaFlexInterface_Types.f90) endif() -add_library(orcaflexlib +add_library(orcaflexlib STATIC src/OrcaFlexInterface.f90 src/OrcaFlexInterface_Types.f90 ) diff --git a/modules/seastate/CMakeLists.txt b/modules/seastate/CMakeLists.txt index a9d852866d..d30787e698 100644 --- a/modules/seastate/CMakeLists.txt +++ b/modules/seastate/CMakeLists.txt @@ -23,7 +23,7 @@ if (GENERATE_TYPES) generate_f90_types(src/SeaState.txt ${CMAKE_CURRENT_LIST_DIR}/src/SeaState_Types.f90 -noextrap) endif() -add_library(seastlib +add_library(seastlib STATIC src/Current.f90 src/Waves.f90 src/Waves2.f90 diff --git a/modules/servodyn/CMakeLists.txt b/modules/servodyn/CMakeLists.txt index 361e3eb712..a4fe70175d 100644 --- a/modules/servodyn/CMakeLists.txt +++ b/modules/servodyn/CMakeLists.txt @@ -32,7 +32,9 @@ set(SERVODYN_SRCS src/ServoDyn_Types.f90 ) -add_library(servodynlib ${SERVODYN_SRCS}) +add_library(servodynlib STATIC + ${SERVODYN_SRCS} +) target_link_libraries(servodynlib nwtclibs) # Driver 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/subdyn/CMakeLists.txt b/modules/subdyn/CMakeLists.txt index fd81ca64ac..dcc82bc86a 100644 --- a/modules/subdyn/CMakeLists.txt +++ b/modules/subdyn/CMakeLists.txt @@ -18,7 +18,7 @@ if (GENERATE_TYPES) generate_f90_types(src/SubDyn_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/SubDyn_Types.f90) endif() -add_library(subdynlib +add_library(subdynlib STATIC src/SubDyn.f90 src/FEM.f90 src/SD_FEM.f90 diff --git a/modules/supercontroller/CMakeLists.txt b/modules/supercontroller/CMakeLists.txt index 6c9323af6d..4d81ea6695 100644 --- a/modules/supercontroller/CMakeLists.txt +++ b/modules/supercontroller/CMakeLists.txt @@ -19,12 +19,12 @@ if (GENERATE_TYPES) generate_f90_types(src/SC_DataEx_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/SCDataEx_Types.f90 -ccode -noextrap) endif() -add_library(sctypeslib +add_library(sctypeslib STATIC src/SCDataEx_Types.f90 ) target_link_libraries(sctypeslib nwtclibs) -add_library(scfastlib +add_library(scfastlib STATIC src/SC_DataEx.f90 src/SuperController_Types.f90 src/SuperController.f90 diff --git a/modules/version/CMakeLists.txt b/modules/version/CMakeLists.txt index 1af85e5e68..1c714c3685 100644 --- a/modules/version/CMakeLists.txt +++ b/modules/version/CMakeLists.txt @@ -27,7 +27,9 @@ else() endif() add_definitions(-DGIT_VERSION_INFO="${GIT_DESCRIBE}") -add_library(versioninfolib src/VersionInfo.f90) +add_library(versioninfolib STATIC + src/VersionInfo.f90 +) target_link_libraries(versioninfolib nwtclibs) install(TARGETS versioninfolib diff --git a/modules/version/src/VersionInfo.f90 b/modules/version/src/VersionInfo.f90 index 9e512b84c3..8f5ba66e10 100644 --- a/modules/version/src/VersionInfo.f90 +++ b/modules/version/src/VersionInfo.f90 @@ -267,6 +267,16 @@ SUBROUTINE CheckArgs ( Arg1, ErrStat, Arg2, Flag, InputArgArray ) RETURN END IF + CASE ('STEADYSTATE') + IF ( SecondArgumentSet .AND. .NOT. FirstArgumentSet ) THEN + Arg1 = Arg2 + END IF + IF ( .NOT. FirstArgumentSet .AND. .NOT. SecondArgumentSet ) THEN + CALL INVALID_SYNTAX( 'the steady-state capability requires at least one argument: -steadystate' ) + CALL CLEANUP() + RETURN + END IF + CASE DEFAULT CALL INVALID_SYNTAX( 'unknown command-line argument given: '//TRIM(FlagIter) ) CALL CLEANUP() diff --git a/modules/wakedynamics/CMakeLists.txt b/modules/wakedynamics/CMakeLists.txt index bab32ba8d0..aad8811799 100644 --- a/modules/wakedynamics/CMakeLists.txt +++ b/modules/wakedynamics/CMakeLists.txt @@ -17,7 +17,7 @@ if (GENERATE_TYPES) generate_f90_types(src/WakeDynamics_Registry.txt ${CMAKE_CURRENT_LIST_DIR}/src/WakeDynamics_Types.f90 -noextrap) endif() -add_library(wdlib +add_library(wdlib STATIC src/WakeDynamics.f90 #src/WakeDynamics_IO.f90 src/WakeDynamics_Types.f90 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 142e57339c..69fdba80da 100644 --- a/reg_tests/CTestList.cmake +++ b/reg_tests/CTestList.cmake @@ -18,7 +18,7 @@ # Generic test functions #=============================================================================== -function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TESTNAME LABEL) +function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY STEADYSTATE_FLAG TESTNAME LABEL) file(TO_NATIVE_PATH "${EXECUTABLE}" EXECUTABLE) file(TO_NATIVE_PATH "${TEST_SCRIPT}" TEST_SCRIPT) @@ -52,6 +52,10 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TEST if(CTEST_NO_RUN_FLAG) set(NO_RUN_FLAG "-n") endif() + + if(STEADYSTATE_FLAG STREQUAL " ") + set(STEADYSTATE_FLAG "") + endif() add_test( ${TESTNAME} ${Python_EXECUTABLE} @@ -65,6 +69,7 @@ function(regression TEST_SCRIPT EXECUTABLE SOURCE_DIRECTORY BUILD_DIRECTORY TEST ${PLOT_FLAG} # empty or "-p" ${RUN_VERBOSE_FLAG} # empty or "-v" ${NO_RUN_FLAG} # empty or "-n" + ${STEADYSTATE_FLAG} # empty or "-steadystate" ) # limit each test to 90 minutes: 5400s set_tests_properties(${TESTNAME} PROPERTIES TIMEOUT 5400 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" LABELS "${LABEL}") @@ -80,15 +85,25 @@ function(of_regression TESTNAME LABEL) set(OPENFAST_EXECUTABLE "${CTEST_OPENFAST_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") - regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(of_regression) +function(of_aeromap_regression TESTNAME LABEL) + set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastRegressionCase.py") + set(OPENFAST_EXECUTABLE "${CTEST_OPENFAST_EXECUTABLE}") + set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") + set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") + set(STEADYSTATE_FLAG "-steadystate") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${STEADYSTATE_FLAG} ${TESTNAME} "${LABEL}") +endfunction(of_aeromap_regression) + function(of_fastlib_regression TESTNAME LABEL) set(TEST_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/executeOpenfastRegressionCase.py") set(OPENFAST_EXECUTABLE "${CMAKE_BINARY_DIR}/glue-codes/openfast/openfast_cpp") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") - regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} "${TESTNAME}_fastlib" "${LABEL}" ${TESTNAME}) + # extra flag in call to "regression" on next line sets the ${TESTDIR} + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " "${TESTNAME}_fastlib" "${LABEL}" ${TESTNAME}) endfunction(of_fastlib_regression) # openfast aeroacoustic @@ -97,7 +112,7 @@ function(of_regression_aeroacoustic TESTNAME LABEL) set(OPENFAST_EXECUTABLE "${CTEST_OPENFAST_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") - regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(of_regression_aeroacoustic) # FAST Farm @@ -106,7 +121,7 @@ function(ff_regression TESTNAME LABEL) set(FASTFARM_EXECUTABLE "${CTEST_FASTFARM_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/fast-farm") - regression(${TEST_SCRIPT} ${FASTFARM_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${FASTFARM_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(ff_regression) # openfast linearized @@ -115,7 +130,7 @@ function(of_regression_linear TESTNAME LABEL) set(OPENFAST_EXECUTABLE "${CTEST_OPENFAST_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast") - regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${OPENFAST_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(of_regression_linear) # openfast C++ interface @@ -124,7 +139,7 @@ function(of_cpp_interface_regression TESTNAME LABEL) set(OPENFAST_CPP_EXECUTABLE "${CTEST_OPENFASTCPP_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/openfast-cpp") - regression(${TEST_SCRIPT} ${OPENFAST_CPP_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${OPENFAST_CPP_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(of_cpp_interface_regression) # openfast Python-interface @@ -133,7 +148,7 @@ function(of_regression_py TESTNAME LABEL) set(EXECUTABLE "None") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/glue-codes/python") - regression(${TEST_SCRIPT} ${EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(of_regression_py) # aerodyn @@ -142,7 +157,7 @@ function(ad_regression TESTNAME LABEL) set(AERODYN_EXECUTABLE "${CTEST_AERODYN_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/aerodyn") - regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(ad_regression) # aerodyn-Py @@ -151,7 +166,7 @@ function(py_ad_regression TESTNAME LABEL) set(AERODYN_EXECUTABLE "${Python_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/aerodyn") - regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(py_ad_regression) @@ -161,7 +176,7 @@ function(ua_regression TESTNAME LABEL) set(AERODYN_EXECUTABLE "${CTEST_UADRIVER_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/unsteadyaero") - regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${AERODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(ua_regression) @@ -171,7 +186,7 @@ function(bd_regression TESTNAME LABEL) set(BEAMDYN_EXECUTABLE "${CTEST_BEAMDYN_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/beamdyn") - regression(${TEST_SCRIPT} ${BEAMDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${BEAMDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(bd_regression) # hydrodyn @@ -180,7 +195,7 @@ function(hd_regression TESTNAME LABEL) set(HYDRODYN_EXECUTABLE "${CTEST_HYDRODYN_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/hydrodyn") - regression(${TEST_SCRIPT} ${HYDRODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${HYDRODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(hd_regression) # py_hydrodyn @@ -189,7 +204,7 @@ function(py_hd_regression TESTNAME LABEL) set(HYDRODYN_EXECUTABLE "${Python_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/hydrodyn") - regression(${TEST_SCRIPT} ${HYDRODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${HYDRODYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(py_hd_regression) # subdyn @@ -198,7 +213,7 @@ function(sd_regression TESTNAME LABEL) set(SUBDYN_EXECUTABLE "${CTEST_SUBDYN_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/subdyn") - regression(${TEST_SCRIPT} ${SUBDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${SUBDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(sd_regression) # inflowwind @@ -207,7 +222,7 @@ function(ifw_regression TESTNAME LABEL) set(INFLOWWIND_EXECUTABLE "${CTEST_INFLOWWIND_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/inflowwind") - regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(ifw_regression) # py_inflowwind @@ -216,7 +231,7 @@ function(py_ifw_regression TESTNAME LABEL) set(INFLOWWIND_EXECUTABLE "${Python_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/inflowwind") - regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${INFLOWWIND_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(py_ifw_regression) # seastate @@ -225,7 +240,7 @@ function(seast_regression TESTNAME LABEL) set(SEASTATE_EXECUTABLE "${CTEST_SEASTATE_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/seastate") - regression(${TEST_SCRIPT} ${SEASTATE_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${SEASTATE_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(seast_regression) # moordyn @@ -234,7 +249,7 @@ function(md_regression TESTNAME LABEL) set(MOORDYN_EXECUTABLE "${CTEST_MOORDYN_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/moordyn") - regression(${TEST_SCRIPT} ${MOORDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${MOORDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(md_regression) # py_moordyn c-bindings interface @@ -243,7 +258,7 @@ function(py_md_regression TESTNAME LABEL) set(MOORDYN_EXECUTABLE "${Python_EXECUTABLE}") set(SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/..") set(BUILD_DIRECTORY "${CTEST_BINARY_DIR}/modules/moordyn") - regression(${TEST_SCRIPT} ${MOORDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} ${TESTNAME} "${LABEL}") + regression(${TEST_SCRIPT} ${MOORDYN_EXECUTABLE} ${SOURCE_DIRECTORY} ${BUILD_DIRECTORY} " " ${TESTNAME} "${LABEL}") endfunction(py_md_regression) # # Python-based OpenFAST Library tests @@ -292,6 +307,9 @@ 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") + +of_aeromap_regression("5MW_Land_AeroMap" "aeromap;elastodyn;aerodyn15") # OpenFAST C++ API test if(BUILD_OPENFAST_CPP_API) @@ -316,6 +334,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") @@ -396,6 +416,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/README.md b/reg_tests/README.md index aaa320639b..39e6317ca3 100644 --- a/reg_tests/README.md +++ b/reg_tests/README.md @@ -11,6 +11,7 @@ Dependencies required to run the regression test suite are - Numpy - CMake and CTest - Bokeh 2.4+ (optional) +- Pandas ## Execution The automated regression test runs CTest and can be executed by running either of the commands `make test` or `ctest` from the build directory. If the entire OpenFAST package is to be built, CMake will configure CTest to find the new binary at `openfast/build/glue-codes/openfast/openfast`. However, if the intention is to build only the test suite, the OpenFAST binary should be specified in the CMake configuration under the `CTEST_OPENFAST_EXECUTABLE` flag. There is also a corresponding `CTEST_[MODULE]_NAME` flag for each module that is included in the regression test. 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..9a721acab4 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,180 @@ 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) + print("Number of local files: {}".format(len(localOutFiles))) + print (" {}".format(localOutFiles)) + print("Number of baseline files: {}".format(len(baselineOutFiles))) + print (" {}".format(baselineOutFiles)) + exitWithError("An expected local solution file does not exist:") + +### test for regression (compare lin files only) + +def compareLin(f): + Errors = [] + ElemErrors = [] -### test for regression -for i, f in enumerate(localOutFiles): local_file = os.path.join(testBuildDirectory, f) baseline_file = os.path.join(targetOutputDirectory, f) + local_file2 = local_file # Ellude the long filename + + # Set a prefix for all errors to identify where it comes from + basename = os.path.splitext(os.path.basename(local_file))[0] + ext2 = os.path.splitext(basename)[1][1:] +'.lin' # '.1' or '.AD' '.BD' + errPrefix = CasePrefix[:-1]+ext2+': ' + + if verbose: + print(errPrefix+'file_ref:', baseline_file) + print(errPrefix+'file_new:', local_file) + + def newError(msg): + msg=errPrefix+msg + if verbose: + print(msg) + Errors.append(msg) + + + # 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) + Err="Local and baseline solutions have different line counts in" + Err+="\n\tFile1:{}".format(local_file) + Err+="\n\tFile2:{}\n\n".format(baseline_file) + newError(Err) + #raise Exception(Err) # 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() + 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_file2) + newError(Err) + #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, fullEV=True) + _, zeta_loc, _, freq_loc = eigA(Aloc, nq=None, nq1=None, sort=True, fullEV=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(errPrefix+'val_ref:', v_bas[:7]) + print(errPrefix+'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: + Err='Failed to compare A-matrix frequencies\n\tLinfile: {}.\n\tException: {}'.format(local_file2, indent(e.args[0])) + newError(Err) + else: + + #if verbose: + print(errPrefix+'freq_ref:', np.around(freq_bas[:8] ,5), '[Hz]') + print(errPrefix+'freq_new:', np.around(freq_loc[:8] ,5),'[Hz]') + print(errPrefix+'damp_ref:', np.around(zeta_bas[:8]*100,5), '[%]') + print(errPrefix+'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: + Err = 'Failed to compare A-matrix frequencies\n\tLinfile: {}.\n\tException: {}'.format(local_file2, indent(e.args[0])) + newError(Err) + + + 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: + Err = 'Failed to compare A-matrix damping ratios\n\tLinfile: {}.\n\tException: {}'.format(local_file2, indent(e.args[0])) + newError(Err) + + # --- 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(errPrefix+'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) + dimEqual=True + 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_file2) + newError(Err) + dimEqual=False + + if not dimEqual: + # We don't compare elements if shapes are different + continue + + # 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]) + Err=errPrefix+'Failed to compare variable `{}`, {} \n\tLinfile: {}.\n\tException: {}'.format(k, sElem, local_file2, indent(e.args[0])) + ElemErrors.append(Err) + return Errors, ElemErrors + +Errors=[] +for i, f in enumerate(localOutFiles): + ErrorsLoc, ElemErrorsLoc = compareLin(f) + Errors += ErrorsLoc + if len(ElemErrorsLoc)>0: + Errors += ElemErrorsLoc[:3] # Just a couple of them + +if len(Errors)>0: + exitWithError('See errors below: \n'+'\n'.join(Errors)) # passing case sys.exit(0) + diff --git a/reg_tests/executeOpenfastRegressionCase.py b/reg_tests/executeOpenfastRegressionCase.py index a9a0d20ad5..3d21879579 100644 --- a/reg_tests/executeOpenfastRegressionCase.py +++ b/reg_tests/executeOpenfastRegressionCase.py @@ -55,6 +55,7 @@ parser.add_argument("-p", "-plot", dest="plot", action='store_true', help="bool to include plots in failed cases") parser.add_argument("-n", "-no-exec", dest="noExec", action='store_true', help="bool to prevent execution of the test cases") parser.add_argument("-v", "-verbose", dest="verbose", action='store_true', help="bool to include verbose system output") +parser.add_argument("-steadystate", dest="steadyState", action='store_true', help="perform steadystate/aeromap analysis" ) args = parser.parse_args() @@ -67,6 +68,7 @@ plotError = args.plot noExec = args.noExec verbose = args.verbose +steadyState = args.steadyState # validate inputs rtl.validateExeOrExit(executable) @@ -94,7 +96,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) @@ -122,8 +124,12 @@ ### Run openfast on the test case if not noExec: - caseInputFile = os.path.join(testBuildDirectory, caseName + ".fst") - returnCode = openfastDrivers.runOpenfastCase(caseInputFile, executable) + if steadyState: + caseInputFile = os.path.join(testBuildDirectory, caseName + ".drv") + returnCode = openfastDrivers.runAeromapCase(caseInputFile, executable) + else: + caseInputFile = os.path.join(testBuildDirectory, caseName + ".fst") + returnCode = openfastDrivers.runOpenfastCase(caseInputFile, executable) if returnCode != 0: sys.exit(returnCode*10) diff --git a/reg_tests/lib/eva.py b/reg_tests/lib/eva.py new file mode 100644 index 0000000000..37cd28ad49 --- /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') + Q, Lambda = eig(A, sort=False) + v = np.diag(Lambda) + + if not fullEV: + 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=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/openfastDrivers.py b/reg_tests/lib/openfastDrivers.py index ceeb5a5634..1173fe5aed 100644 --- a/reg_tests/lib/openfastDrivers.py +++ b/reg_tests/lib/openfastDrivers.py @@ -27,23 +27,22 @@ import subprocess import rtestlib as rtl -def _runCase(executable, inputFile, logFile, stdout, restart=False): +def _runCase(executable, inputFile, logFile, stdout, restart=False, ExtraFlags=""): if logFile is None: - command = f"{executable} {inputFile}" + command = f"{executable} {inputFile} {ExtraFlags}" elif restart: command = f"{executable} -restart {os.path.splitext(inputFile)[0]} > {logFile}" else: - command = f"{executable} {inputFile} > {logFile}" + command = f"{executable} {inputFile} {ExtraFlags} > {logFile}" print(command) return subprocess.call(command, stdout=stdout, shell=True) -def _runGenericCase(inputFile, executable, verbose=False, restart=False, log=True): +def _runGenericCase(inputFile, executable, verbose=False, restart=False, ExtraFlags=""): stdout = sys.stdout if verbose else open(os.devnull, 'w') rtl.validateFileOrExit(inputFile) rtl.validateExeOrExit(executable) -#bjj, why wouldn't we check if log is true instead of verbose being false to generate a log file??? if verbose: logFile = None else: @@ -54,12 +53,12 @@ def _runGenericCase(inputFile, executable, verbose=False, restart=False, log=Tru else: logFile = caseparent + os.path.sep + casebase + '.log' - returnCode = _runCase(executable, inputFile, logFile, stdout, restart) + returnCode = _runCase(executable, inputFile, logFile, stdout, restart, ExtraFlags) print("COMPLETE with code {}".format(returnCode), flush=True) return returnCode -def _runUACase(inputFile, executable, verbose=False, log=True): +def _runUACase(inputFile, executable, verbose=False): stdout = sys.stdout if verbose else open(os.devnull, 'w') rtl.validateFileOrExit(inputFile) @@ -79,6 +78,9 @@ def _runUACase(inputFile, executable, verbose=False, log=True): def runOpenfastCase(inputFile, executable, verbose=False, restart=False): return _runGenericCase(inputFile, executable, verbose, restart) +def runAeromapCase(inputFile, executable, verbose=False): + return _runGenericCase(inputFile, executable, verbose, restart=False, ExtraFlags="-steadystate") + def runAerodynDriverCase(inputFile, executable, verbose=False): caseDirectory = os.path.sep.join(inputFile.split(os.path.sep)[:-1]) os.chdir(caseDirectory) 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 6386eebdff..a2420b965b 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 6386eebdff25b85944ff91cd826f5a2949c63a80 +Subproject commit a2420b965b48f83db07235efba0aa1a7563e0b87 diff --git a/vs-build/AeroDyn/AeroDyn_Driver.vfproj b/vs-build/AeroDyn/AeroDyn_Driver.vfproj index 8b22a773b2..ee8c50a803 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 @@ - + diff --git a/vs-build/FASTlib/FASTlib.vfproj b/vs-build/FASTlib/FASTlib.vfproj index b62392c0f7..983b157bf4 100644 --- a/vs-build/FASTlib/FASTlib.vfproj +++ b/vs-build/FASTlib/FASTlib.vfproj @@ -718,6 +718,9 @@ + + + @@ -1301,33 +1304,33 @@ - + - - - + - + + + - + - - - - - + - - - - - - - + + + + + - + + + + + + + - + @@ -1339,34 +1342,34 @@ - + - - - + - + + + - + - - - - - + - - - - - - - + + + + + - + + + + + + + - - + + @@ -1996,38 +1999,38 @@ - + - + - + - - - + - + + + - + - - - - - + - - - - - - - + + + + + - + + + + + + + - - + + @@ -2036,7 +2039,7 @@ - + @@ -2078,20 +2081,34 @@ + + - + + + + + - + - - - + + + - - - + + + + + + + - + + + + + diff --git a/vs-build/MAPlib/MAP_dll.vcxproj b/vs-build/MAPlib/MAP_dll.vcxproj index 3d09cd2bc3..022b29cb38 100644 --- a/vs-build/MAPlib/MAP_dll.vcxproj +++ b/vs-build/MAPlib/MAP_dll.vcxproj @@ -195,20 +195,7 @@ - - CALL ..\RunRegistry.bat MAP - ..\..\modules\map\src\MAP_Types.h - false - CALL ..\RunRegistry.bat MAP - ..\..\modules\map\src\MAP_Types.h - CALL ..\RunRegistry.bat MAP - ..\..\modules\map\src\MAP_Types.h - false - false - CALL ..\RunRegistry.bat MAP - ..\..\modules\map\src\MAP_Types.h - false - + diff --git a/vs-build/RunRegistry.bat b/vs-build/RunRegistry.bat index f7d9623019..f42eb5634a 100644 --- a/vs-build/RunRegistry.bat +++ b/vs-build/RunRegistry.bat @@ -35,7 +35,7 @@ SET FEAM_Loc=%Modules_Loc%\feamooring\src SET IceF_Loc=%Modules_Loc%\icefloe\src\interfaces\FAST SET IceD_Loc=%Modules_Loc%\icedyn\src SET MD_Loc=%Modules_Loc%\moordyn\src -SET OpFM_Loc=%Modules_Loc%\openfoam\src +SET ExtInfw_Loc=%Modules_Loc%\externalinflow\src SET Orca_Loc=%Modules_Loc%\orcaflex-interface\src SET NWTC_Lib_Loc=%Modules_Loc%\nwtc-library\src SET ExtPtfm_Loc=%Modules_Loc%\extptfm\src @@ -51,7 +51,7 @@ SET Farm_Loc=%Root_Loc%\glue-codes\fast-farm\src SET ALL_FAST_Includes=-I "%FAST_Loc%" -I "%NWTC_Lib_Loc%" -I "%ED_Loc%" -I "%SrvD_Loc%" -I "%AD14_Loc%" -I^ "%AD_Loc%" -I "%BD_Loc%" -I "%SC_Loc%" -I^ "%IfW_Loc%" -I "%SD_Loc%" -I "%HD_Loc%" -I "%SEAST_Loc%" -I "%MAP_Loc%" -I "%FEAM_Loc%" -I^ - "%IceF_Loc%" -I "%IceD_Loc%" -I "%MD_Loc%" -I "%OpFM_Loc%" -I "%Orca_Loc%" -I "%ExtPtfm_Loc%" + "%IceF_Loc%" -I "%IceD_Loc%" -I "%MD_Loc%" -I "%ExtInfw_Loc%" -I "%Orca_Loc%" -I "%ExtPtfm_Loc%" SET ModuleName=%1 @@ -71,7 +71,7 @@ GOTO checkError SET CURR_LOC=%MAP_Loc% SET Output_Loc=%CURR_LOC% %REGISTRY% "%CURR_LOC%\%ModuleName%_Registry.txt" -ccode -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" -%REGISTRY% "%CURR_LOC%\MAP_Fortran_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" -noextrap +:: %REGISTRY% "%CURR_LOC%\MAP_Fortran_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -O "%Output_Loc%" -noextrap GOTO checkError :MAP_Fortran @@ -132,10 +132,10 @@ SET Output_Loc=%CURR_LOC% %REGISTRY% "%CURR_LOC%\%ModuleName%.txt" -I "%NWTC_Lib_Loc%" -I "%CURR_LOC%" -noextrap -O "%Output_Loc%" GOTO checkError -:OpenFOAM -SET CURR_LOC=%OpFM_Loc% +:ExternalInflow +SET CURR_LOC=%ExtInfw_Loc% SET Output_Loc=%CURR_LOC% -%REGISTRY% "%CURR_LOC%\%ModuleName%_Registry.txt" -I "%NWTC_Lib_Loc%" -ccode -O "%Output_Loc%" +%REGISTRY% "%CURR_LOC%\%ModuleName%_Registry.txt" -I "%NWTC_Lib_Loc%" -I "%IfW_Loc%" -ccode -O "%Output_Loc%" GOTO checkError :AeroDyn @@ -326,7 +326,7 @@ SET FEAM_Loc= SET IceF_Loc= SET IceD_Loc= SET MD_Loc= -SET OpFM_Loc= +SET ExtInfw_Loc= SET Orca_Loc= SET NWTC_Lib_Loc= SET ExtPtfm_Loc=